clean project
This commit is contained in:
8
Assets/Oculus/Platform/Samples/EntitlementCheck.meta
Normal file
8
Assets/Oculus/Platform/Samples/EntitlementCheck.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 70f243575cf968b468804ac28d7a7336
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,100 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using Oculus.Platform;
|
||||
using Oculus.Platform.Models;
|
||||
|
||||
namespace Oculus.Platform.Samples.EntitlementCheck
|
||||
{
|
||||
public class EntitlementCheck : MonoBehaviour
|
||||
{
|
||||
// Implements a default behavior for entitlement check failures by simply exiting the app.
|
||||
// Set to false if the app wants to provide custom logic to handle entitlement check failures.
|
||||
// For example, the app can instead display a modal dialog to the user and exit gracefully.
|
||||
public bool exitAppOnFailure = true;
|
||||
|
||||
// The app can optionally subscribe to these events to do custom entitlement check logic.
|
||||
public static event Action UserFailedEntitlementCheck;
|
||||
public static event Action UserPassedEntitlementCheck;
|
||||
|
||||
void Start()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Init the Oculust Platform SDK and send an entitlement check request.
|
||||
if (!Oculus.Platform.Core.IsInitialized())
|
||||
{
|
||||
Oculus.Platform.Core.Initialize();
|
||||
}
|
||||
|
||||
Entitlements.IsUserEntitledToApplication().OnComplete(EntitlementCheckCallback);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Treat any potential initialization exceptions as an entitlement check failure.
|
||||
HandleEntitlementCheckResult(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Called when the Oculus Platform completes the async entitlement check request and a result is available.
|
||||
void EntitlementCheckCallback(Message msg)
|
||||
{
|
||||
// If the user passed the entitlement check, msg.IsError will be false.
|
||||
// If the user failed the entitlement check, msg.IsError will be true.
|
||||
HandleEntitlementCheckResult(msg.IsError == false);
|
||||
}
|
||||
|
||||
void HandleEntitlementCheckResult(bool result)
|
||||
{
|
||||
if (result) // User passed entitlement check
|
||||
{
|
||||
Debug.Log("Oculus user entitlement check successful.");
|
||||
|
||||
try
|
||||
{
|
||||
// Raise the user passed entitlement check event if the app subscribed a handler to it.
|
||||
if (UserPassedEntitlementCheck != null)
|
||||
{
|
||||
UserPassedEntitlementCheck();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Suppressing any exceptions to avoid potential exceptions in the app-provided event handler.
|
||||
Debug.LogError("Suppressed exception in app-provided UserPassedEntitlementCheck() event handler.");
|
||||
}
|
||||
}
|
||||
else // User failed entitlement check
|
||||
{
|
||||
try
|
||||
{
|
||||
// Raise the user failed entitlement check event if the app subscribed a handler to it.
|
||||
if (UserFailedEntitlementCheck != null)
|
||||
{
|
||||
UserFailedEntitlementCheck();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Suppressing any exceptions to avoid potential exceptions in the app-provided event handler.
|
||||
// Ensures the default entitlement check behavior will still execute, if enabled.
|
||||
Debug.LogError("Suppressed exception in app-provided UserFailedEntitlementCheck() event handler.");
|
||||
}
|
||||
|
||||
if (exitAppOnFailure)
|
||||
{
|
||||
// Implements a default behavior for an entitlement check failure -- log the failure and exit the app.
|
||||
Debug.LogError("Oculus user entitlement check failed. Exiting now.");
|
||||
#if UNITY_EDITOR
|
||||
UnityEditor.EditorApplication.isPlaying = false;
|
||||
#else
|
||||
UnityEngine.Application.Quit();
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("Oculus user entitlement check failed.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 75ccf1814f335d94ab1902064233299e
|
||||
timeCreated: 1543369724
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
229
Assets/Oculus/Platform/Samples/EntitlementCheck/Main.unity
Normal file
229
Assets/Oculus/Platform/Samples/EntitlementCheck/Main.unity
Normal file
@@ -0,0 +1,229 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!29 &1
|
||||
OcclusionCullingSettings:
|
||||
m_ObjectHideFlags: 0
|
||||
serializedVersion: 2
|
||||
m_OcclusionBakeSettings:
|
||||
smallestOccluder: 5
|
||||
smallestHole: 0.25
|
||||
backfaceThreshold: 100
|
||||
m_SceneGUID: 00000000000000000000000000000000
|
||||
m_OcclusionCullingData: {fileID: 0}
|
||||
--- !u!104 &2
|
||||
RenderSettings:
|
||||
m_ObjectHideFlags: 0
|
||||
serializedVersion: 9
|
||||
m_Fog: 0
|
||||
m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
|
||||
m_FogMode: 3
|
||||
m_FogDensity: 0.01
|
||||
m_LinearFogStart: 0
|
||||
m_LinearFogEnd: 300
|
||||
m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
|
||||
m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
|
||||
m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
|
||||
m_AmbientIntensity: 1
|
||||
m_AmbientMode: 0
|
||||
m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
|
||||
m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_HaloStrength: 0.5
|
||||
m_FlareStrength: 1
|
||||
m_FlareFadeSpeed: 3
|
||||
m_HaloTexture: {fileID: 0}
|
||||
m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
|
||||
m_DefaultReflectionMode: 0
|
||||
m_DefaultReflectionResolution: 128
|
||||
m_ReflectionBounces: 1
|
||||
m_ReflectionIntensity: 1
|
||||
m_CustomReflection: {fileID: 0}
|
||||
m_Sun: {fileID: 0}
|
||||
m_IndirectSpecularColor: {r: 0.3731193, g: 0.38073996, b: 0.35872698, a: 1}
|
||||
m_UseRadianceAmbientProbe: 0
|
||||
--- !u!157 &3
|
||||
LightmapSettings:
|
||||
m_ObjectHideFlags: 0
|
||||
serializedVersion: 11
|
||||
m_GIWorkflowMode: 0
|
||||
m_GISettings:
|
||||
serializedVersion: 2
|
||||
m_BounceScale: 1
|
||||
m_IndirectOutputScale: 1
|
||||
m_AlbedoBoost: 1
|
||||
m_EnvironmentLightingMode: 0
|
||||
m_EnableBakedLightmaps: 1
|
||||
m_EnableRealtimeLightmaps: 1
|
||||
m_LightmapEditorSettings:
|
||||
serializedVersion: 12
|
||||
m_Resolution: 2
|
||||
m_BakeResolution: 40
|
||||
m_AtlasSize: 1024
|
||||
m_AO: 0
|
||||
m_AOMaxDistance: 1
|
||||
m_CompAOExponent: 1
|
||||
m_CompAOExponentDirect: 0
|
||||
m_ExtractAmbientOcclusion: 0
|
||||
m_Padding: 2
|
||||
m_LightmapParameters: {fileID: 0}
|
||||
m_LightmapsBakeMode: 1
|
||||
m_TextureCompression: 1
|
||||
m_FinalGather: 0
|
||||
m_FinalGatherFiltering: 1
|
||||
m_FinalGatherRayCount: 256
|
||||
m_ReflectionCompression: 2
|
||||
m_MixedBakeMode: 2
|
||||
m_BakeBackend: 0
|
||||
m_PVRSampling: 1
|
||||
m_PVRDirectSampleCount: 32
|
||||
m_PVRSampleCount: 500
|
||||
m_PVRBounces: 2
|
||||
m_PVREnvironmentSampleCount: 500
|
||||
m_PVREnvironmentReferencePointCount: 2048
|
||||
m_PVRFilteringMode: 2
|
||||
m_PVRDenoiserTypeDirect: 0
|
||||
m_PVRDenoiserTypeIndirect: 0
|
||||
m_PVRDenoiserTypeAO: 0
|
||||
m_PVRFilterTypeDirect: 0
|
||||
m_PVRFilterTypeIndirect: 0
|
||||
m_PVRFilterTypeAO: 0
|
||||
m_PVREnvironmentMIS: 0
|
||||
m_PVRCulling: 1
|
||||
m_PVRFilteringGaussRadiusDirect: 1
|
||||
m_PVRFilteringGaussRadiusIndirect: 5
|
||||
m_PVRFilteringGaussRadiusAO: 2
|
||||
m_PVRFilteringAtrousPositionSigmaDirect: 0.5
|
||||
m_PVRFilteringAtrousPositionSigmaIndirect: 2
|
||||
m_PVRFilteringAtrousPositionSigmaAO: 1
|
||||
m_ExportTrainingData: 0
|
||||
m_TrainingDataDestination: TrainingData
|
||||
m_LightProbeSampleCountMultiplier: 4
|
||||
m_LightingDataAsset: {fileID: 0}
|
||||
m_UseShadowmask: 1
|
||||
--- !u!196 &4
|
||||
NavMeshSettings:
|
||||
serializedVersion: 2
|
||||
m_ObjectHideFlags: 0
|
||||
m_BuildSettings:
|
||||
serializedVersion: 2
|
||||
agentTypeID: 0
|
||||
agentRadius: 0.5
|
||||
agentHeight: 2
|
||||
agentSlope: 45
|
||||
agentClimb: 0.4
|
||||
ledgeDropHeight: 0
|
||||
maxJumpAcrossDistance: 0
|
||||
minRegionArea: 2
|
||||
manualCellSize: 0
|
||||
cellSize: 0.16666667
|
||||
manualTileSize: 0
|
||||
tileSize: 256
|
||||
accuratePlacement: 0
|
||||
debug:
|
||||
m_Flags: 0
|
||||
m_NavMeshData: {fileID: 0}
|
||||
--- !u!1 &2000270733
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 2000270738}
|
||||
- component: {fileID: 2000270737}
|
||||
- component: {fileID: 2000270735}
|
||||
- component: {fileID: 2000270734}
|
||||
- component: {fileID: 2000270739}
|
||||
m_Layer: 0
|
||||
m_Name: Main Camera
|
||||
m_TagString: MainCamera
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!81 &2000270734
|
||||
AudioListener:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2000270733}
|
||||
m_Enabled: 1
|
||||
--- !u!124 &2000270735
|
||||
Behaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2000270733}
|
||||
m_Enabled: 1
|
||||
--- !u!20 &2000270737
|
||||
Camera:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2000270733}
|
||||
m_Enabled: 1
|
||||
serializedVersion: 2
|
||||
m_ClearFlags: 1
|
||||
m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0}
|
||||
m_projectionMatrixMode: 1
|
||||
m_GateFitMode: 2
|
||||
m_FOVAxisMode: 0
|
||||
m_SensorSize: {x: 36, y: 24}
|
||||
m_LensShift: {x: 0, y: 0}
|
||||
m_FocalLength: 50
|
||||
m_NormalizedViewPortRect:
|
||||
serializedVersion: 2
|
||||
x: 0
|
||||
y: 0
|
||||
width: 1
|
||||
height: 1
|
||||
near clip plane: 0.3
|
||||
far clip plane: 1000
|
||||
field of view: 60
|
||||
orthographic: 0
|
||||
orthographic size: 5
|
||||
m_Depth: -1
|
||||
m_CullingMask:
|
||||
serializedVersion: 2
|
||||
m_Bits: 4294967295
|
||||
m_RenderingPath: -1
|
||||
m_TargetTexture: {fileID: 0}
|
||||
m_TargetDisplay: 0
|
||||
m_TargetEye: 3
|
||||
m_HDR: 1
|
||||
m_AllowMSAA: 1
|
||||
m_AllowDynamicResolution: 0
|
||||
m_ForceIntoRT: 0
|
||||
m_OcclusionCulling: 1
|
||||
m_StereoConvergence: 10
|
||||
m_StereoSeparation: 0.022
|
||||
--- !u!4 &2000270738
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2000270733}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 1, z: -10}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!114 &2000270739
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2000270733}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 75ccf1814f335d94ab1902064233299e, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
exitAppOnFailure: 1
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9df623f348e176845a764b6c2e269451
|
||||
timeCreated: 1543369713
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Oculus/Platform/Samples/GroupPresenceSample.meta
Normal file
8
Assets/Oculus/Platform/Samples/GroupPresenceSample.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 30acf64326ce6604e8ed8f22e37fcc1a
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f7407bf8d5510524896ddc654b7ba87f
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,405 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &1029123982390752
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 224566574175330634}
|
||||
- component: {fileID: 222109690043464122}
|
||||
- component: {fileID: 114889101218588212}
|
||||
m_Layer: 5
|
||||
m_Name: DestinationsTextList
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &224566574175330634
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1029123982390752}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 224908873728430796}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 800, y: 600}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &222109690043464122
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1029123982390752}
|
||||
m_CullTransparentMesh: 0
|
||||
--- !u!114 &114889101218588212
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1029123982390752}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_FontData:
|
||||
m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
|
||||
m_FontSize: 61
|
||||
m_FontStyle: 0
|
||||
m_BestFit: 0
|
||||
m_MinSize: 3
|
||||
m_MaxSize: 61
|
||||
m_Alignment: 0
|
||||
m_AlignByGeometry: 0
|
||||
m_RichText: 1
|
||||
m_HorizontalOverflow: 0
|
||||
m_VerticalOverflow: 1
|
||||
m_LineSpacing: 1
|
||||
m_Text: Destinations
|
||||
--- !u!1 &1183652821387436
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 224908873728430796}
|
||||
- component: {fileID: 223759242779104624}
|
||||
- component: {fileID: 114398105957111100}
|
||||
- component: {fileID: 114561163922829960}
|
||||
m_Layer: 5
|
||||
m_Name: Destinations Display
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &224908873728430796
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1183652821387436}
|
||||
m_LocalRotation: {x: -0, y: -0.6427876, z: -0, w: 0.7660445}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 500}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children:
|
||||
- {fileID: 224566574175330634}
|
||||
m_Father: {fileID: 4888635847475054}
|
||||
m_RootOrder: 1
|
||||
m_LocalEulerAnglesHint: {x: 0, y: -80, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: -700, y: 75.59}
|
||||
m_SizeDelta: {x: 800, y: 800}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!223 &223759242779104624
|
||||
Canvas:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1183652821387436}
|
||||
m_Enabled: 1
|
||||
serializedVersion: 3
|
||||
m_RenderMode: 2
|
||||
m_Camera: {fileID: 0}
|
||||
m_PlaneDistance: 100
|
||||
m_PixelPerfect: 0
|
||||
m_ReceivesEvents: 1
|
||||
m_OverrideSorting: 0
|
||||
m_OverridePixelPerfect: 0
|
||||
m_SortingBucketNormalizedSize: 0
|
||||
m_AdditionalShaderChannelsFlag: 0
|
||||
m_SortingLayerID: 0
|
||||
m_SortingOrder: 0
|
||||
m_TargetDisplay: 0
|
||||
--- !u!114 &114398105957111100
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1183652821387436}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_UiScaleMode: 0
|
||||
m_ReferencePixelsPerUnit: 100
|
||||
m_ScaleFactor: 1
|
||||
m_ReferenceResolution: {x: 800, y: 600}
|
||||
m_ScreenMatchMode: 0
|
||||
m_MatchWidthOrHeight: 0
|
||||
m_PhysicalUnit: 3
|
||||
m_FallbackScreenDPI: 96
|
||||
m_DefaultSpriteDPI: 96
|
||||
m_DynamicPixelsPerUnit: 1
|
||||
--- !u!114 &114561163922829960
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1183652821387436}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_IgnoreReversedGraphics: 1
|
||||
m_BlockingObjects: 0
|
||||
m_BlockingMask:
|
||||
serializedVersion: 2
|
||||
m_Bits: 4294967295
|
||||
--- !u!1 &1250865195685056
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 224638719472242136}
|
||||
- component: {fileID: 223662648536038570}
|
||||
- component: {fileID: 114472934823343270}
|
||||
- component: {fileID: 114114474722117790}
|
||||
m_Layer: 5
|
||||
m_Name: Rich Presence Display
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &224638719472242136
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1250865195685056}
|
||||
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 751}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children:
|
||||
- {fileID: 224513550524301700}
|
||||
m_Father: {fileID: 4888635847475054}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: -50, y: 168.95}
|
||||
m_SizeDelta: {x: 1000, y: 800}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!223 &223662648536038570
|
||||
Canvas:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1250865195685056}
|
||||
m_Enabled: 1
|
||||
serializedVersion: 3
|
||||
m_RenderMode: 2
|
||||
m_Camera: {fileID: 0}
|
||||
m_PlaneDistance: 100
|
||||
m_PixelPerfect: 0
|
||||
m_ReceivesEvents: 1
|
||||
m_OverrideSorting: 0
|
||||
m_OverridePixelPerfect: 0
|
||||
m_SortingBucketNormalizedSize: 0
|
||||
m_AdditionalShaderChannelsFlag: 0
|
||||
m_SortingLayerID: 0
|
||||
m_SortingOrder: 0
|
||||
m_TargetDisplay: 0
|
||||
--- !u!114 &114472934823343270
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1250865195685056}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_UiScaleMode: 0
|
||||
m_ReferencePixelsPerUnit: 100
|
||||
m_ScaleFactor: 1
|
||||
m_ReferenceResolution: {x: 800, y: 600}
|
||||
m_ScreenMatchMode: 0
|
||||
m_MatchWidthOrHeight: 0
|
||||
m_PhysicalUnit: 3
|
||||
m_FallbackScreenDPI: 96
|
||||
m_DefaultSpriteDPI: 96
|
||||
m_DynamicPixelsPerUnit: 1
|
||||
--- !u!114 &114114474722117790
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1250865195685056}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_IgnoreReversedGraphics: 1
|
||||
m_BlockingObjects: 0
|
||||
m_BlockingMask:
|
||||
serializedVersion: 2
|
||||
m_Bits: 4294967295
|
||||
--- !u!1 &1625345527844402
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 4888635847475054}
|
||||
- component: {fileID: 7539683624769524890}
|
||||
m_Layer: 0
|
||||
m_Name: Rich Presence Sample
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &4888635847475054
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1625345527844402}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children:
|
||||
- {fileID: 224638719472242136}
|
||||
- {fileID: 224908873728430796}
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!114 &7539683624769524890
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1625345527844402}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 9de13f39625194290a3f459c9513e7d2, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
IsJoinable: 1
|
||||
LobbySessionID:
|
||||
MatchSessionID:
|
||||
SuggestedUserID: 0
|
||||
InVRConsole: {fileID: 114782670387223048}
|
||||
DestinationsConsole: {fileID: 114889101218588212}
|
||||
--- !u!1 &1944862617252598
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 224513550524301700}
|
||||
- component: {fileID: 222075363776180578}
|
||||
- component: {fileID: 114782670387223048}
|
||||
m_Layer: 5
|
||||
m_Name: TextStatus
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &224513550524301700
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1944862617252598}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 224638719472242136}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 1000, y: 600}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &222075363776180578
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1944862617252598}
|
||||
m_CullTransparentMesh: 0
|
||||
--- !u!114 &114782670387223048
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1944862617252598}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_FontData:
|
||||
m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
|
||||
m_FontSize: 55
|
||||
m_FontStyle: 0
|
||||
m_BestFit: 0
|
||||
m_MinSize: 3
|
||||
m_MaxSize: 61
|
||||
m_Alignment: 0
|
||||
m_AlignByGeometry: 0
|
||||
m_RichText: 1
|
||||
m_HorizontalOverflow: 0
|
||||
m_VerticalOverflow: 1
|
||||
m_LineSpacing: 1
|
||||
m_Text: VR Console
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a7de3e5619aa4f94c86abdaa1aad343b
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e026616b3e1e7c74486550e66efbe9da
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,401 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!29 &1
|
||||
OcclusionCullingSettings:
|
||||
m_ObjectHideFlags: 0
|
||||
serializedVersion: 2
|
||||
m_OcclusionBakeSettings:
|
||||
smallestOccluder: 5
|
||||
smallestHole: 0.25
|
||||
backfaceThreshold: 100
|
||||
m_SceneGUID: 00000000000000000000000000000000
|
||||
m_OcclusionCullingData: {fileID: 0}
|
||||
--- !u!104 &2
|
||||
RenderSettings:
|
||||
m_ObjectHideFlags: 0
|
||||
serializedVersion: 9
|
||||
m_Fog: 0
|
||||
m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
|
||||
m_FogMode: 3
|
||||
m_FogDensity: 0.01
|
||||
m_LinearFogStart: 0
|
||||
m_LinearFogEnd: 300
|
||||
m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
|
||||
m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
|
||||
m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
|
||||
m_AmbientIntensity: 1
|
||||
m_AmbientMode: 0
|
||||
m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
|
||||
m_SkyboxMaterial: {fileID: 0}
|
||||
m_HaloStrength: 0.5
|
||||
m_FlareStrength: 1
|
||||
m_FlareFadeSpeed: 3
|
||||
m_HaloTexture: {fileID: 0}
|
||||
m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
|
||||
m_DefaultReflectionMode: 0
|
||||
m_DefaultReflectionResolution: 128
|
||||
m_ReflectionBounces: 1
|
||||
m_ReflectionIntensity: 1
|
||||
m_CustomReflection: {fileID: 0}
|
||||
m_Sun: {fileID: 170076734}
|
||||
m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1}
|
||||
m_UseRadianceAmbientProbe: 0
|
||||
--- !u!157 &3
|
||||
LightmapSettings:
|
||||
m_ObjectHideFlags: 0
|
||||
serializedVersion: 11
|
||||
m_GIWorkflowMode: 0
|
||||
m_GISettings:
|
||||
serializedVersion: 2
|
||||
m_BounceScale: 1
|
||||
m_IndirectOutputScale: 1
|
||||
m_AlbedoBoost: 1
|
||||
m_EnvironmentLightingMode: 0
|
||||
m_EnableBakedLightmaps: 1
|
||||
m_EnableRealtimeLightmaps: 0
|
||||
m_LightmapEditorSettings:
|
||||
serializedVersion: 12
|
||||
m_Resolution: 2
|
||||
m_BakeResolution: 10
|
||||
m_AtlasSize: 512
|
||||
m_AO: 0
|
||||
m_AOMaxDistance: 1
|
||||
m_CompAOExponent: 1
|
||||
m_CompAOExponentDirect: 0
|
||||
m_ExtractAmbientOcclusion: 0
|
||||
m_Padding: 2
|
||||
m_LightmapParameters: {fileID: 0}
|
||||
m_LightmapsBakeMode: 1
|
||||
m_TextureCompression: 1
|
||||
m_FinalGather: 0
|
||||
m_FinalGatherFiltering: 1
|
||||
m_FinalGatherRayCount: 256
|
||||
m_ReflectionCompression: 2
|
||||
m_MixedBakeMode: 2
|
||||
m_BakeBackend: 1
|
||||
m_PVRSampling: 1
|
||||
m_PVRDirectSampleCount: 32
|
||||
m_PVRSampleCount: 256
|
||||
m_PVRBounces: 2
|
||||
m_PVREnvironmentSampleCount: 256
|
||||
m_PVREnvironmentReferencePointCount: 2048
|
||||
m_PVRFilteringMode: 2
|
||||
m_PVRDenoiserTypeDirect: 0
|
||||
m_PVRDenoiserTypeIndirect: 0
|
||||
m_PVRDenoiserTypeAO: 0
|
||||
m_PVRFilterTypeDirect: 0
|
||||
m_PVRFilterTypeIndirect: 0
|
||||
m_PVRFilterTypeAO: 0
|
||||
m_PVREnvironmentMIS: 0
|
||||
m_PVRCulling: 1
|
||||
m_PVRFilteringGaussRadiusDirect: 1
|
||||
m_PVRFilteringGaussRadiusIndirect: 5
|
||||
m_PVRFilteringGaussRadiusAO: 2
|
||||
m_PVRFilteringAtrousPositionSigmaDirect: 0.5
|
||||
m_PVRFilteringAtrousPositionSigmaIndirect: 2
|
||||
m_PVRFilteringAtrousPositionSigmaAO: 1
|
||||
m_ExportTrainingData: 0
|
||||
m_TrainingDataDestination: TrainingData
|
||||
m_LightProbeSampleCountMultiplier: 4
|
||||
m_LightingDataAsset: {fileID: 0}
|
||||
m_UseShadowmask: 1
|
||||
--- !u!196 &4
|
||||
NavMeshSettings:
|
||||
serializedVersion: 2
|
||||
m_ObjectHideFlags: 0
|
||||
m_BuildSettings:
|
||||
serializedVersion: 2
|
||||
agentTypeID: 0
|
||||
agentRadius: 0.5
|
||||
agentHeight: 2
|
||||
agentSlope: 45
|
||||
agentClimb: 0.4
|
||||
ledgeDropHeight: 0
|
||||
maxJumpAcrossDistance: 0
|
||||
minRegionArea: 2
|
||||
manualCellSize: 0
|
||||
cellSize: 0.16666667
|
||||
manualTileSize: 0
|
||||
tileSize: 256
|
||||
accuratePlacement: 0
|
||||
debug:
|
||||
m_Flags: 0
|
||||
m_NavMeshData: {fileID: 0}
|
||||
--- !u!1 &170076733
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 170076735}
|
||||
- component: {fileID: 170076734}
|
||||
m_Layer: 0
|
||||
m_Name: Directional Light
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!108 &170076734
|
||||
Light:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 170076733}
|
||||
m_Enabled: 1
|
||||
serializedVersion: 10
|
||||
m_Type: 1
|
||||
m_Shape: 0
|
||||
m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1}
|
||||
m_Intensity: 1
|
||||
m_Range: 10
|
||||
m_SpotAngle: 30
|
||||
m_InnerSpotAngle: 21.80208
|
||||
m_CookieSize: 10
|
||||
m_Shadows:
|
||||
m_Type: 0
|
||||
m_Resolution: -1
|
||||
m_CustomResolution: -1
|
||||
m_Strength: 1
|
||||
m_Bias: 0.05
|
||||
m_NormalBias: 0.4
|
||||
m_NearPlane: 0.2
|
||||
m_CullingMatrixOverride:
|
||||
e00: 1
|
||||
e01: 0
|
||||
e02: 0
|
||||
e03: 0
|
||||
e10: 0
|
||||
e11: 1
|
||||
e12: 0
|
||||
e13: 0
|
||||
e20: 0
|
||||
e21: 0
|
||||
e22: 1
|
||||
e23: 0
|
||||
e30: 0
|
||||
e31: 0
|
||||
e32: 0
|
||||
e33: 1
|
||||
m_UseCullingMatrixOverride: 0
|
||||
m_Cookie: {fileID: 0}
|
||||
m_DrawHalo: 0
|
||||
m_Flare: {fileID: 0}
|
||||
m_RenderMode: 0
|
||||
m_CullingMask:
|
||||
serializedVersion: 2
|
||||
m_Bits: 4294967295
|
||||
m_RenderingLayerMask: 1
|
||||
m_Lightmapping: 1
|
||||
m_LightShadowCasterMode: 0
|
||||
m_AreaSize: {x: 1, y: 1}
|
||||
m_BounceIntensity: 1
|
||||
m_ColorTemperature: 6570
|
||||
m_UseColorTemperature: 0
|
||||
m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_UseBoundingSphereOverride: 0
|
||||
m_ShadowRadius: 0
|
||||
m_ShadowAngle: 0
|
||||
--- !u!4 &170076735
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 170076733}
|
||||
m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261}
|
||||
m_LocalPosition: {x: 0, y: 3, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 1
|
||||
m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0}
|
||||
--- !u!1001 &377356812
|
||||
PrefabInstance:
|
||||
m_ObjectHideFlags: 0
|
||||
serializedVersion: 2
|
||||
m_Modification:
|
||||
m_TransformParent: {fileID: 0}
|
||||
m_Modifications:
|
||||
- target: {fileID: 1250865195685056, guid: a7de3e5619aa4f94c86abdaa1aad343b, type: 3}
|
||||
propertyPath: m_Name
|
||||
value: Group Presence Display
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 1625345527844402, guid: a7de3e5619aa4f94c86abdaa1aad343b, type: 3}
|
||||
propertyPath: m_Name
|
||||
value: Group Presence Sample
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4888635847475054, guid: a7de3e5619aa4f94c86abdaa1aad343b, type: 3}
|
||||
propertyPath: m_LocalPosition.x
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4888635847475054, guid: a7de3e5619aa4f94c86abdaa1aad343b, type: 3}
|
||||
propertyPath: m_LocalPosition.y
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4888635847475054, guid: a7de3e5619aa4f94c86abdaa1aad343b, type: 3}
|
||||
propertyPath: m_LocalPosition.z
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4888635847475054, guid: a7de3e5619aa4f94c86abdaa1aad343b, type: 3}
|
||||
propertyPath: m_LocalRotation.x
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4888635847475054, guid: a7de3e5619aa4f94c86abdaa1aad343b, type: 3}
|
||||
propertyPath: m_LocalRotation.y
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4888635847475054, guid: a7de3e5619aa4f94c86abdaa1aad343b, type: 3}
|
||||
propertyPath: m_LocalRotation.z
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4888635847475054, guid: a7de3e5619aa4f94c86abdaa1aad343b, type: 3}
|
||||
propertyPath: m_LocalRotation.w
|
||||
value: 1
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4888635847475054, guid: a7de3e5619aa4f94c86abdaa1aad343b, type: 3}
|
||||
propertyPath: m_RootOrder
|
||||
value: 2
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 114347612112539610, guid: a7de3e5619aa4f94c86abdaa1aad343b,
|
||||
type: 3}
|
||||
propertyPath: InstanceID
|
||||
value: NewInstance123
|
||||
objectReference: {fileID: 0}
|
||||
m_RemovedComponents:
|
||||
- {fileID: 114347612112539610, guid: a7de3e5619aa4f94c86abdaa1aad343b, type: 3}
|
||||
m_SourcePrefab: {fileID: 100100000, guid: a7de3e5619aa4f94c86abdaa1aad343b, type: 3}
|
||||
--- !u!1 &377356813 stripped
|
||||
GameObject:
|
||||
m_CorrespondingSourceObject: {fileID: 1625345527844402, guid: a7de3e5619aa4f94c86abdaa1aad343b,
|
||||
type: 3}
|
||||
m_PrefabInstance: {fileID: 377356812}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
--- !u!114 &377356814 stripped
|
||||
MonoBehaviour:
|
||||
m_CorrespondingSourceObject: {fileID: 114889101218588212, guid: a7de3e5619aa4f94c86abdaa1aad343b,
|
||||
type: 3}
|
||||
m_PrefabInstance: {fileID: 377356812}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
--- !u!114 &377356815 stripped
|
||||
MonoBehaviour:
|
||||
m_CorrespondingSourceObject: {fileID: 114782670387223048, guid: a7de3e5619aa4f94c86abdaa1aad343b,
|
||||
type: 3}
|
||||
m_PrefabInstance: {fileID: 377356812}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
--- !u!114 &377356816
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 377356813}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 9de13f39625194290a3f459c9513e7d2, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
IsJoinable: 1
|
||||
LobbySessionID:
|
||||
MatchSessionID:
|
||||
SuggestedUserID: 0
|
||||
InVRConsole: {fileID: 377356815}
|
||||
DestinationsConsole: {fileID: 377356814}
|
||||
--- !u!1 &1740205398
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1740205401}
|
||||
- component: {fileID: 1740205400}
|
||||
- component: {fileID: 1740205399}
|
||||
m_Layer: 0
|
||||
m_Name: Camera
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!81 &1740205399
|
||||
AudioListener:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1740205398}
|
||||
m_Enabled: 1
|
||||
--- !u!20 &1740205400
|
||||
Camera:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1740205398}
|
||||
m_Enabled: 1
|
||||
serializedVersion: 2
|
||||
m_ClearFlags: 1
|
||||
m_BackGroundColor: {r: 1, g: 1, b: 1, a: 0}
|
||||
m_projectionMatrixMode: 1
|
||||
m_GateFitMode: 2
|
||||
m_FOVAxisMode: 0
|
||||
m_SensorSize: {x: 36, y: 24}
|
||||
m_LensShift: {x: 0, y: 0}
|
||||
m_FocalLength: 50
|
||||
m_NormalizedViewPortRect:
|
||||
serializedVersion: 2
|
||||
x: 0
|
||||
y: 0
|
||||
width: 1
|
||||
height: 1
|
||||
near clip plane: 0.3
|
||||
far clip plane: 1000
|
||||
field of view: 60
|
||||
orthographic: 0
|
||||
orthographic size: 5
|
||||
m_Depth: 0
|
||||
m_CullingMask:
|
||||
serializedVersion: 2
|
||||
m_Bits: 4294967295
|
||||
m_RenderingPath: -1
|
||||
m_TargetTexture: {fileID: 0}
|
||||
m_TargetDisplay: 0
|
||||
m_TargetEye: 3
|
||||
m_HDR: 1
|
||||
m_AllowMSAA: 1
|
||||
m_AllowDynamicResolution: 0
|
||||
m_ForceIntoRT: 0
|
||||
m_OcclusionCulling: 1
|
||||
m_StereoConvergence: 10
|
||||
m_StereoSeparation: 0.022
|
||||
--- !u!4 &1740205401
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1740205398}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 44e30fce5a7e2fd4db7c4fedc096ccf3
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 296c6b38f6bd34a46aa977dea53f3022
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,477 @@
|
||||
// Uncomment this if you have the Touch controller classes in your project
|
||||
//#define USE_OVRINPUT
|
||||
|
||||
using System;
|
||||
using Oculus.Platform;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
/**
|
||||
* This class shows a very simple way to integrate setting the Group Presence
|
||||
* with a destination and how to respond to a user's app launch details that
|
||||
* include the destination they wish to travel to.
|
||||
*/
|
||||
public class GroupPresenceSample : MonoBehaviour
|
||||
{
|
||||
/**
|
||||
* Sets extra fields on the rich presence
|
||||
*/
|
||||
|
||||
// A boolean to indicate whether the destination is joinable. You can check
|
||||
// the current capacity against the max capacity to determine whether the room
|
||||
// is joinable.
|
||||
public bool IsJoinable = true;
|
||||
|
||||
// Users with the same destination + session ID are considered together by Oculus
|
||||
// Users with the same destination and different session IDs are not
|
||||
public string LobbySessionID;
|
||||
public string MatchSessionID;
|
||||
|
||||
// Users can be suggested as part of the invite flow
|
||||
public UInt64 SuggestedUserID;
|
||||
|
||||
public Text InVRConsole;
|
||||
public Text DestinationsConsole;
|
||||
|
||||
private List<string> DestinationAPINames = new List<string>();
|
||||
private ulong LoggedInUserID = 0;
|
||||
|
||||
// Start is called before the first frame update
|
||||
void Start()
|
||||
{
|
||||
UpdateConsole("Init Oculus Platform SDK...");
|
||||
Core.AsyncInitialize().OnComplete(message => {
|
||||
if (message.IsError)
|
||||
{
|
||||
// Init failed, nothing will work
|
||||
UpdateConsole(message.GetError().Message);
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateConsole("Init complete!");
|
||||
|
||||
/**
|
||||
* Get and cache the Logged in User ID for future queries
|
||||
*/
|
||||
Users.GetLoggedInUser().OnComplete(OnLoggedInUser);
|
||||
|
||||
/**
|
||||
* Get the list of destinations defined for this app from the developer portal
|
||||
*/
|
||||
RichPresence.GetDestinations().OnComplete(OnGetDestinations);
|
||||
|
||||
/**
|
||||
* Listen for future join intents that might come in
|
||||
*/
|
||||
GroupPresence.SetJoinIntentReceivedNotificationCallback(OnJoinIntentChangeNotif);
|
||||
|
||||
/**
|
||||
* Listen for future leave that might come in
|
||||
*/
|
||||
GroupPresence.SetLeaveIntentReceivedNotificationCallback(OnLeaveIntentChangeNotif);
|
||||
|
||||
/**
|
||||
* Listen for the list of users that the current users have invitted
|
||||
*/
|
||||
GroupPresence.SetInvitationsSentNotificationCallback(OnInviteSentNotif);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Setting the group presence
|
||||
*/
|
||||
void SetPresence()
|
||||
{
|
||||
var options = new GroupPresenceOptions();
|
||||
|
||||
options.SetDestinationApiName(DestinationAPINames[DestinationIndex]);
|
||||
|
||||
if (!string.IsNullOrEmpty(MatchSessionID))
|
||||
{
|
||||
options.SetMatchSessionId(MatchSessionID);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(MatchSessionID))
|
||||
{
|
||||
options.SetLobbySessionId(LobbySessionID);
|
||||
}
|
||||
|
||||
// Set is Joinable to let other players deeplink and join this user via the presence
|
||||
options.SetIsJoinable(IsJoinable);
|
||||
|
||||
UpdateConsole("Setting Group Presence to " + DestinationAPINames[DestinationIndex] + " ...");
|
||||
|
||||
// Here we are setting the group presence then fetching it after we successfully set it
|
||||
GroupPresence.Set(options).OnComplete(message => {
|
||||
if (message.IsError)
|
||||
{
|
||||
UpdateConsole(message.GetError().Message);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Note that Users.GetLoggedInUser() does not do a server fetch and will
|
||||
// not get an updated presence status
|
||||
Users.Get(LoggedInUserID).OnComplete(message2 =>
|
||||
{
|
||||
if (message2.IsError)
|
||||
{
|
||||
UpdateConsole("Success! But presence is unknown!");
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateConsole("Group Presence set to:\n" + message2.Data.Presence + "\n" + message2.Data.PresenceDeeplinkMessage + "\n" + message2.Data.PresenceDestinationApiName);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Clearing the rich presence
|
||||
*/
|
||||
void ClearPresence()
|
||||
{
|
||||
UpdateConsole("Clearing Group Presence...");
|
||||
GroupPresence.Clear().OnComplete(message => {
|
||||
if (message.IsError)
|
||||
{
|
||||
UpdateConsole(message.GetError().Message);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Clearing the rich presence then fetching the user's presence afterwards
|
||||
Users.Get(LoggedInUserID).OnComplete(message2 =>
|
||||
{
|
||||
if (message2.IsError)
|
||||
{
|
||||
UpdateConsole("Group Presence cleared! But rich presence is unknown!");
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateConsole("Group Presence cleared!\n" + message2.Data.Presence + "\n");
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Launch the invite panel
|
||||
*/
|
||||
void LaunchInvitePanel()
|
||||
{
|
||||
UpdateConsole("Launching Invite Panel...");
|
||||
var options = new InviteOptions();
|
||||
if (SuggestedUserID != 0)
|
||||
{
|
||||
options.AddSuggestedUser(SuggestedUserID);
|
||||
}
|
||||
GroupPresence.LaunchInvitePanel(options).OnComplete(message =>
|
||||
{
|
||||
if (message.IsError)
|
||||
{
|
||||
UpdateConsole(message.GetError().Message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Launch the roster panel
|
||||
*/
|
||||
void LaunchRosterPanel()
|
||||
{
|
||||
UpdateConsole("Launching Roster Panel...");
|
||||
var options = new RosterOptions();
|
||||
if (SuggestedUserID != 0)
|
||||
{
|
||||
options.AddSuggestedUser(SuggestedUserID);
|
||||
}
|
||||
GroupPresence.LaunchRosterPanel(options).OnComplete(message =>
|
||||
{
|
||||
if (message.IsError)
|
||||
{
|
||||
UpdateConsole(message.GetError().Message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// User has interacted with a deeplink outside this app
|
||||
void OnJoinIntentChangeNotif(Message<Oculus.Platform.Models.GroupPresenceJoinIntent> message)
|
||||
{
|
||||
if (message.IsError)
|
||||
{
|
||||
UpdateConsole(message.GetError().Message);
|
||||
} else
|
||||
{
|
||||
var joinIntent = message.Data;
|
||||
|
||||
// The deeplink message, this should give enough info on how to go the
|
||||
// destination in the app.
|
||||
var deeplinkMessage = joinIntent.DeeplinkMessage;
|
||||
|
||||
// The API Name of the destination. You can set the user to this after
|
||||
// navigating to the app
|
||||
var destinationApiName = joinIntent.DestinationApiName;
|
||||
var matchSessionID = joinIntent.MatchSessionId;
|
||||
var lobbySessionID = joinIntent.LobbySessionId;
|
||||
|
||||
var detailsString = "-Deeplink Message:\n" + deeplinkMessage + "\n-Api Name:\n" + destinationApiName + "\n-Lobby Session Id:\n" + lobbySessionID + "\n-Match Session Id:\n" + matchSessionID;
|
||||
detailsString += "\n";
|
||||
UpdateConsole("Got updated Join Intent & setting the user's presence:\n" + detailsString);
|
||||
|
||||
var options = new GroupPresenceOptions();
|
||||
|
||||
if (!string.IsNullOrEmpty(destinationApiName))
|
||||
{
|
||||
options.SetDestinationApiName(destinationApiName);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(matchSessionID))
|
||||
{
|
||||
options.SetMatchSessionId(matchSessionID);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(lobbySessionID))
|
||||
{
|
||||
options.SetLobbySessionId(lobbySessionID);
|
||||
}
|
||||
GroupPresence.Set(options);
|
||||
}
|
||||
}
|
||||
|
||||
// User has interacted with the roster to leave the current destination / lobby / match
|
||||
void OnLeaveIntentChangeNotif(Message<Oculus.Platform.Models.GroupPresenceLeaveIntent> message)
|
||||
{
|
||||
if (message.IsError)
|
||||
{
|
||||
UpdateConsole(message.GetError().Message);
|
||||
} else
|
||||
{
|
||||
var leaveIntent = message.Data;
|
||||
|
||||
var destinationApiName = leaveIntent.DestinationApiName;
|
||||
MatchSessionID = leaveIntent.MatchSessionId;
|
||||
LobbySessionID = leaveIntent.LobbySessionId;
|
||||
|
||||
var detailsString = "-Api Name:\n" + destinationApiName + "\n-Lobby Session Id:\n" + LobbySessionID + "\n-Match Session Id:\n" + MatchSessionID;
|
||||
detailsString += "\n";
|
||||
UpdateConsole("Clearing presence because user wishes to leave:\n" + detailsString);
|
||||
|
||||
// User left
|
||||
GroupPresence.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
// User has invited users
|
||||
void OnInviteSentNotif(Message<Oculus.Platform.Models.LaunchInvitePanelFlowResult> message)
|
||||
{
|
||||
if (message.IsError)
|
||||
{
|
||||
UpdateConsole(message.GetError().Message);
|
||||
} else
|
||||
{
|
||||
var users = message.Data.InvitedUsers;
|
||||
var usersCount = users.Count;
|
||||
|
||||
var usersInvitedString = "-Users:\n";
|
||||
if (usersCount > 0)
|
||||
{
|
||||
foreach(var user in users)
|
||||
{
|
||||
usersInvitedString += user.OculusID + "\n";
|
||||
}
|
||||
} else
|
||||
{
|
||||
usersInvitedString += "none\n";
|
||||
}
|
||||
|
||||
UpdateConsole("Users sent invite to:\n" + usersInvitedString);
|
||||
}
|
||||
}
|
||||
|
||||
void OnGetDestinations(Message<Oculus.Platform.Models.DestinationList> message)
|
||||
{
|
||||
if (message.IsError)
|
||||
{
|
||||
UpdateConsole("Could not get the list of destinations!");
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach(Oculus.Platform.Models.Destination destination in message.Data)
|
||||
{
|
||||
DestinationAPINames.Add(destination.ApiName);
|
||||
UpdateDestinationsConsole();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region Helper Functions
|
||||
|
||||
private int DestinationIndex = 0;
|
||||
private bool OnlyPushUpOnce = false;
|
||||
// Update is called once per frame
|
||||
void Update()
|
||||
{
|
||||
if (PressAButton())
|
||||
{
|
||||
if (DestinationAPINames.Count > 0)
|
||||
{
|
||||
SetPresence();
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateConsole("No destinations to set to!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (PressBButton())
|
||||
{
|
||||
ClearPresence();
|
||||
}
|
||||
else if (PressXButton())
|
||||
{
|
||||
LaunchInvitePanel();
|
||||
}
|
||||
else if (PressYButton())
|
||||
{
|
||||
LaunchRosterPanel();
|
||||
}
|
||||
|
||||
ScrollThroughDestinations();
|
||||
}
|
||||
|
||||
private void ScrollThroughDestinations()
|
||||
{
|
||||
if (PressUp())
|
||||
{
|
||||
if (!OnlyPushUpOnce)
|
||||
{
|
||||
DestinationIndex--;
|
||||
if (DestinationIndex < 0)
|
||||
{
|
||||
DestinationIndex = DestinationAPINames.Count - 1;
|
||||
}
|
||||
OnlyPushUpOnce = true;
|
||||
UpdateDestinationsConsole();
|
||||
}
|
||||
}
|
||||
else if (PressDown())
|
||||
{
|
||||
if (!OnlyPushUpOnce)
|
||||
{
|
||||
DestinationIndex++;
|
||||
if (DestinationIndex >= DestinationAPINames.Count)
|
||||
{
|
||||
DestinationIndex = 0;
|
||||
}
|
||||
OnlyPushUpOnce = true;
|
||||
UpdateDestinationsConsole();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
OnlyPushUpOnce = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateDestinationsConsole()
|
||||
{
|
||||
if (DestinationAPINames.Count == 0)
|
||||
{
|
||||
DestinationsConsole.text = "Add some destinations to the developer dashboard first!";
|
||||
}
|
||||
string destinations = "Destination API Names:\n";
|
||||
for (int i = 0; i < DestinationAPINames.Count; i++)
|
||||
{
|
||||
if (i == DestinationIndex)
|
||||
{
|
||||
destinations += "==>";
|
||||
}
|
||||
destinations += DestinationAPINames[i] + "\n";
|
||||
}
|
||||
DestinationsConsole.text = destinations;
|
||||
}
|
||||
|
||||
private void OnLoggedInUser(Message<Oculus.Platform.Models.User> message)
|
||||
{
|
||||
if (message.IsError)
|
||||
{
|
||||
Debug.LogError("Cannot get logged in user");
|
||||
}
|
||||
else
|
||||
{
|
||||
LoggedInUserID = message.Data.ID;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateConsole(string value)
|
||||
{
|
||||
Debug.Log(value);
|
||||
|
||||
InVRConsole.text =
|
||||
"Scroll Up/Down on Right Thumbstick\n(A) - Set Group Presence to selected\n(B) - Clear Group Presence\n(X) - Launch Invite Panel\n(Y) - Launch Roster Panel\n\n" + value;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region I/O Inputs
|
||||
private bool PressAButton()
|
||||
{
|
||||
#if USE_OVRINPUT
|
||||
return OVRInput.GetUp(OVRInput.Button.One) || Input.GetKeyUp(KeyCode.A);
|
||||
#else
|
||||
return Input.GetKeyUp(KeyCode.A);
|
||||
#endif
|
||||
}
|
||||
|
||||
private bool PressBButton()
|
||||
{
|
||||
#if USE_OVRINPUT
|
||||
return OVRInput.GetUp(OVRInput.Button.Two) || Input.GetKeyUp(KeyCode.B);
|
||||
#else
|
||||
return Input.GetKeyUp(KeyCode.B);
|
||||
#endif
|
||||
}
|
||||
|
||||
private bool PressXButton()
|
||||
{
|
||||
#if USE_OVRINPUT
|
||||
return OVRInput.GetUp(OVRInput.Button.Three) || Input.GetKeyUp(KeyCode.X);
|
||||
#else
|
||||
return Input.GetKeyUp(KeyCode.X);
|
||||
#endif
|
||||
}
|
||||
|
||||
private bool PressYButton()
|
||||
{
|
||||
#if USE_OVRINPUT
|
||||
return OVRInput.GetUp(OVRInput.Button.Four) || Input.GetKeyUp(KeyCode.Y);
|
||||
#else
|
||||
return Input.GetKeyUp(KeyCode.Y);
|
||||
#endif
|
||||
}
|
||||
|
||||
private bool PressUp()
|
||||
{
|
||||
#if USE_OVRINPUT
|
||||
Vector2 axis = OVRInput.Get(OVRInput.Axis2D.SecondaryThumbstick);
|
||||
return (axis.y > 0.2 || Input.GetKeyUp(KeyCode.UpArrow));
|
||||
#else
|
||||
return Input.GetKeyUp(KeyCode.UpArrow);
|
||||
#endif
|
||||
}
|
||||
|
||||
private bool PressDown()
|
||||
{
|
||||
#if USE_OVRINPUT
|
||||
Vector2 axis = OVRInput.Get(OVRInput.Axis2D.SecondaryThumbstick);
|
||||
return (axis.y < -0.2 || Input.GetKeyUp(KeyCode.DownArrow));
|
||||
#else
|
||||
return Input.GetKeyUp(KeyCode.DownArrow);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9de13f39625194290a3f459c9513e7d2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Oculus/Platform/Samples/NetChat.meta
Normal file
8
Assets/Oculus/Platform/Samples/NetChat.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 840d6e1bd8dea0b459d4c911961e8d19
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
836
Assets/Oculus/Platform/Samples/NetChat/DataEntry.cs
Normal file
836
Assets/Oculus/Platform/Samples/NetChat/DataEntry.cs
Normal file
@@ -0,0 +1,836 @@
|
||||
namespace Oculus.Platform.Samples.NetChat
|
||||
{
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using Oculus.Platform;
|
||||
using Oculus.Platform.Models;
|
||||
|
||||
enum states
|
||||
{
|
||||
NOT_INIT = 0,
|
||||
IDLE,
|
||||
REQUEST_FIND,
|
||||
FINDING_ROOM,
|
||||
REQUEST_CREATE,
|
||||
REQUEST_JOIN,
|
||||
REQUEST_LEAVE,
|
||||
IN_EMPTY_ROOM,
|
||||
IN_FULL_ROOM
|
||||
}
|
||||
|
||||
// Pools are defined on the Oculus developer portal
|
||||
//
|
||||
// For this test we have a pool created with the pool key set as 'filter_pool'
|
||||
// Mode is set to 'Room'
|
||||
// Skill Pool is set to 'None'
|
||||
// We are not considering Round Trip Time
|
||||
// The following Data Settings are set:
|
||||
// key: map_name, Type: STRING, String options: Small_Map, Big_Map, Really_Big_Map
|
||||
// key: game_type, Type: STRING, String Options: deathmatch, CTF
|
||||
//
|
||||
// We also have the following two queries defined:
|
||||
// Query Key: map
|
||||
// Template: Set (String)
|
||||
// Key: map_name
|
||||
// Wildcards: map_param_1, map_param_2
|
||||
//
|
||||
// Query Key: game_type
|
||||
// Template: Set (String)
|
||||
// Key: game_type_name
|
||||
// Wildcards: game_type_param
|
||||
//
|
||||
// For this test we have a pool created with the pool key set as 'bout_pool'
|
||||
// Mode is set to 'Bout'
|
||||
// Skill Pool is set to 'None'
|
||||
// We are not considering Round Trip Time
|
||||
// No Data Settings are set:
|
||||
//
|
||||
|
||||
public static class Constants
|
||||
{
|
||||
public const int BUFFER_SIZE = 512;
|
||||
public const string BOUT_POOL = "bout_pool";
|
||||
public const string FILTER_POOL = "filter_pool";
|
||||
}
|
||||
|
||||
public class chatPacket
|
||||
{
|
||||
public int packetID { get; set; }
|
||||
public string textString { get; set; }
|
||||
|
||||
public byte[] Serialize()
|
||||
{
|
||||
using (MemoryStream m = new MemoryStream())
|
||||
{
|
||||
using (BinaryWriter writer = new BinaryWriter(m))
|
||||
{
|
||||
// Limit our string to BUFFER_SIZE
|
||||
if (textString.Length > Constants.BUFFER_SIZE)
|
||||
{
|
||||
textString = textString.Substring(0, Constants.BUFFER_SIZE-1);
|
||||
}
|
||||
writer.Write(packetID);
|
||||
writer.Write(textString.ToCharArray());
|
||||
writer.Write('\0');
|
||||
}
|
||||
return m.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public static chatPacket Deserialize(byte[] data)
|
||||
{
|
||||
chatPacket result = new chatPacket();
|
||||
using (MemoryStream m = new MemoryStream(data))
|
||||
{
|
||||
using (BinaryReader reader = new BinaryReader(m))
|
||||
{
|
||||
result.packetID = reader.ReadInt32();
|
||||
result.textString = System.Text.Encoding.Default.GetString(reader.ReadBytes(Constants.BUFFER_SIZE));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public class DataEntry : MonoBehaviour {
|
||||
|
||||
public Text dataOutput;
|
||||
|
||||
states currentState;
|
||||
User localUser;
|
||||
User remoteUser;
|
||||
Room currentRoom;
|
||||
int lastPacketID;
|
||||
bool ratedMatchStarted;
|
||||
|
||||
// Use this for initialization
|
||||
void Start () {
|
||||
currentState = states.NOT_INIT;
|
||||
localUser = null;
|
||||
remoteUser = null;
|
||||
currentRoom = null;
|
||||
lastPacketID = 0;
|
||||
ratedMatchStarted = false;
|
||||
|
||||
Core.Initialize();
|
||||
|
||||
// Setup our room update handler
|
||||
Rooms.SetUpdateNotificationCallback(updateRoom);
|
||||
// Setup our match found handler
|
||||
Matchmaking.SetMatchFoundNotificationCallback(foundMatch);
|
||||
|
||||
checkEntitlement();
|
||||
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void Update()
|
||||
{
|
||||
string currentText = GetComponent<InputField>().text;
|
||||
|
||||
if (Input.GetKey(KeyCode.Return))
|
||||
{
|
||||
if (currentText != "")
|
||||
{
|
||||
SubmitCommand(currentText);
|
||||
}
|
||||
|
||||
GetComponent<InputField>().text = "";
|
||||
}
|
||||
|
||||
processNetPackets();
|
||||
// Handle all messages being returned
|
||||
Request.RunCallbacks();
|
||||
}
|
||||
|
||||
void SubmitCommand(string command)
|
||||
{
|
||||
string[] commandParams = command.Split('!');
|
||||
|
||||
if (commandParams.Length > 0)
|
||||
{
|
||||
switch (commandParams[0])
|
||||
{
|
||||
case "c":
|
||||
requestCreateRoom();
|
||||
break;
|
||||
case "d":
|
||||
requestCreateFilterRoom();
|
||||
break;
|
||||
case "f":
|
||||
requestFindMatch();
|
||||
break;
|
||||
case "g":
|
||||
requestFindRoom();
|
||||
break;
|
||||
case "i":
|
||||
requestFindFilteredRoom();
|
||||
break;
|
||||
case "s":
|
||||
if (commandParams.Length > 1)
|
||||
{
|
||||
sendChat(commandParams[1]);
|
||||
}
|
||||
break;
|
||||
case "l":
|
||||
requestLeaveRoom();
|
||||
break;
|
||||
case "1":
|
||||
requestStartRatedMatch();
|
||||
break;
|
||||
case "2":
|
||||
requestReportResults();
|
||||
break;
|
||||
default:
|
||||
printOutputLine("Invalid Command");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void printOutputLine(String newLine)
|
||||
{
|
||||
dataOutput.text = "> " + newLine + System.Environment.NewLine + dataOutput.text;
|
||||
}
|
||||
|
||||
void checkEntitlement()
|
||||
{
|
||||
Entitlements.IsUserEntitledToApplication().OnComplete(getEntitlementCallback);
|
||||
}
|
||||
|
||||
void getEntitlementCallback(Message msg)
|
||||
{
|
||||
if (!msg.IsError)
|
||||
{
|
||||
printOutputLine("You are entitled to use this app.");
|
||||
Users.GetLoggedInUser().OnComplete(init);
|
||||
}
|
||||
else
|
||||
{
|
||||
printOutputLine("You are NOT entitled to use this app.");
|
||||
}
|
||||
}
|
||||
|
||||
void init(Message<User> msg)
|
||||
{
|
||||
if (!msg.IsError)
|
||||
{
|
||||
User user = msg.Data;
|
||||
localUser = user;
|
||||
|
||||
currentState = states.IDLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
printOutputLine("Received get current user error");
|
||||
Error error = msg.GetError();
|
||||
printOutputLine("Error: " + error.Message);
|
||||
|
||||
// Retry getting the current user
|
||||
Users.GetLoggedInUser().OnComplete(init);
|
||||
currentState = states.NOT_INIT;
|
||||
}
|
||||
}
|
||||
|
||||
void requestCreateRoom()
|
||||
{
|
||||
switch (currentState)
|
||||
{
|
||||
case states.NOT_INIT:
|
||||
printOutputLine("The app has not initialized properly and we don't know your userID.");
|
||||
break;
|
||||
case states.IDLE:
|
||||
printOutputLine("Trying to create a matchmaking room");
|
||||
Matchmaking.CreateAndEnqueueRoom(Constants.FILTER_POOL, 8, true, null).OnComplete(createRoomResponse);
|
||||
currentState = states.REQUEST_CREATE;
|
||||
break;
|
||||
case states.REQUEST_FIND:
|
||||
printOutputLine("You have already made a request to find a room. Please wait for that request to complete.");
|
||||
break;
|
||||
case states.FINDING_ROOM:
|
||||
printOutputLine("You have already currently looking for a room. Please wait for the match to be made.");
|
||||
break;
|
||||
case states.REQUEST_JOIN:
|
||||
printOutputLine("We are currently trying to join a room. Please wait to see if we can join it.");
|
||||
break;
|
||||
case states.REQUEST_LEAVE:
|
||||
printOutputLine("We are currently trying to leave a room. Please wait to see if we can leave it.");
|
||||
break;
|
||||
case states.REQUEST_CREATE:
|
||||
printOutputLine("You have already requested a matchmaking room to be created. Please wait for the room to be made.");
|
||||
break;
|
||||
case states.IN_EMPTY_ROOM:
|
||||
printOutputLine("You have already in a matchmaking room. Please wait for an opponent to join.");
|
||||
break;
|
||||
case states.IN_FULL_ROOM:
|
||||
printOutputLine("You have already in a match.");
|
||||
break;
|
||||
default:
|
||||
printOutputLine("You have hit an unknown state.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void createRoomResponse(Message<MatchmakingEnqueueResultAndRoom> msg)
|
||||
{
|
||||
if (!msg.IsError)
|
||||
{
|
||||
printOutputLine("Received create matchmaking room success");
|
||||
Room room = msg.Data.Room;
|
||||
currentRoom = room;
|
||||
|
||||
printOutputLine("RoomID: " + room.ID.ToString());
|
||||
currentState = states.IN_EMPTY_ROOM;
|
||||
}
|
||||
else
|
||||
{
|
||||
printOutputLine("Received create matchmaking room Error");
|
||||
Error error = msg.GetError();
|
||||
printOutputLine("Error: " + error.Message);
|
||||
printOutputLine("You can only create a matchmaking room for pools of mode Room. Make sure you have an appropriate pool setup on the Developer portal.\n");
|
||||
currentState = states.IDLE;
|
||||
}
|
||||
}
|
||||
|
||||
void requestCreateFilterRoom()
|
||||
{
|
||||
switch (currentState)
|
||||
{
|
||||
case states.NOT_INIT:
|
||||
printOutputLine("The app has not initialized properly and we don't know your userID.\n");
|
||||
break;
|
||||
|
||||
case states.IDLE:
|
||||
printOutputLine("Trying to create a matchmaking room");
|
||||
|
||||
// We're going to create a room that has the following values set:
|
||||
// game_type_name = "CTF"
|
||||
// map_name = "Really_Big_Map"
|
||||
//
|
||||
|
||||
Matchmaking.CustomQuery roomCustomQuery = new Matchmaking.CustomQuery();
|
||||
|
||||
roomCustomQuery.criteria = null;
|
||||
roomCustomQuery.data = new Dictionary<string, object>();
|
||||
|
||||
roomCustomQuery.data.Add("game_type_name", "CTF");
|
||||
roomCustomQuery.data.Add("map_name", "Really_Big_Map");
|
||||
|
||||
Matchmaking.CreateAndEnqueueRoom(Constants.FILTER_POOL, 8, true, roomCustomQuery).OnComplete(createRoomResponse);
|
||||
currentState = states.REQUEST_CREATE;
|
||||
break;
|
||||
|
||||
case states.REQUEST_FIND:
|
||||
printOutputLine("You have already made a request to find a room. Please wait for that request to complete.\n");
|
||||
break;
|
||||
case states.FINDING_ROOM:
|
||||
printOutputLine("You have already currently looking for a room. Please wait for the match to be made.\n");
|
||||
break;
|
||||
case states.REQUEST_JOIN:
|
||||
printOutputLine("We are currently trying to join a room. Please wait to see if we can join it.\n");
|
||||
break;
|
||||
case states.REQUEST_LEAVE:
|
||||
printOutputLine("We are currently trying to leave a room. Please wait to see if we can leave it.\n");
|
||||
break;
|
||||
case states.REQUEST_CREATE:
|
||||
printOutputLine("You have already requested a matchmaking room to be created. Please wait for the room to be made.\n");
|
||||
break;
|
||||
case states.IN_EMPTY_ROOM:
|
||||
printOutputLine("You have already in a matchmaking room. Please wait for an opponent to join.\n");
|
||||
break;
|
||||
case states.IN_FULL_ROOM:
|
||||
printOutputLine("You have already in a match.\n");
|
||||
break;
|
||||
default:
|
||||
printOutputLine("You have hit an unknown state.\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void requestFindRoom()
|
||||
{
|
||||
switch (currentState)
|
||||
{
|
||||
case states.NOT_INIT:
|
||||
printOutputLine("The app has not initialized properly and we don't know your userID.");
|
||||
break;
|
||||
|
||||
case states.IDLE:
|
||||
printOutputLine("\nTrying to find a matchmaking room\n");
|
||||
|
||||
Matchmaking.Enqueue(Constants.FILTER_POOL, null).OnComplete(searchingStarted);
|
||||
currentState = states.REQUEST_FIND;
|
||||
break;
|
||||
|
||||
case states.REQUEST_FIND:
|
||||
printOutputLine("You have already made a request to find a room. Please wait for that request to complete.");
|
||||
break;
|
||||
|
||||
case states.FINDING_ROOM:
|
||||
printOutputLine("You have already currently looking for a room. Please wait for the match to be made.");
|
||||
break;
|
||||
|
||||
case states.REQUEST_JOIN:
|
||||
printOutputLine("We are currently trying to join a room. Please wait to see if we can join it.");
|
||||
break;
|
||||
|
||||
case states.REQUEST_LEAVE:
|
||||
printOutputLine("We are currently trying to leave a room. Please wait to see if we can leave it.");
|
||||
break;
|
||||
|
||||
case states.REQUEST_CREATE:
|
||||
printOutputLine("You have already requested a matchmaking room to be created. Please wait for the room to be made.");
|
||||
break;
|
||||
|
||||
case states.IN_EMPTY_ROOM:
|
||||
printOutputLine("You have already in a matchmaking room. Please wait for an opponent to join.");
|
||||
break;
|
||||
|
||||
case states.IN_FULL_ROOM:
|
||||
printOutputLine("You have already in a match.");
|
||||
break;
|
||||
|
||||
default:
|
||||
printOutputLine("You have hit an unknown state.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void requestFindFilteredRoom()
|
||||
{
|
||||
switch (currentState)
|
||||
{
|
||||
case states.NOT_INIT:
|
||||
printOutputLine("The app has not initialized properly and we don't know your userID.");
|
||||
break;
|
||||
|
||||
case states.IDLE:
|
||||
printOutputLine("Trying to find a matchmaking room");
|
||||
|
||||
// Our search filter criterion
|
||||
//
|
||||
// We're filtering using two different queries setup on the developer portal
|
||||
//
|
||||
// map - query to filter by map. The query allows you to filter with up to two different maps using keys called 'map_1' and 'map_2'
|
||||
// game_type - query to filter by game type. The query allows you to filter with up to two different game types using keys called 'type_1' and 'type_2'
|
||||
//
|
||||
// In the example below we are filtering for matches that are of type CTF and on either Big_Map or Really_Big_Map.
|
||||
//
|
||||
|
||||
Matchmaking.CustomQuery roomCustomQuery = new Matchmaking.CustomQuery();
|
||||
Matchmaking.CustomQuery.Criterion[] queries = new Matchmaking.CustomQuery.Criterion[2];
|
||||
|
||||
queries[0].key = "map";
|
||||
queries[0].importance = MatchmakingCriterionImportance.Required;
|
||||
queries[0].parameters = new Dictionary<string, object>();
|
||||
queries[0].parameters.Add("map_param_1","Really_Big_Map");
|
||||
queries[0].parameters.Add("map_param_2", "Big_Map");
|
||||
|
||||
queries[1].key = "game_type";
|
||||
queries[1].importance = MatchmakingCriterionImportance.Required;
|
||||
queries[1].parameters = new Dictionary<string, object>();
|
||||
queries[1].parameters.Add("game_type_param", "CTF");
|
||||
|
||||
roomCustomQuery.criteria = queries;
|
||||
roomCustomQuery.data = null;
|
||||
|
||||
Matchmaking.Enqueue(Constants.FILTER_POOL, roomCustomQuery);
|
||||
currentState = states.REQUEST_FIND;
|
||||
break;
|
||||
|
||||
case states.REQUEST_FIND:
|
||||
printOutputLine("You have already made a request to find a room. Please wait for that request to complete.");
|
||||
break;
|
||||
|
||||
case states.FINDING_ROOM:
|
||||
printOutputLine("You have already currently looking for a room. Please wait for the match to be made.");
|
||||
break;
|
||||
|
||||
case states.REQUEST_JOIN:
|
||||
printOutputLine("We are currently trying to join a room. Please wait to see if we can join it.");
|
||||
break;
|
||||
|
||||
case states.REQUEST_LEAVE:
|
||||
printOutputLine("We are currently trying to leave a room. Please wait to see if we can leave it.");
|
||||
break;
|
||||
|
||||
case states.REQUEST_CREATE:
|
||||
printOutputLine("You have already requested a matchmaking room to be created. Please wait for the room to be made.");
|
||||
break;
|
||||
|
||||
case states.IN_EMPTY_ROOM:
|
||||
printOutputLine("You have already in a matchmaking room. Please wait for an opponent to join.");
|
||||
break;
|
||||
|
||||
case states.IN_FULL_ROOM:
|
||||
printOutputLine("You have already in a match.");
|
||||
break;
|
||||
|
||||
default:
|
||||
printOutputLine("You have hit an unknown state.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void foundMatch(Message<Room> msg)
|
||||
{
|
||||
if (!msg.IsError)
|
||||
{
|
||||
printOutputLine("Received find match success. We are now going to request to join the room.");
|
||||
Room room = msg.Data;
|
||||
|
||||
Rooms.Join(room.ID, true).OnComplete(joinRoomResponse);
|
||||
currentState = states.REQUEST_JOIN;
|
||||
}
|
||||
else
|
||||
{
|
||||
printOutputLine("Received find match error");
|
||||
Error error = msg.GetError();
|
||||
printOutputLine("Error: " + error.Message);
|
||||
currentState = states.IDLE;
|
||||
}
|
||||
}
|
||||
|
||||
void joinRoomResponse(Message<Room> msg)
|
||||
{
|
||||
if (!msg.IsError)
|
||||
{
|
||||
printOutputLine("Received join room success.");
|
||||
currentRoom = msg.Data;
|
||||
|
||||
currentState = states.IN_EMPTY_ROOM;
|
||||
|
||||
// Try to pull out remote user's ID if they have already joined
|
||||
if (currentRoom.UsersOptional != null)
|
||||
{
|
||||
foreach (User element in currentRoom.UsersOptional)
|
||||
{
|
||||
if (element.ID != localUser.ID)
|
||||
{
|
||||
remoteUser = element;
|
||||
currentState = states.IN_FULL_ROOM;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printOutputLine("Received join room error");
|
||||
printOutputLine("It's possible the room filled up before you could join it.");
|
||||
|
||||
Error error = msg.GetError();
|
||||
printOutputLine("Error: " + error.Message);
|
||||
currentState = states.IDLE;
|
||||
}
|
||||
}
|
||||
|
||||
void requestFindMatch()
|
||||
{
|
||||
switch (currentState)
|
||||
{
|
||||
case states.NOT_INIT:
|
||||
printOutputLine("The app has not initialized properly and we don't know your userID.");
|
||||
break;
|
||||
case states.IDLE:
|
||||
printOutputLine("Trying to find a matchmaking room");
|
||||
Matchmaking.Enqueue(Constants.BOUT_POOL, null).OnComplete(searchingStarted);
|
||||
currentState = states.REQUEST_FIND;
|
||||
break;
|
||||
case states.REQUEST_FIND:
|
||||
printOutputLine("You have already made a request to find a room. Please wait for that request to complete.");
|
||||
break;
|
||||
case states.FINDING_ROOM:
|
||||
printOutputLine("You have already currently looking for a room. Please wait for the match to be made.");
|
||||
break;
|
||||
case states.REQUEST_JOIN:
|
||||
printOutputLine("We are currently trying to join a room. Please wait to see if we can join it.");
|
||||
break;
|
||||
case states.REQUEST_LEAVE:
|
||||
printOutputLine("We are currently trying to leave a room. Please wait to see if we can leave it.");
|
||||
break;
|
||||
case states.REQUEST_CREATE:
|
||||
printOutputLine("You have already requested a matchmaking room to be created. Please wait for the room to be made.");
|
||||
break;
|
||||
case states.IN_EMPTY_ROOM:
|
||||
printOutputLine("You have already in a matchmaking room. Please wait for an opponent to join.");
|
||||
break;
|
||||
case states.IN_FULL_ROOM:
|
||||
printOutputLine("You have already in a match.");
|
||||
break;
|
||||
default:
|
||||
printOutputLine("You have hit an unknown state.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void searchingStarted(Message msg)
|
||||
{
|
||||
if (!msg.IsError)
|
||||
{
|
||||
printOutputLine("Searching for a match successfully started");
|
||||
currentState = states.REQUEST_FIND;
|
||||
}
|
||||
else
|
||||
{
|
||||
printOutputLine("Searching for a match error");
|
||||
|
||||
Error error = msg.GetError();
|
||||
printOutputLine("Error: " + error.Message);
|
||||
}
|
||||
}
|
||||
|
||||
void updateRoom(Message<Room> msg)
|
||||
{
|
||||
if (!msg.IsError)
|
||||
{
|
||||
printOutputLine("Received room update notification");
|
||||
Room room = msg.Data;
|
||||
|
||||
if (currentState == states.IN_EMPTY_ROOM)
|
||||
{
|
||||
// Check to see if this update is another user joining
|
||||
if (room.UsersOptional != null)
|
||||
{
|
||||
foreach (User element in room.UsersOptional)
|
||||
{
|
||||
if (element.ID != localUser.ID)
|
||||
{
|
||||
remoteUser = element;
|
||||
currentState = states.IN_FULL_ROOM;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check to see if this update is another user leaving
|
||||
if (room.UsersOptional != null && room.UsersOptional.Count == 1)
|
||||
{
|
||||
printOutputLine("User ID: " + remoteUser.ID.ToString() + "has left");
|
||||
remoteUser = null;
|
||||
currentState = states.IN_EMPTY_ROOM;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printOutputLine("Received room update error");
|
||||
|
||||
Error error = msg.GetError();
|
||||
printOutputLine("Error: " + error.Message);
|
||||
}
|
||||
}
|
||||
|
||||
void sendChat(string chatMessage)
|
||||
{
|
||||
switch (currentState)
|
||||
{
|
||||
case states.NOT_INIT:
|
||||
printOutputLine("The app has not initialized properly and we don't know your userID.");
|
||||
break;
|
||||
|
||||
case states.IDLE:
|
||||
case states.REQUEST_FIND:
|
||||
case states.FINDING_ROOM:
|
||||
case states.REQUEST_JOIN:
|
||||
case states.REQUEST_CREATE:
|
||||
case states.REQUEST_LEAVE:
|
||||
case states.IN_EMPTY_ROOM:
|
||||
printOutputLine("You need to be in a room with another player to send a message.");
|
||||
break;
|
||||
|
||||
case states.IN_FULL_ROOM:
|
||||
{
|
||||
chatPacket newMessage = new chatPacket();
|
||||
|
||||
// Create a packet to send with the packet ID and string payload
|
||||
lastPacketID++;
|
||||
newMessage.packetID = lastPacketID;
|
||||
newMessage.textString = chatMessage;
|
||||
|
||||
Oculus.Platform.Net.SendPacket(remoteUser.ID, newMessage.Serialize(), SendPolicy.Reliable);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
printOutputLine("You have hit an unknown state.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void processNetPackets()
|
||||
{
|
||||
Packet incomingPacket = Net.ReadPacket();
|
||||
|
||||
while (incomingPacket != null)
|
||||
{
|
||||
byte[] rawBits = new byte[incomingPacket.Size];
|
||||
incomingPacket.ReadBytes(rawBits);
|
||||
|
||||
chatPacket newMessage = chatPacket.Deserialize(rawBits);
|
||||
|
||||
printOutputLine("Chat Text: " + newMessage.textString.ToString());
|
||||
printOutputLine("Received Packet from UserID: " + incomingPacket.SenderID.ToString());
|
||||
printOutputLine("Received Packet ID: " + newMessage.packetID.ToString());
|
||||
|
||||
// Look to see if there's another packet waiting
|
||||
incomingPacket = Net.ReadPacket();
|
||||
}
|
||||
}
|
||||
|
||||
void requestLeaveRoom()
|
||||
{
|
||||
switch (currentState)
|
||||
{
|
||||
case states.NOT_INIT:
|
||||
printOutputLine("The app has not initialized properly and we don't know your userID.");
|
||||
break;
|
||||
|
||||
case states.IDLE:
|
||||
case states.REQUEST_FIND:
|
||||
case states.FINDING_ROOM:
|
||||
case states.REQUEST_JOIN:
|
||||
case states.REQUEST_CREATE:
|
||||
printOutputLine("You are currently not in a room to leave.");
|
||||
break;
|
||||
|
||||
case states.REQUEST_LEAVE:
|
||||
printOutputLine("We are currently trying to leave a room. Please wait to see if we can leave it.");
|
||||
break;
|
||||
|
||||
case states.IN_EMPTY_ROOM:
|
||||
case states.IN_FULL_ROOM:
|
||||
printOutputLine("Trying to leave room.");
|
||||
Rooms.Leave(currentRoom.ID).OnComplete(leaveRoomResponse);
|
||||
break;
|
||||
|
||||
default:
|
||||
printOutputLine("You have hit an unknown state.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void leaveRoomResponse(Message<Room> msg)
|
||||
{
|
||||
if (!msg.IsError)
|
||||
{
|
||||
printOutputLine("We were able to leave the room");
|
||||
currentRoom = null;
|
||||
remoteUser = null;
|
||||
currentState = states.IDLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
printOutputLine("Leave room error");
|
||||
|
||||
Error error = msg.GetError();
|
||||
printOutputLine("Error: " + error.Message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void requestStartRatedMatch()
|
||||
{
|
||||
switch (currentState)
|
||||
{
|
||||
case states.NOT_INIT:
|
||||
printOutputLine("The app has not initialized properly and we don't know your userID.");
|
||||
break;
|
||||
|
||||
case states.IDLE:
|
||||
case states.REQUEST_FIND:
|
||||
case states.FINDING_ROOM:
|
||||
case states.REQUEST_JOIN:
|
||||
case states.REQUEST_CREATE:
|
||||
case states.REQUEST_LEAVE:
|
||||
case states.IN_EMPTY_ROOM:
|
||||
printOutputLine("You need to be in a room with another player to start a rated match.");
|
||||
break;
|
||||
|
||||
case states.IN_FULL_ROOM:
|
||||
printOutputLine("Trying to start a rated match. This call should be made once a rated match begins so we will be able to submit results after the game is done.");
|
||||
|
||||
Matchmaking.StartMatch(currentRoom.ID).OnComplete(startRatedMatchResponse);
|
||||
break;
|
||||
|
||||
default:
|
||||
printOutputLine("You have hit an unknown state.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void startRatedMatchResponse(Message msg)
|
||||
{
|
||||
if(!msg.IsError)
|
||||
{
|
||||
printOutputLine("Started a rated match");
|
||||
ratedMatchStarted = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Error error = msg.GetError();
|
||||
printOutputLine("Received starting rated match failure: " + error.Message);
|
||||
printOutputLine("Your matchmaking pool needs to have a skill pool associated with it to play rated matches");
|
||||
}
|
||||
}
|
||||
|
||||
void requestReportResults()
|
||||
{
|
||||
switch (currentState)
|
||||
{
|
||||
case states.NOT_INIT:
|
||||
printOutputLine("The app has not initialized properly and we don't know your userID.");
|
||||
break;
|
||||
|
||||
case states.IDLE:
|
||||
case states.REQUEST_FIND:
|
||||
case states.FINDING_ROOM:
|
||||
case states.REQUEST_JOIN:
|
||||
case states.REQUEST_CREATE:
|
||||
case states.REQUEST_LEAVE:
|
||||
printOutputLine("You need to be in a room with another player to report results on a rated match.");
|
||||
break;
|
||||
|
||||
case states.IN_EMPTY_ROOM:
|
||||
case states.IN_FULL_ROOM:
|
||||
if (ratedMatchStarted)
|
||||
{
|
||||
printOutputLine("Submitting rated match results.");
|
||||
|
||||
Dictionary <string, int> results = new Dictionary<string, int>();
|
||||
results.Add(localUser.ID.ToString(), 1);
|
||||
results.Add(remoteUser.ID.ToString(), 2);
|
||||
|
||||
Matchmaking.ReportResultsInsecure(currentRoom.ID, results).OnComplete(reportResultsResponse);
|
||||
}
|
||||
else
|
||||
{
|
||||
printOutputLine("You can't report results unless you've already started a rated match");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
printOutputLine("You have hit an unknown state.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void reportResultsResponse(Message msg)
|
||||
{
|
||||
if (!msg.IsError)
|
||||
{
|
||||
printOutputLine("Rated match results reported. Now attempting to leave room.");
|
||||
ratedMatchStarted = false;
|
||||
requestLeaveRoom();
|
||||
}
|
||||
else
|
||||
{
|
||||
Error error = msg.GetError();
|
||||
printOutputLine("Received reporting rated match failure: " + error.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Oculus/Platform/Samples/NetChat/DataEntry.cs.meta
Normal file
11
Assets/Oculus/Platform/Samples/NetChat/DataEntry.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bfbb4b78fb9572d4da744c39224c6f1d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
961
Assets/Oculus/Platform/Samples/NetChat/MainScene.unity
Normal file
961
Assets/Oculus/Platform/Samples/NetChat/MainScene.unity
Normal file
@@ -0,0 +1,961 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!29 &1
|
||||
OcclusionCullingSettings:
|
||||
m_ObjectHideFlags: 0
|
||||
serializedVersion: 2
|
||||
m_OcclusionBakeSettings:
|
||||
smallestOccluder: 5
|
||||
smallestHole: 0.25
|
||||
backfaceThreshold: 100
|
||||
m_SceneGUID: 00000000000000000000000000000000
|
||||
m_OcclusionCullingData: {fileID: 0}
|
||||
--- !u!104 &2
|
||||
RenderSettings:
|
||||
m_ObjectHideFlags: 0
|
||||
serializedVersion: 9
|
||||
m_Fog: 0
|
||||
m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
|
||||
m_FogMode: 3
|
||||
m_FogDensity: 0.01
|
||||
m_LinearFogStart: 0
|
||||
m_LinearFogEnd: 300
|
||||
m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
|
||||
m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
|
||||
m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
|
||||
m_AmbientIntensity: 1
|
||||
m_AmbientMode: 0
|
||||
m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
|
||||
m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_HaloStrength: 0.5
|
||||
m_FlareStrength: 1
|
||||
m_FlareFadeSpeed: 3
|
||||
m_HaloTexture: {fileID: 0}
|
||||
m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
|
||||
m_DefaultReflectionMode: 0
|
||||
m_DefaultReflectionResolution: 128
|
||||
m_ReflectionBounces: 1
|
||||
m_ReflectionIntensity: 1
|
||||
m_CustomReflection: {fileID: 0}
|
||||
m_Sun: {fileID: 0}
|
||||
m_IndirectSpecularColor: {r: 0.44657874, g: 0.49641275, b: 0.57481706, a: 1}
|
||||
m_UseRadianceAmbientProbe: 0
|
||||
--- !u!157 &4
|
||||
LightmapSettings:
|
||||
m_ObjectHideFlags: 0
|
||||
serializedVersion: 11
|
||||
m_GIWorkflowMode: 0
|
||||
m_GISettings:
|
||||
serializedVersion: 2
|
||||
m_BounceScale: 1
|
||||
m_IndirectOutputScale: 1
|
||||
m_AlbedoBoost: 1
|
||||
m_EnvironmentLightingMode: 0
|
||||
m_EnableBakedLightmaps: 1
|
||||
m_EnableRealtimeLightmaps: 1
|
||||
m_LightmapEditorSettings:
|
||||
serializedVersion: 12
|
||||
m_Resolution: 2
|
||||
m_BakeResolution: 40
|
||||
m_AtlasSize: 1024
|
||||
m_AO: 0
|
||||
m_AOMaxDistance: 1
|
||||
m_CompAOExponent: 0
|
||||
m_CompAOExponentDirect: 0
|
||||
m_ExtractAmbientOcclusion: 0
|
||||
m_Padding: 2
|
||||
m_LightmapParameters: {fileID: 0}
|
||||
m_LightmapsBakeMode: 1
|
||||
m_TextureCompression: 1
|
||||
m_FinalGather: 0
|
||||
m_FinalGatherFiltering: 1
|
||||
m_FinalGatherRayCount: 1024
|
||||
m_ReflectionCompression: 2
|
||||
m_MixedBakeMode: 1
|
||||
m_BakeBackend: 0
|
||||
m_PVRSampling: 1
|
||||
m_PVRDirectSampleCount: 32
|
||||
m_PVRSampleCount: 500
|
||||
m_PVRBounces: 2
|
||||
m_PVREnvironmentSampleCount: 500
|
||||
m_PVREnvironmentReferencePointCount: 2048
|
||||
m_PVRFilteringMode: 0
|
||||
m_PVRDenoiserTypeDirect: 0
|
||||
m_PVRDenoiserTypeIndirect: 0
|
||||
m_PVRDenoiserTypeAO: 0
|
||||
m_PVRFilterTypeDirect: 0
|
||||
m_PVRFilterTypeIndirect: 0
|
||||
m_PVRFilterTypeAO: 0
|
||||
m_PVREnvironmentMIS: 0
|
||||
m_PVRCulling: 1
|
||||
m_PVRFilteringGaussRadiusDirect: 1
|
||||
m_PVRFilteringGaussRadiusIndirect: 5
|
||||
m_PVRFilteringGaussRadiusAO: 2
|
||||
m_PVRFilteringAtrousPositionSigmaDirect: 0.5
|
||||
m_PVRFilteringAtrousPositionSigmaIndirect: 2
|
||||
m_PVRFilteringAtrousPositionSigmaAO: 1
|
||||
m_ExportTrainingData: 0
|
||||
m_TrainingDataDestination: TrainingData
|
||||
m_LightProbeSampleCountMultiplier: 4
|
||||
m_LightingDataAsset: {fileID: 0}
|
||||
m_UseShadowmask: 0
|
||||
--- !u!196 &5
|
||||
NavMeshSettings:
|
||||
serializedVersion: 2
|
||||
m_ObjectHideFlags: 0
|
||||
m_BuildSettings:
|
||||
serializedVersion: 2
|
||||
agentTypeID: 0
|
||||
agentRadius: 0.5
|
||||
agentHeight: 2
|
||||
agentSlope: 45
|
||||
agentClimb: 0.4
|
||||
ledgeDropHeight: 0
|
||||
maxJumpAcrossDistance: 0
|
||||
minRegionArea: 2
|
||||
manualCellSize: 0
|
||||
cellSize: 0.16666667
|
||||
manualTileSize: 0
|
||||
tileSize: 256
|
||||
accuratePlacement: 0
|
||||
debug:
|
||||
m_Flags: 0
|
||||
m_NavMeshData: {fileID: 0}
|
||||
--- !u!1 &71451189
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 71451191}
|
||||
- component: {fileID: 71451190}
|
||||
m_Layer: 0
|
||||
m_Name: Directional Light
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!108 &71451190
|
||||
Light:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 71451189}
|
||||
m_Enabled: 1
|
||||
serializedVersion: 10
|
||||
m_Type: 1
|
||||
m_Shape: 0
|
||||
m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1}
|
||||
m_Intensity: 1
|
||||
m_Range: 10
|
||||
m_SpotAngle: 30
|
||||
m_InnerSpotAngle: 21.802082
|
||||
m_CookieSize: 10
|
||||
m_Shadows:
|
||||
m_Type: 2
|
||||
m_Resolution: -1
|
||||
m_CustomResolution: -1
|
||||
m_Strength: 1
|
||||
m_Bias: 0.05
|
||||
m_NormalBias: 0.4
|
||||
m_NearPlane: 0.2
|
||||
m_CullingMatrixOverride:
|
||||
e00: 1
|
||||
e01: 0
|
||||
e02: 0
|
||||
e03: 0
|
||||
e10: 0
|
||||
e11: 1
|
||||
e12: 0
|
||||
e13: 0
|
||||
e20: 0
|
||||
e21: 0
|
||||
e22: 1
|
||||
e23: 0
|
||||
e30: 0
|
||||
e31: 0
|
||||
e32: 0
|
||||
e33: 1
|
||||
m_UseCullingMatrixOverride: 0
|
||||
m_Cookie: {fileID: 0}
|
||||
m_DrawHalo: 0
|
||||
m_Flare: {fileID: 0}
|
||||
m_RenderMode: 0
|
||||
m_CullingMask:
|
||||
serializedVersion: 2
|
||||
m_Bits: 4294967295
|
||||
m_RenderingLayerMask: 1
|
||||
m_Lightmapping: 4
|
||||
m_LightShadowCasterMode: 0
|
||||
m_AreaSize: {x: 1, y: 1}
|
||||
m_BounceIntensity: 1
|
||||
m_ColorTemperature: 6570
|
||||
m_UseColorTemperature: 0
|
||||
m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_UseBoundingSphereOverride: 0
|
||||
m_ShadowRadius: 0
|
||||
m_ShadowAngle: 0
|
||||
--- !u!4 &71451191
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 71451189}
|
||||
m_LocalRotation: {x: 0.40821794, y: -0.23456973, z: 0.109381676, w: 0.87542605}
|
||||
m_LocalPosition: {x: 0, y: 3, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 1
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1 &226720192
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 226720193}
|
||||
- component: {fileID: 226720196}
|
||||
- component: {fileID: 226720195}
|
||||
- component: {fileID: 226720194}
|
||||
m_Layer: 5
|
||||
m_Name: Canvas
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &226720193
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 226720192}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 0, y: 0, z: 0}
|
||||
m_Children:
|
||||
- {fileID: 1737575280}
|
||||
- {fileID: 1536036709}
|
||||
- {fileID: 1288670679}
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 2
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0, y: 0}
|
||||
--- !u!114 &226720194
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 226720192}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_IgnoreReversedGraphics: 1
|
||||
m_BlockingObjects: 0
|
||||
m_BlockingMask:
|
||||
serializedVersion: 2
|
||||
m_Bits: 4294967295
|
||||
--- !u!114 &226720195
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 226720192}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_UiScaleMode: 0
|
||||
m_ReferencePixelsPerUnit: 100
|
||||
m_ScaleFactor: 1
|
||||
m_ReferenceResolution: {x: 800, y: 600}
|
||||
m_ScreenMatchMode: 0
|
||||
m_MatchWidthOrHeight: 0
|
||||
m_PhysicalUnit: 3
|
||||
m_FallbackScreenDPI: 96
|
||||
m_DefaultSpriteDPI: 96
|
||||
m_DynamicPixelsPerUnit: 1
|
||||
--- !u!223 &226720196
|
||||
Canvas:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 226720192}
|
||||
m_Enabled: 1
|
||||
serializedVersion: 3
|
||||
m_RenderMode: 0
|
||||
m_Camera: {fileID: 0}
|
||||
m_PlaneDistance: 100
|
||||
m_PixelPerfect: 0
|
||||
m_ReceivesEvents: 1
|
||||
m_OverrideSorting: 0
|
||||
m_OverridePixelPerfect: 0
|
||||
m_SortingBucketNormalizedSize: 0
|
||||
m_AdditionalShaderChannelsFlag: 25
|
||||
m_SortingLayerID: 0
|
||||
m_SortingOrder: 0
|
||||
m_TargetDisplay: 0
|
||||
--- !u!1 &457622391
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 457622396}
|
||||
- component: {fileID: 457622395}
|
||||
- component: {fileID: 457622393}
|
||||
- component: {fileID: 457622392}
|
||||
m_Layer: 0
|
||||
m_Name: Main Camera
|
||||
m_TagString: MainCamera
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!81 &457622392
|
||||
AudioListener:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 457622391}
|
||||
m_Enabled: 1
|
||||
--- !u!124 &457622393
|
||||
Behaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 457622391}
|
||||
m_Enabled: 1
|
||||
--- !u!20 &457622395
|
||||
Camera:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 457622391}
|
||||
m_Enabled: 1
|
||||
serializedVersion: 2
|
||||
m_ClearFlags: 1
|
||||
m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0.019607844}
|
||||
m_projectionMatrixMode: 1
|
||||
m_GateFitMode: 2
|
||||
m_FOVAxisMode: 0
|
||||
m_SensorSize: {x: 36, y: 24}
|
||||
m_LensShift: {x: 0, y: 0}
|
||||
m_FocalLength: 50
|
||||
m_NormalizedViewPortRect:
|
||||
serializedVersion: 2
|
||||
x: 0
|
||||
y: 0
|
||||
width: 1
|
||||
height: 1
|
||||
near clip plane: 0.3
|
||||
far clip plane: 1000
|
||||
field of view: 60
|
||||
orthographic: 0
|
||||
orthographic size: 5
|
||||
m_Depth: -1
|
||||
m_CullingMask:
|
||||
serializedVersion: 2
|
||||
m_Bits: 4294967295
|
||||
m_RenderingPath: -1
|
||||
m_TargetTexture: {fileID: 0}
|
||||
m_TargetDisplay: 0
|
||||
m_TargetEye: 3
|
||||
m_HDR: 0
|
||||
m_AllowMSAA: 1
|
||||
m_AllowDynamicResolution: 0
|
||||
m_ForceIntoRT: 0
|
||||
m_OcclusionCulling: 1
|
||||
m_StereoConvergence: 10
|
||||
m_StereoSeparation: 0.022
|
||||
--- !u!4 &457622396
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 457622391}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 1, z: -10}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1 &761396705
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 761396708}
|
||||
- component: {fileID: 761396707}
|
||||
- component: {fileID: 761396706}
|
||||
m_Layer: 5
|
||||
m_Name: Placeholder
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!114 &761396706
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 761396705}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 0.5}
|
||||
m_RaycastTarget: 1
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_FontData:
|
||||
m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
|
||||
m_FontSize: 14
|
||||
m_FontStyle: 2
|
||||
m_BestFit: 0
|
||||
m_MinSize: 10
|
||||
m_MaxSize: 40
|
||||
m_Alignment: 0
|
||||
m_AlignByGeometry: 0
|
||||
m_RichText: 1
|
||||
m_HorizontalOverflow: 0
|
||||
m_VerticalOverflow: 0
|
||||
m_LineSpacing: 1
|
||||
m_Text: Enter command
|
||||
--- !u!222 &761396707
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 761396705}
|
||||
m_CullTransparentMesh: 0
|
||||
--- !u!224 &761396708
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 761396705}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 1737575280}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 1, y: 1}
|
||||
m_AnchoredPosition: {x: 0, y: -0.5}
|
||||
m_SizeDelta: {x: -20, y: -13}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!1 &1288670678
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1288670679}
|
||||
- component: {fileID: 1288670681}
|
||||
- component: {fileID: 1288670680}
|
||||
m_Layer: 5
|
||||
m_Name: Commands
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &1288670679
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1288670678}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 226720193}
|
||||
m_RootOrder: 2
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 50, y: 150}
|
||||
m_SizeDelta: {x: 700, y: 450}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &1288670680
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1288670678}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_FontData:
|
||||
m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
|
||||
m_FontSize: 14
|
||||
m_FontStyle: 0
|
||||
m_BestFit: 0
|
||||
m_MinSize: 10
|
||||
m_MaxSize: 40
|
||||
m_Alignment: 0
|
||||
m_AlignByGeometry: 0
|
||||
m_RichText: 1
|
||||
m_HorizontalOverflow: 0
|
||||
m_VerticalOverflow: 0
|
||||
m_LineSpacing: 1
|
||||
m_Text: "List of Commands\r\n----------------\r-----\nc - create chat room for
|
||||
matchmaking (Room Mode)\nd - create filtered chat room for matchmaking (Room
|
||||
Mode)\nf - find chat room for matchmaking (Bout Mode)\ng - find chat room for
|
||||
matchmaking w/o filters (Room Mode)\ni - find chat room for matchmaking using
|
||||
filters (Room Mode)\nl - Leave current room\n1 - Start a rated match\n2- Report
|
||||
match results\ns!<chat message> - Send chat message\n"
|
||||
--- !u!222 &1288670681
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1288670678}
|
||||
m_CullTransparentMesh: 0
|
||||
--- !u!1 &1536036708
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1536036709}
|
||||
- component: {fileID: 1536036711}
|
||||
- component: {fileID: 1536036710}
|
||||
m_Layer: 5
|
||||
m_Name: Output
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &1536036709
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1536036708}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 226720193}
|
||||
m_RootOrder: 1
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 0, y: -300}
|
||||
m_SizeDelta: {x: 600, y: 300}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &1536036710
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1536036708}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_FontData:
|
||||
m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
|
||||
m_FontSize: 14
|
||||
m_FontStyle: 0
|
||||
m_BestFit: 0
|
||||
m_MinSize: 10
|
||||
m_MaxSize: 40
|
||||
m_Alignment: 0
|
||||
m_AlignByGeometry: 0
|
||||
m_RichText: 1
|
||||
m_HorizontalOverflow: 0
|
||||
m_VerticalOverflow: 0
|
||||
m_LineSpacing: 1
|
||||
m_Text: '>
|
||||
|
||||
'
|
||||
--- !u!222 &1536036711
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1536036708}
|
||||
m_CullTransparentMesh: 0
|
||||
--- !u!1 &1737575279
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1737575280}
|
||||
- component: {fileID: 1737575284}
|
||||
- component: {fileID: 1737575283}
|
||||
- component: {fileID: 1737575282}
|
||||
- component: {fileID: 1737575281}
|
||||
m_Layer: 5
|
||||
m_Name: InputField
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &1737575280
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1737575279}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children:
|
||||
- {fileID: 761396708}
|
||||
- {fileID: 1773483966}
|
||||
m_Father: {fileID: 226720193}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 0, y: -100}
|
||||
m_SizeDelta: {x: 400, y: 30}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &1737575281
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1737575279}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: bfbb4b78fb9572d4da744c39224c6f1d, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
dataOutput: {fileID: 1536036710}
|
||||
--- !u!114 &1737575282
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1737575279}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: d199490a83bb2b844b9695cbf13b01ef, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Navigation:
|
||||
m_Mode: 3
|
||||
m_SelectOnUp: {fileID: 0}
|
||||
m_SelectOnDown: {fileID: 0}
|
||||
m_SelectOnLeft: {fileID: 0}
|
||||
m_SelectOnRight: {fileID: 0}
|
||||
m_Transition: 1
|
||||
m_Colors:
|
||||
m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
|
||||
m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
|
||||
m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
|
||||
m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
|
||||
m_ColorMultiplier: 1
|
||||
m_FadeDuration: 0.1
|
||||
m_SpriteState:
|
||||
m_HighlightedSprite: {fileID: 0}
|
||||
m_PressedSprite: {fileID: 0}
|
||||
m_SelectedSprite: {fileID: 0}
|
||||
m_DisabledSprite: {fileID: 0}
|
||||
m_AnimationTriggers:
|
||||
m_NormalTrigger: Normal
|
||||
m_HighlightedTrigger: Highlighted
|
||||
m_PressedTrigger: Pressed
|
||||
m_SelectedTrigger: Highlighted
|
||||
m_DisabledTrigger: Disabled
|
||||
m_Interactable: 1
|
||||
m_TargetGraphic: {fileID: 1737575283}
|
||||
m_TextComponent: {fileID: 1773483967}
|
||||
m_Placeholder: {fileID: 761396706}
|
||||
m_ContentType: 0
|
||||
m_InputType: 0
|
||||
m_AsteriskChar: 42
|
||||
m_KeyboardType: 0
|
||||
m_LineType: 0
|
||||
m_HideMobileInput: 0
|
||||
m_CharacterValidation: 0
|
||||
m_CharacterLimit: 0
|
||||
m_OnEndEdit:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_OnValueChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_CaretColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
|
||||
m_CustomCaretColor: 0
|
||||
m_SelectionColor: {r: 0.65882355, g: 0.80784315, b: 1, a: 0.7529412}
|
||||
m_Text:
|
||||
m_CaretBlinkRate: 0.85
|
||||
m_CaretWidth: 1
|
||||
m_ReadOnly: 0
|
||||
--- !u!114 &1737575283
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1737575279}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: 10911, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_Type: 1
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
m_FillMethod: 4
|
||||
m_FillAmount: 1
|
||||
m_FillClockwise: 1
|
||||
m_FillOrigin: 0
|
||||
m_UseSpriteMesh: 0
|
||||
m_PixelsPerUnitMultiplier: 1
|
||||
--- !u!222 &1737575284
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1737575279}
|
||||
m_CullTransparentMesh: 0
|
||||
--- !u!1 &1773483965
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1773483966}
|
||||
- component: {fileID: 1773483968}
|
||||
- component: {fileID: 1773483967}
|
||||
m_Layer: 5
|
||||
m_Name: Text
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &1773483966
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1773483965}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 1737575280}
|
||||
m_RootOrder: 1
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 1, y: 1}
|
||||
m_AnchoredPosition: {x: 0, y: -0.5}
|
||||
m_SizeDelta: {x: -20, y: -13}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &1773483967
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1773483965}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_FontData:
|
||||
m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
|
||||
m_FontSize: 14
|
||||
m_FontStyle: 0
|
||||
m_BestFit: 0
|
||||
m_MinSize: 10
|
||||
m_MaxSize: 40
|
||||
m_Alignment: 0
|
||||
m_AlignByGeometry: 0
|
||||
m_RichText: 0
|
||||
m_HorizontalOverflow: 1
|
||||
m_VerticalOverflow: 0
|
||||
m_LineSpacing: 1
|
||||
m_Text:
|
||||
--- !u!222 &1773483968
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1773483965}
|
||||
m_CullTransparentMesh: 0
|
||||
--- !u!1 &2040691524
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 2040691528}
|
||||
- component: {fileID: 2040691527}
|
||||
- component: {fileID: 2040691526}
|
||||
- component: {fileID: 2040691525}
|
||||
m_Layer: 0
|
||||
m_Name: EventSystem
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!114 &2040691525
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2040691524}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 2d49b7c1bcd2e07499844da127be038d, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_ForceModuleActive: 0
|
||||
--- !u!114 &2040691526
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2040691524}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_HorizontalAxis: Horizontal
|
||||
m_VerticalAxis: Vertical
|
||||
m_SubmitButton: Submit
|
||||
m_CancelButton: Cancel
|
||||
m_InputActionsPerSecond: 10
|
||||
m_RepeatDelay: 0.5
|
||||
m_ForceModuleActive: 0
|
||||
--- !u!114 &2040691527
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2040691524}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_FirstSelected: {fileID: 0}
|
||||
m_sendNavigationEvents: 1
|
||||
m_DragThreshold: 5
|
||||
--- !u!4 &2040691528
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2040691524}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 3
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4a5c060329791374cba1196f7ac36ef5
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Oculus/Platform/Samples/SimplePlatformSample.meta
Normal file
8
Assets/Oculus/Platform/Samples/SimplePlatformSample.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d4456c9adf88d234185bd5299a24db9f
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
641
Assets/Oculus/Platform/Samples/SimplePlatformSample/DataEntry.cs
Normal file
641
Assets/Oculus/Platform/Samples/SimplePlatformSample/DataEntry.cs
Normal file
@@ -0,0 +1,641 @@
|
||||
namespace Oculus.Platform.Samples.SimplePlatformSample
|
||||
{
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Oculus.Platform;
|
||||
using Oculus.Platform.Models;
|
||||
|
||||
public class DataEntry : MonoBehaviour
|
||||
{
|
||||
|
||||
public Text dataOutput;
|
||||
|
||||
void Start()
|
||||
{
|
||||
Core.Initialize();
|
||||
checkEntitlement();
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void Update()
|
||||
{
|
||||
string currentText = GetComponent<InputField>().text;
|
||||
|
||||
if (Input.GetKey(KeyCode.Return))
|
||||
{
|
||||
if (currentText != "")
|
||||
{
|
||||
SubmitCommand(currentText);
|
||||
}
|
||||
|
||||
GetComponent<InputField>().text = "";
|
||||
}
|
||||
|
||||
// Handle all messages being returned
|
||||
Request.RunCallbacks();
|
||||
}
|
||||
|
||||
private void SubmitCommand(string command)
|
||||
{
|
||||
string[] commandParams = command.Split(' ');
|
||||
|
||||
if (commandParams.Length > 0)
|
||||
{
|
||||
switch (commandParams[0])
|
||||
{
|
||||
case "p":
|
||||
if (commandParams.Length > 2)
|
||||
{
|
||||
createAndJoinPrivateRoom(commandParams[1], commandParams[2]);
|
||||
}
|
||||
break;
|
||||
case "c":
|
||||
getCurrentRoom();
|
||||
break;
|
||||
case "g":
|
||||
if (commandParams.Length > 1)
|
||||
{
|
||||
getRoom(commandParams[1]);
|
||||
}
|
||||
break;
|
||||
case "j":
|
||||
if (commandParams.Length > 1)
|
||||
{
|
||||
joinRoom(commandParams[1]);
|
||||
}
|
||||
break;
|
||||
case "l":
|
||||
if (commandParams.Length > 1)
|
||||
{
|
||||
leaveRoom(commandParams[1]);
|
||||
}
|
||||
break;
|
||||
case "k":
|
||||
if (commandParams.Length > 2)
|
||||
{
|
||||
kickUser(commandParams[1], commandParams[2]);
|
||||
}
|
||||
break;
|
||||
case "m":
|
||||
getLoggedInUser();
|
||||
break;
|
||||
case "u":
|
||||
if (commandParams.Length > 1)
|
||||
{
|
||||
getUser(commandParams[1]);
|
||||
}
|
||||
break;
|
||||
case "d":
|
||||
getLoggedInFriends();
|
||||
break;
|
||||
case "i":
|
||||
getInvitableUsers();
|
||||
break;
|
||||
case "o":
|
||||
if (commandParams.Length > 2)
|
||||
{
|
||||
inviteUser(commandParams[1], commandParams[2]);
|
||||
}
|
||||
break;
|
||||
case "s":
|
||||
if (commandParams.Length > 2)
|
||||
{
|
||||
setRoomDescription(commandParams[1], commandParams[2]);
|
||||
}
|
||||
break;
|
||||
case "w":
|
||||
if (commandParams.Length > 3)
|
||||
{
|
||||
updateRoomDataStore(commandParams[1], commandParams[2], commandParams[3]);
|
||||
}
|
||||
break;
|
||||
case "n":
|
||||
getUserNonce();
|
||||
break;
|
||||
case "e":
|
||||
checkEntitlement();
|
||||
break;
|
||||
case "a":
|
||||
if (commandParams.Length > 1)
|
||||
{
|
||||
getAchievementDefinition(commandParams[1]);
|
||||
}
|
||||
break;
|
||||
case "b":
|
||||
if (commandParams.Length > 1)
|
||||
{
|
||||
getAchievementProgress(commandParams[1]);
|
||||
}
|
||||
break;
|
||||
case "3":
|
||||
if (commandParams.Length > 1)
|
||||
{
|
||||
unlockAchievement(commandParams[1]);
|
||||
}
|
||||
break;
|
||||
case "4":
|
||||
if (commandParams.Length > 2)
|
||||
{
|
||||
addCountAchievement(commandParams[1], commandParams[2]);
|
||||
}
|
||||
break;
|
||||
case "5":
|
||||
if (commandParams.Length > 2)
|
||||
{
|
||||
addFieldsAchievement(commandParams[1], commandParams[2]);
|
||||
}
|
||||
break;
|
||||
case "1":
|
||||
if (commandParams.Length > 2)
|
||||
{
|
||||
writeLeaderboardEntry(commandParams[1], commandParams[2]);
|
||||
}
|
||||
break;
|
||||
case "2":
|
||||
if (commandParams.Length > 1)
|
||||
{
|
||||
getLeaderboardEntries(commandParams[1]);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
printOutputLine("Invalid Command");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void getLeaderboardEntries(string leaderboardName)
|
||||
{
|
||||
Leaderboards.GetEntries(leaderboardName, 10, LeaderboardFilterType.None, LeaderboardStartAt.Top).OnComplete(leaderboardGetCallback);
|
||||
}
|
||||
|
||||
void writeLeaderboardEntry(string leaderboardName, string value)
|
||||
{
|
||||
byte[] extraData = new byte[] { 0x54, 0x65, 0x73, 0x74 };
|
||||
|
||||
Leaderboards.WriteEntry(leaderboardName, Convert.ToInt32(value), extraData, false).OnComplete(leaderboardWriteCallback);
|
||||
}
|
||||
|
||||
void addFieldsAchievement(string achievementName, string fields)
|
||||
{
|
||||
Achievements.AddFields(achievementName, fields).OnComplete(achievementFieldsCallback);
|
||||
}
|
||||
|
||||
void addCountAchievement(string achievementName, string count)
|
||||
{
|
||||
Achievements.AddCount(achievementName, Convert.ToUInt64(count)).OnComplete(achievementCountCallback);
|
||||
}
|
||||
|
||||
void unlockAchievement(string achievementName)
|
||||
{
|
||||
Achievements.Unlock(achievementName).OnComplete(achievementUnlockCallback);
|
||||
}
|
||||
|
||||
void getAchievementProgress(string achievementName)
|
||||
{
|
||||
string[] Names = new string[1];
|
||||
Names[0] = achievementName;
|
||||
|
||||
Achievements.GetProgressByName(Names).OnComplete(achievementProgressCallback);
|
||||
}
|
||||
|
||||
void getAchievementDefinition(string achievementName)
|
||||
{
|
||||
string[] Names = new string[1];
|
||||
Names[0] = achievementName;
|
||||
|
||||
Achievements.GetDefinitionsByName(Names).OnComplete(achievementDefinitionCallback);
|
||||
}
|
||||
|
||||
void checkEntitlement()
|
||||
{
|
||||
Entitlements.IsUserEntitledToApplication().OnComplete(getEntitlementCallback);
|
||||
}
|
||||
|
||||
void getUserNonce()
|
||||
{
|
||||
printOutputLine("Trying to get user nonce");
|
||||
|
||||
Users.GetUserProof().OnComplete(userProofCallback);
|
||||
}
|
||||
|
||||
void createAndJoinPrivateRoom(string joinPolicy, string maxUsers)
|
||||
{
|
||||
printOutputLine("Trying to create and join private room");
|
||||
Rooms.CreateAndJoinPrivate((RoomJoinPolicy)Convert.ToUInt32(joinPolicy), Convert.ToUInt32(maxUsers)).OnComplete(createAndJoinPrivateRoomCallback);
|
||||
}
|
||||
|
||||
void getCurrentRoom()
|
||||
{
|
||||
printOutputLine("Trying to get current room");
|
||||
Rooms.GetCurrent().OnComplete(getCurrentRoomCallback);
|
||||
}
|
||||
|
||||
void getRoom(string roomID)
|
||||
{
|
||||
printOutputLine("Trying to get room " + roomID);
|
||||
Rooms.Get(Convert.ToUInt64(roomID)).OnComplete(getCurrentRoomCallback);
|
||||
}
|
||||
|
||||
void joinRoom(string roomID)
|
||||
{
|
||||
printOutputLine("Trying to join room " + roomID);
|
||||
Rooms.Join(Convert.ToUInt64(roomID), true).OnComplete(joinRoomCallback);
|
||||
}
|
||||
|
||||
void leaveRoom(string roomID)
|
||||
{
|
||||
printOutputLine("Trying to leave room " + roomID);
|
||||
Rooms.Leave(Convert.ToUInt64(roomID)).OnComplete(leaveRoomCallback);
|
||||
}
|
||||
|
||||
void kickUser(string roomID, string userID)
|
||||
{
|
||||
printOutputLine("Trying to kick user " + userID + " from room " + roomID);
|
||||
Rooms.KickUser(Convert.ToUInt64(roomID), Convert.ToUInt64(userID), 10 /*kick duration */).OnComplete(getCurrentRoomCallback);
|
||||
}
|
||||
|
||||
void getLoggedInUser()
|
||||
{
|
||||
printOutputLine("Trying to get currently logged in user");
|
||||
Users.GetLoggedInUser().OnComplete(getUserCallback);
|
||||
}
|
||||
|
||||
void getUser(string userID)
|
||||
{
|
||||
printOutputLine("Trying to get user " + userID);
|
||||
Users.Get(Convert.ToUInt64(userID)).OnComplete(getUserCallback);
|
||||
}
|
||||
|
||||
void getLoggedInFriends()
|
||||
{
|
||||
printOutputLine("Trying to get friends of logged in user");
|
||||
Users.GetLoggedInUserFriends().OnComplete(getFriendsCallback);
|
||||
}
|
||||
|
||||
void getInvitableUsers()
|
||||
{
|
||||
printOutputLine("Trying to get invitable users");
|
||||
Rooms.GetInvitableUsers().OnComplete(getInvitableUsersCallback);
|
||||
}
|
||||
|
||||
void inviteUser(string roomID, string inviteToken)
|
||||
{
|
||||
printOutputLine("Trying to invite token " + inviteToken + " to room " + roomID);
|
||||
Rooms.InviteUser(Convert.ToUInt64(roomID), inviteToken).OnComplete(inviteUserCallback);
|
||||
}
|
||||
|
||||
void setRoomDescription(string roomID, string description)
|
||||
{
|
||||
printOutputLine("Trying to set description " + description + " to room " + roomID);
|
||||
Rooms.SetDescription(Convert.ToUInt64(roomID), description).OnComplete(getCurrentRoomCallback);
|
||||
}
|
||||
|
||||
void updateRoomDataStore(string roomID, string key, string value)
|
||||
{
|
||||
Dictionary<string, string> kvPairs = new Dictionary<string, string>();
|
||||
kvPairs.Add(key, value);
|
||||
|
||||
printOutputLine("Trying to set k=" + key + " v=" + value + " for room " + roomID);
|
||||
Rooms.UpdateDataStore(Convert.ToUInt64(roomID), kvPairs).OnComplete(getCurrentRoomCallback);
|
||||
}
|
||||
|
||||
void printOutputLine(String newLine)
|
||||
{
|
||||
dataOutput.text = "> " + newLine + System.Environment.NewLine + dataOutput.text;
|
||||
}
|
||||
|
||||
void outputRoomDetails(Room room)
|
||||
{
|
||||
printOutputLine("Room ID: " + room.ID + ", AppID: " + room.ApplicationID + ", Description: " + room.Description);
|
||||
int numUsers = (room.UsersOptional != null) ? room.UsersOptional.Count : 0;
|
||||
printOutputLine("MaxUsers: " + room.MaxUsers.ToString() + " Users in room: " + numUsers);
|
||||
if (room.OwnerOptional != null)
|
||||
{
|
||||
printOutputLine("Room owner: " + room.OwnerOptional.ID + " " + room.OwnerOptional.OculusID);
|
||||
}
|
||||
printOutputLine("Join Policy: " + room.JoinPolicy.ToString());
|
||||
printOutputLine("Room Type: " + room.Type.ToString());
|
||||
|
||||
Message.MessageType.Matchmaking_Enqueue.GetHashCode();
|
||||
|
||||
}
|
||||
|
||||
void outputUserArray(UserList users)
|
||||
{
|
||||
foreach (User user in users)
|
||||
{
|
||||
printOutputLine("User: " + user.ID + " " + user.OculusID + " " + user.Presence + " " + user.InviteToken);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Callbacks
|
||||
void userProofCallback(Message<UserProof> msg)
|
||||
{
|
||||
if (!msg.IsError)
|
||||
{
|
||||
printOutputLine("Received user nonce generation success");
|
||||
UserProof userNonce = msg.Data;
|
||||
printOutputLine("Nonce: " + userNonce.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
printOutputLine("Received user nonce generation error");
|
||||
Error error = msg.GetError();
|
||||
printOutputLine("Error: " + error.Message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void getEntitlementCallback(Message msg)
|
||||
{
|
||||
if (!msg.IsError)
|
||||
{
|
||||
printOutputLine("You are entitled to use this app.");
|
||||
}
|
||||
else
|
||||
{
|
||||
printOutputLine("You are NOT entitled to use this app.");
|
||||
}
|
||||
}
|
||||
|
||||
void leaderboardGetCallback(Message<LeaderboardEntryList> msg)
|
||||
{
|
||||
if (!msg.IsError)
|
||||
{
|
||||
printOutputLine("Leaderboard entry get success.");
|
||||
var entries = msg.Data;
|
||||
|
||||
foreach (var entry in entries)
|
||||
{
|
||||
printOutputLine(entry.Rank + ". " + entry.User.OculusID + " " + entry.Score + " " + entry.Timestamp);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printOutputLine("Received leaderboard get error");
|
||||
Error error = msg.GetError();
|
||||
printOutputLine("Error: " + error.Message);
|
||||
}
|
||||
}
|
||||
|
||||
void leaderboardWriteCallback(Message msg)
|
||||
{
|
||||
if (!msg.IsError)
|
||||
{
|
||||
printOutputLine("Leaderboard entry write success.");
|
||||
var didUpdate = (Message<bool>)msg;
|
||||
|
||||
if (didUpdate.Data)
|
||||
{
|
||||
printOutputLine("Score updated.");
|
||||
}
|
||||
else
|
||||
{
|
||||
printOutputLine("Score NOT updated.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printOutputLine("Received leaderboard write error");
|
||||
Error error = msg.GetError();
|
||||
printOutputLine("Error: " + error.Message);
|
||||
}
|
||||
}
|
||||
|
||||
void achievementFieldsCallback(Message msg)
|
||||
{
|
||||
if (!msg.IsError)
|
||||
{
|
||||
printOutputLine("Achievement fields added.");
|
||||
}
|
||||
else
|
||||
{
|
||||
printOutputLine("Received achievement fields add error");
|
||||
Error error = msg.GetError();
|
||||
printOutputLine("Error: " + error.Message);
|
||||
}
|
||||
}
|
||||
|
||||
void achievementCountCallback(Message msg)
|
||||
{
|
||||
if (!msg.IsError)
|
||||
{
|
||||
printOutputLine("Achievement count added.");
|
||||
}
|
||||
else
|
||||
{
|
||||
printOutputLine("Received achievement count add error");
|
||||
Error error = msg.GetError();
|
||||
printOutputLine("Error: " + error.Message);
|
||||
}
|
||||
}
|
||||
|
||||
void achievementUnlockCallback(Message msg)
|
||||
{
|
||||
if (!msg.IsError)
|
||||
{
|
||||
printOutputLine("Achievement unlocked");
|
||||
}
|
||||
else
|
||||
{
|
||||
printOutputLine("Received achievement unlock error");
|
||||
Error error = msg.GetError();
|
||||
printOutputLine("Error: " + error.Message);
|
||||
}
|
||||
}
|
||||
|
||||
void achievementProgressCallback(Message<AchievementProgressList> msg)
|
||||
{
|
||||
if (!msg.IsError)
|
||||
{
|
||||
printOutputLine("Received achievement progress success");
|
||||
AchievementProgressList progressList = msg.GetAchievementProgressList();
|
||||
|
||||
foreach (var progress in progressList)
|
||||
{
|
||||
if (progress.IsUnlocked)
|
||||
{
|
||||
printOutputLine("Achievement Unlocked");
|
||||
}
|
||||
else
|
||||
{
|
||||
printOutputLine("Achievement Locked");
|
||||
}
|
||||
printOutputLine("Current Bitfield: " + progress.Bitfield.ToString());
|
||||
printOutputLine("Current Count: " + progress.Count.ToString());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printOutputLine("Received achievement progress error");
|
||||
Error error = msg.GetError();
|
||||
printOutputLine("Error: " + error.Message);
|
||||
}
|
||||
}
|
||||
|
||||
void achievementDefinitionCallback(Message<AchievementDefinitionList> msg)
|
||||
{
|
||||
if (!msg.IsError)
|
||||
{
|
||||
printOutputLine("Received achievement definitions success");
|
||||
AchievementDefinitionList definitionList = msg.GetAchievementDefinitions();
|
||||
|
||||
foreach (var definition in definitionList)
|
||||
{
|
||||
switch (definition.Type)
|
||||
{
|
||||
case AchievementType.Simple:
|
||||
printOutputLine("Achievement Type: Simple");
|
||||
break;
|
||||
case AchievementType.Bitfield:
|
||||
printOutputLine("Achievement Type: Bitfield");
|
||||
printOutputLine("Bitfield Length: " + definition.BitfieldLength.ToString());
|
||||
printOutputLine("Target: " + definition.Target.ToString());
|
||||
break;
|
||||
case AchievementType.Count:
|
||||
printOutputLine("Achievement Type: Count");
|
||||
printOutputLine("Target: " + definition.Target.ToString());
|
||||
break;
|
||||
case AchievementType.Unknown:
|
||||
default:
|
||||
printOutputLine("Achievement Type: Unknown");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printOutputLine("Received achievement definitions error");
|
||||
Error error = msg.GetError();
|
||||
printOutputLine("Error: " + error.Message);
|
||||
}
|
||||
}
|
||||
|
||||
void createAndJoinPrivateRoomCallback(Message<Room> msg)
|
||||
{
|
||||
if (!msg.IsError)
|
||||
{
|
||||
printOutputLine("Received create and join room success");
|
||||
outputRoomDetails(msg.Data);
|
||||
}
|
||||
else
|
||||
{
|
||||
printOutputLine("Received create and join room error");
|
||||
Error error = msg.GetError();
|
||||
printOutputLine("Error: " + error.Message);
|
||||
}
|
||||
}
|
||||
|
||||
void getCurrentRoomCallback(Message<Room> msg)
|
||||
{
|
||||
if (!msg.IsError)
|
||||
{
|
||||
printOutputLine("Received get room success");
|
||||
outputRoomDetails(msg.Data);
|
||||
}
|
||||
else
|
||||
{
|
||||
printOutputLine("Received get room error");
|
||||
Error error = msg.GetError();
|
||||
printOutputLine("Error: " + error.Message);
|
||||
}
|
||||
}
|
||||
|
||||
void joinRoomCallback(Message<Room> msg)
|
||||
{
|
||||
if (!msg.IsError)
|
||||
{
|
||||
printOutputLine("Received join room success");
|
||||
outputRoomDetails(msg.Data);
|
||||
}
|
||||
else
|
||||
{
|
||||
printOutputLine("Received join room error");
|
||||
Error error = msg.GetError();
|
||||
printOutputLine("Error: " + error.Message);
|
||||
}
|
||||
}
|
||||
|
||||
void leaveRoomCallback(Message<Room> msg)
|
||||
{
|
||||
if (!msg.IsError)
|
||||
{
|
||||
printOutputLine("Received leave room success");
|
||||
outputRoomDetails(msg.Data);
|
||||
}
|
||||
else
|
||||
{
|
||||
printOutputLine("Received leave room error");
|
||||
Error error = msg.GetError();
|
||||
printOutputLine("Error: " + error.Message);
|
||||
}
|
||||
}
|
||||
|
||||
void getUserCallback(Message<User> msg)
|
||||
{
|
||||
if (!msg.IsError)
|
||||
{
|
||||
printOutputLine("Received get user success");
|
||||
User user = msg.Data;
|
||||
printOutputLine("User: " + user.ID + " " + user.OculusID + " " + user.Presence + " " + user.InviteToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
printOutputLine("Received get user error");
|
||||
Error error = msg.GetError();
|
||||
printOutputLine("Error: " + error.Message);
|
||||
}
|
||||
}
|
||||
|
||||
void getFriendsCallback(Message<UserList> msg)
|
||||
{
|
||||
if (!msg.IsError)
|
||||
{
|
||||
printOutputLine("Received get friends success");
|
||||
UserList users = msg.Data;
|
||||
outputUserArray(users);
|
||||
}
|
||||
else
|
||||
{
|
||||
printOutputLine("Received get friends error");
|
||||
Error error = msg.GetError();
|
||||
printOutputLine("Error: " + error.Message);
|
||||
}
|
||||
}
|
||||
|
||||
void getInvitableUsersCallback(Message<UserList> msg)
|
||||
{
|
||||
if (!msg.IsError)
|
||||
{
|
||||
printOutputLine("Received get invitable users success");
|
||||
UserList users = msg.Data;
|
||||
outputUserArray(users);
|
||||
}
|
||||
else
|
||||
{
|
||||
printOutputLine("Received get invitable users error");
|
||||
Error error = msg.GetError();
|
||||
printOutputLine("Error: " + error.Message);
|
||||
}
|
||||
}
|
||||
|
||||
void inviteUserCallback(Message msg)
|
||||
{
|
||||
if (!msg.IsError)
|
||||
{
|
||||
printOutputLine("Received invite user success");
|
||||
}
|
||||
else
|
||||
{
|
||||
printOutputLine("Received invite user error");
|
||||
Error error = msg.GetError();
|
||||
printOutputLine("Error: " + error.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e10d7d54285902b48a88ddf18008a848
|
||||
timeCreated: 1446741207
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
1019
Assets/Oculus/Platform/Samples/SimplePlatformSample/MainScene.unity
Normal file
1019
Assets/Oculus/Platform/Samples/SimplePlatformSample/MainScene.unity
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 318d73ef645634c49839069272d9e4f4
|
||||
timeCreated: 1446741350
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Oculus/Platform/Samples/VrBoardGame.meta
Normal file
8
Assets/Oculus/Platform/Samples/VrBoardGame.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0cadc50673a07844289d5f28908a1137
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
3767
Assets/Oculus/Platform/Samples/VrBoardGame/Main.unity
Normal file
3767
Assets/Oculus/Platform/Samples/VrBoardGame/Main.unity
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1bcd80a3e5eb15543bd65c671c26434f
|
||||
timeCreated: 1479498828
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1 @@
|
||||
SKU Name Description Currency Amount Item Type
|
||||
|
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0b687b4832314b24db66e56bef4de820
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Oculus/Platform/Samples/VrBoardGame/Prefabs.meta
Normal file
8
Assets/Oculus/Platform/Samples/VrBoardGame/Prefabs.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1647f8ca022546249ade23a453afc3e8
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
112
Assets/Oculus/Platform/Samples/VrBoardGame/Prefabs/PieceA.prefab
Normal file
112
Assets/Oculus/Platform/Samples/VrBoardGame/Prefabs/PieceA.prefab
Normal file
@@ -0,0 +1,112 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1001 &100100000
|
||||
Prefab:
|
||||
m_ObjectHideFlags: 1
|
||||
serializedVersion: 2
|
||||
m_Modification:
|
||||
m_TransformParent: {fileID: 0}
|
||||
m_Modifications: []
|
||||
m_RemovedComponents: []
|
||||
m_ParentPrefab: {fileID: 0}
|
||||
m_RootGameObject: {fileID: 1000013725221134}
|
||||
m_IsPrefabParent: 1
|
||||
--- !u!1 &1000013725221134
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
serializedVersion: 5
|
||||
m_Component:
|
||||
- component: {fileID: 4000011548025488}
|
||||
- component: {fileID: 33000011356183730}
|
||||
- component: {fileID: 65000012561974784}
|
||||
- component: {fileID: 23000013314552442}
|
||||
- component: {fileID: 114000011207431316}
|
||||
m_Layer: 0
|
||||
m_Name: PieceA
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &4000011548025488
|
||||
Transform:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 1000013725221134}
|
||||
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 0.2, y: 0.2, z: 0.2}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!23 &23000013314552442
|
||||
MeshRenderer:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 1000013725221134}
|
||||
m_Enabled: 1
|
||||
m_CastShadows: 1
|
||||
m_ReceiveShadows: 1
|
||||
m_MotionVectors: 1
|
||||
m_LightProbeUsage: 1
|
||||
m_ReflectionProbeUsage: 1
|
||||
m_Materials:
|
||||
- {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_StaticBatchInfo:
|
||||
firstSubMesh: 0
|
||||
subMeshCount: 0
|
||||
m_StaticBatchRoot: {fileID: 0}
|
||||
m_ProbeAnchor: {fileID: 0}
|
||||
m_LightProbeVolumeOverride: {fileID: 0}
|
||||
m_ScaleInLightmap: 1
|
||||
m_PreserveUVs: 1
|
||||
m_IgnoreNormalsForChartDetection: 0
|
||||
m_ImportantGI: 0
|
||||
m_SelectedEditorRenderState: 3
|
||||
m_MinimumChartSize: 4
|
||||
m_AutoUVMaxDistance: 0.5
|
||||
m_AutoUVMaxAngle: 89
|
||||
m_LightmapParameters: {fileID: 0}
|
||||
m_SortingLayerID: 0
|
||||
m_SortingLayer: 0
|
||||
m_SortingOrder: 0
|
||||
--- !u!33 &33000011356183730
|
||||
MeshFilter:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 1000013725221134}
|
||||
m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0}
|
||||
--- !u!65 &65000012561974784
|
||||
BoxCollider:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 1000013725221134}
|
||||
m_Material: {fileID: 0}
|
||||
m_IsTrigger: 0
|
||||
m_Enabled: 1
|
||||
serializedVersion: 2
|
||||
m_Size: {x: 1, y: 1, z: 1}
|
||||
m_Center: {x: 0, y: 0, z: 0}
|
||||
--- !u!114 &114000011207431316
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 1000013725221134}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 4c243c46c5f7948488696c53b4fa9786, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_type: 0
|
||||
m_prefabA: {fileID: 1000013725221134}
|
||||
m_prefabB: {fileID: 1000011610856386, guid: ff8c3ef67a52afc4a9cf330f025fdec3, type: 2}
|
||||
m_prefabPower: {fileID: 1000010836483084, guid: 81a73acbe18cf784cb5184bd404c30bc,
|
||||
type: 2}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 48e6308f93e461340abb975251ae824b
|
||||
timeCreated: 1480479889
|
||||
licenseType: Store
|
||||
NativeFormatImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
113
Assets/Oculus/Platform/Samples/VrBoardGame/Prefabs/PieceB.prefab
Normal file
113
Assets/Oculus/Platform/Samples/VrBoardGame/Prefabs/PieceB.prefab
Normal file
@@ -0,0 +1,113 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1001 &100100000
|
||||
Prefab:
|
||||
m_ObjectHideFlags: 1
|
||||
serializedVersion: 2
|
||||
m_Modification:
|
||||
m_TransformParent: {fileID: 0}
|
||||
m_Modifications: []
|
||||
m_RemovedComponents: []
|
||||
m_ParentPrefab: {fileID: 0}
|
||||
m_RootGameObject: {fileID: 1000011610856386}
|
||||
m_IsPrefabParent: 1
|
||||
--- !u!1 &1000011610856386
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
serializedVersion: 5
|
||||
m_Component:
|
||||
- component: {fileID: 4000013853064064}
|
||||
- component: {fileID: 33000012696557308}
|
||||
- component: {fileID: 136000012754303966}
|
||||
- component: {fileID: 23000013106303838}
|
||||
- component: {fileID: 114000011050251136}
|
||||
m_Layer: 0
|
||||
m_Name: PieceB
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &4000013853064064
|
||||
Transform:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 1000011610856386}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 0.2, y: 0.1, z: 0.2}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!23 &23000013106303838
|
||||
MeshRenderer:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 1000011610856386}
|
||||
m_Enabled: 1
|
||||
m_CastShadows: 1
|
||||
m_ReceiveShadows: 1
|
||||
m_MotionVectors: 1
|
||||
m_LightProbeUsage: 1
|
||||
m_ReflectionProbeUsage: 1
|
||||
m_Materials:
|
||||
- {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_StaticBatchInfo:
|
||||
firstSubMesh: 0
|
||||
subMeshCount: 0
|
||||
m_StaticBatchRoot: {fileID: 0}
|
||||
m_ProbeAnchor: {fileID: 0}
|
||||
m_LightProbeVolumeOverride: {fileID: 0}
|
||||
m_ScaleInLightmap: 1
|
||||
m_PreserveUVs: 1
|
||||
m_IgnoreNormalsForChartDetection: 0
|
||||
m_ImportantGI: 0
|
||||
m_SelectedEditorRenderState: 3
|
||||
m_MinimumChartSize: 4
|
||||
m_AutoUVMaxDistance: 0.5
|
||||
m_AutoUVMaxAngle: 89
|
||||
m_LightmapParameters: {fileID: 0}
|
||||
m_SortingLayerID: 0
|
||||
m_SortingLayer: 0
|
||||
m_SortingOrder: 0
|
||||
--- !u!33 &33000012696557308
|
||||
MeshFilter:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 1000011610856386}
|
||||
m_Mesh: {fileID: 10206, guid: 0000000000000000e000000000000000, type: 0}
|
||||
--- !u!114 &114000011050251136
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 1000011610856386}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 4c243c46c5f7948488696c53b4fa9786, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_type: 1
|
||||
m_prefabA: {fileID: 1000013725221134, guid: 48e6308f93e461340abb975251ae824b, type: 2}
|
||||
m_prefabB: {fileID: 1000011610856386}
|
||||
m_prefabPower: {fileID: 1000010836483084, guid: 81a73acbe18cf784cb5184bd404c30bc,
|
||||
type: 2}
|
||||
--- !u!136 &136000012754303966
|
||||
CapsuleCollider:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 1000011610856386}
|
||||
m_Material: {fileID: 0}
|
||||
m_IsTrigger: 0
|
||||
m_Enabled: 1
|
||||
m_Radius: 0.5
|
||||
m_Height: 2
|
||||
m_Direction: 1
|
||||
m_Center: {x: 0, y: 0, z: 0}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ff8c3ef67a52afc4a9cf330f025fdec3
|
||||
timeCreated: 1480479894
|
||||
licenseType: Store
|
||||
NativeFormatImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,111 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1001 &100100000
|
||||
Prefab:
|
||||
m_ObjectHideFlags: 1
|
||||
serializedVersion: 2
|
||||
m_Modification:
|
||||
m_TransformParent: {fileID: 0}
|
||||
m_Modifications: []
|
||||
m_RemovedComponents: []
|
||||
m_ParentPrefab: {fileID: 0}
|
||||
m_RootGameObject: {fileID: 1000010836483084}
|
||||
m_IsPrefabParent: 1
|
||||
--- !u!1 &1000010836483084
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
serializedVersion: 5
|
||||
m_Component:
|
||||
- component: {fileID: 4000013490292564}
|
||||
- component: {fileID: 33000012739098690}
|
||||
- component: {fileID: 135000010301361876}
|
||||
- component: {fileID: 23000010370066952}
|
||||
- component: {fileID: 114000013731705678}
|
||||
m_Layer: 0
|
||||
m_Name: PowerBall
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &4000013490292564
|
||||
Transform:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 1000010836483084}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 0.2, y: 0.2, z: 0.2}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!23 &23000010370066952
|
||||
MeshRenderer:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 1000010836483084}
|
||||
m_Enabled: 1
|
||||
m_CastShadows: 1
|
||||
m_ReceiveShadows: 1
|
||||
m_MotionVectors: 1
|
||||
m_LightProbeUsage: 1
|
||||
m_ReflectionProbeUsage: 1
|
||||
m_Materials:
|
||||
- {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_StaticBatchInfo:
|
||||
firstSubMesh: 0
|
||||
subMeshCount: 0
|
||||
m_StaticBatchRoot: {fileID: 0}
|
||||
m_ProbeAnchor: {fileID: 0}
|
||||
m_LightProbeVolumeOverride: {fileID: 0}
|
||||
m_ScaleInLightmap: 1
|
||||
m_PreserveUVs: 1
|
||||
m_IgnoreNormalsForChartDetection: 0
|
||||
m_ImportantGI: 0
|
||||
m_SelectedEditorRenderState: 3
|
||||
m_MinimumChartSize: 4
|
||||
m_AutoUVMaxDistance: 0.5
|
||||
m_AutoUVMaxAngle: 89
|
||||
m_LightmapParameters: {fileID: 0}
|
||||
m_SortingLayerID: 0
|
||||
m_SortingLayer: 0
|
||||
m_SortingOrder: 0
|
||||
--- !u!33 &33000012739098690
|
||||
MeshFilter:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 1000010836483084}
|
||||
m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0}
|
||||
--- !u!114 &114000013731705678
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 1000010836483084}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 4c243c46c5f7948488696c53b4fa9786, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_type: 2
|
||||
m_prefabA: {fileID: 1000013725221134, guid: 48e6308f93e461340abb975251ae824b, type: 2}
|
||||
m_prefabB: {fileID: 1000011610856386, guid: ff8c3ef67a52afc4a9cf330f025fdec3, type: 2}
|
||||
m_prefabPower: {fileID: 1000010836483084}
|
||||
--- !u!135 &135000010301361876
|
||||
SphereCollider:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 1000010836483084}
|
||||
m_Material: {fileID: 0}
|
||||
m_IsTrigger: 0
|
||||
m_Enabled: 1
|
||||
serializedVersion: 2
|
||||
m_Radius: 0.5
|
||||
m_Center: {x: 0, y: 0, z: 0}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 81a73acbe18cf784cb5184bd404c30bc
|
||||
timeCreated: 1480479897
|
||||
licenseType: Store
|
||||
NativeFormatImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
64
Assets/Oculus/Platform/Samples/VrBoardGame/Readme.md
Normal file
64
Assets/Oculus/Platform/Samples/VrBoardGame/Readme.md
Normal file
@@ -0,0 +1,64 @@
|
||||
# Overview
|
||||
|
||||
This example demonstrates using the Oculus In-App-Purchase API and skill based matchmaking.
|
||||
The setting is a simple boardgame (which you are encourage to chage to your creative idea!)
|
||||
on a 3x3 grid with two pieces and one special 'power-piece' that can be purchased with
|
||||
IAP through the Oculus Store. After an Online match is completed the ranking is sent to
|
||||
the Matchmaking Service so that following match selections will take into account a user's
|
||||
skill level.
|
||||
|
||||
# Application Setup
|
||||
|
||||
1. Open the Project in Unity 5.4.1p1 or later
|
||||
2. Import the OculusPlatform Unity package
|
||||
- Unity: Main Menu -> Assets -> Import Package -> Custom Package
|
||||
- SDK Location: Unity/OculusPlatform.unitypackage
|
||||
|
||||
## Rift
|
||||
1. Create your Rift application on the Oculus Developer Dashboard
|
||||
2. Copy the Application ID into the Project (Main Menu -> Oculus Platform -> Edit Settings -> Oculus Rift App Id)
|
||||
|
||||
## GearVR
|
||||
1. Create the GearVR application on the Oculus Developer Dashboard
|
||||
2. Move the GearVR application into the Rift application's App Grouping
|
||||
3. Copy the Application ID into the Project (Main Menu -> Oculus Platform -> Edit Settings -> Gear VR App Id)
|
||||
4. Copy the OSIG files for the GearVR devices you are testing to Assets\Plugins\Android\Assets
|
||||
|
||||
# Configure Matchmaking
|
||||
|
||||
1. On the Oculus Dashboard, navigate to the Matchmaking section for your App Grouping
|
||||
2. Change the option box from 'Pools' to 'Skill Pools'
|
||||
3. Click Create Pool
|
||||
4. Set the 'Skill Pool Key' to ''VR_BOARD_GAME''
|
||||
5. Select ''Medium'' for the 'Luck Factor'
|
||||
6. Enter ''0'' for the 'Draw Probability
|
||||
7. Click 'Save & Deploy'
|
||||
8. Change the option box 'Skill Pools' to 'Pools'
|
||||
9. Click Create Pool
|
||||
10. Set the 'Pool Key' to ''VR_BOARD_GAME_POOL''
|
||||
11. Set the Mode to Quickmatch
|
||||
12. Enter ''2'' for both the Min and Max Users
|
||||
13. Select ''VR_BOARD_GAME'' for the 'Skill Pool'
|
||||
14. Leave 'Advanced Quickmatch' set to ''No''
|
||||
15. Leave 'Should Consider Ping Time?' at the default setting of ''No''
|
||||
16. Click 'Save & Deploy'
|
||||
|
||||
# Configure IAP
|
||||
|
||||
1. On the Oculus Dashboard, make sure the Payment Info is setup for your Organization
|
||||
2. Navigate to the IAP tab under your App Grouping
|
||||
3. Select the Upload TSV button and choose the Oculus_IAP.tsv in the project root directory.
|
||||
|
||||
# Upload your builds
|
||||
|
||||
Build executables from Unity and upload them to your Application Dashboard
|
||||
* Rift
|
||||
1. Add the executable and data folder to a zip file
|
||||
2. Upload the zip to the Alpha channel on your Dashboard
|
||||
3. Set the executable name you chose in the zip file
|
||||
4. Add Friends you are testing with as Subscribed Users for the Alpha channel
|
||||
* GearVR
|
||||
1. Create an android keystore (if you don't have one) so Unity can sign the build. (Player Settings -> Publishing Settings)
|
||||
2. Upload the apk to the Alpha channel on your Dashboard
|
||||
3. Each apk you upload needs a new build number (Player Settings -> Other Settings)
|
||||
4. Add Friends you are testing with as Subscribed Users for the Alpha channel
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0975c71f0ce832c489580f5059a6118a
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Oculus/Platform/Samples/VrBoardGame/Scripts.meta
Normal file
8
Assets/Oculus/Platform/Samples/VrBoardGame/Scripts.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 33f1f2bb7b5261d4195cc3051db6fb83
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,15 @@
|
||||
namespace Oculus.Platform.Samples.VrBoardGame
|
||||
{
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
// This behaviour is attached to GameObjects whose collision mesh
|
||||
// describes a specific position on the GameBoard. The collision
|
||||
// mesh doesn't need to fully cover the board position, but enough
|
||||
// for eye raycasts to detect that the user is looking there.
|
||||
public class BoardPosition : MonoBehaviour {
|
||||
|
||||
[SerializeField] [Range(0,2)] public int x = 0;
|
||||
[SerializeField] [Range(0,2)] public int y = 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d9244e220b0fee34c98de6ed84ee6cdd
|
||||
timeCreated: 1480276073
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,99 @@
|
||||
namespace Oculus.Platform.Samples.VrBoardGame
|
||||
{
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityEngine.EventSystems;
|
||||
|
||||
// This is a helper class for selecting objects that the user is looking at.
|
||||
// It will select UI objects that have an attach 3d collision volume and helps
|
||||
// the GameController locate GamePieces and GamePositions.
|
||||
public class EyeCamera : MonoBehaviour
|
||||
{
|
||||
// the EventSystem used by the UI elements
|
||||
[SerializeField] private EventSystem m_eventSystem = null;
|
||||
|
||||
// the GameController to notify
|
||||
[SerializeField] private GameController m_gameController = null;
|
||||
|
||||
// a tine ball in the distance to debug where the user is looking
|
||||
[SerializeField] private SphereCollider m_gazeTracker = null;
|
||||
|
||||
// the current Button, if any, being looked at
|
||||
private Button m_currentButton;
|
||||
|
||||
// the current GamePiece, if any, being looked at
|
||||
private GamePiece m_currentPiece;
|
||||
|
||||
// the current BoardPosition, if any, being looked at
|
||||
private BoardPosition m_boardPosition;
|
||||
|
||||
void Update()
|
||||
{
|
||||
RaycastHit hit;
|
||||
Button button = null;
|
||||
GamePiece piece = null;
|
||||
BoardPosition pos = null;
|
||||
|
||||
// do a forward raycast to see if we hit a selectable object
|
||||
bool hitSomething = Physics.Raycast(transform.position, transform.forward, out hit, 50f);
|
||||
if (hitSomething) {
|
||||
button = hit.collider.GetComponent<Button>();
|
||||
piece = hit.collider.GetComponent<GamePiece>();
|
||||
pos = hit.collider.GetComponent<BoardPosition>();
|
||||
}
|
||||
|
||||
if (m_currentButton != button)
|
||||
{
|
||||
if (m_eventSystem != null)
|
||||
{
|
||||
m_eventSystem.SetSelectedGameObject(null);
|
||||
}
|
||||
m_currentButton = button;
|
||||
if (m_currentButton != null)
|
||||
{
|
||||
m_currentButton.Select();
|
||||
}
|
||||
}
|
||||
|
||||
if (m_currentPiece != piece)
|
||||
{
|
||||
if (m_currentPiece != null)
|
||||
{
|
||||
m_gameController.StoppedLookingAtPiece();
|
||||
}
|
||||
m_currentPiece = piece;
|
||||
if (m_currentPiece != null)
|
||||
{
|
||||
m_gameController.StartedLookingAtPiece(m_currentPiece);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_boardPosition != pos)
|
||||
{
|
||||
m_boardPosition = pos;
|
||||
if (m_boardPosition != null)
|
||||
{
|
||||
m_gameController.StartedLookingAtPosition(m_boardPosition);
|
||||
}
|
||||
}
|
||||
|
||||
// clear the potential move if they gaze off the board
|
||||
if (hit.collider == m_gazeTracker)
|
||||
{
|
||||
m_gameController.ClearProposedMove();
|
||||
}
|
||||
|
||||
// moves the camera with the mouse - very useful for debugging in to 2D mode.
|
||||
if (Input.GetButton("Fire2"))
|
||||
{
|
||||
var v = Input.GetAxis("Mouse Y");
|
||||
var h = Input.GetAxis("Mouse X");
|
||||
transform.rotation *= Quaternion.AngleAxis(h, Vector3.up);
|
||||
transform.rotation *= Quaternion.AngleAxis(-v, Vector3.right);
|
||||
Vector3 eulers = transform.eulerAngles;
|
||||
eulers.z = 0;
|
||||
transform.eulerAngles = eulers;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 96a29a99957531246921ced0fac365ab
|
||||
timeCreated: 1480201871
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
188
Assets/Oculus/Platform/Samples/VrBoardGame/Scripts/GameBoard.cs
Normal file
188
Assets/Oculus/Platform/Samples/VrBoardGame/Scripts/GameBoard.cs
Normal file
@@ -0,0 +1,188 @@
|
||||
namespace Oculus.Platform.Samples.VrBoardGame
|
||||
{
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
//
|
||||
// This script describes the game board along with the game pieces that
|
||||
// are in play. The rules for the game board are:
|
||||
// 1) Player can place a normal GamePiece on any empty BoardPosition
|
||||
// 2) Player can place a power GamePiece on top of a normal piece
|
||||
// 3) The board is full when all positions have a normal piece
|
||||
// Player score is calculated as:
|
||||
// 1) +10 points for each normal piece on the board
|
||||
// 2) +10 points for each normal piece with 1 square of one of their power pieces
|
||||
// 3) -10 points for each opponent normal piece within 1 square of their power pieces
|
||||
//
|
||||
public class GameBoard : MonoBehaviour
|
||||
{
|
||||
public const int LENGTH_X = 3;
|
||||
public const int LENGTH_Y = 3;
|
||||
public const int MAX_PLAYERS = 2;
|
||||
|
||||
// the placed-piece color for each player
|
||||
[SerializeField] private Color[] m_playerColors = new Color[MAX_PLAYERS];
|
||||
|
||||
// color for pice the player is considering moving to
|
||||
[SerializeField] private Color m_proposedMoveColor = Color.white;
|
||||
|
||||
// the player scores that are recalcuated after a pice is placed
|
||||
private int[] m_scores = new int[MAX_PLAYERS];
|
||||
|
||||
// GameObjects that define each of the allowed piece positions
|
||||
[SerializeField] private BoardPosition[] m_positions = new BoardPosition[9];
|
||||
|
||||
private struct PositionInfo
|
||||
{
|
||||
public GameObject piece;
|
||||
public int pieceOwner;
|
||||
public int powerPieceOwner;
|
||||
}
|
||||
|
||||
// pieces in play for the current game
|
||||
private readonly PositionInfo[,] m_pieces = new PositionInfo[LENGTH_X, LENGTH_Y];
|
||||
|
||||
// removes all game pieces from the board
|
||||
public void Reset()
|
||||
{
|
||||
for (int x = 0; x < LENGTH_X; x++)
|
||||
{
|
||||
for (int y = 0; y < LENGTH_Y; y++)
|
||||
{
|
||||
if (m_pieces[x,y].piece != null)
|
||||
{
|
||||
Destroy(m_pieces[x,y].piece);
|
||||
m_pieces[x,y].piece = null;
|
||||
m_pieces[x,y].pieceOwner = -1;
|
||||
m_pieces[x,y].powerPieceOwner = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region Board status
|
||||
|
||||
// returns true if all the board positions have a piece in them
|
||||
public bool IsFull()
|
||||
{
|
||||
for (int x = 0; x < LENGTH_X; x++)
|
||||
{
|
||||
for (int y = 0; y < LENGTH_Y; y++)
|
||||
{
|
||||
if (m_pieces[x,y].piece == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool CanPlayerMoveToPostion(int x, int y)
|
||||
{
|
||||
return m_pieces[x,y].piece == null;
|
||||
}
|
||||
|
||||
public bool CanPlayerPowerUpPosition(int x, int y)
|
||||
{
|
||||
return m_pieces[x,y].piece != null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region creating game pieces
|
||||
|
||||
public void AddPiece(int player, GameObject prefab, int x, int y)
|
||||
{
|
||||
var pos = m_positions[x * LENGTH_Y + y];
|
||||
var piece = Create(prefab, pos.gameObject, pos, Vector3.zero);
|
||||
piece.GetComponent<Renderer>().material.color = m_playerColors[player];
|
||||
m_pieces[x,y].piece = piece.gameObject;
|
||||
m_pieces[x,y].pieceOwner = player;
|
||||
m_pieces[x,y].powerPieceOwner = -1;
|
||||
|
||||
UpdateScores();
|
||||
}
|
||||
|
||||
public GamePiece AddProposedPiece(GameObject prefab, BoardPosition pos)
|
||||
{
|
||||
var piece = Create(prefab, pos.gameObject, pos, Vector3.zero);
|
||||
piece.GetComponent<Renderer>().material.color = m_proposedMoveColor;
|
||||
return piece;
|
||||
}
|
||||
|
||||
public void AddPowerPiece(int player, GameObject prefab, int x, int y)
|
||||
{
|
||||
var piece = Create(prefab, m_pieces[x,y].piece, m_positions[x*LENGTH_Y+y], .2f*Vector3.up);
|
||||
piece.GetComponent<Renderer>().material.color = m_playerColors[player];
|
||||
m_pieces[x,y].powerPieceOwner = player;
|
||||
|
||||
UpdateScores();
|
||||
}
|
||||
|
||||
public GamePiece AddProposedPowerPiece(GameObject prefab, BoardPosition pos)
|
||||
{
|
||||
var piece = Create(prefab, m_pieces[pos.x, pos.y].piece, pos, .2f*Vector3.up);
|
||||
piece.GetComponent<Renderer>().material.color = m_proposedMoveColor;
|
||||
return piece;
|
||||
}
|
||||
|
||||
private GamePiece Create(GameObject prefab, GameObject parent, BoardPosition pos, Vector3 off)
|
||||
{
|
||||
var go = Instantiate(prefab, parent.transform) as GameObject;
|
||||
go.transform.position = parent.transform.position + off;
|
||||
go.GetComponent<GamePiece>().Position = pos;
|
||||
return go.GetComponent<GamePiece>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region scores
|
||||
|
||||
public int GetPlayerScore(int player)
|
||||
{
|
||||
return m_scores[player];
|
||||
}
|
||||
|
||||
private void UpdateScores()
|
||||
{
|
||||
for (int i = 0; i < MAX_PLAYERS; i++)
|
||||
{
|
||||
m_scores[i] = 0;
|
||||
}
|
||||
|
||||
for (int x = 0; x < LENGTH_X; x++)
|
||||
{
|
||||
for (int y = 0; y < LENGTH_Y; y++)
|
||||
{
|
||||
if (m_pieces[x,y].piece != null)
|
||||
{
|
||||
// for each piece on the board, the player gets 10 points
|
||||
m_scores[m_pieces[x,y].pieceOwner] += 10;
|
||||
|
||||
// for each power piece, the player gains or loses 10 points
|
||||
// based on the ownership of nearby pieces
|
||||
if (m_pieces[x,y].powerPieceOwner >= 0)
|
||||
{
|
||||
for (int px = x-1; px <= x+1; px++)
|
||||
{
|
||||
for (int py = y-1; py <= y+1; py++)
|
||||
{
|
||||
if (px >= 0 && py >= 0 && px < LENGTH_X && py < LENGTH_Y)
|
||||
{
|
||||
var powerup =
|
||||
m_pieces[x,y].pieceOwner == m_pieces[x,y].powerPieceOwner ?
|
||||
+10 : -10;
|
||||
m_scores[m_pieces[x, y].powerPieceOwner] += powerup;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 94decd43dfca0db43a3936edb109ca2e
|
||||
timeCreated: 1479840163
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,405 @@
|
||||
namespace Oculus.Platform.Samples.VrBoardGame
|
||||
{
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
// This is the primary class that implements the game logic.
|
||||
public class GameController : MonoBehaviour
|
||||
{
|
||||
// instance of the object interfacing with the matchmaking service
|
||||
[SerializeField] private MatchmakingManager m_matchmaking = null;
|
||||
|
||||
[SerializeField] private GameBoard m_board = null;
|
||||
[SerializeField] private GamePiece m_pieceA = null;
|
||||
[SerializeField] private GamePiece m_pieceB = null;
|
||||
[SerializeField] private GamePiece m_powerPiece = null;
|
||||
|
||||
// colors for the various states of the selectable games pieces
|
||||
[SerializeField] private Color m_unusableColor = Color.white;
|
||||
[SerializeField] private Color m_unselectedColor = Color.white;
|
||||
[SerializeField] private Color m_selectedColor = Color.white;
|
||||
[SerializeField] private Color m_highlightedColor = Color.white;
|
||||
|
||||
[SerializeField] private Text m_ballCountText = null;
|
||||
[SerializeField] private Text m_player0Text = null;
|
||||
[SerializeField] private Text m_player1Text = null;
|
||||
|
||||
private enum GameState {
|
||||
None,
|
||||
PracticingMyTurn, PracticingAiTurn,
|
||||
OnlineMatchMyTurn, OnlineMatchRemoteTurn
|
||||
}
|
||||
|
||||
private GameState m_state;
|
||||
|
||||
// the game piece the player is currently looking at
|
||||
private GamePiece m_interestedPiece;
|
||||
|
||||
// the piece the player selected with the Fire button
|
||||
private GamePiece m_selectedPiece;
|
||||
|
||||
// the piece that would be placed if the player pressed the Fire button
|
||||
private GamePiece m_proposedPiece;
|
||||
|
||||
// how many IAP power-balls the user has
|
||||
private uint m_powerBallcount;
|
||||
|
||||
// the name of the current opponent
|
||||
private string m_opponentName;
|
||||
|
||||
void Start()
|
||||
{
|
||||
TransitionToState(GameState.None);
|
||||
UpdateScores();
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
PerFrameStateUpdate();
|
||||
}
|
||||
|
||||
#region Game State
|
||||
|
||||
private void TransitionToState(GameState state)
|
||||
{
|
||||
m_state = state;
|
||||
|
||||
UpdateGamePieceColors();
|
||||
}
|
||||
|
||||
private void TransitionToNextState()
|
||||
{
|
||||
if (!m_board.IsFull())
|
||||
{
|
||||
switch (m_state)
|
||||
{
|
||||
case GameState.PracticingAiTurn:
|
||||
TransitionToState(GameState.PracticingMyTurn);
|
||||
break;
|
||||
case GameState.PracticingMyTurn:
|
||||
TransitionToState(GameState.PracticingAiTurn);
|
||||
break;
|
||||
case GameState.OnlineMatchRemoteTurn:
|
||||
TransitionToState(GameState.OnlineMatchMyTurn);
|
||||
break;
|
||||
case GameState.OnlineMatchMyTurn:
|
||||
TransitionToState(GameState.OnlineMatchRemoteTurn);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (m_state)
|
||||
{
|
||||
case GameState.OnlineMatchRemoteTurn:
|
||||
case GameState.OnlineMatchMyTurn:
|
||||
m_matchmaking.EndMatch(m_board.GetPlayerScore(0), m_board.GetPlayerScore(1));
|
||||
break;
|
||||
}
|
||||
TransitionToState(GameState.None);
|
||||
}
|
||||
}
|
||||
|
||||
private void PerFrameStateUpdate()
|
||||
{
|
||||
switch (m_state)
|
||||
{
|
||||
case GameState.PracticingAiTurn:
|
||||
// don't move immediately to give the AI time to 'think'
|
||||
if (Random.Range(1, 100) < 3)
|
||||
{
|
||||
MakeAIMove(1);
|
||||
}
|
||||
break;
|
||||
|
||||
case GameState.PracticingMyTurn:
|
||||
case GameState.OnlineMatchMyTurn:
|
||||
if (Input.GetButton("Fire1"))
|
||||
{
|
||||
TrySelectPiece();
|
||||
TryPlacePiece();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Practicing with an AI Player
|
||||
|
||||
public void PracticeButtonPressed()
|
||||
{
|
||||
m_opponentName = "* AI *";
|
||||
|
||||
switch (m_state)
|
||||
{
|
||||
case GameState.OnlineMatchMyTurn:
|
||||
case GameState.OnlineMatchRemoteTurn:
|
||||
m_matchmaking.EndMatch(m_board.GetPlayerScore(0), m_board.GetPlayerScore(1));
|
||||
break;
|
||||
}
|
||||
m_board.Reset();
|
||||
|
||||
// randomly decised whether the player or AI goes first
|
||||
if (Random.Range(0, 2) == 1)
|
||||
{
|
||||
TransitionToState(GameState.PracticingMyTurn);
|
||||
}
|
||||
else
|
||||
{
|
||||
TransitionToState(GameState.PracticingAiTurn);
|
||||
}
|
||||
|
||||
UpdateScores();
|
||||
}
|
||||
|
||||
private void MakeAIMove(int player)
|
||||
{
|
||||
bool moved = false;
|
||||
|
||||
// pick a random search start position
|
||||
int rx = Random.Range(0, GameBoard.LENGTH_X - 1);
|
||||
int ry = Random.Range(0, GameBoard.LENGTH_Y - 1);
|
||||
|
||||
// from (rx,ry) search of an available move
|
||||
for (int i = 0; i < GameBoard.LENGTH_X && !moved; i++)
|
||||
{
|
||||
for (int j = 0; j < GameBoard.LENGTH_Y && !moved; j++)
|
||||
{
|
||||
int x = (rx + i) % GameBoard.LENGTH_X;
|
||||
int y = (ry + j) % GameBoard.LENGTH_Y;
|
||||
|
||||
// first try to place a piece on the current position
|
||||
if (m_board.CanPlayerMoveToPostion(x, y))
|
||||
{
|
||||
GamePiece p = Random.Range(0, 2) == 0 ? m_pieceA : m_pieceB;
|
||||
m_board.AddPiece(player, p.Prefab, x, y);
|
||||
moved = true;
|
||||
}
|
||||
// a random percentage of the time, try to powerup this position
|
||||
else if (m_board.CanPlayerPowerUpPosition(x, y) && Random.Range(0, 8) < 2)
|
||||
{
|
||||
m_board.AddPowerPiece(player, m_powerPiece.Prefab, x, y);
|
||||
moved = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (moved)
|
||||
{
|
||||
UpdateScores();
|
||||
TransitionToNextState();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Playing Online Match
|
||||
|
||||
// called from the MatchmakingManager was a successly online match is made
|
||||
public void StartOnlineMatch (string opponentName, bool localUserGoesFirst)
|
||||
{
|
||||
m_board.Reset();
|
||||
m_opponentName = opponentName;
|
||||
|
||||
if (localUserGoesFirst)
|
||||
{
|
||||
TransitionToState(GameState.OnlineMatchMyTurn);
|
||||
}
|
||||
else
|
||||
{
|
||||
TransitionToState(GameState.OnlineMatchRemoteTurn);
|
||||
}
|
||||
|
||||
UpdateScores();
|
||||
}
|
||||
|
||||
// called from the Matchmaking Manager when the remote users their next move
|
||||
public void MakeRemoteMove(GamePiece.Piece piece, int x, int y)
|
||||
{
|
||||
GameObject prefab = m_pieceA.PrefabFor(piece);
|
||||
|
||||
if (piece == GamePiece.Piece.PowerBall)
|
||||
{
|
||||
m_board.AddPowerPiece(1, prefab, x, y);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_board.AddPiece(1, prefab, x, y);
|
||||
}
|
||||
|
||||
UpdateScores();
|
||||
}
|
||||
|
||||
// called from the MatchmakingManager when the local user becomes the room
|
||||
// owner and thus it's safe for the local user to make their move
|
||||
public void MarkRemoteTurnComplete()
|
||||
{
|
||||
if (m_state == GameState.OnlineMatchRemoteTurn)
|
||||
{
|
||||
TransitionToNextState();
|
||||
}
|
||||
}
|
||||
|
||||
// the match ended from a player leaving before the board was complete
|
||||
public void RemoteMatchEnded()
|
||||
{
|
||||
m_matchmaking.EndMatch(m_board.GetPlayerScore(0), m_board.GetPlayerScore(1));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Selecting and Placing a Game Place
|
||||
|
||||
public void StartedLookingAtPiece(GamePiece piece)
|
||||
{
|
||||
m_interestedPiece = piece;
|
||||
UpdateGamePieceColors();
|
||||
}
|
||||
|
||||
public void StoppedLookingAtPiece()
|
||||
{
|
||||
m_interestedPiece = null;
|
||||
UpdateGamePieceColors();
|
||||
}
|
||||
|
||||
// This method is used to display an example piece where the player is looking
|
||||
// so they know what to expect when they press the Fire button.
|
||||
public void StartedLookingAtPosition(BoardPosition position)
|
||||
{
|
||||
if (m_state != GameState.OnlineMatchMyTurn && m_state != GameState.PracticingMyTurn)
|
||||
return;
|
||||
|
||||
GamePiece newPiece = null;
|
||||
|
||||
if ((m_selectedPiece == m_pieceA || m_selectedPiece == m_pieceB) &&
|
||||
m_board.CanPlayerMoveToPostion(position.x, position.y))
|
||||
{
|
||||
newPiece = m_board.AddProposedPiece(m_selectedPiece.Prefab, position);
|
||||
}
|
||||
else if (m_selectedPiece == m_powerPiece &&
|
||||
m_board.CanPlayerPowerUpPosition(position.x, position.y))
|
||||
{
|
||||
newPiece = m_board.AddProposedPowerPiece(m_selectedPiece.Prefab, position);
|
||||
}
|
||||
|
||||
if (newPiece != null)
|
||||
{
|
||||
if (m_proposedPiece != null)
|
||||
{
|
||||
Destroy(m_proposedPiece.gameObject);
|
||||
}
|
||||
m_proposedPiece = newPiece;
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearProposedMove()
|
||||
{
|
||||
if (m_proposedPiece != null)
|
||||
{
|
||||
Destroy(m_proposedPiece.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
public void TrySelectPiece()
|
||||
{
|
||||
if (m_interestedPiece == m_pieceA || m_interestedPiece == m_pieceB)
|
||||
{
|
||||
m_selectedPiece = m_interestedPiece;
|
||||
}
|
||||
else if (m_interestedPiece == m_powerPiece &&
|
||||
(m_powerBallcount > 0 || m_state == GameState.PracticingMyTurn))
|
||||
{
|
||||
m_selectedPiece = m_interestedPiece;
|
||||
}
|
||||
UpdateGamePieceColors();
|
||||
}
|
||||
|
||||
public void TryPlacePiece()
|
||||
{
|
||||
if (m_proposedPiece == null)
|
||||
return;
|
||||
|
||||
var position = m_proposedPiece.Position;
|
||||
switch(m_proposedPiece.Type)
|
||||
{
|
||||
case GamePiece.Piece.A:
|
||||
case GamePiece.Piece.B:
|
||||
m_board.AddPiece(0, m_proposedPiece.Prefab, position.x, position.y);
|
||||
break;
|
||||
case GamePiece.Piece.PowerBall:
|
||||
m_board.AddPowerPiece(0, m_proposedPiece.Prefab, position.x, position.y);
|
||||
break;
|
||||
}
|
||||
Destroy(m_proposedPiece.gameObject);
|
||||
|
||||
if (m_state == GameState.OnlineMatchMyTurn)
|
||||
{
|
||||
m_matchmaking.SendLocalMove(m_proposedPiece.Type, position.x, position.y);
|
||||
}
|
||||
|
||||
UpdateScores();
|
||||
TransitionToNextState();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region UI
|
||||
|
||||
public void QuitButtonPressed()
|
||||
{
|
||||
UnityEngine.Application.Quit();
|
||||
}
|
||||
|
||||
public void AddPowerballs(uint count)
|
||||
{
|
||||
m_powerBallcount += count;
|
||||
m_ballCountText.text = "x" + m_powerBallcount.ToString();
|
||||
}
|
||||
|
||||
private void UpdateScores()
|
||||
{
|
||||
m_player0Text.text = string.Format("{0}\n\n{1}",
|
||||
PlatformManager.MyOculusID, m_board.GetPlayerScore(0));
|
||||
|
||||
m_player1Text.text = string.Format("{0}\n\n{1}",
|
||||
m_opponentName, m_board.GetPlayerScore(1));
|
||||
}
|
||||
|
||||
private void UpdateGamePieceColors()
|
||||
{
|
||||
switch (m_state)
|
||||
{
|
||||
case GameState.None:
|
||||
case GameState.PracticingAiTurn:
|
||||
case GameState.OnlineMatchRemoteTurn:
|
||||
m_pieceA.GetComponent<Renderer>().material.color = m_unusableColor;
|
||||
m_pieceB.GetComponent<Renderer>().material.color = m_unusableColor;
|
||||
m_powerPiece.GetComponent<Renderer>().material.color = m_unusableColor;
|
||||
if (m_proposedPiece != null)
|
||||
{
|
||||
Destroy(m_proposedPiece.gameObject);
|
||||
}
|
||||
break;
|
||||
|
||||
case GameState.PracticingMyTurn:
|
||||
case GameState.OnlineMatchMyTurn:
|
||||
m_pieceA.GetComponent<Renderer>().material.color = m_unselectedColor;
|
||||
m_pieceB.GetComponent<Renderer>().material.color = m_unselectedColor;
|
||||
m_powerPiece.GetComponent<Renderer>().material.color = m_unselectedColor;
|
||||
if (m_interestedPiece == m_pieceA || m_interestedPiece == m_pieceB ||
|
||||
m_interestedPiece == m_powerPiece)
|
||||
{
|
||||
m_interestedPiece.GetComponent<Renderer>().material.color = m_highlightedColor;
|
||||
}
|
||||
if (m_selectedPiece != null)
|
||||
{
|
||||
m_selectedPiece.GetComponent<Renderer>().material.color = m_selectedColor;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e8e18544645909d4ca3288d03cc2bb95
|
||||
timeCreated: 1480276241
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,54 @@
|
||||
namespace Oculus.Platform.Samples.VrBoardGame
|
||||
{
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
public class GamePiece : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private Piece m_type = Piece.A;
|
||||
|
||||
// Prefab for the game pieces
|
||||
[SerializeField] private GameObject m_prefabA = null;
|
||||
[SerializeField] private GameObject m_prefabB = null;
|
||||
[SerializeField] private GameObject m_prefabPower = null;
|
||||
|
||||
public enum Piece { A, B, PowerBall }
|
||||
|
||||
private BoardPosition m_position;
|
||||
|
||||
public Piece Type
|
||||
{
|
||||
get { return m_type; }
|
||||
}
|
||||
|
||||
public BoardPosition Position
|
||||
{
|
||||
get { return m_position; }
|
||||
set { m_position = value; }
|
||||
}
|
||||
|
||||
public GameObject Prefab
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (m_type)
|
||||
{
|
||||
case Piece.A: return m_prefabA;
|
||||
case Piece.B: return m_prefabB;
|
||||
default: return m_prefabPower;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public GameObject PrefabFor(Piece p)
|
||||
{
|
||||
switch (p)
|
||||
{
|
||||
case Piece.A: return m_prefabA;
|
||||
case Piece.B: return m_prefabB;
|
||||
default: return m_prefabPower;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4c243c46c5f7948488696c53b4fa9786
|
||||
timeCreated: 1542071393
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences:
|
||||
- m_prefabA: {instanceID: 0}
|
||||
- m_prefabB: {instanceID: 0}
|
||||
- m_prefabPower: {instanceID: 0}
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,97 @@
|
||||
namespace Oculus.Platform.Samples.VrBoardGame
|
||||
{
|
||||
using UnityEngine;
|
||||
using Oculus.Platform;
|
||||
using Oculus.Platform.Models;
|
||||
using UnityEngine.UI;
|
||||
|
||||
|
||||
// This class coordinates In-App-Purchases (IAP) for the application. Follow the
|
||||
// instructions in the Readme for setting up IAP on the Oculus Dashboard. Only
|
||||
// one consumable IAP item is used is the demo: the Power-Ball!
|
||||
public class IAPManager : MonoBehaviour
|
||||
{
|
||||
// the game controler to notify when the user purchaes more powerballs
|
||||
[SerializeField] private GameController m_gameController = null;
|
||||
|
||||
// where to record to display the current price for the IAP item
|
||||
[SerializeField] private Text m_priceText = null;
|
||||
|
||||
// purchasable IAP products we've configured on the Oculus Dashboard
|
||||
private const string CONSUMABLE_1 = "PowerballPack1";
|
||||
|
||||
void Start()
|
||||
{
|
||||
FetchProductPrices();
|
||||
FetchPurchasedProducts();
|
||||
}
|
||||
|
||||
// get the current price for the configured IAP item
|
||||
public void FetchProductPrices()
|
||||
{
|
||||
string[] skus = { CONSUMABLE_1 };
|
||||
IAP.GetProductsBySKU(skus).OnComplete(GetProductsBySKUCallback);
|
||||
}
|
||||
|
||||
void GetProductsBySKUCallback(Message<ProductList> msg)
|
||||
{
|
||||
if (msg.IsError)
|
||||
{
|
||||
PlatformManager.TerminateWithError(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (Product p in msg.GetProductList())
|
||||
{
|
||||
Debug.LogFormat("Product: sku:{0} name:{1} price:{2}", p.Sku, p.Name, p.FormattedPrice);
|
||||
if (p.Sku == CONSUMABLE_1)
|
||||
{
|
||||
m_priceText.text = p.FormattedPrice;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fetches the Durable purchased IAP items. should return none unless you are expanding the
|
||||
// to sample to include them.
|
||||
public void FetchPurchasedProducts()
|
||||
{
|
||||
IAP.GetViewerPurchases().OnComplete(GetViewerPurchasesCallback);
|
||||
}
|
||||
|
||||
void GetViewerPurchasesCallback(Message<PurchaseList> msg)
|
||||
{
|
||||
if (msg.IsError)
|
||||
{
|
||||
PlatformManager.TerminateWithError(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (Purchase p in msg.GetPurchaseList())
|
||||
{
|
||||
Debug.LogFormat("Purchased: sku:{0} granttime:{1} id:{2}", p.Sku, p.GrantTime, p.ID);
|
||||
}
|
||||
}
|
||||
|
||||
public void BuyPowerBallsPressed()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
m_gameController.AddPowerballs(1);
|
||||
#else
|
||||
IAP.LaunchCheckoutFlow(CONSUMABLE_1).OnComplete(LaunchCheckoutFlowCallback);
|
||||
#endif
|
||||
}
|
||||
|
||||
private void LaunchCheckoutFlowCallback(Message<Purchase> msg)
|
||||
{
|
||||
if (msg.IsError)
|
||||
{
|
||||
PlatformManager.TerminateWithError(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
Purchase p = msg.GetPurchase();
|
||||
Debug.Log("purchased " + p.Sku);
|
||||
m_gameController.AddPowerballs(3);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3e54f4e408fb12842b72b24ac5dcbcf6
|
||||
timeCreated: 1479423466
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,400 @@
|
||||
namespace Oculus.Platform.Samples.VrBoardGame
|
||||
{
|
||||
using UnityEngine;
|
||||
using Oculus.Platform;
|
||||
using Oculus.Platform.Models;
|
||||
using UnityEngine.UI;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using UnityEngine.Assertions;
|
||||
|
||||
// This classes uses the Oculus Matchmaking Service to find opponents of a similar
|
||||
// skill and play a match with them. A skill pool is used with the matchmaking pool
|
||||
// to coordinate the skill matching. Follow the instructions in the Readme to setup
|
||||
// the matchmaking pools.
|
||||
// The Datastore for the Room is used to communicate between the clients. This only
|
||||
// works for relatively simple games with tolerance for latency. For more complex
|
||||
// or realtime requirements, you'll want to use the Oculus.Platform.Net API.
|
||||
public class MatchmakingManager : MonoBehaviour
|
||||
{
|
||||
// GameController to notify about match completions or early endings
|
||||
[SerializeField] private GameController m_gameController = null;
|
||||
|
||||
// Text for the button that controls matchmaking
|
||||
[SerializeField] private Text m_matchButtonText = null;
|
||||
|
||||
// Test widget to render matmaking statistics
|
||||
[SerializeField] private Text m_infoText = null;
|
||||
|
||||
// name of the Quckmatch Pool configured on the Oculus Developer Dashboard
|
||||
// which is expected to have an associated skill pool
|
||||
private const string POOL = "VR_BOARD_GAME_POOL";
|
||||
|
||||
// the ID of the room for the current match
|
||||
private ulong m_matchRoom;
|
||||
|
||||
// opponent User data
|
||||
private User m_remotePlayer;
|
||||
|
||||
// last time we've received a room update
|
||||
private float m_lastUpdateTime;
|
||||
|
||||
// how long to wait before polling for updates
|
||||
private const float POLL_FREQUENCY = 30.0f;
|
||||
|
||||
private enum MatchRoomState { None, Queued, Configuring, MyTurn, RemoteTurn }
|
||||
|
||||
private MatchRoomState m_state;
|
||||
|
||||
void Start()
|
||||
{
|
||||
Matchmaking.SetMatchFoundNotificationCallback(MatchFoundCallback);
|
||||
Rooms.SetUpdateNotificationCallback(MatchmakingRoomUpdateCallback);
|
||||
|
||||
TransitionToState(MatchRoomState.None);
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
switch (m_state)
|
||||
{
|
||||
case MatchRoomState.Configuring:
|
||||
case MatchRoomState.MyTurn:
|
||||
case MatchRoomState.RemoteTurn:
|
||||
// if we're expecting an update form the remote player and we haven't
|
||||
// heard from them in a while, check the datastore just-in-case
|
||||
if (POLL_FREQUENCY < (Time.time - m_lastUpdateTime))
|
||||
{
|
||||
Debug.Log("Polling Room");
|
||||
m_lastUpdateTime = Time.time;
|
||||
Rooms.Get(m_matchRoom).OnComplete(MatchmakingRoomUpdateCallback);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void MatchButtonPressed()
|
||||
{
|
||||
switch (m_state)
|
||||
{
|
||||
case MatchRoomState.None:
|
||||
TransitionToState(MatchRoomState.Queued);
|
||||
break;
|
||||
|
||||
default:
|
||||
TransitionToState(MatchRoomState.None);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void EndMatch(int localScore, int remoteScore)
|
||||
{
|
||||
switch (m_state)
|
||||
{
|
||||
case MatchRoomState.MyTurn:
|
||||
case MatchRoomState.RemoteTurn:
|
||||
var myID = PlatformManager.MyID.ToString();
|
||||
var remoteID = m_remotePlayer.ID.ToString();
|
||||
var rankings = new Dictionary<string, int>();
|
||||
if (localScore > remoteScore)
|
||||
{
|
||||
rankings[myID] = 1;
|
||||
rankings[remoteID] = 2;
|
||||
}
|
||||
else if (localScore < remoteScore)
|
||||
{
|
||||
rankings[myID] = 2;
|
||||
rankings[remoteID] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
rankings[myID] = 1;
|
||||
rankings[remoteID] = 1;
|
||||
}
|
||||
|
||||
// since there is no secure server to simulate the game and report
|
||||
// verifiable results, each client needs to independently report their
|
||||
// results for the service to compate for inconsistencies
|
||||
Matchmaking.ReportResultsInsecure(m_matchRoom, rankings)
|
||||
.OnComplete(GenericErrorCheckCallback);
|
||||
break;
|
||||
}
|
||||
|
||||
TransitionToState(MatchRoomState.None);
|
||||
}
|
||||
|
||||
void OnApplicationQuit()
|
||||
{
|
||||
// be a good matchmaking citizen and leave any queue immediately
|
||||
Matchmaking.Cancel();
|
||||
if (m_matchRoom != 0)
|
||||
{
|
||||
Rooms.Leave(m_matchRoom);
|
||||
}
|
||||
}
|
||||
|
||||
private void TransitionToState(MatchRoomState state)
|
||||
{
|
||||
var m_oldState = m_state;
|
||||
m_state = state;
|
||||
|
||||
switch (m_state)
|
||||
{
|
||||
case MatchRoomState.None:
|
||||
m_matchButtonText.text = "Find Match";
|
||||
// the player can abort from any of the other states to the None state
|
||||
// so we need to be careful to clean up all state variables
|
||||
m_remotePlayer = null;
|
||||
Matchmaking.Cancel();
|
||||
if (m_matchRoom != 0)
|
||||
{
|
||||
Rooms.Leave(m_matchRoom);
|
||||
m_matchRoom = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case MatchRoomState.Queued:
|
||||
Assert.AreEqual(MatchRoomState.None, m_oldState);
|
||||
m_matchButtonText.text = "Leave Queue";
|
||||
Matchmaking.Enqueue2(POOL).OnComplete(MatchmakingEnqueueCallback);
|
||||
break;
|
||||
|
||||
case MatchRoomState.Configuring:
|
||||
Assert.AreEqual(MatchRoomState.Queued, m_oldState);
|
||||
m_matchButtonText.text = "Cancel Match";
|
||||
break;
|
||||
|
||||
case MatchRoomState.MyTurn:
|
||||
case MatchRoomState.RemoteTurn:
|
||||
Assert.AreNotEqual(MatchRoomState.None, m_oldState);
|
||||
Assert.AreNotEqual(MatchRoomState.Queued, m_oldState);
|
||||
m_matchButtonText.text = "Cancel Match";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void MatchmakingEnqueueCallback(Message untyped_msg)
|
||||
{
|
||||
if (untyped_msg.IsError)
|
||||
{
|
||||
Debug.Log(untyped_msg.GetError().Message);
|
||||
TransitionToState(MatchRoomState.None);
|
||||
return;
|
||||
}
|
||||
|
||||
Message<MatchmakingEnqueueResult> msg = (Message<MatchmakingEnqueueResult>)untyped_msg;
|
||||
MatchmakingEnqueueResult info = msg.Data;
|
||||
m_infoText.text = string.Format(
|
||||
"Avg Wait Time: {0}s\n" +
|
||||
"Max Expected Wait: {1}s\n" +
|
||||
"In Last Hour: {2}\n" +
|
||||
"Recent Percentage: {3}%",
|
||||
info.AverageWait, info.MaxExpectedWait, info.MatchesInLastHourCount,
|
||||
info.RecentMatchPercentage);
|
||||
}
|
||||
|
||||
void MatchFoundCallback(Message<Room> msg)
|
||||
{
|
||||
if (msg.IsError)
|
||||
{
|
||||
Debug.Log(msg.GetError().Message);
|
||||
TransitionToState(MatchRoomState.None);
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_state != MatchRoomState.Queued)
|
||||
{
|
||||
// ignore callback - user already cancelled
|
||||
return;
|
||||
}
|
||||
|
||||
// since this example communicates via updates to the datastore, it's vital that
|
||||
// we subscribe to room updates
|
||||
Matchmaking.JoinRoom(msg.Data.ID, true /* subscribe to update notifications */)
|
||||
.OnComplete(MatchmakingJoinRoomCallback);
|
||||
m_matchRoom = msg.Data.ID;
|
||||
}
|
||||
|
||||
void MatchmakingJoinRoomCallback(Message<Room> msg)
|
||||
{
|
||||
if (msg.IsError)
|
||||
{
|
||||
Debug.Log(msg.GetError().Message);
|
||||
TransitionToState(MatchRoomState.None);
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_state != MatchRoomState.Queued)
|
||||
{
|
||||
// ignore callback - user already cancelled
|
||||
return;
|
||||
}
|
||||
|
||||
int numUsers = (msg.Data.UsersOptional != null) ? msg.Data.UsersOptional.Count : 0;
|
||||
Debug.Log ("Match room joined: " + m_matchRoom + " count: " + numUsers);
|
||||
|
||||
TransitionToState(MatchRoomState.Configuring);
|
||||
|
||||
// only process the room data if the other user has already joined
|
||||
if (msg.Data.UsersOptional != null && msg.Data.UsersOptional.Count == 2)
|
||||
{
|
||||
ProcessRoomData(msg.Data);
|
||||
}
|
||||
}
|
||||
|
||||
// Room Datastore updates are used to send moves between players. So if the MatchRoomState
|
||||
// is RemoteTurn I'm looking for the other player's move in the Datastore. If the
|
||||
// MatchRoomState is MyTurn I'm waiting for the room ownership to change so that
|
||||
// I have authority to write to the datastore.
|
||||
void MatchmakingRoomUpdateCallback(Message<Room> msg)
|
||||
{
|
||||
if (msg.IsError)
|
||||
{
|
||||
Debug.Log(msg.GetError().Message);
|
||||
TransitionToState(MatchRoomState.None);
|
||||
return;
|
||||
}
|
||||
|
||||
string ownerOculusID = msg.Data.OwnerOptional != null ? msg.Data.OwnerOptional.OculusID : "";
|
||||
int numUsers = (msg.Data.UsersOptional != null) ? msg.Data.UsersOptional.Count : 0;
|
||||
|
||||
Debug.LogFormat(
|
||||
"Room Update {0}\n" +
|
||||
" Owner {1}\n" +
|
||||
" User Count {2}\n" +
|
||||
" Datastore Count {3}\n",
|
||||
msg.Data.ID, ownerOculusID, numUsers, msg.Data.DataStore.Count);
|
||||
|
||||
// check to make sure the room is valid as there are a few odd timing issues (for
|
||||
// example when leaving a room) that can trigger an uninteresting update
|
||||
if (msg.Data.ID != m_matchRoom)
|
||||
{
|
||||
Debug.Log("Unexpected room update from: " + msg.Data.ID);
|
||||
return;
|
||||
}
|
||||
|
||||
ProcessRoomData(msg.Data);
|
||||
}
|
||||
|
||||
private void ProcessRoomData(Room room)
|
||||
{
|
||||
m_lastUpdateTime = Time.time;
|
||||
|
||||
if (m_state == MatchRoomState.Configuring)
|
||||
{
|
||||
// get the User info for the other player
|
||||
if (room.UsersOptional != null)
|
||||
{
|
||||
foreach (var user in room.UsersOptional)
|
||||
{
|
||||
if (PlatformManager.MyID != user.ID)
|
||||
{
|
||||
Debug.Log("Found remote user: " + user.OculusID);
|
||||
m_remotePlayer = user;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_remotePlayer == null)
|
||||
return;
|
||||
|
||||
bool i_go_first = DoesLocalUserGoFirst();
|
||||
TransitionToState(i_go_first ? MatchRoomState.MyTurn : MatchRoomState.RemoteTurn);
|
||||
Matchmaking.StartMatch(m_matchRoom).OnComplete(GenericErrorCheckCallback);
|
||||
m_gameController.StartOnlineMatch(m_remotePlayer.OculusID, i_go_first);
|
||||
}
|
||||
|
||||
// if it's the remote player's turn, look for their move in the datastore
|
||||
if (m_state == MatchRoomState.RemoteTurn &&
|
||||
room.DataStore.ContainsKey(m_remotePlayer.OculusID) &&
|
||||
room.DataStore[m_remotePlayer.OculusID] != "")
|
||||
{
|
||||
// process remote move
|
||||
ProcessRemoteMove(room.DataStore[m_remotePlayer.OculusID]);
|
||||
TransitionToState(MatchRoomState.MyTurn);
|
||||
}
|
||||
|
||||
// If the room ownership transferred to me, we can mark the remote turn complete.
|
||||
// We don't do this when the remote move comes in if we aren't yet the owner because
|
||||
// the local user will not be able to write to the datastore if they aren't the
|
||||
// owner of the room.
|
||||
if (m_state == MatchRoomState.MyTurn && room.OwnerOptional != null && room.OwnerOptional.ID == PlatformManager.MyID)
|
||||
{
|
||||
m_gameController.MarkRemoteTurnComplete();
|
||||
}
|
||||
|
||||
if (room.UsersOptional == null || (room.UsersOptional != null && room.UsersOptional.Count != 2))
|
||||
{
|
||||
Debug.Log("Other user quit the room");
|
||||
m_gameController.RemoteMatchEnded();
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessRemoteMove(string moveString)
|
||||
{
|
||||
Debug.Log("Processing remote move string: " + moveString);
|
||||
string[] tokens = moveString.Split(':');
|
||||
|
||||
GamePiece.Piece piece = (GamePiece.Piece)Enum.Parse(typeof(GamePiece.Piece), tokens[0]);
|
||||
int x = Int32.Parse(tokens[1]);
|
||||
int y = Int32.Parse(tokens[2]);
|
||||
|
||||
// swap the coordinates since each player assumes they are player 0
|
||||
x = GameBoard.LENGTH_X-1 - x;
|
||||
y = GameBoard.LENGTH_Y-1 - y;
|
||||
|
||||
m_gameController.MakeRemoteMove(piece, x, y);
|
||||
}
|
||||
|
||||
public void SendLocalMove(GamePiece.Piece piece, int boardX, int boardY)
|
||||
{
|
||||
string moveString = string.Format("{0}:{1}:{2}", piece.ToString(), boardX, boardY);
|
||||
Debug.Log("Sending move: " + moveString);
|
||||
|
||||
var dict = new Dictionary<string, string>();
|
||||
dict[PlatformManager.MyOculusID] = moveString;
|
||||
dict[m_remotePlayer.OculusID] = "";
|
||||
|
||||
Rooms.UpdateDataStore(m_matchRoom, dict).OnComplete(UpdateDataStoreCallback);
|
||||
TransitionToState(MatchRoomState.RemoteTurn);
|
||||
}
|
||||
|
||||
private void UpdateDataStoreCallback(Message<Room> msg)
|
||||
{
|
||||
if (m_state != MatchRoomState.RemoteTurn)
|
||||
{
|
||||
// ignore calback - user already quit the match
|
||||
return;
|
||||
}
|
||||
|
||||
// after I've updated the datastore with my move, change ownership so the other
|
||||
// user can perform their move
|
||||
Rooms.UpdateOwner(m_matchRoom, m_remotePlayer.ID);
|
||||
}
|
||||
|
||||
// deterministic but somewhat random selection for who goes first
|
||||
private bool DoesLocalUserGoFirst()
|
||||
{
|
||||
// if the room ID is even, the lower ID goes first
|
||||
if (m_matchRoom % 2 == 0)
|
||||
{
|
||||
return PlatformManager.MyID < m_remotePlayer.ID;
|
||||
}
|
||||
// otherwise the higher ID goes first
|
||||
{
|
||||
return PlatformManager.MyID > m_remotePlayer.ID;
|
||||
}
|
||||
}
|
||||
|
||||
private void GenericErrorCheckCallback(Message msg)
|
||||
{
|
||||
if (msg.IsError)
|
||||
{
|
||||
Debug.Log(msg.GetError().Message);
|
||||
TransitionToState(MatchRoomState.None);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e4f7411db9bf50545a8b0b3c5b3c1ff8
|
||||
timeCreated: 1479421035
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,113 @@
|
||||
namespace Oculus.Platform.Samples.VrBoardGame
|
||||
{
|
||||
using UnityEngine;
|
||||
using Oculus.Platform;
|
||||
using Oculus.Platform.Models;
|
||||
|
||||
// Top level class for initializing the Oculus Platform SDK. It also performs
|
||||
// and entitlement check and returns information about the logged-in user.
|
||||
public class PlatformManager : MonoBehaviour
|
||||
{
|
||||
private static PlatformManager s_instance;
|
||||
|
||||
// my Application-scoped Oculus ID
|
||||
private ulong m_myID;
|
||||
|
||||
// my Oculus user name
|
||||
private string m_myOculusID;
|
||||
|
||||
#region Initialization and Shutdown
|
||||
|
||||
void Awake()
|
||||
{
|
||||
// make sure only one instance of this manager ever exists
|
||||
if (s_instance != null)
|
||||
{
|
||||
Destroy(gameObject);
|
||||
return;
|
||||
}
|
||||
|
||||
s_instance = this;
|
||||
DontDestroyOnLoad(gameObject);
|
||||
|
||||
Core.Initialize();
|
||||
}
|
||||
|
||||
void Start()
|
||||
{
|
||||
// First thing we should do is perform an entitlement check to make sure
|
||||
// we successfully connected to the Oculus Platform Service.
|
||||
Entitlements.IsUserEntitledToApplication().OnComplete(IsEntitledCallback);
|
||||
}
|
||||
|
||||
void IsEntitledCallback(Message msg)
|
||||
{
|
||||
if (msg.IsError)
|
||||
{
|
||||
TerminateWithError(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
// Next get the identity of the user that launched the Application.
|
||||
Users.GetLoggedInUser().OnComplete(GetLoggedInUserCallback);
|
||||
}
|
||||
|
||||
void GetLoggedInUserCallback(Message<User> msg)
|
||||
{
|
||||
if (msg.IsError)
|
||||
{
|
||||
TerminateWithError(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
m_myID = msg.Data.ID;
|
||||
m_myOculusID = msg.Data.OculusID;
|
||||
|
||||
Debug.Log(" I am " + m_myOculusID);
|
||||
}
|
||||
|
||||
// In this example, for most errors, we terminate the Application. A full App would do
|
||||
// something more graceful.
|
||||
public static void TerminateWithError(Message msg)
|
||||
{
|
||||
Debug.Log("Error: " + msg.GetError().Message);
|
||||
UnityEngine.Application.Quit();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
public static ulong MyID
|
||||
{
|
||||
get
|
||||
{
|
||||
if (s_instance != null)
|
||||
{
|
||||
return s_instance.m_myID;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string MyOculusID
|
||||
{
|
||||
get
|
||||
{
|
||||
if (s_instance != null && s_instance.m_myOculusID != null)
|
||||
{
|
||||
return s_instance.m_myOculusID;
|
||||
}
|
||||
else
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 46b8fed8b150a8c4688eae89457bd466
|
||||
timeCreated: 1479414194
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Oculus/Platform/Samples/VrHoops.meta
Normal file
8
Assets/Oculus/Platform/Samples/VrHoops.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 99e052b981df6064b9eb1fd9b7a7a139
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,13 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!134 &13400000
|
||||
PhysicMaterial:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 0}
|
||||
m_Name: Bouncey
|
||||
dynamicFriction: 0.5
|
||||
staticFriction: 0.6
|
||||
bounciness: 0.7
|
||||
frictionCombine: 0
|
||||
bounceCombine: 3
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b9c664160cb7a724d9777a6ad6222a28
|
||||
timeCreated: 1474424965
|
||||
licenseType: Store
|
||||
NativeFormatImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
4650
Assets/Oculus/Platform/Samples/VrHoops/Main.unity
Normal file
4650
Assets/Oculus/Platform/Samples/VrHoops/Main.unity
Normal file
File diff suppressed because it is too large
Load Diff
8
Assets/Oculus/Platform/Samples/VrHoops/Main.unity.meta
Normal file
8
Assets/Oculus/Platform/Samples/VrHoops/Main.unity.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8b67239c8d8693441abb62a2ac48f571
|
||||
timeCreated: 1474427891
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Oculus/Platform/Samples/VrHoops/Prefabs.meta
Normal file
8
Assets/Oculus/Platform/Samples/VrHoops/Prefabs.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e0704a47c7ee6de4c9886daac1eadebd
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
123
Assets/Oculus/Platform/Samples/VrHoops/Prefabs/Ball.prefab
Normal file
123
Assets/Oculus/Platform/Samples/VrHoops/Prefabs/Ball.prefab
Normal file
@@ -0,0 +1,123 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1001 &100100000
|
||||
Prefab:
|
||||
m_ObjectHideFlags: 1
|
||||
serializedVersion: 2
|
||||
m_Modification:
|
||||
m_TransformParent: {fileID: 0}
|
||||
m_Modifications: []
|
||||
m_RemovedComponents: []
|
||||
m_ParentPrefab: {fileID: 0}
|
||||
m_RootGameObject: {fileID: 1000012825293744}
|
||||
m_IsPrefabParent: 1
|
||||
--- !u!1 &1000012825293744
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
serializedVersion: 5
|
||||
m_Component:
|
||||
- component: {fileID: 4000014042746218}
|
||||
- component: {fileID: 33000010642644700}
|
||||
- component: {fileID: 23000012964101304}
|
||||
- component: {fileID: 54000011667893522}
|
||||
- component: {fileID: 135000010694715800}
|
||||
- component: {fileID: 114000014063321366}
|
||||
m_Layer: 0
|
||||
m_Name: Ball
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &4000014042746218
|
||||
Transform:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 1000012825293744}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 16.53, y: 8.74, z: 6.33}
|
||||
m_LocalScale: {x: 0.73585784, y: 0.73585784, z: 0.73585784}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!23 &23000012964101304
|
||||
MeshRenderer:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 1000012825293744}
|
||||
m_Enabled: 1
|
||||
m_CastShadows: 1
|
||||
m_ReceiveShadows: 1
|
||||
m_MotionVectors: 1
|
||||
m_LightProbeUsage: 1
|
||||
m_ReflectionProbeUsage: 1
|
||||
m_Materials:
|
||||
- {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_StaticBatchInfo:
|
||||
firstSubMesh: 0
|
||||
subMeshCount: 0
|
||||
m_StaticBatchRoot: {fileID: 0}
|
||||
m_ProbeAnchor: {fileID: 0}
|
||||
m_LightProbeVolumeOverride: {fileID: 0}
|
||||
m_ScaleInLightmap: 1
|
||||
m_PreserveUVs: 1
|
||||
m_IgnoreNormalsForChartDetection: 0
|
||||
m_ImportantGI: 0
|
||||
m_SelectedEditorRenderState: 3
|
||||
m_MinimumChartSize: 4
|
||||
m_AutoUVMaxDistance: 0.5
|
||||
m_AutoUVMaxAngle: 89
|
||||
m_LightmapParameters: {fileID: 0}
|
||||
m_SortingLayerID: 0
|
||||
m_SortingLayer: 0
|
||||
m_SortingOrder: 0
|
||||
--- !u!33 &33000010642644700
|
||||
MeshFilter:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 1000012825293744}
|
||||
m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0}
|
||||
--- !u!54 &54000011667893522
|
||||
Rigidbody:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 1000012825293744}
|
||||
serializedVersion: 2
|
||||
m_Mass: 15
|
||||
m_Drag: 0.47
|
||||
m_AngularDrag: 0
|
||||
m_UseGravity: 0
|
||||
m_IsKinematic: 0
|
||||
m_Interpolate: 0
|
||||
m_Constraints: 0
|
||||
m_CollisionDetection: 0
|
||||
--- !u!114 &114000014063321366
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 1000012825293744}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: a63d0cd5dd6d39a4abd35114563fe347, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
--- !u!135 &135000010694715800
|
||||
SphereCollider:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 1000012825293744}
|
||||
m_Material: {fileID: 13400000, guid: b9c664160cb7a724d9777a6ad6222a28, type: 2}
|
||||
m_IsTrigger: 0
|
||||
m_Enabled: 1
|
||||
serializedVersion: 2
|
||||
m_Radius: 0.5
|
||||
m_Center: {x: 0, y: 0, z: 0}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 73ea9d6c6c3480147ba658fc59d0afa4
|
||||
timeCreated: 1474514953
|
||||
licenseType: Store
|
||||
NativeFormatImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,99 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1001 &100100000
|
||||
Prefab:
|
||||
m_ObjectHideFlags: 1
|
||||
serializedVersion: 2
|
||||
m_Modification:
|
||||
m_TransformParent: {fileID: 0}
|
||||
m_Modifications: []
|
||||
m_RemovedComponents: []
|
||||
m_ParentPrefab: {fileID: 0}
|
||||
m_RootGameObject: {fileID: 1000011449472940}
|
||||
m_IsPrefabParent: 1
|
||||
--- !u!1 &1000011449472940
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
serializedVersion: 5
|
||||
m_Component:
|
||||
- component: {fileID: 224000013885566140}
|
||||
- component: {fileID: 222000012566199212}
|
||||
- component: {fileID: 114000010273600920}
|
||||
- component: {fileID: 114000010103236586}
|
||||
m_Layer: 0
|
||||
m_Name: FlyText
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!114 &114000010103236586
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 1000011449472940}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: dc96f5380d7d743d9ae91f11379eb85b, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
--- !u!114 &114000010273600920
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 1000011449472940}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 708705254, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 0.93003374, g: 0.9852941, b: 0.41295412, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
|
||||
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
m_FontData:
|
||||
m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
|
||||
m_FontSize: 20
|
||||
m_FontStyle: 0
|
||||
m_BestFit: 0
|
||||
m_MinSize: 2
|
||||
m_MaxSize: 40
|
||||
m_Alignment: 4
|
||||
m_AlignByGeometry: 0
|
||||
m_RichText: 1
|
||||
m_HorizontalOverflow: 0
|
||||
m_VerticalOverflow: 0
|
||||
m_LineSpacing: 1
|
||||
m_Text: Likes to Win!
|
||||
--- !u!222 &222000012566199212
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 1000011449472940}
|
||||
--- !u!224 &224000013885566140
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 1000011449472940}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 160, y: 30}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bb4775eb616604e329b92c1b4dfbaa5f
|
||||
timeCreated: 1477081828
|
||||
licenseType: Store
|
||||
NativeFormatImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,106 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1001 &100100000
|
||||
Prefab:
|
||||
m_ObjectHideFlags: 1
|
||||
serializedVersion: 2
|
||||
m_Modification:
|
||||
m_TransformParent: {fileID: 0}
|
||||
m_Modifications: []
|
||||
m_RemovedComponents: []
|
||||
m_ParentPrefab: {fileID: 0}
|
||||
m_RootGameObject: {fileID: 1000012172119028}
|
||||
m_IsPrefabParent: 1
|
||||
--- !u!1 &1000012172119028
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
serializedVersion: 5
|
||||
m_Component:
|
||||
- component: {fileID: 224000013400680178}
|
||||
- component: {fileID: 222000013258767294}
|
||||
- component: {fileID: 114000010166173948}
|
||||
- component: {fileID: 114000010432752000}
|
||||
m_Layer: 5
|
||||
m_Name: LeaderboardText
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!114 &114000010166173948
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 1000012172119028}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 708705254, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 0.8301217, g: 0.8161765, b: 1, a: 1}
|
||||
m_RaycastTarget: 0
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
|
||||
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
m_FontData:
|
||||
m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
|
||||
m_FontSize: 30
|
||||
m_FontStyle: 0
|
||||
m_BestFit: 1
|
||||
m_MinSize: 3
|
||||
m_MaxSize: 40
|
||||
m_Alignment: 3
|
||||
m_AlignByGeometry: 0
|
||||
m_RichText: 0
|
||||
m_HorizontalOverflow: 1
|
||||
m_VerticalOverflow: 0
|
||||
m_LineSpacing: 1
|
||||
m_Text: ' '
|
||||
--- !u!114 &114000010432752000
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 1000012172119028}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 1679637790, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_IgnoreLayout: 0
|
||||
m_MinWidth: -1
|
||||
m_MinHeight: 30
|
||||
m_PreferredWidth: -1
|
||||
m_PreferredHeight: 30
|
||||
m_FlexibleWidth: 1
|
||||
m_FlexibleHeight: -1
|
||||
--- !u!222 &222000013258767294
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 1000012172119028}
|
||||
--- !u!224 &224000013400680178
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 1000012172119028}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 09fc1e67c860e68488d20df60c04cb2a
|
||||
timeCreated: 1476930368
|
||||
licenseType: Store
|
||||
NativeFormatImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
1739
Assets/Oculus/Platform/Samples/VrHoops/Prefabs/PlayerArea.prefab
Normal file
1739
Assets/Oculus/Platform/Samples/VrHoops/Prefabs/PlayerArea.prefab
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cf3f39c980574304d8f8817cd3dfa941
|
||||
timeCreated: 1475179794
|
||||
licenseType: Store
|
||||
NativeFormatImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
71
Assets/Oculus/Platform/Samples/VrHoops/Readme.md
Normal file
71
Assets/Oculus/Platform/Samples/VrHoops/Readme.md
Normal file
@@ -0,0 +1,71 @@
|
||||
# Overview
|
||||
|
||||
This example uses basic Quickmatch and Peer-to-Peer networking to creating a cross-platform ball shooting game.
|
||||
Quickmatch is used to find other players for a match and Networking is used to synchronize player
|
||||
state such as movement of the balls.
|
||||
|
||||
# Application Setup
|
||||
|
||||
1. Open the Project in Unity 5.4.1p1 or later
|
||||
2. Import the OculusPlatform Unity package (Main Menu -> Assets -> Import Package -> Custom Package)
|
||||
|
||||
## Rift
|
||||
1. Create your Rift application on the Oculus Developer Dashboard
|
||||
2. Copy the Application ID into the Project (Main Menu -> Oculus Platform -> Edit Settings -> Oculus Rift App Id)
|
||||
|
||||
## GearVR
|
||||
1. Create the GearVR application on the Oculus Developer Dashboard
|
||||
2. Move the GearVR application into the Rift application's App Grouping
|
||||
3. Copy the Application ID into the Project (Main Menu -> Oculus Platform -> Edit Settings -> Gear VR App Id)
|
||||
4. Copy the OSIG files for the GearVR devices you are testing to Assets\Plugins\Android\Assets
|
||||
|
||||
# Configure Matchmaking
|
||||
|
||||
1. On the Oculus Dashboard, navigate to the Matchmaking section for your App Grouping
|
||||
2. Click Create Pool
|
||||
3. For the Pool Key use: NORMAL_QUICKMATCH, or if you want to use a different Pool Key, update the constant in MatchmakingManager.cs
|
||||
4. Choose Quickmatch mode
|
||||
5. Enter 2 for Min Users and 3 for Max Users
|
||||
6. Choose None for Skill Pool
|
||||
7. Leave Advanced Quickmatch set to No
|
||||
8. Leave Should Consider Ping Time? at the default setting of No
|
||||
9. Don't add anything under Data Settings
|
||||
10. Click Submit.
|
||||
|
||||
# Configure Leaderboards
|
||||
|
||||
This sample uses two Leaderboards to track player scores. One leaderboard tracks the player that has
|
||||
won the most games and another tracks who achieved the highest score in a single game. Setup the leaderboards
|
||||
using the following steps:
|
||||
|
||||
1. Navigate to your App Grouping section on the Developer Dashboard
|
||||
2. Create a new leadername with the API NAME **MOST_MATCHES_WON** and sort order **Higher is Better**
|
||||
3. Create a new leadername with the API NAME **HIGHEST_MATCH_SCORE** and sort order **Higher is Better**
|
||||
|
||||
# Configure Achievements
|
||||
|
||||
The sample updates an achievement that counts the number of times a player has won. Follow these steps to create an
|
||||
achievement that is unlocked when the player has won 10 matches:
|
||||
|
||||
1. Navigate to your App Grouping section on the Developer Dashboard
|
||||
2. Click on the **Create Achievement** button
|
||||
3. Set the API Name to **LIKES_TO_WIN**
|
||||
4. Set an appropriate Title and Description
|
||||
5. Leave the Write Policy as **CLIENT_AUTHORITATIVE**
|
||||
6. Leave Is Achievement Secret untoggled
|
||||
7. Set the Type to **Count**
|
||||
7. Set the Target to *10*
|
||||
|
||||
# Upload your builds
|
||||
|
||||
Build executables from Unity and upload them to your Application Dashboard
|
||||
* Rift
|
||||
1. Add the executable and data folder to a zip file
|
||||
2. Upload the zip to the Alpha channel on your Dashboard
|
||||
3. Set the executable name you chose in the zip file
|
||||
4. Add Friends you are testing with as Subscribed Users for the Alpha channel
|
||||
* GearVR
|
||||
1. Create an android keystore (if you don't have one) so Unity can sign the build. (Player Settings -> Publishing Settings)
|
||||
2. Upload the apk to the Alpha channel on your Dashboard
|
||||
3. Each apk you upload needs a new build number (Player Settings -> Other Settings)
|
||||
4. Add Friends you are testing with as Subscribed Users for the Alpha channel
|
||||
7
Assets/Oculus/Platform/Samples/VrHoops/Readme.md.meta
Normal file
7
Assets/Oculus/Platform/Samples/VrHoops/Readme.md.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a3c974875a2ea724e93b6e5114bca96f
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Oculus/Platform/Samples/VrHoops/Scripts.meta
Normal file
8
Assets/Oculus/Platform/Samples/VrHoops/Scripts.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c2c4feba7e20a244c835a28919f973b1
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
25
Assets/Oculus/Platform/Samples/VrHoops/Scripts/AIPlayer.cs
Normal file
25
Assets/Oculus/Platform/Samples/VrHoops/Scripts/AIPlayer.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
namespace Oculus.Platform.Samples.VrHoops
|
||||
{
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
// An AI Player just shoots a ball forward with some random delay.
|
||||
public class AIPlayer : Player {
|
||||
|
||||
void FixedUpdate ()
|
||||
{
|
||||
if (HasBall)
|
||||
{
|
||||
// add a little randomness to the shoot rate so the AI's don't look synchronized
|
||||
if (Random.Range(0f, 1f) < 0.03f)
|
||||
{
|
||||
ShootBall();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CheckSpawnBall();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 71702635af79217469ed41ba39db8d5a
|
||||
timeCreated: 1475264776
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,43 @@
|
||||
namespace Oculus.Platform.Samples.VrHoops
|
||||
{
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using Oculus.Platform;
|
||||
using Oculus.Platform.Models;
|
||||
|
||||
public class AchievementsManager
|
||||
{
|
||||
// API NAME defined on the dashboard for the achievement
|
||||
private const string LIKES_TO_WIN = "LIKES_TO_WIN";
|
||||
|
||||
// true if the local user hit the achievement Count setup on the dashboard
|
||||
private bool m_likesToWinUnlocked;
|
||||
|
||||
public bool LikesToWin
|
||||
{
|
||||
get { return m_likesToWinUnlocked; }
|
||||
}
|
||||
|
||||
public void CheckForAchievmentUpdates()
|
||||
{
|
||||
Achievements.GetProgressByName(new string[]{ LIKES_TO_WIN }).OnComplete(
|
||||
(Message<AchievementProgressList> msg) =>
|
||||
{
|
||||
foreach (var achievement in msg.Data)
|
||||
{
|
||||
if (achievement.Name == LIKES_TO_WIN)
|
||||
{
|
||||
m_likesToWinUnlocked = achievement.IsUnlocked;
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public void RecordWinForLocalUser()
|
||||
{
|
||||
Achievements.AddCount(LIKES_TO_WIN, 1);
|
||||
CheckForAchievmentUpdates();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 66d441ddf01234331b50e929139f4780
|
||||
timeCreated: 1477071923
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace Oculus.Platform.Samples.VrHoops
|
||||
{
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
public class BallEjector : MonoBehaviour {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b4164fa75939f1e46a3e36dfbdc7f821
|
||||
timeCreated: 1474514990
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,23 @@
|
||||
namespace Oculus.Platform.Samples.VrHoops
|
||||
{
|
||||
using UnityEngine;
|
||||
|
||||
// Helper class to attach to the MainCamera so it can be moved with the mouse while debugging
|
||||
// in 2D mode on a PC.
|
||||
public class Camera2DController : MonoBehaviour
|
||||
{
|
||||
void Update ()
|
||||
{
|
||||
if (Input.GetButton("Fire2"))
|
||||
{
|
||||
var v = Input.GetAxis("Mouse Y");
|
||||
var h = Input.GetAxis("Mouse X");
|
||||
transform.rotation *= Quaternion.AngleAxis(h, Vector3.up);
|
||||
transform.rotation *= Quaternion.AngleAxis(-v, Vector3.right);
|
||||
Vector3 eulers = transform.eulerAngles;
|
||||
eulers.z = 0;
|
||||
transform.eulerAngles = eulers;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7ebf96caaf397684b86c4ff4d566798f
|
||||
timeCreated: 1474514266
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,64 @@
|
||||
namespace Oculus.Platform.Samples.VrHoops
|
||||
{
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
// Uses two triggers to detect that a basket is made by traveling from top to bottom
|
||||
// through the hoop.
|
||||
public class DetectBasket : MonoBehaviour
|
||||
{
|
||||
private enum BasketPhase { NONE, TOP, BOTH, BOTTOM }
|
||||
|
||||
private BasketPhase m_phase = BasketPhase.NONE;
|
||||
|
||||
private Player m_owningPlayer;
|
||||
|
||||
public Player Player
|
||||
{
|
||||
set { m_owningPlayer = value; }
|
||||
}
|
||||
|
||||
void OnTriggerEnter(Collider other)
|
||||
{
|
||||
if (other.gameObject.name == "Basket Top" && m_phase == BasketPhase.NONE)
|
||||
{
|
||||
m_phase = BasketPhase.TOP;
|
||||
}
|
||||
else if (other.gameObject.name == "Basket Bottom" && m_phase == BasketPhase.TOP)
|
||||
{
|
||||
m_phase = BasketPhase.BOTH;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_phase = BasketPhase.NONE;
|
||||
}
|
||||
}
|
||||
|
||||
void OnTriggerExit(Collider other)
|
||||
{
|
||||
if (other.gameObject.name == "Basket Top" && m_phase == BasketPhase.BOTH)
|
||||
{
|
||||
m_phase = BasketPhase.BOTTOM;
|
||||
}
|
||||
else if (other.gameObject.name == "Basket Bottom" && m_phase == BasketPhase.BOTTOM)
|
||||
{
|
||||
m_phase = BasketPhase.NONE;
|
||||
|
||||
switch (PlatformManager.CurrentState)
|
||||
{
|
||||
case PlatformManager.State.PLAYING_A_LOCAL_MATCH:
|
||||
case PlatformManager.State.PLAYING_A_NETWORKED_MATCH:
|
||||
if (m_owningPlayer)
|
||||
{
|
||||
m_owningPlayer.Score += 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_phase = BasketPhase.NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a63d0cd5dd6d39a4abd35114563fe347
|
||||
timeCreated: 1475105001
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
37
Assets/Oculus/Platform/Samples/VrHoops/Scripts/FlyText.cs
Normal file
37
Assets/Oculus/Platform/Samples/VrHoops/Scripts/FlyText.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
namespace Oculus.Platform.Samples.VrHoops
|
||||
{
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using System.Collections;
|
||||
|
||||
// helper script to render fading flytext above an object
|
||||
public class FlyText : MonoBehaviour
|
||||
{
|
||||
// destory the gameobject after this many seconds
|
||||
private const float LIFESPAN = 3.0f;
|
||||
|
||||
// how far to move upwards per frame
|
||||
private readonly Vector3 m_movePerFrame = 0.5f * Vector3.up;
|
||||
|
||||
// actual destruction time
|
||||
private float m_eol;
|
||||
|
||||
void Start()
|
||||
{
|
||||
m_eol = Time.time + LIFESPAN;
|
||||
GetComponent<Text>().CrossFadeColor(Color.black, LIFESPAN * 1.7f, false, true);
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (Time.time < m_eol)
|
||||
{
|
||||
transform.localPosition += m_movePerFrame;
|
||||
}
|
||||
else
|
||||
{
|
||||
Destroy(gameObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dc96f5380d7d743d9ae91f11379eb85b
|
||||
timeCreated: 1477078886
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
84
Assets/Oculus/Platform/Samples/VrHoops/Scripts/GoalMover.cs
Normal file
84
Assets/Oculus/Platform/Samples/VrHoops/Scripts/GoalMover.cs
Normal file
@@ -0,0 +1,84 @@
|
||||
namespace Oculus.Platform.Samples.VrHoops
|
||||
{
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
// This script moves to goal around in a random direction to add a bit more difficulty
|
||||
// to the game.
|
||||
public class GoalMover : MonoBehaviour {
|
||||
|
||||
// how far to from the center before changing direction
|
||||
[SerializeField] private float MAX_OFFSET = 2.0f;
|
||||
|
||||
// how fast the backboard will move
|
||||
[SerializeField] private float m_speed = 0.005f;
|
||||
|
||||
// maximum interpolation distance allow to correct per update
|
||||
private const float MOVE_TOLERANCE = 0.1f;
|
||||
|
||||
// the position the goal should be in - only differs if network updates come in
|
||||
private Vector3 m_expectedPosition;
|
||||
|
||||
// the current move vector * m_speed;
|
||||
private Vector3 m_moveDirection;
|
||||
|
||||
// the direction to move when we run into the boundary
|
||||
private Vector3 m_nextMoveDirection;
|
||||
|
||||
public Vector3 ExpectedPosition
|
||||
{
|
||||
get { return m_expectedPosition; }
|
||||
set { m_expectedPosition = value; }
|
||||
}
|
||||
|
||||
public Vector3 MoveDirection
|
||||
{
|
||||
get { return m_moveDirection; }
|
||||
set { m_moveDirection = value; }
|
||||
}
|
||||
|
||||
public Vector3 NextMoveDirection
|
||||
{
|
||||
get { return m_nextMoveDirection; }
|
||||
set { m_nextMoveDirection = value; }
|
||||
}
|
||||
|
||||
void Start ()
|
||||
{
|
||||
ExpectedPosition = transform.localPosition;
|
||||
|
||||
m_moveDirection.x = Random.Range(-1.0f, 1.0f);
|
||||
m_moveDirection.y = Random.Range(-1.0f, 1.0f);
|
||||
m_moveDirection = Vector3.ClampMagnitude(m_moveDirection, m_speed);
|
||||
|
||||
m_nextMoveDirection.x = -Mathf.Sign(m_moveDirection.x) * Random.Range(0f, 1.0f);
|
||||
m_nextMoveDirection.y = -Mathf.Sign(m_moveDirection.y) * Random.Range(0f, 1.0f);
|
||||
m_nextMoveDirection = Vector3.ClampMagnitude(m_nextMoveDirection, m_speed);
|
||||
}
|
||||
|
||||
void FixedUpdate ()
|
||||
{
|
||||
// move a bit along our random direction
|
||||
transform.localPosition += MoveDirection;
|
||||
ExpectedPosition += MoveDirection;
|
||||
|
||||
// make a slight correction to the position if we're not where we should be
|
||||
Vector3 correction = ExpectedPosition - transform.localPosition;
|
||||
correction = Vector3.ClampMagnitude(correction, MOVE_TOLERANCE);
|
||||
transform.localPosition += correction;
|
||||
|
||||
// if we've gone too far from the center point, correct and change direction
|
||||
if (transform.localPosition.sqrMagnitude > (MAX_OFFSET*MAX_OFFSET))
|
||||
{
|
||||
transform.localPosition = Vector3.ClampMagnitude(transform.localPosition, MAX_OFFSET);
|
||||
ExpectedPosition = transform.localPosition;
|
||||
MoveDirection = NextMoveDirection;
|
||||
|
||||
// select a the next randomish direction to move in
|
||||
m_nextMoveDirection.x = -Mathf.Sign(m_moveDirection.x) * Random.Range(0f, 1.0f);
|
||||
m_nextMoveDirection.y = -Mathf.Sign(m_moveDirection.y) * Random.Range(0f, 1.0f);
|
||||
m_nextMoveDirection = Vector3.ClampMagnitude(m_nextMoveDirection, m_speed);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fbea2c3cb080a064f84d3bd86c2f3a53
|
||||
timeCreated: 1475173562
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,199 @@
|
||||
namespace Oculus.Platform.Samples.VrHoops
|
||||
{
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
using Oculus.Platform;
|
||||
using Oculus.Platform.Models;
|
||||
|
||||
// Coordinates updating leaderboard scores and polling for leaderboard updates.
|
||||
public class LeaderboardManager
|
||||
{
|
||||
// API NAME for the leaderboard where we store how many matches the user has won
|
||||
private const string MOST_MATCHES_WON = "MOST_MATCHES_WON";
|
||||
|
||||
// API NAME for the leaderboard where we store the user's match score
|
||||
private const string HIGHEST_MATCH_SCORE = "HIGHEST_MATCH_SCORE";
|
||||
|
||||
// the top number of entries to query
|
||||
private const int TOP_N_COUNT = 5;
|
||||
|
||||
// how often to poll the service for leaderboard updates
|
||||
private const float LEADERBOARD_POLL_FREQ = 30.0f;
|
||||
|
||||
// the next time to check for leaderboard updates
|
||||
private float m_nextCheckTime;
|
||||
|
||||
// cache to hold most-wins leaderboard entries as they come in
|
||||
private volatile SortedDictionary<int, LeaderboardEntry> m_mostWins;
|
||||
|
||||
// whether we've found the local user's entry yet
|
||||
private bool m_foundLocalUserMostWinsEntry;
|
||||
|
||||
// number of times the local user has won
|
||||
private long m_numWins;
|
||||
|
||||
// callback to deliver the most-wins leaderboard entries
|
||||
private OnMostWinsLeaderboardUpdated m_mostWinsCallback;
|
||||
|
||||
// cache to hold high-score leaderboard entries as they come in
|
||||
private volatile SortedDictionary<int, LeaderboardEntry> m_highScores;
|
||||
|
||||
// whether we've found the local user's entry yet
|
||||
private bool m_foundLocalUserHighScore;
|
||||
|
||||
// callback to deliver the high-scores leaderboard entries
|
||||
private OnHighScoreLeaderboardUpdated m_highScoreCallback;
|
||||
|
||||
public void CheckForUpdates()
|
||||
{
|
||||
if (Time.time >= m_nextCheckTime &&
|
||||
PlatformManager.CurrentState == PlatformManager.State.WAITING_TO_PRACTICE_OR_MATCHMAKE)
|
||||
{
|
||||
m_nextCheckTime = Time.time + LEADERBOARD_POLL_FREQ;
|
||||
|
||||
QueryMostWinsLeaderboard();
|
||||
QueryHighScoreLeaderboard();
|
||||
}
|
||||
}
|
||||
|
||||
#region Most Wins Leaderboard
|
||||
|
||||
public delegate void OnMostWinsLeaderboardUpdated(SortedDictionary<int, LeaderboardEntry> entries);
|
||||
|
||||
public OnMostWinsLeaderboardUpdated MostWinsLeaderboardUpdatedCallback
|
||||
{
|
||||
set { m_mostWinsCallback = value; }
|
||||
}
|
||||
|
||||
void QueryMostWinsLeaderboard()
|
||||
{
|
||||
// if a query is already in progress, don't start a new one.
|
||||
if (m_mostWins != null)
|
||||
return;
|
||||
|
||||
m_mostWins = new SortedDictionary<int, LeaderboardEntry>();
|
||||
m_foundLocalUserMostWinsEntry = false;
|
||||
|
||||
Leaderboards.GetEntries(MOST_MATCHES_WON, TOP_N_COUNT, LeaderboardFilterType.None,
|
||||
LeaderboardStartAt.Top).OnComplete(MostWinsGetEntriesCallback);
|
||||
}
|
||||
|
||||
void MostWinsGetEntriesCallback(Message<LeaderboardEntryList> msg)
|
||||
{
|
||||
if (!msg.IsError)
|
||||
{
|
||||
foreach (LeaderboardEntry entry in msg.Data)
|
||||
{
|
||||
m_mostWins[entry.Rank] = entry;
|
||||
|
||||
if (entry.User.ID == PlatformManager.MyID)
|
||||
{
|
||||
m_foundLocalUserMostWinsEntry = true;
|
||||
m_numWins = entry.Score;
|
||||
}
|
||||
}
|
||||
|
||||
// results might be paged for large requests
|
||||
if (msg.Data.HasNextPage)
|
||||
{
|
||||
Leaderboards.GetNextEntries(msg.Data).OnComplete(MostWinsGetEntriesCallback);
|
||||
return;
|
||||
}
|
||||
|
||||
// if local user not in the top, get their position specifically
|
||||
if (!m_foundLocalUserMostWinsEntry)
|
||||
{
|
||||
Leaderboards.GetEntries(MOST_MATCHES_WON, 1, LeaderboardFilterType.None,
|
||||
LeaderboardStartAt.CenteredOnViewer).OnComplete(MostWinsGetEntriesCallback);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// else an error is returned if the local player isn't ranked - we can ignore that
|
||||
|
||||
if (m_mostWinsCallback != null)
|
||||
{
|
||||
m_mostWinsCallback(m_mostWins);
|
||||
}
|
||||
m_mostWins = null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Highest Score Board
|
||||
|
||||
public delegate void OnHighScoreLeaderboardUpdated(SortedDictionary<int, LeaderboardEntry> entries);
|
||||
|
||||
public OnHighScoreLeaderboardUpdated HighScoreLeaderboardUpdatedCallback
|
||||
{
|
||||
set { m_highScoreCallback = value; }
|
||||
}
|
||||
|
||||
void QueryHighScoreLeaderboard()
|
||||
{
|
||||
// if a query is already in progress, don't start a new one.
|
||||
if (m_highScores != null)
|
||||
return;
|
||||
|
||||
m_highScores = new SortedDictionary<int, LeaderboardEntry>();
|
||||
m_foundLocalUserHighScore = false;
|
||||
|
||||
Leaderboards.GetEntries(HIGHEST_MATCH_SCORE, TOP_N_COUNT, LeaderboardFilterType.None,
|
||||
LeaderboardStartAt.Top).OnComplete(HighestScoreGetEntriesCallback);
|
||||
}
|
||||
|
||||
void HighestScoreGetEntriesCallback(Message<LeaderboardEntryList> msg)
|
||||
{
|
||||
if (!msg.IsError)
|
||||
{
|
||||
foreach (LeaderboardEntry entry in msg.Data)
|
||||
{
|
||||
m_highScores[entry.Rank] = entry;
|
||||
|
||||
if (entry.User.ID == PlatformManager.MyID)
|
||||
{
|
||||
m_foundLocalUserHighScore = true;
|
||||
}
|
||||
}
|
||||
|
||||
// results might be paged for large requests
|
||||
if (msg.Data.HasNextPage)
|
||||
{
|
||||
Leaderboards.GetNextEntries(msg.Data).OnComplete(HighestScoreGetEntriesCallback);;
|
||||
return;
|
||||
}
|
||||
|
||||
// if local user not in the top, get their position specifically
|
||||
if (!m_foundLocalUserHighScore)
|
||||
{
|
||||
Leaderboards.GetEntries(HIGHEST_MATCH_SCORE, 1, LeaderboardFilterType.None,
|
||||
LeaderboardStartAt.CenteredOnViewer).OnComplete(HighestScoreGetEntriesCallback);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// else an error is returned if the local player isn't ranked - we can ignore that
|
||||
|
||||
if (m_highScoreCallback != null)
|
||||
{
|
||||
m_highScoreCallback(m_highScores);
|
||||
}
|
||||
m_highScores = null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
// submit the local player's match score to the leaderboard service
|
||||
public void SubmitMatchScores(bool wonMatch, uint score)
|
||||
{
|
||||
if (wonMatch)
|
||||
{
|
||||
m_numWins += 1;
|
||||
Leaderboards.WriteEntry(MOST_MATCHES_WON, m_numWins);
|
||||
}
|
||||
|
||||
if (score > 0)
|
||||
{
|
||||
Leaderboards.WriteEntry(HIGHEST_MATCH_SCORE, score);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b5525a4fa9d4898438f479b1c25ff8b4
|
||||
timeCreated: 1476809789
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,48 @@
|
||||
namespace Oculus.Platform.Samples.VrHoops
|
||||
{
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
// This class listens for Input events to shoot a ball, and also notifies the P2PManager when
|
||||
// ball or scores needs to be synchronized to remote players.
|
||||
public class LocalPlayer : Player {
|
||||
|
||||
public override uint Score
|
||||
{
|
||||
set
|
||||
{
|
||||
base.Score = value;
|
||||
|
||||
if (PlatformManager.CurrentState == PlatformManager.State.PLAYING_A_NETWORKED_MATCH)
|
||||
{
|
||||
PlatformManager.P2P.SendScoreUpdate(base.Score);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Update ()
|
||||
{
|
||||
GameObject newball = null;
|
||||
|
||||
// if the player is holding a ball
|
||||
if (HasBall)
|
||||
{
|
||||
// check to see if the User is hitting the shoot button
|
||||
if (Input.GetButton("Fire1") || Input.GetKey(KeyCode.Space))
|
||||
{
|
||||
newball = ShootBall();
|
||||
}
|
||||
}
|
||||
// spawn a new held ball if we can
|
||||
else
|
||||
{
|
||||
newball = CheckSpawnBall();
|
||||
}
|
||||
|
||||
if (newball && PlatformManager.CurrentState == PlatformManager.State.PLAYING_A_NETWORKED_MATCH)
|
||||
{
|
||||
PlatformManager.P2P.AddNetworkBall(newball);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ac564d79b10fc01448f93b8dcc74d3d0
|
||||
timeCreated: 1475264810
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,472 @@
|
||||
namespace Oculus.Platform.Samples.VrHoops
|
||||
{
|
||||
using UnityEngine;
|
||||
using UnityEngine.Assertions;
|
||||
using UnityEngine.UI;
|
||||
using System.Collections.Generic;
|
||||
using Oculus.Platform.Models;
|
||||
|
||||
// This class coordinates playing matches. It mediates being idle
|
||||
// and entering a practice or online game match.
|
||||
public class MatchController : MonoBehaviour
|
||||
{
|
||||
// Text to display when the match will start or finish
|
||||
[SerializeField] private Text m_timerText = null;
|
||||
|
||||
// the camera is moved between the idle position and the assigned court position
|
||||
[SerializeField] private Camera m_camera = null;
|
||||
|
||||
// where the camera will be when not in a match
|
||||
[SerializeField] private Transform m_idleCameraTransform = null;
|
||||
|
||||
// button that toggles between matchmaking and cancel
|
||||
[SerializeField] private Text m_matchmakeButtonText = null;
|
||||
|
||||
// this should equal the maximum number of players configured on the Oculus Dashboard
|
||||
[SerializeField] private PlayerArea[] m_playerAreas = new PlayerArea[3];
|
||||
|
||||
// the time to wait between selecting Practice and starting
|
||||
[SerializeField] private uint PRACTICE_WARMUP_TIME = 5;
|
||||
|
||||
// seconds to wait to coordinate P2P setup with other match players before starting
|
||||
[SerializeField] private uint MATCH_WARMUP_TIME = 30;
|
||||
|
||||
// seconds for the match
|
||||
[SerializeField] private uint MATCH_TIME = 20;
|
||||
|
||||
// how long to remain in position after the match to view results
|
||||
[SerializeField] private uint MATCH_COOLDOWN_TIME = 10;
|
||||
|
||||
// panel to add most-wins leaderboard entries to
|
||||
[SerializeField] private GameObject m_mostWinsLeaderboard = null;
|
||||
|
||||
// panel to add high-score leaderboard entries to
|
||||
[SerializeField] private GameObject m_highestScoresLeaderboard = null;
|
||||
|
||||
// leaderboard entry Text prefab
|
||||
[SerializeField] private GameObject m_leaderboardEntryPrefab = null;
|
||||
|
||||
// Text prefab to use for achievements fly-text
|
||||
[SerializeField] private GameObject m_flytext = null;
|
||||
|
||||
// the current state of the match controller
|
||||
private State m_currentState;
|
||||
|
||||
// transition time for states that automatically transition to the next state,
|
||||
// for example ending the match when the timer expires
|
||||
private float m_nextStateTransitionTime;
|
||||
|
||||
// the court the local player was assigned to
|
||||
private int m_localSlot;
|
||||
|
||||
void Start()
|
||||
{
|
||||
PlatformManager.Matchmaking.EnqueueResultCallback = OnMatchFoundCallback;
|
||||
PlatformManager.Matchmaking.MatchPlayerAddedCallback = MatchPlayerAddedCallback;
|
||||
PlatformManager.P2P.StartTimeOfferCallback = StartTimeOfferCallback;
|
||||
PlatformManager.Leaderboards.MostWinsLeaderboardUpdatedCallback = MostWinsLeaderboardCallback;
|
||||
PlatformManager.Leaderboards.HighScoreLeaderboardUpdatedCallback = HighestScoreLeaderboardCallback;
|
||||
|
||||
TransitionToState(State.NONE);
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
UpdateCheckForNextTimedTransition();
|
||||
UpdateMatchTimer();
|
||||
}
|
||||
|
||||
public float MatchStartTime
|
||||
{
|
||||
get
|
||||
{
|
||||
switch(m_currentState)
|
||||
{
|
||||
case State.WAITING_TO_START_PRACTICE:
|
||||
case State.WAITING_TO_SETUP_MATCH:
|
||||
return m_nextStateTransitionTime;
|
||||
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
private set { m_nextStateTransitionTime = value; }
|
||||
}
|
||||
|
||||
#region State Management
|
||||
|
||||
private enum State
|
||||
{
|
||||
UNKNOWN,
|
||||
|
||||
// no current match, waiting for the local user to select something
|
||||
NONE,
|
||||
|
||||
// user selected a practice match, waiting for the match timer to start
|
||||
WAITING_TO_START_PRACTICE,
|
||||
|
||||
// playing a Practice match against AI players
|
||||
PRACTICING,
|
||||
|
||||
// post practice match, time to view the scores
|
||||
VIEWING_RESULTS_PRACTICE,
|
||||
|
||||
// selecting Player Online and waiting for the Matchmaking service to find and create a
|
||||
// match and join the assigned match room
|
||||
WAITING_FOR_MATCH,
|
||||
|
||||
// match room is joined, waiting to coordinate with the other players
|
||||
WAITING_TO_SETUP_MATCH,
|
||||
|
||||
// playing a competative match against other players
|
||||
PLAYING_MATCH,
|
||||
|
||||
// match is complete, viewing the match scores
|
||||
VIEWING_MATCH_RESULTS,
|
||||
}
|
||||
|
||||
void TransitionToState(State newState)
|
||||
{
|
||||
Debug.LogFormat("MatchController State {0} -> {1}", m_currentState, newState);
|
||||
|
||||
if (m_currentState != newState)
|
||||
{
|
||||
var oldState = m_currentState;
|
||||
m_currentState = newState;
|
||||
|
||||
// state transition logic
|
||||
switch (newState)
|
||||
{
|
||||
case State.NONE:
|
||||
SetupForIdle();
|
||||
MoveCameraToIdlePosition();
|
||||
PlatformManager.TransitionToState(PlatformManager.State.WAITING_TO_PRACTICE_OR_MATCHMAKE);
|
||||
m_matchmakeButtonText.text = "Play Online";
|
||||
break;
|
||||
|
||||
case State.WAITING_TO_START_PRACTICE:
|
||||
Assert.AreEqual(oldState, State.NONE);
|
||||
SetupForPractice();
|
||||
MoveCameraToMatchPosition();
|
||||
PlatformManager.TransitionToState(PlatformManager.State.MATCH_TRANSITION);
|
||||
m_nextStateTransitionTime = Time.time + PRACTICE_WARMUP_TIME;
|
||||
break;
|
||||
|
||||
case State.PRACTICING:
|
||||
Assert.AreEqual(oldState, State.WAITING_TO_START_PRACTICE);
|
||||
PlatformManager.TransitionToState(PlatformManager.State.PLAYING_A_LOCAL_MATCH);
|
||||
m_nextStateTransitionTime = Time.time + MATCH_TIME;
|
||||
break;
|
||||
|
||||
case State.VIEWING_RESULTS_PRACTICE:
|
||||
Assert.AreEqual(oldState, State.PRACTICING);
|
||||
PlatformManager.TransitionToState(PlatformManager.State.MATCH_TRANSITION);
|
||||
m_nextStateTransitionTime = Time.time + MATCH_COOLDOWN_TIME;
|
||||
m_timerText.text = "0:00.00";
|
||||
break;
|
||||
|
||||
case State.WAITING_FOR_MATCH:
|
||||
Assert.AreEqual(oldState, State.NONE);
|
||||
PlatformManager.TransitionToState(PlatformManager.State.MATCH_TRANSITION);
|
||||
m_matchmakeButtonText.text = "Cancel";
|
||||
break;
|
||||
|
||||
case State.WAITING_TO_SETUP_MATCH:
|
||||
Assert.AreEqual(oldState, State.WAITING_FOR_MATCH);
|
||||
m_nextStateTransitionTime = Time.time + MATCH_WARMUP_TIME;
|
||||
break;
|
||||
|
||||
case State.PLAYING_MATCH:
|
||||
Assert.AreEqual(oldState, State.WAITING_TO_SETUP_MATCH);
|
||||
PlatformManager.TransitionToState(PlatformManager.State.PLAYING_A_NETWORKED_MATCH);
|
||||
m_nextStateTransitionTime = Time.time + MATCH_TIME;
|
||||
break;
|
||||
|
||||
case State.VIEWING_MATCH_RESULTS:
|
||||
Assert.AreEqual(oldState, State.PLAYING_MATCH);
|
||||
PlatformManager.TransitionToState(PlatformManager.State.MATCH_TRANSITION);
|
||||
m_nextStateTransitionTime = Time.time + MATCH_COOLDOWN_TIME;
|
||||
m_timerText.text = "0:00.00";
|
||||
CalculateMatchResults();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateCheckForNextTimedTransition()
|
||||
{
|
||||
if (m_currentState != State.NONE && Time.time >= m_nextStateTransitionTime)
|
||||
{
|
||||
switch (m_currentState)
|
||||
{
|
||||
case State.WAITING_TO_START_PRACTICE:
|
||||
TransitionToState(State.PRACTICING);
|
||||
break;
|
||||
|
||||
case State.PRACTICING:
|
||||
TransitionToState(State.VIEWING_RESULTS_PRACTICE);
|
||||
break;
|
||||
|
||||
case State.VIEWING_RESULTS_PRACTICE:
|
||||
TransitionToState(State.NONE);
|
||||
break;
|
||||
|
||||
case State.WAITING_TO_SETUP_MATCH:
|
||||
TransitionToState(State.PLAYING_MATCH);
|
||||
break;
|
||||
|
||||
case State.PLAYING_MATCH:
|
||||
TransitionToState(State.VIEWING_MATCH_RESULTS);
|
||||
break;
|
||||
|
||||
case State.VIEWING_MATCH_RESULTS:
|
||||
PlatformManager.Matchmaking.EndMatch();
|
||||
TransitionToState(State.NONE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateMatchTimer()
|
||||
{
|
||||
if (Time.time <= m_nextStateTransitionTime)
|
||||
{
|
||||
switch (m_currentState)
|
||||
{
|
||||
case State.WAITING_TO_START_PRACTICE:
|
||||
case State.WAITING_TO_SETUP_MATCH:
|
||||
m_timerText.text = string.Format("{0:0}", Mathf.Ceil(Time.time - MatchStartTime));
|
||||
break;
|
||||
|
||||
case State.PRACTICING:
|
||||
case State.PLAYING_MATCH:
|
||||
var delta = m_nextStateTransitionTime - Time.time;
|
||||
m_timerText.text = string.Format("{0:#0}:{1:#00}.{2:00}",
|
||||
Mathf.Floor(delta / 60),
|
||||
Mathf.Floor(delta) % 60,
|
||||
Mathf.Floor(delta * 100) % 100);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Player Setup/Teardown
|
||||
|
||||
void SetupForIdle()
|
||||
{
|
||||
for (int i = 0; i < m_playerAreas.Length; i++)
|
||||
{
|
||||
m_playerAreas[i].SetupForPlayer<AIPlayer>("* AI *");
|
||||
}
|
||||
}
|
||||
|
||||
void SetupForPractice()
|
||||
{
|
||||
// randomly select a position for the local player
|
||||
m_localSlot = Random.Range(0,m_playerAreas.Length-1);
|
||||
|
||||
for (int i=0; i < m_playerAreas.Length; i++)
|
||||
{
|
||||
if (i == m_localSlot)
|
||||
{
|
||||
m_playerAreas[i].SetupForPlayer<LocalPlayer>(PlatformManager.MyOculusID);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_playerAreas[i].SetupForPlayer<AIPlayer>("* AI *");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Player MatchPlayerAddedCallback(int slot, User user)
|
||||
{
|
||||
Player player = null;
|
||||
|
||||
if (m_currentState == State.WAITING_TO_SETUP_MATCH && slot < m_playerAreas.Length)
|
||||
{
|
||||
if (user.ID == PlatformManager.MyID)
|
||||
{
|
||||
var localPlayer = m_playerAreas[slot].SetupForPlayer<LocalPlayer>(user.OculusID);
|
||||
MoveCameraToMatchPosition();
|
||||
player = localPlayer;
|
||||
m_localSlot = slot;
|
||||
}
|
||||
else
|
||||
{
|
||||
var remotePlayer = m_playerAreas[slot].SetupForPlayer<RemotePlayer>(user.OculusID);
|
||||
remotePlayer.User = user;
|
||||
player = remotePlayer;
|
||||
}
|
||||
}
|
||||
|
||||
return player;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Main Camera Movement
|
||||
|
||||
void MoveCameraToIdlePosition()
|
||||
{
|
||||
var ejector = m_camera.gameObject.GetComponentInChildren<BallEjector>();
|
||||
if (ejector)
|
||||
{
|
||||
ejector.transform.SetParent(m_camera.transform.parent, false);
|
||||
m_camera.transform.SetParent(m_idleCameraTransform, false);
|
||||
}
|
||||
}
|
||||
|
||||
void MoveCameraToMatchPosition()
|
||||
{
|
||||
foreach (var playerArea in m_playerAreas)
|
||||
{
|
||||
var player = playerArea.GetComponentInChildren<LocalPlayer>();
|
||||
if (player)
|
||||
{
|
||||
var ejector = player.GetComponentInChildren<BallEjector>();
|
||||
m_camera.transform.SetParent(player.transform, false);
|
||||
ejector.transform.SetParent(m_camera.transform, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
DisplayAchievementFlytext();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Match Initiation
|
||||
|
||||
public void StartPracticeMatch()
|
||||
{
|
||||
if (m_currentState == State.NONE)
|
||||
{
|
||||
TransitionToState(State.WAITING_TO_START_PRACTICE);
|
||||
}
|
||||
}
|
||||
|
||||
public void PlayOnlineOrCancel()
|
||||
{
|
||||
Debug.Log ("Play online or Cancel");
|
||||
|
||||
if (m_currentState == State.NONE)
|
||||
{
|
||||
PlatformManager.Matchmaking.QueueForMatch();
|
||||
TransitionToState (State.WAITING_FOR_MATCH);
|
||||
}
|
||||
else if (m_currentState == State.WAITING_FOR_MATCH)
|
||||
{
|
||||
PlatformManager.Matchmaking.LeaveQueue();
|
||||
TransitionToState (State.NONE);
|
||||
}
|
||||
}
|
||||
|
||||
// notification from the Matchmaking service if we succeeded in finding an online match
|
||||
void OnMatchFoundCallback(bool success)
|
||||
{
|
||||
if (success)
|
||||
{
|
||||
TransitionToState(State.WAITING_TO_SETUP_MATCH);
|
||||
}
|
||||
else
|
||||
{
|
||||
TransitionToState(State.NONE);
|
||||
}
|
||||
}
|
||||
|
||||
// handle an offer from a remote player for a new match start time
|
||||
float StartTimeOfferCallback(float remoteTime)
|
||||
{
|
||||
if (m_currentState == State.WAITING_TO_SETUP_MATCH)
|
||||
{
|
||||
// if the remote start time is later use that, as long as it's not horribly wrong
|
||||
if (remoteTime > MatchStartTime && (remoteTime - 60) < MatchStartTime)
|
||||
{
|
||||
Debug.Log("Moving Start time by " + (remoteTime - MatchStartTime));
|
||||
MatchStartTime = remoteTime;
|
||||
}
|
||||
}
|
||||
return MatchStartTime;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Leaderboards and Achievements
|
||||
|
||||
void MostWinsLeaderboardCallback(SortedDictionary<int, LeaderboardEntry> entries)
|
||||
{
|
||||
foreach (Transform entry in m_mostWinsLeaderboard.transform)
|
||||
{
|
||||
Destroy(entry.gameObject);
|
||||
}
|
||||
foreach (var entry in entries.Values)
|
||||
{
|
||||
GameObject label = Instantiate(m_leaderboardEntryPrefab);
|
||||
label.transform.SetParent(m_mostWinsLeaderboard.transform, false);
|
||||
label.GetComponent<Text>().text =
|
||||
string.Format("{0} - {1} - {2}", entry.Rank, entry.User.OculusID, entry.Score);
|
||||
}
|
||||
}
|
||||
|
||||
void HighestScoreLeaderboardCallback(SortedDictionary<int, LeaderboardEntry> entries)
|
||||
{
|
||||
foreach (Transform entry in m_highestScoresLeaderboard.transform)
|
||||
{
|
||||
Destroy(entry.gameObject);
|
||||
}
|
||||
foreach (var entry in entries.Values)
|
||||
{
|
||||
GameObject label = Instantiate(m_leaderboardEntryPrefab);
|
||||
label.transform.SetParent(m_highestScoresLeaderboard.transform, false);
|
||||
label.GetComponent<Text>().text =
|
||||
string.Format("{0} - {1} - {2}", entry.Rank, entry.User.OculusID, entry.Score);
|
||||
}
|
||||
}
|
||||
|
||||
void CalculateMatchResults()
|
||||
{
|
||||
LocalPlayer localPlayer = null;
|
||||
RemotePlayer remotePlayer = null;
|
||||
|
||||
foreach (var court in m_playerAreas)
|
||||
{
|
||||
if (court.Player is LocalPlayer)
|
||||
{
|
||||
localPlayer = court.Player as LocalPlayer;
|
||||
}
|
||||
else if (court.Player is RemotePlayer &&
|
||||
(remotePlayer == null || court.Player.Score > remotePlayer.Score))
|
||||
{
|
||||
remotePlayer = court.Player as RemotePlayer;
|
||||
}
|
||||
}
|
||||
|
||||
// ignore the match results if the player got into a session without an opponent
|
||||
if (!localPlayer || !remotePlayer)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bool wonMatch = localPlayer.Score > remotePlayer.Score;
|
||||
PlatformManager.Leaderboards.SubmitMatchScores(wonMatch, localPlayer.Score);
|
||||
|
||||
if (wonMatch)
|
||||
{
|
||||
PlatformManager.Achievements.RecordWinForLocalUser();
|
||||
}
|
||||
}
|
||||
|
||||
void DisplayAchievementFlytext()
|
||||
{
|
||||
if (PlatformManager.Achievements.LikesToWin)
|
||||
{
|
||||
GameObject go = Instantiate(m_flytext);
|
||||
go.GetComponent<Text>().text = "Likes to Win!";
|
||||
go.transform.position = Vector3.up * 40;
|
||||
go.transform.SetParent(m_playerAreas[m_localSlot].NameText.transform, false);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5e31d7fbc2f31b7499684c9e87fc8454
|
||||
timeCreated: 1475257003
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,145 @@
|
||||
namespace Oculus.Platform.Samples.VrHoops
|
||||
{
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
using Oculus.Platform;
|
||||
using Oculus.Platform.Models;
|
||||
|
||||
// This class coordinates with the Oculus Platform Matchmaking Service to
|
||||
// establish a Quickmatch session with one or two other players.
|
||||
public class MatchmakingManager
|
||||
{
|
||||
// the name we setup on the Developer Dashboard for the quickmatch pool
|
||||
private const string NORMAL_POOL = "NORMAL_QUICKMATCH";
|
||||
|
||||
// the ID of the Room the matchmaking service sent to join
|
||||
private ulong m_matchRoom;
|
||||
|
||||
// the list of players that join the match room.
|
||||
// it may not be all the match players since some might disconnect
|
||||
// before joining the room, but then again they might disconnect
|
||||
// midway through a match as well.
|
||||
private readonly Dictionary<ulong, User> m_remotePlayers;
|
||||
|
||||
public MatchmakingManager()
|
||||
{
|
||||
m_remotePlayers = new Dictionary<ulong, User>();
|
||||
|
||||
Matchmaking.SetMatchFoundNotificationCallback(MatchFoundCallback);
|
||||
Rooms.SetUpdateNotificationCallback(MatchmakingRoomUpdateCallback);
|
||||
}
|
||||
|
||||
public delegate void OnEnqueueResult(bool successful);
|
||||
public delegate Player OnMatchPlayerAdded(int slot, User user);
|
||||
|
||||
private OnEnqueueResult m_enqueueCallback;
|
||||
private OnMatchPlayerAdded m_playerCallback;
|
||||
|
||||
public OnEnqueueResult EnqueueResultCallback
|
||||
{
|
||||
private get { return m_enqueueCallback; }
|
||||
set { m_enqueueCallback = value; }
|
||||
}
|
||||
|
||||
public OnMatchPlayerAdded MatchPlayerAddedCallback
|
||||
{
|
||||
private get { return m_playerCallback; }
|
||||
set { m_playerCallback = value; }
|
||||
}
|
||||
|
||||
public void QueueForMatch()
|
||||
{
|
||||
Matchmaking.Enqueue (NORMAL_POOL).OnComplete(MatchmakingEnqueueCallback);
|
||||
}
|
||||
|
||||
void MatchmakingEnqueueCallback(Message msg)
|
||||
{
|
||||
if (msg.IsError)
|
||||
{
|
||||
Debug.Log(msg.GetError().Message);
|
||||
EnqueueResultCallback(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void MatchFoundCallback(Message<Room> msg)
|
||||
{
|
||||
m_matchRoom = msg.Data.ID;
|
||||
Matchmaking.JoinRoom(msg.Data.ID, true).OnComplete(MatchmakingJoinRoomCallback);
|
||||
}
|
||||
|
||||
void MatchmakingJoinRoomCallback(Message<Room> msg)
|
||||
{
|
||||
if (msg.IsError)
|
||||
{
|
||||
Debug.Log (msg.GetError().Message);
|
||||
EnqueueResultCallback(false);
|
||||
return;
|
||||
}
|
||||
Debug.Log ("Match found and room joined " + m_matchRoom);
|
||||
|
||||
EnqueueResultCallback(true);
|
||||
|
||||
// this sample doesn't try to coordinate that all the players see consistent
|
||||
// positioning to assigned courts, but that would be a great next feature to add
|
||||
int slot = 0;
|
||||
|
||||
if (msg.Data.UsersOptional != null)
|
||||
{
|
||||
foreach (var user in msg.Data.UsersOptional)
|
||||
{
|
||||
var player = MatchPlayerAddedCallback(slot++, user);
|
||||
if (PlatformManager.MyID != user.ID)
|
||||
{
|
||||
m_remotePlayers[user.ID] = user;
|
||||
PlatformManager.P2P.AddRemotePlayer (player as RemotePlayer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MatchmakingRoomUpdateCallback(Message<Room> msg)
|
||||
{
|
||||
if (msg.IsError)
|
||||
{
|
||||
PlatformManager.TerminateWithError(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
// check to make sure the room is valid as there are a few odd timing issues (for
|
||||
// example when leaving a room) that can trigger an uninteresting update
|
||||
if (msg.Data.ID == m_matchRoom)
|
||||
{
|
||||
if (msg.Data.UsersOptional != null)
|
||||
{
|
||||
foreach (User user in msg.Data.UsersOptional)
|
||||
{
|
||||
if (PlatformManager.MyID != user.ID && !m_remotePlayers.ContainsKey(user.ID))
|
||||
{
|
||||
m_remotePlayers[user.ID] = user;
|
||||
var player = MatchPlayerAddedCallback(m_remotePlayers.Count, user);
|
||||
PlatformManager.P2P.AddRemotePlayer(player as RemotePlayer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void EndMatch()
|
||||
{
|
||||
if (m_matchRoom != 0)
|
||||
{
|
||||
Rooms.Leave (m_matchRoom);
|
||||
m_remotePlayers.Clear ();
|
||||
PlatformManager.P2P.DisconnectAll ();
|
||||
m_matchRoom = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void LeaveQueue()
|
||||
{
|
||||
Matchmaking.Cancel();
|
||||
EndMatch();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fa69df7dcb6814fab9439789f1e23e2e
|
||||
timeCreated: 1475629968
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
579
Assets/Oculus/Platform/Samples/VrHoops/Scripts/P2PManager.cs
Normal file
579
Assets/Oculus/Platform/Samples/VrHoops/Scripts/P2PManager.cs
Normal file
@@ -0,0 +1,579 @@
|
||||
namespace Oculus.Platform.Samples.VrHoops
|
||||
{
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
using Oculus.Platform;
|
||||
using Oculus.Platform.Models;
|
||||
using System;
|
||||
using UnityEngine.Assertions;
|
||||
|
||||
// This helper class coordinates establishing Peer-to-Peer connections between the
|
||||
// players in the match. It tries to sychronize time between the devices and
|
||||
// handles position update messages for the backboard and moving balls.
|
||||
public class P2PManager
|
||||
{
|
||||
#region Member variables
|
||||
|
||||
// helper class to hold data we need for remote players
|
||||
private class RemotePlayerData
|
||||
{
|
||||
// the last received Net connection state
|
||||
public PeerConnectionState state;
|
||||
// the Unity Monobehaviour
|
||||
public RemotePlayer player;
|
||||
// offset from my local time to the time of the remote host
|
||||
public float remoteTimeOffset;
|
||||
// the last ball update remote time, used to disgard out of order packets
|
||||
public float lastReceivedBallsTime;
|
||||
// remote Instance ID -> local MonoBahaviours for balls we're receiving updates on
|
||||
public readonly Dictionary<int, P2PNetworkBall> activeBalls = new Dictionary<int, P2PNetworkBall>();
|
||||
}
|
||||
|
||||
// authorized users to connect to and associated data
|
||||
private readonly Dictionary<ulong, RemotePlayerData> m_remotePlayers = new Dictionary<ulong, RemotePlayerData>();
|
||||
|
||||
// when to send the next update to remotes on the state on my local balls
|
||||
private float m_timeForNextBallUpdate;
|
||||
|
||||
private const byte TIME_SYNC_MESSAGE = 1;
|
||||
private const uint TIME_SYNC_MESSAGE_SIZE = 1+4;
|
||||
private const int TIME_SYNC_MESSAGE_COUNT = 7;
|
||||
private const byte START_TIME_MESSAGE = 2;
|
||||
private const uint START_TIME_MESSAGE_SIZE = 1+4;
|
||||
private const byte BACKBOARD_UPDATE_MESSAGE = 3;
|
||||
private const uint BACKBOARD_UPDATE_MESSAGE_SIZE = 1+4+12+12+12;
|
||||
private const byte LOCAL_BALLS_UPDATE_MESSAGE = 4;
|
||||
private const uint LOCAL_BALLS_UPDATE_MESSATE_SIZE_MAX = 1+4+(2*Player.MAX_BALLS*(1+4+12+12));
|
||||
private const float LOCAL_BALLS_UPDATE_DELAY = 0.1f;
|
||||
private const byte SCORE_UPDATE_MESSAGE = 5;
|
||||
private const uint SCORE_UPDATE_MESSAGE_SIZE = 1 + 4;
|
||||
|
||||
// cache of local balls that we are sending updates for
|
||||
private readonly Dictionary<int, P2PNetworkBall> m_localBalls = new Dictionary<int, P2PNetworkBall>();
|
||||
|
||||
// reusable buffer to read network data into
|
||||
private readonly byte[] readBuffer = new byte[LOCAL_BALLS_UPDATE_MESSATE_SIZE_MAX];
|
||||
|
||||
// temporary time-sync cache of the calculated time offsets
|
||||
private readonly Dictionary<ulong, List<float>> m_remoteSyncTimeCache = new Dictionary<ulong, List<float>>();
|
||||
|
||||
// temporary time-sync cache of the last sent message
|
||||
private readonly Dictionary<ulong, float> m_remoteSentTimeCache = new Dictionary<ulong, float>();
|
||||
|
||||
// the delegate to handle start-time coordination
|
||||
private StartTimeOffer m_startTimeOfferCallback;
|
||||
|
||||
#endregion
|
||||
|
||||
public P2PManager()
|
||||
{
|
||||
Net.SetPeerConnectRequestCallback(PeerConnectRequestCallback);
|
||||
Net.SetConnectionStateChangedCallback(ConnectionStateChangedCallback);
|
||||
}
|
||||
|
||||
public void UpdateNetwork()
|
||||
{
|
||||
if (m_remotePlayers.Count == 0)
|
||||
return;
|
||||
|
||||
// check for new messages
|
||||
Packet packet;
|
||||
while ((packet = Net.ReadPacket()) != null)
|
||||
{
|
||||
if (!m_remotePlayers.ContainsKey(packet.SenderID))
|
||||
continue;
|
||||
|
||||
packet.ReadBytes(readBuffer);
|
||||
|
||||
switch (readBuffer[0])
|
||||
{
|
||||
case TIME_SYNC_MESSAGE:
|
||||
Assert.AreEqual(TIME_SYNC_MESSAGE_SIZE, packet.Size);
|
||||
ReadTimeSyncMessage(packet.SenderID, readBuffer);
|
||||
break;
|
||||
|
||||
case START_TIME_MESSAGE:
|
||||
Assert.AreEqual(START_TIME_MESSAGE_SIZE, packet.Size);
|
||||
ReceiveMatchStartTimeOffer(packet.SenderID, readBuffer);
|
||||
break;
|
||||
|
||||
case BACKBOARD_UPDATE_MESSAGE:
|
||||
Assert.AreEqual(BACKBOARD_UPDATE_MESSAGE_SIZE, packet.Size);
|
||||
ReceiveBackboardUpdate(packet.SenderID, readBuffer);
|
||||
break;
|
||||
|
||||
case LOCAL_BALLS_UPDATE_MESSAGE:
|
||||
ReceiveBallTransforms(packet.SenderID, readBuffer, packet.Size);
|
||||
break;
|
||||
|
||||
case SCORE_UPDATE_MESSAGE:
|
||||
Assert.AreEqual(SCORE_UPDATE_MESSAGE_SIZE, packet.Size);
|
||||
ReceiveScoredUpdate(packet.SenderID, readBuffer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (Time.time >= m_timeForNextBallUpdate && m_localBalls.Count > 0)
|
||||
{
|
||||
SendLocalBallTransforms();
|
||||
}
|
||||
}
|
||||
|
||||
#region Connection Management
|
||||
|
||||
// adds a remote player to establish a connection to, or accept a connection from
|
||||
public void AddRemotePlayer(RemotePlayer player)
|
||||
{
|
||||
if (!m_remotePlayers.ContainsKey (player.ID))
|
||||
{
|
||||
m_remotePlayers[player.ID] = new RemotePlayerData();
|
||||
m_remotePlayers[player.ID].state = PeerConnectionState.Unknown;
|
||||
m_remotePlayers [player.ID].player = player;
|
||||
|
||||
// ID comparison is used to decide who Connects and who Accepts
|
||||
if (PlatformManager.MyID < player.ID)
|
||||
{
|
||||
Debug.Log ("P2P Try Connect to: " + player.ID);
|
||||
Net.Connect (player.ID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void DisconnectAll()
|
||||
{
|
||||
foreach (var id in m_remotePlayers.Keys)
|
||||
{
|
||||
Net.Close(id);
|
||||
}
|
||||
m_remotePlayers.Clear();
|
||||
}
|
||||
|
||||
void PeerConnectRequestCallback(Message<NetworkingPeer> msg)
|
||||
{
|
||||
if (m_remotePlayers.ContainsKey(msg.Data.ID))
|
||||
{
|
||||
Debug.LogFormat("P2P Accepting Connection request from {0}", msg.Data.ID);
|
||||
Net.Accept(msg.Data.ID);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogFormat("P2P Ignoring unauthorized Connection request from {0}", msg.Data.ID);
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectionStateChangedCallback(Message<NetworkingPeer> msg)
|
||||
{
|
||||
Debug.LogFormat("P2P {0} Connection state changed to {1}", msg.Data.ID, msg.Data.State);
|
||||
|
||||
if (m_remotePlayers.ContainsKey(msg.Data.ID))
|
||||
{
|
||||
m_remotePlayers[msg.Data.ID].state = msg.Data.State;
|
||||
|
||||
switch (msg.Data.State)
|
||||
{
|
||||
case PeerConnectionState.Connected:
|
||||
if (PlatformManager.MyID < msg.Data.ID)
|
||||
{
|
||||
SendTimeSyncMessage(msg.Data.ID);
|
||||
}
|
||||
break;
|
||||
|
||||
case PeerConnectionState.Timeout:
|
||||
if (PlatformManager.MyID < msg.Data.ID)
|
||||
{
|
||||
Net.Connect(msg.Data.ID);
|
||||
}
|
||||
break;
|
||||
|
||||
case PeerConnectionState.Closed:
|
||||
m_remotePlayers.Remove(msg.Data.ID);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Time Synchronizaiton
|
||||
|
||||
// This section implements some basic time synchronization between the players.
|
||||
// The algorithm is:
|
||||
// -Send a time-sync message and receive a time-sync message response
|
||||
// -Estimate time offset
|
||||
// -Repeat several times
|
||||
// -Average values discarding any statistical anomalies
|
||||
// Normally delays would be added in case there is intermittent network congestion
|
||||
// however the match times are so short we don't do that here. Also, if one client
|
||||
// pauses their game and Unity stops their simulation, all bets are off for time
|
||||
// synchronization. Depending on the goals of your app, you could either reinitiate
|
||||
// time synchronization, or just disconnect that player.
|
||||
|
||||
void SendTimeSyncMessage(ulong remoteID)
|
||||
{
|
||||
if (!m_remoteSyncTimeCache.ContainsKey(remoteID))
|
||||
{
|
||||
m_remoteSyncTimeCache[remoteID] = new List<float>();
|
||||
}
|
||||
|
||||
float time = Time.realtimeSinceStartup;
|
||||
m_remoteSentTimeCache[remoteID] = time;
|
||||
|
||||
byte[] buf = new byte[TIME_SYNC_MESSAGE_SIZE];
|
||||
buf[0] = TIME_SYNC_MESSAGE;
|
||||
int offset = 1;
|
||||
PackFloat(time, buf, ref offset);
|
||||
|
||||
Net.SendPacket(remoteID, buf, SendPolicy.Reliable);
|
||||
}
|
||||
|
||||
void ReadTimeSyncMessage(ulong remoteID, byte[] msg)
|
||||
{
|
||||
if (!m_remoteSentTimeCache.ContainsKey(remoteID))
|
||||
{
|
||||
SendTimeSyncMessage(remoteID);
|
||||
return;
|
||||
}
|
||||
|
||||
int offset = 1;
|
||||
float remoteTime = UnpackFloat(msg, ref offset);
|
||||
float now = Time.realtimeSinceStartup;
|
||||
float latency = (now - m_remoteSentTimeCache[remoteID]) / 2;
|
||||
float remoteTimeOffset = now - (remoteTime + latency);
|
||||
|
||||
m_remoteSyncTimeCache[remoteID].Add(remoteTimeOffset);
|
||||
|
||||
if (m_remoteSyncTimeCache[remoteID].Count < TIME_SYNC_MESSAGE_COUNT)
|
||||
{
|
||||
SendTimeSyncMessage(remoteID);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (PlatformManager.MyID < remoteID)
|
||||
{
|
||||
// this client started the sync, need to send one last message to
|
||||
// the remote so they can finish their sync calculation
|
||||
SendTimeSyncMessage(remoteID);
|
||||
}
|
||||
|
||||
// sort the times and remember the median
|
||||
m_remoteSyncTimeCache[remoteID].Sort();
|
||||
float median = m_remoteSyncTimeCache[remoteID][TIME_SYNC_MESSAGE_COUNT/2];
|
||||
|
||||
// calucate the mean and standard deviation
|
||||
double mean = 0;
|
||||
foreach (var time in m_remoteSyncTimeCache[remoteID])
|
||||
{
|
||||
mean += time;
|
||||
}
|
||||
mean /= TIME_SYNC_MESSAGE_COUNT;
|
||||
|
||||
double std_dev = 0;
|
||||
foreach (var time in m_remoteSyncTimeCache[remoteID])
|
||||
{
|
||||
std_dev += (mean-time)*(mean-time);
|
||||
}
|
||||
std_dev = Math.Sqrt(std_dev)/TIME_SYNC_MESSAGE_COUNT;
|
||||
|
||||
// time delta is the mean of the values less than 1 standard deviation from the median
|
||||
mean = 0;
|
||||
int meanCount = 0;
|
||||
foreach (var time in m_remoteSyncTimeCache[remoteID])
|
||||
{
|
||||
if (Math.Abs(time-median) < std_dev)
|
||||
{
|
||||
mean += time;
|
||||
meanCount++;
|
||||
}
|
||||
}
|
||||
mean /= meanCount;
|
||||
Debug.LogFormat("Time offset to {0} is {1}", remoteID, mean);
|
||||
|
||||
m_remoteSyncTimeCache.Remove(remoteID);
|
||||
m_remoteSentTimeCache.Remove(remoteID);
|
||||
m_remotePlayers[remoteID].remoteTimeOffset = (float)mean;
|
||||
|
||||
// now that times are synchronized, lets try to coordinate the
|
||||
// start time for the match
|
||||
OfferMatchStartTime();
|
||||
}
|
||||
}
|
||||
|
||||
float ShiftRemoteTime(ulong remoteID, float remoteTime)
|
||||
{
|
||||
if (m_remotePlayers.ContainsKey(remoteID))
|
||||
{
|
||||
return remoteTime + m_remotePlayers[remoteID].remoteTimeOffset;
|
||||
}
|
||||
else
|
||||
{
|
||||
return remoteTime;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Match Start Coordination
|
||||
|
||||
// Since all the clients will calculate a slightly different start time, this
|
||||
// message tries to coordinate the match start time to be the lastest of all
|
||||
// the clients in the match.
|
||||
|
||||
// Delegate to coordiate match start times - the return value is our start time
|
||||
// and the argument is the remote start time, or 0 if that hasn't been given yet.
|
||||
public delegate float StartTimeOffer(float remoteTime);
|
||||
|
||||
public StartTimeOffer StartTimeOfferCallback
|
||||
{
|
||||
private get { return m_startTimeOfferCallback; }
|
||||
set { m_startTimeOfferCallback = value; }
|
||||
}
|
||||
|
||||
void OfferMatchStartTime()
|
||||
{
|
||||
byte[] buf = new byte[START_TIME_MESSAGE_SIZE];
|
||||
buf[0] = START_TIME_MESSAGE;
|
||||
int offset = 1;
|
||||
PackFloat(StartTimeOfferCallback(0), buf, ref offset);
|
||||
|
||||
foreach (var remoteID in m_remotePlayers.Keys)
|
||||
{
|
||||
if (m_remotePlayers [remoteID].state == PeerConnectionState.Connected)
|
||||
{
|
||||
Net.SendPacket (remoteID, buf, SendPolicy.Reliable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ReceiveMatchStartTimeOffer(ulong remoteID, byte[] msg)
|
||||
{
|
||||
int offset = 1;
|
||||
float remoteTime = UnpackTime(remoteID, msg, ref offset);
|
||||
StartTimeOfferCallback(remoteTime);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Backboard Transforms
|
||||
|
||||
public void SendBackboardUpdate(float time, Vector3 pos, Vector3 moveDir, Vector3 nextMoveDir)
|
||||
{
|
||||
byte[] buf = new byte[BACKBOARD_UPDATE_MESSAGE_SIZE];
|
||||
buf[0] = BACKBOARD_UPDATE_MESSAGE;
|
||||
int offset = 1;
|
||||
PackFloat(time, buf, ref offset);
|
||||
PackVector3(pos, buf, ref offset);
|
||||
PackVector3(moveDir, buf, ref offset);
|
||||
PackVector3(nextMoveDir, buf, ref offset);
|
||||
|
||||
foreach (KeyValuePair<ulong,RemotePlayerData> player in m_remotePlayers)
|
||||
{
|
||||
if (player.Value.state == PeerConnectionState.Connected)
|
||||
{
|
||||
Net.SendPacket(player.Key, buf, SendPolicy.Reliable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ReceiveBackboardUpdate(ulong remoteID, byte[] msg)
|
||||
{
|
||||
int offset = 1;
|
||||
float remoteTime = UnpackTime(remoteID, msg, ref offset);
|
||||
Vector3 pos = UnpackVector3(msg, ref offset);
|
||||
Vector3 moveDir = UnpackVector3(msg, ref offset);
|
||||
Vector3 nextMoveDir = UnpackVector3(msg, ref offset);
|
||||
|
||||
var goal = m_remotePlayers [remoteID].player.Goal;
|
||||
goal.RemoteBackboardUpdate(remoteTime, pos, moveDir, nextMoveDir);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Ball Tansforms
|
||||
|
||||
public void AddNetworkBall(GameObject ball)
|
||||
{
|
||||
m_localBalls[ball.GetInstanceID()] = ball.AddComponent<P2PNetworkBall>();
|
||||
}
|
||||
|
||||
public void RemoveNetworkBall(GameObject ball)
|
||||
{
|
||||
m_localBalls.Remove(ball.GetInstanceID());
|
||||
}
|
||||
|
||||
void SendLocalBallTransforms()
|
||||
{
|
||||
m_timeForNextBallUpdate = Time.time + LOCAL_BALLS_UPDATE_DELAY;
|
||||
|
||||
int msgSize = 1 + 4 + (m_localBalls.Count * (1 + 4 + 12 + 12));
|
||||
byte[] sendBuffer = new byte[msgSize];
|
||||
sendBuffer[0] = LOCAL_BALLS_UPDATE_MESSAGE;
|
||||
int offset = 1;
|
||||
PackFloat(Time.realtimeSinceStartup, sendBuffer, ref offset);
|
||||
|
||||
foreach (var ball in m_localBalls.Values)
|
||||
{
|
||||
PackBool(ball.IsHeld(), sendBuffer, ref offset);
|
||||
PackInt32(ball.gameObject.GetInstanceID(), sendBuffer, ref offset);
|
||||
PackVector3(ball.transform.localPosition, sendBuffer, ref offset);
|
||||
PackVector3(ball.velocity, sendBuffer, ref offset);
|
||||
}
|
||||
|
||||
foreach (KeyValuePair<ulong, RemotePlayerData> player in m_remotePlayers)
|
||||
{
|
||||
if (player.Value.state == PeerConnectionState.Connected)
|
||||
{
|
||||
Net.SendPacket(player.Key, sendBuffer, SendPolicy.Unreliable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ReceiveBallTransforms(ulong remoteID, byte[] msg, ulong msgLength)
|
||||
{
|
||||
int offset = 1;
|
||||
float remoteTime = UnpackTime(remoteID, msg, ref offset);
|
||||
|
||||
// because we're using unreliable networking the packets could come out of order
|
||||
// and the best thing to do is just ignore old packets because the data isn't
|
||||
// very useful anyway
|
||||
if (remoteTime < m_remotePlayers[remoteID].lastReceivedBallsTime)
|
||||
return;
|
||||
|
||||
m_remotePlayers[remoteID].lastReceivedBallsTime = remoteTime;
|
||||
|
||||
// loop over all ball updates in the message
|
||||
while (offset != (int)msgLength)
|
||||
{
|
||||
bool isHeld = UnpackBool(msg, ref offset);
|
||||
int instanceID = UnpackInt32(msg, ref offset);
|
||||
Vector3 pos = UnpackVector3(msg, ref offset);
|
||||
Vector3 vel = UnpackVector3(msg, ref offset);
|
||||
|
||||
if (!m_remotePlayers[remoteID].activeBalls.ContainsKey(instanceID))
|
||||
{
|
||||
var newball = m_remotePlayers[remoteID].player.CreateBall().AddComponent<P2PNetworkBall>();
|
||||
newball.transform.SetParent(m_remotePlayers[remoteID].player.transform.parent);
|
||||
m_remotePlayers[remoteID].activeBalls[instanceID] = newball;
|
||||
}
|
||||
var ball = m_remotePlayers[remoteID].activeBalls[instanceID];
|
||||
if (ball)
|
||||
{
|
||||
ball.ProcessRemoteUpdate(remoteTime, isHeld, pos, vel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Score Updates
|
||||
|
||||
public void SendScoreUpdate(uint score)
|
||||
{
|
||||
byte[] buf = new byte[SCORE_UPDATE_MESSAGE_SIZE];
|
||||
buf[0] = SCORE_UPDATE_MESSAGE;
|
||||
int offset = 1;
|
||||
PackUint32(score, buf, ref offset);
|
||||
|
||||
foreach (KeyValuePair<ulong, RemotePlayerData> player in m_remotePlayers)
|
||||
{
|
||||
if (player.Value.state == PeerConnectionState.Connected)
|
||||
{
|
||||
Net.SendPacket(player.Key, buf, SendPolicy.Reliable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ReceiveScoredUpdate(ulong remoteID, byte[] msg)
|
||||
{
|
||||
int offset = 1;
|
||||
uint score = UnpackUint32(msg, ref offset);
|
||||
|
||||
m_remotePlayers[remoteID].player.ReceiveRemoteScore(score);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Serialization
|
||||
|
||||
// This region contains basic data serialization logic. This sample doesn't warrant
|
||||
// much optimization, but the opportunites are ripe those interested in the topic.
|
||||
|
||||
void PackVector3(Vector3 vec, byte[] buf, ref int offset)
|
||||
{
|
||||
PackFloat(vec.x, buf, ref offset);
|
||||
PackFloat(vec.y, buf, ref offset);
|
||||
PackFloat(vec.z, buf, ref offset);
|
||||
}
|
||||
|
||||
Vector3 UnpackVector3(byte[] buf, ref int offset)
|
||||
{
|
||||
Vector3 vec;
|
||||
vec.x = UnpackFloat(buf, ref offset);
|
||||
vec.y = UnpackFloat(buf, ref offset);
|
||||
vec.z = UnpackFloat(buf, ref offset);
|
||||
return vec;
|
||||
}
|
||||
|
||||
void PackQuaternion(Quaternion quat, byte[] buf, ref int offset)
|
||||
{
|
||||
PackFloat(quat.x, buf, ref offset);
|
||||
PackFloat(quat.y, buf, ref offset);
|
||||
PackFloat(quat.z, buf, ref offset);
|
||||
PackFloat(quat.w, buf, ref offset);
|
||||
}
|
||||
|
||||
void PackFloat(float value, byte[] buf, ref int offset)
|
||||
{
|
||||
Buffer.BlockCopy(BitConverter.GetBytes(value), 0, buf, offset, 4);
|
||||
offset = offset + 4;
|
||||
}
|
||||
|
||||
float UnpackFloat(byte[] buf, ref int offset)
|
||||
{
|
||||
float value = BitConverter.ToSingle(buf, offset);
|
||||
offset += 4;
|
||||
return value;
|
||||
}
|
||||
|
||||
float UnpackTime(ulong remoteID, byte[] buf, ref int offset)
|
||||
{
|
||||
return ShiftRemoteTime(remoteID, UnpackFloat(buf, ref offset));
|
||||
}
|
||||
|
||||
void PackInt32(int value, byte[] buf, ref int offset)
|
||||
{
|
||||
Buffer.BlockCopy(BitConverter.GetBytes(value), 0, buf, offset, 4);
|
||||
offset = offset + 4;
|
||||
}
|
||||
|
||||
int UnpackInt32(byte[] buf, ref int offset)
|
||||
{
|
||||
int value = BitConverter.ToInt32(buf, offset);
|
||||
offset += 4;
|
||||
return value;
|
||||
}
|
||||
|
||||
void PackUint32(uint value, byte[] buf, ref int offset)
|
||||
{
|
||||
Buffer.BlockCopy(BitConverter.GetBytes(value), 0, buf, offset, 4);
|
||||
offset = offset + 4;
|
||||
}
|
||||
|
||||
uint UnpackUint32(byte[] buf, ref int offset)
|
||||
{
|
||||
uint value = BitConverter.ToUInt32(buf, offset);
|
||||
offset += 4;
|
||||
return value;
|
||||
}
|
||||
|
||||
void PackBool(bool value, byte[] buf, ref int offset)
|
||||
{
|
||||
buf[offset++] = (byte)(value ? 1 : 0);
|
||||
}
|
||||
|
||||
bool UnpackBool(byte[] buf, ref int offset)
|
||||
{
|
||||
return buf[offset++] != 0;;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f418f541d32d24e7aad85c24970462d1
|
||||
timeCreated: 1475634295
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,87 @@
|
||||
namespace Oculus.Platform.Samples.VrHoops
|
||||
{
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
// This component handles network coordination for moving balls.
|
||||
// Synchronizing moving objects that are under the influence of physics
|
||||
// and other forces is somewhat of an art and this example only scratches
|
||||
// the surface. Ultimately how you synchronize will depend on the requirements
|
||||
// of your application and its tolerance for users seeing slightly different
|
||||
// versions of the simulation.
|
||||
public class P2PNetworkBall : MonoBehaviour
|
||||
{
|
||||
// the last time this ball locally collided with something
|
||||
private float lastCollisionTime;
|
||||
|
||||
// cached reference to the GameObject's Rigidbody component
|
||||
private Rigidbody rigidBody;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
rigidBody = gameObject.GetComponent<Rigidbody>();
|
||||
}
|
||||
|
||||
public Vector3 velocity
|
||||
{
|
||||
get { return rigidBody.velocity; }
|
||||
}
|
||||
|
||||
public bool IsHeld()
|
||||
{
|
||||
return !rigidBody.useGravity;
|
||||
}
|
||||
|
||||
public void ProcessRemoteUpdate(float remoteTime, bool isHeld, Vector3 pos, Vector3 vel)
|
||||
{
|
||||
if (isHeld)
|
||||
{
|
||||
transform.localPosition = pos;
|
||||
}
|
||||
// if we've collided since the update was sent, our state is going to be more accurate so
|
||||
// it's better to ignore the update
|
||||
else if (lastCollisionTime < remoteTime)
|
||||
{
|
||||
// To correct the position this sample directly moves the ball.
|
||||
// Another approach would be to gradually lerp the ball there during
|
||||
// FixedUpdate. However, that approach aggravates any errors that
|
||||
// come from estimatePosition and estimateVelocity so the lerp
|
||||
// should be done over few timesteps.
|
||||
float deltaT = Time.realtimeSinceStartup - remoteTime;
|
||||
transform.localPosition = estimatePosition(pos, vel, deltaT);
|
||||
rigidBody.velocity = estimateVelocity(vel, deltaT);
|
||||
|
||||
// if the ball is transitioning from held to ballistic, we need to
|
||||
// update the RigidBody parameters
|
||||
if (IsHeld())
|
||||
{
|
||||
rigidBody.useGravity = true;
|
||||
rigidBody.detectCollisions = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Estimates the new position assuming simple ballistic motion.
|
||||
private Vector3 estimatePosition(Vector3 startPosition, Vector3 startVelocty, float time)
|
||||
{
|
||||
return startPosition + startVelocty * time + 0.5f * Physics.gravity * time * time;
|
||||
}
|
||||
|
||||
// Estimates the new velocity assuming ballistic motion and drag.
|
||||
private Vector3 estimateVelocity(Vector3 startVelocity, float time)
|
||||
{
|
||||
return startVelocity + Physics.gravity * time * Mathf.Clamp01 (1 - rigidBody.drag * time);
|
||||
}
|
||||
|
||||
void OnCollisionEnter(Collision collision)
|
||||
{
|
||||
lastCollisionTime = Time.realtimeSinceStartup;
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
PlatformManager.P2P.RemoveNetworkBall(gameObject);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b4360c472d4f2ab498faa9c614ac7c80
|
||||
timeCreated: 1476304390
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,65 @@
|
||||
namespace Oculus.Platform.Samples.VrHoops
|
||||
{
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
// This component handles network coordination for the moving backboard.
|
||||
// Although there is randomness in the next direction, the movement is
|
||||
// otherwise completely predictable, much like a moving platform or door,
|
||||
// thus we only need to send occasional updates. If the position of the
|
||||
// backboard is not correct, the GoalMover will gradually nudge it in the
|
||||
// correct direction until the local and remote motion is synchronized.
|
||||
public class P2PNetworkGoal : MonoBehaviour
|
||||
{
|
||||
// cached reference to the associated GoalMover component
|
||||
private GoalMover m_goal;
|
||||
|
||||
// the last move direction we sent to remote clients
|
||||
private Vector3 m_lastSentMoveDirection;
|
||||
|
||||
private bool m_sendUpdates;
|
||||
|
||||
public bool SendUpdates
|
||||
{
|
||||
set { m_sendUpdates = value; }
|
||||
}
|
||||
|
||||
void Awake()
|
||||
{
|
||||
m_goal = gameObject.GetComponent<GoalMover>();
|
||||
}
|
||||
|
||||
void FixedUpdate ()
|
||||
{
|
||||
// since the backboard's movement is deterministic, we don't need to send position
|
||||
// updates constantly, just when the move direction changes
|
||||
if (m_sendUpdates && m_goal.MoveDirection != m_lastSentMoveDirection)
|
||||
{
|
||||
SendBackboardUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
public void SendBackboardUpdate()
|
||||
{
|
||||
m_lastSentMoveDirection = m_goal.MoveDirection;
|
||||
|
||||
float time = Time.realtimeSinceStartup;
|
||||
PlatformManager.P2P.SendBackboardUpdate(
|
||||
time, transform.localPosition,
|
||||
m_goal.MoveDirection, m_goal.NextMoveDirection);
|
||||
}
|
||||
|
||||
// message from the remote player with new transforms
|
||||
public void RemoteBackboardUpdate(float remoteTime, Vector3 pos, Vector3 moveDir, Vector3 nextMoveDir)
|
||||
{
|
||||
// interpolate the position forward since the backboard would have moved over
|
||||
// the time it took to send the message
|
||||
float time = Time.realtimeSinceStartup;
|
||||
float numMissedSteps = (time - remoteTime) / Time.fixedDeltaTime;
|
||||
m_goal.ExpectedPosition = pos + (Mathf.Round(numMissedSteps) * moveDir);
|
||||
|
||||
m_goal.MoveDirection = moveDir;
|
||||
m_goal.NextMoveDirection = nextMoveDir;
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user