Spellforce-Spell-framework
Loading...
Searching...
No Matches
sf_error_registry.cpp
Go to the documentation of this file.
1
5
6#include "sf_error_registry.h"
7
9
10#include <algorithm>
11#include <map>
12#include <string>
13
14#include <ctype.h>
15#include <stdarg.h>
16#include <stdio.h>
17#include <string.h>
18
19static std::map<uint32_t, SFMod *> s_numeric_claims[CONFLICT_DOMAIN_COUNT];
20static std::map<std::string, SFMod *> s_string_claims[CONFLICT_DOMAIN_COUNT];
21static std::list<RegisteredMod> s_registered_mods;
22
26static void append_to_buffer(char *buffer, size_t buffer_size, const char *format, va_list args)
27{
28 size_t used = strnlen(buffer, buffer_size);
29 if (used + 1 >= buffer_size)
30 {
31 return;
32 }
33
34 vsnprintf(buffer + used, buffer_size - used, format, args);
35 buffer[buffer_size - 1] = '\0';
36}
37
38static std::string make_key(const char *key)
39{
40 std::string lowered(key != NULL ? key : "");
41 std::transform(lowered.begin(), lowered.end(), lowered.begin(),
42 [](unsigned char c) { return (char)tolower(c); });
43 return lowered;
44}
45
46void append_mod_error(SFMod *mod, const char *format, ...)
47{
48 if (mod == NULL)
49 {
50 return;
51 }
52
53 va_list args;
54 va_start(args, format);
55 append_to_buffer(mod->mod_errors, sizeof(mod->mod_errors), format, args);
56 va_end(args);
57}
58
59void report_mod_error(SFMod *mod, const char *format, ...)
60{
61 char message[256];
62
63 va_list args;
64 va_start(args, format);
65 vsnprintf(message, sizeof(message), format, args);
66 va_end(args);
67
68 log_error("| - %s", message);
69
70 if (mod != NULL)
71 {
72 append_mod_error(mod, "%s\n", message);
73 }
74
76}
77
78void report_mod_warning(SFMod *mod, const char *format, ...)
79{
80 (void)mod;
81
82 char message[256];
83
84 va_list args;
85 va_start(args, format);
86 vsnprintf(message, sizeof(message), format, args);
87 va_end(args);
88
89 log_warning_level(DEBUG_INFO, "| - %s", message);
90}
91
92void report_mod_warning(SFMod *mod, DebugLevel level, const char *format, ...)
93{
94 (void)mod;
95
96 char message[256];
97
98 va_list args;
99 va_start(args, format);
100 vsnprintf(message, sizeof(message), format, args);
101 va_end(args);
102
103 log_warning_level(level, "| - %s", message);
104}
105
107{
108 if (mod != NULL)
109 {
110 mod->mod_errors[0] = '\0';
111 }
112}
113
114bool claim_numeric_id(ConflictDomain domain, uint32_t id, SFMod *mod,
115 uint32_t vanilla_max, const char *id_label)
116{
117 if (domain >= CONFLICT_DOMAIN_COUNT || mod == NULL)
118 {
119 return false;
120 }
121
122 std::map<uint32_t, SFMod *> &claims = s_numeric_claims[domain];
123 std::map<uint32_t, SFMod *>::iterator existing = claims.find(id);
124 bool was_free = (existing == claims.end());
125
126 if (!was_free)
127 {
128 SFMod *previous_owner = existing->second;
129
130 if (id < vanilla_max)
131 {
133 "%s has Overwritten a vanilla %s [%u], this was previously registered by [%s]",
134 mod->mod_id, id_label, id, previous_owner->mod_id);
135 }
136 else
137 {
138 log_error("| - Mod Conflict Detected [%s]: %s [%u] is already registered by [%s]",
139 mod->mod_id, id_label, id, previous_owner->mod_id);
140
141 // The error is shown on the mod that LOST the ID
142 append_mod_error(previous_owner, "%s [%u] was overwritten by %s\n",
143 id_label, id, mod->mod_id);
144
146 }
147 }
148
149 claims[id] = mod;
150 return was_free;
151}
152
153bool claim_string_id(ConflictDomain domain, const char *key, SFMod *mod,
154 const char *id_label)
155{
156 if (domain >= CONFLICT_DOMAIN_COUNT || mod == NULL || key == NULL)
157 {
158 return false;
159 }
160
161 std::map<std::string, SFMod *> &claims = s_string_claims[domain];
162 std::string lookup = make_key(key);
163 std::map<std::string, SFMod *>::iterator existing = claims.find(lookup);
164 bool was_free = (existing == claims.end());
165
166 if (!was_free)
167 {
168 SFMod *previous_owner = existing->second;
169
170 log_error("| - Mod Conflict Detected [%s]: %s [%s] is already registered by [%s]",
171 mod->mod_id, id_label, key, previous_owner->mod_id);
172
173 append_mod_error(previous_owner, "%s [%s] was overwritten by %s\n",
174 id_label, key, mod->mod_id);
175
177 }
178
179 claims[lookup] = mod;
180 return was_free;
181}
182
184{
185 if (domain < CONFLICT_DOMAIN_COUNT)
186 {
187 s_numeric_claims[domain].clear();
188 s_string_claims[domain].clear();
189 }
190}
191
193{
194 switch (type)
195 {
197 return "[ FRAMEWORK ]";
198 case MOD_TYPE_CORE:
199 return "[ CORE MODULE ]";
200 default:
201 return " ";
202 }
203}
204
206{
207 if (mod == NULL)
208 {
209 return;
210 }
211
212 for (const RegisteredMod &known : s_registered_mods)
213 {
214 if (known.mod == mod)
215 {
216 return;
217 }
218 }
219
220 RegisteredMod entry;
221 entry.mod = mod;
222 entry.type = type;
223
224 /* Insert ahead of the first entry of a later type. Groups therefore stay in
225 * framework -> core -> external order while registration order is preserved
226 * inside each group, whatever order the subsystems initialise in. */
227 std::list<RegisteredMod>::iterator position = s_registered_mods.begin();
228 while (position != s_registered_mods.end() && position->type <= type)
229 {
230 ++position;
231 }
232
233 s_registered_mods.insert(position, entry);
234}
235
236const std::list<RegisteredMod> &get_registered_mods()
237{
238 return s_registered_mods;
239}
240
const char * get_mod_type_label(ModType type)
Tag rendered next to a mod in the list. Empty for external mods.
bool claim_numeric_id(ConflictDomain domain, uint32_t id, SFMod *mod, uint32_t vanilla_max, const char *id_label)
Claims a numeric ID within a domain for a mod.
void clear_mod_errors(SFMod *mod)
Empties a mod's error buffer.
void register_mod_for_listing(SFMod *mod, ModType type)
Adds a mod to the list rendered by the in-game mod list screen.
bool claim_string_id(ConflictDomain domain, const char *key, SFMod *mod, const char *id_label)
Claims a string key within a domain for a mod. Comparison is case-insensitive, since the keys are Win...
void append_mod_error(SFMod *mod, const char *format,...)
Appends a line to a mod's error buffer without logging it.
const std::list< RegisteredMod > & get_registered_mods()
The mods known to the framework, grouped framework -> core -> external.
void report_mod_warning(SFMod *mod, const char *format,...)
Logs a warning against a mod at DEBUG_INFO, i.e. always shown.
ConflictDomain
Namespaces for conflict checking.
ModType
What sort of mod an entry in the mod list is.
void reset_conflict_domain(ConflictDomain domain)
Drops every claim in a domain. Intended for reloads and tests.
void report_mod_error(SFMod *mod, const char *format,...)
Logs an error, appends it to the mod's error buffer and counts it.
@ CONFLICT_DOMAIN_COUNT
@ MOD_TYPE_CORE
@ MOD_TYPE_FRAMEWORK
void log_error(const char *format,...)
void log_warning_level(DebugLevel level, const char *format,...)
Logs a warning that is only shown once the log level reaches level.
int g_error_count
A mod as shown in the in-game mod list.
char mod_errors[256]