FANDOM


LF2 has built-in capabilities for two computers to connect to each other. With each side supporting up to 4 players using different controls, a total of 8 players can be in the same game this way. However, most keyboards can't process so many keys being pressed at the same time. With certain fan-made tools it is possible for up to 8 different computers to connect.

Third party toolsEdit

LF2 allows two computers that are on the same IP network to connect to each other. This means that two people who are on the same LAN can connect to each other. However, in practice, most people are connected to the Internet behind a NAT router, meaning that connecting through the Internet is not possible without some extra work. Explaining how to play online is outside the scope of this wiki, but in the LF2 community the most popular methods are currently:

  • Configuring one's router to forward TCP port 12345
  • Hamachi, a freemium VPN app
  • LF2 Lobby, which supports up to 4 players
  • Multiserver, which supports up to 8 players

InternalsEdit

The workings of LF2's network protocol have been reverse engineered by many different people in the course of building the third party multiplayer tools. That being said, documentation is hard to come by. The following Java code demonstrates how to create a server that accepts connections from LF2 (credit probably goes to Azriel):

class Server {

   private TcpListener tcpListener;
   private Thread listenThread;
   private byte[] array;
   private ArrayList list;
   private int numberOfPeople = 0;
   private ManualResetEvent[] resetEvents;
   private byte[][] packets;
   
   public Server() {
       this.tcpListener = new TcpListener(IPAddress.Any, 12345);
       this.listenThread = new Thread(new ThreadStart(ListenForClients));
       this.listenThread.Start();
       this.array = new byte[3001];
       list = new ArrayList();
       resetEvents = new ManualResetEvent[2];
       for (int i = 0; i < resetEvents.Length; i++) {
           resetEvents[i] = new ManualResetEvent(false);
       }
       packets = new byte[4][];
   }
   
   private void ListenForClients() {
       this.tcpListener.Start();
       Random random = new Random();
       random.NextBytes(array);
       while (true) {
           //blocks until a client has connected to the server
           TcpClient client = this.tcpListener.AcceptTcpClient();
           numberOfPeople++;
           Thread clientThread;
           //create a thread to handle communication
           //with connected client
           if (numberOfPeople > 2) clientThread = new Thread(new ParameterizedThreadStart(HandleClientSpec));
           else clientThread = new Thread(new ParameterizedThreadStart(HandleClientPlayer));
           clientThread.Start(client);
       }
   }
   
   private void HandleClientSpec(object client) {
       lf2Logic(client, numberOfPeople);
   }
   
   private void HandleClientPlayer(object client) {
       lf2Logic(client, numberOfPeople);
   }
   
   private void lf2Logic(object client, int player) {
       TcpClient tcpClient = (TcpClient) client;
       NetworkStream clientStream = tcpClient.GetStream();
       
       byte[] message = new byte[78];
       int bytesRead;
       int state = 0;
       int nextState = 0;
       
       while (true) {
           state = nextState;
           bytesRead = 0;
           try {
               switch (state) {
               case 0:
                   clientStream.Write(System.Text.Encoding.ASCII.GetBytes("u can connect\0"), 0, 13);
                   nextState = 1;
                   break;
               case 1:
                   bytesRead = clientStream.Read(message, 0, 77);
                   nextState = 2;
                   break;
               case 2:
                   switch (player) {
                   case 1:
                       clientStream.Write(System.Text.Encoding.ASCII.GetBytes("111101110000000000000000000000001__________2__________3__________4__________\0"), 0, 77);
                       break;
                   case 2:
                       clientStream.Write(System.Text.Encoding.ASCII.GetBytes("111110110000000000000000000000001__________2__________3__________4__________\0"), 0, 77);
                       break;
                   }
                   nextState = 3;
                   break;
               case 3:
                   while (numberOfPeople < 2) {};
                   clientStream.Write(array, 0, 3001);
                   nextState = 4;
                   break;
               case 4:
                   resetEvents[(player - 1)].Set();
                   bytesRead = clientStream.Read(message, 0, 22);
                   WaitHandle.WaitAll(resetEvents);
                   packets[player - 1] = message;
                   nextState = 5;
                   resetEvents[(player - 1)].Reset();
                   break;
               case 5:
                   resetEvents[(player - 1)].Set();
                   WaitHandle.WaitAll(resetEvents);
                   
                   for (int i = 0; i < numberOfPeople; i++) {
                       message[4 + i] = packets[i][4 + i];
                   }
                   
                   nextState = 6;
                   break;
               case 6:
                   resetEvents[(player - 1)].Reset();
                   clientStream.Write(message, 0, 22);
                   nextState = 7;
                   break;
               case 7:
                   nextState = 4;
                   break;
               }
           } catch {
               break;
           }
       }
       
       tcpClient.Close();
   }

}