001package net.tnemc.plugincore;
002
003/*
004 * The New Plugin Core
005 * Copyright (C) 2022 - 2024 Daniel "creatorfromhell" Vidmar
006 *
007 * This program is free software: you can redistribute it and/or modify
008 * it under the terms of the GNU Affero General Public License as published by
009 * the Free Software Foundation, either version 3 of the License, or
010 * (at your option) any later version.
011 *
012 * This program is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
015 * GNU Affero General Public License for more details.
016 *
017 * You should have received a copy of the GNU Affero General Public License
018 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
019 */
020
021import net.tnemc.plugincore.core.Platform;
022import net.tnemc.plugincore.core.PluginEngine;
023import net.tnemc.plugincore.core.api.CallbackManager;
024import net.tnemc.plugincore.core.api.CallbackProvider;
025import net.tnemc.plugincore.core.channel.ChannelMessageManager;
026import net.tnemc.plugincore.core.compatibility.LogProvider;
027import net.tnemc.plugincore.core.compatibility.ServerConnector;
028import net.tnemc.plugincore.core.compatibility.log.DebugLevel;
029import net.tnemc.plugincore.core.id.UUIDProvider;
030import net.tnemc.plugincore.core.id.impl.provider.BaseUUIDProvider;
031import net.tnemc.plugincore.core.io.message.MessageHandler;
032import net.tnemc.plugincore.core.io.message.TranslationProvider;
033import net.tnemc.plugincore.core.io.storage.StorageManager;
034import net.tnemc.plugincore.core.module.ModuleLoader;
035import net.tnemc.plugincore.core.module.cache.ModuleFileCache;
036import net.tnemc.plugincore.core.utils.UpdateChecker;
037import org.jetbrains.annotations.Nullable;
038import revxrsal.commands.Lamp;
039import revxrsal.commands.command.CommandActor;
040import revxrsal.commands.orphan.Orphans;
041
042import java.io.File;
043import java.util.UUID;
044import java.util.regex.Pattern;
045
046public class PluginCore {
047
048  /*
049   * Core final variables utilized within TNPC.
050   */
051  public static final Pattern UUID_MATCHER_PATTERN = Pattern.compile("(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})");
052  public static final Pattern USERNAME_MATCHER_PATTERN = Pattern.compile("^\\w*$");
053  /* Plugin Instance */
054  private static PluginCore instance;
055  private final MessageHandler messenger;
056
057  /* Key Managers and Object instances utilized with TNE */
058  /* Core non-final variables utilized within TNPC as settings */
059  protected File directory;
060  //The DebugLevel that the server is currently running in.
061  protected DebugLevel level = DebugLevel.STANDARD;
062  //General Key Object Instances
063  protected LogProvider logger;
064  protected PluginEngine engine;
065  //Manager Instances
066  protected ServerConnector server;
067  protected UUIDProvider uuidProvider;
068  protected CallbackManager callbackManager;
069  protected ChannelMessageManager channelMessageManager;
070
071  protected ModuleLoader loader;
072  protected ModuleFileCache moduleCache;
073  protected UUID serverID;
074  protected Platform platform;
075  protected String version;
076  private boolean loaded = false;
077  private boolean enabled = false;
078
079  public PluginCore(final PluginEngine engine, final ServerConnector server, final LogProvider logger,
080                    final TranslationProvider provider, final CallbackProvider callbackProvider,
081                    final Platform platform, final String version) {
082
083    this.server = server;
084    this.logger = logger;
085    this.engine = engine;
086    this.messenger = new MessageHandler(provider);
087    this.callbackManager = new CallbackManager(callbackProvider);
088
089    this.platform = platform;
090    this.version = version;
091  }
092
093  public static void setInstance(final PluginCore core) {
094
095    if(instance == null) {
096      instance = core;
097    } else {
098      throw new IllegalStateException("PluginCore has already been initiated. Please refrain from attempting" +
099                                      "to modify the instance variable.");
100    }
101  }
102
103  /**
104   * The implementation's {@link LogProvider}.
105   *
106   * @return The log provider.
107   */
108  public static LogProvider log() {
109
110    return instance.logger;
111  }
112
113  /**
114   * The {@link StorageManager} we are utilizing.
115   *
116   * @return The {@link StorageManager}.
117   */
118  public static StorageManager storage() {
119
120    return instance.engine.storage();
121  }
122
123  /**
124   * The {@link ServerConnector} for the implementation.
125   *
126   * @return The {@link ServerConnector} for the implementation.
127   */
128  public static ServerConnector server() {
129
130    return instance.server;
131  }
132
133  public static MessageHandler messenger() {
134
135    return instance.messenger;
136  }
137
138  public static File directory() {
139
140    return instance.directory;
141  }
142
143  public static CallbackManager callbacks() {
144
145    return instance.callbackManager;
146  }
147
148  public static ModuleLoader loader() {
149
150    return instance.loader;
151  }
152
153  @Nullable
154  public static UpdateChecker update() {
155
156    return instance.engine.update();
157  }
158
159  public static PluginCore instance() {
160
161    return instance;
162  }
163
164  public static UUIDProvider uuidProvider() {
165
166    return instance.uuidProvider;
167  }
168
169  public static PluginEngine engine() {
170
171    return instance.engine;
172  }
173
174  public void load() {
175
176    if(loaded) {
177      throw new IllegalStateException("PluginCore has already been loaded!");
178    }
179    onLoad();
180  }
181
182  protected void onLoad() {
183
184    this.engine.load();
185
186    if(!directory.exists()) {
187      final boolean created = directory.mkdir();
188      if(!created) {
189        logger.error("Failed to create plugin directory. Disabling plugin.", DebugLevel.OFF);
190        return;
191      }
192    }
193    this.serverID = UUID.randomUUID();
194
195    this.uuidProvider = new BaseUUIDProvider();
196
197    this.engine.registerConfigs();
198
199    this.engine.initComponents(platform, version);
200    this.engine.initRegistries(platform, version);
201
202    this.engine.registerCallbacks(callbackManager);
203
204    this.engine.postLoad();
205  }
206
207  public void enable() {
208
209    if(enabled) {
210      throw new IllegalStateException("PluginCore has already been enabled!");
211    }
212
213    this.enabled = true;
214    this.loader = new ModuleLoader();
215    onEnable();
216  }
217
218  /**
219   * Used to enable the core. This should contain things that can't be initialized until after the
220   * server software is operational.
221   */
222  protected void onEnable() {
223
224    //Load our modules
225    loader.load();
226
227    //Call onEnable for all modules loaded.
228    loader.getModules().values().forEach((moduleWrapper->moduleWrapper.getModule().enable(this)));
229
230    //Call initConfigurations for all modules loaded.
231    loader.getModules().values().forEach((moduleWrapper->moduleWrapper.getModule().initConfigurations(directory)));
232
233    //Register the callback listeners and callbacks for the modules
234    loader.getModules().values().forEach((moduleWrapper->{
235      moduleWrapper.getModule().registerCallbacks().forEach((key, entry)->{
236        callbackManager.addCallback(key, entry);
237      });
238
239      moduleWrapper.getModule().registerListeners().forEach((key, function)->{
240        callbackManager.addConsumer(key, function);
241      });
242    }));
243
244    this.engine.postConfigs();
245
246    this.channelMessageManager = new ChannelMessageManager();
247
248    this.engine.registerPluginChannels();
249
250    this.channelMessageManager.register();
251
252    this.engine.registerStorage();
253    if(this.engine.storage() == null) {
254      logger.warning("Storage engine not initialized, proceeding without storage!", DebugLevel.OFF);
255    } else {
256      if(!storage().meetsRequirement()) {
257        logger.error("This server does not meet SQL requirements needed!", DebugLevel.OFF);
258        return;
259      }
260    }
261
262    this.engine.postStorage();
263
264    //Call the enableSave method for all modules loaded.
265    loader.getModules().values().forEach((moduleWrapper->moduleWrapper.getModule().enableSave(this.engine.storage())));
266
267    //register our commands
268    this.engine.registerCommandHandler();
269
270    //Register our help writer.
271    //command().setHelpWriter(engine::commandHelpWriter);
272
273    //Register our commands.
274    this.engine.registerCommands();
275
276    //Call our command methods for the modules.
277    loader.getModules().values().forEach((moduleWrapper->{
278      moduleWrapper.getModule().registerCommands(this.engine.command());
279    }));
280
281
282    this.engine.postCommands();
283
284    this.engine.registerMenuHandler();
285
286    //Call enableMenu for all modules loaded.
287    loader.getModules().values().forEach((moduleWrapper->moduleWrapper.getModule().enableMenu(this.engine.menu())));
288
289    this.moduleCache = new ModuleFileCache();
290
291    this.engine.registerUpdateChecker();
292
293    this.engine.postEnable();
294  }
295
296  public void registerModuleCommands(final Lamp<?> lamp) {
297
298    loader.getModules().values().forEach((moduleWrapper->moduleWrapper.getModule().registerAdminSub().forEach(orphanCommand->{
299      lamp.register(Orphans.path("tne").handler(orphanCommand));
300    })));
301
302    loader.getModules().values().forEach((moduleWrapper->moduleWrapper.getModule().registerMoneySub().forEach(orphanCommand->{
303      lamp.register(Orphans.path("money").handler(orphanCommand));
304    })));
305
306    loader.getModules().values().forEach((moduleWrapper->moduleWrapper.getModule().registerTransactionSub().forEach(orphanCommand->{
307      lamp.register(Orphans.path("transaction").handler(orphanCommand));
308    })));
309  }
310
311  public void onDisable() {
312
313    loader.getModules().values().forEach((moduleWrapper->moduleWrapper.getModule().disable(this)));
314
315    this.engine.postDisable();
316  }
317
318  public ChannelMessageManager getChannelMessageManager() {
319
320    return channelMessageManager;
321  }
322
323  public ModuleFileCache moduleCache() {
324
325    return moduleCache;
326  }
327
328  public DebugLevel getLevel() {
329
330    return level;
331  }
332
333  public void setLevel(final DebugLevel level) {
334
335    this.level = level;
336  }
337
338  public Lamp<? extends CommandActor> command() {
339
340    return engine.command();
341  }
342
343  public UUID getServerID() {
344
345    return serverID;
346  }
347
348  public void setServerID(final UUID serverID) {
349
350    this.serverID = serverID;
351  }
352
353  public void setCallbackManager(final CallbackManager callbackManager) {
354
355    this.callbackManager = callbackManager;
356  }
357}