working disappearing buttons. TODO opacity over time, disappearing bar

This commit is contained in:
R2DLiu 2020-07-12 23:51:25 -04:00
commit f565855b85
4 changed files with 92 additions and 130 deletions

View file

@ -1165,8 +1165,8 @@ void CEXISlippi::prepareFrameData(u8* payload)
// data from this frame. Don't wait until next frame is processing is complete // data from this frame. Don't wait until next frame is processing is complete
// (this is the last frame, in that case) // (this is the last frame, in that case)
auto isFrameFound = m_current_game->DoesFrameExist(frameIndex); auto isFrameFound = m_current_game->DoesFrameExist(frameIndex);
g_playbackStatus->latestFrame = m_current_game->GetLatestIndex(); g_playbackStatus->lastFrame = m_current_game->GetLatestIndex();
auto isNextFrameFound = g_playbackStatus->latestFrame > frameIndex; auto isNextFrameFound = g_playbackStatus->lastFrame > frameIndex;
auto isFrameComplete = checkFrameFullyFetched(frameIndex); auto isFrameComplete = checkFrameFullyFetched(frameIndex);
auto isFrameReady = isFrameFound && (isProcessingComplete || isNextFrameFound || isFrameComplete); auto isFrameReady = isFrameFound && (isProcessingComplete || isNextFrameFound || isFrameComplete);
@ -1199,8 +1199,8 @@ void CEXISlippi::prepareFrameData(u8* payload)
} }
// If RealTimeMode is enabled, let's trigger fast forwarding under certain conditions // If RealTimeMode is enabled, let's trigger fast forwarding under certain conditions
auto isFarBehind = g_playbackStatus->latestFrame - frameIndex > 2; auto isFarBehind = g_playbackStatus->lastFrame - frameIndex > 2;
auto isVeryFarBehind = g_playbackStatus->latestFrame - frameIndex > 25; auto isVeryFarBehind = g_playbackStatus->lastFrame - frameIndex > 25;
if (isFarBehind && commSettings.mode == "mirror" && commSettings.isRealTimeMode) if (isFarBehind && commSettings.mode == "mirror" && commSettings.isRealTimeMode)
{ {
g_playbackStatus->isSoftFFW = true; g_playbackStatus->isSoftFFW = true;
@ -1211,7 +1211,7 @@ void CEXISlippi::prepareFrameData(u8* payload)
g_playbackStatus->isHardFFW = isVeryFarBehind; g_playbackStatus->isHardFFW = isVeryFarBehind;
} }
if (g_playbackStatus->latestFrame == frameIndex) if (g_playbackStatus->lastFrame == frameIndex)
{ {
// The reason to disable fast forwarding here is in hopes // The reason to disable fast forwarding here is in hopes
// of disabling it on the last frame that we have actually received. // of disabling it on the last frame that we have actually received.
@ -1257,14 +1257,11 @@ void CEXISlippi::prepareFrameData(u8* payload)
rollbackCode = 1; rollbackCode = 1;
} }
// WARN_LOG(EXPANSIONINTERFACE, "[Frame %d] Playback current behind by: %d frames.", frameIndex,
// g_playbackStatus->latestFrame - frameIndex);
// Keep track of last FFW frame, used for soft FFW's // Keep track of last FFW frame, used for soft FFW's
if (shouldFFW) if (shouldFFW)
{ {
WARN_LOG(EXPANSIONINTERFACE, "[Frame %d] FFW frame, behind by: %d frames.", frameIndex, WARN_LOG(SLIPPI, "[Frame %d] FFW frame, behind by: %d frames.", frameIndex,
g_playbackStatus->latestFrame - frameIndex); g_playbackStatus->lastFrame - frameIndex);
g_playbackStatus->lastFFWFrame = frameIndex; g_playbackStatus->lastFFWFrame = frameIndex;
} }
@ -1291,23 +1288,6 @@ void CEXISlippi::prepareFrameData(u8* payload)
frameSeqIdx += 1; frameSeqIdx += 1;
} }
// else
//{
// std::vector<u8> fakePayload(8, 0);
// *(s32 *)(&fakePayload[0]) = Common::swap32(frame->frame);
// if (frame->frame == 400)
// {
// handleCaptureSavestate(&fakePayload[0]);
// }
// if (frame->frame == 950)
// {
// *(s32 *)(&fakePayload[0]) = Common::swap32(400);
// handleLoadSavestate(&fakePayload[0]);
// handleCaptureSavestate(&fakePayload[0]);
// }
//}
// For normal replays, modify slippi seek/playback data as needed // For normal replays, modify slippi seek/playback data as needed
// TODO: maybe handle other modes too? // TODO: maybe handle other modes too?

View file

@ -21,6 +21,7 @@ extern std::unique_ptr<SlippiReplayComm> g_replayComm;
static std::mutex mtx; static std::mutex mtx;
static std::mutex seekMtx; static std::mutex seekMtx;
static std::mutex ffwMtx;
static std::mutex diffMtx; static std::mutex diffMtx;
static std::unique_lock<std::mutex> processingLock(diffMtx); static std::unique_lock<std::mutex> processingLock(diffMtx);
static std::condition_variable condVar; static std::condition_variable condVar;
@ -61,14 +62,13 @@ SlippiPlaybackStatus::SlippiPlaybackStatus()
lastFFWFrame = INT_MIN; lastFFWFrame = INT_MIN;
currentPlaybackFrame = INT_MIN; currentPlaybackFrame = INT_MIN;
targetFrameNum = INT_MAX; targetFrameNum = INT_MAX;
latestFrame = Slippi::GAME_FIRST_FRAME; lastFrame = Slippi::PLAYBACK_FIRST_SAVE;
} }
void SlippiPlaybackStatus::startThreads() void SlippiPlaybackStatus::startThreads()
{ {
shouldRunThreads = true; shouldRunThreads = true;
m_savestateThread = std::thread(&SlippiPlaybackStatus::SavestateThread, this); m_savestateThread = std::thread(&SlippiPlaybackStatus::SavestateThread, this);
m_seekThread = std::thread(&SlippiPlaybackStatus::SeekThread, this);
} }
void SlippiPlaybackStatus::prepareSlippiPlayback(s32& frameIndex) void SlippiPlaybackStatus::prepareSlippiPlayback(s32& frameIndex)
@ -113,9 +113,6 @@ void SlippiPlaybackStatus::resetPlayback()
if (m_savestateThread.joinable()) if (m_savestateThread.joinable())
m_savestateThread.detach(); m_savestateThread.detach();
if (m_seekThread.joinable())
m_seekThread.detach();
condVar.notify_one(); // Will allow thread to kill itself condVar.notify_one(); // Will allow thread to kill itself
futureDiffs.clear(); futureDiffs.clear();
futureDiffs.rehash(0); futureDiffs.rehash(0);
@ -178,96 +175,66 @@ void SlippiPlaybackStatus::SavestateThread()
INFO_LOG(SLIPPI, "Exiting savestate thread"); INFO_LOG(SLIPPI, "Exiting savestate thread");
} }
void SlippiPlaybackStatus::SeekThread() void SlippiPlaybackStatus::SeekToFrame(s32 frameNum)
{ {
Common::SetCurrentThreadName("Seek thread"); if (seekMtx.try_lock()) {
std::unique_lock<std::mutex> seekLock(seekMtx); if (frameNum < Slippi::PLAYBACK_FIRST_SAVE || frameNum > lastFrame) {
INFO_LOG(SLIPPI, "Error: Invalid seek to frame: %d", frameNum);
INFO_LOG(SLIPPI, "Entering seek thread"); seekMtx.unlock();
return;
while (shouldRunThreads)
{
bool shouldSeek = inSlippiPlayback && (shouldJumpBack || shouldJumpForward || targetFrameNum != INT_MAX);
if (shouldSeek)
{
auto replayCommSettings = g_replayComm->getSettings();
if (replayCommSettings.mode == "queue")
clearWatchSettingsStartEnd();
bool paused = (Core::GetState() == Core::State::Paused);
Core::SetState(Core::State::Paused);
u32 jumpInterval = 300; // 5 seconds;
if (shouldJumpForward)
targetFrameNum = currentPlaybackFrame + jumpInterval;
if (shouldJumpBack)
targetFrameNum = currentPlaybackFrame - jumpInterval;
// Handle edgecases for trying to seek before start or past end of game
if (targetFrameNum < Slippi::PLAYBACK_FIRST_SAVE)
targetFrameNum = Slippi::PLAYBACK_FIRST_SAVE;
if (targetFrameNum > latestFrame)
{
targetFrameNum = latestFrame;
}
s32 closestStateFrame = targetFrameNum - emod(targetFrameNum - Slippi::PLAYBACK_FIRST_SAVE, FRAME_INTERVAL);
bool isLoadingStateOptimal =
targetFrameNum < currentPlaybackFrame || closestStateFrame > currentPlaybackFrame;
if (isLoadingStateOptimal)
{
if (closestStateFrame <= Slippi::PLAYBACK_FIRST_SAVE)
{
State::LoadFromBuffer(iState);
}
else
{
// If this diff has been processed, load it
if (futureDiffs.count(closestStateFrame) > 0)
{
std::string stateString;
decoder.Decode((char*)iState.data(), iState.size(), futureDiffs[closestStateFrame].get(),
&stateString);
std::vector<u8> stateToLoad(stateString.begin(), stateString.end());
State::LoadFromBuffer(stateToLoad);
};
}
}
// Fastforward until we get to the frame we want
if (targetFrameNum != closestStateFrame && targetFrameNum != latestFrame)
{
isHardFFW = true;
SConfig::GetInstance().m_OCEnable = true;
SConfig::GetInstance().m_OCFactor = 4.0f;
Core::SetState(Core::State::Running);
cv_waitingForTargetFrame.wait(seekLock);
Core::SetState(Core::State::Paused);
SConfig::GetInstance().m_OCFactor = 1.0f;
SConfig::GetInstance().m_OCEnable = false;
isHardFFW = false;
}
if (!paused)
Core::SetState(Core::State::Running);
shouldJumpBack = false;
shouldJumpForward = false;
targetFrameNum = INT_MAX;
} }
Common::SleepCurrentThread(SLEEP_TIME_MS); std::unique_lock<std::mutex> ffwLock(ffwMtx);
} auto replayCommSettings = g_replayComm->getSettings();
if (replayCommSettings.mode == "queue")
clearWatchSettingsStartEnd();
INFO_LOG(SLIPPI, "Exit seek thread"); auto prevState = Core::GetState();
if (prevState != Core::State::Paused)
Core::SetState(Core::State::Paused);
s32 closestStateFrame = frameNum - emod(frameNum - Slippi::PLAYBACK_FIRST_SAVE, FRAME_INTERVAL);
bool isLoadingStateOptimal = frameNum < currentPlaybackFrame || closestStateFrame > currentPlaybackFrame;
if (isLoadingStateOptimal)
{
if (closestStateFrame <= Slippi::PLAYBACK_FIRST_SAVE)
{
State::LoadFromBuffer(iState);
}
else
{
// If this diff has been processed, load it
if (futureDiffs.count(closestStateFrame) > 0)
{
std::string stateString;
decoder.Decode((char*)iState.data(), iState.size(), futureDiffs[closestStateFrame].get(),
&stateString);
std::vector<u8> stateToLoad(stateString.begin(), stateString.end());
State::LoadFromBuffer(stateToLoad);
};
}
}
// Fastforward until we get to the frame we want
if (frameNum != closestStateFrame && frameNum != lastFrame)
{
isHardFFW = true;
SConfig::GetInstance().m_OCEnable = true;
SConfig::GetInstance().m_OCFactor = 4.0f;
Core::SetState(Core::State::Running);
cv_waitingForTargetFrame.wait(ffwLock);
Core::SetState(Core::State::Paused);
SConfig::GetInstance().m_OCFactor = 1.0f;
SConfig::GetInstance().m_OCEnable = false;
isHardFFW = false;
}
Core::SetState(prevState);
} else {
INFO_LOG(SLIPPI, "Already seeking. Ignoring this call");
}
} }
void SlippiPlaybackStatus::clearWatchSettingsStartEnd() void SlippiPlaybackStatus::clearWatchSettingsStartEnd()

View file

@ -25,10 +25,9 @@ public:
s32 lastFFWFrame = INT_MIN; s32 lastFFWFrame = INT_MIN;
s32 currentPlaybackFrame = INT_MIN; s32 currentPlaybackFrame = INT_MIN;
s32 targetFrameNum = INT_MAX; s32 targetFrameNum = INT_MAX;
s32 latestFrame = Slippi::GAME_FIRST_FRAME; s32 lastFrame = Slippi::PLAYBACK_FIRST_SAVE;
std::thread m_savestateThread; std::thread m_savestateThread;
std::thread m_seekThread;
void startThreads(void); void startThreads(void);
void resetPlayback(void); void resetPlayback(void);
@ -36,7 +35,7 @@ public:
private: private:
void SavestateThread(void); void SavestateThread(void);
void SeekThread(void); void SeekToFrame(s32 targetFrameNum);
void processInitialState(); void processInitialState();
void clearWatchSettingsStartEnd(); void clearWatchSettingsStartEnd();

View file

@ -169,9 +169,9 @@ bool ButtonCustom(const char* label, const ImVec2& size_arg, ImGuiButtonFlags fl
ImGui::RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding); ImGui::RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding);
if (hovered || held) if (hovered || held)
ImGui::RenderTextClipped(bb.Min + style.FramePadding, bb.Max - style.FramePadding, label, NULL, &label_size, style.ButtonTextAlign, &bb, ImVec4(0.9f, 0.9f, 0.9f, 1.0f)); ImGui::RenderTextClipped(bb.Min + style.FramePadding, bb.Max - style.FramePadding, label, NULL, &label_size, style.ButtonTextAlign, &bb, ImVec4(0.9f, 0.9f, 0.9f, style.Alpha));
else else
ImGui::RenderTextClipped(bb.Min + style.FramePadding, bb.Max - style.FramePadding, label, NULL, &label_size, style.ButtonTextAlign, &bb, ImVec4(0.9f, 0.9f, 0.9f, 0.6f)); ImGui::RenderTextClipped(bb.Min + style.FramePadding, bb.Max - style.FramePadding, label, NULL, &label_size, style.ButtonTextAlign, &bb, ImVec4(0.9f, 0.9f, 0.9f, 0.6f * style.Alpha));
// Automatically close popups // Automatically close popups
//if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup)) //if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup))
@ -210,8 +210,14 @@ bool SliderCustomBehavior(const ImRect& bb, ImGuiID id, int* v, int v_min, int v
bool isActive = g.ActiveId == id; bool isActive = g.ActiveId == id;
static bool isHeld = false; static bool isHeld = false;
const bool hovered = ImGui::ItemHoverable(bb, id); const bool hovered = ImGui::ItemHoverable(bb, id);
if (isHeld) if (isHeld) {
isHeld = isHeld && isDown; isHeld = isHeld && isDown;
// If no longer held, slider was let go. Trigger mark edited
if (!isHeld) {
INFO_LOG(SLIPPI, "Do seek here!");
ImGui::MarkItemEdited(id); // TODO only mark on mouse up
}
}
else else
isHeld = hovered && isDown; isHeld = hovered && isDown;
@ -257,7 +263,6 @@ bool SliderCustomBehavior(const ImRect& bb, ImGuiID id, int* v, int v_min, int v
{ {
*v = new_value; *v = new_value;
value_changed = true; value_changed = true;
ImGui::MarkItemEdited(id); // TODO only mark on mouse up
} }
} }
@ -365,14 +370,25 @@ void DrawSlippiPlaybackControls()
// We have to provide a window name, and these shouldn't be duplicated. // We have to provide a window name, and these shouldn't be duplicated.
// So instead, we generate a name based on the number of messages drawn. // So instead, we generate a name based on the number of messages drawn.
const std::string window_name = fmt::format("Slippi Playback Controls"); const std::string window_name = fmt::format("Slippi Playback Controls");
const float alpha = 1.0f;
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, alpha);
ImGui::SetNextWindowPos(ImVec2(0, 0)); ImGui::SetNextWindowPos(ImVec2(0, 0));
ImGui::SetNextWindowSize(ImGui::GetIO().DisplaySize); ImGui::SetNextWindowSize(ImGui::GetIO().DisplaySize);
bool isActive = false;
auto mousePos = ImGui::GetMousePos();
auto mouseDown = GImGui->IO.MouseDown[0];
if (mousePos[1] > ImGui::GetIO().DisplaySize.y - 44 && mousePos[1] < ImGui::GetIO().DisplaySize.y || mouseDown) {
isActive = true;
last_active_tick = std::chrono::steady_clock::now();
}
if (isActive) {
INFO_LOG(SLIPPI, "hovering!");
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 1.0f);
}
else {
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.00001f);
}
if (ImGui::Begin(window_name.c_str(), nullptr, if (ImGui::Begin(window_name.c_str(), nullptr,
ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings |
ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoBackground |