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 bc9968163ccb929cffc2fd2d69b4a8bf75f546ed..bb1ce49770b1e3b4a85995485ecb586cd958b0b6 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 4579f88159dc975aa43e1e874879cd456db87ee1..f823e1f2f2c9e28184a4c6eba8bad84f2655076b 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 125e1666e309293488566ae1a6a3677a258cdeba..380614c4b9799c766d0104d11135be76aa127648 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 0a3661e139a7b8d0692b7a144050751df48ae3c3..eef7aa111e43466b56be71b44afa311e259b3c7f 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 d69deca7a7725962383fd2aeed74d8591bca96b1..baebb99c2298fb19ccc4ad8a281bfa4acf7c33db 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 728517465eb8d5123dc5652f5ab9cbcf716a4a2b..bfe53c37c829e388dbf5ffb2bb197f9be720ef2e 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 c682105ce89a7b3985e7e68e1ef872b512183a13..22a826c6ba4228341137d0345e0f56ade391c13b 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);