Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -294,6 +294,7 @@
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=mipmaps/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Mordor/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=MSAA/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=multiplayer/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Multisample/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=multisampled/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=multisampling/@EntryIndexedValue">True</s:Boolean>
|
||||
|
||||
@@ -86,6 +86,8 @@ struct BoundingFrustum;
|
||||
struct Color;
|
||||
struct Color32;
|
||||
struct Variant;
|
||||
template<typename T>
|
||||
class Span;
|
||||
class HeapAllocation;
|
||||
template<int Capacity>
|
||||
class FixedAllocation;
|
||||
|
||||
@@ -773,6 +773,21 @@ Variant::Variant(const Dictionary<Variant, Variant>& v)
|
||||
AsDictionary = New<Dictionary<Variant, Variant>>(v);
|
||||
}
|
||||
|
||||
Variant::Variant(const Span<byte>& v)
|
||||
: Type(VariantType::Blob)
|
||||
{
|
||||
AsBlob.Length = v.Length();
|
||||
if (AsBlob.Length > 0)
|
||||
{
|
||||
AsBlob.Data = Allocator::Allocate(AsBlob.Length);
|
||||
Platform::MemoryCopy(AsBlob.Data, v.Get(), AsBlob.Length);
|
||||
}
|
||||
else
|
||||
{
|
||||
AsBlob.Data = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
Variant::Variant(const CommonValue& value)
|
||||
: Variant()
|
||||
{
|
||||
|
||||
@@ -229,6 +229,7 @@ public:
|
||||
Variant(Array<Variant, HeapAllocation>&& v);
|
||||
Variant(const Array<Variant, HeapAllocation>& v);
|
||||
explicit Variant(const Dictionary<Variant, Variant, HeapAllocation>& v);
|
||||
explicit Variant(const Span<byte>& v);
|
||||
explicit Variant(const CommonValue& v);
|
||||
|
||||
~Variant();
|
||||
|
||||
@@ -52,17 +52,15 @@ int32 GameBase::LoadProduct()
|
||||
|
||||
// Load build game header file
|
||||
{
|
||||
int32 tmp;
|
||||
Array<byte> data;
|
||||
FileReadStream* stream = nullptr;
|
||||
|
||||
#if 1
|
||||
// Open file
|
||||
FileReadStream* stream = nullptr;
|
||||
stream = FileReadStream::Open(Globals::ProjectFolder / TEXT("Content/head"));
|
||||
if (stream == nullptr)
|
||||
goto LOAD_GAME_HEAD_FAILED;
|
||||
|
||||
// Check header
|
||||
int32 tmp;
|
||||
stream->ReadInt32(&tmp);
|
||||
if (tmp != ('x' + 'D') * 131)
|
||||
goto LOAD_GAME_HEAD_FAILED;
|
||||
@@ -73,6 +71,7 @@ int32 GameBase::LoadProduct()
|
||||
goto LOAD_GAME_HEAD_FAILED;
|
||||
|
||||
// Load game primary data
|
||||
Array<byte> data;
|
||||
stream->ReadArray(&data);
|
||||
if (data.Count() != 808 + sizeof(Guid))
|
||||
goto LOAD_GAME_HEAD_FAILED;
|
||||
|
||||
@@ -37,6 +37,7 @@ public class Engine : EngineModule
|
||||
options.PublicDependencies.Add("Utilities");
|
||||
options.PublicDependencies.Add("Visject");
|
||||
options.PublicDependencies.Add("Localization");
|
||||
options.PublicDependencies.Add("Online");
|
||||
|
||||
// Use source folder per platform group
|
||||
switch (options.Platform.Target)
|
||||
|
||||
@@ -251,8 +251,8 @@ bool GPUDeviceDX12::Init()
|
||||
updateFrameEvents();
|
||||
|
||||
#if PLATFORM_GDK
|
||||
GDKPlatform::OnSuspend.Bind<GPUDeviceDX12, &GPUDeviceDX12::OnSuspend>(this);
|
||||
GDKPlatform::OnResume.Bind<GPUDeviceDX12, &GPUDeviceDX12::OnResume>(this);
|
||||
GDKPlatform::Suspended.Bind<GPUDeviceDX12, &GPUDeviceDX12::OnSuspended>(this);
|
||||
GDKPlatform::Resumed.Bind<GPUDeviceDX12, &GPUDeviceDX12::OnResumed>(this);
|
||||
#endif
|
||||
#else
|
||||
// Get DXGI adapter
|
||||
@@ -838,12 +838,12 @@ void GPUDeviceDX12::updateRes2Dispose()
|
||||
|
||||
#if PLATFORM_XBOX_SCARLETT || PLATFORM_XBOX_ONE
|
||||
|
||||
void GPUDeviceDX12::OnSuspend()
|
||||
void GPUDeviceDX12::OnSuspended()
|
||||
{
|
||||
_commandQueue->GetCommandQueue()->SuspendX(0);
|
||||
}
|
||||
|
||||
void GPUDeviceDX12::OnResume()
|
||||
void GPUDeviceDX12::OnResumed()
|
||||
{
|
||||
_commandQueue->GetCommandQueue()->ResumeX();
|
||||
|
||||
|
||||
@@ -158,8 +158,8 @@ public:
|
||||
}
|
||||
|
||||
#if PLATFORM_XBOX_SCARLETT ||PLATFORM_XBOX_ONE
|
||||
void OnSuspend();
|
||||
void OnResume();
|
||||
void OnSuspended();
|
||||
void OnResumed();
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
@@ -0,0 +1,237 @@
|
||||
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Online.h"
|
||||
#include "Engine/Core/Types/Span.h"
|
||||
#include "Engine/Core/Types/String.h"
|
||||
#include "Engine/Core/Types/DateTime.h"
|
||||
|
||||
/// <summary>
|
||||
/// Online platform user presence common states.
|
||||
/// </summary>
|
||||
API_ENUM(Namespace="FlaxEngine.Online") enum class OnlinePresenceStates
|
||||
{
|
||||
/// <summary>
|
||||
/// User is offline.
|
||||
/// </summary>
|
||||
Offline = 0,
|
||||
|
||||
/// <summary>
|
||||
/// User is online.
|
||||
/// </summary>
|
||||
Online,
|
||||
|
||||
/// <summary>
|
||||
/// User is online but busy.
|
||||
/// </summary>
|
||||
Busy,
|
||||
|
||||
/// <summary>
|
||||
/// User is online but away (no activity for some time).
|
||||
/// </summary>
|
||||
Away,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Online platform user description.
|
||||
/// </summary>
|
||||
API_STRUCT(Namespace="FlaxEngine.Online") struct FLAXENGINE_API OnlineUser
|
||||
{
|
||||
DECLARE_SCRIPTING_TYPE_MINIMAL(OnlineUser);
|
||||
|
||||
/// <summary>
|
||||
/// Unique player identifier. Specific for a certain online platform.
|
||||
/// </summary>
|
||||
API_FIELD() Guid Id;
|
||||
|
||||
/// <summary>
|
||||
/// The player name.
|
||||
/// </summary>
|
||||
API_FIELD() String Name;
|
||||
|
||||
/// <summary>
|
||||
/// The current player presence state.
|
||||
/// </summary>
|
||||
API_FIELD() OnlinePresenceStates PresenceState;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Online platform achievement description.
|
||||
/// </summary>
|
||||
API_STRUCT(Namespace="FlaxEngine.Online") struct FLAXENGINE_API OnlineAchievement
|
||||
{
|
||||
DECLARE_SCRIPTING_TYPE_MINIMAL(OnlineAchievement);
|
||||
|
||||
/// <summary>
|
||||
/// Unique achievement identifier. Specific for a certain online platform.
|
||||
/// </summary>
|
||||
API_FIELD() String Identifier;
|
||||
|
||||
/// <summary>
|
||||
/// Achievement name. Specific for a game.
|
||||
/// </summary>
|
||||
API_FIELD() String Name;
|
||||
|
||||
/// <summary>
|
||||
/// The achievement title text.
|
||||
/// </summary>
|
||||
API_FIELD() String Title;
|
||||
|
||||
/// <summary>
|
||||
/// The achievement description text.
|
||||
/// </summary>
|
||||
API_FIELD() String Description;
|
||||
|
||||
/// <summary>
|
||||
/// True if achievement is hidden from user (eg. can see it once it's unlocked).
|
||||
/// </summary>
|
||||
API_FIELD() bool IsHidden = false;
|
||||
|
||||
/// <summary>
|
||||
/// Achievement unlock percentage progress (normalized to 0-100 range).
|
||||
/// </summary>
|
||||
API_FIELD() float Progress = 0.0f;
|
||||
|
||||
/// <summary>
|
||||
/// Date and time at which player unlocked the achievement.
|
||||
/// </summary>
|
||||
API_FIELD() DateTime UnlockTime = DateTime::MinValue();
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Interface for online platform providers for communicating with various multiplayer services such as player info, achievements, game lobby or in-game store.
|
||||
/// </summary>
|
||||
API_INTERFACE(Namespace="FlaxEngine.Online") class FLAXENGINE_API IOnlinePlatform
|
||||
{
|
||||
DECLARE_SCRIPTING_TYPE_MINIMAL(IOnlinePlatform);
|
||||
|
||||
/// <summary>
|
||||
/// Finalizes an instance of the <see cref="IOnlinePlatform"/> class.
|
||||
/// </summary>
|
||||
virtual ~IOnlinePlatform() = default;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the online platform services.
|
||||
/// </summary>
|
||||
/// <remarks>Called only by Online system.</remarks>
|
||||
/// <returns>True if failed, otherwise false.</returns>
|
||||
API_FUNCTION() virtual bool Initialize() = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Shutdowns the online platform services.
|
||||
/// </summary>
|
||||
/// <remarks>Called only by Online system. Can be used to destroy the object.</remarks>
|
||||
API_FUNCTION() virtual void Deinitialize() = 0;
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
/// Logins the local user into the online platform.
|
||||
/// </summary>
|
||||
/// <param name="localUser">The local user (null if use default one).</param>
|
||||
/// <returns>True if failed, otherwise false.</returns>
|
||||
API_FUNCTION() virtual bool UserLogin(User* localUser = nullptr) = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Logout the local user from the online platform.
|
||||
/// </summary>
|
||||
/// <param name="localUser">The local user (null if use default one).</param>
|
||||
/// <returns>True if failed, otherwise false.</returns>
|
||||
API_FUNCTION() virtual bool UserLogout(User* localUser = nullptr) = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the local user is logged in.
|
||||
/// </summary>
|
||||
/// <param name="localUser">The local user (null if use default one).</param>
|
||||
/// <returns>True if user is logged, otherwise false.</returns>
|
||||
API_FUNCTION() virtual bool GetUserLoggedIn(User* localUser = nullptr) = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the player from the online platform.
|
||||
/// </summary>
|
||||
/// <param name="user">The local player user info.</param>
|
||||
/// <param name="localUser">The local user (null if use default one).</param>
|
||||
/// <returns>True if failed, otherwise false.</returns>
|
||||
API_FUNCTION() virtual bool GetUser(API_PARAM(Out) OnlineUser& user, User* localUser = nullptr) = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of friends of the user from the online platform.
|
||||
/// </summary>
|
||||
/// <param name="friends">The result local player friends user infos.</param>
|
||||
/// <param name="localUser">The local user (null if use default one).</param>
|
||||
/// <returns>True if failed, otherwise false.</returns>
|
||||
API_FUNCTION() virtual bool GetFriends(API_PARAM(Out) Array<OnlineUser, HeapAllocation>& friends, User* localUser = nullptr) = 0;
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
/// Gets the list of all achievements for this game.
|
||||
/// </summary>
|
||||
/// <param name="achievements">The result achievements list</param>
|
||||
/// <param name="localUser">The local user (null if use default one).</param>
|
||||
/// <returns>True if failed, otherwise false.</returns>
|
||||
API_FUNCTION() virtual bool GetAchievements(API_PARAM(Out) Array<OnlineAchievement, HeapAllocation>& achievements, User* localUser = nullptr) = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Unlocks the achievement.
|
||||
/// </summary>
|
||||
/// <param name="name">The achievement name. Specific for a game.</param>
|
||||
/// <param name="localUser">The local user (null if use default one).</param>
|
||||
/// <returns>True if failed, otherwise false.</returns>
|
||||
API_FUNCTION() virtual bool UnlockAchievement(const StringView& name, User* localUser = nullptr) = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Updates the achievement unlocking progress (in range 0-100).
|
||||
/// </summary>
|
||||
/// <param name="name">The achievement name. Specific for a game.</param>
|
||||
/// <param name="progress">The achievement unlock progress (in range 0-100).</param>
|
||||
/// <param name="localUser">The local user (null if use default one).</param>
|
||||
/// <returns>True if failed, otherwise false.</returns>
|
||||
API_FUNCTION() virtual bool UnlockAchievementProgress(const StringView& name, float progress, User* localUser = nullptr) = 0;
|
||||
|
||||
#if !BUILD_RELEASE
|
||||
/// <summary>
|
||||
/// Resets the all achievements progress for this game.
|
||||
/// </summary>
|
||||
/// <param name="localUser">The local user (null if use default one).</param>
|
||||
/// <returns>True if failed, otherwise false.</returns>
|
||||
API_FUNCTION() virtual bool ResetAchievements(User* localUser = nullptr) = 0;
|
||||
#endif
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
/// Gets the online statistical value.
|
||||
/// </summary>
|
||||
/// <param name="name">The stat name.</param>
|
||||
/// <param name="value">The result value.</param>
|
||||
/// <param name="localUser">The local user (null if use default one).</param>
|
||||
/// <returns>True if failed, otherwise false.</returns>
|
||||
API_FUNCTION() virtual bool GetStat(const StringView& name, API_PARAM(Out) float& value, User* localUser = nullptr) = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the online statistical value.
|
||||
/// </summary>
|
||||
/// <param name="name">The stat name.</param>
|
||||
/// <param name="value">The value.</param>
|
||||
/// <param name="localUser">The local user (null if use default one).</param>
|
||||
/// <returns>True if failed, otherwise false.</returns>
|
||||
API_FUNCTION() virtual bool SetStat(const StringView& name, float value, User* localUser = nullptr) = 0;
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
/// Gets the online savegame data. Returns empty if savegame slot is unused.
|
||||
/// </summary>
|
||||
/// <param name="name">The savegame slot name.</param>
|
||||
/// <param name="data">The result data. Empty or null for unused slot name.</param>
|
||||
/// <param name="localUser">The local user (null if use default one).</param>
|
||||
/// <returns>True if failed, otherwise false.</returns>
|
||||
API_FUNCTION() virtual bool GetSaveGame(const StringView& name, API_PARAM(Out) Array<byte, HeapAllocation>& data, User* localUser = nullptr) = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the online savegame data.
|
||||
/// </summary>
|
||||
/// <param name="name">The savegame slot name.</param>
|
||||
/// <param name="data">The data. Empty or null to delete slot (or mark as unused).</param>
|
||||
/// <param name="localUser">The local user (null if use default one).</param>
|
||||
/// <returns>True if failed, otherwise false.</returns>
|
||||
API_FUNCTION() virtual bool SetSaveGame(const StringView& name, const Span<byte>& data, User* localUser = nullptr) = 0;
|
||||
};
|
||||
@@ -0,0 +1,10 @@
|
||||
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
|
||||
|
||||
using Flax.Build;
|
||||
|
||||
/// <summary>
|
||||
/// Online services base module.
|
||||
/// </summary>
|
||||
public class Online : EngineModule
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "Online.h"
|
||||
#include "IOnlinePlatform.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Engine/EngineService.h"
|
||||
#include "Engine/Scripting/ScriptingObject.h"
|
||||
|
||||
class OnlineService : public EngineService
|
||||
{
|
||||
public:
|
||||
OnlineService()
|
||||
: EngineService(TEXT("Online"), 100)
|
||||
{
|
||||
}
|
||||
|
||||
void Dispose() override
|
||||
{
|
||||
// Cleanup current online platform
|
||||
Online::Initialize(nullptr);
|
||||
}
|
||||
};
|
||||
|
||||
IOnlinePlatform* Online::Platform = nullptr;
|
||||
Action Online::PlatformChanged;
|
||||
OnlineService OnlineServiceInstance;
|
||||
|
||||
bool Online::Initialize(IOnlinePlatform* platform)
|
||||
{
|
||||
if (Platform == platform)
|
||||
return false;
|
||||
const auto object = ScriptingObject::FromInterface(platform, IOnlinePlatform::TypeInitializer);
|
||||
LOG(Info, "Changing online platform to {0}", object ? object->ToString() : (platform ? TEXT("?") : TEXT("none")));
|
||||
|
||||
if (Platform)
|
||||
{
|
||||
Platform->Deinitialize();
|
||||
}
|
||||
Platform = platform;
|
||||
if (Platform)
|
||||
{
|
||||
if (Platform->Initialize())
|
||||
{
|
||||
Platform = nullptr;
|
||||
LOG(Error, "Failed to initialize online platform.");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Engine/Core/Delegate.h"
|
||||
#include "Engine/Scripting/ScriptingType.h"
|
||||
|
||||
class IOnlinePlatform;
|
||||
|
||||
/// <summary>
|
||||
/// The online system for communicating with various multiplayer services such as player info, achievements, game lobby or in-game store.
|
||||
/// </summary>
|
||||
API_CLASS(Static, Namespace="FlaxEngine.Online") class FLAXENGINE_API Online
|
||||
{
|
||||
DECLARE_SCRIPTING_TYPE_NO_SPAWN(Online);
|
||||
public:
|
||||
/// <summary>
|
||||
/// The current online platform.
|
||||
/// </summary>
|
||||
API_FIELD(ReadOnly) static IOnlinePlatform* Platform;
|
||||
|
||||
/// <summary>
|
||||
/// Event called when current online platform gets changed.
|
||||
/// </summary>
|
||||
API_EVENT() static Action PlatformChanged;
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
/// Initializes the online system with a given online platform implementation.
|
||||
/// </summary>
|
||||
/// <remarks>Destroys the current platform (in any already in-use).</remarks>
|
||||
/// <param name="platform">The online platform object.</param>
|
||||
/// <returns>True if failed, otherwise false.</returns>
|
||||
API_FUNCTION() static bool Initialize(IOnlinePlatform* platform);
|
||||
};
|
||||
@@ -406,6 +406,12 @@ bool StringUtils::Parse(const Char* str, float* result)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool StringUtils::Parse(const char* str, float* result)
|
||||
{
|
||||
*result = (float)atof(str);
|
||||
return false;
|
||||
}
|
||||
|
||||
String StringUtils::ToString(int32 value)
|
||||
{
|
||||
char buf[STRING_UTILS_ITOSTR_BUFFER_SIZE];
|
||||
|
||||
@@ -21,6 +21,10 @@
|
||||
#include <XGameRuntime.h>
|
||||
#include <appnotify.h>
|
||||
|
||||
#define GDK_LOG(result, method) \
|
||||
if (FAILED(result)) \
|
||||
LOG(Error, "GDK method {0} failed with result 0x{1:x}", TEXT(method), (uint32)result)
|
||||
|
||||
inline bool operator==(const APP_LOCAL_DEVICE_ID& l, const APP_LOCAL_DEVICE_ID& r)
|
||||
{
|
||||
return Platform::MemoryCompare(&l, &r, sizeof(APP_LOCAL_DEVICE_ID)) == 0;
|
||||
@@ -28,8 +32,8 @@ inline bool operator==(const APP_LOCAL_DEVICE_ID& l, const APP_LOCAL_DEVICE_ID&
|
||||
|
||||
const Char* GDKPlatform::ApplicationWindowClass = TEXT("FlaxWindow");
|
||||
void* GDKPlatform::Instance = nullptr;
|
||||
Delegate<> GDKPlatform::OnSuspend;
|
||||
Delegate<> GDKPlatform::OnResume;
|
||||
Delegate<> GDKPlatform::Suspended;
|
||||
Delegate<> GDKPlatform::Resumed;
|
||||
|
||||
namespace
|
||||
{
|
||||
@@ -51,7 +55,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
LOG(Info, "Suspending application");
|
||||
IsSuspended = true;
|
||||
GDKPlatform::OnSuspend();
|
||||
GDKPlatform::Suspended();
|
||||
|
||||
// Complete deferral
|
||||
SetEvent(PlmSuspendComplete);
|
||||
@@ -60,7 +64,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
|
||||
IsSuspended = false;
|
||||
LOG(Info, "Resuming application");
|
||||
GDKPlatform::OnResume();
|
||||
GDKPlatform::Resumed();
|
||||
return DefWindowProc(hWnd, msg, wParam, lParam);
|
||||
}
|
||||
}
|
||||
@@ -93,6 +97,7 @@ void CALLBACK UserChangeEventCallback(_In_opt_ void* context, _In_ XUserLocalId
|
||||
if (user)
|
||||
{
|
||||
// Logout
|
||||
LOG(Info, "GDK user '{0}' logged out", user->GetName());
|
||||
OnPlatformUserRemove(user);
|
||||
}
|
||||
break;
|
||||
@@ -161,8 +166,9 @@ void OnMainWindowCreated(HWND hWnd)
|
||||
void CALLBACK AddUserComplete(_In_ XAsyncBlock* ab)
|
||||
{
|
||||
XUserHandle userHandle;
|
||||
HRESULT hr = XUserAddResult(ab, &userHandle);
|
||||
if (SUCCEEDED(hr))
|
||||
HRESULT result = XUserAddResult(ab, &userHandle);
|
||||
delete ab;
|
||||
if (SUCCEEDED(result))
|
||||
{
|
||||
XUserLocalId userLocalId;
|
||||
XUserGetLocalId(userHandle, &userLocalId);
|
||||
@@ -173,12 +179,24 @@ void CALLBACK AddUserComplete(_In_ XAsyncBlock* ab)
|
||||
if (Platform::FindUser(localId) == nullptr)
|
||||
{
|
||||
// Login
|
||||
auto user = New<User>(userHandle, userLocalId, String::Empty);
|
||||
char gamerTag[XUserGamertagComponentModernMaxBytes];
|
||||
size_t gamerTagSize;
|
||||
XUserGetGamertag(userHandle, XUserGamertagComponent::Modern, ARRAY_COUNT(gamerTag), gamerTag, &gamerTagSize);
|
||||
String name;
|
||||
name.SetUTF8(gamerTag, StringUtils::Length(gamerTag));
|
||||
LOG(Info, "GDK user '{0}' logged in", name);
|
||||
auto user = New<User>(userHandle, userLocalId, name);
|
||||
OnPlatformUserAdd(user);
|
||||
}
|
||||
}
|
||||
|
||||
delete ab;
|
||||
else if (result == E_GAMEUSER_NO_DEFAULT_USER || result == E_GAMEUSER_RESOLVE_USER_ISSUE_REQUIRED || result == 0x8015DC12)
|
||||
{
|
||||
Platform::SignInWithUI();
|
||||
}
|
||||
else
|
||||
{
|
||||
GDK_LOG(result, "XUserAddResult");
|
||||
}
|
||||
}
|
||||
|
||||
DialogResult MessageBox::Show(Window* parent, const StringView& text, const StringView& caption, MessageBoxButtons buttons, MessageBoxIcon icon)
|
||||
@@ -312,6 +330,32 @@ bool GDKPlatform::IsRunningOnDevKit()
|
||||
return deviceType == XSystemDeviceType::XboxOneXDevkit || deviceType == XSystemDeviceType::XboxScarlettDevkit;
|
||||
}
|
||||
|
||||
void GDKPlatform::SignInSilently()
|
||||
{
|
||||
auto asyncBlock = new XAsyncBlock();
|
||||
asyncBlock->queue = TaskQueue;
|
||||
asyncBlock->callback = AddUserComplete;
|
||||
HRESULT result = XUserAddAsync(XUserAddOptions::AddDefaultUserSilently, asyncBlock);
|
||||
if (FAILED(result))
|
||||
{
|
||||
GDK_LOG(result, "XUserAddAsync");
|
||||
delete asyncBlock;
|
||||
}
|
||||
}
|
||||
|
||||
void GDKPlatform::SignInWithUI()
|
||||
{
|
||||
auto ab = new XAsyncBlock();
|
||||
ab->queue = TaskQueue;
|
||||
ab->callback = AddUserComplete;
|
||||
HRESULT result = XUserAddAsync(XUserAddOptions::AllowGuests, ab);
|
||||
if (FAILED(result))
|
||||
{
|
||||
GDK_LOG(result, "XUserAddAsync");
|
||||
delete ab;
|
||||
}
|
||||
}
|
||||
|
||||
User* GDKPlatform::FindUser(const XUserLocalId& id)
|
||||
{
|
||||
User* result = nullptr;
|
||||
@@ -366,29 +410,27 @@ bool GDKPlatform::Init()
|
||||
&UserDeviceAssociationChangedCallbackToken
|
||||
);
|
||||
|
||||
// Login the default user
|
||||
{
|
||||
auto asyncBlock = new XAsyncBlock();
|
||||
asyncBlock->queue = TaskQueue;
|
||||
asyncBlock->callback = AddUserComplete;
|
||||
HRESULT hr = XUserAddAsync(XUserAddOptions::AddDefaultUserAllowingUI, asyncBlock);
|
||||
if (FAILED(hr))
|
||||
delete asyncBlock;
|
||||
}
|
||||
|
||||
GDKInput::Init();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void GDKPlatform::BeforeRun()
|
||||
void GDKPlatform::LogInfo()
|
||||
{
|
||||
Win32Platform::LogInfo();
|
||||
|
||||
// Log system info
|
||||
const XSystemAnalyticsInfo analyticsInfo = XSystemGetAnalyticsInfo();
|
||||
LOG(Info, "{0}, {1}", StringAsUTF16<64>(analyticsInfo.family).Get(), StringAsUTF16<64>(analyticsInfo.form).Get());
|
||||
LOG(Info, "OS Version {0}.{1}.{2}.{3}", analyticsInfo.osVersion.major, analyticsInfo.osVersion.minor, analyticsInfo.osVersion.build, analyticsInfo.osVersion.revision);
|
||||
}
|
||||
|
||||
void GDKPlatform::BeforeRun()
|
||||
{
|
||||
// Login the default user
|
||||
SignInSilently();
|
||||
}
|
||||
|
||||
void GDKPlatform::Tick()
|
||||
{
|
||||
PROFILE_CPU_NAMED("Application.Tick");
|
||||
|
||||
@@ -23,8 +23,8 @@ public:
|
||||
/// </summary>
|
||||
static void* Instance;
|
||||
|
||||
static Delegate<> OnSuspend;
|
||||
static Delegate<> OnResume;
|
||||
static Delegate<> Suspended;
|
||||
static Delegate<> Resumed;
|
||||
|
||||
public:
|
||||
|
||||
@@ -44,12 +44,15 @@ public:
|
||||
|
||||
static bool IsRunningOnDevKit();
|
||||
|
||||
static void SignInSilently();
|
||||
static void SignInWithUI();
|
||||
static User* FindUser(const struct XUserLocalId& id);
|
||||
|
||||
public:
|
||||
|
||||
// [Win32Platform]
|
||||
static bool Init();
|
||||
static void LogInfo();
|
||||
static void BeforeRun();
|
||||
static void Tick();
|
||||
static void BeforeExit();
|
||||
|
||||
@@ -15,9 +15,8 @@ class Texture;
|
||||
/// </summary>
|
||||
API_CLASS(Namespace="FlaxEditor.Content.Settings") class FLAXENGINE_API GDKPlatformSettings : public SettingsBase
|
||||
{
|
||||
DECLARE_SCRIPTING_TYPE_MINIMAL(GDKPlatformSettings);
|
||||
DECLARE_SCRIPTING_TYPE_MINIMAL(GDKPlatformSettings);
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Game identity name stored in game package manifest (for store). If empty the product name will be used from Game Settings.
|
||||
/// </summary>
|
||||
@@ -96,6 +95,12 @@ public:
|
||||
API_FIELD(Attributes="EditorOrder(320), EditorDisplay(\"Xbox Live\")")
|
||||
bool RequiresXboxLive = false;
|
||||
|
||||
/// <summary>
|
||||
/// Service Configuration ID (see Xbox Live docs).
|
||||
/// </summary>
|
||||
API_FIELD(Attributes="EditorOrder(330), EditorDisplay(\"Xbox Live\")")
|
||||
StringAnsi SCID;
|
||||
|
||||
/// <summary>
|
||||
/// Specifies if the Game DVR system component is enabled or not.
|
||||
/// </summary>
|
||||
@@ -106,16 +111,15 @@ public:
|
||||
/// Specifies if broadcasting the title should be blocked or allowed.
|
||||
/// </summary>
|
||||
API_FIELD(Attributes="EditorOrder(410), EditorDisplay(\"Media Capture\")")
|
||||
bool BlockBroadcast = false;
|
||||
bool BlockBroadcast = false;
|
||||
|
||||
/// <summary>
|
||||
/// Specifies if Game DVR of the title should be blocked or allowed.
|
||||
/// </summary>
|
||||
API_FIELD(Attributes="EditorOrder(420), EditorDisplay(\"Media Capture\")")
|
||||
bool BlockGameDVR = false;
|
||||
bool BlockGameDVR = false;
|
||||
|
||||
public:
|
||||
|
||||
// [SettingsBase]
|
||||
void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) override
|
||||
{
|
||||
@@ -131,6 +135,7 @@ public:
|
||||
DESERIALIZE(TitleId);
|
||||
DESERIALIZE(StoreId);
|
||||
DESERIALIZE(RequiresXboxLive);
|
||||
DESERIALIZE(SCID);
|
||||
DESERIALIZE(GameDVRSystemComponent);
|
||||
DESERIALIZE(BlockBroadcast);
|
||||
DESERIALIZE(BlockGameDVR);
|
||||
|
||||
@@ -428,6 +428,7 @@ public:
|
||||
// @return Result value
|
||||
// @returns True if cannot convert data, otherwise false
|
||||
static bool Parse(const Char* str, float* result);
|
||||
static bool Parse(const char* str, float* result);
|
||||
|
||||
public:
|
||||
|
||||
|
||||
@@ -411,8 +411,7 @@ namespace Flax.Build.Bindings
|
||||
if ((typeInfo.Type == "Array" || typeInfo.Type == "Span") && typeInfo.GenericArgs != null)
|
||||
{
|
||||
type = "MonoArray*";
|
||||
var valueClass = GenerateCppGetNativeClass(buildData, typeInfo.GenericArgs[0], caller, functionInfo);
|
||||
return "MUtils::ToArray({0}, " + valueClass + ")";
|
||||
return "MUtils::ToArray({0}, " + GenerateCppGetNativeClass(buildData, typeInfo.GenericArgs[0], caller, functionInfo) + ")";
|
||||
}
|
||||
|
||||
// BytesContainer
|
||||
@@ -735,6 +734,43 @@ namespace Flax.Build.Bindings
|
||||
}
|
||||
}
|
||||
|
||||
private static string GenerateCppWrapperNativeToBox(BuildData buildData, TypeInfo typeInfo, ApiTypeInfo caller, string value)
|
||||
{
|
||||
// Optimize passing scripting objects
|
||||
var apiType = FindApiTypeInfo(buildData, typeInfo, caller);
|
||||
if (apiType != null && apiType.IsScriptingObject)
|
||||
return $"ScriptingObject::ToManaged((ScriptingObject*){value})";
|
||||
|
||||
// Array or Span
|
||||
if ((typeInfo.Type == "Array" || typeInfo.Type == "Span") && typeInfo.GenericArgs != null && typeInfo.GenericArgs.Count >= 1)
|
||||
return $"MUtils::ToArray({value}, {GenerateCppGetNativeClass(buildData, typeInfo.GenericArgs[0], caller, null)})";
|
||||
|
||||
// BytesContainer
|
||||
if (typeInfo.Type == "BytesContainer" && typeInfo.GenericArgs == null)
|
||||
return "MUtils::ToArray({0})";
|
||||
|
||||
// Construct native typename for MUtils template argument
|
||||
var nativeType = new StringBuilder(64);
|
||||
nativeType.Append(typeInfo.Type);
|
||||
if (typeInfo.GenericArgs != null)
|
||||
{
|
||||
nativeType.Append('<');
|
||||
for (var j = 0; j < typeInfo.GenericArgs.Count; j++)
|
||||
{
|
||||
if (j != 0)
|
||||
nativeType.Append(", ");
|
||||
nativeType.Append(typeInfo.GenericArgs[j]);
|
||||
}
|
||||
|
||||
nativeType.Append('>');
|
||||
}
|
||||
if (typeInfo.IsPtr)
|
||||
nativeType.Append('*');
|
||||
|
||||
// Use MUtils to box the value
|
||||
return $"MUtils::Box<{nativeType}>({value}, {GenerateCppGetNativeClass(buildData, typeInfo, caller, null)})";
|
||||
}
|
||||
|
||||
private static void GenerateCppWrapperFunction(BuildData buildData, StringBuilder contents, ApiTypeInfo caller, FunctionInfo functionInfo, string callFormat = "{0}({1})")
|
||||
{
|
||||
// Setup function binding glue to ensure that wrapper method signature matches for C++ and C#
|
||||
@@ -1127,33 +1163,8 @@ namespace Flax.Build.Bindings
|
||||
separator = true;
|
||||
thunkParams += "void*";
|
||||
|
||||
// Optimize passing scripting objects
|
||||
var apiType = FindApiTypeInfo(buildData, parameterInfo.Type, classInfo);
|
||||
if (apiType != null && apiType.IsScriptingObject)
|
||||
{
|
||||
thunkCall += $"ScriptingObject::ToManaged((ScriptingObject*){parameterInfo.Name})";
|
||||
continue;
|
||||
}
|
||||
|
||||
var nativeType = new StringBuilder(64);
|
||||
nativeType.Append(parameterInfo.Type.Type);
|
||||
if (parameterInfo.Type.GenericArgs != null)
|
||||
{
|
||||
nativeType.Append('<');
|
||||
for (var j = 0; j < parameterInfo.Type.GenericArgs.Count; j++)
|
||||
{
|
||||
if (j != 0)
|
||||
nativeType.Append(", ");
|
||||
nativeType.Append(parameterInfo.Type.GenericArgs[j]);
|
||||
}
|
||||
|
||||
nativeType.Append('>');
|
||||
}
|
||||
if (parameterInfo.Type.IsPtr)
|
||||
nativeType.Append('*');
|
||||
|
||||
// Mono thunk call uses boxed values as objects
|
||||
thunkCall += $"MUtils::Box<{nativeType}>({parameterInfo.Name}, {GenerateCppGetNativeClass(buildData, parameterInfo.Type, classInfo, null)})";
|
||||
thunkCall += GenerateCppWrapperNativeToBox(buildData, parameterInfo.Type, classInfo, parameterInfo.Name);
|
||||
}
|
||||
|
||||
if (functionInfo.ReturnType.IsVoid)
|
||||
|
||||
Reference in New Issue
Block a user