Added VR libraries

This commit is contained in:
Chris Midkiff
2018-10-08 23:54:11 -04:00
parent d9eb2a9763
commit 7ce1036e39
1037 changed files with 195630 additions and 348 deletions

View File

@@ -0,0 +1,258 @@
// Copyright 2016 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// This class is only used in the Editor, so make sure to only compile it on that platform.
// Additionally, If this class is compiled on Android then Unity will insert the INTERNET permission
// into the manifest because of the reference to the type TCPClient. Excluding this class in the android
// build ensures that it is only included if the developer using the SDK actually uses INTERNET related services.
// This MonoBehaviour is only ever instantiated dynamically, so it is fine that it is only compiled in the Editor,
// Otherwise it would cause serialization issues.
#if UNITY_EDITOR
using UnityEngine;
using System;
using System.IO;
using System.Net.Sockets;
using System.Threading;
using proto;
/// @cond
namespace Gvr.Internal {
public enum EmulatorClientSocketConnectionState {
Disconnected = 0,
Connecting = 1,
Connected = 2,
};
class EmulatorClientSocket : MonoBehaviour {
private static readonly int kPhoneEventPort = 7003;
private const int kSocketReadTimeoutMillis = 5000;
// Minimum interval, in seconds, between attempts to reconnect the socket.
private const float kMinReconnectInterval = 1f;
private TcpClient phoneMirroringSocket;
private Thread phoneEventThread;
private volatile bool shouldStop = false;
// Flag used to limit connection state logging to initial failure and successful reconnects.
private volatile bool lastConnectionAttemptWasSuccessful = true;
private EmulatorManager phoneRemote;
public EmulatorClientSocketConnectionState connected { get; private set; }
public void Init(EmulatorManager remote) {
phoneRemote = remote;
if (EmulatorConfig.Instance.PHONE_EVENT_MODE != EmulatorConfig.Mode.OFF) {
phoneEventThread = new Thread(phoneEventSocketLoop);
phoneEventThread.IsBackground = true;
phoneEventThread.Start();
}
}
private void phoneEventSocketLoop() {
while (!shouldStop) {
long lastConnectionAttemptTime = DateTime.Now.Ticks;
try {
phoneConnect();
} catch(Exception e) {
if (lastConnectionAttemptWasSuccessful) {
Debug.LogWarningFormat("{0}\n{1}", e.Message, e.StackTrace);
// Suppress additional failures until we have successfully reconnected.
lastConnectionAttemptWasSuccessful = false;
}
}
// Wait a while in order to enforce the minimum time between connection attempts.
TimeSpan elapsed = new TimeSpan(DateTime.Now.Ticks - lastConnectionAttemptTime);
float toWait = kMinReconnectInterval - (float) elapsed.TotalSeconds;
if (toWait > 0) {
Thread.Sleep((int) (toWait * 1000));
}
}
}
private void phoneConnect() {
string addr = EmulatorConfig.Instance.PHONE_EVENT_MODE == EmulatorConfig.Mode.USB
? EmulatorConfig.USB_SERVER_IP : EmulatorConfig.WIFI_SERVER_IP;
try {
if (EmulatorConfig.Instance.PHONE_EVENT_MODE == EmulatorConfig.Mode.USB) {
setupPortForwarding(kPhoneEventPort);
}
TcpClient tcpClient = new TcpClient(addr, kPhoneEventPort);
connected = EmulatorClientSocketConnectionState.Connecting;
ProcessConnection(tcpClient);
tcpClient.Close();
} finally {
connected = EmulatorClientSocketConnectionState.Disconnected;
}
}
private void setupPortForwarding(int port) {
#if !UNITY_WEBPLAYER
string adbCommand = string.Format("adb forward tcp:{0} tcp:{0}", port);
System.Diagnostics.Process myProcess = new System.Diagnostics.Process();
string processFilename;
string processArguments;
int kExitCodeCommandNotFound;
if (Application.platform == RuntimePlatform.WindowsEditor ||
Application.platform == RuntimePlatform.WindowsPlayer) {
processFilename = "CMD.exe";
processArguments = @"/k " + adbCommand + " & exit";
// See "Common Error Lookup Tool" (https://www.microsoft.com/en-us/download/details.aspx?id=985)
// MSG_DIR_BAD_COMMAND_OR_FILE (cmdmsg.h)
kExitCodeCommandNotFound = 9009; // 0x2331
} else { // Unix
processFilename = "bash";
processArguments = string.Format("-l -c \"{0}\"", adbCommand);
// "command not found" (see http://tldp.org/LDP/abs/html/exitcodes.html)
kExitCodeCommandNotFound = 127;
}
System.Diagnostics.ProcessStartInfo myProcessStartInfo =
new System.Diagnostics.ProcessStartInfo(processFilename, processArguments);
myProcessStartInfo.UseShellExecute = false;
myProcessStartInfo.RedirectStandardError = true;
myProcessStartInfo.CreateNoWindow = true;
myProcess.StartInfo = myProcessStartInfo;
myProcess.Start();
myProcess.WaitForExit();
// Also wait for HasExited here, to avoid ExitCode access below occasionally throwing InvalidOperationException
while (!myProcess.HasExited) {
Thread.Sleep(1);
}
int exitCode = myProcess.ExitCode;
string standardError = myProcess.StandardError.ReadToEnd();
myProcess.Close();
if (exitCode == 0) {
// Port forwarding setup successfully.
return;
}
if (exitCode == kExitCodeCommandNotFound) {
// Caught by phoneEventSocketLoop.
throw new Exception(
"Android Debug Bridge (`adb`) command not found." +
"\nVerify that the Android SDK is installed and that the directory containing" +
" `adb` is included in your PATH environment variable.");
}
// Caught by phoneEventSocketLoop.
throw new Exception(
string.Format(
"Failed to setup port forwarding." +
" Exit code {0} returned by process: {1} {2}\n{3}",
exitCode, processFilename, processArguments, standardError));
#endif // !UNITY_WEBPLAYER
}
private void ProcessConnection(TcpClient tcpClient) {
byte[] buffer = new byte[4];
NetworkStream stream = tcpClient.GetStream();
stream.ReadTimeout = kSocketReadTimeoutMillis;
tcpClient.ReceiveTimeout = kSocketReadTimeoutMillis;
while (!shouldStop) {
int bytesRead = blockingRead(stream, buffer, 0, 4);
if (bytesRead < 4) {
// Caught by phoneEventSocketLoop.
throw new Exception(
"Failed to read from controller emulator app event socket." +
"\nVerify that the controller emulator app is running.");
}
int msgLen = unpack32bits(correctEndianness(buffer), 0);
byte[] dataBuffer = new byte[msgLen];
bytesRead = blockingRead(stream, dataBuffer, 0, msgLen);
if (bytesRead < msgLen) {
// Caught by phoneEventSocketLoop.
throw new Exception(
"Failed to read from controller emulator app event socket." +
"\nVerify that the controller emulator app is running.");
}
PhoneEvent proto =
PhoneEvent.CreateBuilder().MergeFrom(dataBuffer).Build();
phoneRemote.OnPhoneEvent(proto);
connected = EmulatorClientSocketConnectionState.Connected;
if (!lastConnectionAttemptWasSuccessful) {
Debug.Log("Successfully connected to controller emulator app.");
// Log first failure after after successful read from event socket.
lastConnectionAttemptWasSuccessful = true;
}
}
}
private int blockingRead(NetworkStream stream, byte[] buffer, int index,
int count) {
int bytesRead = 0;
while (!shouldStop && bytesRead < count) {
try {
int n = stream.Read(buffer, index + bytesRead, count - bytesRead);
if (n <= 0) {
// Failed to read.
return -1;
}
bytesRead += n;
} catch (IOException) {
// Read failed or timed out.
return -1;
} catch (ObjectDisposedException) {
// Socket closed.
return -1;
}
}
return bytesRead;
}
void OnDestroy() {
shouldStop = true;
if (phoneMirroringSocket != null) {
phoneMirroringSocket.Close ();
phoneMirroringSocket = null;
}
if (phoneEventThread != null) {
phoneEventThread.Join();
}
}
private int unpack32bits(byte[] array, int offset) {
int num = 0;
for (int i = 0; i < 4; i++) {
num += array [offset + i] << (i * 8);
}
return num;
}
static private byte[] correctEndianness(byte[] array) {
if (BitConverter.IsLittleEndian)
Array.Reverse(array);
return array;
}
}
}
/// @endcond
#endif // UNITY_EDITOR

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 6bf1f92fb4ae24291b71e77c1ccac323
timeCreated: 1462051657
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,60 @@
// Copyright 2016 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using UnityEngine;
/// @cond
namespace Gvr.Internal {
class EmulatorConfig : MonoBehaviour {
public static EmulatorConfig Instance {
get {
if (instance == null) {
EmulatorConfig[] configs = (EmulatorConfig[]) FindObjectsOfType(typeof(EmulatorConfig));
if (configs.Length == 1) {
instance = configs[0];
} else if (configs.Length > 1) {
Debug.LogError(
"Multiple PhoneRemote/Config objects in scene. Ignoring all.");
}
}
if (instance == null) {
var gameObject = new GameObject("PhoneRemoteConfig");
instance = gameObject.AddComponent<EmulatorConfig>();
DontDestroyOnLoad(instance);
}
return instance;
}
}
private static EmulatorConfig instance = null;
public enum Mode {
OFF,
USB,
WIFI,
}
// Set this value to match how the PC is connected to the phone that is
// streaming gyro, accel, and touch events. Set to OFF if using Wifi instead.
public Mode PHONE_EVENT_MODE = Mode.USB;
/*----- Internal Parameters (should not require any changes). -----*/
// IP address of the phone, when connected to the PC via USB.
public static readonly string USB_SERVER_IP = "127.0.0.1";
// IP address of the phone, when connected to the PC via WiFi.
public static readonly string WIFI_SERVER_IP = "192.168.43.1";
}
}
/// @endcond

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: a229fefd8ee7448b0b700f6000ebdec3
timeCreated: 1462051657
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,189 @@
// Copyright 2016 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using proto;
/// @cond
namespace Gvr.Internal {
struct EmulatorGyroEvent {
public readonly long timestamp;
public readonly Vector3 value;
public EmulatorGyroEvent(PhoneEvent.Types.GyroscopeEvent proto) {
timestamp = proto.Timestamp;
value = new Vector3(proto.X, proto.Y, proto.Z);
}
}
struct EmulatorAccelEvent {
public readonly long timestamp;
public readonly Vector3 value;
public EmulatorAccelEvent(PhoneEvent.Types.AccelerometerEvent proto) {
timestamp = proto.Timestamp;
value = new Vector3(proto.X, proto.Y, proto.Z);
}
}
struct EmulatorTouchEvent {
// Action constants. These should match the constants in the Android
// MotionEvent:
// http://developer.android.com/reference/android/view/MotionEvent.html#ACTION_CANCEL
public enum Action {
kActionDown = 0,
kActionUp = 1,
kActionMove = 2,
kActionCancel = 3,
kActionPointerDown = 5,
kActionPointerUp = 6,
kActionHoverMove = 7,
kActionHoverEnter = 9,
kActionHoverExit = 10
};
// Use getActionMasked() and getActionPointer() instead.
private readonly int action;
public readonly int relativeTimestamp;
public readonly List<Pointer> pointers;
public struct Pointer {
public readonly int fingerId;
public readonly float normalizedX;
public readonly float normalizedY;
public Pointer(int fingerId, float normalizedX, float normalizedY) {
this.fingerId = fingerId;
this.normalizedX = normalizedX;
this.normalizedY = normalizedY;
}
public override string ToString () {
return string.Format ("({0}, {1}, {2})", fingerId, normalizedX,
normalizedY);
}
}
public EmulatorTouchEvent(PhoneEvent.Types.MotionEvent proto, long lastDownTimeMs) {
action = proto.Action;
relativeTimestamp =
(Action)(proto.Action & ACTION_MASK) == Action.kActionDown
? 0 : (int) (proto.Timestamp - lastDownTimeMs);
pointers = new List<Pointer>();
foreach (PhoneEvent.Types.MotionEvent.Types.Pointer pointer in
proto.PointersList) {
pointers.Add(
new Pointer(pointer.Id, pointer.NormalizedX, pointer.NormalizedY));
}
}
public EmulatorTouchEvent(Action action, int pointerId, int relativeTimestamp,
List<Pointer> pointers) {
int fingerIndex = 0;
if (action == Action.kActionPointerDown
|| action == Action.kActionPointerUp) {
fingerIndex = findPointerIndex(pointerId, pointers);
if (fingerIndex == -1) {
Debug.LogWarning("Could not find specific fingerId " + pointerId
+ " in the supplied list of pointers.");
fingerIndex = 0;
}
}
this.action = getActionUnmasked(action, fingerIndex);
this.relativeTimestamp = relativeTimestamp;
this.pointers = pointers;
}
// See Android's getActionMasked() and getActionIndex().
private static readonly int ACTION_POINTER_INDEX_SHIFT = 8;
private static readonly int ACTION_POINTER_INDEX_MASK = 0xff00;
private static readonly int ACTION_MASK = 0xff;
public Action getActionMasked() {
return (Action)(action & ACTION_MASK);
}
public Pointer getActionPointer() {
int index =
(action & ACTION_POINTER_INDEX_MASK) >> ACTION_POINTER_INDEX_SHIFT;
return pointers[index];
}
private static int getActionUnmasked(Action action, int fingerIndex) {
return ((int)action) | (fingerIndex << ACTION_POINTER_INDEX_SHIFT);
}
private static int findPointerIndex(int fingerId, List<Pointer> pointers) {
// Encode the fingerId info into the action, as Android does. See Android's
// getActionMasked() and getActionIndex().
int fingerIndex = -1;
for (int i = 0; i < pointers.Count; i++) {
if (fingerId == pointers[i].fingerId) {
fingerIndex = i;
break;
}
}
return fingerIndex;
}
public override string ToString () {
System.Text.StringBuilder builder = new System.Text.StringBuilder ();
builder.AppendFormat("t = {0}; A = {1}; P = {2}; N = {3}; [",
relativeTimestamp, getActionMasked (), getActionPointer ().fingerId,
pointers.Count);
for (int i = 0; i < pointers.Count; i++) {
builder.Append(pointers[i]).Append (", ");
}
builder.Append ("]");
return builder.ToString();
}
}
struct EmulatorOrientationEvent {
public readonly long timestamp;
public readonly Quaternion orientation;
public EmulatorOrientationEvent(PhoneEvent.Types.OrientationEvent proto) {
timestamp = proto.Timestamp;
// Convert from right-handed coordinates to left-handed.
orientation = new Quaternion(proto.X, proto.Y, -proto.Z, proto.W);
}
}
struct EmulatorButtonEvent {
// Codes as reported by the IC app (reuses Android KeyEvent codes).
public enum ButtonCode {
kNone = 0,
kHome = 3, // android.view.KeyEvent.KEYCODE_HOME
kVolumeUp = 25, // android.view.KeyEvent.KEYCODE_VOLUME_UP
kVolumeDown = 24, // android.view.KeyEvent.KEYCODE_VOLUME_DOWN
kClick = 66, // android.view.KeyEvent.KEYCODE_ENTER
kApp = 82, // android.view.KeyEvent.KEYCODE_MENU
}
public readonly ButtonCode code;
public readonly bool down;
public EmulatorButtonEvent(PhoneEvent.Types.KeyEvent proto) {
code = (ButtonCode) proto.Code;
down = proto.Action == 0;
}
}
}
/// @endcond

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 76d2b695633884daf905c07095c8a01c
timeCreated: 1462051657
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,250 @@
// Copyright 2016 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// This class is only used in the Editor, so make sure to only compile it on that platform.
// Additionally, it depends on EmulatorClientSocket which is only compiled in the editor.
// This MonoBehaviour is only ever instantiated dynamically, so it is fine that it is only compiled in the Editor,
// Otherwise it would cause serialization issues.
#if UNITY_EDITOR
using System.Collections;
using UnityEngine;
using proto;
/// @cond
namespace Gvr.Internal {
class EmulatorManager : MonoBehaviour {
private IEnumerator emulatorUpdate;
private WaitForEndOfFrame waitForEndOfFrame = new WaitForEndOfFrame();
public static EmulatorManager Instance {
get {
if (instance == null) {
var gameObject = new GameObject("PhoneRemote");
instance = gameObject.AddComponent<EmulatorManager>();
// This object should survive all scene transitions.
GameObject.DontDestroyOnLoad(instance);
}
return instance;
}
}
private static EmulatorManager instance = null;
public delegate void OnGyroEvent(EmulatorGyroEvent gyroEvent);
public event OnGyroEvent gyroEventListeners {
add {
if (value != null) {
value(currentGyroEvent);
}
gyroEventListenersInternal += value;
}
remove {
gyroEventListenersInternal -= value;
}
}
public delegate void OnAccelEvent(EmulatorAccelEvent accelEvent);
public event OnAccelEvent accelEventListeners {
add {
if (value != null) {
value(currentAccelEvent);
}
accelEventListenersInternal += value;
}
remove {
accelEventListenersInternal -= value;
}
}
public delegate void OnTouchEvent(EmulatorTouchEvent touchEvent);
public event OnTouchEvent touchEventListeners {
add {
if (value != null
&& currentTouchEvent.pointers != null /* null only during init */) {
value(currentTouchEvent);
}
touchEventListenersInternal += value;
}
remove {
touchEventListenersInternal -= value;
}
}
public delegate void OnOrientationEvent(EmulatorOrientationEvent orientationEvent);
public event OnOrientationEvent orientationEventListeners {
add {
if (value != null) {
value(currentOrientationEvent);
}
orientationEventListenersInternal += value;
}
remove {
orientationEventListenersInternal -= value;
}
}
public delegate void OnButtonEvent(EmulatorButtonEvent buttonEvent);
public event OnButtonEvent buttonEventListeners {
add {
if (value != null) {
value(currentButtonEvent);
}
buttonEventListenersInternal += value;
}
remove {
buttonEventListenersInternal -= value;
}
}
private void onGyroEvent(EmulatorGyroEvent e) {
currentGyroEvent = e;
if (gyroEventListenersInternal != null) {
gyroEventListenersInternal(e);
}
}
private void onAccelEvent(EmulatorAccelEvent e) {
currentAccelEvent = e;
if (accelEventListenersInternal != null) {
accelEventListenersInternal(e);
}
}
private void onTouchEvent(EmulatorTouchEvent e) {
currentTouchEvent = e;
if (touchEventListenersInternal != null) {
touchEventListenersInternal(e);
}
}
private void onOrientationEvent(EmulatorOrientationEvent e) {
currentOrientationEvent = e;
if (orientationEventListenersInternal != null) {
orientationEventListenersInternal(e);
}
}
private void onButtonEvent(EmulatorButtonEvent e) {
currentButtonEvent = e;
if (buttonEventListenersInternal != null) {
buttonEventListenersInternal(e);
}
}
EmulatorGyroEvent currentGyroEvent;
EmulatorAccelEvent currentAccelEvent;
EmulatorTouchEvent currentTouchEvent;
EmulatorOrientationEvent currentOrientationEvent;
EmulatorButtonEvent currentButtonEvent;
private event OnGyroEvent gyroEventListenersInternal;
private event OnAccelEvent accelEventListenersInternal;
private event OnTouchEvent touchEventListenersInternal;
private event OnOrientationEvent orientationEventListenersInternal;
private event OnButtonEvent buttonEventListenersInternal;
private Queue pendingEvents = Queue.Synchronized(new Queue());
private EmulatorClientSocket socket;
private long lastDownTimeMs;
public bool Connected {
get {
return socket != null && socket.connected == EmulatorClientSocketConnectionState.Connected;
}
}
public bool Connecting {
get {
return socket != null && socket.connected == EmulatorClientSocketConnectionState.Connecting;
}
}
public void Awake() {
if (instance == null) {
instance = this;
}
if (instance != this) {
Debug.LogWarning("PhoneRemote must be a singleton.");
enabled = false;
return;
}
}
public void Start() {
socket = gameObject.AddComponent<EmulatorClientSocket>();
socket.Init(this);
emulatorUpdate = EndOfFrame();
StartCoroutine(emulatorUpdate);
}
IEnumerator EndOfFrame() {
while (true) {
yield return waitForEndOfFrame;
lock (pendingEvents.SyncRoot) {
while (pendingEvents.Count > 0) {
PhoneEvent phoneEvent = (PhoneEvent) pendingEvents.Dequeue();
ProcessEventAtEndOfFrame(phoneEvent);
}
}
}
}
public void OnPhoneEvent(PhoneEvent e) {
pendingEvents.Enqueue(e);
}
private void ProcessEventAtEndOfFrame(PhoneEvent e) {
switch (e.Type) {
case PhoneEvent.Types.Type.MOTION:
EmulatorTouchEvent touchEvent = new EmulatorTouchEvent(e.MotionEvent, lastDownTimeMs);
onTouchEvent(touchEvent);
if (touchEvent.getActionMasked() == EmulatorTouchEvent.Action.kActionDown) {
lastDownTimeMs = e.MotionEvent.Timestamp;
}
break;
case PhoneEvent.Types.Type.GYROSCOPE:
EmulatorGyroEvent gyroEvent = new EmulatorGyroEvent(e.GyroscopeEvent);
onGyroEvent(gyroEvent);
break;
case PhoneEvent.Types.Type.ACCELEROMETER:
EmulatorAccelEvent accelEvent = new EmulatorAccelEvent(e.AccelerometerEvent);
onAccelEvent(accelEvent);
break;
case PhoneEvent.Types.Type.ORIENTATION:
EmulatorOrientationEvent orientationEvent =
new EmulatorOrientationEvent(e.OrientationEvent);
onOrientationEvent(orientationEvent);
break;
case PhoneEvent.Types.Type.KEY:
EmulatorButtonEvent buttonEvent = new EmulatorButtonEvent(e.KeyEvent);
onButtonEvent(buttonEvent);
break;
default:
Debug.Log("Unsupported PhoneEvent type: " + e.Type);
break;
}
}
}
}
/// @endcond
#endif // UNITY_EDITOR

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: c42ca6bb02b364893b127c681c158442
timeCreated: 1462051658
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 1a6b456eb0cd540a489e0f82c377b187
timeCreated: 1462046540
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: