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
054  /* Core non-final variables utilized within TNPC as settings */
055  protected File directory;
056
057  //The DebugLevel that the server is currently running in.
058  protected DebugLevel level = DebugLevel.STANDARD;
059
060  /* Key Managers and Object instances utilized with TNE */
061
062  //General Key Object Instances
063  protected LogProvider logger;
064
065  protected PluginEngine engine;
066
067  //Manager Instances
068  protected ServerConnector server;
069  protected UUIDProvider uuidProvider;
070  private final MessageHandler messenger;
071
072  /* Plugin Instance */
073  private static PluginCore instance;
074
075  protected CallbackManager callbackManager;
076  protected ChannelMessageManager channelMessageManager;
077
078  protected ModuleLoader loader;
079  protected ModuleFileCache moduleCache;
080
081  private boolean enabled = false;
082
083  protected UUID serverID;
084
085  protected Platform platform;
086  protected String version;
087
088  public PluginCore(final PluginEngine engine, final ServerConnector server, final LogProvider logger,
089                    final TranslationProvider provider, final CallbackProvider callbackProvider,
090                    final Platform platform, final String version) {
091    this.server = server;
092    this.logger = logger;
093    this.engine = engine;
094    this.messenger = new MessageHandler(provider);
095    this.callbackManager = new CallbackManager(callbackProvider);
096
097    this.platform = platform;
098    this.version = version;
099  }
100
101  public static void setInstance(final PluginCore core) {
102    if(instance == null) {
103      instance = core;
104    } else {
105      throw new IllegalStateException("PluginCore has already been initiated. Please refrain from attempting" +
106              "to modify the instance variable.");
107    }
108  }
109
110  public void enable() {
111    if(!enabled) {
112
113      this.enabled = true;
114      this.loader = new ModuleLoader();
115      onEnable();
116
117    } else {
118      throw new IllegalStateException("PluginCore has already been enabled!");
119    }
120  }
121
122  /**
123   * Used to enable the core. This should contain things that can't be initialized until after the
124   * server software is operational.
125   */
126  protected void onEnable() {
127
128    if(!directory.exists()) {
129      final boolean created = directory.mkdir();
130      if(!created) {
131        logger.error("Failed to create plugin directory. Disabling plugin.", DebugLevel.OFF);
132        return;
133      }
134    }
135    this.serverID = UUID.randomUUID();
136
137    this.uuidProvider = new BaseUUIDProvider();
138
139    this.engine.registerConfigs();
140
141    this.engine.initComponents(platform, version);
142    this.engine.initRegistries(platform, version);
143
144    //Load our modules
145    loader.load();
146
147    //Call onEnable for all modules loaded.
148    loader.getModules().values().forEach((moduleWrapper -> moduleWrapper.getModule().enable(this)));
149
150    //Call initConfigurations for all modules loaded.
151    loader.getModules().values().forEach((moduleWrapper -> moduleWrapper.getModule().initConfigurations(directory)));
152
153    this.engine.registerCallbacks(callbackManager);
154
155    //Register the callback listeners and callbacks for the modules
156    loader.getModules().values().forEach((moduleWrapper ->{
157      moduleWrapper.getModule().registerCallbacks().forEach((key, entry)->{
158        callbackManager.addCallback(key, entry);
159      });
160
161      moduleWrapper.getModule().registerListeners().forEach((key, function)->{
162        callbackManager.addConsumer(key, function);
163      });
164    }));
165
166    this.engine.postConfigs();
167
168    this.channelMessageManager = new ChannelMessageManager();
169
170    this.engine.registerPluginChannels();
171
172    this.channelMessageManager.register();
173
174    this.engine.registerStorage();
175    if(this.engine.storage() == null) {
176      logger.warning("Storage engine not initialized, proceeding without storage!", DebugLevel.OFF);
177    } else {
178      if(!storage().meetsRequirement()) {
179        logger.error("This server does not meet SQL requirements needed!", DebugLevel.OFF);
180        return;
181      }
182    }
183
184    this.engine.postStorage();
185
186    //Call the enableSave method for all modules loaded.
187    loader.getModules().values().forEach((moduleWrapper -> moduleWrapper.getModule().enableSave(this.engine.storage())));
188
189    //register our commands
190    this.engine.registerCommandHandler();
191
192    //Register our help writer.
193    //command().setHelpWriter(engine::commandHelpWriter);
194
195    //Register our commands.
196    this.engine.registerCommands();
197
198    //Call our command methods for the modules.
199    loader.getModules().values().forEach((moduleWrapper ->{
200      moduleWrapper.getModule().registerCommands(this.engine.command());
201    }));
202
203
204    this.engine.postCommands();
205
206    this.engine.registerMenuHandler();
207
208    //Call enableMenu for all modules loaded.
209    loader.getModules().values().forEach((moduleWrapper -> moduleWrapper.getModule().enableMenu(this.engine.menu())));
210
211    this.moduleCache = new ModuleFileCache();
212
213    this.engine.registerUpdateChecker();
214
215    this.engine.postEnable();
216  }
217
218  public void registerModuleCommands(final Lamp<?> lamp) {
219    loader.getModules().values().forEach((moduleWrapper -> moduleWrapper.getModule().registerAdminSub().forEach(orphanCommand -> {
220      lamp.register(Orphans.path("tne").handler(orphanCommand));
221    })));
222
223    loader.getModules().values().forEach((moduleWrapper -> moduleWrapper.getModule().registerMoneySub().forEach(orphanCommand -> {
224      lamp.register(Orphans.path("money").handler(orphanCommand));
225    })));
226
227    loader.getModules().values().forEach((moduleWrapper -> moduleWrapper.getModule().registerTransactionSub().forEach(orphanCommand -> {
228      lamp.register(Orphans.path("transaction").handler(orphanCommand));
229    })));
230  }
231
232  public void onDisable() {
233
234    loader.getModules().values().forEach((moduleWrapper -> moduleWrapper.getModule().disable(this)));
235
236    this.engine.postDisable();
237  }
238
239  /**
240   * The implementation's {@link LogProvider}.
241   *
242   * @return The log provider.
243   */
244  public static LogProvider log() {
245    return instance.logger;
246  }
247
248  /**
249   * The {@link StorageManager} we are utilizing.
250   *
251   * @return The {@link StorageManager}.
252   */
253  public static StorageManager storage() {
254    return instance.engine.storage();
255  }
256
257  /**
258   * The {@link ServerConnector} for the implementation.
259   * @return The {@link ServerConnector} for the implementation.
260   */
261  public static ServerConnector server() {
262    return instance.server;
263  }
264
265  public static MessageHandler messenger() {
266    return instance.messenger;
267  }
268
269  public static File directory() {
270    return instance.directory;
271  }
272
273  public static CallbackManager callbacks() {
274    return instance.callbackManager;
275  }
276
277  public ChannelMessageManager getChannelMessageManager() {
278    return channelMessageManager;
279  }
280
281  public static ModuleLoader loader() {
282    return instance.loader;
283  }
284
285  @Nullable
286  public static UpdateChecker update() {
287    return instance.engine.update();
288  }
289
290  public ModuleFileCache moduleCache() {
291    return moduleCache;
292  }
293
294  public DebugLevel getLevel() {
295    return level;
296  }
297
298  public void setLevel(final DebugLevel level) {
299    this.level = level;
300  }
301
302  public Lamp.Builder<? extends CommandActor> command() {
303    return engine.command();
304  }
305
306  public static PluginCore instance() {
307    return instance;
308  }
309
310  public static UUIDProvider uuidProvider() {
311    return instance.uuidProvider;
312  }
313
314  public UUID getServerID() {
315    return serverID;
316  }
317
318  public void setServerID(final UUID serverID) {
319    this.serverID = serverID;
320  }
321
322  public void setCallbackManager(final CallbackManager callbackManager) {
323    this.callbackManager = callbackManager;
324  }
325
326  public static PluginEngine engine() {
327    return instance.engine;
328  }
329}