Skip to content

Commit

Permalink
Add SV 2.0.1 and DLC support (#161)
Browse files Browse the repository at this point in the history
Closes #160
  • Loading branch information
LegoFigure11 authored Sep 20, 2023
2 parents 57b45d4 + f0452be commit 7386834
Show file tree
Hide file tree
Showing 49 changed files with 3,669 additions and 872 deletions.
139 changes: 111 additions & 28 deletions RaidCrawler.Core/Connection/ConnectionWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ namespace RaidCrawler.Core.Connection
public class ConnectionWrapperAsync : Offsets
{
public readonly ISwitchConnectionAsync Connection;
public bool Connected { get => Connection is not null && IsConnected; }
public bool Connected
{
get => Connection is not null && IsConnected;
}
private bool IsConnected { get; set; }
private readonly bool CRLF;
private readonly Action<string> _statusUpdate;
Expand All @@ -38,7 +41,9 @@ public ConnectionWrapperAsync(SwitchConnectionConfig config, Action<string> stat
{
_statusUpdate("Connecting...");
Connection.Connect();
BaseBlockKeyPointer = await Connection.PointerAll(BlockKeyPointer, token).ConfigureAwait(false);
BaseBlockKeyPointer = await Connection
.PointerAll(BlockKeyPointer, token)
.ConfigureAwait(false);
IsConnected = true;
_statusUpdate("Connected!");
return (true, "");
Expand All @@ -58,7 +63,9 @@ public ConnectionWrapperAsync(SwitchConnectionConfig config, Action<string> stat
try
{
_statusUpdate("Disconnecting controller...");
await Connection.SendAsync(SwitchCommand.DetachController(CRLF), token).ConfigureAwait(false);
await Connection
.SendAsync(SwitchCommand.DetachController(CRLF), token)
.ConfigureAwait(false);

_statusUpdate("Disconnecting...");
Connection.Disconnect();
Expand Down Expand Up @@ -88,28 +95,43 @@ public async Task<int> GetStoryProgress(CancellationToken token)
private async Task<byte[]> ReadSaveBlock(uint key, int size, CancellationToken token)
{
var block_ofs = await SearchSaveKey(key, token).ConfigureAwait(false);
var data = await Connection.ReadBytesAbsoluteAsync(block_ofs + 8, 0x8, token).ConfigureAwait(false);
var data = await Connection
.ReadBytesAbsoluteAsync(block_ofs + 8, 0x8, token)
.ConfigureAwait(false);
block_ofs = BitConverter.ToUInt64(data, 0);

var block = await Connection.ReadBytesAbsoluteAsync(block_ofs, size, token).ConfigureAwait(false);
var block = await Connection
.ReadBytesAbsoluteAsync(block_ofs, size, token)
.ConfigureAwait(false);
return DecryptBlock(key, block);
}

private async Task<byte[]> ReadSaveBlockObject(uint key, CancellationToken token)
{
var header_ofs = await SearchSaveKey(key, token).ConfigureAwait(false);
var data = await Connection.ReadBytesAbsoluteAsync(header_ofs + 8, 8, token).ConfigureAwait(false);
var data = await Connection
.ReadBytesAbsoluteAsync(header_ofs + 8, 8, token)
.ConfigureAwait(false);
header_ofs = BitConverter.ToUInt64(data);

var header = await Connection.ReadBytesAbsoluteAsync(header_ofs, 5, token).ConfigureAwait(false);
var header = await Connection
.ReadBytesAbsoluteAsync(header_ofs, 5, token)
.ConfigureAwait(false);
header = DecryptBlock(key, header);

var size = BitConverter.ToUInt32(header.AsSpan()[1..]);
var obj = await Connection.ReadBytesAbsoluteAsync(header_ofs, (int)size + 5, token).ConfigureAwait(false);
var obj = await Connection
.ReadBytesAbsoluteAsync(header_ofs, (int)size + 5, token)
.ConfigureAwait(false);
return DecryptBlock(key, obj)[5..];
}

public async Task<byte[]> ReadBlockDefault(uint key, string? cache, bool force, CancellationToken token)
public async Task<byte[]> ReadBlockDefault(
uint key,
string? cache,
bool force,
CancellationToken token
)
{
var folder = Path.Combine(Directory.GetCurrentDirectory(), "cache");
Directory.CreateDirectory(folder);
Expand All @@ -125,7 +147,9 @@ public async Task<byte[]> ReadBlockDefault(uint key, string? cache, bool force,

private async Task<ulong> SearchSaveKey(uint key, CancellationToken token)
{
var data = await Connection.ReadBytesAbsoluteAsync(BaseBlockKeyPointer + 8, 16, token).ConfigureAwait(false);
var data = await Connection
.ReadBytesAbsoluteAsync(BaseBlockKeyPointer + 8, 16, token)
.ConfigureAwait(false);
var start = BitConverter.ToUInt64(data.AsSpan()[..8]);
var end = BitConverter.ToUInt64(data.AsSpan()[8..]);

Expand All @@ -141,7 +165,8 @@ private async Task<ulong> SearchSaveKey(uint key, CancellationToken token)

if (found >= key)
end = mid;
else start = mid + 48;
else
start = mid + 48;
}
return start;
}
Expand All @@ -156,26 +181,46 @@ private static byte[] DecryptBlock(uint key, byte[] block)

private async Task Click(SwitchButton button, int delay, CancellationToken token)
{
await Connection.SendAsync(SwitchCommand.Click(button, CRLF), token).ConfigureAwait(false);
await Connection
.SendAsync(SwitchCommand.Click(button, CRLF), token)
.ConfigureAwait(false);
await Task.Delay(delay, token).ConfigureAwait(false);
}

private async Task Touch(int x, int y, int hold, int delay, CancellationToken token)
{
var command = Encoding.ASCII.GetBytes($"touchHold {x} {y} {hold}{(CRLF ? "\r\n" : "")}");
var command = Encoding.ASCII.GetBytes(
$"touchHold {x} {y} {hold}{(CRLF ? "\r\n" : "")}"
);
await Connection.SendAsync(command, token).ConfigureAwait(false);
await Task.Delay(delay, token).ConfigureAwait(false);
}

private async Task SetStick(SwitchStick stick, short x, short y, int hold, int delay, CancellationToken token)
private async Task SetStick(
SwitchStick stick,
short x,
short y,
int hold,
int delay,
CancellationToken token
)
{
await Connection.SendAsync(SwitchCommand.SetStick(stick, x, y, CRLF), token).ConfigureAwait(false);
await Connection
.SendAsync(SwitchCommand.SetStick(stick, x, y, CRLF), token)
.ConfigureAwait(false);
await Task.Delay(hold, token).ConfigureAwait(false);
await Connection.SendAsync(SwitchCommand.SetStick(stick, 0, 0, CRLF), token).ConfigureAwait(false);
await Connection
.SendAsync(SwitchCommand.SetStick(stick, 0, 0, CRLF), token)
.ConfigureAwait(false);
await Task.Delay(delay, token).ConfigureAwait(false);
}

private async Task PressAndHold(SwitchButton b, int hold, int delay, CancellationToken token)
private async Task PressAndHold(
SwitchButton b,
int hold,
int delay,
CancellationToken token
)
{
await Connection.SendAsync(SwitchCommand.Hold(b, CRLF), token).ConfigureAwait(false);
await Task.Delay(hold, token).ConfigureAwait(false);
Expand All @@ -184,10 +229,18 @@ private async Task PressAndHold(SwitchButton b, int hold, int delay, Cancellatio
}

// Thank you to Anubis for sharing a more optimized routine, as well as CloseGame(), StartGame(), and SaveGame()!
public async Task AdvanceDate(IDateAdvanceConfig config, CancellationToken token, Action<int>? action = null)
public async Task AdvanceDate(
IDateAdvanceConfig config,
CancellationToken token,
Action<int>? action = null
)
{
// Not great, but when adding/removing clicks, make sure to account for command count for an accurate StreamerView progress bar.
int steps = (config.UseTouch ? 19 : 25) + (config.UseOvershoot ? 2 : config.SystemDownPresses) + (config.DodgeSystemUpdate ? 2 : 0) + config.DaysToSkip;
int steps =
(config.UseTouch ? 19 : 25)
+ (config.UseOvershoot ? 2 : config.SystemDownPresses)
+ (config.DodgeSystemUpdate ? 2 : 0)
+ config.DaysToSkip;

_statusUpdate("Changing date...");
var BaseDelay = config.BaseDelay;
Expand All @@ -211,12 +264,14 @@ public async Task AdvanceDate(IDateAdvanceConfig config, CancellationToken token
}
else
{
await Click(DDOWN, config.NavigateToSettingsDelay + BaseDelay, token).ConfigureAwait(false);
await Click(DDOWN, config.NavigateToSettingsDelay + BaseDelay, token)
.ConfigureAwait(false);
UpdateProgressBar(action, steps);

for (int i = 0; i < 5; i++)
{
await Click(DRIGHT, config.NavigateToSettingsDelay + BaseDelay, token).ConfigureAwait(false);
await Click(DRIGHT, config.NavigateToSettingsDelay + BaseDelay, token)
.ConfigureAwait(false);
UpdateProgressBar(action, steps);
}
}
Expand All @@ -226,8 +281,18 @@ public async Task AdvanceDate(IDateAdvanceConfig config, CancellationToken token

// Scroll to bottom
if (config.UseSetStick)
await SetStick(SwitchStick.LEFT, 0, -30_000, config.HoldDuration, 0_100 + BaseDelay, token).ConfigureAwait(false);
else await PressAndHold(DDOWN, config.HoldDuration, 0_100 + BaseDelay, token).ConfigureAwait(false);
await SetStick(
SwitchStick.LEFT,
0,
-30_000,
config.HoldDuration,
0_100 + BaseDelay,
token
)
.ConfigureAwait(false);
else
await PressAndHold(DDOWN, config.HoldDuration, 0_100 + BaseDelay, token)
.ConfigureAwait(false);
UpdateProgressBar(action, steps);

// Navigate to "Date and Time"
Expand All @@ -239,8 +304,18 @@ public async Task AdvanceDate(IDateAdvanceConfig config, CancellationToken token
if (config.UseOvershoot)
{
if (config.UseSetStick)
await SetStick(SwitchStick.LEFT, 0, -30_000, config.SystemOvershoot, 0_100 + BaseDelay, token).ConfigureAwait(false);
else await PressAndHold(DDOWN, config.SystemOvershoot, 0_100 + BaseDelay, token).ConfigureAwait(false);
await SetStick(
SwitchStick.LEFT,
0,
-30_000,
config.SystemOvershoot,
0_100 + BaseDelay,
token
)
.ConfigureAwait(false);
else
await PressAndHold(DDOWN, config.SystemOvershoot, 0_100 + BaseDelay, token)
.ConfigureAwait(false);
UpdateProgressBar(action, steps);

await Click(DUP, 0_500 + BaseDelay, token).ConfigureAwait(false);
Expand Down Expand Up @@ -285,7 +360,8 @@ public async Task AdvanceDate(IDateAdvanceConfig config, CancellationToken token

for (int i = 0; i < 6; i++)
{
await Click(DRIGHT, (i < 5 ? 0_050 : 0_100) + BaseDelay, token).ConfigureAwait(false);
await Click(DRIGHT, (i < 5 ? 0_050 : 0_100) + BaseDelay, token)
.ConfigureAwait(false);
UpdateProgressBar(action, steps);
}

Expand All @@ -296,7 +372,12 @@ public async Task AdvanceDate(IDateAdvanceConfig config, CancellationToken token
await Click(HOME, config.ReturnHomeDelay + BaseDelay, token).ConfigureAwait(false);
UpdateProgressBar(action, steps);

await Click(HOME, (config.DodgeSystemUpdate ? 0_500 : config.ReturnGameDelay) + BaseDelay, token).ConfigureAwait(false);
await Click(
HOME,
(config.DodgeSystemUpdate ? 0_500 : config.ReturnGameDelay) + BaseDelay,
token
)
.ConfigureAwait(false);
UpdateProgressBar(action, steps);

if (config.DodgeSystemUpdate)
Expand Down Expand Up @@ -345,7 +426,9 @@ public async Task StartGame(CancellationToken token)
await Click(A, 1_000, token).ConfigureAwait(false);

_statusUpdate("Back in the overworld! Refreshing the base block key pointer...");
BaseBlockKeyPointer = await Connection.PointerAll(BlockKeyPointer, token).ConfigureAwait(false);
BaseBlockKeyPointer = await Connection
.PointerAll(BlockKeyPointer, token)
.ConfigureAwait(false);
}

public async Task SaveGame(IDateAdvanceConfig config, CancellationToken token)
Expand Down
Loading

0 comments on commit 7386834

Please sign in to comment.