Cheevos: Move to core

This commit is contained in:
Connor McLaughlin
2022-03-26 23:51:37 +10:00
parent c43df29abc
commit 584525cb11
20 changed files with 181 additions and 114 deletions

View File

@ -157,3 +157,12 @@ elseif(${CPU_ARCH} STREQUAL "aarch64")
else()
message("Not building recompiler")
endif()
if(ENABLE_CHEEVOS)
target_sources(core PRIVATE
cheevos.cpp
cheevos.h
)
target_compile_definitions(core PUBLIC -DWITH_CHEEVOS=1)
target_link_libraries(core PRIVATE rcheevos rapidjson)
endif()

1431
src/core/cheevos.cpp Normal file

File diff suppressed because it is too large Load Diff

123
src/core/cheevos.h Normal file
View File

@ -0,0 +1,123 @@
#pragma once
#include "common/string.h"
#include "core/types.h"
#include <functional>
#include <optional>
#include <string>
class CDImage;
namespace Cheevos {
enum class AchievementCategory : u32
{
Local = 0,
Core = 3,
Unofficial = 5
};
struct Achievement
{
u32 id;
std::string title;
std::string description;
std::string memaddr;
std::string locked_badge_path;
std::string unlocked_badge_path;
u32 points;
AchievementCategory category;
bool locked;
bool active;
};
struct Leaderboard
{
u32 id;
std::string title;
std::string description;
int format;
};
struct LeaderboardEntry
{
std::string user;
std::string formatted_score;
u32 rank;
bool is_self;
};
extern bool g_active;
extern bool g_challenge_mode;
extern u32 g_game_id;
ALWAYS_INLINE bool IsActive()
{
return g_active;
}
ALWAYS_INLINE bool IsChallengeModeEnabled()
{
return g_challenge_mode;
}
ALWAYS_INLINE bool IsChallengeModeActive()
{
return g_active && g_challenge_mode;
}
ALWAYS_INLINE bool HasActiveGame()
{
return g_game_id != 0;
}
ALWAYS_INLINE u32 GetGameID()
{
return g_game_id;
}
bool Initialize(bool test_mode, bool use_first_disc_from_playlist, bool enable_rich_presence, bool challenge_mode,
bool include_unofficial);
void Reset();
void Shutdown();
void Update();
bool IsLoggedIn();
bool IsTestModeActive();
bool IsUnofficialTestModeActive();
bool IsUsingFirstDiscFromPlaylist();
bool IsRichPresenceEnabled();
const std::string& GetUsername();
const std::string& GetRichPresenceString();
bool LoginAsync(const char* username, const char* password);
bool Login(const char* username, const char* password);
void Logout();
bool HasActiveGame();
void GameChanged(const std::string& path, CDImage* image);
const std::string& GetGameTitle();
const std::string& GetGameDeveloper();
const std::string& GetGamePublisher();
const std::string& GetGameReleaseDate();
const std::string& GetGameIcon();
bool EnumerateAchievements(std::function<bool(const Achievement&)> callback);
u32 GetUnlockedAchiementCount();
u32 GetAchievementCount();
u32 GetMaximumPointsForGame();
u32 GetCurrentPointsForGame();
bool EnumerateLeaderboards(std::function<bool(const Leaderboard&)> callback);
std::optional<bool> TryEnumerateLeaderboardEntries(u32 id, std::function<bool(const LeaderboardEntry&)> callback);
const Leaderboard* GetLeaderboardByID(u32 id);
u32 GetLeaderboardCount();
bool IsLeaderboardTimeType(const Leaderboard& leaderboard);
std::pair<u32, u32> GetAchievementProgress(const Achievement& achievement);
TinyString GetAchievementProgressText(const Achievement& achievement);
void UnlockAchievement(u32 achievement_id, bool add_notification = true);
void SubmitLeaderboard(u32 leaderboard_id, int value);
} // namespace Cheevos

View File

@ -4,10 +4,11 @@
<ItemDefinitionGroup>
<ClCompile>
<PreprocessorDefinitions>WITH_CHEEVOS=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Platform)'=='x64' Or '$(Platform)'=='ARM' Or '$(Platform)'=='ARM64'">WITH_RECOMPILER=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="('$(Platform)'=='x64' Or '$(Platform)'=='ARM64') And ('$(BuildingForUWP)'!='true')">WITH_MMAP_FASTMEM=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)dep\glad\include;$(SolutionDir)dep\stb\include;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\xxhash\include;$(SolutionDir)dep\zlib\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)dep\glad\include;$(SolutionDir)dep\stb\include;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\xxhash\include;$(SolutionDir)dep\zlib\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)dep\rcheevos\include;$(SolutionDir)dep\rapidjson\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories Condition="'$(Platform)'=='x64'">$(SolutionDir)dep\xbyak\xbyak;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories Condition="'$(Platform)'=='ARM' Or '$(Platform)'=='ARM64'">$(SolutionDir)dep\vixl\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
@ -16,7 +17,7 @@
<ItemDefinitionGroup>
<Lib>
<AdditionalDependencies>$(RootBuildDir)imgui\imgui.lib;$(RootBuildDir)stb\stb.lib;$(RootBuildDir)vulkan-loader\vulkan-loader.lib;$(RootBuildDir)xxhash\xxhash.lib;$(RootBuildDir)zlib\zlib.lib;$(RootBuildDir)common\common.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>$(RootBuildDir)rcheevos\rcheevos.lib;$(RootBuildDir)imgui\imgui.lib;$(RootBuildDir)stb\stb.lib;$(RootBuildDir)vulkan-loader\vulkan-loader.lib;$(RootBuildDir)xxhash\xxhash.lib;$(RootBuildDir)zlib\zlib.lib;$(RootBuildDir)common\common.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies Condition="'$(Platform)'=='ARM64'">$(RootBuildDir)vixl\vixl.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Lib>
</ItemDefinitionGroup>

View File

@ -9,6 +9,7 @@
<ClCompile Include="cdrom.cpp" />
<ClCompile Include="cdrom_async_reader.cpp" />
<ClCompile Include="cheats.cpp" />
<ClCompile Include="cheevos.cpp" />
<ClCompile Include="cpu_core.cpp" />
<ClCompile Include="cpu_disasm.cpp" />
<ClCompile Include="cpu_code_cache.cpp" />
@ -82,6 +83,7 @@
<ClInclude Include="cdrom.h" />
<ClInclude Include="cdrom_async_reader.h" />
<ClInclude Include="cheats.h" />
<ClInclude Include="cheevos.h" />
<ClInclude Include="cpu_core.h" />
<ClInclude Include="cpu_core_private.h" />
<ClInclude Include="cpu_disasm.h" />

View File

@ -60,6 +60,7 @@
<ClCompile Include="gpu_hw_d3d12.cpp" />
<ClCompile Include="imgui_fullscreen.cpp" />
<ClCompile Include="imgui_styles.cpp" />
<ClCompile Include="cheevos.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="types.h" />
@ -124,5 +125,6 @@
<ClInclude Include="gdb_protocol.h" />
<ClInclude Include="imgui_fullscreen.h" />
<ClInclude Include="imgui_styles.h" />
<ClInclude Include="cheevos.h" />
</ItemGroup>
</Project>

View File

@ -41,6 +41,7 @@ public:
/// Access to host display.
ALWAYS_INLINE HostDisplay* GetDisplay() const { return m_display.get(); }
ALWAYS_INLINE bool HasDisplay() const { return static_cast<bool>(m_display.get()); }
/// Access to host audio stream.
ALWAYS_INLINE AudioStream* GetAudioStream() const { return m_audio_stream.get(); }
@ -123,6 +124,10 @@ public:
/// Returns a string list from the configuration.
virtual std::vector<std::string> GetSettingStringList(const char* section, const char* key) = 0;
/// Returns the settings interface.
virtual SettingsInterface* GetSettingsInterface() = 0;
virtual std::lock_guard<std::recursive_mutex> GetSettingsLock() = 0;
/// Translates a string to the current language.
virtual TinyString TranslateString(const char* context, const char* str, const char* disambiguation = nullptr,
int n = -1) const;
@ -156,6 +161,9 @@ public:
/// Called when the display is invalidated (e.g. a state is loaded).
virtual void OnDisplayInvalidated() = 0;
/// Called when achievements data is loaded.
virtual void OnAchievementsRefreshed() = 0;
protected:
virtual bool AcquireHostDisplay() = 0;
virtual void ReleaseHostDisplay() = 0;

View File

@ -4,6 +4,7 @@
#include "IconsFontAwesome5.h"
#include "common/assert.h"
#include "common/easing.h"
#include "common/lru_cache.h"
#include "common/file_system.h"
#include "common/string.h"
#include "common/string_util.h"
@ -21,6 +22,8 @@ static void DrawChoiceDialog();
static void DrawBackgroundProgressDialogs(ImVec2& position, float spacing);
static void DrawNotifications(ImVec2& position, float spacing);
bool g_initialized = false;
ImFont* g_standard_font = nullptr;
ImFont* g_medium_font = nullptr;
ImFont* g_large_font = nullptr;
@ -37,10 +40,12 @@ static std::vector<u8> s_text_font_data;
static std::vector<u8> s_icon_font_data;
static float s_font_size = 15.0f;
static const ImWchar* s_font_glyph_range = nullptr;
static ResolveTextureHandleCallback s_resolve_texture_handle = nullptr;
static LoadTextureFunction s_load_texture = nullptr;
static u32 s_menu_button_index = 0;
static LRUCache<std::string, std::unique_ptr<HostDisplayTexture>> s_texture_cache;
void SetFontFilename(const char* filename)
{
if (filename)
@ -93,9 +98,26 @@ void SetMenuBarSize(float size)
g_menu_bar_size = size;
}
void SetResolveTextureFunction(ResolveTextureHandleCallback callback)
HostDisplayTexture* GetCachedTexture(const std::string& name)
{
s_resolve_texture_handle = callback;
std::unique_ptr<HostDisplayTexture>* tex_ptr = s_texture_cache.Lookup(name);
if (!tex_ptr)
{
std::unique_ptr<HostDisplayTexture> tex = s_load_texture(name.c_str());
tex_ptr = s_texture_cache.Insert(name, std::move(tex));
}
return tex_ptr->get();
}
bool InvalidateCachedTexture(const std::string& path)
{
return s_texture_cache.Remove(path);
}
void SetLoadTextureFunction(LoadTextureFunction callback)
{
s_load_texture = callback;
}
static ImFont* AddTextFont(float size /*= 15.0f*/)
@ -977,6 +999,7 @@ static ImGuiID s_enum_choice_button_id = 0;
static s32 s_enum_choice_button_value = 0;
static bool s_enum_choice_button_set = false;
bool EnumChoiceButtonImpl(const char* title, const char* summary, s32* value_pointer,
const char* (*to_display_name_function)(s32 value, void* opaque), void* opaque, u32 count,
bool enabled, float height, ImFont* font, ImFont* summary_font)
@ -1747,11 +1770,11 @@ void DrawNotifications(ImVec2& position, float spacing)
const ImVec2 badge_min(box_min.x + horizontal_padding, box_min.y + vertical_padding);
const ImVec2 badge_max(badge_min.x + badge_size, badge_min.y + badge_size);
if (!notif.badge_path.empty() && s_resolve_texture_handle)
if (!notif.badge_path.empty())
{
ImTextureID tex = s_resolve_texture_handle(notif.badge_path);
HostDisplayTexture* tex = GetCachedTexture(notif.badge_path);
if (tex)
dl->AddImage(tex, badge_min, badge_max);
dl->AddImage(static_cast<ImTextureID>(tex->GetHandle()), badge_min, badge_max);
}
const ImVec2 title_min(badge_max.x + horizontal_spacing, box_min.y + vertical_padding);
@ -1769,4 +1792,40 @@ void DrawNotifications(ImVec2& position, float spacing)
}
}
bool Initialize()
{
s_texture_cache.SetMaxCapacity(128);
g_initialized = true;
return true;
}
void Shutdown()
{
g_standard_font = nullptr;
g_medium_font = nullptr;
g_large_font = nullptr;
s_texture_cache.Clear();
s_notifications.clear();
s_background_progress_dialogs.clear();
s_choice_dialog_open = false;
s_choice_dialog_checkable = false;
s_choice_dialog_title = {};
s_choice_dialog_options.clear();
s_choice_dialog_callback = {};
s_enum_choice_button_id = 0;
s_enum_choice_button_value = 0;
s_enum_choice_button_set = false;
s_file_selector_open = false;
s_file_selector_directory = false;
s_file_selector_title = {};
s_file_selector_callback = {};
s_file_selector_current_directory = {};
s_file_selector_filters.clear();
s_file_selector_items.clear();
g_initialized = false;
}
} // namespace ImGuiFullscreen

View File

@ -5,12 +5,14 @@
#include <string>
#include <vector>
class HostDisplayTexture;
namespace ImGuiFullscreen {
#define HEX_TO_IMVEC4(hex, alpha) \
ImVec4(static_cast<float>((hex >> 16) & 0xFFu) / 255.0f, static_cast<float>((hex >> 8) & 0xFFu) / 255.0f, \
static_cast<float>(hex & 0xFFu) / 255.0f, static_cast<float>(alpha) / 255.0f)
using ResolveTextureHandleCallback = ImTextureID (*)(const std::string& path);
using LoadTextureFunction = std::unique_ptr<HostDisplayTexture>(*)(const char* path);
static constexpr float LAYOUT_SCREEN_WIDTH = 1280.0f;
static constexpr float LAYOUT_SCREEN_HEIGHT = 720.0f;
@ -26,11 +28,17 @@ extern ImFont* g_standard_font;
extern ImFont* g_medium_font;
extern ImFont* g_large_font;
extern bool g_initialized;
extern float g_layout_scale;
extern float g_layout_padding_left;
extern float g_layout_padding_top;
extern float g_menu_bar_size;
static ALWAYS_INLINE bool IsInitialized()
{
return g_initialized;
}
static ALWAYS_INLINE float DPIScale(float v)
{
return ImGui::GetIO().DisplayFramebufferScale.x * v;
@ -132,6 +140,12 @@ static ALWAYS_INLINE ImVec4 UISecondaryTextColor()
return HEX_TO_IMVEC4(0xffffff, 0xff);
}
/// Initializes, setting up any state.
bool Initialize();
/// Shuts down, clearing all state.
void Shutdown();
void SetFontFilename(std::string filename);
void SetFontData(std::vector<u8> data);
void SetIconFontFilename(std::string icon_font_filename);
@ -142,8 +156,10 @@ void SetFontGlyphRanges(const ImWchar* glyph_ranges);
/// Changes the menu bar size. Don't forget to call UpdateLayoutScale() and UpdateFonts().
void SetMenuBarSize(float size);
/// Resolves a texture name to a handle.
void SetResolveTextureFunction(ResolveTextureHandleCallback callback);
/// Texture cache.
HostDisplayTexture* GetCachedTexture(const std::string& name);
bool InvalidateCachedTexture(const std::string& path);
void SetLoadTextureFunction(LoadTextureFunction callback);
/// Rebuilds fonts to a new scale if needed. Returns true if fonts have changed and the texture needs updating.
bool UpdateFonts();