I_Jemin

Complete UDP/TCP Transporter

Showing 38 changed files with 634 additions and 26 deletions
1 +// 이벤트 종류
2 +public enum NetEventType
3 +{
4 + Connect = 0, // 연결 이벤트
5 + Disconnect, // 끊기 이벤트
6 + SendError, // 송신 오류
7 + ReceiveError, // 수신 오류
8 +}
9 +
10 +// 이벤트 결과
11 +public enum NetEventResult
12 +{
13 + Failure = -1, // 실패
14 + Success = 0, // 성공
15 +}
16 +
17 +// 이벤트 상태 통지용 타입
18 +public class NetEventState
19 +{
20 + public NetEventType type; // 이벤트 타입
21 + public NetEventResult result; // 이벤트 결과
22 +}
...\ No newline at end of file ...\ No newline at end of file
1 +fileFormatVersion: 2
2 +guid: 7a68fdeeae9b0445992ea9d05f42454e
3 +timeCreated: 1517151676
4 +licenseType: Pro
5 +MonoImporter:
6 + externalObjects: {}
7 + serializedVersion: 2
8 + defaultReferences: []
9 + executionOrder: 0
10 + icon: {instanceID: 0}
11 + userData:
12 + assetBundleName:
13 + assetBundleVariant:
1 -using UnityEngine; 1 +using System.Collections;
2 -using System.Collections; 2 +using System.Collections.Generic;
3 +using UnityEngine;
3 using System.Net; 4 using System.Net;
4 using System.Net.Sockets; 5 using System.Net.Sockets;
5 using System.Threading; 6 using System.Threading;
6 7
8 +public class TransportTCP : MonoBehaviour
9 +{
7 10
8 -public class TransportTCP : MonoBehaviour { 11 + // 소켓 액세스 포인트들
9 12
10 - // 소켓 액세스 13 + // 리스닝 소켓
14 + private Socket m_listner = null;
11 15
12 - // 리스너 소켓 16 + // 클라이언트의 접속을 받을 소켓
13 - private Socket m_listener = null; 17 + private Socket m_socket = null;
14 18
19 + private PacketQueue m_sendQueue; // 송신 버퍼
15 20
21 + private PacketQueue m_recvQueue; // 수신 버퍼
16 22
23 + public bool isServer { get; private set;} // 서버 플래그
17 24
25 + public bool isConnected {get; private set;} // 접속 플래그
26 +
27 +
28 + // 이벤트 관련
29 +
30 + // 이벤트 통지 델리게이트 타입 정의
31 + public delegate void EventHandler(NetEventState state);
32 + // 이벤트 핸들러
33 + public event EventHandler onStateChanged;
34 +
35 +
36 + // 스레드 관련 멤버 변수
37 +
38 + // 스레드 실행 프래그
39 + protected bool m_threadLoop = false;
40 + protected Thread m_thread = null;
41 + private static int s_mtu = 1400; // 한번에 읽을 데이터
42 +
43 +
44 + // 초기화 페이즈: 큐 생성
45 + void Awake()
46 + {
47 + m_sendQueue = new PacketQueue();
48 + m_recvQueue = new PacketQueue();
49 + }
50 +
51 + // 서버로서 가동 (대기) 시작
52 + public bool StartServer(int port, int connectionNum)
53 + {
54 +
55 + Debug.Log("Initiate Server!");
56 +
57 + try
58 + {
59 + m_listner = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
60 +
61 + // 대응 대역폭 지정
62 + m_listner.Bind(new IPEndPoint(IPAddress.Any, port));
63 +
64 + m_listner.Listen(connectionNum);
65 + }
66 + catch
67 + {
68 + Debug.Log("Server Failed!");
69 +
70 + return false;
71 + }
72 +
73 + isServer = true;
74 +
75 + bool success = LaunchThread();
76 +
77 + return success;
78 + }
79 +
80 + // 서버로서 대기 종료
81 + public void StopServer()
82 + {
83 + // 쓰레드 종료
84 + m_threadLoop = false;
85 +
86 + if (m_thread != null)
87 + {
88 + m_thread.Join(); // https://msdn.microsoft.com/ko-kr/library/95hbf2ta(v=vs.110).aspx
89 + m_thread = null;
90 + }
91 +
92 + // 접속 종료
93 + Disconnect();
94 +
95 + if(m_listner != null)
96 + {
97 + m_listner.Close();
98 + m_listner = null;
99 + }
100 +
101 + isServer = false;
102 +
103 + Debug.Log("Server Stopped");
104 + }
105 +
106 +
107 + // 접속
108 + public bool Connect(string address, int port)
109 + {
110 + Debug.Log("TransportTCP Connect Called");
111 +
112 + // 이미 리스너 소켓이 선점되어 있다면
113 + if (m_listner != null) {
114 + return false;
115 + }
116 +
117 + bool ret = false;
118 +
119 + try {
120 + m_socket = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
121 +
122 + m_socket.NoDelay = true; // 소켓 지연시간 없음
123 + m_socket.SendBufferSize = 0;
124 + m_socket.Connect(address,port); // 소켓 연결 시작
125 +
126 + // 커넥션 스레드 시작
127 + ret = LaunchThread();
128 + } catch {
129 + // 실패했다면 소켓 파괴
130 + m_socket = null;
131 + }
132 +
133 + if(ret == true)
134 + {
135 + isConnected = true;
136 + Debug.Log("Connection Success");
137 + }
138 + else
139 + {
140 + isConnected = false;
141 + Debug.Log("Connection Fail");
142 + }
143 +
144 + // 리스너가 존재한다면 통지
145 + if(onStateChanged != null) {
146 + NetEventState state = new NetEventState();
147 + state.type = NetEventType.Connect;
148 + state.result = (isConnected == true) ? NetEventResult.Success : NetEventResult.Failure;
149 +
150 + Debug.Log("Event Handler Called");
151 + }
152 +
153 + return isConnected;
154 + }
155 +
156 + // 접속 종료
157 + public void Disconnect()
158 + {
159 + isConnected = false;
160 +
161 + if (m_socket != null)
162 + {
163 + m_socket.Shutdown(SocketShutdown.Both); // 쌍방향 소켓 연결 내리기
164 + m_socket.Close(); // 소켓 종료
165 + m_socket = null; // 소켓 파괴
166 + }
167 +
168 + // 리스터가 존재한다면 접속 종료를 공지
169 + if (onStateChanged != null)
170 + {
171 + // 새로운 네트워크 상태 정보 생성후
172 + NetEventState state = new NetEventState();
173 + state.type = NetEventType.Disconnect;
174 + state.result = NetEventResult.Success;
175 +
176 + // 이벤트로 공지
177 + onStateChanged(state);
178 + }
179 + }
180 +
181 + // 송신 처리
182 + // 큐에 데이터를 넣어놓으면 알아서 쓰레드가 빼가서 보내놓을거라능 ㅇㅅㅇ
183 + public int Send(byte[] data, int size)
184 + {
185 + // 세이프티 체크
186 + if(m_sendQueue == null)
187 + {
188 + return 0;
189 + }
190 +
191 + return m_sendQueue.Enqueue(data,size);
192 + }
193 +
194 +
195 + // 수신 처리
196 + // 큐에 데이터를 넣어놓으면 알아서 쓰레드가 빼가서 보내놓을거라능 ㅇㅅㅇ
197 + public int Receive(ref byte[] data, int size)
198 + {
199 + // 세이프티 체크
200 + if(m_recvQueue == null)
201 + {
202 + return 0;
203 + }
204 +
205 + return m_recvQueue.Dequeue(ref data,size);
206 + }
207 +
208 + // 스레드 실행 함수.
209 + // 목적: 돌려 놓으면 알아서 Send Queue 에 쌓아놓은 데이터는 보내주고
210 + // 온 데이터는 Recv Queue 에 쌓아놓아줌
211 + bool LaunchThread()
212 + {
213 + try {
214 + // Dispatch용 스레드 시작.
215 + m_threadLoop = true;
216 + m_thread = new Thread(new ThreadStart(Dispatch));
217 + m_thread.Start();
218 + }
219 + catch {
220 + Debug.Log("Cannot launch thread.");
221 + return false;
222 + }
223 +
224 + return true;
225 + }
226 +
227 +
228 + // 스레드를 통해 송수신을 처리해주는 실제 패킷큐 처리부
229 + public void Dispatch()
230 + {
231 + Debug.Log("Distpach thread started.");
232 +
233 + // 스레드 루프가 계속 돌아가는 동안
234 + while(m_threadLoop)
235 + {
236 + //클라이언트의 접속을 기다림
237 +
238 + AcceptClient();
239 +
240 +
241 + if(m_socket != null && isConnected == true)
242 + {
243 + // 송신
244 + DispatchSend();
245 +
246 + // 수신
247 + DispatchReceive();
248 + }
249 +
250 + // 실행 간격 5밀리 세컨드
251 + Thread.Sleep(5);
252 + }
253 +
254 + Debug.Log("Dispatch thread ended");
255 + }
256 +
257 + void AcceptClient()
258 + {
259 + // 리스너가 클라이언트를 감지하고 준비됬다면
260 + if(m_listner != null && m_listner.Poll(0, SelectMode.SelectRead))
261 + {
262 + // 클라이언트로부터 통신 소켓 지정
263 + m_socket = m_listner.Accept();
264 +
265 + isConnected = true;
266 + Debug.Log("Connected from client");
267 + }
268 +
269 + }
270 +
271 + void DispatchSend()
272 + {
273 + try{
274 + // 데이터를 보낼 준비가 되있다면
275 + if(m_socket.Poll(0,SelectMode.SelectWrite))
276 + {
277 + // 바이트 배열 생성
278 + byte[] buffer = new byte[s_mtu];
279 +
280 + // 전송 대기큐로부터 데이터를 빼내어 가져옴
281 + int sendSize = m_sendQueue.Dequeue(ref buffer, buffer.Length);
282 +
283 + // 보낼 데이터가 있는 동안 계속 송신-데이터 빼오기 반복
284 + while(sendSize > 0) {
285 + m_socket.Send(buffer, sendSize, SocketFlags.None);
286 + sendSize = m_sendQueue.Dequeue(ref buffer, buffer.Length);
287 + }
288 + }
289 + } catch {
290 + return;
291 + }
292 + }
293 +
294 + void DispatchReceive()
295 + {
296 + try{
297 + // 읽을 데이터가 있으면
298 + while(m_socket.Poll(0,SelectMode.SelectRead)) {
299 + byte[] buffer = new byte[s_mtu];
300 +
301 + int recvSize = m_socket.Receive(buffer,buffer.Length,SocketFlags.None);
302 +
303 + if(recvSize == 0)
304 + {
305 + // 더이상 가져올 데이터가 없다면
306 +
307 + Debug.Log("Diconnect recv from client.");
308 + Disconnect();
309 + }
310 + else if (recvSize > 0) { // 데이터를 가져왔다면 리시브 큐에 적재해둠
311 + m_recvQueue.Enqueue(buffer,recvSize);
312 +
313 + }
314 + }
315 + }
316 + catch {
317 + return;
318 + }
319 + }
18 } 320 }
......
...@@ -3,11 +3,286 @@ using System.Collections.Generic; ...@@ -3,11 +3,286 @@ using System.Collections.Generic;
3 using UnityEngine; 3 using UnityEngine;
4 using System.Net; 4 using System.Net;
5 using System.Net.Sockets; 5 using System.Net.Sockets;
6 +using System.Threading;
6 7
7 -public class TransportUDP : MonoBehaviour { 8 +public class TransportUDP : MonoBehaviour
9 +{
8 10
9 // 소켓 액세스 포인트들 11 // 소켓 액세스 포인트들
10 12
11 // 클라이언트의 접속을 받을 소켓 13 // 클라이언트의 접속을 받을 소켓
12 private Socket m_socket = null; 14 private Socket m_socket = null;
15 +
16 + private PacketQueue m_sendQueue; // 송신 버퍼
17 +
18 + private PacketQueue m_recvQueue; // 수신 버퍼
19 +
20 + public bool isServer { get; private set;} // 서버 플래그
21 +
22 + public bool isConnected {get; private set;} // 접속 플래그
23 +
24 +
25 + // 이벤트 관련
26 +
27 + // 이벤트 통지 델리게이트 타입 정의
28 + public delegate void EventHandler(NetEventState state);
29 + // 이벤트 핸들러
30 + public event EventHandler onStateChanged;
31 +
32 +
33 + // 스레드 관련 멤버 변수
34 +
35 + // 스레드 실행 프래그
36 + protected bool m_threadLoop = false;
37 + protected Thread m_thread = null;
38 + private static int s_mtu = 1400; // 한번에 읽을 데이터
39 +
40 +
41 + // 초기화 페이즈: 큐 생성
42 + void Awake()
43 + {
44 + m_sendQueue = new PacketQueue();
45 + m_recvQueue = new PacketQueue();
46 + }
47 +
48 + // 서버로서 가동 (대기) 시작
49 + public bool StartServer(int port, int connectionNum)
50 + {
51 +
52 + Debug.Log("Initiate Server!");
53 +
54 + try
55 + {
56 + // 소켓 생성후
57 + m_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Udp);
58 +
59 + // 대응 대역폭 지정
60 + m_socket.Bind(new IPEndPoint(IPAddress.Any, port));
61 + }
62 + catch
63 + {
64 + Debug.Log("Server Failed!");
65 +
66 + return false;
67 + }
68 +
69 + isServer = true;
70 +
71 + bool success = LaunchThread();
72 +
73 + return success;
74 + }
75 +
76 + // 서버로서 대기 종료
77 + public void StopServer()
78 + {
79 + // 쓰레드 종료
80 + m_threadLoop = false;
81 +
82 + if (m_thread != null)
83 + {
84 + m_thread.Join();
85 + m_thread = null;
86 + }
87 +
88 + // 접속 종료
89 + Disconnect();
90 +
91 + isServer = false;
92 +
93 + Debug.Log("Server Stopped");
94 + }
95 +
96 + public bool Connect(string address, int port)
97 + {
98 + Debug.Log("TransportUDP Connect Called");
99 +
100 + // 이미 통신 소켓이 선점되어 있다면
101 + if (m_socket != null) {
102 + return false;
103 + }
104 +
105 + bool ret = false;
106 +
107 + try {
108 + m_socket = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Udp);
109 +
110 + m_socket.NoDelay = true; // 소켓 지연시간 없음
111 + m_socket.Connect(address,port); // 소켓 연결 시작
112 +
113 + // 커넥션 스레드 시작
114 + ret = LaunchThread();
115 + } catch {
116 + // 실패했다면 소켓 파괴
117 + m_socket = null;
118 + }
119 +
120 + if(ret == true)
121 + {
122 + isConnected = true;
123 + Debug.Log("Connection Success");
124 + }
125 + else
126 + {
127 + isConnected = false;
128 + Debug.Log("Connection Fail");
129 + }
130 +
131 + // 리스너가 존재한다면 통지
132 + if(onStateChanged != null) {
133 + NetEventState state = new NetEventState();
134 + state.type = NetEventType.Connect;
135 + state.result = (isConnected == true) ? NetEventResult.Success : NetEventResult.Failure;
136 +
137 + Debug.Log("Event Handler Called");
138 + }
139 +
140 + return isConnected;
141 + }
142 +
143 + // 접속 종료
144 + public void Disconnect()
145 + {
146 + isConnected = false;
147 +
148 + if (m_socket != null)
149 + {
150 + m_socket.Shutdown(SocketShutdown.Both); // 쌍방향 소켓 연결 내리기
151 + m_socket.Close(); // 소켓 종료
152 + m_socket = null; // 소켓 파괴
153 + }
154 +
155 + // 리스터가 존재한다면 접속 종료를 공지
156 + if (onStateChanged != null)
157 + {
158 + // 새로운 네트워크 상태 정보 생성후
159 + NetEventState state = new NetEventState();
160 + state.type = NetEventType.Disconnect;
161 + state.result = NetEventResult.Success;
162 +
163 + // 이벤트로 공지
164 + onStateChanged(state);
165 + }
166 + }
167 +
168 + // 송신 처리
169 + // 큐에 데이터를 넣어놓으면 알아서 쓰레드가 빼가서 보내놓을거라능 ㅇㅅㅇ
170 + public int Send(byte[] data, int size)
171 + {
172 + // 세이프티 체크
173 + if(m_sendQueue == null)
174 + {
175 + return 0;
176 + }
177 +
178 + return m_sendQueue.Enqueue(data,size);
179 + }
180 +
181 +
182 + // 수신 처리
183 + // 큐에 데이터를 넣어놓으면 알아서 쓰레드가 빼가서 보내놓을거라능 ㅇㅅㅇ
184 + public int Receive(ref byte[] data, int size)
185 + {
186 + // 세이프티 체크
187 + if(m_recvQueue == null)
188 + {
189 + return 0;
190 + }
191 +
192 + return m_recvQueue.Dequeue(ref data,size);
193 + }
194 +
195 + // 스레드 실행 함수.
196 + // 목적: 돌려 놓으면 알아서 Send Queue 에 쌓아놓은 데이터는 보내주고
197 + // 온 데이터는 Recv Queue 에 쌓아놓아줌
198 + bool LaunchThread()
199 + {
200 + try {
201 + // Dispatch용 스레드 시작.
202 + m_threadLoop = true;
203 + m_thread = new Thread(new ThreadStart(Dispatch));
204 + m_thread.Start();
205 + }
206 + catch {
207 + Debug.Log("Cannot launch thread.");
208 + return false;
209 + }
210 +
211 + return true;
212 + }
213 +
214 +
215 + // 스레드를 통해 송수신을 처리해주는 실제 패킷큐 처리부
216 + public void Dispatch()
217 + {
218 + Debug.Log("Distpach thread started.");
219 +
220 + // 스레드 루프가 계속 돌아가는 동안
221 + while(m_threadLoop)
222 + {
223 + if(m_socket != null && isConnected == true)
224 + {
225 + // 송신
226 + DispatchSend();
227 +
228 + // 수신
229 + DispatchReceive();
230 + }
231 +
232 + // 실행 간격 5밀리 세컨드
233 + Thread.Sleep(5);
234 + }
235 +
236 + Debug.Log("Dispatch thread ended");
237 + }
238 +
239 + void DispatchSend()
240 + {
241 + try{
242 + // 데이터를 보낼 준비가 되있다면
243 + if(m_socket.Poll(0,SelectMode.SelectWrite))
244 + {
245 + // 바이트 배열 생성
246 + byte[] buffer = new byte[s_mtu];
247 +
248 + // 전송 대기큐로부터 데이터를 빼내어 가져옴
249 + int sendSize = m_sendQueue.Dequeue(ref buffer, buffer.Length);
250 +
251 + // 보낼 데이터가 있는 동안 계속 송신-데이터 빼오기 반복
252 + while(sendSize > 0) {
253 + m_socket.Send(buffer, sendSize, SocketFlags.None);
254 + sendSize = m_sendQueue.Dequeue(ref buffer, buffer.Length);
255 + }
256 + }
257 + } catch {
258 + return;
259 + }
260 + }
261 +
262 + void DispatchReceive()
263 + {
264 + try{
265 + // 읽을 데이터가 있으면
266 + while(m_socket.Poll(0,SelectMode.SelectRead)) {
267 + byte[] buffer = new byte[s_mtu];
268 +
269 + int recvSize = m_socket.Receive(buffer,buffer.Length,SocketFlags.None);
270 +
271 + if(recvSize == 0)
272 + {
273 + // 더이상 가져올 데이터가 없다면
274 +
275 + Debug.Log("Diconnect recv from client.");
276 + Disconnect();
277 + }
278 + else if (recvSize > 0) { // 데이터를 가져왔다면 리시브 큐에 적재해둠
279 + m_recvQueue.Enqueue(buffer,recvSize);
280 +
281 + }
282 + }
283 + }
284 + catch {
285 + return;
286 + }
287 + }
13 } 288 }
......
...@@ -70,7 +70,7 @@ MonoBehaviour: ...@@ -70,7 +70,7 @@ MonoBehaviour:
70 m_MinSize: {x: 277, y: 192} 70 m_MinSize: {x: 277, y: 192}
71 m_MaxSize: {x: 4002, y: 8042} 71 m_MaxSize: {x: 4002, y: 8042}
72 vertical: 1 72 vertical: 1
73 - controlID: 131 73 + controlID: 147
74 --- !u!114 &4 74 --- !u!114 &4
75 MonoBehaviour: 75 MonoBehaviour:
76 m_ObjectHideFlags: 52 76 m_ObjectHideFlags: 52
...@@ -119,7 +119,7 @@ MonoBehaviour: ...@@ -119,7 +119,7 @@ MonoBehaviour:
119 m_MinSize: {x: 234, y: 492} 119 m_MinSize: {x: 234, y: 492}
120 m_MaxSize: {x: 10004, y: 14042} 120 m_MaxSize: {x: 10004, y: 14042}
121 vertical: 1 121 vertical: 1
122 - controlID: 73 122 + controlID: 94
123 --- !u!114 &6 123 --- !u!114 &6
124 MonoBehaviour: 124 MonoBehaviour:
125 m_ObjectHideFlags: 52 125 m_ObjectHideFlags: 52
...@@ -188,7 +188,7 @@ MonoBehaviour: ...@@ -188,7 +188,7 @@ MonoBehaviour:
188 m_MinSize: {x: 713, y: 492} 188 m_MinSize: {x: 713, y: 492}
189 m_MaxSize: {x: 18008, y: 14042} 189 m_MaxSize: {x: 18008, y: 14042}
190 vertical: 0 190 vertical: 0
191 - controlID: 130 191 + controlID: 93
192 --- !u!114 &9 192 --- !u!114 &9
193 MonoBehaviour: 193 MonoBehaviour:
194 m_ObjectHideFlags: 52 194 m_ObjectHideFlags: 52
...@@ -389,9 +389,9 @@ MonoBehaviour: ...@@ -389,9 +389,9 @@ MonoBehaviour:
389 m_PersistentViewDataDictionary: {fileID: 0} 389 m_PersistentViewDataDictionary: {fileID: 0}
390 m_TreeViewState: 390 m_TreeViewState:
391 scrollPos: {x: 0, y: 0} 391 scrollPos: {x: 0, y: 0}
392 - m_SelectedIDs: eaffffff 392 + m_SelectedIDs:
393 m_LastClickedID: 0 393 m_LastClickedID: 0
394 - m_ExpandedIDs: d8f9ffff00000000 394 + m_ExpandedIDs: 92fbffff00000000
395 m_RenameOverlay: 395 m_RenameOverlay:
396 m_UserAcceptedRename: 0 396 m_UserAcceptedRename: 0
397 m_Name: 397 m_Name:
...@@ -441,7 +441,7 @@ MonoBehaviour: ...@@ -441,7 +441,7 @@ MonoBehaviour:
441 width: 565 441 width: 565
442 height: 636 442 height: 636
443 m_PersistentViewDataDictionary: {fileID: 0} 443 m_PersistentViewDataDictionary: {fileID: 0}
444 - m_ScrollPosition: {x: 0, y: 586.21094} 444 + m_ScrollPosition: {x: 0, y: 0}
445 m_InspectorMode: 0 445 m_InspectorMode: 0
446 m_PreviewResizer: 446 m_PreviewResizer:
447 m_CachedPref: -160 447 m_CachedPref: -160
...@@ -487,20 +487,20 @@ MonoBehaviour: ...@@ -487,20 +487,20 @@ MonoBehaviour:
487 m_ShowAllHits: 0 487 m_ShowAllHits: 0
488 m_SearchArea: 0 488 m_SearchArea: 0
489 m_Folders: 489 m_Folders:
490 - - Assets 490 + - Assets/Scripts
491 m_ViewMode: 1 491 m_ViewMode: 1
492 m_StartGridSize: 64 492 m_StartGridSize: 64
493 m_LastFolders: 493 m_LastFolders:
494 - - Assets 494 + - Assets/Scripts
495 m_LastFoldersGridSize: -1 495 m_LastFoldersGridSize: -1
496 - m_LastProjectPath: /Users/jeminlee/git-projects/Basic-Socket-Programming-with-Unity/Basic 496 + m_LastProjectPath: /Users/jeminlee/git-projects/dotnet-Network-Programming-with-Unity/Basic
497 Network Library 497 Network Library
498 m_IsLocked: 0 498 m_IsLocked: 0
499 m_FolderTreeState: 499 m_FolderTreeState:
500 scrollPos: {x: 0, y: 0} 500 scrollPos: {x: 0, y: 0}
501 - m_SelectedIDs: b6280000 501 + m_SelectedIDs: a0270000
502 - m_LastClickedID: 10422 502 + m_LastClickedID: 10144
503 - m_ExpandedIDs: b628000000ca9a3bffffff7f 503 + m_ExpandedIDs: 000000009227000000ca9a3bffffff7f
504 m_RenameOverlay: 504 m_RenameOverlay:
505 m_UserAcceptedRename: 0 505 m_UserAcceptedRename: 0
506 m_Name: 506 m_Name:
...@@ -528,7 +528,7 @@ MonoBehaviour: ...@@ -528,7 +528,7 @@ MonoBehaviour:
528 scrollPos: {x: 0, y: 0} 528 scrollPos: {x: 0, y: 0}
529 m_SelectedIDs: 529 m_SelectedIDs:
530 m_LastClickedID: 0 530 m_LastClickedID: 0
531 - m_ExpandedIDs: 531 + m_ExpandedIDs: 0000000092270000
532 m_RenameOverlay: 532 m_RenameOverlay:
533 m_UserAcceptedRename: 0 533 m_UserAcceptedRename: 0
534 m_Name: 534 m_Name:
...@@ -555,7 +555,7 @@ MonoBehaviour: ...@@ -555,7 +555,7 @@ MonoBehaviour:
555 m_ListAreaState: 555 m_ListAreaState:
556 m_SelectedInstanceIDs: 556 m_SelectedInstanceIDs:
557 m_LastClickedInstanceID: 0 557 m_LastClickedInstanceID: 0
558 - m_HadKeyboardFocusLastEvent: 0 558 + m_HadKeyboardFocusLastEvent: 1
559 m_ExpandedInstanceIDs: 559 m_ExpandedInstanceIDs:
560 m_RenameOverlay: 560 m_RenameOverlay:
561 m_UserAcceptedRename: 0 561 m_UserAcceptedRename: 0
......
1 -{
2 - "process_id" : 2262,
3 - "version" : "2017.3.0p3"
4 -}
...\ No newline at end of file ...\ No newline at end of file
1 -13618c6e4cac08c053b4c6480a12c062c880a4be 1 +f4d2a52a7ae35650c675960e6c91d6581973cd3e
......