Advertisement
asqapro

Unity Multiplayer using Sockets

Jan 30th, 2014
113
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 6.90 KB | None | 0 0
  1. using UnityEngine;
  2. using System;
  3. using System.Collections;
  4. using System.Net;
  5. using System.Net.Sockets;
  6. using System.Threading;
  7.  
  8. public class accept_thread_check{ //class for the accept() threads (to avoid blocking)
  9.     public bool done = false;
  10.     public Socket connection;
  11. }
  12.  
  13. public class holder{ //class for a socket and thread container, and to see if each connection is open
  14.     public Socket[] s_holder;
  15.     public Thread[] t_holder;
  16.     public bool[] open_closed;
  17. }
  18.  
  19. public class data_array{ //class to create jagged multi-type array for receiving and sending
  20.     public Socket connection;
  21.     public double[] data_double {get;set;}
  22.     public double[] data_double_temp {get;set;}
  23.     public byte[] data_byte {get;set;}
  24.     //public byte[] data_byte_temp {get;set;} //not currently in use
  25. }
  26.  
  27. public class Client : MonoBehaviour{
  28.     int player_count = -1; //number of players. set by outside script before Start() is called
  29.  
  30.     //IPAddress[] ipaddrs; //currently no need to store the connected IP Adresses
  31.  
  32.     data_array[] data; //array of objects for the data_array class
  33.  
  34.     holder holder_obj = new holder(); //object for the holder_object class
  35.     int holder_obj_index = 0; //reference to the current index of both arrays in the class
  36.    
  37.     accept_thread_check[] setup_server(){ //sets up the main part of the server
  38.         //ipaddrs = new IPAddress[player_count];
  39.         Socket[] listeners = new Socket[player_count]; //creates the listener array
  40.         data = new data_array[player_count]; //creates the data_array array
  41.         IPHostEntry local_host = Dns.GetHostEntry(Dns.GetHostName()); //gets the local IP
  42.         IPAddress local_ip = local_host.AddressList[0]; //gets the local IP
  43.         IPEndPoint localEndPoint = new IPEndPoint(local_ip, 0); //gets the local IP
  44.         for(int iter = 0; iter < player_count; iter++){
  45.             listeners[iter].Bind(localEndPoint); //sets up listeners on the local IP
  46.             listeners[iter].Listen(player_count); //sets up listeners on the local IP
  47.         }
  48.  
  49.         Thread[] accepter_threads = new Thread[player_count]; //creates the array to hold the accept threads
  50.         accept_thread_check[] accept_thread_check_arr_local = new accept_thread_check[player_count]; //array of the class for the accept threads
  51.         for(int iter_i = 0; iter_i < player_count; iter_i++){
  52.             accept_thread_check_arr_local[iter_i] = new accept_thread_check(); //populates the accept thread check array
  53.         }
  54.         for(int iter = 0; iter < player_count; iter++){
  55.             accepter_threads[iter] = new Thread(() => accept_socket_thread(listeners[iter], accept_thread_check_arr_local[iter]));
  56.             accepter_threads[iter].Start(); //creates the threads within the accept threads array
  57.         }
  58.  
  59.         return accept_thread_check_arr_local; //return the refernce to the array of the class
  60.     }
  61.  
  62.     void accept_socket_thread(Socket listener, accept_thread_check is_done){ //thread to accept connections
  63.         is_done.connection = listener.Accept(); //accept() is blocking, asynchronous Sockets will come later
  64.         is_done.done = true;
  65.     }
  66.  
  67.     Socket server_accept_conn(accept_thread_check[] accept_thread_check_arr){ //get the connected sockets
  68.         for(int iter = 0; iter < player_count; iter++){
  69.             if(accept_thread_check_arr[iter].done){
  70.                     return accept_thread_check_arr[iter].connection; //if there is a connection, return the socket
  71.             }
  72.         }
  73.         return null; //otherwise, return nothing
  74.     }
  75.  
  76.     void read_socket_conn(){ //thread to read data on connections
  77.         while(true){ //own thread, run forever
  78.             for(int iter = 0; iter < player_count; iter++){ //for each possible connection, there may be data. update to come to only check active connections
  79.                 if(data[iter].connection.Available > 0){ //receiving data
  80.                     data[iter].data_double_temp = new double[data[iter].data_double.Length]; //set the size of the temp
  81.                     data[iter].data_double_temp = data[iter].data_double; //preserve the original data
  82.                     data[iter].data_double = new double[data[iter].data_double_temp.Length+1]; //increase the size of the array by 1
  83.                     for(int resize = 0; resize < data[iter].data_double_temp.Length; resize++){
  84.                         data[iter].data_double[resize] = data[iter].data_double_temp[resize]; //copy the old into the new
  85.                     }
  86.                     data[iter].data_byte = new byte[data[iter].connection.Available]; //byte array to receive the data in
  87.                     data[iter].connection.Receive(data[iter].data_byte); //receive the data
  88.                     data[iter].data_double[data[iter].data_double.Length] = BitConverter.ToDouble(data[iter].data_byte, 0); //convert bytes to double, add to array
  89.                 }
  90.             }
  91.             for(int iter = 0; iter < player_count; iter++){ //sending data
  92.                 //todo:
  93.                 //find way to send data to all connections except connection received from
  94.                 //find way to send to self (if received from outsite source)
  95.                 if(data[iter].data_double.Length > 0){ //if there is data to be sent
  96.                     for(int send_iter = 0; send_iter < data[iter].data_double.Length; send_iter++){ //for each double in the array
  97.                         data[iter].connection.Send(BitConverter.GetBytes(data[iter].data_double[send_iter])); //convert it to bytes, send it
  98.                         data[iter].data_double_temp = new double[data[iter].data_double.Length]; //set the size of the temp array
  99.                         data[iter].data_double_temp = data[iter].data_double; //preserve the original data
  100.                         data[iter].data_double = new double[data[iter].data_double_temp.Length-1]; //decrease the size of the array by 1
  101.                         for(int resize = 1; resize < data[iter].data_double.Length; resize++){
  102.                             data[iter].data_double[resize] = data[iter].data_double_temp[resize]; //copy the old into the new, minus 1 entry (entry is already sent)
  103.                         }
  104.                     }
  105.                 }
  106.             }
  107.         }
  108.     }
  109.  
  110.     accept_thread_check[] accept_thread_check_arr; //array of class objects
  111.  
  112.     // Use this for initialization
  113.     void Start (){
  114.         if(player_count < 1){ //if the amount of players was not set when this script is called
  115.             player_count = 1; //make sure there is at least 1 player
  116.         }
  117.         accept_thread_check_arr = new accept_thread_check[player_count]; //set the array size
  118.         accept_thread_check_arr = setup_server(); //populate the waiting-to-accept array
  119.         holder_obj.s_holder = new Socket[player_count]; //initialize the socket_holder
  120.         holder_obj.t_holder = new Thread[player_count]; //and the thread_holder
  121.     }
  122.  
  123.     double conn_check_wait = 0.5; //time to wait between checking for new connections (to ease comp usage)
  124.     double next_check = 0; //when the next check will happen
  125.  
  126.     Socket temp; //a temporary socket for checking connections, in case it returns null
  127.  
  128.     // Update is called once per frame (Unity method)
  129.     void Update () {
  130.         if(Time.time > next_check){ //if enough time has passed
  131.             next_check = Time.time + conn_check_wait; //set the next_check time
  132.             temp = server_accept_conn(accept_thread_check_arr); //accept the connection (store in temp in case it is null)
  133.             if(temp != null){ //if there is a connection
  134.                 holder_obj.s_holder[holder_obj_index] = temp; //store it in the holder_obj array
  135.                 holder_obj_index++; //increase the index for the next entry
  136.             }
  137.         }
  138.     }
  139. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement