2020-04-20 12:50:28 +02:00
|
|
|
/*
|
|
|
|
* This file is part of BlueMap, licensed under the MIT License (MIT).
|
|
|
|
*
|
|
|
|
* Copyright (c) Blue (Lukas Rieger) <https://bluecolored.de>
|
|
|
|
* Copyright (c) contributors
|
|
|
|
*
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
|
|
* in the Software without restriction, including without limitation the rights
|
|
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
|
|
* furnished to do so, subject to the following conditions:
|
|
|
|
*
|
|
|
|
* The above copyright notice and this permission notice shall be included in
|
|
|
|
* all copies or substantial portions of the Software.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
|
|
* THE SOFTWARE.
|
|
|
|
*/
|
2020-01-15 20:20:22 +01:00
|
|
|
package de.bluecolored.bluemap.common.plugin;
|
2020-01-13 17:13:20 +01:00
|
|
|
|
2022-07-30 15:31:42 +02:00
|
|
|
import de.bluecolored.bluemap.api.debug.DebugDump;
|
2022-06-06 22:51:26 +02:00
|
|
|
import de.bluecolored.bluemap.common.BlueMapConfigProvider;
|
2021-04-24 22:11:26 +02:00
|
|
|
import de.bluecolored.bluemap.common.BlueMapService;
|
|
|
|
import de.bluecolored.bluemap.common.InterruptableReentrantLock;
|
|
|
|
import de.bluecolored.bluemap.common.MissingResourcesException;
|
2022-07-24 12:10:00 +02:00
|
|
|
import de.bluecolored.bluemap.common.api.BlueMapAPIImpl;
|
2022-04-20 22:54:27 +02:00
|
|
|
import de.bluecolored.bluemap.common.config.*;
|
2022-07-30 15:31:42 +02:00
|
|
|
import de.bluecolored.bluemap.common.live.LivePlayersDataSupplier;
|
2020-08-07 14:17:48 +02:00
|
|
|
import de.bluecolored.bluemap.common.plugin.skins.PlayerSkinUpdater;
|
2021-05-16 11:13:21 +02:00
|
|
|
import de.bluecolored.bluemap.common.rendermanager.MapUpdateTask;
|
|
|
|
import de.bluecolored.bluemap.common.rendermanager.RenderManager;
|
2022-06-27 01:13:48 +02:00
|
|
|
import de.bluecolored.bluemap.common.serverinterface.ServerEventListener;
|
|
|
|
import de.bluecolored.bluemap.common.serverinterface.ServerInterface;
|
2023-02-22 16:19:34 +01:00
|
|
|
import de.bluecolored.bluemap.common.web.*;
|
2023-02-24 13:55:21 +01:00
|
|
|
import de.bluecolored.bluemap.common.web.http.HttpServer;
|
2021-06-16 20:09:45 +02:00
|
|
|
import de.bluecolored.bluemap.core.debug.StateDumper;
|
2020-01-13 17:13:20 +01:00
|
|
|
import de.bluecolored.bluemap.core.logger.Logger;
|
2021-04-24 22:11:26 +02:00
|
|
|
import de.bluecolored.bluemap.core.map.BmMap;
|
2020-01-13 17:13:20 +01:00
|
|
|
import de.bluecolored.bluemap.core.metrics.Metrics;
|
2023-01-03 16:03:07 +01:00
|
|
|
import de.bluecolored.bluemap.core.resources.resourcepack.ResourcePack;
|
2022-08-03 12:54:03 +02:00
|
|
|
import de.bluecolored.bluemap.core.storage.Storage;
|
2022-10-14 10:24:19 +02:00
|
|
|
import de.bluecolored.bluemap.core.util.FileHelper;
|
2020-01-13 17:13:20 +01:00
|
|
|
import de.bluecolored.bluemap.core.world.World;
|
2023-01-03 16:03:07 +01:00
|
|
|
import org.jetbrains.annotations.Nullable;
|
2021-05-17 00:24:27 +02:00
|
|
|
import org.spongepowered.configurate.gson.GsonConfigurationLoader;
|
|
|
|
import org.spongepowered.configurate.serialize.SerializationException;
|
2020-01-13 17:13:20 +01:00
|
|
|
|
2021-04-24 22:11:26 +02:00
|
|
|
import java.io.IOException;
|
2022-07-30 15:31:42 +02:00
|
|
|
import java.io.OutputStream;
|
|
|
|
import java.io.OutputStreamWriter;
|
|
|
|
import java.io.Writer;
|
2023-02-22 16:19:34 +01:00
|
|
|
import java.net.InetSocketAddress;
|
2022-04-20 22:54:27 +02:00
|
|
|
import java.net.UnknownHostException;
|
|
|
|
import java.nio.file.Path;
|
2021-04-02 12:20:48 +02:00
|
|
|
import java.util.*;
|
2021-03-28 13:25:39 +02:00
|
|
|
import java.util.concurrent.TimeUnit;
|
2022-07-04 13:07:56 +02:00
|
|
|
import java.util.function.Predicate;
|
2022-06-27 01:13:48 +02:00
|
|
|
import java.util.regex.Pattern;
|
2021-03-28 13:25:39 +02:00
|
|
|
|
2021-06-16 20:09:45 +02:00
|
|
|
@DebugDump
|
2021-09-18 14:04:03 +02:00
|
|
|
public class Plugin implements ServerEventListener {
|
2020-01-13 17:13:20 +01:00
|
|
|
|
2021-09-19 22:15:50 +02:00
|
|
|
public static final String PLUGIN_ID = "bluemap";
|
|
|
|
public static final String PLUGIN_NAME = "BlueMap";
|
|
|
|
|
|
|
|
private final InterruptableReentrantLock loadingLock = new InterruptableReentrantLock();
|
|
|
|
|
|
|
|
private final String implementationType;
|
|
|
|
private final ServerInterface serverInterface;
|
|
|
|
|
|
|
|
private BlueMapService blueMap;
|
|
|
|
|
|
|
|
private PluginState pluginState;
|
|
|
|
|
2022-04-20 22:54:27 +02:00
|
|
|
private Map<String, World> worlds;
|
2021-09-19 22:15:50 +02:00
|
|
|
private Map<String, BmMap> maps;
|
|
|
|
|
|
|
|
private RenderManager renderManager;
|
2023-02-24 13:55:21 +01:00
|
|
|
private HttpServer webServer;
|
2021-09-19 22:15:50 +02:00
|
|
|
|
2022-07-24 12:10:00 +02:00
|
|
|
private BlueMapAPIImpl api;
|
|
|
|
|
2021-09-19 22:15:50 +02:00
|
|
|
private Timer daemonTimer;
|
|
|
|
|
|
|
|
private Map<String, RegionFileWatchService> regionFileWatchServices;
|
|
|
|
|
|
|
|
private PlayerSkinUpdater skinUpdater;
|
|
|
|
|
|
|
|
private boolean loaded = false;
|
|
|
|
|
2022-04-20 22:54:27 +02:00
|
|
|
public Plugin(String implementationType, ServerInterface serverInterface) {
|
2021-09-19 22:15:50 +02:00
|
|
|
this.implementationType = implementationType.toLowerCase();
|
|
|
|
this.serverInterface = serverInterface;
|
|
|
|
|
|
|
|
StateDumper.global().register(this);
|
|
|
|
}
|
|
|
|
|
2022-05-28 21:55:41 +02:00
|
|
|
public void load() throws IOException {
|
2023-01-03 16:03:07 +01:00
|
|
|
load(null);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void load(@Nullable ResourcePack preloadedResourcePack) throws IOException {
|
|
|
|
loadingLock.lock();
|
2021-09-19 22:15:50 +02:00
|
|
|
try {
|
|
|
|
synchronized (this) {
|
|
|
|
|
|
|
|
if (loaded) return;
|
|
|
|
unload(); //ensure nothing is left running (from a failed load or something)
|
|
|
|
|
|
|
|
//load configs
|
2023-01-03 16:03:07 +01:00
|
|
|
blueMap = new BlueMapService(serverInterface, new BlueMapConfigs(serverInterface), preloadedResourcePack);
|
2022-04-20 22:54:27 +02:00
|
|
|
CoreConfig coreConfig = getConfigs().getCoreConfig();
|
|
|
|
WebserverConfig webserverConfig = getConfigs().getWebserverConfig();
|
|
|
|
WebappConfig webappConfig = getConfigs().getWebappConfig();
|
|
|
|
PluginConfig pluginConfig = getConfigs().getPluginConfig();
|
2021-09-19 22:15:50 +02:00
|
|
|
|
|
|
|
//load plugin state
|
|
|
|
try {
|
|
|
|
GsonConfigurationLoader loader = GsonConfigurationLoader.builder()
|
2022-04-20 22:54:27 +02:00
|
|
|
.path(coreConfig.getData().resolve("pluginState.json"))
|
2021-09-19 22:15:50 +02:00
|
|
|
.build();
|
|
|
|
pluginState = loader.load().get(PluginState.class);
|
|
|
|
} catch (SerializationException ex) {
|
|
|
|
Logger.global.logWarning("Failed to load pluginState.json (invalid format), creating a new one...");
|
|
|
|
pluginState = new PluginState();
|
|
|
|
}
|
|
|
|
|
|
|
|
//try load resources
|
|
|
|
try {
|
|
|
|
blueMap.getResourcePack();
|
|
|
|
} catch (MissingResourcesException ex) {
|
|
|
|
Logger.global.logWarning("BlueMap is missing important resources!");
|
|
|
|
Logger.global.logWarning("You must accept the required file download in order for BlueMap to work!");
|
2022-06-06 22:51:26 +02:00
|
|
|
|
|
|
|
BlueMapConfigProvider configProvider = blueMap.getConfigs();
|
|
|
|
if (configProvider instanceof BlueMapConfigs) {
|
|
|
|
Logger.global.logWarning("Please check: " + ((BlueMapConfigs) configProvider).getConfigManager().findConfigPath(Path.of("core")).toAbsolutePath().normalize());
|
|
|
|
}
|
|
|
|
|
2021-09-19 22:15:50 +02:00
|
|
|
Logger.global.logInfo("If you have changed the config you can simply reload the plugin using: /bluemap reload");
|
|
|
|
|
|
|
|
unload();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
//load worlds and maps
|
|
|
|
worlds = blueMap.getWorlds();
|
|
|
|
maps = blueMap.getMaps();
|
|
|
|
|
2021-11-14 14:18:31 +01:00
|
|
|
//create and start webserver
|
2022-04-20 22:54:27 +02:00
|
|
|
if (webserverConfig.isEnabled()) {
|
|
|
|
Path webroot = webserverConfig.getWebroot();
|
2022-10-14 10:24:19 +02:00
|
|
|
FileHelper.createDirectories(webroot);
|
2021-11-14 14:18:31 +01:00
|
|
|
|
2022-06-27 01:13:48 +02:00
|
|
|
RoutingRequestHandler routingRequestHandler = new RoutingRequestHandler();
|
|
|
|
|
|
|
|
// default route
|
|
|
|
routingRequestHandler.register(".*", new FileRequestHandler(webroot));
|
2021-11-14 14:18:31 +01:00
|
|
|
|
2022-06-27 01:13:48 +02:00
|
|
|
// map route
|
2022-08-03 12:54:03 +02:00
|
|
|
for (var mapConfigEntry : getConfigs().getMapConfigs().entrySet()) {
|
|
|
|
String id = mapConfigEntry.getKey();
|
|
|
|
MapConfig mapConfig = mapConfigEntry.getValue();
|
|
|
|
|
|
|
|
MapRequestHandler mapRequestHandler;
|
|
|
|
BmMap map = maps.get(id);
|
|
|
|
if (map != null) {
|
|
|
|
mapRequestHandler = new MapRequestHandler(map, serverInterface, pluginConfig, Predicate.not(pluginState::isPlayerHidden));
|
|
|
|
} else {
|
|
|
|
Storage storage = blueMap.getStorage(mapConfig.getStorage());
|
|
|
|
mapRequestHandler = new MapRequestHandler(id, storage);
|
|
|
|
}
|
|
|
|
|
2022-06-27 01:13:48 +02:00
|
|
|
routingRequestHandler.register(
|
2022-08-03 12:54:03 +02:00
|
|
|
"maps/" + Pattern.quote(id) + "/(.*)",
|
2022-06-27 01:13:48 +02:00
|
|
|
"$1",
|
2023-02-22 16:19:34 +01:00
|
|
|
new BlueMapResponseModifier(mapRequestHandler)
|
2022-06-27 01:13:48 +02:00
|
|
|
);
|
2021-11-14 14:18:31 +01:00
|
|
|
}
|
|
|
|
|
2022-04-20 22:54:27 +02:00
|
|
|
try {
|
2023-02-24 13:55:21 +01:00
|
|
|
webServer = new HttpServer(routingRequestHandler);
|
2023-02-22 16:19:34 +01:00
|
|
|
webServer.bind(new InetSocketAddress(
|
2022-04-20 22:54:27 +02:00
|
|
|
webserverConfig.resolveIp(),
|
2023-02-22 16:19:34 +01:00
|
|
|
webserverConfig.getPort()
|
|
|
|
));
|
2023-02-23 10:54:17 +01:00
|
|
|
webServer.start();
|
2022-04-20 22:54:27 +02:00
|
|
|
} catch (UnknownHostException ex) {
|
|
|
|
throw new ConfigurationException("BlueMap failed to resolve the ip in your webserver-config.\n" +
|
|
|
|
"Check if that is correctly configured.", ex);
|
2023-02-22 16:19:34 +01:00
|
|
|
} catch (IOException ex) {
|
|
|
|
throw new ConfigurationException("BlueMap failed to initialize the webserver.\n" +
|
|
|
|
"Check your webserver-config if everything is configured correctly.\n" +
|
|
|
|
"(Make sure you DON'T use the same port for bluemap that you also use for your minecraft server)", ex);
|
2022-04-20 22:54:27 +02:00
|
|
|
}
|
2021-11-14 14:18:31 +01:00
|
|
|
}
|
|
|
|
|
2023-02-25 12:28:07 +01:00
|
|
|
//warn if no maps are configured
|
|
|
|
if (maps.isEmpty()) {
|
|
|
|
Logger.global.logWarning("There are no valid maps configured, please check your map-configs! Disabling BlueMap...");
|
|
|
|
unload(true);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-09-19 22:15:50 +02:00
|
|
|
//initialize render manager
|
|
|
|
renderManager = new RenderManager();
|
|
|
|
|
|
|
|
//update all maps
|
2022-07-31 18:45:30 +02:00
|
|
|
maps.values().stream()
|
|
|
|
.sorted(Comparator.comparing(bmMap -> bmMap.getMapSettings().getSorting()))
|
|
|
|
.forEach(map -> {
|
2021-09-19 22:15:50 +02:00
|
|
|
if (pluginState.getMapState(map).isUpdateEnabled()) {
|
|
|
|
renderManager.scheduleRenderTask(new MapUpdateTask(map));
|
|
|
|
}
|
2022-07-31 18:45:30 +02:00
|
|
|
});
|
2021-09-19 22:15:50 +02:00
|
|
|
|
|
|
|
//start render-manager
|
|
|
|
if (pluginState.isRenderThreadsEnabled()) {
|
|
|
|
checkPausedByPlayerCount(); // <- this also starts the render-manager if it should start
|
|
|
|
} else {
|
|
|
|
Logger.global.logInfo("Render-Threads are STOPPED! Use the command 'bluemap start' to start them.");
|
|
|
|
}
|
|
|
|
|
|
|
|
//update webapp and settings
|
2022-12-13 16:54:31 +01:00
|
|
|
if (webappConfig.isEnabled())
|
|
|
|
blueMap.createOrUpdateWebApp(false);
|
2021-09-19 22:15:50 +02:00
|
|
|
|
|
|
|
//start skin updater
|
2022-04-20 22:54:27 +02:00
|
|
|
if (pluginConfig.isLivePlayerMarkers()) {
|
2022-12-13 16:54:31 +01:00
|
|
|
this.skinUpdater = new PlayerSkinUpdater(this);
|
2021-09-19 22:15:50 +02:00
|
|
|
serverInterface.registerListener(skinUpdater);
|
|
|
|
}
|
|
|
|
|
|
|
|
//init timer
|
2022-12-13 16:54:31 +01:00
|
|
|
daemonTimer = new Timer("BlueMap-Plugin-DaemonTimer", true);
|
2021-09-19 22:15:50 +02:00
|
|
|
|
|
|
|
//periodically save
|
|
|
|
TimerTask saveTask = new TimerTask() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
save();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
daemonTimer.schedule(saveTask, TimeUnit.MINUTES.toMillis(2), TimeUnit.MINUTES.toMillis(2));
|
|
|
|
|
2022-07-30 15:31:42 +02:00
|
|
|
//periodically save markers
|
|
|
|
int writeMarkersInterval = pluginConfig.getWriteMarkersInterval();
|
|
|
|
if (writeMarkersInterval > 0) {
|
|
|
|
TimerTask saveMarkersTask = new TimerTask() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
saveMarkerStates();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
daemonTimer.schedule(saveMarkersTask, TimeUnit.SECONDS.toMillis(writeMarkersInterval), TimeUnit.SECONDS.toMillis(writeMarkersInterval));
|
|
|
|
}
|
|
|
|
|
|
|
|
//periodically save players
|
|
|
|
int writePlayersInterval = pluginConfig.getWritePlayersInterval();
|
|
|
|
if (writePlayersInterval > 0) {
|
|
|
|
TimerTask savePlayersTask = new TimerTask() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
savePlayerStates();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
daemonTimer.schedule(savePlayersTask, TimeUnit.SECONDS.toMillis(writePlayersInterval), TimeUnit.SECONDS.toMillis(writePlayersInterval));
|
|
|
|
}
|
|
|
|
|
2021-09-19 22:15:50 +02:00
|
|
|
//periodically restart the file-watchers
|
|
|
|
TimerTask fileWatcherRestartTask = new TimerTask() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
regionFileWatchServices.values().forEach(RegionFileWatchService::close);
|
|
|
|
regionFileWatchServices.clear();
|
|
|
|
initFileWatcherTasks();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
daemonTimer.schedule(fileWatcherRestartTask, TimeUnit.HOURS.toMillis(1), TimeUnit.HOURS.toMillis(1));
|
|
|
|
|
|
|
|
//periodically update all (non frozen) maps
|
2022-04-20 22:54:27 +02:00
|
|
|
if (pluginConfig.getFullUpdateInterval() > 0) {
|
|
|
|
long fullUpdateTime = TimeUnit.MINUTES.toMillis(pluginConfig.getFullUpdateInterval());
|
2021-09-19 22:15:50 +02:00
|
|
|
TimerTask updateAllMapsTask = new TimerTask() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
for (BmMap map : maps.values()) {
|
|
|
|
if (pluginState.getMapState(map).isUpdateEnabled()) {
|
|
|
|
renderManager.scheduleRenderTask(new MapUpdateTask(map));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
daemonTimer.scheduleAtFixedRate(updateAllMapsTask, fullUpdateTime, fullUpdateTime);
|
|
|
|
}
|
|
|
|
|
|
|
|
//metrics
|
|
|
|
TimerTask metricsTask = new TimerTask() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
2022-04-20 22:54:27 +02:00
|
|
|
if (Plugin.this.serverInterface.isMetricsEnabled().getOr(coreConfig::isMetrics))
|
2021-09-19 22:15:50 +02:00
|
|
|
Metrics.sendReport(Plugin.this.implementationType);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
daemonTimer.scheduleAtFixedRate(metricsTask, TimeUnit.MINUTES.toMillis(1), TimeUnit.MINUTES.toMillis(30));
|
|
|
|
|
|
|
|
//watch map-changes
|
|
|
|
this.regionFileWatchServices = new HashMap<>();
|
|
|
|
initFileWatcherTasks();
|
|
|
|
|
|
|
|
//register listener
|
|
|
|
serverInterface.registerListener(this);
|
|
|
|
|
2022-07-24 12:10:00 +02:00
|
|
|
//enable api
|
|
|
|
this.api = new BlueMapAPIImpl(this);
|
|
|
|
this.api.register();
|
2021-09-19 22:15:50 +02:00
|
|
|
|
2022-12-13 16:54:31 +01:00
|
|
|
//save webapp settings again (for api-registered scripts and styles)
|
2023-01-15 11:43:22 +01:00
|
|
|
if (webappConfig.isEnabled())
|
|
|
|
this.getBlueMap().getWebFilesManager().saveSettings();
|
2022-12-13 16:54:31 +01:00
|
|
|
|
2021-09-19 22:15:50 +02:00
|
|
|
//done
|
|
|
|
loaded = true;
|
|
|
|
}
|
2021-11-14 14:18:31 +01:00
|
|
|
} catch (ConfigurationException ex) {
|
|
|
|
Logger.global.logWarning(ex.getFormattedExplanation());
|
|
|
|
throw new IOException(ex);
|
2021-09-19 22:15:50 +02:00
|
|
|
} catch (InterruptedException e) {
|
|
|
|
Thread.currentThread().interrupt();
|
|
|
|
Logger.global.logWarning("Loading has been interrupted!");
|
|
|
|
} finally {
|
|
|
|
loadingLock.unlock();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void unload() {
|
2023-02-25 12:28:07 +01:00
|
|
|
this.unload(false);
|
|
|
|
}
|
|
|
|
public void unload(boolean keepWebserver) {
|
2023-01-03 16:03:07 +01:00
|
|
|
loadingLock.interruptAndLock();
|
2021-09-19 22:15:50 +02:00
|
|
|
try {
|
|
|
|
synchronized (this) {
|
|
|
|
//save
|
|
|
|
save();
|
|
|
|
|
2022-07-24 12:10:00 +02:00
|
|
|
//disable api
|
|
|
|
if (api != null) api.unregister();
|
|
|
|
api = null;
|
2021-09-19 22:15:50 +02:00
|
|
|
|
|
|
|
//unregister listeners
|
|
|
|
serverInterface.unregisterAllListeners();
|
|
|
|
skinUpdater = null;
|
|
|
|
|
|
|
|
//stop scheduled threads
|
|
|
|
if (daemonTimer != null) daemonTimer.cancel();
|
|
|
|
daemonTimer = null;
|
|
|
|
|
|
|
|
//stop file-watchers
|
|
|
|
if (regionFileWatchServices != null) {
|
|
|
|
regionFileWatchServices.values().forEach(RegionFileWatchService::close);
|
|
|
|
regionFileWatchServices.clear();
|
|
|
|
}
|
|
|
|
regionFileWatchServices = null;
|
|
|
|
|
|
|
|
//stop services
|
2021-11-14 14:18:31 +01:00
|
|
|
if (renderManager != null){
|
|
|
|
renderManager.stop();
|
|
|
|
try {
|
|
|
|
renderManager.awaitShutdown();
|
|
|
|
} catch (InterruptedException ex) {
|
|
|
|
Thread.currentThread().interrupt();
|
|
|
|
}
|
|
|
|
}
|
2021-09-19 22:15:50 +02:00
|
|
|
renderManager = null;
|
|
|
|
|
2023-02-25 12:28:07 +01:00
|
|
|
if (webServer != null && !keepWebserver) {
|
2023-02-22 16:19:34 +01:00
|
|
|
try {
|
|
|
|
webServer.close();
|
|
|
|
} catch (IOException ex) {
|
|
|
|
Logger.global.logError("Failed to close the webserver!", ex);
|
|
|
|
}
|
2023-02-25 12:28:07 +01:00
|
|
|
webServer = null;
|
2023-02-22 16:19:34 +01:00
|
|
|
}
|
2021-09-19 22:15:50 +02:00
|
|
|
|
2022-08-27 15:08:17 +02:00
|
|
|
//close bluemap
|
|
|
|
if (blueMap != null) {
|
|
|
|
try {
|
|
|
|
blueMap.close();
|
|
|
|
} catch (IOException ex) {
|
|
|
|
Logger.global.logError("Failed to close a bluemap-service!", ex);
|
|
|
|
}
|
2021-11-14 14:18:31 +01:00
|
|
|
}
|
2021-09-19 22:15:50 +02:00
|
|
|
blueMap = null;
|
2022-08-27 15:08:17 +02:00
|
|
|
|
|
|
|
//clear resources
|
2021-09-19 22:15:50 +02:00
|
|
|
worlds = null;
|
|
|
|
maps = null;
|
|
|
|
|
|
|
|
pluginState = null;
|
|
|
|
|
|
|
|
//done
|
|
|
|
loaded = false;
|
|
|
|
}
|
|
|
|
} finally {
|
|
|
|
loadingLock.unlock();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-28 21:55:41 +02:00
|
|
|
public void reload() throws IOException {
|
2021-09-19 22:15:50 +02:00
|
|
|
unload();
|
|
|
|
load();
|
|
|
|
}
|
|
|
|
|
2023-01-03 16:03:07 +01:00
|
|
|
/**
|
|
|
|
* {@link #reload()} but without reloading the resourcepack (if it is loaded).
|
|
|
|
*/
|
|
|
|
public void lightReload() throws IOException {
|
|
|
|
loadingLock.lock();
|
|
|
|
try {
|
|
|
|
synchronized (this) {
|
|
|
|
|
|
|
|
if (!loaded) {
|
|
|
|
reload(); // reload normally
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// hold and reuse loaded resourcepack
|
|
|
|
ResourcePack preloadedResourcePack = this.blueMap.getResourcePackIfLoaded().orElse(null);
|
|
|
|
|
|
|
|
unload();
|
|
|
|
load(preloadedResourcePack);
|
|
|
|
|
|
|
|
}
|
|
|
|
} finally {
|
|
|
|
loadingLock.unlock();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-19 22:15:50 +02:00
|
|
|
public synchronized void save() {
|
|
|
|
if (pluginState != null) {
|
|
|
|
try {
|
|
|
|
GsonConfigurationLoader loader = GsonConfigurationLoader.builder()
|
2022-04-20 22:54:27 +02:00
|
|
|
.path(blueMap.getConfigs().getCoreConfig().getData().resolve("pluginState.json"))
|
2021-09-19 22:15:50 +02:00
|
|
|
.build();
|
|
|
|
loader.save(loader.createNode().set(PluginState.class, pluginState));
|
|
|
|
} catch (IOException ex) {
|
|
|
|
Logger.global.logError("Failed to save pluginState.json!", ex);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (maps != null) {
|
|
|
|
for (BmMap map : maps.values()) {
|
|
|
|
map.save();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-30 15:31:42 +02:00
|
|
|
public void saveMarkerStates() {
|
|
|
|
if (maps != null) {
|
|
|
|
for (BmMap map : maps.values()) {
|
|
|
|
map.saveMarkerState();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void savePlayerStates() {
|
|
|
|
if (maps != null) {
|
|
|
|
for (BmMap map : maps.values()) {
|
|
|
|
var dataSupplier = new LivePlayersDataSupplier(
|
|
|
|
serverInterface,
|
|
|
|
getConfigs().getPluginConfig(),
|
|
|
|
map.getWorldId(),
|
|
|
|
Predicate.not(pluginState::isPlayerHidden)
|
|
|
|
);
|
|
|
|
try (
|
2022-12-13 16:54:31 +01:00
|
|
|
OutputStream out = map.getStorage().writeMeta(map.getId(), BmMap.META_FILE_PLAYERS);
|
2022-07-30 15:31:42 +02:00
|
|
|
Writer writer = new OutputStreamWriter(out)
|
|
|
|
) {
|
|
|
|
writer.write(dataSupplier.get());
|
|
|
|
} catch (Exception ex) {
|
|
|
|
Logger.global.logError("Failed to save players for map '" + map.getId() + "'!", ex);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-19 22:15:50 +02:00
|
|
|
public synchronized void startWatchingMap(BmMap map) {
|
|
|
|
stopWatchingMap(map);
|
|
|
|
|
|
|
|
try {
|
|
|
|
RegionFileWatchService watcher = new RegionFileWatchService(renderManager, map, false);
|
|
|
|
watcher.start();
|
|
|
|
regionFileWatchServices.put(map.getId(), watcher);
|
|
|
|
} catch (IOException ex) {
|
|
|
|
Logger.global.logError("Failed to create file-watcher for map: " + map.getId() + " (This means the map might not automatically update)", ex);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public synchronized void stopWatchingMap(BmMap map) {
|
|
|
|
RegionFileWatchService watcher = regionFileWatchServices.remove(map.getId());
|
|
|
|
if (watcher != null) {
|
|
|
|
watcher.close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-20 22:54:27 +02:00
|
|
|
public boolean flushWorldUpdates(World world) throws IOException {
|
|
|
|
var implWorld = serverInterface.getWorld(world.getSaveFolder()).orElse(null);
|
|
|
|
if (implWorld != null) return implWorld.persistWorldChanges();
|
|
|
|
return false;
|
2021-09-19 22:15:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onPlayerJoin(UUID playerUuid) {
|
2022-08-21 00:26:34 +02:00
|
|
|
checkPausedByPlayerCountSoon();
|
2021-09-19 22:15:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onPlayerLeave(UUID playerUuid) {
|
2022-08-21 00:26:34 +02:00
|
|
|
checkPausedByPlayerCountSoon();
|
|
|
|
}
|
|
|
|
|
|
|
|
private void checkPausedByPlayerCountSoon() {
|
|
|
|
// check is done a second later to make sure the player has actually joined/left and is no longer on the list
|
2022-09-08 12:29:11 +02:00
|
|
|
try {
|
|
|
|
daemonTimer.schedule(new TimerTask() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
checkPausedByPlayerCount();
|
|
|
|
}
|
|
|
|
}, 1000);
|
|
|
|
} catch (IllegalStateException ex) { // Timer is cancelled for some reason
|
|
|
|
Logger.global.logWarning("Timer is already cancelled, skipping player-limit checks!");
|
|
|
|
}
|
2021-09-19 22:15:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public boolean checkPausedByPlayerCount() {
|
2022-04-20 22:54:27 +02:00
|
|
|
CoreConfig coreConfig = getConfigs().getCoreConfig();
|
|
|
|
PluginConfig pluginConfig = getConfigs().getPluginConfig();
|
|
|
|
|
2021-09-19 22:15:50 +02:00
|
|
|
if (
|
2022-04-20 22:54:27 +02:00
|
|
|
pluginConfig.getPlayerRenderLimit() > 0 &&
|
|
|
|
getServerInterface().getOnlinePlayers().size() >= pluginConfig.getPlayerRenderLimit()
|
2021-09-19 22:15:50 +02:00
|
|
|
) {
|
|
|
|
if (renderManager.isRunning()) renderManager.stop();
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
if (!renderManager.isRunning() && getPluginState().isRenderThreadsEnabled())
|
2022-04-24 15:56:03 +02:00
|
|
|
renderManager.start(coreConfig.resolveRenderThreadCount());
|
2021-09-19 22:15:50 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public ServerInterface getServerInterface() {
|
|
|
|
return serverInterface;
|
|
|
|
}
|
|
|
|
|
2022-04-20 22:54:27 +02:00
|
|
|
public BlueMapService getBlueMap() {
|
|
|
|
return blueMap;
|
2021-09-19 22:15:50 +02:00
|
|
|
}
|
|
|
|
|
2022-06-06 22:51:26 +02:00
|
|
|
public BlueMapConfigProvider getConfigs() {
|
2022-04-20 22:54:27 +02:00
|
|
|
return blueMap.getConfigs();
|
2021-09-19 22:15:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public PluginState getPluginState() {
|
|
|
|
return pluginState;
|
|
|
|
}
|
|
|
|
|
2022-04-20 22:54:27 +02:00
|
|
|
public Map<String, World> getWorlds(){
|
|
|
|
return worlds;
|
2021-09-19 22:15:50 +02:00
|
|
|
}
|
|
|
|
|
2022-04-20 22:54:27 +02:00
|
|
|
public Map<String, BmMap> getMaps(){
|
|
|
|
return maps;
|
2021-09-19 22:15:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public RenderManager getRenderManager() {
|
|
|
|
return renderManager;
|
|
|
|
}
|
|
|
|
|
2023-02-24 13:55:21 +01:00
|
|
|
public HttpServer getWebServer() {
|
2021-09-19 22:15:50 +02:00
|
|
|
return webServer;
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean isLoaded() {
|
|
|
|
return loaded;
|
|
|
|
}
|
|
|
|
|
|
|
|
public String getImplementationType() {
|
|
|
|
return implementationType;
|
|
|
|
}
|
|
|
|
|
2022-12-13 16:54:31 +01:00
|
|
|
public PlayerSkinUpdater getSkinUpdater() {
|
|
|
|
return skinUpdater;
|
|
|
|
}
|
|
|
|
|
2021-09-19 22:15:50 +02:00
|
|
|
private void initFileWatcherTasks() {
|
|
|
|
for (BmMap map : maps.values()) {
|
|
|
|
if (pluginState.getMapState(map).isUpdateEnabled()) {
|
|
|
|
startWatchingMap(map);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-06-09 00:34:12 +02:00
|
|
|
|
2020-01-13 17:13:20 +01:00
|
|
|
}
|