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
// (this is the last frame, in that case)
auto isFrameFound = m_current_game->DoesFrameExist(frameIndex);
g_playbackStatus->latestFrame = m_current_game->GetLatestIndex();
auto isNextFrameFound = g_playbackStatus->latestFrame > frameIndex;
g_playbackStatus->lastFrame = m_current_game->GetLatestIndex();
auto isNextFrameFound = g_playbackStatus->lastFrame > frameIndex;
auto isFrameComplete = checkFrameFullyFetched(frameIndex);
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
auto isFarBehind = g_playbackStatus->latestFrame - frameIndex > 2;
auto isVeryFarBehind = g_playbackStatus->latestFrame - frameIndex > 25;
auto isFarBehind = g_playbackStatus->lastFrame - frameIndex > 2;
auto isVeryFarBehind = g_playbackStatus->lastFrame - frameIndex > 25;
if (isFarBehind && commSettings.mode == "mirror" && commSettings.isRealTimeMode)
{
g_playbackStatus->isSoftFFW = true;
@ -1211,7 +1211,7 @@ void CEXISlippi::prepareFrameData(u8* payload)
g_playbackStatus->isHardFFW = isVeryFarBehind;
}
if (g_playbackStatus->latestFrame == frameIndex)
if (g_playbackStatus->lastFrame == frameIndex)
{
// The reason to disable fast forwarding here is in hopes
// of disabling it on the last frame that we have actually received.
@ -1257,14 +1257,11 @@ void CEXISlippi::prepareFrameData(u8* payload)
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
if (shouldFFW)
{
WARN_LOG(EXPANSIONINTERFACE, "[Frame %d] FFW frame, behind by: %d frames.", frameIndex,
g_playbackStatus->latestFrame - frameIndex);
WARN_LOG(SLIPPI, "[Frame %d] FFW frame, behind by: %d frames.", frameIndex,
g_playbackStatus->lastFrame - frameIndex);
g_playbackStatus->lastFFWFrame = frameIndex;
}
@ -1291,23 +1288,6 @@ void CEXISlippi::prepareFrameData(u8* payload)
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
// 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 seekMtx;
static std::mutex ffwMtx;
static std::mutex diffMtx;
static std::unique_lock<std::mutex> processingLock(diffMtx);
static std::condition_variable condVar;
@ -61,14 +62,13 @@ SlippiPlaybackStatus::SlippiPlaybackStatus()
lastFFWFrame = INT_MIN;
currentPlaybackFrame = INT_MIN;
targetFrameNum = INT_MAX;
latestFrame = Slippi::GAME_FIRST_FRAME;
lastFrame = Slippi::PLAYBACK_FIRST_SAVE;
}
void SlippiPlaybackStatus::startThreads()
{
shouldRunThreads = true;
m_savestateThread = std::thread(&SlippiPlaybackStatus::SavestateThread, this);
m_seekThread = std::thread(&SlippiPlaybackStatus::SeekThread, this);
}
void SlippiPlaybackStatus::prepareSlippiPlayback(s32& frameIndex)
@ -113,9 +113,6 @@ void SlippiPlaybackStatus::resetPlayback()
if (m_savestateThread.joinable())
m_savestateThread.detach();
if (m_seekThread.joinable())
m_seekThread.detach();
condVar.notify_one(); // Will allow thread to kill itself
futureDiffs.clear();
futureDiffs.rehash(0);
@ -178,96 +175,66 @@ void SlippiPlaybackStatus::SavestateThread()
INFO_LOG(SLIPPI, "Exiting savestate thread");
}
void SlippiPlaybackStatus::SeekThread()
void SlippiPlaybackStatus::SeekToFrame(s32 frameNum)
{
Common::SetCurrentThreadName("Seek thread");
std::unique_lock<std::mutex> seekLock(seekMtx);
INFO_LOG(SLIPPI, "Entering seek thread");
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;
if (seekMtx.try_lock()) {
if (frameNum < Slippi::PLAYBACK_FIRST_SAVE || frameNum > lastFrame) {
INFO_LOG(SLIPPI, "Error: Invalid seek to frame: %d", frameNum);
seekMtx.unlock();
return;
}
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()

View file

@ -25,10 +25,9 @@ public:
s32 lastFFWFrame = INT_MIN;
s32 currentPlaybackFrame = INT_MIN;
s32 targetFrameNum = INT_MAX;
s32 latestFrame = Slippi::GAME_FIRST_FRAME;
s32 lastFrame = Slippi::PLAYBACK_FIRST_SAVE;
std::thread m_savestateThread;
std::thread m_seekThread;
void startThreads(void);
void resetPlayback(void);
@ -36,7 +35,7 @@ public:
private:
void SavestateThread(void);
void SeekThread(void);
void SeekToFrame(s32 targetFrameNum);
void processInitialState();
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);
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
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
//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;
static bool isHeld = false;
const bool hovered = ImGui::ItemHoverable(bb, id);
if (isHeld)
if (isHeld) {
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
isHeld = hovered && isDown;
@ -257,7 +263,6 @@ bool SliderCustomBehavior(const ImRect& bb, ImGuiID id, int* v, int v_min, int v
{
*v = new_value;
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.
// So instead, we generate a name based on the number of messages drawn.
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::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,
ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings |
ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoBackground |