2024-07-01 16:52:32 +08:00
|
|
|
/* Copyright (C) 2019 Mr Goldberg
|
|
|
|
This file is part of the Goldberg Emulator
|
|
|
|
|
|
|
|
The Goldberg Emulator is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU Lesser General Public
|
|
|
|
License as published by the Free Software Foundation; either
|
|
|
|
version 3 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
The Goldberg Emulator is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
Lesser General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
|
|
License along with the Goldberg Emulator; if not, see
|
|
|
|
<http://www.gnu.org/licenses/>. */
|
|
|
|
|
|
|
|
#include "dll/steam_timeline.h"
|
|
|
|
|
2024-11-25 10:57:08 +08:00
|
|
|
|
|
|
|
const std::chrono::system_clock::time_point& Steam_Timeline::TimelineEvent_t::get_time_added() const
|
|
|
|
{
|
|
|
|
return time_added;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const std::chrono::system_clock::time_point& Steam_Timeline::TimelineState_t::get_time_added() const
|
|
|
|
{
|
|
|
|
return time_added;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const std::chrono::system_clock::time_point& Steam_Timeline::TimelineGamePhase_t::get_time_added() const
|
|
|
|
{
|
|
|
|
return time_added;
|
|
|
|
}
|
|
|
|
|
2024-07-01 16:52:32 +08:00
|
|
|
|
|
|
|
|
|
|
|
void Steam_Timeline::steam_callback(void *object, Common_Message *msg)
|
|
|
|
{
|
|
|
|
// PRINT_DEBUG_ENTRY();
|
|
|
|
|
|
|
|
auto instance = (Steam_Timeline *)object;
|
|
|
|
instance->Callback(msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Steam_Timeline::steam_run_every_runcb(void *object)
|
|
|
|
{
|
|
|
|
// PRINT_DEBUG_ENTRY();
|
|
|
|
|
|
|
|
auto instance = (Steam_Timeline *)object;
|
|
|
|
instance->RunCallbacks();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Steam_Timeline::Steam_Timeline(class Settings *settings, class Networking *network, class SteamCallResults *callback_results, class SteamCallBacks *callbacks, class RunEveryRunCB *run_every_runcb)
|
|
|
|
{
|
|
|
|
this->settings = settings;
|
|
|
|
this->network = network;
|
|
|
|
this->callback_results = callback_results;
|
|
|
|
this->callbacks = callbacks;
|
|
|
|
this->run_every_runcb = run_every_runcb;
|
|
|
|
|
|
|
|
// this->network->setCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &Steam_Timeline::steam_callback, this);
|
|
|
|
this->run_every_runcb->add(&Steam_Timeline::steam_run_every_runcb, this);
|
2024-08-03 04:44:19 +08:00
|
|
|
|
|
|
|
// timeline starts with a default event as seen here: https://www.youtube.com/watch?v=YwBD0E4-EsI
|
|
|
|
SetTimelineGameMode(ETimelineGameMode::k_ETimelineGameMode_Invalid);
|
2024-07-01 16:52:32 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
Steam_Timeline::~Steam_Timeline()
|
|
|
|
{
|
|
|
|
// this->network->rmCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &Steam_Timeline::steam_callback, this);
|
|
|
|
this->run_every_runcb->remove(&Steam_Timeline::steam_run_every_runcb, this);
|
|
|
|
}
|
|
|
|
|
2024-08-03 04:44:19 +08:00
|
|
|
|
|
|
|
// Sets a description for the current game state in the timeline. These help the user to find specific
|
|
|
|
// moments in the timeline when saving clips. Setting a new state description replaces any previous
|
|
|
|
// description.
|
|
|
|
//
|
|
|
|
// Examples could include:
|
|
|
|
// * Where the user is in the world in a single player game
|
|
|
|
// * Which round is happening in a multiplayer game
|
|
|
|
// * The current score for a sports game
|
|
|
|
//
|
|
|
|
// Parameters:
|
|
|
|
// - pchDescription: provide a localized string in the language returned by SteamUtils()->GetSteamUILanguage()
|
|
|
|
// - flTimeDelta: The time offset in seconds to apply to this event. Negative times indicate an
|
|
|
|
// event that happened in the past.
|
2024-11-25 10:57:08 +08:00
|
|
|
void Steam_Timeline::SetTimelineTooltip( const char *pchDescription, float flTimeDelta )
|
2024-07-01 16:52:32 +08:00
|
|
|
{
|
|
|
|
PRINT_DEBUG("'%s' %f", pchDescription, flTimeDelta);
|
2024-11-25 10:57:08 +08:00
|
|
|
std::lock_guard lock(timeline_mutex);
|
2024-07-01 16:52:32 +08:00
|
|
|
|
2024-11-25 10:57:08 +08:00
|
|
|
const auto target_timepoint = std::chrono::system_clock::now() + std::chrono::milliseconds(static_cast<long long>(flTimeDelta * 1000));
|
2024-07-01 16:52:32 +08:00
|
|
|
|
2024-11-25 10:57:08 +08:00
|
|
|
// reverse iterators to find last/nearest match in recent time
|
2024-07-01 16:52:32 +08:00
|
|
|
auto event_it = std::find_if(timeline_states.rbegin(), timeline_states.rend(), [this, &target_timepoint](const TimelineState_t &item) {
|
2024-11-25 10:57:08 +08:00
|
|
|
return target_timepoint >= item.get_time_added();
|
2024-07-01 16:52:32 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
if (timeline_states.rend() != event_it) {
|
|
|
|
PRINT_DEBUG("setting timeline state description");
|
|
|
|
if (pchDescription) {
|
|
|
|
event_it->description = pchDescription;
|
|
|
|
} else {
|
|
|
|
event_it->description.clear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2024-11-25 10:57:08 +08:00
|
|
|
void Steam_Timeline::ClearTimelineTooltip( float flTimeDelta )
|
2024-07-01 16:52:32 +08:00
|
|
|
{
|
|
|
|
PRINT_DEBUG("%f", flTimeDelta);
|
2024-11-25 10:57:08 +08:00
|
|
|
std::lock_guard lock(timeline_mutex);
|
2024-07-01 16:52:32 +08:00
|
|
|
|
2024-11-25 10:57:08 +08:00
|
|
|
const auto target_timepoint = std::chrono::system_clock::now() + std::chrono::milliseconds(static_cast<long long>(flTimeDelta * 1000));
|
2024-07-01 16:52:32 +08:00
|
|
|
|
2024-11-25 10:57:08 +08:00
|
|
|
// reverse iterators to find last/nearest match in recent time
|
2024-07-01 16:52:32 +08:00
|
|
|
auto event_it = std::find_if(timeline_states.rbegin(), timeline_states.rend(), [this, &target_timepoint](const TimelineState_t &item) {
|
2024-11-25 10:57:08 +08:00
|
|
|
return target_timepoint >= item.get_time_added();
|
2024-07-01 16:52:32 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
if (timeline_states.rend() != event_it) {
|
|
|
|
PRINT_DEBUG("clearing timeline state description");
|
|
|
|
event_it->description.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2024-11-25 10:57:08 +08:00
|
|
|
void Steam_Timeline::SetTimelineStateDescription( const char *pchDescription, float flTimeDelta )
|
|
|
|
{
|
|
|
|
PRINT_DEBUG("old v1");
|
|
|
|
SetTimelineTooltip(pchDescription, flTimeDelta);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Steam_Timeline::ClearTimelineStateDescription( float flTimeDelta )
|
|
|
|
{
|
|
|
|
PRINT_DEBUG("old v1");
|
|
|
|
ClearTimelineTooltip(flTimeDelta);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Steam_Timeline::SetTimelineGameMode( ETimelineGameMode eMode )
|
|
|
|
{
|
|
|
|
PRINT_DEBUG("%i", (int)eMode);
|
|
|
|
std::lock_guard lock(timeline_mutex);
|
|
|
|
|
|
|
|
auto &new_timeline_state = timeline_states.emplace_back(TimelineState_t{});
|
|
|
|
new_timeline_state.bar_color = eMode;
|
|
|
|
}
|
|
|
|
|
|
|
|
TimelineEventHandle_t Steam_Timeline::AddInstantaneousTimelineEvent( const char *pchTitle, const char *pchDescription, const char *pchIcon, uint32 unIconPriority, float flStartOffsetSeconds, ETimelineEventClipPriority ePossibleClip )
|
|
|
|
{
|
|
|
|
PRINT_DEBUG_TODO();
|
|
|
|
return AddRangeTimelineEvent(pchTitle, pchDescription, pchIcon, unIconPriority, flStartOffsetSeconds, 0, ePossibleClip);
|
|
|
|
}
|
|
|
|
|
|
|
|
TimelineEventHandle_t Steam_Timeline::AddRangeTimelineEvent( const char *pchTitle, const char *pchDescription, const char *pchIcon, uint32 unIconPriority, float flStartOffsetSeconds, float flDuration, ETimelineEventClipPriority ePossibleClip)
|
|
|
|
{
|
|
|
|
PRINT_DEBUG("'%s' ('%s') icon='%s', %u, [%f, %f) %i", pchTitle, pchDescription, pchIcon, unIconPriority, flStartOffsetSeconds, flDuration, (int)ePossibleClip);
|
|
|
|
std::lock_guard lock(timeline_mutex);
|
|
|
|
|
|
|
|
auto event_id = StartRangeTimelineEvent(pchTitle, pchDescription, pchIcon, unIconPriority, flStartOffsetSeconds, ePossibleClip);
|
|
|
|
if (!event_id || event_id > timeline_events.size()) return event_id;
|
|
|
|
|
|
|
|
auto& my_event = timeline_events[static_cast<size_t>(event_id - 1)];
|
|
|
|
my_event.ended = true; // ranged and instantaneous events are ended/closed events, they can't be modified later according to docs
|
|
|
|
|
|
|
|
// make events last at least 1 sec
|
|
|
|
if (static_cast<long long>(flDuration * 1000) < 1000LL) { // < 1000ms
|
|
|
|
flDuration = 1;
|
|
|
|
}
|
|
|
|
// for events with priority=ETimelineEventClipPriority::k_ETimelineEventClipPriority_Featured steam creates ~30 sec clip
|
|
|
|
if (flDuration < PRIORITY_CLIP_MIN_SEC && ePossibleClip == ETimelineEventClipPriority::k_ETimelineEventClipPriority_Featured) {
|
|
|
|
flDuration = PRIORITY_CLIP_MIN_SEC;
|
|
|
|
}
|
|
|
|
if (flDuration > k_flMaxTimelineEventDuration) {
|
|
|
|
flDuration = k_flMaxTimelineEventDuration;
|
|
|
|
}
|
|
|
|
|
|
|
|
my_event.flDurationSeconds = flDuration;
|
|
|
|
|
|
|
|
return event_id;
|
|
|
|
}
|
|
|
|
|
|
|
|
TimelineEventHandle_t Steam_Timeline::AddTimelineEvent( const char *pchTitle, const char *pchDescription, const char *pchIcon, uint32 unIconPriority, float flStartOffsetSeconds, float flDurationSeconds, ETimelineEventClipPriority ePossibleClip )
|
|
|
|
{
|
|
|
|
PRINT_DEBUG("undocumented v2/v3");
|
|
|
|
|
|
|
|
// this is how actual steamclient64.dll implements it
|
|
|
|
if (flDurationSeconds > 0) {
|
|
|
|
return AddRangeTimelineEvent(pchTitle, pchDescription, pchIcon, unIconPriority, flStartOffsetSeconds, flDurationSeconds, ePossibleClip);
|
|
|
|
} else {
|
|
|
|
return AddInstantaneousTimelineEvent(pchTitle, pchDescription, pchIcon, unIconPriority, flStartOffsetSeconds, ePossibleClip);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-03 04:44:19 +08:00
|
|
|
// Use this to mark an event on the Timeline. The event can be instantaneous or take some amount of time
|
|
|
|
// to complete, depending on the value passed in flDurationSeconds
|
|
|
|
//
|
|
|
|
// Examples could include:
|
|
|
|
// * a boss battle
|
|
|
|
// * a cut scene
|
|
|
|
// * a large team fight
|
|
|
|
// * picking up a new weapon or ammunition
|
|
|
|
// * scoring a goal
|
|
|
|
//
|
|
|
|
// Parameters:
|
|
|
|
//
|
|
|
|
// - pchIcon: specify the name of the icon uploaded through the Steamworks Partner Site for your title
|
|
|
|
// or one of the provided icons that start with steam_
|
|
|
|
// - pchTitle & pchDescription: provide a localized string in the language returned by
|
|
|
|
// SteamUtils()->GetSteamUILanguage()
|
|
|
|
// - unPriority: specify how important this range is compared to other markers provided by the game.
|
|
|
|
// Ranges with larger priority values will be displayed more prominently in the UI. This value
|
|
|
|
// may be between 0 and k_unMaxTimelinePriority.
|
|
|
|
// - flStartOffsetSeconds: The time that this range started relative to now. Negative times
|
|
|
|
// indicate an event that happened in the past.
|
|
|
|
// - flDurationSeconds: How long the time range should be in seconds. For instantaneous events, this
|
|
|
|
// should be 0
|
|
|
|
// - ePossibleClip: By setting this parameter to Featured or Standard, the game indicates to Steam that it
|
|
|
|
// would be appropriate to offer this range as a clip to the user. For instantaneous events, the
|
|
|
|
// suggested clip will be for a short time before and after the event itself.
|
2024-11-25 10:57:08 +08:00
|
|
|
void Steam_Timeline::AddTimelineEvent_old( const char *pchIcon, const char *pchTitle, const char *pchDescription, uint32 unPriority, float flStartOffsetSeconds, float flDurationSeconds, ETimelineEventClipPriority ePossibleClip )
|
2024-07-01 16:52:32 +08:00
|
|
|
{
|
2024-11-25 10:57:08 +08:00
|
|
|
PRINT_DEBUG("old v1");
|
|
|
|
|
|
|
|
// this is how actual steamclient64.dll implements it
|
|
|
|
if (flDurationSeconds > 0) {
|
|
|
|
AddRangeTimelineEvent(pchTitle, pchDescription, pchIcon, unPriority, flStartOffsetSeconds, flDurationSeconds, ePossibleClip);
|
|
|
|
} else {
|
|
|
|
AddInstantaneousTimelineEvent(pchTitle, pchDescription, pchIcon, unPriority, flStartOffsetSeconds, ePossibleClip);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TimelineEventHandle_t Steam_Timeline::StartRangeTimelineEvent( const char *pchTitle, const char *pchDescription, const char *pchIcon, uint32 unPriority, float flStartOffsetSeconds, ETimelineEventClipPriority ePossibleClip )
|
|
|
|
{
|
|
|
|
PRINT_DEBUG("'%s' ('%s') icon='%s', %u, @[%f]sec %i", pchTitle, pchDescription, pchIcon, unPriority, flStartOffsetSeconds, (int)ePossibleClip);
|
|
|
|
std::lock_guard lock(timeline_mutex);
|
|
|
|
// this adds a new event, but the duration is set once EndRangeTimelineEvent is called
|
|
|
|
// also its "ended" flag is not set
|
2024-07-01 16:52:32 +08:00
|
|
|
|
|
|
|
auto &new_event = timeline_events.emplace_back(TimelineEvent_t{});
|
2024-11-25 10:57:08 +08:00
|
|
|
new_event.pchTitle = pchTitle ? pchTitle : "";
|
|
|
|
new_event.pchDescription = pchDescription ? pchDescription : "";
|
|
|
|
new_event.pchIcon = pchIcon ? pchIcon : "";
|
2024-07-01 16:52:32 +08:00
|
|
|
new_event.unPriority = unPriority;
|
|
|
|
new_event.flStartOffsetSeconds = flStartOffsetSeconds;
|
2024-11-25 10:57:08 +08:00
|
|
|
new_event.ePossibleClip = ePossibleClip;
|
2024-07-01 16:52:32 +08:00
|
|
|
|
2024-11-25 10:57:08 +08:00
|
|
|
auto new_event_id = timeline_events.size(); // never return 0, most APIs in other interfaces use it for invalid IDs
|
|
|
|
PRINT_DEBUG(" new event ID = [%zu]", new_event_id);
|
|
|
|
return static_cast<TimelineEventHandle_t>(new_event_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Steam_Timeline::UpdateRangeTimelineEvent( TimelineEventHandle_t ulEvent, const char *pchTitle, const char *pchDescription, const char *pchIcon, uint32 unPriority, ETimelineEventClipPriority ePossibleClip )
|
|
|
|
{
|
|
|
|
PRINT_DEBUG("[%llu] '%s' ('%s') | icon='%s', %u, %i", ulEvent, pchTitle, pchDescription, pchIcon, unPriority, (int)ePossibleClip);
|
|
|
|
std::lock_guard lock(timeline_mutex);
|
|
|
|
|
|
|
|
if (!ulEvent || ulEvent > timeline_events.size()) return;
|
|
|
|
|
|
|
|
auto& my_event = timeline_events[static_cast<size_t>(ulEvent - 1)];
|
|
|
|
if (my_event.ended) return;
|
|
|
|
|
|
|
|
if (pchTitle) {
|
|
|
|
my_event.pchTitle = pchTitle;
|
|
|
|
} else {
|
|
|
|
my_event.pchTitle.clear();
|
2024-08-03 04:44:19 +08:00
|
|
|
}
|
2024-11-25 10:57:08 +08:00
|
|
|
|
|
|
|
if (pchDescription) {
|
|
|
|
my_event.pchDescription = pchDescription;
|
|
|
|
} else {
|
|
|
|
my_event.pchDescription.clear();
|
2024-07-01 16:52:32 +08:00
|
|
|
}
|
|
|
|
|
2024-11-25 10:57:08 +08:00
|
|
|
if (pchIcon) {
|
|
|
|
my_event.pchIcon = pchIcon;
|
|
|
|
} else {
|
|
|
|
my_event.pchIcon.clear();
|
|
|
|
}
|
2024-07-01 16:52:32 +08:00
|
|
|
|
2024-11-25 10:57:08 +08:00
|
|
|
my_event.unPriority = unPriority;
|
|
|
|
my_event.ePossibleClip = ePossibleClip;
|
2024-07-01 16:52:32 +08:00
|
|
|
|
2024-11-25 10:57:08 +08:00
|
|
|
PRINT_DEBUG(" updated event");
|
2024-07-01 16:52:32 +08:00
|
|
|
}
|
|
|
|
|
2024-11-25 10:57:08 +08:00
|
|
|
void Steam_Timeline::EndRangeTimelineEvent( TimelineEventHandle_t ulEvent, float flEndOffsetSeconds )
|
2024-11-18 01:33:21 +08:00
|
|
|
{
|
2024-11-25 10:57:08 +08:00
|
|
|
PRINT_DEBUG("[%llu] %f", ulEvent, flEndOffsetSeconds);
|
|
|
|
std::lock_guard lock(timeline_mutex);
|
2024-11-18 01:33:21 +08:00
|
|
|
|
2024-11-25 10:57:08 +08:00
|
|
|
if (!ulEvent || ulEvent > timeline_events.size()) return;
|
|
|
|
|
|
|
|
auto& my_event = timeline_events[static_cast<size_t>(ulEvent - 1)];
|
|
|
|
if (my_event.ended) return;
|
|
|
|
|
|
|
|
my_event.ended = true;
|
|
|
|
|
|
|
|
auto end_timepoint = std::chrono::system_clock::now();
|
|
|
|
auto start_timepoint = my_event.get_time_added() + std::chrono::milliseconds(static_cast<long long>(my_event.flStartOffsetSeconds * 1000));
|
|
|
|
auto duration_ms = std::chrono::duration_cast<std::chrono::milliseconds>(end_timepoint - start_timepoint);
|
|
|
|
|
|
|
|
my_event.flDurationSeconds = duration_ms.count() / 1000.0f;
|
|
|
|
|
|
|
|
PRINT_DEBUG(" ended event // TODO show in the UI");
|
2024-11-18 01:33:21 +08:00
|
|
|
}
|
|
|
|
|
2024-11-25 10:57:08 +08:00
|
|
|
void Steam_Timeline::RemoveTimelineEvent( TimelineEventHandle_t ulEvent )
|
2024-11-18 01:33:21 +08:00
|
|
|
{
|
2024-11-25 10:57:08 +08:00
|
|
|
PRINT_DEBUG("[%llu]", ulEvent);
|
|
|
|
std::lock_guard lock(timeline_mutex);
|
|
|
|
|
|
|
|
if (!ulEvent || ulEvent > timeline_events.size()) return;
|
|
|
|
|
|
|
|
timeline_events.erase(timeline_events.begin() + static_cast<size_t>(ulEvent - 1));
|
|
|
|
|
|
|
|
PRINT_DEBUG(" removed event // TODO remove from the UI");
|
2024-11-18 01:33:21 +08:00
|
|
|
}
|
|
|
|
|
2024-11-25 10:57:08 +08:00
|
|
|
STEAM_CALL_RESULT( SteamTimelineEventRecordingExists_t )
|
|
|
|
SteamAPICall_t Steam_Timeline::DoesEventRecordingExist(TimelineEventHandle_t ulEvent)
|
2024-11-18 01:33:21 +08:00
|
|
|
{
|
2024-11-25 10:57:08 +08:00
|
|
|
PRINT_DEBUG("[%llu] // TODO", ulEvent);
|
|
|
|
std::lock_guard lock(timeline_mutex);
|
|
|
|
|
|
|
|
if (!ulEvent || ulEvent > timeline_events.size()) {
|
|
|
|
SteamTimelineEventRecordingExists_t data_invalid{};
|
|
|
|
data_invalid.m_bRecordingExists = false;
|
|
|
|
data_invalid.m_ulEventID = ulEvent;
|
|
|
|
auto ret = callback_results->addCallResult(data_invalid.k_iCallback, &data_invalid, sizeof(data_invalid));
|
|
|
|
callbacks->addCBResult(data_invalid.k_iCallback, &data_invalid, sizeof(data_invalid));
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto& my_event = timeline_events[static_cast<size_t>(ulEvent - 1)];
|
|
|
|
auto recordings_count = my_event.recordings.size();
|
|
|
|
|
|
|
|
SteamTimelineEventRecordingExists_t data{};
|
|
|
|
data.m_bRecordingExists = !my_event.recordings.empty();
|
|
|
|
data.m_ulEventID = ulEvent;
|
|
|
|
auto ret = callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
|
|
|
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
|
|
|
return ret;
|
2024-11-18 01:33:21 +08:00
|
|
|
}
|
|
|
|
|
2024-11-25 10:57:08 +08:00
|
|
|
void Steam_Timeline::StartGamePhase()
|
2024-11-18 01:33:21 +08:00
|
|
|
{
|
2024-11-25 10:57:08 +08:00
|
|
|
PRINT_DEBUG_ENTRY();
|
|
|
|
std::lock_guard lock(timeline_mutex);
|
|
|
|
|
|
|
|
timeline_game_phases.emplace_back(TimelineGamePhase_t{});
|
2024-11-18 01:33:21 +08:00
|
|
|
}
|
|
|
|
|
2024-11-25 10:57:08 +08:00
|
|
|
void Steam_Timeline::EndGamePhase()
|
2024-11-18 01:33:21 +08:00
|
|
|
{
|
2024-11-25 10:57:08 +08:00
|
|
|
PRINT_DEBUG_ENTRY();
|
|
|
|
std::lock_guard lock(timeline_mutex);
|
2024-11-18 01:33:21 +08:00
|
|
|
|
2024-11-25 10:57:08 +08:00
|
|
|
if (timeline_game_phases.empty()) return;
|
|
|
|
|
|
|
|
auto &last_game_phase = timeline_game_phases.back();
|
|
|
|
last_game_phase.ended = true;
|
2024-11-18 01:33:21 +08:00
|
|
|
}
|
|
|
|
|
2024-11-25 10:57:08 +08:00
|
|
|
void Steam_Timeline::SetGamePhaseID( const char *pchPhaseID )
|
2024-11-18 01:33:21 +08:00
|
|
|
{
|
2024-11-25 10:57:08 +08:00
|
|
|
PRINT_DEBUG("['%s']", pchPhaseID);
|
|
|
|
std::lock_guard lock(timeline_mutex);
|
|
|
|
|
|
|
|
if (timeline_game_phases.empty()) return;
|
2024-11-18 01:33:21 +08:00
|
|
|
|
2024-11-25 10:57:08 +08:00
|
|
|
auto &last_game_phase = timeline_game_phases.back();
|
|
|
|
if (last_game_phase.ended) return;
|
|
|
|
|
|
|
|
last_game_phase.pchPhaseID = pchPhaseID ? pchPhaseID : "";
|
|
|
|
PRINT_DEBUG(" changed phase ID");
|
2024-11-18 01:33:21 +08:00
|
|
|
}
|
|
|
|
|
2024-11-25 10:57:08 +08:00
|
|
|
STEAM_CALL_RESULT( SteamTimelineGamePhaseRecordingExists_t )
|
|
|
|
SteamAPICall_t Steam_Timeline::DoesGamePhaseRecordingExist( const char *pchPhaseID )
|
2024-11-18 01:33:21 +08:00
|
|
|
{
|
2024-11-25 10:57:08 +08:00
|
|
|
PRINT_DEBUG("'%s' // TODO", pchPhaseID);
|
|
|
|
std::lock_guard lock(timeline_mutex);
|
|
|
|
|
|
|
|
if (!pchPhaseID) pchPhaseID = "";
|
|
|
|
std::string_view game_phase_id_view(pchPhaseID);
|
|
|
|
|
|
|
|
const auto trigger_failure = [game_phase_id_view, this]() {
|
|
|
|
SteamTimelineGamePhaseRecordingExists_t data_invalid{};
|
|
|
|
auto chars_copied = game_phase_id_view.copy(data_invalid.m_rgchPhaseID, sizeof(data_invalid.m_rgchPhaseID) - 1);
|
|
|
|
data_invalid.m_rgchPhaseID[chars_copied] = 0;
|
|
|
|
data_invalid.m_ulLongestClipMS = 0;
|
|
|
|
data_invalid.m_ulRecordingMS = 0;
|
|
|
|
data_invalid.m_unClipCount = 0;
|
|
|
|
data_invalid.m_unScreenshotCount = 0;
|
|
|
|
|
|
|
|
auto ret = callback_results->addCallResult(data_invalid.k_iCallback, &data_invalid, sizeof(data_invalid));
|
|
|
|
callbacks->addCBResult(data_invalid.k_iCallback, &data_invalid, sizeof(data_invalid));
|
|
|
|
return ret;
|
|
|
|
};
|
|
|
|
|
|
|
|
if (timeline_game_phases.empty()) {
|
|
|
|
return trigger_failure();
|
|
|
|
}
|
|
|
|
|
|
|
|
auto phase_it = std::find_if(timeline_game_phases.begin(), timeline_game_phases.end(), [game_phase_id_view](const TimelineGamePhase_t &item){
|
|
|
|
return game_phase_id_view == item.pchPhaseID;
|
|
|
|
});
|
|
|
|
if (timeline_game_phases.end() == phase_it) {
|
|
|
|
return trigger_failure();
|
|
|
|
}
|
2024-11-18 01:33:21 +08:00
|
|
|
|
2024-11-25 10:57:08 +08:00
|
|
|
// TODO return actual count ?
|
|
|
|
auto recordings_count = phase_it->recordings.size();
|
|
|
|
return trigger_failure();
|
2024-11-18 01:33:21 +08:00
|
|
|
}
|
|
|
|
|
2024-11-25 10:57:08 +08:00
|
|
|
void Steam_Timeline::AddGamePhaseTag( const char *pchTagName, const char *pchTagIcon, const char *pchTagGroup, uint32 unPriority )
|
2024-11-18 01:33:21 +08:00
|
|
|
{
|
2024-11-25 10:57:08 +08:00
|
|
|
PRINT_DEBUG("['%s']: '%s' '%s' <%u>", pchTagGroup, pchTagName, pchTagIcon, unPriority);
|
|
|
|
std::lock_guard lock(timeline_mutex);
|
|
|
|
|
|
|
|
if (timeline_game_phases.empty()) return;
|
|
|
|
|
|
|
|
auto &last_game_phase = timeline_game_phases.back();
|
|
|
|
if (last_game_phase.ended) return;
|
|
|
|
|
|
|
|
if (!pchTagGroup) pchTagGroup = "";
|
|
|
|
|
|
|
|
auto &phase_tag = last_game_phase.tags[pchTagGroup].emplace_back(Steam_Timeline::TimelineGamePhase_t::Tag_t{});
|
|
|
|
phase_tag.pchTagName = pchTagName ? pchTagName : "";
|
|
|
|
phase_tag.pchTagIcon = pchTagIcon ? pchTagIcon : "";
|
|
|
|
phase_tag.unPriority = unPriority;
|
|
|
|
PRINT_DEBUG(" added phase tag");
|
2024-11-18 01:33:21 +08:00
|
|
|
}
|
|
|
|
|
2024-11-25 10:57:08 +08:00
|
|
|
void Steam_Timeline::SetGamePhaseAttribute( const char *pchAttributeGroup, const char *pchAttributeValue, uint32 unPriority )
|
2024-11-18 01:33:21 +08:00
|
|
|
{
|
2024-11-25 10:57:08 +08:00
|
|
|
PRINT_DEBUG("['%s']: '%s' <%u>", pchAttributeGroup, pchAttributeValue, unPriority);
|
|
|
|
std::lock_guard lock(timeline_mutex);
|
|
|
|
|
|
|
|
if (timeline_game_phases.empty()) return;
|
2024-11-18 01:33:21 +08:00
|
|
|
|
2024-11-25 10:57:08 +08:00
|
|
|
auto &last_game_phase = timeline_game_phases.back();
|
|
|
|
if (last_game_phase.ended) return;
|
|
|
|
|
|
|
|
if (!pchAttributeGroup) pchAttributeGroup = "";
|
|
|
|
|
|
|
|
auto &phase_att = last_game_phase.attributes[pchAttributeGroup];
|
|
|
|
phase_att.pchAttributeValue = pchAttributeValue ? pchAttributeValue : "";
|
|
|
|
phase_att.unPriority = unPriority;
|
|
|
|
PRINT_DEBUG(" changed phase attribute");
|
2024-11-18 01:33:21 +08:00
|
|
|
}
|
|
|
|
|
2024-11-25 10:57:08 +08:00
|
|
|
void Steam_Timeline::OpenOverlayToGamePhase( const char *pchPhaseID )
|
2024-11-18 01:33:21 +08:00
|
|
|
{
|
2024-11-25 10:57:08 +08:00
|
|
|
PRINT_DEBUG("['%s'] // TODO", pchPhaseID);
|
|
|
|
std::lock_guard lock(timeline_mutex);
|
2024-11-18 01:33:21 +08:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2024-11-25 10:57:08 +08:00
|
|
|
void Steam_Timeline::OpenOverlayToTimelineEvent( const TimelineEventHandle_t ulEvent )
|
2024-11-18 01:33:21 +08:00
|
|
|
{
|
2024-11-25 10:57:08 +08:00
|
|
|
PRINT_DEBUG("[%llu] // TODO", ulEvent);
|
|
|
|
std::lock_guard lock(timeline_mutex);
|
2024-11-18 01:33:21 +08:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2024-11-25 10:57:08 +08:00
|
|
|
|
|
|
|
uint32 Steam_Timeline::unknown_ret0_1()
|
2024-11-18 01:33:21 +08:00
|
|
|
{
|
2024-11-25 10:57:08 +08:00
|
|
|
PRINT_DEBUG_TODO();
|
2024-11-18 01:33:21 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2024-11-25 10:57:08 +08:00
|
|
|
uint32 Steam_Timeline::unknown_ret0_2()
|
2024-11-18 01:33:21 +08:00
|
|
|
{
|
2024-11-25 10:57:08 +08:00
|
|
|
PRINT_DEBUG_TODO();
|
|
|
|
return 0;
|
2024-11-18 01:33:21 +08:00
|
|
|
}
|
|
|
|
|
2024-11-25 10:57:08 +08:00
|
|
|
void Steam_Timeline::unknown_nop_3()
|
2024-11-18 01:33:21 +08:00
|
|
|
{
|
2024-11-25 10:57:08 +08:00
|
|
|
PRINT_DEBUG_TODO();
|
2024-11-18 01:33:21 +08:00
|
|
|
}
|
|
|
|
|
2024-11-25 10:57:08 +08:00
|
|
|
void Steam_Timeline::unknown_nop_4()
|
2024-11-18 01:33:21 +08:00
|
|
|
{
|
2024-11-25 10:57:08 +08:00
|
|
|
PRINT_DEBUG_TODO();
|
|
|
|
}
|
2024-11-18 01:33:21 +08:00
|
|
|
|
2024-11-25 10:57:08 +08:00
|
|
|
void Steam_Timeline::unknown_nop_5()
|
|
|
|
{
|
|
|
|
PRINT_DEBUG_TODO();
|
2024-11-18 01:33:21 +08:00
|
|
|
}
|
|
|
|
|
2024-11-25 10:57:08 +08:00
|
|
|
void Steam_Timeline::unknown_nop_6()
|
2024-11-18 01:33:21 +08:00
|
|
|
{
|
2024-11-25 10:57:08 +08:00
|
|
|
PRINT_DEBUG_TODO();
|
|
|
|
}
|
2024-11-18 01:33:21 +08:00
|
|
|
|
2024-11-25 10:57:08 +08:00
|
|
|
void Steam_Timeline::unknown_nop_7()
|
|
|
|
{
|
|
|
|
PRINT_DEBUG_TODO();
|
2024-11-18 01:33:21 +08:00
|
|
|
}
|
2024-07-01 16:52:32 +08:00
|
|
|
|
|
|
|
|
|
|
|
void Steam_Timeline::RunCallbacks()
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Steam_Timeline::Callback(Common_Message *msg)
|
|
|
|
{
|
|
|
|
if (msg->has_low_level()) {
|
|
|
|
if (msg->low_level().type() == Low_Level::CONNECT) {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (msg->low_level().type() == Low_Level::DISCONNECT) {
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|