mirror of
https://github.com/stenzek/duckstation.git
synced 2024-11-22 21:39:40 +00:00
WIP
This commit is contained in:
parent
0110295f2c
commit
e9413f6d94
@ -186,10 +186,68 @@ std::string EncodeHex(const u8* data, int length)
|
||||
std::stringstream ss;
|
||||
for (int i = 0; i < length; i++)
|
||||
ss << std::hex << std::setfill('0') << std::setw(2) << static_cast<int>(data[i]);
|
||||
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
void TrimWhitespace(std::string& str)
|
||||
{
|
||||
size_t pos = 0;
|
||||
while (pos < str.size() && std::isspace(str[pos]))
|
||||
pos++;
|
||||
|
||||
if (pos > 0)
|
||||
str.erase(0, pos);
|
||||
|
||||
while (!str.empty() && std::isspace(str.back()))
|
||||
str.pop_back();
|
||||
}
|
||||
|
||||
std::string_view TrimWhitespace(const std::string_view& str)
|
||||
{
|
||||
if (str.empty())
|
||||
return {};
|
||||
|
||||
size_t start_pos = 0;
|
||||
while (start_pos < str.size() && std::isspace(str[start_pos]))
|
||||
start_pos++;
|
||||
|
||||
if (start_pos == str.size())
|
||||
return {};
|
||||
|
||||
size_t end_pos = str.size() - 1;
|
||||
while (end_pos > start_pos && std::isspace(str[end_pos]))
|
||||
end_pos--;
|
||||
|
||||
return str.substr(start_pos, end_pos - start_pos + 1);
|
||||
}
|
||||
|
||||
void SplitString(const std::string_view& str, char delim, std::vector<std::string_view>* tokens)
|
||||
{
|
||||
tokens->clear();
|
||||
|
||||
std::string::size_type start_pos = 0;
|
||||
std::string::size_type current_pos = 0;
|
||||
while (current_pos < str.size())
|
||||
{
|
||||
if (str[current_pos] != delim)
|
||||
{
|
||||
current_pos++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (current_pos != start_pos)
|
||||
tokens->push_back(str.substr(start_pos, current_pos - start_pos));
|
||||
else
|
||||
tokens->emplace_back();
|
||||
|
||||
start_pos = ++current_pos;
|
||||
}
|
||||
|
||||
if (start_pos != current_pos)
|
||||
tokens->push_back(str.substr(start_pos, current_pos - start_pos));
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
std::wstring UTF8StringToWideString(const std::string_view& str)
|
||||
|
@ -118,6 +118,13 @@ inline std::optional<bool> FromChars(const std::string_view& str, int base)
|
||||
std::optional<std::vector<u8>> DecodeHex(const std::string_view& str);
|
||||
std::string EncodeHex(const u8* data, int length);
|
||||
|
||||
/// Trims whitespace characters
|
||||
void TrimWhitespace(std::string& str);
|
||||
std::string_view TrimWhitespace(const std::string_view& str);
|
||||
|
||||
/// Splits a string into tokens.
|
||||
void SplitString(const std::string_view& str, char delim, std::vector<std::string_view>* tokens);
|
||||
|
||||
/// starts_with from C++20
|
||||
ALWAYS_INLINE static bool StartsWith(const std::string_view& str, const char* prefix)
|
||||
{
|
||||
|
@ -697,6 +697,8 @@ TickCount CDROM::GetTicksForSeek(CDImage::LBA new_lba)
|
||||
ticks += static_cast<u32>(static_cast<double>(tps) * 0.1);
|
||||
}
|
||||
|
||||
ticks = 20000;
|
||||
|
||||
Log_DevPrintf("Seek time for %u LBAs: %d", lba_diff, ticks);
|
||||
return ticks;
|
||||
}
|
||||
|
@ -136,6 +136,7 @@
|
||||
<ClCompile Include="mdec.cpp" />
|
||||
<ClCompile Include="memory_card.cpp" />
|
||||
<ClCompile Include="memory_card_image.cpp" />
|
||||
<ClCompile Include="movie.cpp" />
|
||||
<ClCompile Include="namco_guncon.cpp" />
|
||||
<ClCompile Include="negcon.cpp" />
|
||||
<ClCompile Include="pad.cpp" />
|
||||
@ -213,6 +214,7 @@
|
||||
<ClInclude Include="mdec.h" />
|
||||
<ClInclude Include="memory_card.h" />
|
||||
<ClInclude Include="memory_card_image.h" />
|
||||
<ClInclude Include="movie.h" />
|
||||
<ClInclude Include="namco_guncon.h" />
|
||||
<ClInclude Include="negcon.h" />
|
||||
<ClInclude Include="pad.h" />
|
||||
|
@ -57,6 +57,7 @@
|
||||
<ClCompile Include="libcrypt_game_codes.cpp" />
|
||||
<ClCompile Include="texture_replacements.cpp" />
|
||||
<ClCompile Include="gdb_protocol.h" />
|
||||
<ClCompile Include="movie.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="types.h" />
|
||||
@ -116,5 +117,6 @@
|
||||
<ClInclude Include="libcrypt_game_codes.h" />
|
||||
<ClInclude Include="texture_replacements.h" />
|
||||
<ClInclude Include="shader_cache_version.h" />
|
||||
<ClInclude Include="movie.h" />
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -112,6 +112,16 @@ bool DigitalController::Transfer(const u8 data_in, u8* data_out)
|
||||
|
||||
case TransferState::ButtonsLSB:
|
||||
{
|
||||
System::InputPolled();
|
||||
{
|
||||
for (u32 i = 0; i < 16; i++)
|
||||
{
|
||||
if (m_button_state & (1 << i))
|
||||
continue;
|
||||
|
||||
printf("Button %u was down on poll\n", i);
|
||||
}
|
||||
}
|
||||
*data_out = Truncate8(m_button_state) & GetButtonsLSBMask();
|
||||
m_transfer_state = TransferState::ButtonsMSB;
|
||||
return true;
|
||||
|
244
src/core/movie.cpp
Normal file
244
src/core/movie.cpp
Normal file
@ -0,0 +1,244 @@
|
||||
#include "movie.h"
|
||||
#include "common/file_system.h"
|
||||
#include "common/log.h"
|
||||
#include "common/string_util.h"
|
||||
#include "controller.h"
|
||||
#include "pad.h"
|
||||
#include "settings.h"
|
||||
#include "system.h"
|
||||
#include <sstream>
|
||||
Log_SetChannel(Movie);
|
||||
|
||||
Movie::Movie() = default;
|
||||
|
||||
Movie::~Movie() = default;
|
||||
|
||||
void Movie::Rewind()
|
||||
{
|
||||
m_current_frame = START_OF_MOVIE;
|
||||
}
|
||||
|
||||
void Movie::NextFrame()
|
||||
{
|
||||
if (m_current_frame == m_num_frames)
|
||||
return;
|
||||
|
||||
m_current_frame++;
|
||||
ApplyInputsForFrame(m_current_frame);
|
||||
}
|
||||
|
||||
void Movie::ApplyInputsForFrame(u32 frame_number)
|
||||
{
|
||||
if (frame_number >= m_num_frames)
|
||||
return;
|
||||
|
||||
const std::size_t start_index = frame_number * m_input_mappings.size();
|
||||
Assert((start_index + m_input_mappings.size()) <= m_input_values.size());
|
||||
|
||||
std::size_t index = start_index;
|
||||
for (const InputMapping& im : m_input_mappings)
|
||||
{
|
||||
const s8 value = m_input_values[index++];
|
||||
switch (im.type)
|
||||
{
|
||||
case InputMapping::Type::Button:
|
||||
{
|
||||
Controller* controller = g_pad.GetController(im.controller_index);
|
||||
if (controller)
|
||||
{
|
||||
if (value != 0)
|
||||
Log_InfoPrintf("Frame %u button %d down", frame_number + 1, im.axis_or_button_code);
|
||||
|
||||
controller->SetButtonState(im.axis_or_button_code, (value != 0));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<Movie> Movie::Load(const char* filename)
|
||||
{
|
||||
std::unique_ptr<Movie> movie = std::unique_ptr<Movie>(new Movie());
|
||||
if (!movie->LoadBk2(filename))
|
||||
return {};
|
||||
|
||||
return movie;
|
||||
}
|
||||
|
||||
bool Movie::LoadBk2(const char* filename)
|
||||
{
|
||||
std::optional<std::string> data = FileSystem::ReadFileToString(filename);
|
||||
if (!data.has_value() || data->empty())
|
||||
return false;
|
||||
|
||||
return LoadBk2Txt(data.value());
|
||||
}
|
||||
|
||||
static void SplitBk2InputString(const std::string_view& str, char delim, std::vector<std::string_view>* tokens)
|
||||
{
|
||||
tokens->clear();
|
||||
|
||||
std::string::size_type start_pos = 0;
|
||||
std::string::size_type current_pos = 0;
|
||||
while (current_pos < str.size())
|
||||
{
|
||||
if (str[current_pos] == ' ' || str[current_pos] == ',' || str[current_pos] == '|')
|
||||
{
|
||||
if (current_pos != start_pos)
|
||||
tokens->push_back(str.substr(start_pos, current_pos - start_pos));
|
||||
|
||||
current_pos++;
|
||||
start_pos = current_pos;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (str[current_pos] >= '0' && str[current_pos] <= '9')
|
||||
{
|
||||
current_pos++;
|
||||
continue;
|
||||
}
|
||||
|
||||
current_pos++;
|
||||
tokens->push_back(str.substr(start_pos, current_pos - start_pos));
|
||||
start_pos = current_pos;
|
||||
}
|
||||
|
||||
if (start_pos != current_pos)
|
||||
tokens->push_back(str.substr(start_pos, current_pos - start_pos));
|
||||
}
|
||||
|
||||
bool Movie::LoadBk2Txt(const std::string& data)
|
||||
{
|
||||
std::istringstream iss(data);
|
||||
|
||||
std::string line;
|
||||
std::vector<std::string_view> tokens;
|
||||
bool in_input_section = false;
|
||||
while (std::getline(iss, line))
|
||||
{
|
||||
StringUtil::TrimWhitespace(line);
|
||||
if (line.empty())
|
||||
continue;
|
||||
|
||||
if (line == "[Input]")
|
||||
{
|
||||
in_input_section = true;
|
||||
continue;
|
||||
}
|
||||
else if (line == "[/Input]")
|
||||
{
|
||||
in_input_section = false;
|
||||
break;
|
||||
}
|
||||
else if (!in_input_section)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (StringUtil::StartsWith(line, "LogKey:") && line.size() >= 8)
|
||||
{
|
||||
// parse key - extra character here for the terminating |
|
||||
const std::string_view sv(line.c_str() + 7, line.size() - 8);
|
||||
StringUtil::SplitString(sv, '|', &tokens);
|
||||
for (const std::string_view& token : tokens)
|
||||
{
|
||||
InputMapping mapping = {};
|
||||
mapping.type = InputMapping::Type::None;
|
||||
|
||||
if (token.size() > 2 && token[0] == 'P' && token[1] >= '1' && token[1] <= '2' && token[2] == ' ')
|
||||
{
|
||||
mapping.controller_index = token[1] - '1';
|
||||
|
||||
const ControllerType ctype = g_settings.controller_types[mapping.controller_index];
|
||||
if (ctype != ControllerType::None)
|
||||
{
|
||||
const std::string_view& bsv(token.substr(3));
|
||||
const Controller::ButtonList blist(Controller::GetButtonNames(ctype));
|
||||
for (const auto& it : blist)
|
||||
{
|
||||
if (bsv == it.first)
|
||||
{
|
||||
mapping.axis_or_button_code = it.second;
|
||||
mapping.type = InputMapping::Type::Button;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (mapping.type == InputMapping::Type::None)
|
||||
Log_WarningPrintf("Input '%s' was not mapped", std::string(token).c_str());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log_WarningPrintf("Unhandled key token '%s'", std::string(token).c_str());
|
||||
}
|
||||
|
||||
m_input_mappings.push_back(mapping);
|
||||
}
|
||||
}
|
||||
else if (line.size() >= 2 && line.front() == '|' && line.back() == '|')
|
||||
{
|
||||
if (m_input_mappings.empty())
|
||||
{
|
||||
Log_ErrorPrintf("Mappings not set");
|
||||
return false;
|
||||
}
|
||||
|
||||
// parse line
|
||||
const std::string_view sv(line.c_str() + 1, line.size() - 2);
|
||||
SplitBk2InputString(sv, ',', &tokens);
|
||||
if (tokens.size() != m_input_mappings.size())
|
||||
{
|
||||
Log_ErrorPrintf("Incorrect number of mappings: got %zu expected %zu", tokens.size(), m_input_mappings.size());
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const std::string_view& token : tokens)
|
||||
{
|
||||
const std::string_view& trimmed_token(StringUtil::TrimWhitespace(token));
|
||||
if (trimmed_token.empty())
|
||||
{
|
||||
// ???
|
||||
m_input_values.push_back(0);
|
||||
}
|
||||
else if (trimmed_token[0] == '.')
|
||||
{
|
||||
// button off
|
||||
m_input_values.push_back(0);
|
||||
}
|
||||
else if (trimmed_token[0] < '0' || trimmed_token[0] > '1')
|
||||
{
|
||||
// button on
|
||||
m_input_values.push_back(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
const s32 value = StringUtil::FromChars<s32>(trimmed_token).value_or(0);
|
||||
m_input_values.push_back(static_cast<s8>(std::clamp<s32>(value, -127, 128)));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log_ErrorPrintf("Malformed line: '%s'", line.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_input_mappings.empty())
|
||||
{
|
||||
Log_ErrorPrintf("Missing input mapping");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_num_frames = static_cast<u32>(m_input_values.size() / m_input_mappings.size());
|
||||
if (m_num_frames == 0)
|
||||
{
|
||||
Log_ErrorPrintf("Missing input data");
|
||||
return false;
|
||||
}
|
||||
|
||||
Log_InfoPrintf("Mapped %zu inputs", m_input_mappings.size());
|
||||
Log_InfoPrintf("Loaded inputs for %u frames", m_num_frames);
|
||||
return true;
|
||||
}
|
56
src/core/movie.h
Normal file
56
src/core/movie.h
Normal file
@ -0,0 +1,56 @@
|
||||
#pragma once
|
||||
#include "types.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
class Movie
|
||||
{
|
||||
public:
|
||||
~Movie();
|
||||
|
||||
static std::unique_ptr<Movie> Load(const char* filename);
|
||||
|
||||
ALWAYS_INLINE u32 GetNumFrames() const { return m_num_frames; }
|
||||
ALWAYS_INLINE bool AtEnd() const { return (m_current_frame == m_num_frames); }
|
||||
|
||||
void Rewind();
|
||||
void NextFrame();
|
||||
|
||||
private:
|
||||
enum : u32
|
||||
{
|
||||
START_OF_MOVIE = 0xFFFFFFFFu
|
||||
};
|
||||
|
||||
using InputValue = s8;
|
||||
|
||||
struct InputMapping
|
||||
{
|
||||
enum class Type
|
||||
{
|
||||
None,
|
||||
DiscSelect,
|
||||
DiscOpen,
|
||||
DiscClose,
|
||||
DiscReset,
|
||||
Button,
|
||||
Axis,
|
||||
};
|
||||
|
||||
Type type;
|
||||
u32 controller_index;
|
||||
s32 axis_or_button_code;
|
||||
};
|
||||
|
||||
Movie();
|
||||
|
||||
bool LoadBk2(const char* filename);
|
||||
bool LoadBk2Txt(const std::string& data);
|
||||
void ApplyInputsForFrame(u32 frame_number);
|
||||
|
||||
std::vector<InputMapping> m_input_mappings;
|
||||
std::vector<InputValue> m_input_values;
|
||||
u32 m_num_frames = 0;
|
||||
u32 m_current_frame = START_OF_MOVIE;
|
||||
};
|
@ -30,6 +30,7 @@
|
||||
#include "spu.h"
|
||||
#include "texture_replacements.h"
|
||||
#include "timers.h"
|
||||
#include "movie.h"
|
||||
#include <cctype>
|
||||
#include <cinttypes>
|
||||
#include <cmath>
|
||||
@ -119,6 +120,7 @@ static std::vector<std::string> s_media_playlist;
|
||||
static std::string s_media_playlist_filename;
|
||||
|
||||
static std::unique_ptr<CheatList> s_cheat_list;
|
||||
static std::unique_ptr<Movie> s_movie;
|
||||
|
||||
static bool s_memory_saves_enabled = false;
|
||||
|
||||
@ -220,6 +222,15 @@ void IncrementInternalFrameNumber()
|
||||
s_internal_frame_number++;
|
||||
}
|
||||
|
||||
void InputPolled()
|
||||
{
|
||||
#if 1
|
||||
if (s_movie)
|
||||
s_movie->NextFrame();
|
||||
#endif
|
||||
Log_InfoPrintf("Input polled at frame %u", s_frame_number);
|
||||
}
|
||||
|
||||
const std::string& GetRunningPath()
|
||||
{
|
||||
return s_running_game_path;
|
||||
@ -773,6 +784,9 @@ bool Boot(const SystemBootParameters& params)
|
||||
|
||||
// Good to go.
|
||||
s_state = (g_settings.start_paused || params.override_start_paused.value_or(false)) ? State::Paused : State::Running;
|
||||
|
||||
s_movie = Movie::Load("D:\\test.txt");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1264,6 +1278,11 @@ void SingleStepCPU()
|
||||
|
||||
void DoRunFrame()
|
||||
{
|
||||
#if 0
|
||||
if (s_movie)
|
||||
s_movie->NextFrame();
|
||||
#endif
|
||||
|
||||
g_gpu->RestoreGraphicsAPIState();
|
||||
|
||||
if (CPU::g_state.use_debug_dispatcher)
|
||||
|
@ -129,6 +129,7 @@ u32 GetFrameNumber();
|
||||
u32 GetInternalFrameNumber();
|
||||
void FrameDone();
|
||||
void IncrementInternalFrameNumber();
|
||||
void InputPolled();
|
||||
|
||||
const std::string& GetRunningPath();
|
||||
const std::string& GetRunningCode();
|
||||
|
Loading…
Reference in New Issue
Block a user