From fd7b722fd81c72a9dd2c2bc49ce22ee2ae3922be Mon Sep 17 00:00:00 2001 From: jeefo Date: Wed, 21 Sep 2022 14:47:36 +0300 Subject: [PATCH] add: make graph author read-only if graph file already has author upon load (resolves #369) --- inc/control.h | 1 + inc/graph.h | 24 ++++++++++++----- src/control.cpp | 12 ++++++--- src/graph.cpp | 70 ++++++++++++++++++++++++++++++++++++++++++------- src/support.cpp | 6 +++++ 5 files changed, 93 insertions(+), 20 deletions(-) diff --git a/inc/control.h b/inc/control.h index e71754f..b225ca3 100644 --- a/inc/control.h +++ b/inc/control.h @@ -123,6 +123,7 @@ private: int cmdNodeUpload (); int cmdNodeIterateCamp (); int cmdNodeShowStats (); + int cmdNodeFileInfo (); private: int menuMain (int item); diff --git a/inc/graph.h b/inc/graph.h index 6512207..19a2037 100644 --- a/inc/graph.h +++ b/inc/graph.h @@ -70,7 +70,7 @@ CR_DECLARE_SCOPED_ENUM (StorageOption, // storage header versions CR_DECLARE_SCOPED_ENUM (StorageVersion, - Graph = 2, + Graph = 3, Practice = 1, Vistable = 1, Matrix = 1, @@ -122,8 +122,9 @@ struct StorageHeader { // extension header for graph information struct ExtenHeader { - char author[32]; - int32 mapSize; + char author[32]; // original author of graph + int32 mapSize; // bsp size for checksumming map consistency + char modified[32]; // by whom modified }; // general waypoint header information structure @@ -262,7 +263,6 @@ private: int x, y, z; }; - int m_version; int m_editFlags; int m_loadAttempts; int m_cacheNodeIndex; @@ -303,7 +303,12 @@ private: SmallArray m_paths; SmallArray m_vistable; - String m_tempStrings; + String m_graphAuthor; + String m_graphModified; + + ExtenHeader m_extenHeader {}; + StorageHeader m_graphHeader {}; + edict_t *m_editor; public: @@ -385,6 +390,7 @@ public: void convertCampDirection (Path &path); void setAutoPathDistance (const float distance); void showStats (); + void showFileInfo (); const char *getDataDirectory (bool isMemoryFile = false); const char *getOldFormatGraphName (bool isMemoryFile = false); @@ -407,7 +413,11 @@ public: } StringRef getAuthor () const { - return m_tempStrings; + return m_graphAuthor; + } + + StringRef getModifiedBy () const { + return m_graphModified; } bool hasChanged () const { @@ -473,7 +483,7 @@ template bool BotGraph::raiseLoadingError (bool isGraph, MemF if (isGraph) { bots.kickEveryone (true); - m_tempStrings = result; + m_graphAuthor = result; m_paths.clear (); } file.close (); diff --git a/src/control.cpp b/src/control.cpp index 3f08bdb..74f982b 100644 --- a/src/control.cpp +++ b/src/control.cpp @@ -279,7 +279,8 @@ int BotControl::cmdNode () { "save", "load", "help", - "erase" + "erase", + "fileinfo" }; // check if cmd is allowed on dedicated server @@ -331,6 +332,7 @@ int BotControl::cmdNode () { addGraphCmd ("teleport", "teleport [index]", "Teleports player to specified node index.", &BotControl::cmdNodeTeleport); addGraphCmd ("upload", "upload", "Uploads created graph to graph database.", &BotControl::cmdNodeUpload); addGraphCmd ("stats", "stats [noarguments]", "Shows the stats about node types on the map.", &BotControl::cmdNodeShowStats); + addGraphCmd ("fileinfo", "fileinfo [noarguments]", "Shows basic information about graph file.", &BotControl::cmdNodeFileInfo); // add path commands addGraphCmd ("path_create", "path_create [noarguments]", "Opens and displays path creation menu.", &BotControl::cmdNodePathCreate); @@ -854,13 +856,17 @@ int BotControl::cmdNodeIterateCamp () { } int BotControl::cmdNodeShowStats () { - enum args { graph_cmd = 1 }; - graph.showStats (); return BotCommandResult::Handled; } +int BotControl::cmdNodeFileInfo () { + graph.showFileInfo (); + + return BotCommandResult::Handled; +} + int BotControl::menuMain (int item) { closeMenu (); // reset menu display diff --git a/src/graph.cpp b/src/graph.cpp index 0719707..7248a38 100644 --- a/src/graph.cpp +++ b/src/graph.cpp @@ -1132,6 +1132,23 @@ void BotGraph::showStats () { ctrl.msg ("Block Hostage Points: %d - Sniper Points: %d", noHostagePoints, sniperPoints); } +void BotGraph::showFileInfo () { + ctrl.msg ("header:"); + ctrl.msg (" magic: %d", m_graphHeader.magic); + ctrl.msg (" version: %d", m_graphHeader.version); + ctrl.msg (" node_count: %d", m_graphHeader.length); + ctrl.msg (" compressed_size: %dkB", m_graphHeader.compressed / 1024); + ctrl.msg (" uncompressed_size: %dkB", m_graphHeader.uncompressed / 1024); + ctrl.msg (" options: %d", m_graphHeader.options); // display as string ? + + ctrl.msg (""); + + ctrl.msg ("extensions:"); + ctrl.msg (" author: %s", m_extenHeader.author); + ctrl.msg (" modified_by: %s", m_extenHeader.modified); + ctrl.msg (" bsp_size: %d", m_extenHeader.mapSize); +} + void BotGraph::calculatePathRadius (int index) { // calculate "wayzones" for the nearest node (meaning a dynamic distance area to vary node origin) @@ -1388,7 +1405,7 @@ void BotGraph::initNarrowPlaces () { constexpr int32 kNarrowPlacesMinGraphVersion = 2; // if version 2 or higher, narrow places already initialized and saved into file - if (m_version >= kNarrowPlacesMinGraphVersion) { + if (m_graphHeader.version >= kNarrowPlacesMinGraphVersion) { m_narrowChecked = true; return; } @@ -1560,7 +1577,7 @@ bool BotGraph::convertOldFormat () { if (!m_paths.empty ()) { ctrl.msg ("Converting old PWF to new format Graph."); - m_tempStrings = header.author; + m_graphAuthor = header.author; return saveGraphData (); } return true; @@ -1736,7 +1753,7 @@ template bool BotGraph::loadStorage (StringRef ext, StringRef name, // save graph version if (isGraph) { - m_version = hdr.version; + memcpy (&m_graphHeader, &hdr, sizeof (StorageHeader)); } // check the storage type @@ -1765,7 +1782,24 @@ template bool BotGraph::loadStorage (StringRef ext, StringRef name, // author of graph.. save if ((hdr.options & StorageOption::Exten) && exten != nullptr) { - file.read (exten, sizeof (ExtenHeader)); + size_t extenSize = sizeof (ExtenHeader); + + if (hdr.version < 3) { + extenSize -= sizeof (char[32]); // modified by + } + file.read (exten, extenSize); + + if (isGraph) { + strings.copy (m_extenHeader.author, exten->author, cr::bufsize (exten->author)); + + if (hdr.version > 2) { + strings.copy (m_extenHeader.modified, exten->modified, cr::bufsize (exten->modified)); + } + else { + strings.copy (m_extenHeader.modified, "(none)", cr::bufsize (exten->modified)); + } + m_extenHeader.mapSize = exten->mapSize; + } } ctrl.msg ("Successfully loaded Bots %s data v%d (%d/%.2fMB).", name, hdr.version, m_paths.length (), static_cast (data.capacity () * sizeof (U)) / 1024.0f / 1024.0f); file.close (); @@ -1782,6 +1816,9 @@ bool BotGraph::loadGraphData () { ExtenHeader exten {}; int32 outOptions = 0; + m_graphHeader = {}; + m_extenHeader = {}; + // check if loaded bool dataLoaded = loadStorage ("graph", "Graph", StorageOption::Graph, StorageVersion::Graph, m_paths, &exten, &outOptions); @@ -1795,11 +1832,16 @@ bool BotGraph::loadGraphData () { } if ((outOptions & StorageOption::Official) || strncmp (exten.author, "official", 8) == 0 || strlen (exten.author) < 2) { - m_tempStrings.assign (product.folder); + m_graphAuthor.assign (product.folder); } else { - m_tempStrings.assign (exten.author); + m_graphAuthor.assign (exten.author); } + + if (m_graphHeader.version > 2) { + m_graphModified.assign (exten.modified); + } + initNodesTypes (); loadPathMatrix (); loadVisibility (); @@ -1827,8 +1869,8 @@ bool BotGraph::saveGraphData () { auto options = StorageOption::Graph | StorageOption::Exten; String author; - if (game.isNullEntity (m_editor) && !m_tempStrings.empty ()) { - author = m_tempStrings; + if (game.isNullEntity (m_editor) && !m_graphAuthor.empty ()) { + author = m_graphAuthor; if (!game.isDedicated ()) { options |= StorageOption::Recovered; @@ -1847,7 +1889,16 @@ bool BotGraph::saveGraphData () { } ExtenHeader exten {}; - strings.copy (exten.author, author.chars (), cr::bufsize (exten.author)); + + // only modify the author if no author currenlty assigned to graph file + if (m_graphAuthor.empty ()) { + strings.copy (exten.author, author.chars (), cr::bufsize (exten.author)); + } + else { + strings.copy (exten.author, m_extenHeader.author, cr::bufsize (exten.author)); + } + + strings.copy (exten.modified, author.chars (), cr::bufsize (exten.author)); // always update modified by exten.mapSize = getBspSize (); // ensure narrow places saved into file @@ -2884,7 +2935,6 @@ BotGraph::BotGraph () { m_rescuePoints.clear (); m_sniperPoints.clear (); - m_version = StorageVersion::Graph; m_loadAttempts = 0; m_editFlags = 0; diff --git a/src/support.cpp b/src/support.cpp index fe7ee55..98556c8 100644 --- a/src/support.cpp +++ b/src/support.cpp @@ -294,10 +294,16 @@ void BotSupport::checkWelcome () { game.serverCommand ("speak \"%s\"", m_sentences.random ()); } String authorStr = "Official Navigation Graph"; + StringRef graphAuthor = graph.getAuthor (); + StringRef graphModified = graph.getModifiedBy (); if (!graphAuthor.startsWith (product.folder)) { authorStr.assignf ("Navigation Graph by: %s", graphAuthor); + + if (!graphModified.empty ()) { + authorStr.appendf (" (Modified by: %s)", graphModified); + } } MessageWriter (MSG_ONE, msgs.id (NetMsg::TextMsg), nullptr, receiveEntity)