OpenTTD Source 20250711-master-gaaf5d39b15
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 <ranges>
12#include "../debug.h"
13#include "../network/network.h"
14#include "../openttd.h"
15#include "../core/random_func.hpp"
16
17#include "../script/squirrel_class.hpp"
18#include "../script/api/script_object.hpp"
19#include "ai_info.hpp"
20#include "ai_scanner.hpp"
21
22#include "../safeguards.h"
23
24
25AIScannerInfo::AIScannerInfo() = default;
26AIScannerInfo::~AIScannerInfo() = default;
27
28void AIScannerInfo::Initialize()
29{
30 ScriptScanner::Initialize("AIScanner");
31
32 ScriptAllocatorScope alloc_scope(this->engine);
33
34 /* Create the dummy AI */
35 this->main_script = "%_dummy";
36 Script_CreateDummyInfo(this->engine->GetVM(), "AI", "ai");
37}
38
39void AIScannerInfo::SetDummyAI(std::unique_ptr<class AIInfo> &&info)
40{
41 this->info_dummy = std::move(info);
42}
43
45{
46 return info.GetName();
47}
48
53
55{
56 if (_game_mode == GM_MENU) {
57 Debug(script, 0, "The intro game should not use AI, loading 'dummy' AI.");
58 return this->info_dummy.get();
59 }
60
61 /* Filter for AIs suitable as Random AI. */
62 auto random_ais = info_single_list | std::views::filter([](const auto &item) { return static_cast<AIInfo *>(item.second)->UseAsRandomAI(); });
63
64 uint num_random_ais = std::ranges::distance(random_ais);
65 if (num_random_ais == 0) {
66 Debug(script, 0, "No suitable AI found, loading 'dummy' AI.");
67 return this->info_dummy.get();
68 }
69
70 /* Pick a random AI */
71 uint pos = ScriptObject::GetRandomizer(OWNER_NONE).Next(num_random_ais);
72 auto it = std::ranges::next(std::begin(random_ais), pos, std::end(random_ais));
73 assert(it != std::end(random_ais));
74
75 return static_cast<AIInfo *>(it->second);
76}
77
78AIInfo *AIScannerInfo::FindInfo(const std::string &name, int version, bool force_exact_match)
79{
80 if (this->info_list.empty()) return nullptr;
81 if (name.empty()) return nullptr;
82
83 if (version == -1) {
84 /* We want to load the latest version of this AI; so find it */
85 auto it = this->info_single_list.find(name);
86 if (it != this->info_single_list.end()) return static_cast<AIInfo *>(it->second);
87 return nullptr;
88 }
89
90 if (force_exact_match) {
91 /* Try to find a direct 'name.version' match */
92 std::string name_with_version = fmt::format("{}.{}", name, version);
93 auto it = this->info_list.find(name_with_version);
94 if (it != this->info_list.end()) return static_cast<AIInfo *>(it->second);
95 return nullptr;
96 }
97
98 AIInfo *info = nullptr;
99 int highest_version = -1;
100
101 /* See if there is a compatible AI which goes by that name, with the highest
102 * version which allows loading the requested version */
103 for (const auto &item : this->info_list) {
104 AIInfo *i = static_cast<AIInfo *>(item.second);
105 if (StrEqualsIgnoreCase(name, i->GetName()) && i->CanLoadFromVersion(version) && (highest_version == -1 || i->GetVersion() > highest_version)) {
106 highest_version = item.second->GetVersion();
107 info = i;
108 }
109 }
110
111 return info;
112}
113
114
115void AIScannerLibrary::Initialize()
116{
117 ScriptScanner::Initialize("AIScanner");
118}
119
121{
122 AILibrary &library = static_cast<AILibrary &>(info);
123 return fmt::format("{}.{}", library.GetCategory(), library.GetInstanceName());
124}
125
130
131AILibrary *AIScannerLibrary::FindLibrary(const std::string &library, int version)
132{
133 /* Internally we store libraries as 'library.version' */
134 std::string library_name = fmt::format("{}.{}", library, version);
135
136 /* Check if the library + version exists */
137 ScriptInfoList::iterator it = this->info_list.find(library_name);
138 if (it == this->info_list.end()) return nullptr;
139
140 return static_cast<AILibrary *>((*it).second);
141}
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:121
static void RegisterAPI(Squirrel &engine)
Register the functions of this class.
Definition ai_info.cpp:32
All static information from an AI library like name, version, etc.
Definition ai_info.hpp:60
const std::string & GetCategory() const
Get the category this library is in.
Definition ai_info.hpp:77
static void RegisterAPI(Squirrel &engine)
Register the functions of this class.
Definition ai_info.cpp:128
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.
void SetDummyAI(std::unique_ptr< class AIInfo > &&info)
Set the Dummy AI.
std::unique_ptr< AIInfo > info_dummy
The dummy AI.
void RegisterAPI(class Squirrel &engine) override
Register the API for this ScriptInfo.
class AIInfo * SelectRandomAI() const
Select a random AI.
std::string GetScriptName(ScriptInfo &info) override
Get the script name how to store the script in memory.
void RegisterAPI(class Squirrel &engine) override
Register the API for this ScriptInfo.
std::string GetScriptName(ScriptInfo &info) override
Get the script name how to store the script in memory.
class AILibrary * FindLibrary(const std::string &library, int version)
Find a library in the pool.
All static information from an Script like name, version, etc.
const std::string & GetInstanceName() const
Get the name of the instance of the script to create.
const std::string & GetName() const
Get the Name of the script.
int GetVersion() const
Get the version of the script.
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:82
static constexpr Owner OWNER_NONE
The tile has no ownership.
#define Debug(category, level, format_string,...)
Output a line of debugging information.
Definition debug.h:37
void Script_CreateDummyInfo(HSQUIRRELVM vm, std::string_view type, std::string_view dir)
Run the dummy info.nut.
bool StrEqualsIgnoreCase(std::string_view str1, std::string_view str2)
Compares two string( view)s for equality, while ignoring the case of the characters.
Definition string.cpp:321