remove Bkm as a IMovie implementation and remove all code other than what is necessary to import it
This commit is contained in:
parent
adf834480a
commit
c4658c3e85
|
@ -180,21 +180,8 @@
|
|||
</Compile>
|
||||
<Compile Include="movie\bkm\BkmControllerAdapter.cs" />
|
||||
<Compile Include="movie\bkm\BkmHeader.cs" />
|
||||
<Compile Include="movie\bkm\BkmLogEntryGenerator.cs" />
|
||||
<Compile Include="movie\bkm\BkmMnemonicConstants.cs" />
|
||||
<Compile Include="movie\bkm\BkmMovie.cs" />
|
||||
<Compile Include="movie\bkm\BkmMovie.HeaderApi.cs">
|
||||
<DependentUpon>BkmMovie.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="movie\bkm\BkmMovie.InputLog.cs">
|
||||
<DependentUpon>BkmMovie.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="movie\bkm\BkmMovie.IO.cs">
|
||||
<DependentUpon>BkmMovie.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="movie\bkm\BkmMovie.ModeApi.cs">
|
||||
<DependentUpon>BkmMovie.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="movie\conversions\MovieConversionExtensions.cs" />
|
||||
<Compile Include="movie\HeaderKeys.cs" />
|
||||
<Compile Include="movie\import\Fm2Import.cs" />
|
||||
|
|
|
@ -5,7 +5,7 @@ using BizHawk.Emulation.Common;
|
|||
|
||||
namespace BizHawk.Client.Common
|
||||
{
|
||||
public class BkmControllerAdapter : IMovieController
|
||||
internal class BkmControllerAdapter : IController
|
||||
{
|
||||
#region IController Implementation
|
||||
|
||||
|
@ -23,54 +23,6 @@ namespace BizHawk.Client.Common
|
|||
|
||||
#endregion
|
||||
|
||||
#region IMovieController Implementation
|
||||
|
||||
/// <summary>
|
||||
/// latches one player from the source
|
||||
/// </summary>
|
||||
public void LatchPlayerFromSource(IController playerSource, int playerNum)
|
||||
{
|
||||
foreach (var button in playerSource.Definition.BoolButtons)
|
||||
{
|
||||
var bnp = ButtonNameParser.Parse(button);
|
||||
|
||||
if (bnp?.PlayerNum != playerNum)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var val = playerSource.IsPressed(button);
|
||||
_myBoolButtons[button] = val;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// latches all buttons from the provided source
|
||||
/// </summary>
|
||||
public void LatchFromSource(IController source)
|
||||
{
|
||||
foreach (var button in Definition.BoolButtons)
|
||||
{
|
||||
_myBoolButtons[button] = source.IsPressed(button);
|
||||
}
|
||||
|
||||
foreach (var name in Definition.FloatControls)
|
||||
{
|
||||
_myFloatControls[name] = source.GetFloat(name);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// latches sticky buttons from Global.AutofireStickyXORAdapter
|
||||
/// </summary>
|
||||
public void LatchSticky()
|
||||
{
|
||||
foreach (var button in Definition.BoolButtons)
|
||||
{
|
||||
_myBoolButtons[button] = Global.AutofireStickyXORAdapter.IsSticky(button);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// latches all buttons from the supplied mnemonic string
|
||||
/// </summary>
|
||||
|
@ -273,8 +225,6 @@ namespace BizHawk.Client.Common
|
|||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private readonly WorkingDictionary<string, bool> _myBoolButtons = new WorkingDictionary<string, bool>();
|
||||
private readonly WorkingDictionary<string, float> _myFloatControls = new WorkingDictionary<string, float>();
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ using System.Text;
|
|||
|
||||
namespace BizHawk.Client.Common
|
||||
{
|
||||
public class BkmHeader : Dictionary<string, string>
|
||||
internal class BkmHeader : Dictionary<string, string>
|
||||
{
|
||||
public BkmHeader()
|
||||
{
|
||||
|
@ -45,91 +45,9 @@ namespace BizHawk.Client.Common
|
|||
}
|
||||
}
|
||||
|
||||
public ulong Rerecords
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!ContainsKey(HeaderKeys.RERECORDS))
|
||||
{
|
||||
this[HeaderKeys.RERECORDS] = "0";
|
||||
}
|
||||
|
||||
return ulong.Parse(this[HeaderKeys.RERECORDS]);
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
this[HeaderKeys.RERECORDS] = value.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public bool StartsFromSavestate
|
||||
{
|
||||
get
|
||||
{
|
||||
if (ContainsKey(HeaderKeys.STARTSFROMSAVESTATE))
|
||||
{
|
||||
return bool.Parse(this[HeaderKeys.STARTSFROMSAVESTATE]);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (value)
|
||||
{
|
||||
Add(HeaderKeys.STARTSFROMSAVESTATE, "True");
|
||||
}
|
||||
else
|
||||
{
|
||||
Remove(HeaderKeys.STARTSFROMSAVESTATE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string GameName
|
||||
{
|
||||
get
|
||||
{
|
||||
if (ContainsKey(HeaderKeys.GAMENAME))
|
||||
{
|
||||
return this[HeaderKeys.GAMENAME];
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
this[HeaderKeys.GAMENAME] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public string SystemId
|
||||
{
|
||||
get
|
||||
{
|
||||
if (ContainsKey(HeaderKeys.PLATFORM))
|
||||
{
|
||||
return this[HeaderKeys.PLATFORM];
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
this[HeaderKeys.PLATFORM] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public new string this[string key]
|
||||
{
|
||||
get
|
||||
{
|
||||
return ContainsKey(key) ? base[key] : "";
|
||||
}
|
||||
get => ContainsKey(key) ? base[key] : "";
|
||||
|
||||
set
|
||||
{
|
||||
|
|
|
@ -1,610 +0,0 @@
|
|||
using System.Text;
|
||||
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Client.Common
|
||||
{
|
||||
public class BkmLogEntryGenerator : ILogEntryGenerator
|
||||
{
|
||||
private IController _source;
|
||||
|
||||
public void SetSource(IController source)
|
||||
{
|
||||
_source = source;
|
||||
_controlType = source.Definition.Name;
|
||||
}
|
||||
|
||||
public string GenerateLogEntry()
|
||||
{
|
||||
if (_controlType == "Null Controller")
|
||||
{
|
||||
return "|.|";
|
||||
}
|
||||
|
||||
if (_controlType == "Lynx Controller")
|
||||
{
|
||||
return GetLynxControllersAsMnemonic();
|
||||
}
|
||||
|
||||
if (_controlType == "Atari 7800 ProLine Joystick Controller")
|
||||
{
|
||||
return GetA78ControllersAsMnemonic();
|
||||
}
|
||||
|
||||
if (_controlType == "SNES Controller")
|
||||
{
|
||||
return GetSNESControllersAsMnemonic();
|
||||
}
|
||||
|
||||
if (_controlType == "Commodore 64 Controller")
|
||||
{
|
||||
return GetC64ControllersAsMnemonic();
|
||||
}
|
||||
|
||||
if (_controlType == "GBA Controller")
|
||||
{
|
||||
return GetGBAControllersAsMnemonic();
|
||||
}
|
||||
|
||||
if (_controlType == "Dual Gameboy Controller")
|
||||
{
|
||||
return GetDualGameBoyControllerAsMnemonic();
|
||||
}
|
||||
|
||||
if (_controlType == "WonderSwan Controller")
|
||||
{
|
||||
return GetWonderSwanControllerAsMnemonic();
|
||||
}
|
||||
|
||||
if (_controlType == "Nintento 64 Controller")
|
||||
{
|
||||
return GetN64ControllersAsMnemonic();
|
||||
}
|
||||
|
||||
if (_controlType == "Saturn Controller")
|
||||
{
|
||||
return GetSaturnControllersAsMnemonic();
|
||||
}
|
||||
|
||||
if (_controlType == "PSP Controller")
|
||||
{
|
||||
return "|.|"; // TODO
|
||||
}
|
||||
|
||||
if (_controlType == "GPGX Genesis Controller")
|
||||
{
|
||||
return GetGeneis6ButtonControllersAsMnemonic();
|
||||
}
|
||||
|
||||
if (_controlType == "GPGX 3-Button Controller")
|
||||
{
|
||||
return GetGeneis3ButtonControllersAsMnemonic();
|
||||
}
|
||||
|
||||
var input = new StringBuilder("|");
|
||||
|
||||
if (_controlType == "PC Engine Controller")
|
||||
{
|
||||
input.Append(".");
|
||||
}
|
||||
else if (_controlType == "Atari 2600 Basic Controller")
|
||||
{
|
||||
input.Append(IsBasePressed("Reset") ? "r" : ".");
|
||||
input.Append(IsBasePressed("Select") ? "s" : ".");
|
||||
}
|
||||
else if (_controlType == "NES Controller")
|
||||
{
|
||||
if (IsBasePressed("Power"))
|
||||
{
|
||||
input.Append(BkmMnemonicConstants.Commands[_controlType]["Power"]);
|
||||
}
|
||||
else if (IsBasePressed("Reset"))
|
||||
{
|
||||
input.Append(BkmMnemonicConstants.Commands[_controlType]["Reset"]);
|
||||
}
|
||||
else if (IsBasePressed("FDS Eject"))
|
||||
{
|
||||
input.Append(BkmMnemonicConstants.Commands[_controlType]["FDS Eject"]);
|
||||
}
|
||||
else if (IsBasePressed("FDS Insert 0"))
|
||||
{
|
||||
input.Append("0");
|
||||
}
|
||||
else if (IsBasePressed("FDS Insert 1"))
|
||||
{
|
||||
input.Append("1");
|
||||
}
|
||||
else if (IsBasePressed("FDS Insert 2"))
|
||||
{
|
||||
input.Append("2");
|
||||
}
|
||||
else if (IsBasePressed("FDS Insert 3"))
|
||||
{
|
||||
input.Append("3");
|
||||
}
|
||||
else if (IsBasePressed("VS Coin 1"))
|
||||
{
|
||||
input.Append(BkmMnemonicConstants.Commands[_controlType]["VS Coin 1"]);
|
||||
}
|
||||
else if (IsBasePressed("VS Coin 2"))
|
||||
{
|
||||
input.Append(BkmMnemonicConstants.Commands[_controlType]["VS Coin 2"]);
|
||||
}
|
||||
else
|
||||
{
|
||||
input.Append('.');
|
||||
}
|
||||
}
|
||||
else if (_controlType == "Genesis 3-Button Controller")
|
||||
{
|
||||
if (IsBasePressed("Power"))
|
||||
{
|
||||
input.Append(BkmMnemonicConstants.Commands[_controlType]["Power"]);
|
||||
}
|
||||
else if (IsBasePressed("Reset"))
|
||||
{
|
||||
input.Append(BkmMnemonicConstants.Commands[_controlType]["Reset"]);
|
||||
}
|
||||
else
|
||||
{
|
||||
input.Append('.');
|
||||
}
|
||||
}
|
||||
else if (_controlType == "Gameboy Controller")
|
||||
{
|
||||
input.Append(IsBasePressed("Power") ? BkmMnemonicConstants.Commands[_controlType]["Power"] : ".");
|
||||
}
|
||||
|
||||
if (_controlType != "SMS Controller" && _controlType != "TI83 Controller" && _controlType != "ColecoVision Basic Controller")
|
||||
{
|
||||
input.Append("|");
|
||||
}
|
||||
|
||||
for (int player = 1; player <= BkmMnemonicConstants.Players[_controlType]; player++)
|
||||
{
|
||||
var prefix = "";
|
||||
if (_controlType != "Gameboy Controller" && _controlType != "TI83 Controller")
|
||||
{
|
||||
prefix = $"P{player} ";
|
||||
}
|
||||
|
||||
foreach (var button in BkmMnemonicConstants.Buttons[_controlType].Keys)
|
||||
{
|
||||
input.Append(IsBasePressed(prefix + button) ? BkmMnemonicConstants.Buttons[_controlType][button] : ".");
|
||||
}
|
||||
|
||||
input.Append("|");
|
||||
}
|
||||
|
||||
if (_controlType == "SMS Controller")
|
||||
{
|
||||
foreach (var command in BkmMnemonicConstants.Commands[_controlType].Keys)
|
||||
{
|
||||
input.Append(IsBasePressed(command) ? BkmMnemonicConstants.Commands[_controlType][command] : ".");
|
||||
}
|
||||
|
||||
input.Append("|");
|
||||
}
|
||||
|
||||
if (_controlType == "TI83 Controller")
|
||||
{
|
||||
input.Append(".|"); // TODO: perhaps ON should go here?
|
||||
}
|
||||
|
||||
return input.ToString();
|
||||
}
|
||||
|
||||
public string GenerateInputDisplay()
|
||||
{
|
||||
return GenerateLogEntry()
|
||||
.Replace(".", " ")
|
||||
.Replace("|", "")
|
||||
.Replace(" 000, 000", " ");
|
||||
}
|
||||
|
||||
public bool IsEmpty => EmptyEntry == GenerateLogEntry();
|
||||
|
||||
public string EmptyEntry
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (Global.Emulator.SystemId)
|
||||
{
|
||||
default:
|
||||
case "NULL":
|
||||
return "|.|";
|
||||
case "A26":
|
||||
return "|..|.....|.....|";
|
||||
case "A78":
|
||||
return "|....|......|......|";
|
||||
case "TI83":
|
||||
return "|..................................................|.|";
|
||||
case "NES":
|
||||
return "|.|........|........|........|........|";
|
||||
case "SNES":
|
||||
return "|.|............|............|............|............|";
|
||||
case "SMS":
|
||||
case "GG":
|
||||
case "SG":
|
||||
return "|......|......|..|";
|
||||
case "GEN":
|
||||
return "|.|........|........|";
|
||||
case "GB":
|
||||
return "|.|........|";
|
||||
case "DGB":
|
||||
return "|.|........|.|........|";
|
||||
case "PCE":
|
||||
case "PCECD":
|
||||
case "SGX":
|
||||
return "|.|........|........|........|........|........|";
|
||||
case "Coleco":
|
||||
return "|..................|..................|";
|
||||
case "C64":
|
||||
return "|.....|.....|..................................................................|";
|
||||
case "GBA":
|
||||
return "|.|..........|";
|
||||
case "N64":
|
||||
return "|.|............|............|............|............|";
|
||||
case "SAT":
|
||||
return "|.|.............|.............|";
|
||||
case "WSWAN":
|
||||
return "|...........|...........|..|";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public IMovieController MovieControllerAdapter => new BkmControllerAdapter();
|
||||
|
||||
#region Privates
|
||||
|
||||
private bool IsBasePressed(string name)
|
||||
{
|
||||
return _source.IsPressed(name);
|
||||
}
|
||||
|
||||
private float GetBaseFloat(string name)
|
||||
{
|
||||
return _source.GetFloat(name);
|
||||
}
|
||||
|
||||
private string _controlType;
|
||||
|
||||
private string GetGBAControllersAsMnemonic()
|
||||
{
|
||||
var input = new StringBuilder("|");
|
||||
if (IsBasePressed("Power"))
|
||||
{
|
||||
input.Append(BkmMnemonicConstants.Commands[_controlType]["Power"]);
|
||||
}
|
||||
else
|
||||
{
|
||||
input.Append(".");
|
||||
}
|
||||
|
||||
input.Append("|");
|
||||
foreach (var button in BkmMnemonicConstants.Buttons[_controlType].Keys)
|
||||
{
|
||||
input.Append(IsBasePressed(button) ? BkmMnemonicConstants.Buttons[_controlType][button] : ".");
|
||||
}
|
||||
|
||||
input.Append("|");
|
||||
return input.ToString();
|
||||
}
|
||||
|
||||
private string GetSNESControllersAsMnemonic()
|
||||
{
|
||||
var input = new StringBuilder("|");
|
||||
|
||||
if (IsBasePressed("Power"))
|
||||
{
|
||||
input.Append(BkmMnemonicConstants.Commands[_controlType]["Power"]);
|
||||
}
|
||||
else if (IsBasePressed("Reset"))
|
||||
{
|
||||
input.Append(BkmMnemonicConstants.Commands[_controlType]["Reset"]);
|
||||
}
|
||||
else
|
||||
{
|
||||
input.Append('.');
|
||||
}
|
||||
|
||||
input.Append("|");
|
||||
for (int player = 1; player <= BkmMnemonicConstants.Players[_controlType]; player++)
|
||||
{
|
||||
foreach (var button in BkmMnemonicConstants.Buttons[_controlType].Keys)
|
||||
{
|
||||
input.Append(IsBasePressed($"P{player} {button}") ? BkmMnemonicConstants.Buttons[_controlType][button] : ".");
|
||||
}
|
||||
|
||||
input.Append("|");
|
||||
}
|
||||
|
||||
return input.ToString();
|
||||
}
|
||||
|
||||
private string GetC64ControllersAsMnemonic()
|
||||
{
|
||||
var input = new StringBuilder("|");
|
||||
|
||||
for (int player = 1; player <= BkmMnemonicConstants.Players[_controlType]; player++)
|
||||
{
|
||||
foreach (var button in BkmMnemonicConstants.Buttons[_controlType].Keys)
|
||||
{
|
||||
input.Append(IsBasePressed($"P{player} {button}") ? BkmMnemonicConstants.Buttons[_controlType][button] : ".");
|
||||
}
|
||||
|
||||
input.Append('|');
|
||||
}
|
||||
|
||||
foreach (var button in BkmMnemonicConstants.Buttons["Commodore 64 Keyboard"].Keys)
|
||||
{
|
||||
input.Append(IsBasePressed(button) ? BkmMnemonicConstants.Buttons["Commodore 64 Keyboard"][button] : ".");
|
||||
}
|
||||
|
||||
input.Append('|');
|
||||
return input.ToString();
|
||||
}
|
||||
|
||||
private string GetDualGameBoyControllerAsMnemonic()
|
||||
{
|
||||
// |.|........|.|........|
|
||||
var input = new StringBuilder();
|
||||
|
||||
foreach (var t in BkmMnemonicConstants.DgbMnemonic)
|
||||
{
|
||||
if (t.Item1 != null)
|
||||
{
|
||||
input.Append(IsBasePressed(t.Item1) ? t.Item2 : '.');
|
||||
}
|
||||
else
|
||||
{
|
||||
input.Append(t.Item2); // Separator
|
||||
}
|
||||
}
|
||||
|
||||
return input.ToString();
|
||||
}
|
||||
|
||||
private string GetWonderSwanControllerAsMnemonic()
|
||||
{
|
||||
// |....|....|...|
|
||||
var input = new StringBuilder();
|
||||
|
||||
foreach (var t in BkmMnemonicConstants.WsMnemonic)
|
||||
{
|
||||
if (t.Item1 != null)
|
||||
{
|
||||
input.Append(IsBasePressed(t.Item1) ? t.Item2 : '.');
|
||||
}
|
||||
else
|
||||
{
|
||||
input.Append(t.Item2); // Separator
|
||||
}
|
||||
}
|
||||
|
||||
return input.ToString();
|
||||
}
|
||||
|
||||
private string GetA78ControllersAsMnemonic()
|
||||
{
|
||||
var input = new StringBuilder("|");
|
||||
input.Append(IsBasePressed("Power") ? 'P' : '.');
|
||||
input.Append(IsBasePressed("Reset") ? 'r' : '.');
|
||||
input.Append(IsBasePressed("Select") ? 's' : '.');
|
||||
input.Append(IsBasePressed("Pause") ? 'p' : '.');
|
||||
input.Append('|');
|
||||
|
||||
for (int player = 1; player <= BkmMnemonicConstants.Players[_controlType]; player++)
|
||||
{
|
||||
foreach (var button in BkmMnemonicConstants.Buttons[_controlType].Keys)
|
||||
{
|
||||
input.Append(IsBasePressed($"P{player} {button}") ? BkmMnemonicConstants.Buttons[_controlType][button] : ".");
|
||||
}
|
||||
|
||||
input.Append('|');
|
||||
}
|
||||
|
||||
return input.ToString();
|
||||
}
|
||||
|
||||
private string GetLynxControllersAsMnemonic()
|
||||
{
|
||||
var input = new StringBuilder("|");
|
||||
input.Append(IsBasePressed("Power") ? 'P' : '.');
|
||||
input.Append('|');
|
||||
|
||||
for (int player = 1; player <= BkmMnemonicConstants.Players[_controlType]; player++)
|
||||
{
|
||||
foreach (var button in BkmMnemonicConstants.Buttons[_controlType].Keys)
|
||||
{
|
||||
input.Append(IsBasePressed(button) ? BkmMnemonicConstants.Buttons[_controlType][button] : ".");
|
||||
}
|
||||
|
||||
input.Append('|');
|
||||
}
|
||||
|
||||
return input.ToString();
|
||||
}
|
||||
|
||||
private string GetN64ControllersAsMnemonic()
|
||||
{
|
||||
var input = new StringBuilder("|");
|
||||
if (IsBasePressed("Power"))
|
||||
{
|
||||
input.Append('P');
|
||||
}
|
||||
else if (IsBasePressed("Reset"))
|
||||
{
|
||||
input.Append('r');
|
||||
}
|
||||
else
|
||||
{
|
||||
input.Append('.');
|
||||
}
|
||||
|
||||
input.Append('|');
|
||||
|
||||
for (int player = 1; player <= BkmMnemonicConstants.Players[_controlType]; player++)
|
||||
{
|
||||
foreach (var button in BkmMnemonicConstants.Buttons[_controlType].Keys)
|
||||
{
|
||||
input.Append(IsBasePressed($"P{player} {button}") ? BkmMnemonicConstants.Buttons[_controlType][button] : ".");
|
||||
}
|
||||
|
||||
if (BkmMnemonicConstants.Analogs[_controlType].Keys.Count > 0)
|
||||
{
|
||||
foreach (var name in BkmMnemonicConstants.Analogs[_controlType].Keys)
|
||||
{
|
||||
int val;
|
||||
|
||||
// Nasty hackery
|
||||
if (name == "Y Axis")
|
||||
{
|
||||
if (IsBasePressed($"P{player} A Up"))
|
||||
{
|
||||
val = 127;
|
||||
}
|
||||
else if (IsBasePressed($"P{player} A Down"))
|
||||
{
|
||||
val = -127;
|
||||
}
|
||||
else
|
||||
{
|
||||
val = (int)GetBaseFloat($"P{player} {name}");
|
||||
}
|
||||
}
|
||||
else if (name == "X Axis")
|
||||
{
|
||||
if (IsBasePressed($"P{player} A Left"))
|
||||
{
|
||||
val = -127;
|
||||
}
|
||||
else if (IsBasePressed($"P{player} A Right"))
|
||||
{
|
||||
val = 127;
|
||||
}
|
||||
else
|
||||
{
|
||||
val = (int)GetBaseFloat($"P{player} {name}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
val = (int)GetBaseFloat($"P{player} {name}");
|
||||
}
|
||||
|
||||
if (val >= 0)
|
||||
{
|
||||
input.Append(' ');
|
||||
}
|
||||
|
||||
input.Append($"{val:000}").Append(',');
|
||||
}
|
||||
|
||||
input.Remove(input.Length - 1, 1);
|
||||
}
|
||||
|
||||
input.Append('|');
|
||||
}
|
||||
|
||||
return input.ToString();
|
||||
}
|
||||
|
||||
private string GetSaturnControllersAsMnemonic()
|
||||
{
|
||||
var input = new StringBuilder("|");
|
||||
if (IsBasePressed("Power"))
|
||||
{
|
||||
input.Append('P');
|
||||
}
|
||||
else if (IsBasePressed("Reset"))
|
||||
{
|
||||
input.Append('r');
|
||||
}
|
||||
else
|
||||
{
|
||||
input.Append('.');
|
||||
}
|
||||
|
||||
input.Append('|');
|
||||
|
||||
for (int player = 1; player <= BkmMnemonicConstants.Players[_controlType]; player++)
|
||||
{
|
||||
foreach (var button in BkmMnemonicConstants.Buttons[_controlType].Keys)
|
||||
{
|
||||
input.Append(IsBasePressed($"P{player} {button}") ? BkmMnemonicConstants.Buttons[_controlType][button] : ".");
|
||||
}
|
||||
|
||||
input.Append('|');
|
||||
}
|
||||
|
||||
return input.ToString();
|
||||
}
|
||||
|
||||
private string GetGeneis6ButtonControllersAsMnemonic()
|
||||
{
|
||||
var input = new StringBuilder("|");
|
||||
|
||||
if (IsBasePressed("Power"))
|
||||
{
|
||||
input.Append(BkmMnemonicConstants.Commands[_controlType]["Power"]);
|
||||
}
|
||||
else if (IsBasePressed("Reset"))
|
||||
{
|
||||
input.Append(BkmMnemonicConstants.Commands[_controlType]["Reset"]);
|
||||
}
|
||||
else
|
||||
{
|
||||
input.Append('.');
|
||||
}
|
||||
|
||||
input.Append("|");
|
||||
for (int player = 1; player <= BkmMnemonicConstants.Players[_controlType]; player++)
|
||||
{
|
||||
foreach (var button in BkmMnemonicConstants.Buttons[_controlType].Keys)
|
||||
{
|
||||
input.Append(IsBasePressed($"P{player} {button}") ? BkmMnemonicConstants.Buttons[_controlType][button] : ".");
|
||||
}
|
||||
|
||||
input.Append("|");
|
||||
}
|
||||
|
||||
input.Append("|");
|
||||
return input.ToString();
|
||||
}
|
||||
|
||||
private string GetGeneis3ButtonControllersAsMnemonic()
|
||||
{
|
||||
var input = new StringBuilder("|");
|
||||
|
||||
if (IsBasePressed("Power"))
|
||||
{
|
||||
input.Append(BkmMnemonicConstants.Commands[_controlType]["Power"]);
|
||||
}
|
||||
else if (IsBasePressed("Reset"))
|
||||
{
|
||||
input.Append(BkmMnemonicConstants.Commands[_controlType]["Reset"]);
|
||||
}
|
||||
else
|
||||
{
|
||||
input.Append('.');
|
||||
}
|
||||
|
||||
input.Append("|");
|
||||
for (int player = 1; player <= BkmMnemonicConstants.Players[_controlType]; player++)
|
||||
{
|
||||
foreach (var button in BkmMnemonicConstants.Buttons[_controlType].Keys)
|
||||
{
|
||||
input.Append(IsBasePressed($"P{player} {button}") ? BkmMnemonicConstants.Buttons[_controlType][button] : ".");
|
||||
}
|
||||
|
||||
input.Append("|");
|
||||
}
|
||||
|
||||
input.Append("|");
|
||||
return input.ToString();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@ using System.Collections.Generic;
|
|||
|
||||
namespace BizHawk.Client.Common
|
||||
{
|
||||
public static class BkmMnemonicConstants
|
||||
internal static class BkmMnemonicConstants
|
||||
{
|
||||
public static readonly Dictionary<string, Dictionary<string, string>> Buttons = new Dictionary<string, Dictionary<string, string>>
|
||||
{
|
||||
|
|
|
@ -1,90 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace BizHawk.Client.Common
|
||||
{
|
||||
public partial class BkmMovie
|
||||
{
|
||||
public IDictionary<string, string> HeaderEntries => Header;
|
||||
|
||||
public SubtitleList Subtitles => Header.Subtitles;
|
||||
|
||||
public IList<string> Comments => Header.Comments;
|
||||
|
||||
public string SyncSettingsJson
|
||||
{
|
||||
get { return Header[HeaderKeys.SYNCSETTINGS]; }
|
||||
set { Header[HeaderKeys.SYNCSETTINGS] = value; }
|
||||
}
|
||||
|
||||
public ulong Rerecords
|
||||
{
|
||||
get { return Header.Rerecords; }
|
||||
set { Header.Rerecords = value; }
|
||||
}
|
||||
|
||||
public bool StartsFromSavestate
|
||||
{
|
||||
get { return Header.StartsFromSavestate; }
|
||||
set { Header.StartsFromSavestate = value; }
|
||||
}
|
||||
|
||||
// Bkm doesn't support saveram anchored movies
|
||||
public bool StartsFromSaveRam
|
||||
{
|
||||
get { return false; } set { }
|
||||
}
|
||||
|
||||
public string GameName
|
||||
{
|
||||
get { return Header.GameName; }
|
||||
set { Header.GameName = value; }
|
||||
}
|
||||
|
||||
public string SystemID
|
||||
{
|
||||
get { return Header.SystemId; }
|
||||
set { Header.SystemId = value; }
|
||||
}
|
||||
|
||||
public string Hash
|
||||
{
|
||||
get { return Header[HeaderKeys.SHA1]; }
|
||||
set { Header[HeaderKeys.SHA1] = value; }
|
||||
}
|
||||
|
||||
public string Author
|
||||
{
|
||||
get { return Header[HeaderKeys.AUTHOR]; }
|
||||
set { Header[HeaderKeys.AUTHOR] = value; }
|
||||
}
|
||||
|
||||
public string Core
|
||||
{
|
||||
get { return Header[HeaderKeys.CORE]; }
|
||||
set { Header[HeaderKeys.CORE] = value; }
|
||||
}
|
||||
|
||||
public string BoardName
|
||||
{
|
||||
get { return Header[HeaderKeys.BOARDNAME]; }
|
||||
set { Header[HeaderKeys.BOARDNAME] = value; }
|
||||
}
|
||||
|
||||
public string EmulatorVersion
|
||||
{
|
||||
get { return Header[HeaderKeys.EMULATIONVERSION]; }
|
||||
set { Header[HeaderKeys.EMULATIONVERSION] = value; }
|
||||
}
|
||||
|
||||
public string FirmwareHash
|
||||
{
|
||||
get { return Header[HeaderKeys.FIRMWARESHA1]; }
|
||||
set { Header[HeaderKeys.FIRMWARESHA1] = value; }
|
||||
}
|
||||
|
||||
public string TextSavestate { get; set; }
|
||||
public byte[] BinarySavestate { get; set; }
|
||||
public int[] SavestateFramebuffer { get { return null; } set { } } // eat and ignore framebuffers
|
||||
public byte[] SaveRam { get { return null; } set { } } // Bkm does not support Saveram anchored movies
|
||||
}
|
||||
}
|
|
@ -1,281 +0,0 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
using BizHawk.Common;
|
||||
|
||||
namespace BizHawk.Client.Common
|
||||
{
|
||||
public partial class BkmMovie
|
||||
{
|
||||
private int _preloadFramecount; // Not a a reliable number, used for preloading (when no log has yet been loaded), this is only for quick stat compilation for dialogs such as play movie
|
||||
|
||||
public void SaveAs(string path)
|
||||
{
|
||||
Filename = path;
|
||||
if (!Loaded)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var directoryInfo = new FileInfo(Filename).Directory;
|
||||
if (directoryInfo != null)
|
||||
{
|
||||
Directory.CreateDirectory(directoryInfo.FullName);
|
||||
}
|
||||
|
||||
Write(Filename);
|
||||
}
|
||||
|
||||
public void Save()
|
||||
{
|
||||
if (!Loaded || string.IsNullOrWhiteSpace(Filename))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SaveAs(Filename);
|
||||
_changes = false;
|
||||
}
|
||||
|
||||
public void SaveBackup()
|
||||
{
|
||||
if (!Loaded || string.IsNullOrWhiteSpace(Filename))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var backupName = Filename;
|
||||
backupName = backupName.Insert(Filename.LastIndexOf("."), $".{DateTime.Now:yyyy-MM-dd HH.mm.ss}");
|
||||
backupName = Path.Combine(Global.Config.PathEntries["Global", "Movie backups"].Path, Path.GetFileName(backupName));
|
||||
|
||||
var directoryInfo = new FileInfo(backupName).Directory;
|
||||
if (directoryInfo != null)
|
||||
{
|
||||
Directory.CreateDirectory(directoryInfo.FullName);
|
||||
}
|
||||
|
||||
Write(backupName);
|
||||
}
|
||||
|
||||
public bool Load(bool preload)
|
||||
{
|
||||
var file = new FileInfo(Filename);
|
||||
|
||||
if (file.Exists == false)
|
||||
{
|
||||
Loaded = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
Header.Clear();
|
||||
_log.Clear();
|
||||
|
||||
using (var sr = file.OpenText())
|
||||
{
|
||||
string line;
|
||||
|
||||
while ((line = sr.ReadLine()) != null)
|
||||
{
|
||||
if (line == "")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (line.Contains("LoopOffset"))
|
||||
{
|
||||
try
|
||||
{
|
||||
_loopOffset = int.Parse(line.Split(new[] { ' ' }, 2)[1]);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (Header.ParseLineFromFile(line))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (line.StartsWith("|"))
|
||||
{
|
||||
_log.Add(line);
|
||||
}
|
||||
else
|
||||
{
|
||||
Header.Comments.Add(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Header.SavestateBinaryBase64Blob != null)
|
||||
{
|
||||
BinarySavestate = Convert.FromBase64String(Header.SavestateBinaryBase64Blob);
|
||||
}
|
||||
|
||||
Loaded = true;
|
||||
_changes = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Load Header information only for displaying file information in dialogs such as play movie
|
||||
/// TODO - consider not loading the SavestateBinaryBase64Blob key?
|
||||
/// </summary>
|
||||
public bool PreLoadHeaderAndLength(HawkFile hawkFile)
|
||||
{
|
||||
Loaded = false;
|
||||
var file = new FileInfo(hawkFile.CanonicalFullPath);
|
||||
|
||||
if (file.Exists == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Header.Clear();
|
||||
_log.Clear();
|
||||
|
||||
var origStreamPosn = hawkFile.GetStream().Position;
|
||||
hawkFile.GetStream().Position = 0; // Reset to start
|
||||
|
||||
// No using block because we're sharing the stream and need to give it back undisposed.
|
||||
var sr = new StreamReader(hawkFile.GetStream());
|
||||
|
||||
for (;;)
|
||||
{
|
||||
// read to first space (key/value delimeter), or pipe, or EOF
|
||||
int first = sr.Read();
|
||||
|
||||
if (first == -1)
|
||||
{
|
||||
break;
|
||||
} // EOF
|
||||
|
||||
if (first == '|') // pipe: begin input log
|
||||
{
|
||||
// NOTE - this code is a bit convoluted due to its predating the basic outline of the parser which was upgraded in may 2014
|
||||
var line = '|' + sr.ReadLine();
|
||||
|
||||
// how many bytes are left, total?
|
||||
long remain = sr.BaseStream.Length - sr.BaseStream.Position;
|
||||
|
||||
// try to find out whether we use \r\n or \n
|
||||
// but only look for 1K characters.
|
||||
bool usesR = false;
|
||||
for (int i = 0; i < 1024; i++)
|
||||
{
|
||||
int c = sr.Read();
|
||||
if (c == -1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (c == '\r')
|
||||
{
|
||||
usesR = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (c == '\n')
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int lineLen = line.Length + 1; // account for \n
|
||||
if (usesR)
|
||||
{
|
||||
lineLen++; // account for \r
|
||||
}
|
||||
|
||||
_preloadFramecount = (int)(remain / lineLen); // length is remaining bytes / length per line
|
||||
_preloadFramecount++; // account for the current line
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
// a header line. finish reading key token, to make sure it isn't one of the FORBIDDEN keys
|
||||
var sbLine = new StringBuilder();
|
||||
sbLine.Append((char)first);
|
||||
for (;;)
|
||||
{
|
||||
int c = sr.Read();
|
||||
if (c == -1 || c == '\n' || c == ' ')
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
sbLine.Append((char)c);
|
||||
}
|
||||
|
||||
var line = sbLine.ToString();
|
||||
|
||||
// ignore these suckers, theyre way too big for preloading. seriously, we will get out of memory errors.
|
||||
var skip = line == HeaderKeys.SAVESTATEBINARYBASE64BLOB;
|
||||
|
||||
if (skip)
|
||||
{
|
||||
// skip remainder of the line
|
||||
sr.DiscardBufferedData();
|
||||
var stream = sr.BaseStream;
|
||||
for (;;)
|
||||
{
|
||||
int c = stream.ReadByte();
|
||||
if (c == -1 || c == '\n')
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// proceed to next line
|
||||
continue;
|
||||
}
|
||||
|
||||
var remainder = sr.ReadLine();
|
||||
sbLine.Append(' ');
|
||||
sbLine.Append(remainder);
|
||||
line = sbLine.ToString();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(line) || Header.ParseLineFromFile(line))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Header.Comments.Add(line);
|
||||
}
|
||||
}
|
||||
|
||||
hawkFile.GetStream().Position = origStreamPosn;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void Write(string fn)
|
||||
{
|
||||
Header.SavestateBinaryBase64Blob = BinarySavestate != null
|
||||
? Convert.ToBase64String(BinarySavestate)
|
||||
: null;
|
||||
|
||||
using (var fs = new FileStream(fn, FileMode.Create, FileAccess.Write, FileShare.Read))
|
||||
{
|
||||
using (var sw = new StreamWriter(fs))
|
||||
{
|
||||
sw.Write(Header.ToString());
|
||||
|
||||
// TODO: clean this up
|
||||
if (_loopOffset.HasValue)
|
||||
{
|
||||
sw.WriteLine($"LoopOffset {_loopOffset}");
|
||||
}
|
||||
|
||||
foreach (var input in _log)
|
||||
{
|
||||
sw.WriteLine(input);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_changes = false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,291 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace BizHawk.Client.Common
|
||||
{
|
||||
public partial class BkmMovie
|
||||
{
|
||||
private readonly List<string> _log = new List<string>();
|
||||
|
||||
public void WriteInputLog(TextWriter writer)
|
||||
{
|
||||
writer.WriteLine("[Input]");
|
||||
|
||||
foreach (var record in _log)
|
||||
{
|
||||
writer.WriteLine(record);
|
||||
}
|
||||
|
||||
writer.WriteLine("[/Input]");
|
||||
}
|
||||
|
||||
public string GetInputLogEntry(int frame)
|
||||
{
|
||||
if (frame < FrameCount && frame >= 0)
|
||||
{
|
||||
return _log[frame];
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
public bool ExtractInputLog(TextReader reader, out string errorMessage)
|
||||
{
|
||||
errorMessage = "";
|
||||
int? stateFrame = null;
|
||||
|
||||
// We are in record mode so replace the movie log with the one from the savestate
|
||||
if (!Global.MovieSession.MultiTrack.IsActive)
|
||||
{
|
||||
if (Global.Config.EnableBackupMovies && _makeBackup && _log.Any())
|
||||
{
|
||||
SaveBackup();
|
||||
_makeBackup = false;
|
||||
}
|
||||
|
||||
_log.Clear();
|
||||
while (true)
|
||||
{
|
||||
var line = reader.ReadLine();
|
||||
if (line == null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (line.Trim() == "" || line == "[Input]")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (line == "[/Input]")
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (line.Contains("Frame 0x")) // NES stores frame count in hex, yay
|
||||
{
|
||||
var strs = line.Split('x');
|
||||
try
|
||||
{
|
||||
stateFrame = int.Parse(strs[1], NumberStyles.HexNumber);
|
||||
}
|
||||
catch
|
||||
{
|
||||
errorMessage = "Savestate Frame number failed to parse";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (line.Contains("Frame "))
|
||||
{
|
||||
var strs = line.Split(' ');
|
||||
try
|
||||
{
|
||||
stateFrame = int.Parse(strs[1]);
|
||||
}
|
||||
catch
|
||||
{
|
||||
errorMessage = "Savestate Frame number failed to parse";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (line[0] == '|')
|
||||
{
|
||||
_log.Add(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var i = 0;
|
||||
while (true)
|
||||
{
|
||||
var line = reader.ReadLine();
|
||||
if (line == null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (line.Trim() == "" || line == "[Input]")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (line == "[/Input]")
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (line.Contains("Frame 0x")) // NES stores frame count in hex, yay
|
||||
{
|
||||
var strs = line.Split('x');
|
||||
try
|
||||
{
|
||||
stateFrame = int.Parse(strs[1], NumberStyles.HexNumber);
|
||||
}
|
||||
catch
|
||||
{
|
||||
errorMessage = "Savestate Frame number failed to parse";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (line.Contains("Frame "))
|
||||
{
|
||||
var strs = line.Split(' ');
|
||||
try
|
||||
{
|
||||
stateFrame = int.Parse(strs[1]);
|
||||
}
|
||||
catch
|
||||
{
|
||||
errorMessage = "Savestate Frame number failed to parse";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (line.StartsWith("|"))
|
||||
{
|
||||
SetFrameAt(i, line);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!stateFrame.HasValue)
|
||||
{
|
||||
errorMessage = "Savestate Frame number failed to parse";
|
||||
}
|
||||
|
||||
var stateFramei = stateFrame ?? 0;
|
||||
|
||||
if (stateFramei > 0 && stateFramei < _log.Count)
|
||||
{
|
||||
if (!Global.Config.VBAStyleMovieLoadState)
|
||||
{
|
||||
Truncate(stateFramei);
|
||||
}
|
||||
}
|
||||
else if (stateFramei > _log.Count) // Post movie savestate
|
||||
{
|
||||
if (!Global.Config.VBAStyleMovieLoadState)
|
||||
{
|
||||
Truncate(_log.Count);
|
||||
}
|
||||
|
||||
_mode = Moviemode.Finished;
|
||||
}
|
||||
|
||||
if (IsCountingRerecords)
|
||||
{
|
||||
Rerecords++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool CheckTimeLines(TextReader reader, out string errorMessage)
|
||||
{
|
||||
// This function will compare the movie data to the savestate movie data to see if they match
|
||||
errorMessage = "";
|
||||
var log = new List<string>();
|
||||
var stateFrame = 0;
|
||||
while (true)
|
||||
{
|
||||
var line = reader.ReadLine();
|
||||
if (line == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (line.Trim() == "")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (line.Contains("Frame 0x")) // NES stores frame count in hex, yay
|
||||
{
|
||||
var strs = line.Split('x');
|
||||
try
|
||||
{
|
||||
stateFrame = int.Parse(strs[1], NumberStyles.HexNumber);
|
||||
}
|
||||
catch
|
||||
{
|
||||
errorMessage = "Savestate Frame number failed to parse";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (line.Contains("Frame "))
|
||||
{
|
||||
var strs = line.Split(' ');
|
||||
try
|
||||
{
|
||||
stateFrame = int.Parse(strs[1]);
|
||||
}
|
||||
catch
|
||||
{
|
||||
errorMessage = "Savestate Frame number failed to parse";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (line == "[Input]")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (line == "[/Input]")
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (line[0] == '|')
|
||||
{
|
||||
log.Add(line);
|
||||
}
|
||||
}
|
||||
|
||||
if (stateFrame == 0)
|
||||
{
|
||||
stateFrame = log.Count; // In case the frame count failed to parse, revert to using the entire state input log
|
||||
}
|
||||
|
||||
if (_log.Count < stateFrame)
|
||||
{
|
||||
if (IsFinished)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
errorMessage = $"The savestate is from frame {log.Count} which is greater than the current movie length of {_log.Count}";
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
for (var i = 0; i < stateFrame; i++)
|
||||
{
|
||||
if (_log[i] != log[i])
|
||||
{
|
||||
errorMessage = $"The savestate input does not match the movie input at frame {(i + 1)}.";
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (stateFrame > log.Count) // stateFrame is greater than state input log, so movie finished mode
|
||||
{
|
||||
if (_mode == Moviemode.Play || _mode == Moviemode.Finished)
|
||||
{
|
||||
_mode = Moviemode.Finished;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_mode == Moviemode.Finished)
|
||||
{
|
||||
_mode = Moviemode.Play;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
using System.Linq;
|
||||
|
||||
namespace BizHawk.Client.Common
|
||||
{
|
||||
public partial class BkmMovie
|
||||
{
|
||||
private enum Moviemode
|
||||
{
|
||||
Inactive, Play, Record, Finished
|
||||
}
|
||||
|
||||
private Moviemode _mode = Moviemode.Inactive;
|
||||
|
||||
public bool IsPlaying => _mode == Moviemode.Play || _mode == Moviemode.Finished;
|
||||
|
||||
public bool IsRecording => _mode == Moviemode.Record;
|
||||
|
||||
public bool IsActive => _mode != Moviemode.Inactive;
|
||||
|
||||
public bool IsFinished => _mode == Moviemode.Finished;
|
||||
|
||||
public void StartNewRecording()
|
||||
{
|
||||
_mode = Moviemode.Record;
|
||||
if (Global.Config.EnableBackupMovies && _makeBackup && _log.Any())
|
||||
{
|
||||
SaveBackup();
|
||||
_makeBackup = false;
|
||||
}
|
||||
|
||||
_log.Clear();
|
||||
}
|
||||
|
||||
public void StartNewPlayback()
|
||||
{
|
||||
_mode = Moviemode.Play;
|
||||
}
|
||||
|
||||
public void SwitchToRecord()
|
||||
{
|
||||
_mode = Moviemode.Record;
|
||||
}
|
||||
|
||||
public void SwitchToPlay()
|
||||
{
|
||||
_mode = Moviemode.Play;
|
||||
Save();
|
||||
}
|
||||
|
||||
public bool Stop(bool saveChanges = true)
|
||||
{
|
||||
bool saved = false;
|
||||
if (saveChanges)
|
||||
{
|
||||
if (_mode == Moviemode.Record || _changes)
|
||||
{
|
||||
Save();
|
||||
saved = true;
|
||||
}
|
||||
}
|
||||
|
||||
_changes = false;
|
||||
_mode = Moviemode.Inactive;
|
||||
|
||||
return saved;
|
||||
}
|
||||
|
||||
public void FinishedMode()
|
||||
{
|
||||
_mode = Moviemode.Finished;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,52 +1,27 @@
|
|||
using BizHawk.Emulation.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace BizHawk.Client.Common
|
||||
{
|
||||
public partial class BkmMovie : IMovie
|
||||
internal class BkmMovie
|
||||
{
|
||||
private bool _makeBackup;
|
||||
private bool _changes;
|
||||
private readonly List<string> _log = new List<string>();
|
||||
private int? _loopOffset;
|
||||
|
||||
public BkmMovie(string filename)
|
||||
: this()
|
||||
{
|
||||
Rerecords = 0;
|
||||
Filename = filename;
|
||||
Loaded = !string.IsNullOrWhiteSpace(filename);
|
||||
}
|
||||
|
||||
public BkmMovie()
|
||||
{
|
||||
Header = new BkmHeader { [HeaderKeys.MOVIEVERSION] = "BizHawk v0.0.1" };
|
||||
Filename = "";
|
||||
_preloadFramecount = 0;
|
||||
|
||||
IsCountingRerecords = true;
|
||||
_mode = Moviemode.Inactive;
|
||||
_makeBackup = true;
|
||||
}
|
||||
|
||||
#region Properties
|
||||
|
||||
public ILogEntryGenerator LogGeneratorInstance()
|
||||
{
|
||||
return new BkmLogEntryGenerator();
|
||||
}
|
||||
|
||||
public string PreferredExtension => Extension;
|
||||
|
||||
public const string Extension = "bkm";
|
||||
public string PreferredExtension => "bkm";
|
||||
|
||||
public BkmHeader Header { get; }
|
||||
public string Filename { get; set; }
|
||||
public bool IsCountingRerecords { get; set; }
|
||||
public string Filename { get; set; } = "";
|
||||
public bool Loaded { get; private set; }
|
||||
|
||||
public int InputLogLength => _log.Count;
|
||||
|
||||
public int TimeLength => _log.Count;
|
||||
|
||||
public double FrameCount
|
||||
{
|
||||
get
|
||||
|
@ -61,114 +36,115 @@ namespace BizHawk.Client.Common
|
|||
return _log.Count;
|
||||
}
|
||||
|
||||
return _preloadFramecount;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Changes => _changes;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Log Editing
|
||||
|
||||
public IController GetInputState(int frame)
|
||||
public BkmControllerAdapter GetInputState(int frame)
|
||||
{
|
||||
if (frame < FrameCount && frame >= 0)
|
||||
{
|
||||
int getframe;
|
||||
int getFrame;
|
||||
|
||||
if (_loopOffset.HasValue)
|
||||
{
|
||||
if (frame < _log.Count)
|
||||
{
|
||||
getframe = frame;
|
||||
getFrame = frame;
|
||||
}
|
||||
else
|
||||
{
|
||||
getframe = ((frame - _loopOffset.Value) % (_log.Count - _loopOffset.Value)) + _loopOffset.Value;
|
||||
getFrame = ((frame - _loopOffset.Value) % (_log.Count - _loopOffset.Value)) + _loopOffset.Value;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
getframe = frame;
|
||||
getFrame = frame;
|
||||
}
|
||||
|
||||
var adapter = new BkmControllerAdapter
|
||||
{
|
||||
Definition = Global.MovieSession.MovieControllerAdapter.Definition
|
||||
};
|
||||
adapter.SetControllersAsMnemonic(_log[getframe]);
|
||||
adapter.SetControllersAsMnemonic(_log[getFrame]);
|
||||
return adapter;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void ClearFrame(int frame)
|
||||
public IDictionary<string, string> HeaderEntries => Header;
|
||||
|
||||
public SubtitleList Subtitles => Header.Subtitles;
|
||||
|
||||
public IList<string> Comments => Header.Comments;
|
||||
|
||||
public string SyncSettingsJson
|
||||
{
|
||||
var lg = LogGeneratorInstance();
|
||||
SetFrameAt(frame, lg.EmptyEntry);
|
||||
_changes = true;
|
||||
get => Header[HeaderKeys.SYNCSETTINGS];
|
||||
set => Header[HeaderKeys.SYNCSETTINGS] = value;
|
||||
}
|
||||
|
||||
public void AppendFrame(IController source)
|
||||
{
|
||||
var lg = LogGeneratorInstance();
|
||||
lg.SetSource(source);
|
||||
_log.Add(lg.GenerateLogEntry());
|
||||
_changes = true;
|
||||
}
|
||||
public string TextSavestate { get; set; }
|
||||
public byte[] BinarySavestate { get; set; }
|
||||
|
||||
public void Truncate(int frame)
|
||||
public bool Load()
|
||||
{
|
||||
if (frame < _log.Count)
|
||||
var file = new FileInfo(Filename);
|
||||
|
||||
if (file.Exists == false)
|
||||
{
|
||||
_log.RemoveRange(frame, _log.Count - frame);
|
||||
_changes = true;
|
||||
Loaded = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void PokeFrame(int frame, IController source)
|
||||
{
|
||||
var lg = LogGeneratorInstance();
|
||||
lg.SetSource(source);
|
||||
Header.Clear();
|
||||
_log.Clear();
|
||||
|
||||
_changes = true;
|
||||
SetFrameAt(frame, lg.GenerateLogEntry());
|
||||
}
|
||||
|
||||
public void RecordFrame(int frame, IController source)
|
||||
{
|
||||
// Note: Truncation here instead of loadstate will make VBA style loadstates
|
||||
// (Where an entire movie is loaded then truncated on the next frame
|
||||
// this allows users to restore a movie with any savestate from that "timeline"
|
||||
if (Global.Config.VBAStyleMovieLoadState)
|
||||
using (var sr = file.OpenText())
|
||||
{
|
||||
if (Global.Emulator.Frame < _log.Count)
|
||||
string line;
|
||||
|
||||
while ((line = sr.ReadLine()) != null)
|
||||
{
|
||||
Truncate(Global.Emulator.Frame);
|
||||
if (line == "")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (line.Contains("LoopOffset"))
|
||||
{
|
||||
try
|
||||
{
|
||||
_loopOffset = int.Parse(line.Split(new[] { ' ' }, 2)[1]);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (Header.ParseLineFromFile(line))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (line.StartsWith("|"))
|
||||
{
|
||||
_log.Add(line);
|
||||
}
|
||||
else
|
||||
{
|
||||
Header.Comments.Add(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var lg = LogGeneratorInstance();
|
||||
lg.SetSource(source);
|
||||
SetFrameAt(frame, lg.GenerateLogEntry());
|
||||
|
||||
_changes = true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private void SetFrameAt(int frameNum, string frame)
|
||||
{
|
||||
if (_log.Count > frameNum)
|
||||
if (Header.SavestateBinaryBase64Blob != null)
|
||||
{
|
||||
_log[frameNum] = frame;
|
||||
}
|
||||
else
|
||||
{
|
||||
_log.Add(frame);
|
||||
BinarySavestate = Convert.FromBase64String(Header.SavestateBinaryBase64Blob);
|
||||
}
|
||||
|
||||
Loaded = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,8 +13,46 @@ namespace BizHawk.Client.Common.movie.import
|
|||
Filename = SourceFile.FullName
|
||||
};
|
||||
|
||||
movie.Load(false);
|
||||
Result.Movie = movie.ToBk2();
|
||||
movie.Load();
|
||||
Result.Movie = ToBk2(movie);
|
||||
}
|
||||
|
||||
public static Bk2Movie ToBk2(BkmMovie old)
|
||||
{
|
||||
var bk2 = new Bk2Movie(old.Filename.Replace(old.PreferredExtension, Bk2Movie.Extension));
|
||||
|
||||
for (var i = 0; i < old.InputLogLength; i++)
|
||||
{
|
||||
var input = old.GetInputState(i);
|
||||
bk2.AppendFrame(input);
|
||||
}
|
||||
|
||||
bk2.HeaderEntries.Clear();
|
||||
foreach (var kvp in old.HeaderEntries)
|
||||
{
|
||||
bk2.HeaderEntries[kvp.Key] = kvp.Value;
|
||||
}
|
||||
|
||||
bk2.SyncSettingsJson = old.SyncSettingsJson;
|
||||
|
||||
bk2.Comments.Clear();
|
||||
foreach (var comment in old.Comments)
|
||||
{
|
||||
bk2.Comments.Add(comment);
|
||||
}
|
||||
|
||||
bk2.Subtitles.Clear();
|
||||
foreach (var sub in old.Subtitles)
|
||||
{
|
||||
bk2.Subtitles.Add(sub);
|
||||
}
|
||||
|
||||
bk2.TextSavestate = old.TextSavestate;
|
||||
bk2.BinarySavestate = old.BinarySavestate;
|
||||
|
||||
bk2.Save();
|
||||
|
||||
return bk2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue