diff --git a/Source/Engine/Engine/Engine.Build.cs b/Source/Engine/Engine/Engine.Build.cs
index e7bf85034..85c88024d 100644
--- a/Source/Engine/Engine/Engine.Build.cs
+++ b/Source/Engine/Engine/Engine.Build.cs
@@ -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)
diff --git a/Source/Engine/Online/IOnlinePlatform.h b/Source/Engine/Online/IOnlinePlatform.h
new file mode 100644
index 000000000..6d387021d
--- /dev/null
+++ b/Source/Engine/Online/IOnlinePlatform.h
@@ -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"
+
+///
+/// Online platform user presence common states.
+///
+API_ENUM(Namespace="FlaxEngine.Online") enum class OnlinePresenceStates
+{
+ ///
+ /// User is offline.
+ ///
+ Offline = 0,
+
+ ///
+ /// User is online.
+ ///
+ Online,
+
+ ///
+ /// User is online but busy.
+ ///
+ Busy,
+
+ ///
+ /// User is online but away (no activity for some time).
+ ///
+ Away,
+};
+
+///
+/// Online platform user description.
+///
+API_STRUCT(Namespace="FlaxEngine.Online") struct FLAXENGINE_API OnlineUser
+{
+ DECLARE_SCRIPTING_TYPE_MINIMAL(OnlineUser);
+
+ ///
+ /// Unique player identifier. Specific for a certain online platform.
+ ///
+ API_FIELD() Guid Id;
+
+ ///
+ /// The player name.
+ ///
+ API_FIELD() String Name;
+
+ ///
+ /// The current player presence state.
+ ///
+ API_FIELD() OnlinePresenceStates PresenceState;
+};
+
+///
+/// Online platform achievement description.
+///
+API_STRUCT(Namespace="FlaxEngine.Online") struct FLAXENGINE_API OnlineAchievement
+{
+ DECLARE_SCRIPTING_TYPE_MINIMAL(OnlineAchievement);
+
+ ///
+ /// Unique achievement identifier. Specific for a certain online platform.
+ ///
+ API_FIELD() String Identifier;
+
+ ///
+ /// Achievement name. Specific for a game.
+ ///
+ API_FIELD() String Name;
+
+ ///
+ /// The achievement title text.
+ ///
+ API_FIELD() String Title;
+
+ ///
+ /// The achievement description text.
+ ///
+ API_FIELD() String Description;
+
+ ///
+ /// True if achievement is hidden from user (eg. can see it once it's unlocked).
+ ///
+ API_FIELD() bool IsHidden = false;
+
+ ///
+ /// Achievement unlock percentage progress (normalized to 0-100 range).
+ ///
+ API_FIELD() float Progress = 0.0f;
+
+ ///
+ /// Date and time at which player unlocked the achievement.
+ ///
+ API_FIELD() DateTime UnlockTime = DateTime::MinValue();
+};
+
+///
+/// Interface for online platform providers for communicating with various multiplayer services such as player info, achievements, game lobby or in-game store.
+///
+API_INTERFACE(Namespace="FlaxEngine.Online") class FLAXENGINE_API IOnlinePlatform
+{
+ DECLARE_SCRIPTING_TYPE_MINIMAL(IOnlinePlatform);
+
+ ///
+ /// Finalizes an instance of the class.
+ ///
+ virtual ~IOnlinePlatform() = default;
+
+ ///
+ /// Initializes the online platform services.
+ ///
+ /// Called only by Online system.
+ /// True if failed, otherwise false.
+ API_FUNCTION() virtual bool Initialize() = 0;
+
+ ///
+ /// Shutdowns the online platform services.
+ ///
+ /// Called only by Online system. Can be used to destroy the object.
+ API_FUNCTION() virtual void Deinitialize() = 0;
+
+public:
+ ///
+ /// Logins the local user into the online platform.
+ ///
+ /// The local user (null if use default one).
+ /// True if failed, otherwise false.
+ API_FUNCTION() virtual bool UserLogin(User* localUser = nullptr) = 0;
+
+ ///
+ /// Logout the local user from the online platform.
+ ///
+ /// The local user (null if use default one).
+ /// True if failed, otherwise false.
+ API_FUNCTION() virtual bool UserLogout(User* localUser = nullptr) = 0;
+
+ ///
+ /// Checks if the local user is logged in.
+ ///
+ /// The local user (null if use default one).
+ /// True if user is logged, otherwise false.
+ API_FUNCTION() virtual bool GetUserLoggedIn(User* localUser = nullptr) = 0;
+
+ ///
+ /// Gets the player from the online platform.
+ ///
+ /// The local player user info.
+ /// The local user (null if use default one).
+ /// True if failed, otherwise false.
+ API_FUNCTION() virtual bool GetUser(API_PARAM(Out) OnlineUser& user, User* localUser = nullptr) = 0;
+
+ ///
+ /// Gets the list of friends of the user from the online platform.
+ ///
+ /// The result local player friends user infos.
+ /// The local user (null if use default one).
+ /// True if failed, otherwise false.
+ API_FUNCTION() virtual bool GetFriends(API_PARAM(Out) Array& friends, User* localUser = nullptr) = 0;
+
+public:
+ ///
+ /// Gets the list of all achievements for this game.
+ ///
+ /// The result achievements list
+ /// The local user (null if use default one).
+ /// True if failed, otherwise false.
+ API_FUNCTION() virtual bool GetAchievements(API_PARAM(Out) Array& achievements, User* localUser = nullptr) = 0;
+
+ ///
+ /// Unlocks the achievement.
+ ///
+ /// The achievement name. Specific for a game.
+ /// The local user (null if use default one).
+ /// True if failed, otherwise false.
+ API_FUNCTION() virtual bool UnlockAchievement(const StringView& name, User* localUser = nullptr) = 0;
+
+ ///
+ /// Updates the achievement unlocking progress (in range 0-100).
+ ///
+ /// The achievement name. Specific for a game.
+ /// The achievement unlock progress (in range 0-100).
+ /// The local user (null if use default one).
+ /// True if failed, otherwise false.
+ API_FUNCTION() virtual bool UnlockAchievementProgress(const StringView& name, float progress, User* localUser = nullptr) = 0;
+
+#if !BUILD_RELEASE
+ ///
+ /// Resets the all achievements progress for this game.
+ ///
+ /// The local user (null if use default one).
+ /// True if failed, otherwise false.
+ API_FUNCTION() virtual bool ResetAchievements(User* localUser = nullptr) = 0;
+#endif
+
+public:
+ ///
+ /// Gets the online statistical value.
+ ///
+ /// The stat name.
+ /// The result value.
+ /// The local user (null if use default one).
+ /// True if failed, otherwise false.
+ API_FUNCTION() virtual bool GetStat(const StringView& name, API_PARAM(Out) float& value, User* localUser = nullptr) = 0;
+
+ ///
+ /// Sets the online statistical value.
+ ///
+ /// The stat name.
+ /// The value.
+ /// The local user (null if use default one).
+ /// True if failed, otherwise false.
+ API_FUNCTION() virtual bool SetStat(const StringView& name, float value, User* localUser = nullptr) = 0;
+
+public:
+ ///
+ /// Gets the online savegame data. Returns empty if savegame slot is unused.
+ ///
+ /// The savegame slot name.
+ /// The result data. Empty or null for unused slot name.
+ /// The local user (null if use default one).
+ /// True if failed, otherwise false.
+ API_FUNCTION() virtual bool GetSaveGame(const StringView& name, API_PARAM(Out) Array& data, User* localUser = nullptr) = 0;
+
+ ///
+ /// Sets the online savegame data.
+ ///
+ /// The savegame slot name.
+ /// The data. Empty or null to delete slot (or mark as unused).
+ /// The local user (null if use default one).
+ /// True if failed, otherwise false.
+ API_FUNCTION() virtual bool SetSaveGame(const StringView& name, const Span& data, User* localUser = nullptr) = 0;
+};
diff --git a/Source/Engine/Online/Online.Build.cs b/Source/Engine/Online/Online.Build.cs
new file mode 100644
index 000000000..bb4ff1ba5
--- /dev/null
+++ b/Source/Engine/Online/Online.Build.cs
@@ -0,0 +1,10 @@
+// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
+
+using Flax.Build;
+
+///
+/// Online services base module.
+///
+public class Online : EngineModule
+{
+}
diff --git a/Source/Engine/Online/Online.cpp b/Source/Engine/Online/Online.cpp
new file mode 100644
index 000000000..ca53ed78e
--- /dev/null
+++ b/Source/Engine/Online/Online.cpp
@@ -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;
+}
diff --git a/Source/Engine/Online/Online.h b/Source/Engine/Online/Online.h
new file mode 100644
index 000000000..7d8bdc820
--- /dev/null
+++ b/Source/Engine/Online/Online.h
@@ -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;
+
+///
+/// The online system for communicating with various multiplayer services such as player info, achievements, game lobby or in-game store.
+///
+API_CLASS(Static, Namespace="FlaxEngine.Online") class FLAXENGINE_API Online
+{
+ DECLARE_SCRIPTING_TYPE_NO_SPAWN(Online);
+public:
+ ///
+ /// The current online platform.
+ ///
+ API_FIELD(ReadOnly) static IOnlinePlatform* Platform;
+
+ ///
+ /// Event called when current online platform gets changed.
+ ///
+ API_EVENT() static Action PlatformChanged;
+
+public:
+ ///
+ /// Initializes the online system with a given online platform implementation.
+ ///
+ /// Destroys the current platform (in any already in-use).
+ /// The online platform object.
+ /// True if failed, otherwise false.
+ API_FUNCTION() static bool Initialize(IOnlinePlatform* platform);
+};