diff --git a/LICENSE.txt b/LICENSE.txt
index 9e419e0..20d40b6 100644
--- a/LICENSE.txt
+++ b/LICENSE.txt
@@ -1,4 +1,4 @@
-GNU GENERAL PUBLIC LICENSE
+ GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc.
diff --git a/ext/crlib/cr-ulz.h b/ext/crlib/cr-ulz.h
index f339918..a4d2b6d 100644
--- a/ext/crlib/cr-ulz.h
+++ b/ext/crlib/cr-ulz.h
@@ -20,7 +20,7 @@
CR_NAMESPACE_BEGIN
// see https://github.com/encode84/ulz/
-class ULZ final : DenyCopying {
+class ULZ final : public Singleton {
public:
enum : int32 {
Excess = 16,
@@ -314,4 +314,7 @@ private:
}
};
+// expose global ulz object
+CR_EXPOSE_GLOBAL_SINGLETON (ULZ, ulz);
+
CR_NAMESPACE_END
diff --git a/inc/graph.h b/inc/graph.h
index 91c07ae..5864a70 100644
--- a/inc/graph.h
+++ b/inc/graph.h
@@ -83,7 +83,7 @@ CR_DECLARE_SCOPED_ENUM (StorageOption,
// storage header versions
CR_DECLARE_SCOPED_ENUM (StorageVersion,
- Graph = 1,
+ Graph = 2,
Practice = 1,
Vistable = 1,
Matrix = 1,
@@ -251,6 +251,7 @@ private:
int x, y, z;
};
+ int m_version;
int m_editFlags;
int m_loadAttempts;
int m_cacheNodeIndex;
@@ -325,6 +326,7 @@ public:
bool saveGraphData ();
bool loadGraphData ();
+ bool canDownload ();
template bool saveStorage (StringRef ext, StringRef name, StorageOption options, StorageVersion version, const SmallArray &data, ExtenHeader *exten);
template bool loadStorage (StringRef ext, StringRef name, StorageOption options, StorageVersion version, SmallArray &data, ExtenHeader *exten, int32 *outOptions);
diff --git a/meson.build b/meson.build
index 1aee964..3f003ce 100644
--- a/meson.build
+++ b/meson.build
@@ -70,7 +70,7 @@ cdata.set ('commitCount', run_command ('git', 'rev-list', '--count', 'HEAD').std
cdata.set ('commitAuthor', run_command ('git', 'log', '--pretty="%ae"', '-1').stdout ().strip ())
cdata.set ('buildVersion', buildVersion)
-cdata.set ('buildMachine', run_command ('hostname').stdout ().strip ())
+cdata.set ('buildMachine', run_command ('hostname', '-f').stdout ().strip ())
cdata.set ('buildCompiler', compilerId + ' ' + compilerVersion)
configure_file (input: 'inc/version.h.in', output: 'version.build.h', configuration: cdata)
diff --git a/src/botlib.cpp b/src/botlib.cpp
index 18db4da..02dc84c 100644
--- a/src/botlib.cpp
+++ b/src/botlib.cpp
@@ -2940,6 +2940,8 @@ void Bot::frame () {
}
void Bot::update () {
+ pev->flags |= FL_FAKECLIENT; // restore fake client bit
+
pev->button = 0;
m_moveSpeed = 0.0f;
diff --git a/src/config.cpp b/src/config.cpp
index c84074d..0806c66 100644
--- a/src/config.cpp
+++ b/src/config.cpp
@@ -586,7 +586,7 @@ void BotConfig::loadDifficultyConfig () {
if (util.openConfig ("difficulty.cfg", "Difficulty config file not found. Loading defaults.", &file)) {
while (file.getLine (line)) {
- if (isCommentLine (line)) {
+ if (isCommentLine (line) || line.length () < 3) {
continue;
}
auto items = line.split ("=");
diff --git a/src/control.cpp b/src/control.cpp
index afcccf2..0a1df8a 100644
--- a/src/control.cpp
+++ b/src/control.cpp
@@ -269,8 +269,25 @@ int BotControl::cmdCvars () {
int BotControl::cmdNode () {
enum args { root, alias, cmd, cmd2 };
+ static Array allowedOnDedicatedServer {
+ "acquire_editor",
+ "upload",
+ "save",
+ "load"
+ };
+
+ // check if cmd is allowed on dedicated server
+ auto isAllowedOnDedicatedServer = [] (StringRef str) -> bool {
+ for (const auto &test : allowedOnDedicatedServer) {
+ if (test == str) {
+ return true;
+ }
+ }
+ return false;
+ };
+
// graph editor supported only with editor
- if (game.isDedicated () && !graph.hasEditor () && strValue (cmd) != "acquire_editor" && strValue (cmd) != "upload") {
+ if (game.isDedicated () && !graph.hasEditor () && !isAllowedOnDedicatedServer (strValue (cmd))) {
msg ("Unable to use graph edit commands without setting graph editor player. Please use \"graph acquire_editor\" to acquire rights for graph editing.");
return BotCommandResult::Handled;
}
@@ -738,7 +755,7 @@ int BotControl::cmdNodeUpload () {
http.setTimeout (6);
// try to upload the file
- if (http.uploadFile ("http://yapb.ru/graph", strings.format ("%sgraph/%s.graph", graph.getDataDirectory (false), game.getMapName ()))) {
+ if (http.uploadFile (strings.format ("http://%s/graph", product.download), strings.format ("%sgraph/%s.graph", graph.getDataDirectory (false), game.getMapName ()))) {
msg ("Graph file was successfully validated and uploaded to the YaPB Graph DB (%s).", product.download);
msg ("It will be available for download for all YaPB users in a few minutes.");
msg ("\n");
diff --git a/src/graph.cpp b/src/graph.cpp
index 5b28b24..acb0b11 100644
--- a/src/graph.cpp
+++ b/src/graph.cpp
@@ -16,7 +16,7 @@
#include
ConVar cv_graph_fixcamp ("yb_graph_fixcamp", "1", "Specifies whether bot should not 'fix' camp directions of camp waypoints when loading old PWF format.");
-ConVar cv_graph_url ("yb_graph_url", product.download.chars (), "Specifies the URL from bots will be able to download graph in case of missing local one.", false, 0.0f, 0.0f);
+ConVar cv_graph_url ("yb_graph_url", product.download.chars (), "Specifies the URL from bots will be able to download graph in case of missing local one. Set to empty, if no downloads needed.", false, 0.0f, 0.0f);
void BotGraph::initGraph () {
// this function initialize the graph structures..
@@ -1316,6 +1316,13 @@ void BotGraph::initNarrowPlaces () {
if (m_paths.empty () || m_narrowChecked) {
return;
}
+ constexpr int32 kNarrowPlacesMinGraphVersion = 2;
+
+ // if version 2 or higher, narrow places already initialized and saved into file
+ if (m_version >= kNarrowPlacesMinGraphVersion) {
+ m_narrowChecked = true;
+ return;
+ }
TraceResult tr;
const auto distance = 178.0f;
@@ -1518,13 +1525,11 @@ template bool BotGraph::saveStorage (StringRef ext, StringRef name,
return false;
}
- ULZ lz;
-
int32 rawLength = data.template length () * sizeof (U);
SmallArray compressed (rawLength + sizeof (uint8) * ULZ::Excess);
// try to compress
- auto compressedLength = lz.compress (reinterpret_cast (data.data ()), rawLength, reinterpret_cast (compressed.data ()));
+ auto compressedLength = ulz.compress (reinterpret_cast (data.data ()), rawLength, reinterpret_cast (compressed.data ()));
if (compressedLength > 0) {
StorageHeader hdr {};
@@ -1585,11 +1590,11 @@ template bool BotGraph::loadStorage (StringRef ext, StringRef name,
// downloader for graph
auto download = [&] () -> bool {
- auto downloadAddress = cv_graph_url.str ();
-
- if (strings.isEmpty (downloadAddress)) {
+ if (!graph.canDownload ()) {
return false;
}
+ auto downloadAddress = cv_graph_url.str ();
+
auto toDownload = strings.format ("%sgraph/%s", getDataDirectory (false), filename);
auto fromDownload = strings.format ("http://%s/graph/%s", downloadAddress, filename);
@@ -1599,7 +1604,7 @@ template bool BotGraph::loadStorage (StringRef ext, StringRef name,
return true;
}
else {
- game.print ("Can't download '%s'. from '%s' to '%s'... (%d).", filename, fromDownload, toDownload, http.getLastStatusCode ());
+ game.print ("Can't download '%s' from '%s' to '%s'... (%d).", filename, fromDownload, toDownload, http.getLastStatusCode ());
}
return false;
};
@@ -1656,13 +1661,18 @@ template bool BotGraph::loadStorage (StringRef ext, StringRef name,
}
// check the version
- if (hdr.version != version) {
+ if (hdr.version > version) {
if (tryReload ()) {
return true;
}
return raiseLoadingError (isGraph, file, "Damaged %s (filename: '%s'). Version number differs (got: '%d', need: '%d').", name, filename, hdr.version, version);
}
+ // save graph version
+ if (isGraph) {
+ m_version = hdr.version;
+ }
+
// check the storage type
if ((hdr.options & options) != options) {
return raiseLoadingError (isGraph, file, "Incorrect storage format for %s (filename: '%s').", name, filename);
@@ -1676,10 +1686,9 @@ template bool BotGraph::loadStorage (StringRef ext, StringRef name,
// read compressed data
if (file.read (compressed.data (), sizeof (uint8), hdr.compressed) == static_cast (hdr.compressed)) {
- ULZ lz;
// try to uncompress
- if (lz.uncompress (compressed.data (), hdr.compressed, reinterpret_cast (data.data ()), hdr.uncompressed) == ULZ::UncompressFailure) {
+ if (ulz.uncompress (compressed.data (), hdr.compressed, reinterpret_cast (data.data ()), hdr.uncompressed) == ULZ::UncompressFailure) {
return raiseLoadingError (isGraph, file, "Unable to decompress ULZ data for %s (filename: '%s').", name, filename);
}
else {
@@ -1692,7 +1701,7 @@ template bool BotGraph::loadStorage (StringRef ext, StringRef name,
if ((hdr.options & StorageOption::Exten) && exten != nullptr) {
file.read (exten, sizeof (ExtenHeader));
}
- game.print ("Successfully loaded Bots %s data (%d/%.2fMB).", name, m_paths.length (), static_cast (data.capacity () * sizeof (U)) / 1024.0f / 1024.0f);
+ game.print ("Successfully loaded Bots %s data v%d.0 (%d/%.2fMB).", name, hdr.version, m_paths.length (), static_cast (data.capacity () * sizeof (U)) / 1024.0f / 1024.0f);
file.close ();
return true;
@@ -1747,6 +1756,10 @@ bool BotGraph::loadGraphData () {
return false;
}
+bool BotGraph::canDownload () {
+ return !strings.isEmpty (cv_graph_url.str ());
+}
+
bool BotGraph::saveGraphData () {
auto options = StorageOption::Graph | StorageOption::Exten;
String author;
@@ -1754,7 +1767,9 @@ bool BotGraph::saveGraphData () {
if (game.isNullEntity (m_editor) && !m_tempStrings.empty ()) {
author = m_tempStrings;
- options |= StorageOption::Recovered;
+ if (!game.isDedicated ()) {
+ options |= StorageOption::Recovered;
+ }
}
else if (!game.isNullEntity (m_editor)) {
author = m_editor->v.netname.chars ();
@@ -1772,6 +1787,10 @@ bool BotGraph::saveGraphData () {
strings.copy (exten.author, author.chars (), cr::bufsize (exten.author));
exten.mapSize = engfuncs.pfnGetFileSize (strings.format ("maps/%s.bsp", game.getMapName ()));
+ // ensure narrow places saved into file
+ m_narrowChecked = false;
+ initNarrowPlaces ();
+
return saveStorage ("graph", "Graph", static_cast (options), StorageVersion::Graph, m_paths, &exten);
}
@@ -2798,8 +2817,10 @@ BotGraph::BotGraph () {
m_rescuePoints.clear ();
m_sniperPoints.clear ();
+ m_version = StorageVersion::Graph;
m_loadAttempts = 0;
m_editFlags = 0;
+
m_pathDisplayTime = 0.0f;
m_arrowDisplayTime = 0.0f;
m_autoPathDistance = 250.0f;