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}