Skip to content

Commit

Permalink
[XLast] Partially implemented presence string parsing
Browse files Browse the repository at this point in the history
Thanks Gliniak for parser.
  • Loading branch information
AdrianCassar committed Sep 24, 2024
1 parent 257b835 commit fb93be0
Show file tree
Hide file tree
Showing 7 changed files with 280 additions and 0 deletions.
151 changes: 151 additions & 0 deletions src/xenia/kernel/util/presence_string_builder.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2024 Xenia Canary. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/

#include "xenia/kernel/util/presence_string_builder.h"
#include "xenia/kernel/util/shim_utils.h"

namespace xe {
namespace kernel {
namespace util {

AttributeStringFormatter::~AttributeStringFormatter() {}

AttributeStringFormatter::AttributeStringFormatter(
std::string_view attribute_string, XLast* title_xlast,
std::map<uint32_t, uint32_t> contexts)
: attribute_string_(attribute_string), attribute_to_string_mapping_() {
contexts_ = contexts;
title_xlast_ = title_xlast;

presence_string_ = "";

if (!ParseAttributeString()) {
return;
}

BuildPresenceString();
}

bool AttributeStringFormatter::ParseAttributeString() {
auto specifiers = GetPresenceFormatSpecifiers();

if (specifiers.empty()) {
return true;
}

std::string specifier;
while (!specifiers.empty()) {
std::string specifier = specifiers.front();
attribute_to_string_mapping_[specifier] = GetStringFromSpecifier(specifier);
specifiers.pop();
}
return true;
}

void AttributeStringFormatter::BuildPresenceString() {
presence_string_ = attribute_string_;

for (const auto& entry : attribute_to_string_mapping_) {
presence_string_.replace(presence_string_.find(entry.first),
entry.first.length(), entry.second);
}
}

AttributeStringFormatter::AttributeType
AttributeStringFormatter::GetAttributeTypeFromSpecifier(
std::string_view specifier) const {
if (specifier.length() < 3) {
return AttributeStringFormatter::AttributeType::Unknown;
}

const char presence_type = specifier.at(1);
if (presence_type == 'c') {
return AttributeStringFormatter::AttributeType::Context;
}
if (presence_type == 'p') {
return AttributeStringFormatter::AttributeType::Property;
}
return AttributeStringFormatter::AttributeType::Unknown;
}

std::optional<uint32_t> AttributeStringFormatter::GetAttributeIdFromSpecifier(
const std::string& specifier,
const AttributeStringFormatter::AttributeType specifier_type) const {
std::smatch string_match;
if (std::regex_search(specifier, string_match,
presence_id_extract_from_specifier)) {
return std::make_optional<uint32_t>(stoi(string_match[1].str()));
}

return std::nullopt;
}

std::string AttributeStringFormatter::GetStringFromSpecifier(
std::string_view specifier) const {
std::string presence_string = "";

const AttributeStringFormatter::AttributeType attribute_type =
GetAttributeTypeFromSpecifier(specifier);

if (attribute_type == AttributeStringFormatter::AttributeType::Unknown) {
return "";
}

const auto attribute_id =
GetAttributeIdFromSpecifier(std::string(specifier), attribute_type);
if (!attribute_id) {
return "";
}

if (attribute_type == AttributeStringFormatter::AttributeType::Context) {
// TODO: Different handling for contexts and properties
const auto itr = contexts_.find(attribute_id.value());

if (itr == contexts_.cend()) {
auto x = fmt::format("{{c{}}}", attribute_id.value());

return x;
}

const auto attribute_string_id =
title_xlast_->GetContextStringId(attribute_id.value(), itr->second);

const auto attribute_string = title_xlast_->GetLocalizedString(
attribute_string_id, XLanguage::kEnglish);

return xe::to_utf8(attribute_string);
}

if (attribute_type == AttributeStringFormatter::AttributeType::Property) {
return "";
}

return "";
}

std::queue<std::string> AttributeStringFormatter::GetPresenceFormatSpecifiers()
const {
std::queue<std::string> format_specifiers;

std::smatch match;

std::string attribute_string = attribute_string_;

while (std::regex_search(attribute_string, match,
format_specifier_replace_fragment_regex_)) {
for (const auto& presence : match) {
format_specifiers.emplace(presence);
}
attribute_string = match.suffix().str();
}
return format_specifiers;
}
} // namespace util
} // namespace kernel
} // namespace xe
80 changes: 80 additions & 0 deletions src/xenia/kernel/util/presence_string_builder.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2024 Xenia Canary. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/

#ifndef XENIA_KERNEL_UTIL_PRESENCE_STRING_BUILDER_H_
#define XENIA_KERNEL_UTIL_PRESENCE_STRING_BUILDER_H_

#include <cstdint>
#include <map>
#include <optional>
#include <queue>
#include <regex>
#include <string>
#include <string_view>

#include "xenia/kernel/util/xlast.h"

namespace xe {
namespace kernel {
namespace util {

class AttributeStringFormatter {
public:
~AttributeStringFormatter();

AttributeStringFormatter(std::string_view attribute_string,
XLast* title_xlast,
std::map<uint32_t, uint32_t> contexts);

bool IsValid() const { return true; }
std::string GetPresenceString() const { return presence_string_; }

private:
enum class AttributeType { Context = 0, Property = 1, Unknown = 255 };

const std::regex presence_id_extract_from_specifier =
std::regex("\\{c(\\d+)\\}");
const std::regex format_specifier_replace_fragment_regex_ =
std::regex(R"(\{c\d+\}|\{p0x\d+\})");

bool ParseAttributeString();
void BuildPresenceString();

std::string GetStringFromSpecifier(std::string_view specifier) const;
std::queue<std::string> GetPresenceFormatSpecifiers() const;

AttributeType GetAttributeTypeFromSpecifier(std::string_view specifier) const;
std::optional<uint32_t> GetAttributeIdFromSpecifier(
const std::string& specifier,
const AttributeStringFormatter::AttributeType specifier_type) const;

const std::string attribute_string_;
std::map<std::string, std::string> attribute_to_string_mapping_;

std::string presence_string_;

std::map<uint32_t, uint32_t> contexts_;

XLast* title_xlast_;

// Tests
//
// std::map<uint32_t, std::string> contexts_ = {
// {0, "Context 0"}, {1, "Context 1"}, {2, "Context 2"}};

// std::map<uint32_t, std::string> properties_ = {
// {0x10000001, "Prop 0"}, {0x20000002, "Prop 2"}, {0x30000001, "Prop
// 3"}};
};

} // namespace util
} // namespace kernel
} // namespace xe

#endif XENIA_KERNEL_UTIL_PRESENCE_STRING_BUILDER_H_
15 changes: 15 additions & 0 deletions src/xenia/kernel/util/xlast.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "third_party/zlib/zlib.h"
#include "xenia/base/logging.h"
#include "xenia/base/string_util.h"
#include "xenia/kernel/util/presence_string_builder.h"

namespace xe {
namespace kernel {
Expand Down Expand Up @@ -182,6 +183,20 @@ const uint32_t XLast::GetPropertyStringId(const uint32_t property_id) {
return value;
}

const std::u16string XLast::GetPresenceRawString(const uint32_t presence_value,
const XLanguage language) {
const std::optional<uint32_t> presence_string_id =
GetPresenceStringId(presence_value);

std::u16string raw_presence = u"";

if (presence_string_id.has_value()) {
raw_presence = GetLocalizedString(presence_string_id.value(), language);
}

return raw_presence;
}

const uint32_t XLast::GetContextStringId(const uint32_t context_id,
const uint32_t context_value) {
std::string xpath = fmt::format(
Expand Down
2 changes: 2 additions & 0 deletions src/xenia/kernel/util/xlast.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ class XLast {
std::u16string GetLocalizedString(uint32_t string_id, XLanguage language);
XLastMatchmakingQuery* GetMatchmakingQuery(uint32_t query_id);
const std::optional<uint32_t> GetPresenceStringId(const uint32_t context_id);
const std::u16string GetPresenceRawString(const uint32_t presence_value,
const XLanguage language);
const uint32_t GetPropertyStringId(const uint32_t property_id);
const uint32_t GetContextStringId(const uint32_t context_id,
const uint32_t context_value);
Expand Down
4 changes: 4 additions & 0 deletions src/xenia/kernel/xam/apps/xgi_app.cc
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,10 @@ X_HRESULT XgiApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr,
UserProfile* user_profile = kernel_state_->user_profile(user_index);
if (user_profile) {
user_profile->contexts_[context_id] = context_value;

if (context_id == X_CONTEXT_PRESENCE) {
auto presence = user_profile->GetPresenceString();
}
}
}
return X_E_SUCCESS;
Expand Down
26 changes: 26 additions & 0 deletions src/xenia/kernel/xam/user_profile.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include <sstream>

#include <xenia/kernel/util/presence_string_builder.h>
#include "third_party/fmt/include/fmt/format.h"
#include "xenia/base/clock.h"
#include "xenia/base/cvar.h"
Expand All @@ -18,6 +19,7 @@
#include "xenia/emulator.h"
#include "xenia/kernel/kernel_state.h"
#include "xenia/kernel/util/shim_utils.h"
#include "xenia/kernel/util/xlast.h"
#include "xenia/kernel/xam/user_profile.h"

#include "xenia/kernel/XLiveAPI.h"
Expand Down Expand Up @@ -504,6 +506,30 @@ const std::vector<uint64_t> UserProfile::GetSubscribedXUIDs() const {
return subscribed_xuids;
}

std::string UserProfile::GetPresenceString() {
if (contexts_.find(X_CONTEXT_PRESENCE) == contexts_.end()) {
return "";
}

std::u16string presence = u"";

const auto xlast = kernel_state()->emulator()->xlast();

const std::u16string raw_presence = xlast->GetPresenceRawString(
contexts_[X_CONTEXT_PRESENCE], XLanguage::kEnglish);

const auto presence_string_formatter =
util::AttributeStringFormatter::AttributeStringFormatter(
xe::to_utf8(raw_presence), xlast, contexts_);

auto presence_parsed = presence_string_formatter.GetPresenceString();

XELOGI("Raw Presence: {}", xe::to_utf8(raw_presence.c_str()));
XELOGI("Parsed Presence: {}", presence_parsed);

return presence_parsed;
}

void UserProfile::AddSetting(std::unique_ptr<UserSetting> setting) {
UserSetting* previous_setting = setting.get();

Expand Down
2 changes: 2 additions & 0 deletions src/xenia/kernel/xam/user_profile.h
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,8 @@ class UserProfile {

const std::vector<uint64_t> GetSubscribedXUIDs() const;

std::string GetPresenceString();

void AddSetting(std::unique_ptr<UserSetting> setting);
UserSetting* GetSetting(uint32_t setting_id);

Expand Down

0 comments on commit fb93be0

Please sign in to comment.