Init
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 139572fa5184347bf8b9bb111fdd1f44
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,67 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1001 &926441648132743765
|
||||
PrefabInstance:
|
||||
m_ObjectHideFlags: 0
|
||||
serializedVersion: 2
|
||||
m_Modification:
|
||||
serializedVersion: 3
|
||||
m_TransformParent: {fileID: 0}
|
||||
m_Modifications:
|
||||
- target: {fileID: 625823154146548787, guid: 4f60822af0c06433c9c52cd9de5ecb11, type: 3}
|
||||
propertyPath: m_Name
|
||||
value: UnityServices
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 5348375844202089011, guid: 4f60822af0c06433c9c52cd9de5ecb11, type: 3}
|
||||
propertyPath: GenerateName
|
||||
value: 1
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 5348375844202089011, guid: 4f60822af0c06433c9c52cd9de5ecb11, type: 3}
|
||||
propertyPath: FetchPlayerName
|
||||
value: 1
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 8214134490659830777, guid: 4f60822af0c06433c9c52cd9de5ecb11, type: 3}
|
||||
propertyPath: m_LocalPosition.x
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 8214134490659830777, guid: 4f60822af0c06433c9c52cd9de5ecb11, type: 3}
|
||||
propertyPath: m_LocalPosition.y
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 8214134490659830777, guid: 4f60822af0c06433c9c52cd9de5ecb11, type: 3}
|
||||
propertyPath: m_LocalPosition.z
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 8214134490659830777, guid: 4f60822af0c06433c9c52cd9de5ecb11, type: 3}
|
||||
propertyPath: m_LocalRotation.w
|
||||
value: 1
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 8214134490659830777, guid: 4f60822af0c06433c9c52cd9de5ecb11, type: 3}
|
||||
propertyPath: m_LocalRotation.x
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 8214134490659830777, guid: 4f60822af0c06433c9c52cd9de5ecb11, type: 3}
|
||||
propertyPath: m_LocalRotation.y
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 8214134490659830777, guid: 4f60822af0c06433c9c52cd9de5ecb11, type: 3}
|
||||
propertyPath: m_LocalRotation.z
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 8214134490659830777, guid: 4f60822af0c06433c9c52cd9de5ecb11, type: 3}
|
||||
propertyPath: m_LocalEulerAnglesHint.x
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 8214134490659830777, guid: 4f60822af0c06433c9c52cd9de5ecb11, type: 3}
|
||||
propertyPath: m_LocalEulerAnglesHint.y
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 8214134490659830777, guid: 4f60822af0c06433c9c52cd9de5ecb11, type: 3}
|
||||
propertyPath: m_LocalEulerAnglesHint.z
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
m_RemovedComponents: []
|
||||
m_RemovedGameObjects: []
|
||||
m_AddedGameObjects: []
|
||||
m_AddedComponents: []
|
||||
m_SourcePrefab: {fileID: 100100000, guid: 4f60822af0c06433c9c52cd9de5ecb11, type: 3}
|
||||
@@ -0,0 +1,14 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 579655fa7bd8b4bc5a4166bc19562233
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 341930
|
||||
packageName: Unity Building Block - Multiplayer Session
|
||||
packageVersion: 1.0
|
||||
assetPath: Assets/Blocks/CommonSession/Prefabs/UnityServicesWithName.prefab
|
||||
uploadId: 814574
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 399cc951ef56db867bcd210200de514e
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"name": "Blocks.Sessions.Common",
|
||||
"rootNamespace": "Blocks.Sessions.Common",
|
||||
"references": [
|
||||
"GUID:37e17ffe38d86ae48bc3207e83ffef88",
|
||||
"GUID:510d22f9fb515c2299f915419086bb2b"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [
|
||||
"MULTIPLAYER_SERVICES_1_2_0_OR_NEWER"
|
||||
],
|
||||
"versionDefines": [
|
||||
{
|
||||
"name": "com.unity.netcode.gameobjects",
|
||||
"expression": "2.0.0",
|
||||
"define": "GAMEOBJECTS_NETCODE_2_AVAILABLE"
|
||||
},
|
||||
{
|
||||
"name": "com.unity.services.multiplayer",
|
||||
"expression": "1.2.0",
|
||||
"define": "MULTIPLAYER_SERVICES_1_2_0_OR_NEWER"
|
||||
}
|
||||
],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 97271b4cf421601668d136f3ed0c346d
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 341930
|
||||
packageName: Unity Building Block - Multiplayer Session
|
||||
packageVersion: 1.0
|
||||
assetPath: Assets/Blocks/CommonSession/Runtime/Blocks.Sessions.Common.asmdef
|
||||
uploadId: 814574
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7fc3051e1697b2f4e98b6cf9949d2a7e
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,108 @@
|
||||
using Blocks.Common;
|
||||
using System.Collections.Generic;
|
||||
using Unity.Properties;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace Blocks.Sessions.Common
|
||||
{
|
||||
[UxmlElement]
|
||||
public partial class CopySessionCodeElement : VisualElement
|
||||
{
|
||||
const string k_CopySessionCodeButtonText = "COPY";
|
||||
|
||||
[CreateProperty, UxmlAttribute]
|
||||
public string SessionType
|
||||
{
|
||||
get => m_SessionType;
|
||||
set
|
||||
{
|
||||
if (m_SessionType == value)
|
||||
return;
|
||||
|
||||
m_SessionType = value;
|
||||
if (panel != null)
|
||||
UpdateBindings();
|
||||
}
|
||||
}
|
||||
string m_SessionType;
|
||||
|
||||
CopySessionCodeViewModel m_ViewModel;
|
||||
|
||||
readonly List<DataBinding> m_Bindings = new();
|
||||
|
||||
public CopySessionCodeElement()
|
||||
{
|
||||
AddToClassList(BlocksTheme.ContainerHorizontal);
|
||||
|
||||
var hasSessionCode = new DataBinding
|
||||
{
|
||||
dataSourcePath = new PropertyPath(nameof(CopySessionCodeViewModel.HasSessionCode)),
|
||||
bindingMode = BindingMode.ToTarget
|
||||
};
|
||||
SetBinding(new BindingId(nameof(enabledSelf)), hasSessionCode);
|
||||
|
||||
var sessionCode = new TextField
|
||||
{
|
||||
textEdition =
|
||||
{
|
||||
isReadOnly = true
|
||||
},
|
||||
selectAllOnMouseUp = false,
|
||||
selectAllOnFocus = false
|
||||
};
|
||||
sessionCode.AddToClassList(BlocksTheme.TextField);
|
||||
sessionCode.AddToClassList(BlocksTheme.SpaceRight);
|
||||
var sessionCodeBinding = new DataBinding
|
||||
{
|
||||
dataSourcePath = new PropertyPath(nameof(CopySessionCodeViewModel.SessionCode)),
|
||||
bindingMode = BindingMode.ToTarget
|
||||
};
|
||||
sessionCode.SetBinding("value", sessionCodeBinding);
|
||||
Add(sessionCode);
|
||||
m_Bindings.Add(sessionCodeBinding);
|
||||
|
||||
var copySessionCodeButton = new Button
|
||||
{
|
||||
text = k_CopySessionCodeButtonText
|
||||
};
|
||||
copySessionCodeButton.AddToClassList(BlocksTheme.Button);
|
||||
copySessionCodeButton.clicked += CopySessionCode;
|
||||
Add(copySessionCodeButton);
|
||||
m_Bindings.Add(hasSessionCode);
|
||||
|
||||
RegisterCallback<AttachToPanelEvent>(_ => UpdateBindings());
|
||||
RegisterCallback<DetachFromPanelEvent>(_ => CleanupBindings());
|
||||
}
|
||||
|
||||
void CopySessionCode()
|
||||
{
|
||||
if (string.IsNullOrEmpty(m_ViewModel?.SessionCode))
|
||||
return;
|
||||
|
||||
GUIUtility.systemCopyBuffer = m_ViewModel.SessionCode;
|
||||
}
|
||||
|
||||
void UpdateBindings()
|
||||
{
|
||||
CleanupBindings();
|
||||
|
||||
m_ViewModel = new CopySessionCodeViewModel(SessionType);
|
||||
foreach (var binding in m_Bindings)
|
||||
{
|
||||
binding.dataSource = m_ViewModel;
|
||||
}
|
||||
}
|
||||
|
||||
void CleanupBindings()
|
||||
{
|
||||
m_ViewModel?.Dispose();
|
||||
m_ViewModel = null;
|
||||
|
||||
foreach (var binding in m_Bindings)
|
||||
{
|
||||
binding.dataSource = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: de2ba267bbd77504ab9606732bf832e0
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 341930
|
||||
packageName: Unity Building Block - Multiplayer Session
|
||||
packageVersion: 1.0
|
||||
assetPath: Assets/Blocks/CommonSession/Runtime/CopySessionCode/CopySessionCodeElement.cs
|
||||
uploadId: 814574
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Unity.Properties;
|
||||
using Unity.Services.Multiplayer;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace Blocks.Sessions.Common
|
||||
{
|
||||
public class CopySessionCodeViewModel : IDisposable, IDataSourceViewHashProvider, INotifyBindablePropertyChanged
|
||||
{
|
||||
const string k_NoSessionText = "No Session Code";
|
||||
|
||||
SessionObserver m_SessionObserver;
|
||||
ISession m_Session;
|
||||
long m_UpdateVersion;
|
||||
|
||||
[CreateProperty]
|
||||
public bool HasSessionCode
|
||||
{
|
||||
get => m_HasSessionCode;
|
||||
private set
|
||||
{
|
||||
if (m_HasSessionCode == value)
|
||||
return;
|
||||
|
||||
m_HasSessionCode = value;
|
||||
Notify();
|
||||
}
|
||||
}
|
||||
bool m_HasSessionCode;
|
||||
|
||||
[CreateProperty]
|
||||
public string SessionCode
|
||||
{
|
||||
get => m_SessionCode;
|
||||
private set
|
||||
{
|
||||
if (m_SessionCode == value)
|
||||
return;
|
||||
|
||||
m_SessionCode = value;
|
||||
HasSessionCode = m_SessionCode != k_NoSessionText;
|
||||
++m_UpdateVersion;
|
||||
|
||||
Notify();
|
||||
}
|
||||
}
|
||||
string m_SessionCode = k_NoSessionText;
|
||||
|
||||
public CopySessionCodeViewModel(string sessionType)
|
||||
{
|
||||
m_SessionObserver = new SessionObserver(sessionType);
|
||||
|
||||
m_SessionObserver.SessionAdded += OnSessionAdded;
|
||||
|
||||
if (m_SessionObserver.Session != null)
|
||||
{
|
||||
OnSessionAdded(m_SessionObserver.Session);
|
||||
}
|
||||
}
|
||||
|
||||
void OnSessionAdded(ISession session)
|
||||
{
|
||||
m_Session = session;
|
||||
SessionCode = session?.Code;
|
||||
m_Session.RemovedFromSession += OnSessionRemoved;
|
||||
m_Session.Deleted += OnSessionRemoved;
|
||||
}
|
||||
|
||||
void OnSessionRemoved()
|
||||
{
|
||||
m_Session.RemovedFromSession -= OnSessionRemoved;
|
||||
m_Session.Deleted -= OnSessionRemoved;
|
||||
SessionCode = k_NoSessionText;
|
||||
m_Session = null;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (m_SessionObserver != null)
|
||||
{
|
||||
m_SessionObserver.SessionAdded -= OnSessionAdded;
|
||||
m_SessionObserver.Dispose();
|
||||
m_SessionObserver = null;
|
||||
}
|
||||
if (m_Session != null)
|
||||
{
|
||||
m_Session.RemovedFromSession -= OnSessionRemoved;
|
||||
m_Session.Deleted -= OnSessionRemoved;
|
||||
m_Session = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method is used by UIToolkit to determine if any data bound to the UI has changed.
|
||||
/// Instead of hashing the data, an m_UpdateVersion counter is incremented when changes occur.
|
||||
/// </summary>
|
||||
public long GetViewHashCode() => m_UpdateVersion;
|
||||
|
||||
/// <summary>
|
||||
/// Suggested implementation of INotifyBindablePropertyChanged from UIToolkit.
|
||||
/// </summary>
|
||||
public event EventHandler<BindablePropertyChangedEventArgs> propertyChanged;
|
||||
void Notify([CallerMemberName] string property = null) =>
|
||||
propertyChanged?.Invoke(this, new BindablePropertyChangedEventArgs(property));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 95e390a0b04dc0b428a3a458c263ebde
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 341930
|
||||
packageName: Unity Building Block - Multiplayer Session
|
||||
packageVersion: 1.0
|
||||
assetPath: Assets/Blocks/CommonSession/Runtime/CopySessionCode/CopySessionCodeViewModel.cs
|
||||
uploadId: 814574
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e960173361b7463393e18cf7d484f83e
|
||||
timeCreated: 1748895508
|
||||
@@ -0,0 +1,73 @@
|
||||
using System;
|
||||
using Blocks.Common;
|
||||
using Unity.Properties;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace Blocks.Sessions.Common
|
||||
{
|
||||
[UxmlElement]
|
||||
public partial class LeaveSessionButton : Button
|
||||
{
|
||||
const string k_LeaveSessionButtonText = "Leave Session";
|
||||
|
||||
[CreateProperty, UxmlAttribute]
|
||||
public string SessionType
|
||||
{
|
||||
get => m_SessionType;
|
||||
set
|
||||
{
|
||||
if (m_SessionType == value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_SessionType = value;
|
||||
if (panel != null)
|
||||
{
|
||||
UpdateBindings();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string m_SessionType;
|
||||
|
||||
DataBinding m_DataBinding;
|
||||
LeaveSessionViewModel m_ViewModel;
|
||||
|
||||
public LeaveSessionButton()
|
||||
{
|
||||
text = k_LeaveSessionButtonText;
|
||||
|
||||
AddToClassList(BlocksTheme.Button);
|
||||
m_DataBinding = new DataBinding() { dataSourcePath = new PropertyPath(nameof(LeaveSessionViewModel.CanLeaveSession)), bindingMode = BindingMode.ToTarget };
|
||||
SetBinding(new BindingId(nameof(enabledSelf)), m_DataBinding);
|
||||
clicked += LeaveSession;
|
||||
|
||||
RegisterCallback<AttachToPanelEvent>(_ => UpdateBindings());
|
||||
RegisterCallback<DetachFromPanelEvent>(_ => CleanupBindings());
|
||||
}
|
||||
|
||||
void LeaveSession()
|
||||
{
|
||||
_ = m_ViewModel.LeaveSession(m_SessionType);
|
||||
}
|
||||
|
||||
void UpdateBindings()
|
||||
{
|
||||
CleanupBindings();
|
||||
m_ViewModel = new LeaveSessionViewModel(m_SessionType);
|
||||
m_DataBinding.dataSource = m_ViewModel;
|
||||
}
|
||||
|
||||
void CleanupBindings()
|
||||
{
|
||||
if (m_DataBinding.dataSource is IDisposable disposable)
|
||||
{
|
||||
disposable.Dispose();
|
||||
}
|
||||
|
||||
m_ViewModel = null;
|
||||
m_DataBinding.dataSource = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 26c91da98adaf109abcae03e989988aa
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 341930
|
||||
packageName: Unity Building Block - Multiplayer Session
|
||||
packageVersion: 1.0
|
||||
assetPath: Assets/Blocks/CommonSession/Runtime/LeaveSession/LeaveSessionButton.cs
|
||||
uploadId: 814574
|
||||
@@ -0,0 +1,102 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading.Tasks;
|
||||
using JetBrains.Annotations;
|
||||
using Unity.Properties;
|
||||
using Unity.Services.Multiplayer;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace Blocks.Sessions.Common
|
||||
{
|
||||
class LeaveSessionViewModel : IDisposable, IDataSourceViewHashProvider, INotifyBindablePropertyChanged
|
||||
{
|
||||
SessionObserver m_SessionObserver;
|
||||
ISession m_Session;
|
||||
|
||||
[CreateProperty]
|
||||
public bool CanLeaveSession
|
||||
{
|
||||
get => m_CanLeaveSession;
|
||||
private set
|
||||
{
|
||||
if (m_CanLeaveSession == value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_CanLeaveSession = value;
|
||||
Notify();
|
||||
}
|
||||
}
|
||||
|
||||
bool m_CanLeaveSession;
|
||||
|
||||
public LeaveSessionViewModel(string sessionType)
|
||||
{
|
||||
m_SessionObserver = new SessionObserver(sessionType);
|
||||
m_SessionObserver.SessionAdded += OnSessionAdded;
|
||||
if (m_SessionObserver.Session != null)
|
||||
{
|
||||
OnSessionAdded(m_SessionObserver.Session);
|
||||
}
|
||||
}
|
||||
|
||||
void OnSessionAdded(ISession newSession)
|
||||
{
|
||||
m_Session = newSession;
|
||||
m_Session.RemovedFromSession += OnSessionRemoved;
|
||||
m_Session.Deleted += OnSessionRemoved;
|
||||
CanLeaveSession = true;
|
||||
}
|
||||
|
||||
void OnSessionRemoved()
|
||||
{
|
||||
CanLeaveSession = false;
|
||||
CleanupSession();
|
||||
}
|
||||
|
||||
public async Task LeaveSession(string sessionType)
|
||||
{
|
||||
var leaveTask = MultiplayerService.Instance?.Sessions[sessionType]?.LeaveAsync();
|
||||
if (leaveTask != null)
|
||||
await leaveTask;
|
||||
}
|
||||
|
||||
void CleanupSession()
|
||||
{
|
||||
m_Session.RemovedFromSession -= OnSessionRemoved;
|
||||
m_Session.Deleted -= OnSessionRemoved;
|
||||
m_Session = null;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (m_SessionObserver != null)
|
||||
{
|
||||
m_SessionObserver.Dispose();
|
||||
m_SessionObserver = null;
|
||||
}
|
||||
|
||||
if (m_Session != null)
|
||||
{
|
||||
CleanupSession();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method is used by UIToolkit to determine if any data bound to the UI has changed.
|
||||
/// Instead of hashing the data, an m_CanLeaveSession boolean is toggled when changes occur.
|
||||
/// </summary>
|
||||
public long GetViewHashCode() => m_CanLeaveSession ? 1 : 0;
|
||||
|
||||
/// <summary>
|
||||
/// Suggested implementation of INotifyBindablePropertyChanged from UIToolkit.
|
||||
/// </summary>
|
||||
public event EventHandler<BindablePropertyChangedEventArgs> propertyChanged;
|
||||
|
||||
void Notify([CallerMemberName] string property = null)
|
||||
{
|
||||
propertyChanged?.Invoke(this, new BindablePropertyChangedEventArgs(property));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9b15923ac8de40429b36be39da11e1b6
|
||||
timeCreated: 1748894877
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 341930
|
||||
packageName: Unity Building Block - Multiplayer Session
|
||||
packageVersion: 1.0
|
||||
assetPath: Assets/Blocks/CommonSession/Runtime/LeaveSession/LeaveSessionViewModel.cs
|
||||
uploadId: 814574
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e627378cef157d44391e5f80f689429c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,64 @@
|
||||
using System;
|
||||
using Blocks.Common;
|
||||
using Unity.Properties;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace Blocks.Sessions.Common
|
||||
{
|
||||
[UxmlElement]
|
||||
public partial class PlayerCountLabel : Label
|
||||
{
|
||||
[CreateProperty, UxmlAttribute]
|
||||
public string SessionType
|
||||
{
|
||||
get => m_SessionType;
|
||||
set
|
||||
{
|
||||
if (m_SessionType == value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_SessionType = value;
|
||||
if (panel != null)
|
||||
{
|
||||
UpdateBindings();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string m_SessionType;
|
||||
|
||||
DataBinding m_DataBinding;
|
||||
|
||||
public PlayerCountLabel()
|
||||
{
|
||||
AddToClassList(BlocksTheme.Label);
|
||||
m_DataBinding = new DataBinding()
|
||||
{
|
||||
dataSourcePath = new PropertyPath(nameof(PlayerCountViewModel.DisplayText)),
|
||||
bindingMode = BindingMode.ToTarget
|
||||
};
|
||||
SetBinding(new BindingId(nameof(text)), m_DataBinding);
|
||||
|
||||
RegisterCallback<AttachToPanelEvent>(_ => UpdateBindings());
|
||||
RegisterCallback<DetachFromPanelEvent>(_ => CleanupBindings());
|
||||
}
|
||||
|
||||
void UpdateBindings()
|
||||
{
|
||||
CleanupBindings();
|
||||
m_DataBinding.dataSource = new PlayerCountViewModel(m_SessionType);
|
||||
}
|
||||
|
||||
void CleanupBindings()
|
||||
{
|
||||
if (m_DataBinding.dataSource is IDisposable disposable)
|
||||
{
|
||||
disposable.Dispose();
|
||||
}
|
||||
|
||||
m_DataBinding.dataSource = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6ba500f520b97b346b2521ef36ef885d
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 341930
|
||||
packageName: Unity Building Block - Multiplayer Session
|
||||
packageVersion: 1.0
|
||||
assetPath: Assets/Blocks/CommonSession/Runtime/PlayerCount/PlayerCountLabel.cs
|
||||
uploadId: 814574
|
||||
@@ -0,0 +1,108 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Unity.Properties;
|
||||
using Unity.Services.Multiplayer;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace Blocks.Sessions.Common
|
||||
{
|
||||
public class PlayerCountViewModel : INotifyBindablePropertyChanged, IDataSourceViewHashProvider, IDisposable
|
||||
{
|
||||
const string k_DefaultDisplayText = "- / - Players";
|
||||
|
||||
SessionObserver m_SessionObserver;
|
||||
ISession m_Session;
|
||||
long m_UpdateVersion;
|
||||
|
||||
/// <summary>
|
||||
/// This property is bound to <see cref="PlayerCountLabel.text"/> so that the label displays the number of
|
||||
/// players in the session.
|
||||
/// It is a property using [CreateProperty] attribute to allow for data binding in UIToolkit
|
||||
/// <summary>
|
||||
[CreateProperty]
|
||||
public string DisplayText
|
||||
{
|
||||
get => m_DisplayText;
|
||||
set
|
||||
{
|
||||
if (m_DisplayText == value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_DisplayText = value;
|
||||
++m_UpdateVersion;
|
||||
Notify();
|
||||
}
|
||||
}
|
||||
string m_DisplayText = k_DefaultDisplayText;
|
||||
|
||||
public PlayerCountViewModel(string sessionType)
|
||||
{
|
||||
m_SessionObserver = new SessionObserver(sessionType);
|
||||
m_SessionObserver.SessionAdded += OnSessionAdded;
|
||||
|
||||
if (m_SessionObserver.Session != null)
|
||||
{
|
||||
OnSessionAdded(m_SessionObserver.Session);
|
||||
}
|
||||
}
|
||||
|
||||
void OnSessionAdded(ISession newSession)
|
||||
{
|
||||
m_Session = newSession;
|
||||
m_Session.Changed += OnSessionChanged;
|
||||
m_Session.RemovedFromSession += OnSessionRemoved;
|
||||
m_Session.Deleted += OnSessionRemoved;
|
||||
OnSessionChanged();
|
||||
}
|
||||
|
||||
void OnSessionRemoved()
|
||||
{
|
||||
DisplayText = k_DefaultDisplayText;
|
||||
CleanUpSession();
|
||||
}
|
||||
|
||||
void CleanUpSession()
|
||||
{
|
||||
m_Session.RemovedFromSession -= OnSessionRemoved;
|
||||
m_Session.Deleted -= OnSessionRemoved;
|
||||
m_Session.Changed -= OnSessionChanged;
|
||||
m_Session = null;
|
||||
}
|
||||
|
||||
void OnSessionChanged()
|
||||
{
|
||||
DisplayText = $"{m_Session.Players.Count} / {m_Session.MaxPlayers} Players";
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (m_SessionObserver != null)
|
||||
{
|
||||
m_SessionObserver.Dispose();
|
||||
m_SessionObserver = null;
|
||||
}
|
||||
|
||||
if (m_Session != null)
|
||||
{
|
||||
CleanUpSession();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method is used by UIToolkit to determine if any data bound to the UI has changed.
|
||||
/// Instead of hashing the data, an m_UpdateVersion counter is incremented when changes occur.
|
||||
/// </summary>
|
||||
public long GetViewHashCode() => m_UpdateVersion;
|
||||
|
||||
/// <summary>
|
||||
/// Suggested implementation of INotifyBindablePropertyChanged from UIToolkit.
|
||||
/// </summary>
|
||||
public event EventHandler<BindablePropertyChangedEventArgs> propertyChanged;
|
||||
void Notify([CallerMemberName] string property = null)
|
||||
{
|
||||
propertyChanged?.Invoke(this, new BindablePropertyChangedEventArgs(property));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5092878c82fa2624cae291fe02975c67
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 341930
|
||||
packageName: Unity Building Block - Multiplayer Session
|
||||
packageVersion: 1.0
|
||||
assetPath: Assets/Blocks/CommonSession/Runtime/PlayerCount/PlayerCountViewModel.cs
|
||||
uploadId: 814574
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3c25d9615542e8f46b89f18602b0133c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,115 @@
|
||||
using Blocks.Common;
|
||||
using Unity.Properties;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace Blocks.Sessions.Common
|
||||
{
|
||||
[UxmlElement]
|
||||
public partial class PlayerListViewElement : ListView
|
||||
{
|
||||
private const string k_PlayerListIsEmptyLabel = "No player has joined";
|
||||
|
||||
private string m_SessionType;
|
||||
private DataBinding m_DataBinding;
|
||||
private PlayerListViewModel m_ViewModel;
|
||||
|
||||
[CreateProperty, UxmlAttribute]
|
||||
public string SessionType
|
||||
{
|
||||
get => m_SessionType;
|
||||
set
|
||||
{
|
||||
if (m_SessionType == value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_SessionType = value;
|
||||
if (panel != null)
|
||||
{
|
||||
UpdateBindingSources();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public PlayerListViewElement()
|
||||
{
|
||||
selectionType = SelectionType.None;
|
||||
virtualizationMethod = CollectionVirtualizationMethod.DynamicHeight;
|
||||
// required for making each element inheriting an indexed array item for the data source path
|
||||
// if not set, you need to specify the datasource path manually in the bindItem callback for each item
|
||||
bindingSourceSelectionMode = BindingSourceSelectionMode.AutoAssign;
|
||||
|
||||
AddToClassList(BlocksTheme.ListViewNoHover);
|
||||
AddToClassList(BlocksTheme.ScrollView);
|
||||
|
||||
makeNoneElement = MakeNoneElement;
|
||||
|
||||
makeItem = MakeDefaultItem;
|
||||
|
||||
BindItemSource();
|
||||
|
||||
RegisterCallback<AttachToPanelEvent>(OnAttachToPanelEvent);
|
||||
RegisterCallback<DetachFromPanelEvent>(OnDetachFromPanelEvent);
|
||||
}
|
||||
|
||||
|
||||
private void OnDetachFromPanelEvent(DetachFromPanelEvent panelEvent)
|
||||
{
|
||||
CleanupBindings();
|
||||
}
|
||||
|
||||
private void OnAttachToPanelEvent(AttachToPanelEvent panelEvent)
|
||||
{
|
||||
UpdateBindingSources();
|
||||
}
|
||||
|
||||
private void UpdateBindingSources()
|
||||
{
|
||||
CleanupBindings();
|
||||
|
||||
m_ViewModel = new PlayerListViewModel(m_SessionType);
|
||||
m_DataBinding.dataSource = m_ViewModel;
|
||||
}
|
||||
|
||||
private void CleanupBindings()
|
||||
{
|
||||
m_ViewModel?.Dispose();
|
||||
m_ViewModel = null;
|
||||
m_DataBinding.dataSource = null;
|
||||
}
|
||||
|
||||
private static VisualElement MakeNoneElement()
|
||||
{
|
||||
var label = new Label(k_PlayerListIsEmptyLabel);
|
||||
label.AddToClassList(BlocksTheme.Label);
|
||||
return label;
|
||||
}
|
||||
|
||||
private void BindItemSource()
|
||||
{
|
||||
m_DataBinding = new DataBinding
|
||||
{
|
||||
dataSourcePath = new PropertyPath(nameof(PlayerListViewModel.Players)),
|
||||
bindingMode = BindingMode.ToTarget
|
||||
};
|
||||
SetBinding(new BindingId(nameof(itemsSource)), m_DataBinding);
|
||||
}
|
||||
|
||||
private static VisualElement MakeDefaultItem()
|
||||
{
|
||||
var playerNameLabel = new Label { name = nameof(PlayerNameLabel) };
|
||||
playerNameLabel.AddToClassList(BlocksTheme.Label);
|
||||
|
||||
var dataBinding = new DataBinding
|
||||
{
|
||||
dataSourcePath = PropertyPath.FromName(nameof(PlayerViewModel.Name)),
|
||||
bindingMode = BindingMode.ToTarget
|
||||
};
|
||||
|
||||
playerNameLabel.SetBinding(new BindingId(nameof(Label.text)), dataBinding);
|
||||
|
||||
return playerNameLabel;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ebf8a475674a6344a8602c7b78150111
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 341930
|
||||
packageName: Unity Building Block - Multiplayer Session
|
||||
packageVersion: 1.0
|
||||
assetPath: Assets/Blocks/CommonSession/Runtime/PlayerList/PlayerListViewElement.cs
|
||||
uploadId: 814574
|
||||
@@ -0,0 +1,147 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Unity.Properties;
|
||||
using Unity.Services.Multiplayer;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace Blocks.Sessions.Common
|
||||
{
|
||||
public class PlayerListViewModel : INotifyBindablePropertyChanged, IDataSourceViewHashProvider, IDisposable
|
||||
{
|
||||
SessionObserver m_SessionObserver;
|
||||
ISession m_Session;
|
||||
long m_UpdateVersion;
|
||||
|
||||
List<PlayerViewModel> m_Players;
|
||||
|
||||
[CreateProperty]
|
||||
public List<PlayerViewModel> Players
|
||||
{
|
||||
get => m_Players;
|
||||
set
|
||||
{
|
||||
if (m_Players == value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_Players = value;
|
||||
++m_UpdateVersion;
|
||||
Notify();
|
||||
}
|
||||
}
|
||||
|
||||
public PlayerListViewModel(string sessionType)
|
||||
{
|
||||
Players = new List<PlayerViewModel>();
|
||||
|
||||
m_SessionObserver = new SessionObserver(sessionType);
|
||||
m_SessionObserver.SessionAdded += OnSessionAdded;
|
||||
|
||||
if (m_SessionObserver.Session != null)
|
||||
{
|
||||
OnSessionAdded(m_SessionObserver.Session);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdatePlayerList()
|
||||
{
|
||||
if (m_Session == null)
|
||||
return;
|
||||
|
||||
var updatedPlayerList = new List<PlayerViewModel>();
|
||||
foreach (var player in m_Session.Players)
|
||||
{
|
||||
updatedPlayerList.Add(new PlayerViewModel(player, m_Session));
|
||||
}
|
||||
|
||||
// properly dispose the player view models first
|
||||
DisposeAndClearPlayerList();
|
||||
Players.AddRange(updatedPlayerList);
|
||||
|
||||
++m_UpdateVersion;
|
||||
|
||||
Notify(nameof(Players));
|
||||
}
|
||||
|
||||
private void DisposeAndClearPlayerList()
|
||||
{
|
||||
foreach (var player in Players)
|
||||
{
|
||||
player.Dispose();
|
||||
}
|
||||
|
||||
Players.Clear();
|
||||
}
|
||||
|
||||
void OnSessionAdded(ISession newSession)
|
||||
{
|
||||
m_Session = newSession;
|
||||
m_Session.RemovedFromSession += OnSessionRemoved;
|
||||
m_Session.Deleted += OnSessionRemoved;
|
||||
|
||||
m_Session.PlayerJoined += OnPlayerCountChanged;
|
||||
m_Session.PlayerHasLeft += OnPlayerCountChanged;
|
||||
m_Session.PlayerPropertiesChanged += OnPlayerPropertiesChanged;
|
||||
|
||||
UpdatePlayerList();
|
||||
}
|
||||
|
||||
void OnPlayerCountChanged(string playerId)
|
||||
{
|
||||
UpdatePlayerList();
|
||||
}
|
||||
|
||||
void OnPlayerPropertiesChanged()
|
||||
{
|
||||
UpdatePlayerList();
|
||||
}
|
||||
|
||||
void OnSessionRemoved()
|
||||
{
|
||||
DisposeAndClearPlayerList();
|
||||
CleanupSession();
|
||||
}
|
||||
|
||||
void CleanupSession()
|
||||
{
|
||||
m_Session.RemovedFromSession -= OnSessionRemoved;
|
||||
m_Session.Deleted -= OnSessionRemoved;
|
||||
m_Session.PlayerHasLeft -= OnPlayerCountChanged;
|
||||
m_Session.PlayerJoined -= OnPlayerCountChanged;
|
||||
m_Session.PlayerPropertiesChanged -= OnPlayerPropertiesChanged;
|
||||
m_Session = null;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (m_SessionObserver != null)
|
||||
{
|
||||
m_SessionObserver.SessionAdded -= OnSessionAdded;
|
||||
m_SessionObserver.Dispose();
|
||||
m_SessionObserver = null;
|
||||
}
|
||||
|
||||
if (m_Session != null)
|
||||
{
|
||||
CleanupSession();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method is used by UIToolkit to determine if any data bound to the UI has changed.
|
||||
/// Instead of hashing the data, an m_UpdateVersion counter is incremented when changes occur.
|
||||
/// </summary>
|
||||
public long GetViewHashCode() => m_UpdateVersion;
|
||||
|
||||
/// <summary>
|
||||
/// Suggested implementation of INotifyBindablePropertyChanged from UIToolkit.
|
||||
/// </summary>
|
||||
public event EventHandler<BindablePropertyChangedEventArgs> propertyChanged;
|
||||
void Notify([CallerMemberName] string property = null)
|
||||
{
|
||||
propertyChanged?.Invoke(this, new BindablePropertyChangedEventArgs(property));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 261a2bc9eb4f2eb48a133715c1244987
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 341930
|
||||
packageName: Unity Building Block - Multiplayer Session
|
||||
packageVersion: 1.0
|
||||
assetPath: Assets/Blocks/CommonSession/Runtime/PlayerList/PlayerListViewModel.cs
|
||||
uploadId: 814574
|
||||
@@ -0,0 +1,124 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Unity.Properties;
|
||||
using Unity.Services.Multiplayer;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace Blocks.Sessions.Common
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a DataBinding compatible representation of a player in a session.
|
||||
/// </summary>
|
||||
public class PlayerViewModel :
|
||||
/* IReadOnlyPlayer, */
|
||||
INotifyBindablePropertyChanged, IDataSourceViewHashProvider, IDisposable
|
||||
{
|
||||
private IReadOnlyPlayer _player;
|
||||
private ISession _session;
|
||||
|
||||
private long _updateVersion;
|
||||
|
||||
/// <summary>
|
||||
/// The unique identifier for the player. If not provided for a create or join request, it will be set to the ID of the caller.
|
||||
/// </summary>
|
||||
[CreateProperty]
|
||||
public string Id => _player?.Id;
|
||||
|
||||
/// <summary>
|
||||
/// The name of the player retrieved via the Authentication service.
|
||||
/// </summary>
|
||||
[CreateProperty]
|
||||
public string Name => _player?.GetPlayerName();
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if the given player is the host of the current Session.
|
||||
/// </summary>
|
||||
[CreateProperty]
|
||||
public bool IsHost => _session?.Host == Id;
|
||||
|
||||
/// <summary>
|
||||
/// The allocation id
|
||||
/// </summary>
|
||||
public string AllocationId => _player?.AllocationId;
|
||||
|
||||
/// <summary>
|
||||
/// Custom game-specific properties that apply to an individual player (e.g. `role` or `skill`).
|
||||
/// </summary>
|
||||
public IReadOnlyDictionary<string, PlayerProperty> Properties => _player?.Properties;
|
||||
|
||||
/// <summary>
|
||||
/// The time at which the member joined the Session.
|
||||
/// </summary>
|
||||
public DateTime Joined => _player?.Joined ?? DateTime.UnixEpoch;
|
||||
|
||||
/// <summary>
|
||||
/// The last time the metadata for this member was updated.
|
||||
/// </summary>
|
||||
public DateTime LastUpdated => _player?.LastUpdated ?? DateTime.UnixEpoch;
|
||||
|
||||
/// <summary>
|
||||
/// The Session the player is part of.
|
||||
/// </summary>
|
||||
public ISession Session => _session;
|
||||
|
||||
public PlayerViewModel(IReadOnlyPlayer player, ISession session)
|
||||
{
|
||||
_player = player;
|
||||
_session = session;
|
||||
|
||||
_session.Changed += OnSessionChanged;
|
||||
_session.SessionHostChanged += OnSessionHostChanged;
|
||||
_session.PlayerPropertiesChanged += OnSessionPlayerPropertiesChanged;
|
||||
}
|
||||
|
||||
private void OnSessionHostChanged(string obj)
|
||||
{
|
||||
_updateVersion++;
|
||||
Notify(nameof(IsHost));
|
||||
}
|
||||
|
||||
private void OnSessionPlayerPropertiesChanged()
|
||||
{
|
||||
_updateVersion++;
|
||||
if (!string.IsNullOrEmpty(Name))
|
||||
{
|
||||
Notify(nameof(Name));
|
||||
}
|
||||
|
||||
Notify(nameof(Properties));
|
||||
}
|
||||
|
||||
private void OnSessionChanged()
|
||||
{
|
||||
_updateVersion++;
|
||||
Notify(nameof(Session));
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_session.Changed -= OnSessionChanged;
|
||||
_session.SessionHostChanged -= OnSessionHostChanged;
|
||||
_session.PlayerPropertiesChanged -= OnSessionPlayerPropertiesChanged;
|
||||
|
||||
_player = null;
|
||||
_session = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method is used by UIToolkit to determine if any data bound to the UI has changed.
|
||||
/// Instead of hashing the data, an m_UpdateVersion counter is incremented when changes occur.
|
||||
/// </summary>
|
||||
public long GetViewHashCode() => _updateVersion;
|
||||
|
||||
/// <summary>
|
||||
/// Suggested implementation of INotifyBindablePropertyChanged from UIToolkit.
|
||||
/// </summary>
|
||||
public event EventHandler<BindablePropertyChangedEventArgs> propertyChanged;
|
||||
|
||||
private void Notify([CallerMemberName] string property = null)
|
||||
{
|
||||
propertyChanged?.Invoke(this, new BindablePropertyChangedEventArgs(property));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 75d4b34acea8451a8a3d375147ba9213
|
||||
timeCreated: 1761247019
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 341930
|
||||
packageName: Unity Building Block - Multiplayer Session
|
||||
packageVersion: 1.0
|
||||
assetPath: Assets/Blocks/CommonSession/Runtime/PlayerList/PlayerViewModel.cs
|
||||
uploadId: 814574
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e56a3e1a35f34254f86a44e67062b781
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,64 @@
|
||||
using System;
|
||||
using Blocks.Common;
|
||||
using Unity.Properties;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace Blocks.Sessions.Common
|
||||
{
|
||||
[UxmlElement]
|
||||
public partial class PlayerNameLabel : Label
|
||||
{
|
||||
[UxmlAttribute, CreateProperty]
|
||||
public string SessionType
|
||||
{
|
||||
get => m_SessionType;
|
||||
set
|
||||
{
|
||||
if (m_SessionType == value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_SessionType = value;
|
||||
if (panel != null)
|
||||
{
|
||||
UpdateBindings();
|
||||
}
|
||||
}
|
||||
}
|
||||
string m_SessionType;
|
||||
|
||||
DataBinding m_DataBinding;
|
||||
|
||||
public PlayerNameLabel()
|
||||
{
|
||||
AddToClassList(BlocksTheme.Header);
|
||||
AddToClassList(BlocksTheme.HeaderSmall);
|
||||
m_DataBinding = new DataBinding()
|
||||
{
|
||||
dataSourcePath = new PropertyPath(nameof(PlayerNameViewModel.PlayerName)),
|
||||
bindingMode = BindingMode.ToTarget
|
||||
};
|
||||
SetBinding(new BindingId(nameof(text)), m_DataBinding);
|
||||
|
||||
RegisterCallback<AttachToPanelEvent>(_ => UpdateBindings());
|
||||
RegisterCallback<DetachFromPanelEvent>(_ => CleanupBindings());
|
||||
}
|
||||
|
||||
void UpdateBindings()
|
||||
{
|
||||
CleanupBindings();
|
||||
m_DataBinding.dataSource = new PlayerNameViewModel(m_SessionType);
|
||||
}
|
||||
|
||||
void CleanupBindings()
|
||||
{
|
||||
if (m_DataBinding.dataSource is IDisposable disposable)
|
||||
{
|
||||
disposable.Dispose();
|
||||
}
|
||||
|
||||
m_DataBinding.dataSource = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f97a8d9411142084183390e9f2939757
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 341930
|
||||
packageName: Unity Building Block - Multiplayer Session
|
||||
packageVersion: 1.0
|
||||
assetPath: Assets/Blocks/CommonSession/Runtime/PlayerName/PlayerNameLabel.cs
|
||||
uploadId: 814574
|
||||
@@ -0,0 +1,107 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Unity.Properties;
|
||||
using Unity.Services.Multiplayer;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace Blocks.Sessions.Common
|
||||
{
|
||||
public class PlayerNameViewModel : INotifyBindablePropertyChanged, IDataSourceViewHashProvider, IDisposable
|
||||
{
|
||||
const string k_NoSession = "No Player Joined";
|
||||
|
||||
SessionObserver m_SessionObserver;
|
||||
ISession m_Session;
|
||||
long m_UpdateVersion;
|
||||
|
||||
/// <summary>
|
||||
/// This property is bound to <see cref="PlayerNameLabel.text"/> so that the label displays the current
|
||||
/// session name.
|
||||
/// <summary>
|
||||
[CreateProperty]
|
||||
public string PlayerName
|
||||
{
|
||||
get => m_PlayerName;
|
||||
set
|
||||
{
|
||||
if (m_PlayerName == value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_PlayerName = value;
|
||||
++m_UpdateVersion;
|
||||
Notify();
|
||||
}
|
||||
}
|
||||
string m_PlayerName = k_NoSession;
|
||||
|
||||
public PlayerNameViewModel(string sessionType)
|
||||
{
|
||||
m_SessionObserver = new SessionObserver(sessionType);
|
||||
m_SessionObserver.SessionAdded += OnSessionAdded;
|
||||
|
||||
if (m_SessionObserver.Session != null)
|
||||
{
|
||||
OnSessionAdded(m_SessionObserver.Session);
|
||||
}
|
||||
}
|
||||
|
||||
void OnSessionAdded(ISession newSession)
|
||||
{
|
||||
m_Session = newSession;
|
||||
m_Session.RemovedFromSession += OnSessionRemoved;
|
||||
m_Session.Deleted += OnSessionRemoved;
|
||||
m_Session.Changed += OnSessionChanged;
|
||||
OnSessionChanged();
|
||||
}
|
||||
|
||||
void OnSessionChanged()
|
||||
{
|
||||
PlayerName = m_Session.CurrentPlayer.GetPlayerName();
|
||||
}
|
||||
|
||||
void OnSessionRemoved()
|
||||
{
|
||||
PlayerName = k_NoSession;
|
||||
CleanupSession();
|
||||
}
|
||||
|
||||
void CleanupSession()
|
||||
{
|
||||
m_Session.RemovedFromSession -= OnSessionRemoved;
|
||||
m_Session.Deleted -= OnSessionRemoved;
|
||||
m_Session.Changed -= OnSessionChanged;
|
||||
m_Session = null;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (m_SessionObserver != null)
|
||||
{
|
||||
m_SessionObserver.Dispose();
|
||||
m_SessionObserver = null;
|
||||
}
|
||||
|
||||
if (m_Session != null)
|
||||
{
|
||||
CleanupSession();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method is used by UIToolkit to determine if any data bound to the UI has changed.
|
||||
/// Instead of hashing the data, an m_UpdateVersion counter is incremented when changes occur.
|
||||
/// </summary>
|
||||
public long GetViewHashCode() => m_UpdateVersion;
|
||||
|
||||
/// <summary>
|
||||
/// Suggested implementation of INotifyBindablePropertyChanged from UIToolkit.
|
||||
/// </summary>
|
||||
public event EventHandler<BindablePropertyChangedEventArgs> propertyChanged;
|
||||
void Notify([CallerMemberName] string property = null)
|
||||
{
|
||||
propertyChanged?.Invoke(this, new BindablePropertyChangedEventArgs(property));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dfc41271b4bb8404f8777303da017982
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 341930
|
||||
packageName: Unity Building Block - Multiplayer Session
|
||||
packageVersion: 1.0
|
||||
assetPath: Assets/Blocks/CommonSession/Runtime/PlayerName/PlayerNameViewModel.cs
|
||||
uploadId: 814574
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f3423f74f83ac4547a18d6ebfa1a0e0f
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,437 @@
|
||||
using System.Collections.Generic;
|
||||
using Blocks.Common;
|
||||
using Unity.Properties;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace Blocks.Sessions.Common
|
||||
{
|
||||
[UxmlElement]
|
||||
public partial class SessionInfoElement : VisualElement
|
||||
{
|
||||
|
||||
const string k_SessionInfoHeaderName = "SessionInfoHeader";
|
||||
const string k_SessionInfoHeaderText = "SESSION INFO";
|
||||
|
||||
const string k_SessionDataHeaderName = "SessionData";
|
||||
const string k_SessionDataHeaderText = "Session Data";
|
||||
|
||||
const string k_ListIsEmptyLabel = "List is empty";
|
||||
const string k_KeyLabelPropertyName = "PropertyKeyLabel";
|
||||
const string k_VisibilityLabelPropertyName = "PropertyVisibilityLabel";
|
||||
const string k_ValueLabelPropertyName = "PropertyValueLabel";
|
||||
|
||||
const string k_SessionPropertiesHeaderName = "SessionProperties";
|
||||
const string k_SessionPropertiesHeaderText = "Session Properties";
|
||||
|
||||
const string k_PlayerDataHeaderName = "PlayerData";
|
||||
const string k_PlayerDataHeaderText = "Player Data";
|
||||
|
||||
const string k_PlayerHeaderName = "PlayerHeader";
|
||||
const string k_PlayerIdLabelName = "PlayerIdLabel";
|
||||
const string k_PlayerJoinedLabelName = "PlayerJoinedLabel";
|
||||
const string k_PlayerLastUpdatedLabelName = "PlayerLastUpdatedLabel";
|
||||
const string k_PlayerPropertiesListName = "PlayerPropertiesList";
|
||||
|
||||
const string k_PlayerPropertiesHeaderText = "Player Properties";
|
||||
|
||||
const string k_PlayerPropertiesIdKeyName = "PlayerPropertiesIDKey";
|
||||
const string k_PlayerPropertiesIdValueName = "PlayerPropertiesIDValue";
|
||||
const string k_PlayerPropertiesIdVisibilityName = "PlayerPropertiesIDVisibility";
|
||||
|
||||
[CreateProperty, UxmlAttribute]
|
||||
public string SessionType
|
||||
{
|
||||
get => m_SessionType;
|
||||
set
|
||||
{
|
||||
if (m_SessionType == value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_SessionType = value;
|
||||
if (panel != null)
|
||||
{
|
||||
UpdateBindings();
|
||||
}
|
||||
}
|
||||
}
|
||||
string m_SessionType;
|
||||
|
||||
SessionInfoViewModel m_ViewModel;
|
||||
|
||||
readonly List<DataBinding> m_Bindings = new();
|
||||
|
||||
public SessionInfoElement()
|
||||
{
|
||||
AddToClassList(BlocksTheme.FullWidth);
|
||||
|
||||
var sessionInfoHeader = new Label
|
||||
{
|
||||
name = k_SessionInfoHeaderName,
|
||||
text = k_SessionInfoHeaderText
|
||||
};
|
||||
sessionInfoHeader.AddToClassList(BlocksTheme.Header);
|
||||
sessionInfoHeader.AddToClassList(BlocksTheme.HeaderSpaceBottom);
|
||||
Add(sessionInfoHeader);
|
||||
|
||||
var stateLabel = new Label();
|
||||
stateLabel.AddToClassList(BlocksTheme.Header);
|
||||
stateLabel.AddToClassList(BlocksTheme.HeaderXSmall);
|
||||
stateLabel.AddToClassList(BlocksTheme.SpaceBottom);
|
||||
var stateBinding = new DataBinding
|
||||
{
|
||||
dataSourcePath = new PropertyPath(nameof(SessionInfoViewModel.SessionState)),
|
||||
bindingMode = BindingMode.ToTarget
|
||||
};
|
||||
stateLabel.SetBinding(new BindingId(nameof(stateLabel.text)), stateBinding);
|
||||
Add(stateLabel);
|
||||
m_Bindings.Add(stateBinding);
|
||||
|
||||
var scrollViewParent = new ScrollView();
|
||||
scrollViewParent.AddToClassList(BlocksTheme.ScrollView);
|
||||
var sessionContainerBinding = new DataBinding
|
||||
{
|
||||
dataSourcePath = new PropertyPath(nameof(SessionInfoViewModel.SessionInfoDisplayStyle)),
|
||||
bindingMode = BindingMode.ToTarget,
|
||||
};
|
||||
scrollViewParent.SetBinding(new BindingId("style.display"), sessionContainerBinding);
|
||||
Add(scrollViewParent);
|
||||
m_Bindings.Add(sessionContainerBinding);
|
||||
|
||||
var sessionDataHeader = new Label
|
||||
{
|
||||
name = k_SessionDataHeaderName,
|
||||
text = k_SessionDataHeaderText
|
||||
};
|
||||
sessionDataHeader.AddToClassList(BlocksTheme.Header);
|
||||
sessionDataHeader.AddToClassList(BlocksTheme.HeaderSmall);
|
||||
sessionDataHeader.AddToClassList(BlocksTheme.SpaceBottomSmall);
|
||||
scrollViewParent.Add(sessionDataHeader);
|
||||
|
||||
var sessionIdLabel = new Label();
|
||||
sessionIdLabel.AddToClassList(BlocksTheme.Label);
|
||||
var sessionIdBinding = new DataBinding
|
||||
{
|
||||
dataSourcePath = new PropertyPath(nameof(SessionInfoViewModel.SessionId)),
|
||||
bindingMode = BindingMode.ToTarget
|
||||
};
|
||||
sessionIdLabel.SetBinding(new BindingId(nameof(sessionIdLabel.text)), sessionIdBinding);
|
||||
scrollViewParent.Add(sessionIdLabel);
|
||||
m_Bindings.Add(sessionIdBinding);
|
||||
|
||||
var sessionNameLabel = new Label();
|
||||
sessionNameLabel.AddToClassList(BlocksTheme.Label);
|
||||
var sessionNameBinding = new DataBinding
|
||||
{
|
||||
dataSourcePath = new PropertyPath(nameof(SessionInfoViewModel.Name)),
|
||||
bindingMode = BindingMode.ToTarget
|
||||
};
|
||||
sessionNameLabel.SetBinding(new BindingId(nameof(sessionNameLabel.text)), sessionNameBinding);
|
||||
scrollViewParent.Add(sessionNameLabel);
|
||||
m_Bindings.Add(sessionNameBinding);
|
||||
|
||||
var maxPlayersLabel = new Label();
|
||||
maxPlayersLabel.AddToClassList(BlocksTheme.Label);
|
||||
var maxPlayersBinding = new DataBinding
|
||||
{
|
||||
dataSourcePath = new PropertyPath(nameof(SessionInfoViewModel.MaxPlayers)),
|
||||
bindingMode = BindingMode.ToTarget
|
||||
};
|
||||
maxPlayersLabel.SetBinding(new BindingId(nameof(maxPlayersLabel.text)), maxPlayersBinding);
|
||||
scrollViewParent.Add(maxPlayersLabel);
|
||||
m_Bindings.Add(maxPlayersBinding);
|
||||
|
||||
var isPrivateLabel = new Label();
|
||||
isPrivateLabel.AddToClassList(BlocksTheme.Label);
|
||||
var isPrivateBinding = new DataBinding
|
||||
{
|
||||
dataSourcePath = new PropertyPath(nameof(SessionInfoViewModel.IsPrivate)),
|
||||
bindingMode = BindingMode.ToTarget
|
||||
};
|
||||
isPrivateLabel.SetBinding(new BindingId(nameof(isPrivateLabel.text)), isPrivateBinding);
|
||||
scrollViewParent.Add(isPrivateLabel);
|
||||
m_Bindings.Add(isPrivateBinding);
|
||||
|
||||
var isLockedLabel = new Label();
|
||||
isLockedLabel.AddToClassList(BlocksTheme.Label);
|
||||
var isLockedBinding = new DataBinding
|
||||
{
|
||||
dataSourcePath = new PropertyPath(nameof(SessionInfoViewModel.IsLocked)),
|
||||
bindingMode = BindingMode.ToTarget
|
||||
};
|
||||
isLockedLabel.SetBinding(new BindingId(nameof(isLockedLabel.text)), isLockedBinding);
|
||||
scrollViewParent.Add(isLockedLabel);
|
||||
m_Bindings.Add(isLockedBinding);
|
||||
|
||||
var sessionCodeLabel = new Label();
|
||||
sessionCodeLabel.AddToClassList(BlocksTheme.Label);
|
||||
var sessionCodeBinding = new DataBinding
|
||||
{
|
||||
dataSourcePath = new PropertyPath(nameof(SessionInfoViewModel.SessionCode)),
|
||||
bindingMode = BindingMode.ToTarget
|
||||
};
|
||||
sessionCodeLabel.SetBinding(new BindingId(nameof(sessionCodeLabel.text)), sessionCodeBinding);
|
||||
scrollViewParent.Add(sessionCodeLabel);
|
||||
m_Bindings.Add(sessionCodeBinding);
|
||||
|
||||
var hostIDLabel = new Label();
|
||||
hostIDLabel.AddToClassList(BlocksTheme.Label);
|
||||
var hostIDBinding = new DataBinding
|
||||
{
|
||||
dataSourcePath = new PropertyPath(nameof(SessionInfoViewModel.HostID)),
|
||||
bindingMode = BindingMode.ToTarget
|
||||
};
|
||||
hostIDLabel.SetBinding(new BindingId(nameof(hostIDLabel.text)), hostIDBinding);
|
||||
scrollViewParent.Add(hostIDLabel);
|
||||
m_Bindings.Add(hostIDBinding);
|
||||
|
||||
var isHostLabel = new Label();
|
||||
isHostLabel.AddToClassList(BlocksTheme.Label);
|
||||
isHostLabel.AddToClassList(BlocksTheme.SpaceBottomSmall);
|
||||
var isHostBinding = new DataBinding
|
||||
{
|
||||
dataSourcePath = new PropertyPath(nameof(SessionInfoViewModel.IsHost)),
|
||||
bindingMode = BindingMode.ToTarget
|
||||
};
|
||||
isHostLabel.SetBinding(new BindingId(nameof(isHostLabel.text)), isHostBinding);
|
||||
scrollViewParent.Add(isHostLabel);
|
||||
m_Bindings.Add(isHostBinding);
|
||||
|
||||
var propertiesListView = new ListView
|
||||
{
|
||||
virtualizationMethod = CollectionVirtualizationMethod.DynamicHeight,
|
||||
makeNoneElement = () =>
|
||||
{
|
||||
var label = new Label(k_ListIsEmptyLabel);
|
||||
label.AddToClassList(BlocksTheme.Label);
|
||||
return label;
|
||||
},
|
||||
makeHeader = () =>
|
||||
{
|
||||
var sessionPropertiesHeader = new Label
|
||||
{
|
||||
name = k_SessionPropertiesHeaderName,
|
||||
text = k_SessionPropertiesHeaderText
|
||||
};
|
||||
sessionPropertiesHeader.AddToClassList(BlocksTheme.Header);
|
||||
sessionPropertiesHeader.AddToClassList(BlocksTheme.HeaderXSmall);
|
||||
sessionPropertiesHeader.AddToClassList(BlocksTheme.HeaderXSmall);
|
||||
return sessionPropertiesHeader;
|
||||
},
|
||||
makeItem = () =>
|
||||
{
|
||||
var container = new VisualElement();
|
||||
container.AddToClassList(BlocksTheme.Label);
|
||||
|
||||
var keyLabel = new Label
|
||||
{
|
||||
name = k_KeyLabelPropertyName
|
||||
};
|
||||
keyLabel.AddToClassList(BlocksTheme.Label);
|
||||
container.Add(keyLabel);
|
||||
|
||||
var visibilityLabel = new Label
|
||||
{
|
||||
name = k_VisibilityLabelPropertyName
|
||||
};
|
||||
visibilityLabel.AddToClassList(BlocksTheme.Label);
|
||||
container.Add(visibilityLabel);
|
||||
|
||||
var valueLabel = new Label
|
||||
{
|
||||
name = k_ValueLabelPropertyName
|
||||
};
|
||||
valueLabel.AddToClassList(BlocksTheme.Label);
|
||||
container.Add(valueLabel);
|
||||
return container;
|
||||
},
|
||||
bindItem = (element, index) =>
|
||||
{
|
||||
var sessionProperty = m_ViewModel.SessionProperties[index];
|
||||
|
||||
element.Q<Label>(k_KeyLabelPropertyName).text = $"Key: {sessionProperty.Key}";
|
||||
element.Q<Label>(k_VisibilityLabelPropertyName).text = $"Visibility: {sessionProperty.Visibility}";
|
||||
element.Q<Label>(k_ValueLabelPropertyName).text = $"Value: {sessionProperty.Value}";
|
||||
}
|
||||
};
|
||||
propertiesListView.AddToClassList(BlocksTheme.Label);
|
||||
propertiesListView.AddToClassList(BlocksTheme.SpaceBottom);
|
||||
var propertiesBinding = new DataBinding
|
||||
{
|
||||
dataSourcePath = new PropertyPath(nameof(SessionInfoViewModel.SessionProperties)),
|
||||
bindingMode = BindingMode.ToTarget,
|
||||
};
|
||||
propertiesListView.SetBinding(new BindingId(nameof(ListView.itemsSource)), propertiesBinding);
|
||||
scrollViewParent.Add(propertiesListView);
|
||||
m_Bindings.Add(propertiesBinding);
|
||||
|
||||
var playerStatsListView = new ListView
|
||||
{
|
||||
selectionType = SelectionType.None,
|
||||
virtualizationMethod = CollectionVirtualizationMethod.DynamicHeight,
|
||||
makeNoneElement = () =>
|
||||
{
|
||||
var label = new Label(k_ListIsEmptyLabel);
|
||||
label.AddToClassList(BlocksTheme.Label);
|
||||
return label;
|
||||
},
|
||||
makeHeader = () =>
|
||||
{
|
||||
var playerDataHeader = new Label
|
||||
{
|
||||
name = k_PlayerDataHeaderName,
|
||||
text = k_PlayerDataHeaderText
|
||||
};
|
||||
playerDataHeader.AddToClassList(BlocksTheme.Header);
|
||||
playerDataHeader.AddToClassList(BlocksTheme.HeaderSmall);
|
||||
playerDataHeader.AddToClassList(BlocksTheme.SpaceBottomSmall);
|
||||
return playerDataHeader;
|
||||
},
|
||||
makeItem = () =>
|
||||
{
|
||||
var container = new VisualElement();
|
||||
container.AddToClassList(BlocksTheme.SpaceBottom);
|
||||
|
||||
var playerHeaderLabel = new Label
|
||||
{
|
||||
name = k_PlayerHeaderName
|
||||
};
|
||||
playerHeaderLabel.AddToClassList(BlocksTheme.Header);
|
||||
playerHeaderLabel.AddToClassList(BlocksTheme.HeaderXSmall);
|
||||
playerHeaderLabel.AddToClassList(BlocksTheme.SpaceBottomSmall);
|
||||
container.Add(playerHeaderLabel);
|
||||
|
||||
var playerIdLabel = new Label
|
||||
{
|
||||
name = k_PlayerIdLabelName
|
||||
};
|
||||
playerIdLabel.AddToClassList(BlocksTheme.Label);
|
||||
container.Add(playerIdLabel);
|
||||
|
||||
var playerJoinedLabel = new Label
|
||||
{
|
||||
name = k_PlayerJoinedLabelName
|
||||
};
|
||||
playerJoinedLabel.AddToClassList(BlocksTheme.Label);
|
||||
container.Add(playerJoinedLabel);
|
||||
|
||||
var playerLastUpdatedLabel = new Label
|
||||
{
|
||||
name = k_PlayerLastUpdatedLabelName
|
||||
};
|
||||
playerLastUpdatedLabel.AddToClassList(BlocksTheme.Label);
|
||||
playerLastUpdatedLabel.AddToClassList(BlocksTheme.SpaceBottomSmall);
|
||||
container.Add(playerLastUpdatedLabel);
|
||||
|
||||
var playerPropertiesList = new ListView
|
||||
{
|
||||
name = k_PlayerPropertiesListName,
|
||||
headerTitle = k_PlayerPropertiesHeaderText,
|
||||
virtualizationMethod = CollectionVirtualizationMethod.DynamicHeight,
|
||||
makeNoneElement = () =>
|
||||
{
|
||||
var label = new Label(k_ListIsEmptyLabel);
|
||||
label.AddToClassList(BlocksTheme.Label);
|
||||
return label;
|
||||
},
|
||||
makeHeader = () =>
|
||||
{
|
||||
var playerPropertiesHeader = new Label
|
||||
{
|
||||
text = k_PlayerPropertiesHeaderText
|
||||
};
|
||||
playerPropertiesHeader.AddToClassList(BlocksTheme.Header);
|
||||
playerPropertiesHeader.AddToClassList(BlocksTheme.HeaderXSmall);
|
||||
playerPropertiesHeader.AddToClassList(BlocksTheme.SpaceBottomSmall);
|
||||
return playerPropertiesHeader;
|
||||
}
|
||||
};
|
||||
container.Add(playerPropertiesList);
|
||||
|
||||
return container;
|
||||
},
|
||||
bindItem = (element, index) =>
|
||||
{
|
||||
var player = m_ViewModel.PlayerStats[index];
|
||||
element.Q<Label>(k_PlayerHeaderName).text = $"Player {index + 1}";
|
||||
element.Q<Label>(k_PlayerIdLabelName).text = $"ID: {player.Id}";
|
||||
element.Q<Label>(k_PlayerJoinedLabelName).text = $"Joined: {player.Joined}";
|
||||
element.Q<Label>(k_PlayerLastUpdatedLabelName).text = $"Last Updated: {player.LastUpdated}";
|
||||
|
||||
var playerPropertiesList = element.Q<ListView>(k_PlayerPropertiesListName);
|
||||
if (playerPropertiesList == null)
|
||||
return;
|
||||
|
||||
playerPropertiesList.itemsSource = player.PlayerPropertiesList;
|
||||
playerPropertiesList.makeItem = () =>
|
||||
{
|
||||
var propertyContainer = new VisualElement();
|
||||
|
||||
var propertyKeyLabel = new Label
|
||||
{
|
||||
name = k_PlayerPropertiesIdKeyName
|
||||
};
|
||||
propertyKeyLabel.AddToClassList(BlocksTheme.Label);
|
||||
propertyContainer.Add(propertyKeyLabel);
|
||||
|
||||
var propertyValueLabel = new Label
|
||||
{
|
||||
name = k_PlayerPropertiesIdValueName
|
||||
};
|
||||
propertyValueLabel.AddToClassList(BlocksTheme.Label);
|
||||
propertyContainer.Add(propertyValueLabel);
|
||||
|
||||
var propertyVisibilityLabel = new Label
|
||||
{
|
||||
name = k_PlayerPropertiesIdVisibilityName
|
||||
};
|
||||
propertyVisibilityLabel.AddToClassList(BlocksTheme.Label);
|
||||
propertyContainer.Add(propertyVisibilityLabel);
|
||||
return propertyContainer;
|
||||
};
|
||||
playerPropertiesList.bindItem = (propertyElement, propertyIndex) =>
|
||||
{
|
||||
var sessionProperty = player.PlayerPropertiesList[propertyIndex];
|
||||
propertyElement.Q<Label>(k_PlayerPropertiesIdKeyName).text = $"Key: {sessionProperty.Key}";
|
||||
propertyElement.Q<Label>(k_PlayerPropertiesIdValueName).text = $"Value: {sessionProperty.Value}";
|
||||
propertyElement.Q<Label>(k_PlayerPropertiesIdVisibilityName).text = $"Visibility: {sessionProperty.Visibility}";
|
||||
};
|
||||
}
|
||||
};
|
||||
playerStatsListView.AddToClassList(BlocksTheme.ListViewNoHover);
|
||||
var playerStatsBinding = new DataBinding
|
||||
{
|
||||
dataSourcePath = new PropertyPath(nameof(SessionInfoViewModel.PlayerStats)),
|
||||
bindingMode = BindingMode.ToTarget,
|
||||
};
|
||||
playerStatsListView.SetBinding(new BindingId(nameof(ListView.itemsSource)), playerStatsBinding);
|
||||
scrollViewParent.Add(playerStatsListView);
|
||||
m_Bindings.Add(playerStatsBinding);
|
||||
|
||||
RegisterCallback<AttachToPanelEvent>(_ => UpdateBindings());
|
||||
RegisterCallback<DetachFromPanelEvent>(_ => CleanupBindings());
|
||||
}
|
||||
|
||||
void UpdateBindings()
|
||||
{
|
||||
CleanupBindings();
|
||||
|
||||
m_ViewModel = new SessionInfoViewModel(m_SessionType);
|
||||
foreach (var binding in m_Bindings)
|
||||
{
|
||||
binding.dataSource = m_ViewModel;
|
||||
}
|
||||
}
|
||||
|
||||
void CleanupBindings()
|
||||
{
|
||||
m_ViewModel?.Dispose();
|
||||
m_ViewModel = null;
|
||||
foreach (var binding in m_Bindings)
|
||||
{
|
||||
binding.dataSource = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2b4ddfd6af5d6c24e8bfea2f6d96389e
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 341930
|
||||
packageName: Unity Building Block - Multiplayer Session
|
||||
packageVersion: 1.0
|
||||
assetPath: Assets/Blocks/CommonSession/Runtime/SessionInfo/SessionInfoElement.cs
|
||||
uploadId: 814574
|
||||
@@ -0,0 +1,349 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Unity.Properties;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Unity.Services.Multiplayer;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace Blocks.Sessions.Common
|
||||
{
|
||||
public class SessionProperty
|
||||
{
|
||||
public string Key { get; set; }
|
||||
public string Visibility { get; set; }
|
||||
public string Value { get; set; }
|
||||
}
|
||||
|
||||
public class Players
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string Joined { get; set; }
|
||||
public string LastUpdated { get; set; }
|
||||
public List<PlayerProperties> PlayerPropertiesList { get; set; }
|
||||
}
|
||||
|
||||
public class PlayerProperties
|
||||
{
|
||||
public string Key { get; set; }
|
||||
public string Visibility { get; set; }
|
||||
public string Value { get; set; }
|
||||
}
|
||||
|
||||
public class SessionInfoViewModel : IDisposable, IDataSourceViewHashProvider, INotifyBindablePropertyChanged
|
||||
{
|
||||
SessionObserver m_SessionObserver;
|
||||
ISession m_Session;
|
||||
long m_UpdateVersion;
|
||||
|
||||
[CreateProperty]
|
||||
public string SessionState
|
||||
{
|
||||
get => m_SessionState;
|
||||
set
|
||||
{
|
||||
if (m_SessionState == value)
|
||||
return;
|
||||
m_SessionState = value;
|
||||
Notify();
|
||||
}
|
||||
}
|
||||
|
||||
string m_SessionState = "No Session";
|
||||
|
||||
[CreateProperty]
|
||||
public DisplayStyle SessionInfoDisplayStyle
|
||||
{
|
||||
get => m_SessionInfoDisplayStyle;
|
||||
set
|
||||
{
|
||||
if (m_SessionInfoDisplayStyle == value)
|
||||
return;
|
||||
m_SessionInfoDisplayStyle = value;
|
||||
Notify();
|
||||
}
|
||||
}
|
||||
|
||||
DisplayStyle m_SessionInfoDisplayStyle = DisplayStyle.None;
|
||||
|
||||
[CreateProperty]
|
||||
public string SessionId
|
||||
{
|
||||
get => m_SessionId;
|
||||
set
|
||||
{
|
||||
if (m_SessionId == value)
|
||||
return;
|
||||
m_SessionId = value;
|
||||
Notify();
|
||||
}
|
||||
}
|
||||
|
||||
string m_SessionId = "Unknown Session ID";
|
||||
|
||||
[CreateProperty]
|
||||
public string Name
|
||||
{
|
||||
get => m_SessionName;
|
||||
set
|
||||
{
|
||||
if (m_SessionName == value)
|
||||
return;
|
||||
m_SessionName = value;
|
||||
Notify();
|
||||
}
|
||||
}
|
||||
|
||||
string m_SessionName = "Unknown Session Name";
|
||||
|
||||
[CreateProperty]
|
||||
public string MaxPlayers
|
||||
{
|
||||
get => m_MaxPlayers;
|
||||
set
|
||||
{
|
||||
if (m_MaxPlayers == value)
|
||||
return;
|
||||
m_MaxPlayers = value;
|
||||
Notify();
|
||||
}
|
||||
}
|
||||
|
||||
string m_MaxPlayers = "Max Players: 0";
|
||||
|
||||
[CreateProperty]
|
||||
public string IsPrivate
|
||||
{
|
||||
get => m_IsPrivate;
|
||||
set
|
||||
{
|
||||
if (m_IsPrivate == value)
|
||||
return;
|
||||
m_IsPrivate = value;
|
||||
Notify();
|
||||
}
|
||||
}
|
||||
|
||||
string m_IsPrivate = "true";
|
||||
|
||||
[CreateProperty]
|
||||
public string IsLocked
|
||||
{
|
||||
get => m_IsLocked;
|
||||
set
|
||||
{
|
||||
if (m_IsLocked == value)
|
||||
return;
|
||||
m_IsLocked = value;
|
||||
Notify();
|
||||
}
|
||||
}
|
||||
|
||||
string m_IsLocked = "false";
|
||||
|
||||
[CreateProperty]
|
||||
public string SessionCode
|
||||
{
|
||||
get => m_SessionCode;
|
||||
set
|
||||
{
|
||||
if (m_SessionCode == value)
|
||||
return;
|
||||
m_SessionCode = value;
|
||||
Notify();
|
||||
}
|
||||
}
|
||||
|
||||
string m_SessionCode = "Unknown Session Code";
|
||||
|
||||
[CreateProperty]
|
||||
public string HostID
|
||||
{
|
||||
get => m_HostId;
|
||||
set
|
||||
{
|
||||
if (m_HostId == value)
|
||||
return;
|
||||
m_HostId = value;
|
||||
Notify();
|
||||
}
|
||||
}
|
||||
|
||||
string m_HostId = "Unknown Host ID";
|
||||
|
||||
[CreateProperty]
|
||||
public string IsHost
|
||||
{
|
||||
get => m_IsHost;
|
||||
set
|
||||
{
|
||||
if (m_IsHost == value)
|
||||
return;
|
||||
m_IsHost = value;
|
||||
Notify();
|
||||
}
|
||||
}
|
||||
|
||||
string m_IsHost = "Unknown";
|
||||
|
||||
[CreateProperty]
|
||||
public List<SessionProperty> SessionProperties
|
||||
{
|
||||
get => m_SessionProperties;
|
||||
set
|
||||
{
|
||||
if (m_SessionProperties == value)
|
||||
return;
|
||||
m_SessionProperties = value;
|
||||
Notify();
|
||||
}
|
||||
}
|
||||
|
||||
List<SessionProperty> m_SessionProperties;
|
||||
|
||||
[CreateProperty]
|
||||
public List<Players> PlayerStats
|
||||
{
|
||||
get => m_PlayerStats;
|
||||
set
|
||||
{
|
||||
if (m_PlayerStats == value)
|
||||
return;
|
||||
m_PlayerStats = value;
|
||||
Notify();
|
||||
}
|
||||
}
|
||||
|
||||
List<Players> m_PlayerStats;
|
||||
|
||||
public SessionInfoViewModel(string sessionType)
|
||||
{
|
||||
SessionProperties = new List<SessionProperty>();
|
||||
|
||||
m_SessionObserver = new SessionObserver(sessionType);
|
||||
m_SessionObserver.AddingSessionStarted += SessionInfoReceptionStarted;
|
||||
m_SessionObserver.SessionAdded += OnSessionAdded;
|
||||
m_SessionObserver.AddingSessionFailed += OnAddingSessionFailed;
|
||||
if (m_SessionObserver.Session != null)
|
||||
{
|
||||
OnSessionAdded(m_SessionObserver.Session);
|
||||
}
|
||||
}
|
||||
|
||||
void SessionInfoReceptionStarted(AddingSessionOptions sessionOptions)
|
||||
{
|
||||
SessionInfoDisplayStyle = DisplayStyle.None;
|
||||
SessionState = "Awaiting Session information.";
|
||||
|
||||
++m_UpdateVersion;
|
||||
}
|
||||
|
||||
void OnSessionAdded(ISession newSession)
|
||||
{
|
||||
m_Session = newSession;
|
||||
m_Session.Changed += OnSessionChanged;
|
||||
m_Session.RemovedFromSession += OnSessionRemoved;
|
||||
m_Session.Deleted += OnSessionRemoved;
|
||||
|
||||
OnSessionChanged();
|
||||
}
|
||||
|
||||
void OnSessionChanged()
|
||||
{
|
||||
SessionInfoDisplayStyle = DisplayStyle.Flex;
|
||||
SessionState = $"Session State: {m_Session.State}";
|
||||
SessionId = $"Session ID: {m_Session.Id}";
|
||||
Name = $"Session Name: {m_Session.Name}";
|
||||
MaxPlayers = $"MaxPlayers: {m_Session.MaxPlayers}";
|
||||
IsPrivate = $"IsPrivate: {m_Session.IsPrivate}";
|
||||
IsLocked = $"IsLocked: {m_Session.IsLocked}";
|
||||
SessionCode = $"Session Code: {m_Session.Code}";
|
||||
HostID = $"Host ID: {m_Session.Host}";
|
||||
IsHost = $"Is Host: {m_Session.IsHost}";
|
||||
|
||||
var sessionPropertiesList = new List<SessionProperty>();
|
||||
foreach (var property in m_Session.Properties)
|
||||
{
|
||||
sessionPropertiesList.Add(new SessionProperty { Key = property.Key, Visibility = property.Value.Visibility.ToString(), Value = property.Value.Value });
|
||||
}
|
||||
|
||||
SessionProperties = sessionPropertiesList;
|
||||
|
||||
var playersList = new List<Players>();
|
||||
foreach (var player in m_Session.Players)
|
||||
{
|
||||
var playerPropertiesList = new List<PlayerProperties>();
|
||||
var playerProperties = player.Properties;
|
||||
foreach (var property in playerProperties)
|
||||
{
|
||||
playerPropertiesList.Add(new PlayerProperties { Key = property.Key, Visibility = property.Value.Visibility.ToString(), Value = property.Value.Value });
|
||||
}
|
||||
|
||||
playersList.Add(new Players { Id = player.Id, Joined = player.Joined.ToString(), LastUpdated = player.LastUpdated.ToString(), PlayerPropertiesList = playerPropertiesList });
|
||||
}
|
||||
|
||||
PlayerStats = playersList;
|
||||
|
||||
++m_UpdateVersion;
|
||||
}
|
||||
|
||||
void OnAddingSessionFailed(AddingSessionOptions addingSessionOptions, Exception exception)
|
||||
{
|
||||
SessionInfoDisplayStyle = DisplayStyle.None;
|
||||
SessionState = exception.Message;
|
||||
|
||||
++m_UpdateVersion;
|
||||
}
|
||||
|
||||
void OnSessionRemoved()
|
||||
{
|
||||
CleanupSession();
|
||||
|
||||
SessionInfoDisplayStyle = DisplayStyle.None;
|
||||
SessionState = "Session State: No Session";
|
||||
|
||||
++m_UpdateVersion;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (m_SessionObserver != null)
|
||||
{
|
||||
m_SessionObserver.AddingSessionStarted -= SessionInfoReceptionStarted;
|
||||
m_SessionObserver.SessionAdded -= OnSessionAdded;
|
||||
m_SessionObserver.AddingSessionFailed -= OnAddingSessionFailed;
|
||||
|
||||
m_SessionObserver.Dispose();
|
||||
m_SessionObserver = null;
|
||||
}
|
||||
|
||||
if (m_Session != null)
|
||||
{
|
||||
CleanupSession();
|
||||
}
|
||||
}
|
||||
|
||||
void CleanupSession()
|
||||
{
|
||||
m_Session.Changed -= OnSessionChanged;
|
||||
m_Session.RemovedFromSession -= OnSessionRemoved;
|
||||
m_Session.Deleted -= OnSessionRemoved;
|
||||
m_Session = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method is used by UIToolkit to determine if any data bound to the UI has changed.
|
||||
/// Instead of hashing the data, an m_UpdateVersion counter is incremented when changes occur.
|
||||
/// </summary>
|
||||
public long GetViewHashCode() => m_UpdateVersion;
|
||||
|
||||
/// <summary>
|
||||
/// Suggested implementation of INotifyBindablePropertyChanged from UIToolkit.
|
||||
/// </summary>
|
||||
public event EventHandler<BindablePropertyChangedEventArgs> propertyChanged;
|
||||
|
||||
void Notify([CallerMemberName] string property = null)
|
||||
{
|
||||
propertyChanged?.Invoke(this, new BindablePropertyChangedEventArgs(property));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 25c64e96e7394114a2da0fc5ce47bedf
|
||||
timeCreated: 1761688334
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 341930
|
||||
packageName: Unity Building Block - Multiplayer Session
|
||||
packageVersion: 1.0
|
||||
assetPath: Assets/Blocks/CommonSession/Runtime/SessionInfo/SessionInfoViewModel.cs
|
||||
uploadId: 814574
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 877c74e863e5cbe4b9f43c3f8d79b287
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,62 @@
|
||||
using Unity.Properties;
|
||||
using System;
|
||||
using Blocks.Common;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace Blocks.Sessions.Common
|
||||
{
|
||||
[UxmlElement]
|
||||
public partial class SessionNameLabel : Label
|
||||
{
|
||||
[UxmlAttribute, CreateProperty]
|
||||
public string SessionType
|
||||
{
|
||||
get => m_SessionType;
|
||||
set
|
||||
{
|
||||
if (m_SessionType == value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_SessionType = value;
|
||||
if (panel != null)
|
||||
{
|
||||
UpdateBindings();
|
||||
}
|
||||
}
|
||||
}
|
||||
string m_SessionType;
|
||||
|
||||
DataBinding m_DataBinding;
|
||||
|
||||
public SessionNameLabel()
|
||||
{
|
||||
AddToClassList(BlocksTheme.Header);
|
||||
m_DataBinding = new DataBinding()
|
||||
{
|
||||
dataSourcePath = new PropertyPath(nameof(SessionNameViewModel.SessionName)),
|
||||
bindingMode = BindingMode.ToTarget
|
||||
};
|
||||
SetBinding(new BindingId(nameof(text)), m_DataBinding);
|
||||
|
||||
RegisterCallback<AttachToPanelEvent>(_ => UpdateBindings());
|
||||
RegisterCallback<DetachFromPanelEvent>(_ => CleanupBindings());
|
||||
}
|
||||
|
||||
void UpdateBindings()
|
||||
{
|
||||
CleanupBindings();
|
||||
m_DataBinding.dataSource = new SessionNameViewModel(m_SessionType);
|
||||
}
|
||||
|
||||
void CleanupBindings()
|
||||
{
|
||||
if (m_DataBinding.dataSource is IDisposable disposable)
|
||||
{
|
||||
disposable.Dispose();
|
||||
}
|
||||
m_DataBinding.dataSource = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8d5496c0ddcf24a47b023a1787a6fd15
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 341930
|
||||
packageName: Unity Building Block - Multiplayer Session
|
||||
packageVersion: 1.0
|
||||
assetPath: Assets/Blocks/CommonSession/Runtime/SessionName/SessionNameLabel.cs
|
||||
uploadId: 814574
|
||||
@@ -0,0 +1,107 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Unity.Properties;
|
||||
using Unity.Services.Multiplayer;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace Blocks.Sessions.Common
|
||||
{
|
||||
public class SessionNameViewModel : INotifyBindablePropertyChanged, IDataSourceViewHashProvider, IDisposable
|
||||
{
|
||||
const string k_NoSession = "No Session joined";
|
||||
|
||||
SessionObserver m_SessionObserver;
|
||||
ISession m_Session;
|
||||
long m_UpdateVersion;
|
||||
|
||||
/// <summary>
|
||||
/// This property is bound to <see cref="SessionNameLabel.text"/> so that the label displays the current
|
||||
/// session name.
|
||||
/// <summary>
|
||||
[CreateProperty]
|
||||
public string SessionName
|
||||
{
|
||||
get => m_SessionName;
|
||||
set
|
||||
{
|
||||
if (m_SessionName == value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_SessionName = value;
|
||||
++m_UpdateVersion;
|
||||
Notify();
|
||||
}
|
||||
}
|
||||
string m_SessionName = k_NoSession;
|
||||
|
||||
public SessionNameViewModel(string sessionType)
|
||||
{
|
||||
m_SessionObserver = new SessionObserver(sessionType);
|
||||
m_SessionObserver.SessionAdded += OnSessionAdded;
|
||||
|
||||
if (m_SessionObserver.Session != null)
|
||||
{
|
||||
OnSessionAdded(m_SessionObserver.Session);
|
||||
}
|
||||
}
|
||||
|
||||
void OnSessionAdded(ISession newSession)
|
||||
{
|
||||
m_Session = newSession;
|
||||
m_Session.RemovedFromSession += OnSessionRemoved;
|
||||
m_Session.Deleted += OnSessionRemoved;
|
||||
m_Session.Changed += OnSessionChanged;
|
||||
SessionName = newSession.Name;
|
||||
}
|
||||
|
||||
void OnSessionChanged()
|
||||
{
|
||||
SessionName = m_Session.Name;
|
||||
}
|
||||
|
||||
void OnSessionRemoved()
|
||||
{
|
||||
SessionName = k_NoSession;
|
||||
CleanupSession();
|
||||
}
|
||||
|
||||
void CleanupSession()
|
||||
{
|
||||
m_Session.RemovedFromSession -= OnSessionRemoved;
|
||||
m_Session.Deleted -= OnSessionRemoved;
|
||||
m_Session.Changed -= OnSessionChanged;
|
||||
m_Session = null;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (m_SessionObserver != null)
|
||||
{
|
||||
m_SessionObserver.Dispose();
|
||||
m_SessionObserver = null;
|
||||
}
|
||||
|
||||
if (m_Session != null)
|
||||
{
|
||||
CleanupSession();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method is used by UIToolkit to determine if any data bound to the UI has changed.
|
||||
/// Instead of hashing the data, an m_UpdateVersion counter is incremented when changes occur.
|
||||
/// </summary>
|
||||
public long GetViewHashCode() => m_UpdateVersion;
|
||||
|
||||
/// <summary>
|
||||
/// Suggested implementation of INotifyBindablePropertyChanged from UIToolkit.
|
||||
/// </summary>
|
||||
public event EventHandler<BindablePropertyChangedEventArgs> propertyChanged;
|
||||
void Notify([CallerMemberName] string property = null)
|
||||
{
|
||||
propertyChanged?.Invoke(this, new BindablePropertyChangedEventArgs(property));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f6ca50c010d7e5e439af60ce0f1ca4ad
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 341930
|
||||
packageName: Unity Building Block - Multiplayer Session
|
||||
packageVersion: 1.0
|
||||
assetPath: Assets/Blocks/CommonSession/Runtime/SessionName/SessionNameViewModel.cs
|
||||
uploadId: 814574
|
||||
@@ -0,0 +1,112 @@
|
||||
using Unity.Services.Multiplayer;
|
||||
using UnityEngine;
|
||||
|
||||
#if !GAMEOBJECTS_NETCODE_2_AVAILABLE
|
||||
using System;
|
||||
#endif
|
||||
|
||||
namespace Blocks.Sessions.Common
|
||||
{
|
||||
[CreateAssetMenu(fileName = nameof(SessionSettings), menuName = "Services/Blocks/Session/" + nameof(SessionSettings))]
|
||||
public class SessionSettings : ScriptableObject
|
||||
{
|
||||
[Header("Session options")]
|
||||
[Tooltip("Maximum number of players allowed in the session.")]
|
||||
public int maxPlayers = 5;
|
||||
[Tooltip("The name of the created session. It can be used to display the list of existing sessions in the UI.")]
|
||||
public string sessionName = "default-session-name";
|
||||
[Tooltip("The Session Type is used to uniquely identify a type of session locally. This is used to reference a session through the Kits elements.")]
|
||||
public string sessionType = "default-session";
|
||||
public bool usePlayerName = true;
|
||||
|
||||
[Header("Network options")]
|
||||
[Tooltip("If true, a network session will be created when creating or joining a Session. " +
|
||||
"The Multiplayer Service will try to connect using the NetworkManager or the Entity Drivers depending on which network SDK is installed in your project.")]
|
||||
public bool createNetworkSession = true;
|
||||
[Tooltip("The type of network connection to use. This is only used if `Create Network Session` is true.")]
|
||||
public NetworkType networkType = NetworkType.Relay;
|
||||
|
||||
[Header("DirectConnect options")]
|
||||
[Tooltip("The IP address to use for direct connections. This is only used if `Network Type` is set to `Direct`.")]
|
||||
public string ipAddress = "127.0.0.1";
|
||||
[Tooltip("The port to use for direct connections. This is only used if `Network Type` is set to `Direct`.")]
|
||||
public ushort port = 7777;
|
||||
|
||||
public SessionOptions ToSessionOptions()
|
||||
{
|
||||
var options = BuildSessionOptions();
|
||||
|
||||
if (usePlayerName)
|
||||
{
|
||||
options.WithPlayerName();
|
||||
}
|
||||
|
||||
if (createNetworkSession)
|
||||
{
|
||||
AddCreateNetworkOptions(options);
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
void AddCreateNetworkOptions(SessionOptions options)
|
||||
{
|
||||
switch (networkType)
|
||||
{
|
||||
case NetworkType.Direct:
|
||||
options.WithDirectNetwork(new DirectNetworkOptions(new ListenIPAddress(ipAddress), new PublishIPAddress(ipAddress), port));
|
||||
break;
|
||||
case NetworkType.Relay:
|
||||
options.WithRelayNetwork();
|
||||
break;
|
||||
case NetworkType.DistributedAuthority:
|
||||
#if GAMEOBJECTS_NETCODE_2_AVAILABLE
|
||||
options.WithDistributedAuthorityNetwork();
|
||||
break;
|
||||
#else
|
||||
throw new InvalidOperationException(
|
||||
"Distributed Authority network is not supported without Netcode for Gameobjects v2.0.");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
SessionOptions BuildSessionOptions()
|
||||
{
|
||||
return new SessionOptions
|
||||
{
|
||||
MaxPlayers = maxPlayers,
|
||||
Name = sessionName,
|
||||
Type = sessionType,
|
||||
};
|
||||
}
|
||||
|
||||
#if UNITY_SERVER
|
||||
public SessionOptions ToServerSessionOptions()
|
||||
{
|
||||
var options = BuildSessionOptions();
|
||||
|
||||
if (createNetworkSession)
|
||||
{
|
||||
AddCreateNetworkOptions(options);
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
#endif
|
||||
|
||||
public JoinSessionOptions ToJoinSessionOptions()
|
||||
{
|
||||
var options = new JoinSessionOptions
|
||||
{
|
||||
Type = sessionType,
|
||||
};
|
||||
|
||||
if (usePlayerName)
|
||||
{
|
||||
options.WithPlayerName();
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 383e97d81e425c14f9b074d4dfab93e2
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 341930
|
||||
packageName: Unity Building Block - Multiplayer Session
|
||||
packageVersion: 1.0
|
||||
assetPath: Assets/Blocks/CommonSession/Runtime/SessionSettings.cs
|
||||
uploadId: 814574
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fcb316c4e8682214d850c3d4f2df5f85
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,59 @@
|
||||
using System;
|
||||
using Blocks.Common;
|
||||
using Unity.Properties;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace Blocks.Sessions.Common
|
||||
{
|
||||
[UxmlElement]
|
||||
public partial class SessionStatusLabel : Label
|
||||
{
|
||||
[UxmlAttribute, CreateProperty]
|
||||
public string SessionType
|
||||
{
|
||||
get => m_SessiontType;
|
||||
set
|
||||
{
|
||||
if (m_SessiontType == value)
|
||||
return;
|
||||
|
||||
m_SessiontType = value;
|
||||
if (panel != null)
|
||||
UpdateBindings();
|
||||
}
|
||||
}
|
||||
|
||||
string m_SessiontType;
|
||||
|
||||
DataBinding m_Binding;
|
||||
|
||||
public SessionStatusLabel()
|
||||
{
|
||||
AddToClassList(BlocksTheme.Label);
|
||||
|
||||
m_Binding = new DataBinding()
|
||||
{
|
||||
dataSourcePath = new PropertyPath(nameof(SessionStatusViewModel.DisplayText)),
|
||||
bindingMode = BindingMode.ToTarget,
|
||||
};
|
||||
|
||||
SetBinding(new BindingId(nameof(text)), m_Binding);
|
||||
|
||||
RegisterCallback<AttachToPanelEvent>(evt => UpdateBindings());
|
||||
RegisterCallback<DetachFromPanelEvent>(evt => RemoveBindings());
|
||||
}
|
||||
|
||||
void RemoveBindings()
|
||||
{
|
||||
if (m_Binding.dataSource is IDisposable disposable)
|
||||
disposable.Dispose();
|
||||
m_Binding.dataSource = null;
|
||||
}
|
||||
|
||||
void UpdateBindings()
|
||||
{
|
||||
RemoveBindings();
|
||||
m_Binding.dataSource = new SessionStatusViewModel(SessionType);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4da76dc5904c6224f90646080a5911cd
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 341930
|
||||
packageName: Unity Building Block - Multiplayer Session
|
||||
packageVersion: 1.0
|
||||
assetPath: Assets/Blocks/CommonSession/Runtime/SessionStatus/SessionStatusLabel.cs
|
||||
uploadId: 814574
|
||||
@@ -0,0 +1,98 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Unity.Properties;
|
||||
using Unity.Services.Multiplayer;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace Blocks.Sessions.Common
|
||||
{
|
||||
public class SessionStatusViewModel : INotifyBindablePropertyChanged, IDataSourceViewHashProvider, IDisposable
|
||||
{
|
||||
const string k_NoSessionText = "Not in a session";
|
||||
|
||||
SessionObserver m_SessionObserver;
|
||||
ISession m_Session;
|
||||
long m_UpdateVersion;
|
||||
|
||||
[CreateProperty]
|
||||
public string DisplayText
|
||||
{
|
||||
get => m_DisplayText;
|
||||
set
|
||||
{
|
||||
if (m_DisplayText == value)
|
||||
return;
|
||||
|
||||
m_DisplayText = value;
|
||||
m_UpdateVersion++;
|
||||
Notify();
|
||||
}
|
||||
}
|
||||
|
||||
string m_DisplayText = k_NoSessionText;
|
||||
|
||||
public SessionStatusViewModel(string sessionType)
|
||||
{
|
||||
m_SessionObserver = new SessionObserver(sessionType);
|
||||
m_SessionObserver.AddingSessionStarted += OnAddingSessionStarted;
|
||||
m_SessionObserver.AddingSessionFailed += OnAddingSessionFailed;
|
||||
m_SessionObserver.SessionAdded += OnSessionAdded;
|
||||
if (m_SessionObserver.Session != null)
|
||||
OnSessionAdded(m_SessionObserver.Session);
|
||||
}
|
||||
|
||||
void OnAddingSessionFailed(AddingSessionOptions sessionOptions, SessionException exception)
|
||||
{
|
||||
DisplayText = "Session operation failed: " + exception.Message;
|
||||
}
|
||||
|
||||
void OnAddingSessionStarted(AddingSessionOptions sessionOptions)
|
||||
{
|
||||
DisplayText = "Awaiting Session information...";
|
||||
}
|
||||
|
||||
void OnSessionAdded(ISession session)
|
||||
{
|
||||
m_Session = session;
|
||||
m_Session.RemovedFromSession += OnRemovedFromSession;
|
||||
m_Session.Deleted += OnRemovedFromSession;
|
||||
DisplayText = "In session: " + m_Session.Name;
|
||||
}
|
||||
|
||||
void OnRemovedFromSession()
|
||||
{
|
||||
CleanupSession();
|
||||
DisplayText = k_NoSessionText;
|
||||
}
|
||||
|
||||
void CleanupSession()
|
||||
{
|
||||
m_Session.RemovedFromSession -= OnRemovedFromSession;
|
||||
m_Session.Deleted -= OnRemovedFromSession;
|
||||
m_Session = null;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
m_SessionObserver?.Dispose();
|
||||
m_SessionObserver = null;
|
||||
|
||||
if (m_Session != null)
|
||||
CleanupSession();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method is used by UIToolkit to determine if any data bound to the UI has changed.
|
||||
/// Instead of hashing the data, an m_UpdateVersion counter is incremented when changes occur.
|
||||
/// </summary>
|
||||
public long GetViewHashCode() => m_UpdateVersion;
|
||||
|
||||
/// <summary>
|
||||
/// Suggested implementation of INotifyBindablePropertyChanged from UIToolkit.
|
||||
/// </summary>
|
||||
public event EventHandler<BindablePropertyChangedEventArgs> propertyChanged;
|
||||
|
||||
void Notify([CallerMemberName] string property = null) =>
|
||||
propertyChanged?.Invoke(this, new BindablePropertyChangedEventArgs(property));
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 12b466ea4a0f660488391a3c0f5cdfe1
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 341930
|
||||
packageName: Unity Building Block - Multiplayer Session
|
||||
packageVersion: 1.0
|
||||
assetPath: Assets/Blocks/CommonSession/Runtime/SessionStatus/SessionStatusViewModel.cs
|
||||
uploadId: 814574
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 45d00dd10186d94aa9dcbf4b5a8be28c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,50 @@
|
||||
<engine:UXML xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:engine="UnityEngine.UIElements"
|
||||
xmlns:editor="UnityEditor.UIElements"
|
||||
noNamespaceSchemaLocation="../../../../../../../UIElementsSchema/UIElements.xsd"
|
||||
editor-extension-mode="False">
|
||||
<engine:VisualElement class="blocks-modal">
|
||||
<engine:VisualElement
|
||||
class="blocks-container--horizontal blocks-container--space-between blocks-modal--left-aligned-text">
|
||||
<Blocks.Sessions.Common.SessionNameLabel class="blocks-header blocks-element--space-right">
|
||||
<Bindings>
|
||||
<engine:DataBinding property="SessionType" data-source-path="sessionType" binding-mode="ToTarget" />
|
||||
</Bindings>
|
||||
</Blocks.Sessions.Common.SessionNameLabel>
|
||||
<Blocks.Sessions.Common.PlayerCountLabel>
|
||||
<Bindings>
|
||||
<engine:DataBinding property="SessionType" binding-mode="ToTarget" data-source-path="sessionType" />
|
||||
</Bindings>
|
||||
</Blocks.Sessions.Common.PlayerCountLabel>
|
||||
</engine:VisualElement>
|
||||
<engine:VisualElement
|
||||
class="blocks-container--horizontal blocks-container--space-between blocks-element--space-bottom blocks-modal--left-aligned-text">
|
||||
<Blocks.Sessions.Common.PlayerNameLabel class="blocks-element--space-right blocks-header blocks-header--sm">
|
||||
<Bindings>
|
||||
<engine:DataBinding property="SessionType" data-source-path="sessionType" binding-mode="ToTarget" />
|
||||
</Bindings>
|
||||
</Blocks.Sessions.Common.PlayerNameLabel>
|
||||
<Blocks.Sessions.Common.CopySessionCodeElement class="blocks-copy-session--header">
|
||||
<Bindings>
|
||||
<engine:DataBinding property="SessionType" data-source-path="sessionType" binding-mode="ToTarget" />
|
||||
</Bindings>
|
||||
</Blocks.Sessions.Common.CopySessionCodeElement>
|
||||
</engine:VisualElement>
|
||||
<Blocks.Sessions.Common.PlayerListViewElement class="blocks-element--space-bottom">
|
||||
<Bindings>
|
||||
<engine:DataBinding property="SessionType" data-source-path="sessionType" binding-mode="ToTarget" />
|
||||
</Bindings>
|
||||
</Blocks.Sessions.Common.PlayerListViewElement>
|
||||
<Blocks.Sessions.Common.LeaveSessionButton>
|
||||
<Bindings>
|
||||
<engine:DataBinding property="SessionType" binding-mode="ToTarget" data-source-path="sessionType" />
|
||||
</Bindings>
|
||||
</Blocks.Sessions.Common.LeaveSessionButton>
|
||||
<engine:VisualElement class="blocks-container--horizontal blocks-container--right">
|
||||
<Blocks.Sessions.Common.SessionStatusLabel class="blocks-element--space-right blocks-label">
|
||||
<Bindings>
|
||||
<engine:DataBinding property="SessionType" data-source-path="sessionType" binding-mode="ToTarget" />
|
||||
</Bindings>
|
||||
</Blocks.Sessions.Common.SessionStatusLabel>
|
||||
</engine:VisualElement>
|
||||
</engine:VisualElement>
|
||||
</engine:UXML>
|
||||
@@ -0,0 +1,17 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6a55f10912d74d3449f68f82c91df9d2
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 341930
|
||||
packageName: Unity Building Block - Multiplayer Session
|
||||
packageVersion: 1.0
|
||||
assetPath: Assets/Blocks/CommonSession/UI/CurrentSession.uxml
|
||||
uploadId: 814574
|
||||
@@ -0,0 +1,9 @@
|
||||
<engine:UXML xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:engine="UnityEngine.UIElements" xmlns:editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../../../../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="False">
|
||||
<engine:VisualElement class="blocks-modal blocks-modal--left-aligned-text">
|
||||
<Blocks.Sessions.Common.SessionInfoElement>
|
||||
<Bindings>
|
||||
<engine:DataBinding property="SessionType" data-source-path="sessionType" binding-mode="ToTarget"/>
|
||||
</Bindings>
|
||||
</Blocks.Sessions.Common.SessionInfoElement>
|
||||
</engine:VisualElement>
|
||||
</engine:UXML>
|
||||
@@ -0,0 +1,17 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 23d191ee94bd3e249be3e6429d4e6220
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 341930
|
||||
packageName: Unity Building Block - Multiplayer Session
|
||||
packageVersion: 1.0
|
||||
assetPath: Assets/Blocks/CommonSession/UI/SessionInfo.uxml
|
||||
uploadId: 814574
|
||||
Reference in New Issue
Block a user