diff --git a/network/netplay/netplay.c b/network/netplay/netplay.c
index 9aea43cc03..3b0d36beff 100644
--- a/network/netplay/netplay.c
+++ b/network/netplay/netplay.c
@@ -1471,6 +1471,10 @@ bool init_netplay(bool is_spectate, const char *server, unsigned port)
       quirks |= NETPLAY_QUIRK_NO_TRANSMISSION;
    if (serialization_quirks & NETPLAY_QUIRK_MAP_INITIALIZATION)
       quirks |= NETPLAY_QUIRK_INITIALIZATION;
+   if (serialization_quirks & NETPLAY_QUIRK_MAP_ENDIAN_DEPENDENT)
+      quirks |= NETPLAY_QUIRK_ENDIAN_DEPENDENT;
+   if (serialization_quirks & NETPLAY_QUIRK_MAP_PLATFORM_DEPENDENT)
+      quirks |= NETPLAY_QUIRK_PLATFORM_DEPENDENT;
 
    if (netplay_is_client)
    {
diff --git a/network/netplay/netplay_common.c b/network/netplay/netplay_common.c
index dc2033978b..782f8b9b42 100644
--- a/network/netplay/netplay_common.c
+++ b/network/netplay/netplay_common.c
@@ -125,24 +125,61 @@ uint32_t netplay_impl_magic(void)
    return res;
 }
 
-bool netplay_send_info(netplay_t *netplay)
+/**
+ * netplay_platform_magic
+ *
+ * Just enough info to tell us if our platforms mismatch: Endianness and a
+ * couple of type sizes.
+ *
+ * Format:
+ *    bit 31:     Reserved
+ *    bit 30:     1 for big endian
+ *    bits 29-15: sizeof(size_t)
+ *    bits 14-0:  sizeof(long)
+ */
+static uint32_t netplay_platform_magic(void)
+{
+   uint32_t ret =
+       ((1 == htonl(1)) << 30)
+      |(sizeof(size_t) << 15)
+      |(sizeof(long));
+   return ret;
+}
+
+/**
+ * netplay_endian_mismatch
+ *
+ * Do the platform magics mismatch on endianness?
+ */
+static bool netplay_endian_mismatch(uint32_t pma, uint32_t pmb)
+{
+   uint32_t ebit = (1<<30);
+   return (pma & ebit) != (pmb & ebit);
+}
+
+bool netplay_handshake(netplay_t *netplay)
 {
    unsigned sram_size, remote_sram_size;
    retro_ctx_memory_info_t mem_info;
    char msg[512]             = {0};
    uint32_t *content_crc_ptr = NULL;
    void *sram                = NULL;
-   uint32_t header[3]        = {0};
+   uint32_t header[4]        = {0};
    size_t i;
+   uint32_t local_pmagic, remote_pmagic;
+   bool is_server = netplay->is_server;
 
    mem_info.id = RETRO_MEMORY_SAVE_RAM;
 
    core_get_memory(&mem_info);
    content_get_crc(&content_crc_ptr);
 
+   local_pmagic = netplay_platform_magic();
+
    header[0] = htonl(*content_crc_ptr);
    header[1] = htonl(netplay_impl_magic());
    header[2] = htonl(mem_info.size);
+   header[3] = htonl(local_pmagic);
 
    if (!socket_send_all_blocking(netplay->fd, header, sizeof(header), false))
       return false;
@@ -176,62 +213,116 @@ bool netplay_send_info(netplay_t *netplay)
       RARCH_WARN("Content SRAM sizes do not correspond.\n");
    }
 
-   if (!netplay_send_nickname(netplay, netplay->fd))
+   /* We only care about platform magic if our core is quirky */
+   remote_pmagic = ntohl(header[3]);
+   if ((netplay->quirks & NETPLAY_QUIRK_ENDIAN_DEPENDENT) &&
+       netplay_endian_mismatch(local_pmagic, remote_pmagic))
    {
-      RARCH_ERR("%s\n",
-            msg_hash_to_str(MSG_FAILED_TO_SEND_NICKNAME_TO_HOST));
+      RARCH_ERR("Endianness mismatch with an endian-sensitive core.\n");
+      return false;
+   }
+   if ((netplay->quirks & NETPLAY_QUIRK_PLATFORM_DEPENDENT) &&
+       (local_pmagic != remote_pmagic))
+   {
+      RARCH_ERR("Platform mismatch with a platform-sensitive core.\n");
       return false;
    }
 
-   /* Get SRAM data from User 1. */
-   if (sram_size != 0 && sram_size == remote_sram_size)
+   /* Client sends nickname first, server replies with nickname */
+   if (!is_server)
    {
-      sram      = mem_info.data;
-
-      if (!socket_receive_all_blocking(netplay->fd, sram, sram_size))
+      if (!netplay_send_nickname(netplay, netplay->fd))
       {
          RARCH_ERR("%s\n",
-               msg_hash_to_str(MSG_FAILED_TO_RECEIVE_SRAM_DATA_FROM_HOST));
+               msg_hash_to_str(MSG_FAILED_TO_SEND_NICKNAME_TO_HOST));
+         return false;
+      }
+   }
+
+   if (!netplay_get_nickname(netplay, netplay->fd))
+   {
+      if (is_server)
+         RARCH_ERR("%s\n",
+               msg_hash_to_str(MSG_FAILED_TO_GET_NICKNAME_FROM_CLIENT));
+      else
+         RARCH_ERR("%s\n", 
+               msg_hash_to_str(MSG_FAILED_TO_RECEIVE_NICKNAME_FROM_HOST));
+      return false;
+   }
+
+   if (is_server)
+   {
+      if (!netplay_send_nickname(netplay, netplay->fd))
+      {
+         RARCH_ERR("%s\n",
+               msg_hash_to_str(MSG_FAILED_TO_SEND_NICKNAME_TO_CLIENT));
+         return false;
+      }
+   }
+
+   /* Server sends SRAM, client receives */
+   if (is_server)
+   {
+      /* Send SRAM data to the client */
+      sram      = mem_info.data;
+
+      if (!socket_send_all_blocking(netplay->fd, sram, sram_size, false))
+      {
+         RARCH_ERR("%s\n",
+               msg_hash_to_str(MSG_FAILED_TO_SEND_SRAM_DATA_TO_CLIENT));
          return false;
       }
 
    }
-   else if (remote_sram_size != 0)
+   else
    {
-      /* We can't load this, but we still need to get rid of the data */
-      uint32_t quickbuf;
-      while (remote_sram_size > 0)
+      /* Get SRAM data from User 1. */
+      if (sram_size != 0 && sram_size == remote_sram_size)
       {
-         if (!socket_receive_all_blocking(netplay->fd, &quickbuf, (remote_sram_size > sizeof(uint32_t)) ? sizeof(uint32_t) : remote_sram_size))
+         sram      = mem_info.data;
+
+         if (!socket_receive_all_blocking(netplay->fd, sram, sram_size))
          {
             RARCH_ERR("%s\n",
                   msg_hash_to_str(MSG_FAILED_TO_RECEIVE_SRAM_DATA_FROM_HOST));
             return false;
          }
-         if (remote_sram_size > sizeof(uint32_t))
-            remote_sram_size -= sizeof(uint32_t);
-         else
-            remote_sram_size = 0;
+
+      }
+      else if (remote_sram_size != 0)
+      {
+         /* We can't load this, but we still need to get rid of the data */
+         uint32_t quickbuf;
+         while (remote_sram_size > 0)
+         {
+            if (!socket_receive_all_blocking(netplay->fd, &quickbuf, (remote_sram_size > sizeof(uint32_t)) ? sizeof(uint32_t) : remote_sram_size))
+            {
+               RARCH_ERR("%s\n",
+                     msg_hash_to_str(MSG_FAILED_TO_RECEIVE_SRAM_DATA_FROM_HOST));
+               return false;
+            }
+            if (remote_sram_size > sizeof(uint32_t))
+               remote_sram_size -= sizeof(uint32_t);
+            else
+               remote_sram_size = 0;
+         }
+
       }
 
    }
 
-   if (!netplay_get_nickname(netplay, netplay->fd))
-   {
-      RARCH_ERR("%s\n", 
-            msg_hash_to_str(MSG_FAILED_TO_RECEIVE_NICKNAME_FROM_HOST));
-      return false;
-   }
-
    /* Reset our frame count so it's consistent with the server */
-   netplay->self_frame_count = netplay->read_frame_count = netplay->other_frame_count = 0;
+   netplay->self_frame_count = netplay->other_frame_count = 0;
+   netplay->read_frame_count = 1;
    for (i = 0; i < netplay->buffer_size; i++)
    {
       netplay->buffer[i].used = false;
       if (i == netplay->self_ptr)
       {
          netplay_delta_frame_ready(netplay, &netplay->buffer[i], 0);
-         netplay->read_ptr = netplay->other_ptr = i;
+         netplay->buffer[i].have_remote = true;
+         netplay->other_ptr = i;
+         netplay->read_ptr = NEXT_PTR(i);
       }
       else
       {
@@ -239,108 +330,19 @@ bool netplay_send_info(netplay_t *netplay)
       }
    }
 
-   snprintf(msg, sizeof(msg), "%s: \"%s\"",
-         msg_hash_to_str(MSG_CONNECTED_TO),
-         netplay->other_nick);
-   RARCH_LOG("%s\n", msg);
-   runloop_msg_queue_push(msg, 1, 180, false);
-
-   return true;
-}
-
-bool netplay_get_info(netplay_t *netplay)
-{
-   unsigned sram_size, remote_sram_size;
-   uint32_t header[3];
-   retro_ctx_memory_info_t mem_info;
-   uint32_t *content_crc_ptr = NULL;
-   const void *sram          = NULL;
-   size_t i;
-
-   /* FIXME: There's a huge amount of duplication between send_info and
-    * get_info */
-
-   mem_info.id = RETRO_MEMORY_SAVE_RAM;
-
-   core_get_memory(&mem_info);
-   content_get_crc(&content_crc_ptr);
-
-   header[0] = htonl(*content_crc_ptr);
-   header[1] = htonl(netplay_impl_magic());
-   header[2] = htonl(mem_info.size);
-
-   if (!socket_send_all_blocking(netplay->fd, header, sizeof(header), false))
-      return false;
-
-   if (!socket_receive_all_blocking(netplay->fd, header, sizeof(header)))
+   if (is_server)
    {
-      RARCH_ERR("%s\n",
-            msg_hash_to_str(MSG_FAILED_TO_RECEIVE_HEADER_FROM_CLIENT));
-      return false;
+      netplay_log_connection(&netplay->other_addr, 0, netplay->other_nick);
    }
-
-   if (*content_crc_ptr != ntohl(header[0]))
+   else
    {
-      RARCH_ERR("%s\n", msg_hash_to_str(MSG_CONTENT_CRC32S_DIFFER));
-      return false;
+      snprintf(msg, sizeof(msg), "%s: \"%s\"",
+            msg_hash_to_str(MSG_CONNECTED_TO),
+            netplay->other_nick);
+      RARCH_LOG("%s\n", msg);
+      runloop_msg_queue_push(msg, 1, 180, false);
    }
 
-   if (netplay_impl_magic() != ntohl(header[1]))
-   {
-      RARCH_ERR("Implementations differ, make sure you're using exact same "
-            "libretro implementations and RetroArch version.\n");
-      return false;
-   }
-
-   sram_size = mem_info.size;
-   remote_sram_size = ntohl(header[2]);
-   if (sram_size != 0 && remote_sram_size != 0 && sram_size != remote_sram_size)
-   {
-      RARCH_WARN("Content SRAM sizes do not correspond.\n");
-   }
-
-   if (!netplay_get_nickname(netplay, netplay->fd))
-   {
-      RARCH_ERR("%s\n",
-            msg_hash_to_str(MSG_FAILED_TO_GET_NICKNAME_FROM_CLIENT));
-      return false;
-   }
-
-   /* Send SRAM data to our User 2. */
-   sram      = mem_info.data;
-
-   if (!socket_send_all_blocking(netplay->fd, sram, sram_size, false))
-   {
-      RARCH_ERR("%s\n",
-            msg_hash_to_str(MSG_FAILED_TO_SEND_SRAM_DATA_TO_CLIENT));
-      return false;
-   }
-
-   if (!netplay_send_nickname(netplay, netplay->fd))
-   {
-      RARCH_ERR("%s\n",
-            msg_hash_to_str(MSG_FAILED_TO_SEND_NICKNAME_TO_CLIENT));
-      return false;
-   }
-
-   /* Reset our frame count so it's consistent with the client */
-   netplay->self_frame_count = netplay->read_frame_count = netplay->other_frame_count = 0;
-   for (i = 0; i < netplay->buffer_size; i++)
-   {
-      netplay->buffer[i].used = false;
-      if (i == netplay->self_ptr)
-      {
-         netplay_delta_frame_ready(netplay, &netplay->buffer[i], 0);
-         netplay->read_ptr = netplay->other_ptr = i;
-      }
-      else
-      {
-         netplay->buffer[i].used = false;
-      }
-   }
-
-   netplay_log_connection(&netplay->other_addr, 0, netplay->other_nick);
-
    return true;
 }
 
diff --git a/network/netplay/netplay_net.c b/network/netplay/netplay_net.c
index 10019ba242..c594587e0f 100644
--- a/network/netplay/netplay_net.c
+++ b/network/netplay/netplay_net.c
@@ -81,7 +81,7 @@ static bool netplay_net_pre_frame(netplay_t *netplay)
       serial_info.size = netplay->state_size;
 
       memset(serial_info.data, 0, serial_info.size);
-      if (netplay->quirks & NETPLAY_QUIRK_INITIALIZATION)
+      if ((netplay->quirks & NETPLAY_QUIRK_INITIALIZATION) || netplay->self_frame_count == 0)
       {
          /* Don't serialize until it's safe */
       }
@@ -105,6 +105,7 @@ static bool netplay_net_pre_frame(netplay_t *netplay)
 
       /* If we can't transmit savestates, we must stall until the client is ready */
       if (!netplay->has_connection &&
+          netplay->self_frame_count > 0 &&
           (netplay->quirks & (NETPLAY_QUIRK_NO_SAVESTATES|NETPLAY_QUIRK_NO_TRANSMISSION)))
          netplay->stall = RARCH_NETPLAY_STALL_NO_CONNECTION;
    }
@@ -148,14 +149,23 @@ static bool netplay_net_pre_frame(netplay_t *netplay)
             RARCH_WARN("Cannot set Netplay port to close-on-exec. It may fail to reopen if the client disconnects.\n");
 #endif
 
-         /* Connection header */
-         if (netplay_get_info(netplay))
+         /* Establish the connection */
+         if (netplay_handshake(netplay))
          {
             netplay->has_connection = true;
 
             /* Send them the savestate */
             if (!(netplay->quirks & (NETPLAY_QUIRK_NO_SAVESTATES|NETPLAY_QUIRK_NO_TRANSMISSION)))
-               netplay_load_savestate(netplay, NULL, true);
+            {
+               netplay->force_send_savestate = true;
+            }
+            else
+            {
+               /* Because the first frame isn't serialized, we're actually at
+                * frame 1 */
+               netplay->self_ptr = NEXT_PTR(netplay->self_ptr);
+               netplay->self_frame_count = 1;
+            }
 
             /* And expect the current frame from the other side */
             netplay->read_frame_count = netplay->other_frame_count = netplay->self_frame_count;
@@ -322,7 +332,7 @@ static bool netplay_net_info_cb(netplay_t* netplay, unsigned frames)
 {
    if (!netplay_is_server(netplay))
    {
-      if (!netplay_send_info(netplay))
+      if (!netplay_handshake(netplay))
          return false;
       netplay->has_connection = true;
    }
diff --git a/network/netplay/netplay_private.h b/network/netplay/netplay_private.h
index ae80b5eb53..0a7e38254d 100644
--- a/network/netplay/netplay_private.h
+++ b/network/netplay/netplay_private.h
@@ -35,7 +35,7 @@
 #define MAX_SPECTATORS 16
 #define RARCH_DEFAULT_PORT 55435
 
-#define NETPLAY_PROTOCOL_VERSION 1
+#define NETPLAY_PROTOCOL_VERSION 2
 
 #define PREV_PTR(x) ((x) == 0 ? netplay->buffer_size - 1 : (x) - 1)
 #define NEXT_PTR(x) ((x + 1) % netplay->buffer_size)
@@ -45,6 +45,8 @@
 #define NETPLAY_QUIRK_NO_SAVESTATES (1<<0)
 #define NETPLAY_QUIRK_NO_TRANSMISSION (1<<1)
 #define NETPLAY_QUIRK_INITIALIZATION (1<<2)
+#define NETPLAY_QUIRK_ENDIAN_DEPENDENT (1<<3)
+#define NETPLAY_QUIRK_PLATFORM_DEPENDENT (1<<4)
 
 /* Mapping of serialization quirks to netplay quirks. */
 #define NETPLAY_QUIRK_MAP_UNDERSTOOD \
@@ -56,11 +58,13 @@
 #define NETPLAY_QUIRK_MAP_NO_SAVESTATES \
    (RETRO_SERIALIZATION_QUIRK_INCOMPLETE)
 #define NETPLAY_QUIRK_MAP_NO_TRANSMISSION \
-   (RETRO_SERIALIZATION_QUIRK_SINGLE_SESSION \
-   |RETRO_SERIALIZATION_QUIRK_ENDIAN_DEPENDENT \
-   |RETRO_SERIALIZATION_QUIRK_PLATFORM_DEPENDENT)
+   (RETRO_SERIALIZATION_QUIRK_SINGLE_SESSION)
 #define NETPLAY_QUIRK_MAP_INITIALIZATION \
    (RETRO_SERIALIZATION_QUIRK_MUST_INITIALIZE)
+#define NETPLAY_QUIRK_MAP_ENDIAN_DEPENDENT \
+   (RETRO_SERIALIZATION_QUIRK_ENDIAN_DEPENDENT)
+#define NETPLAY_QUIRK_MAP_PLATFORM_DEPENDENT \
+   (RETRO_SERIALIZATION_QUIRK_PLATFORM_DEPENDENT)
 
 struct delta_frame
 {
@@ -214,14 +218,10 @@ bool netplay_get_nickname(netplay_t *netplay, int fd);
 
 bool netplay_send_nickname(netplay_t *netplay, int fd);
 
-bool netplay_send_info(netplay_t *netplay);
+bool netplay_handshake(netplay_t *netplay);
 
 uint32_t netplay_impl_magic(void);
 
-bool netplay_send_info(netplay_t *netplay);
-
-bool netplay_get_info(netplay_t *netplay);
-
 bool netplay_is_server(netplay_t* netplay);
 
 bool netplay_is_spectate(netplay_t* netplay);