added sending level file (and level template) for network games
authorHolger Schemel <info@artsoft.org>
Fri, 24 Aug 2018 22:42:10 +0000 (00:42 +0200)
committerHolger Schemel <info@artsoft.org>
Fri, 24 Aug 2018 22:42:10 +0000 (00:42 +0200)
As the level to play may not exist on the receiving side (but only on
the sending side -- the client who initiates the network game), this
change adds sending the level file (and the level template, if needed)
to all receiving network clients, so all clients always play the exact
same level (and do not have to worry about having the same level sets).

src/files.c
src/files.h
src/game.c
src/netserv.c
src/netserv.h
src/network.c
src/network.h

index bc99681..bb1ce49 100644 (file)
@@ -2287,6 +2287,17 @@ static void setLevelFileInfo(struct LevelFileInfo *level_file_info, int nr)
   determineLevelFileInfo_Filetype(level_file_info);
 }
 
+static void copyLevelFileInfo(struct LevelFileInfo *lfi_from,
+                             struct LevelFileInfo *lfi_to)
+{
+  lfi_to->nr     = lfi_from->nr;
+  lfi_to->type   = lfi_from->type;
+  lfi_to->packed = lfi_from->packed;
+
+  setString(&lfi_to->basename, lfi_from->basename);
+  setString(&lfi_to->filename, lfi_from->filename);
+}
+
 /* ------------------------------------------------------------------------- */
 /* functions for loading R'n'D level                                         */
 /* ------------------------------------------------------------------------- */
@@ -6582,6 +6593,16 @@ static void LoadLevel_InitNativeEngines(struct LevelInfo *level)
     CopyNativeLevel_RND_to_Native(level);
 }
 
+static void LoadLevelTemplate_LoadAndInit()
+{
+  LoadLevelFromFileInfo(&level_template, &level_template.file_info, FALSE);
+
+  LoadLevel_InitVersion(&level_template);
+  LoadLevel_InitElements(&level_template);
+
+  ActivateLevelTemplate();
+}
+
 void LoadLevelTemplate(int nr)
 {
   if (!fileExists(getGlobalLevelTemplateFilename()))
@@ -6593,22 +6614,27 @@ void LoadLevelTemplate(int nr)
 
   setLevelFileInfo(&level_template.file_info, nr);
 
-  LoadLevelFromFileInfo(&level_template, &level_template.file_info, FALSE);
+  LoadLevelTemplate_LoadAndInit();
+}
 
-  LoadLevel_InitVersion(&level_template);
-  LoadLevel_InitElements(&level_template);
+static void LoadLevelTemplateFromNetwork(struct LevelFileInfo *lfi_network_template)
+{
+  copyLevelFileInfo(lfi_network_template, &level_template.file_info);
 
-  ActivateLevelTemplate();
+  LoadLevelTemplate_LoadAndInit();
 }
 
-void LoadLevel(int nr)
+static void LoadLevel_LoadAndInit(struct LevelFileInfo *lfi_network_template)
 {
-  setLevelFileInfo(&level.file_info, nr);
-
   LoadLevelFromFileInfo(&level, &level.file_info, FALSE);
 
   if (level.use_custom_template)
-    LoadLevelTemplate(-1);
+  {
+    if (lfi_network_template != NULL)
+      LoadLevelTemplateFromNetwork(lfi_network_template);
+    else
+      LoadLevelTemplate(-1);
+  }
 
   LoadLevel_InitVersion(&level);
   LoadLevel_InitElements(&level);
@@ -6617,6 +6643,13 @@ void LoadLevel(int nr)
   LoadLevel_InitNativeEngines(&level);
 }
 
+void LoadLevel(int nr)
+{
+  setLevelFileInfo(&level.file_info, nr);
+
+  LoadLevel_LoadAndInit(NULL);
+}
+
 void LoadLevelInfoOnly(int nr)
 {
   setLevelFileInfo(&level.file_info, nr);
@@ -6624,6 +6657,14 @@ void LoadLevelInfoOnly(int nr)
   LoadLevelFromFileInfo(&level, &level.file_info, TRUE);
 }
 
+void LoadLevelFromNetwork(struct LevelFileInfo *lfi_network_level,
+                         struct LevelFileInfo *lfi_network_template)
+{
+  copyLevelFileInfo(lfi_network_level, &level.file_info);
+
+  LoadLevel_LoadAndInit(lfi_network_template);
+}
+
 static int SaveLevel_VERS(FILE *file, struct LevelInfo *level)
 {
   int chunk_size = 0;
index 4579f88..f823e1f 100644 (file)
@@ -37,6 +37,7 @@ void LoadLevelFromFilename(struct LevelInfo *, char *);
 void LoadLevel(int);
 void LoadLevelTemplate(int);
 void LoadLevelInfoOnly(int);
+void LoadLevelFromNetwork(struct LevelFileInfo *, struct LevelFileInfo *);
 void SaveLevel(int);
 void SaveLevelTemplate();
 void SaveNativeLevel(struct LevelInfo *);
index 125e166..380614c 100644 (file)
@@ -11228,6 +11228,7 @@ void StartGameActions(boolean init_network_game, boolean record_tape,
 
   if (init_network_game)
   {
+    SendToServer_LevelFile();
     SendToServer_StartPlaying();
 
     return;
index 0a3661e..eef7aa1 100644 (file)
@@ -809,6 +809,13 @@ static void Handle_OP_BROADCAST_MESSAGE(struct NetworkServerPlayerInfo *player)
   SendNetworkBufferToAllButOne(write_buffer, player);
 }
 
+static void Handle_OP_LEVEL_FILE(struct NetworkServerPlayerInfo *player)
+{
+  copyNetworkBufferForWriting(read_buffer, write_buffer, player->number);
+
+  SendNetworkBufferToAllButOne(write_buffer, player);
+}
+
 void ExitNetworkServer(int exit_value)
 {
   Error(ERR_NETWORK_SERVER, "exiting network server");
@@ -1007,6 +1014,10 @@ void NetworkServer(int port, int serveronly)
          Handle_OP_BROADCAST_MESSAGE(player);
          break;
 
+       case OP_LEVEL_FILE:
+         Handle_OP_LEVEL_FILE(player);
+         break;
+
        default:
          if (options.verbose)
            Error(ERR_NETWORK_SERVER,
index d69deca..baebb99 100644 (file)
@@ -33,6 +33,7 @@
 #define OP_STOP_PLAYING                11
 #define OP_MOVE_PLAYER         12
 #define OP_BROADCAST_MESSAGE   13
+#define OP_LEVEL_FILE          14
 
 #define MAX_BUFFER_SIZE                4096
 
index 7285174..bfe53c3 100644 (file)
@@ -37,6 +37,15 @@ static struct NetworkClientPlayerInfo first_player =
   NULL
 };
 
+struct NetworkLevelFileInfo
+{
+  char *leveldir_identifier;
+  struct LevelFileInfo file_info;
+  struct LevelFileInfo tmpl_info;
+  boolean use_network_level_files;
+  boolean use_custom_template;
+};
+
 /* server stuff */
 
 static TCPsocket sfd;          /* TCP server socket */
@@ -50,6 +59,8 @@ static boolean stop_network_game = FALSE;
 static boolean stop_network_client = FALSE;
 static char stop_network_client_message[MAX_OUTPUT_LINESIZE + 1];
 
+static struct NetworkLevelFileInfo network_level;
+
 static void DrawNetworkTextExt(char *message, int font_nr, boolean initialize)
 {
   static int xpos = 0, ypos = 0;
@@ -376,6 +387,44 @@ void SendToServer_NrWanted(int nr_wanted)
   SendNetworkBufferToServer(write_buffer);
 }
 
+void SendToServer_LevelFile()
+{
+  initNetworkBufferForWriting(write_buffer, OP_LEVEL_FILE, 0);
+
+  putNetworkBufferString(      write_buffer, leveldir_current->identifier);
+  putNetworkBuffer16BitInteger(write_buffer, level.file_info.nr);
+  putNetworkBuffer8BitInteger( write_buffer, level.file_info.type);
+  putNetworkBuffer8BitInteger( write_buffer, level.file_info.packed);
+  putNetworkBufferString(      write_buffer, level.file_info.basename);
+  putNetworkBufferFile(        write_buffer, level.file_info.filename);
+  putNetworkBuffer8BitInteger( write_buffer, level.use_custom_template);
+
+  if (level.use_custom_template)
+  {
+    putNetworkBufferString(write_buffer, level_template.file_info.basename);
+    putNetworkBufferFile(  write_buffer, level_template.file_info.filename);
+  }
+
+  SendNetworkBufferToServer(write_buffer);
+
+  setString(&network_level.leveldir_identifier, leveldir_current->identifier);
+
+  /* the sending client does not use network level files (but the real ones) */
+  network_level.use_network_level_files = FALSE;
+
+#if 0
+  printf("::: '%s'\n", leveldir_current->identifier);
+  printf("::: '%d'\n", level.file_info.nr);
+  printf("::: '%d'\n", level.file_info.type);
+  printf("::: '%d'\n", level.file_info.packed);
+  printf("::: '%s'\n", level.file_info.basename);
+  printf("::: '%s'\n", level.file_info.filename);
+
+  if (level.use_custom_template)
+    printf("::: '%s'\n", level_template.file_info.filename);
+#endif
+}
+
 void SendToServer_StartPlaying()
 {
   unsigned int new_random_seed = InitRND(level.random_seed);
@@ -621,10 +670,7 @@ static void Handle_OP_START_PLAYING()
   int new_level_nr = getNetworkBuffer16BitInteger(read_buffer);
   unsigned int new_random_seed = getNetworkBuffer32BitInteger(read_buffer);
 
-  LevelDirTree *new_leveldir =
-    getTreeInfoFromIdentifier(leveldir_first, new_leveldir_identifier);
-
-  if (new_leveldir == NULL)
+  if (!strEqual(new_leveldir_identifier, network_level.leveldir_identifier))
   {
     Error(ERR_WARN, "no such level identifier: '%s'", new_leveldir_identifier);
 
@@ -636,14 +682,24 @@ static void Handle_OP_START_PLAYING()
   printf("OP_START_PLAYING: %d\n", player_nr);
   Error(ERR_NETWORK_CLIENT,
        "client %d starts game [level %d from level identifier '%s']\n",
-       player_nr, new_level_nr, new_leveldir->identifier);
+       player_nr, new_level_nr, new_leveldir_identifier);
+
+  LevelDirTree *new_leveldir =
+    getTreeInfoFromIdentifier(leveldir_first, new_leveldir_identifier);
 
-  leveldir_current = new_leveldir;
-  level_nr = new_level_nr;
+  if (new_leveldir != NULL)
+  {
+    leveldir_current = new_leveldir;
+    level_nr = new_level_nr;
+  }
 
   TapeErase();
-  LoadTape(level_nr);
-  LoadLevel(level_nr);
+
+  if (network_level.use_network_level_files)
+    LoadLevelFromNetwork(&network_level.file_info,
+                        &network_level.tmpl_info);
+  else
+    LoadLevel(level_nr);
 
   StartGameActions(FALSE, setup.autorecord, new_random_seed);
 }
@@ -746,6 +802,66 @@ static void Handle_OP_BROADCAST_MESSAGE()
   Error(ERR_NETWORK_CLIENT, "client %d sends message", player_nr);
 }
 
+static void Handle_OP_LEVEL_FILE()
+{
+  int player_nr = getNetworkBuffer8BitInteger(read_buffer);
+  char *leveldir_identifier;
+  char *network_level_dir;
+  struct LevelFileInfo *file_info = &network_level.file_info;
+  struct LevelFileInfo *tmpl_info = &network_level.tmpl_info;
+  boolean use_custom_template;
+
+  setString(&network_level.leveldir_identifier, NULL);
+  setString(&network_level.file_info.basename,  NULL);
+  setString(&network_level.file_info.filename,  NULL);
+  setString(&network_level.tmpl_info.basename,  NULL);
+  setString(&network_level.tmpl_info.filename,  NULL);
+
+  printf("OP_LEVEL_FILE: %d\n", player_nr);
+
+  leveldir_identifier = getStringCopy(getNetworkBufferString(read_buffer));
+  network_level_dir   = getNetworkLevelDir(leveldir_identifier);
+
+  file_info->nr       = getNetworkBuffer16BitInteger(read_buffer);
+  file_info->type     = getNetworkBuffer8BitInteger(read_buffer);
+  file_info->packed   = getNetworkBuffer8BitInteger(read_buffer);
+  file_info->basename = getStringCopy(getNetworkBufferString(read_buffer));
+  file_info->filename = getPath2(network_level_dir, file_info->basename);
+
+  InitNetworkLevelDirectory(leveldir_identifier);
+
+  getNetworkBufferFile(read_buffer, file_info->filename);
+
+  use_custom_template = getNetworkBuffer8BitInteger(read_buffer);
+  if (use_custom_template)
+  {
+    *tmpl_info = *file_info;
+
+    tmpl_info->basename = getStringCopy(getNetworkBufferString(read_buffer));
+    tmpl_info->filename = getPath2(network_level_dir, tmpl_info->basename);
+
+    getNetworkBufferFile(read_buffer, tmpl_info->filename);
+  }
+
+  network_level.leveldir_identifier = leveldir_identifier;
+  network_level.use_custom_template = use_custom_template;
+
+  /* the receiving client(s) use(s) the transferred network level files */
+  network_level.use_network_level_files = TRUE;
+
+#if 0
+  printf("::: '%s'\n", leveldir_identifier);
+  printf("::: '%d'\n", file_info->nr);
+  printf("::: '%d'\n", file_info->type);
+  printf("::: '%d'\n", file_info->packed);
+  printf("::: '%s'\n", file_info->basename);
+  printf("::: '%s'\n", file_info->filename);
+
+  if (use_custom_template)
+    printf("::: '%s'\n", tmpl_info->filename);
+#endif
+}
+
 static void HandleNetworkingMessage()
 {
   stop_network_game = FALSE;
@@ -804,6 +920,10 @@ static void HandleNetworkingMessage()
       Handle_OP_BROADCAST_MESSAGE();
       break;
 
+    case OP_LEVEL_FILE:
+      Handle_OP_LEVEL_FILE();
+      break;
+
     default:
       if (options.verbose)
        Error(ERR_NETWORK_CLIENT,
index c682105..22a826c 100644 (file)
@@ -23,6 +23,7 @@ boolean ConnectToServer(char *, int);
 void SendToServer_PlayerName(char *);
 void SendToServer_ProtocolVersion(void);
 void SendToServer_NrWanted(int);
+void SendToServer_LevelFile(void);
 void SendToServer_StartPlaying(void);
 void SendToServer_PausePlaying(void);
 void SendToServer_ContinuePlaying(void);