OpenTTD Source  20241108-master-g80f628063a
ai_scanner.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of OpenTTD.
3  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6  */
7 
10 #include "../stdafx.h"
11 #include "../debug.h"
12 #include "../network/network.h"
13 #include "../openttd.h"
14 #include "../core/random_func.hpp"
15 
16 #include "../script/squirrel_class.hpp"
17 #include "../script/api/script_object.hpp"
18 #include "ai_info.hpp"
19 #include "ai_scanner.hpp"
20 
21 #include "../safeguards.h"
22 
23 
24 AIScannerInfo::AIScannerInfo() :
25  ScriptScanner(),
26  info_dummy(nullptr)
27 {
28 }
29 
30 void AIScannerInfo::Initialize()
31 {
32  ScriptScanner::Initialize("AIScanner");
33 
34  ScriptAllocatorScope alloc_scope(this->engine);
35 
36  /* Create the dummy AI */
37  this->main_script = "%_dummy";
38  Script_CreateDummyInfo(this->engine->GetVM(), "AI", "ai");
39 }
40 
42 {
43  this->info_dummy = info;
44 }
45 
46 AIScannerInfo::~AIScannerInfo()
47 {
48  delete this->info_dummy;
49 }
50 
52 {
53  return info->GetName();
54 }
55 
57 {
59 }
60 
62 {
63  if (_game_mode == GM_MENU) {
64  Debug(script, 0, "The intro game should not use AI, loading 'dummy' AI.");
65  return this->info_dummy;
66  }
67 
68  uint num_random_ais = 0;
69  for (const auto &item : info_single_list) {
70  AIInfo *i = static_cast<AIInfo *>(item.second);
71  if (i->UseAsRandomAI()) num_random_ais++;
72  }
73 
74  if (num_random_ais == 0) {
75  Debug(script, 0, "No suitable AI found, loading 'dummy' AI.");
76  return this->info_dummy;
77  }
78 
79  /* Find a random AI */
80  uint pos = ScriptObject::GetRandomizer(OWNER_NONE).Next(num_random_ais);
81 
82  /* Find the Nth item from the array */
83  ScriptInfoList::const_iterator it = this->info_single_list.begin();
84 
85 #define GetAIInfo(it) static_cast<AIInfo *>((*it).second)
86  while (!GetAIInfo(it)->UseAsRandomAI()) it++;
87  for (; pos > 0; pos--) {
88  it++;
89  while (!GetAIInfo(it)->UseAsRandomAI()) it++;
90  }
91  return GetAIInfo(it);
92 #undef GetAIInfo
93 }
94 
95 AIInfo *AIScannerInfo::FindInfo(const std::string &name, int version, bool force_exact_match)
96 {
97  if (this->info_list.empty()) return nullptr;
98  if (name.empty()) return nullptr;
99 
100  if (version == -1) {
101  /* We want to load the latest version of this AI; so find it */
102  auto it = this->info_single_list.find(name);
103  if (it != this->info_single_list.end()) return static_cast<AIInfo *>(it->second);
104  return nullptr;
105  }
106 
107  if (force_exact_match) {
108  /* Try to find a direct 'name.version' match */
109  std::string name_with_version = fmt::format("{}.{}", name, version);
110  auto it = this->info_list.find(name_with_version);
111  if (it != this->info_list.end()) return static_cast<AIInfo *>(it->second);
112  return nullptr;
113  }
114 
115  AIInfo *info = nullptr;
116  int highest_version = -1;
117 
118  /* See if there is a compatible AI which goes by that name, with the highest
119  * version which allows loading the requested version */
120  for (const auto &item : this->info_list) {
121  AIInfo *i = static_cast<AIInfo *>(item.second);
122  if (StrEqualsIgnoreCase(name, i->GetName()) && i->CanLoadFromVersion(version) && (highest_version == -1 || i->GetVersion() > highest_version)) {
123  highest_version = item.second->GetVersion();
124  info = i;
125  }
126  }
127 
128  return info;
129 }
130 
131 
132 void AIScannerLibrary::Initialize()
133 {
134  ScriptScanner::Initialize("AIScanner");
135 }
136 
138 {
139  AILibrary *library = static_cast<AILibrary *>(info);
140  return fmt::format("{}.{}", library->GetCategory(), library->GetInstanceName());
141 }
142 
144 {
146 }
147 
148 AILibrary *AIScannerLibrary::FindLibrary(const std::string &library, int version)
149 {
150  /* Internally we store libraries as 'library.version' */
151  std::string library_name = fmt::format("{}.{}", library, version);
152 
153  /* Check if the library + version exists */
154  ScriptInfoList::iterator it = this->info_list.find(library_name);
155  if (it == this->info_list.end()) return nullptr;
156 
157  return static_cast<AILibrary *>((*it).second);
158 }
AIInfo keeps track of all information of an AI, like Author, Description, ...
declarations of the class for AI scanner
All static information from an AI like name, version, etc.
Definition: ai_info.hpp:16
bool CanLoadFromVersion(int version) const
Check if we can start this AI.
Definition: ai_info.cpp:124
bool UseAsRandomAI() const
Use this AI as a random AI.
Definition: ai_info.hpp:43
static void RegisterAPI(Squirrel *engine)
Register the functions of this class.
Definition: ai_info.cpp:36
All static information from an AI library like name, version, etc.
Definition: ai_info.hpp:57
static void RegisterAPI(Squirrel *engine)
Register the functions of this class.
Definition: ai_info.cpp:131
const std::string & GetCategory() const
Get the category this library is in.
Definition: ai_info.hpp:74
class AIInfo * FindInfo(const std::string &name, int version, bool force_exact_match)
Check if we have an AI by name and version available in our list.
Definition: ai_scanner.cpp:95
AIInfo * info_dummy
The dummy AI.
Definition: ai_scanner.hpp:50
class AIInfo * SelectRandomAI() const
Select a random AI.
Definition: ai_scanner.cpp:61
std::string GetScriptName(ScriptInfo *info) override
Get the script name how to store the script in memory.
Definition: ai_scanner.cpp:51
void RegisterAPI(class Squirrel *engine) override
Register the API for this ScriptInfo.
Definition: ai_scanner.cpp:56
void SetDummyAI(class AIInfo *info)
Set the Dummy AI.
Definition: ai_scanner.cpp:41
void RegisterAPI(class Squirrel *engine) override
Register the API for this ScriptInfo.
Definition: ai_scanner.cpp:143
std::string GetScriptName(ScriptInfo *info) override
Get the script name how to store the script in memory.
Definition: ai_scanner.cpp:137
class AILibrary * FindLibrary(const std::string &library, int version)
Find a library in the pool.
Definition: ai_scanner.cpp:148
All static information from an Script like name, version, etc.
Definition: script_info.hpp:30
const std::string & GetInstanceName() const
Get the name of the instance of the script to create.
Definition: script_info.hpp:71
int GetVersion() const
Get the version of the script.
Definition: script_info.hpp:61
const std::string & GetName() const
Get the Name of the script.
Definition: script_info.hpp:46
Scanner to help finding scripts.
class Squirrel * engine
The engine we're scanning with.
std::string main_script
The full path of the script.
ScriptInfoList info_list
The list of all script.
ScriptInfoList info_single_list
The list of all unique script. The best script (highest version) is shown.
HSQUIRRELVM GetVM()
Get the squirrel VM.
Definition: squirrel.hpp:80
@ OWNER_NONE
The tile has no ownership.
Definition: company_type.h:25
#define Debug(category, level, format_string,...)
Ouptut a line of debugging information.
Definition: debug.h:37
void Script_CreateDummyInfo(HSQUIRRELVM vm, const char *type, const char *dir)
Run the dummy info.nut.
bool StrEqualsIgnoreCase(const std::string_view str1, const std::string_view str2)
Compares two string( view)s for equality, while ignoring the case of the characters.
Definition: string.cpp:347