From 35d7827611e430a1dc3af9b9fa9aa79ded466c59 Mon Sep 17 00:00:00 2001 From: "Blue (Lukas Rieger)" Date: Mon, 13 Jan 2020 17:13:20 +0100 Subject: [PATCH] Start implemention a common plugin solution --- BlueMapBukkit/build.gradle | 2 +- BlueMapPlugin/build.gradle | 3 + .../bluecolored/bluemap/plugin}/MapType.java | 2 +- .../bluemap/plugin/MapUpdateHandler.java | 102 ++++++ .../de/bluecolored/bluemap/plugin/Plugin.java | 295 ++++++++++++++++++ .../bluemap/plugin}/RenderManager.java | 8 +- .../bluemap/plugin}/RenderTask.java | 6 +- .../bluemap/plugin}/RenderTicket.java | 2 +- .../plugin/serverinterface/CommandSource.java | 106 +++++++ .../serverinterface/ServerEventListener.java | 16 + .../serverinterface/ServerInterface.java | 24 ++ .../plugin/serverinterface/TextColor.java | 47 +++ BlueMapSponge/build.gradle | 2 +- .../bluecolored/bluemap/sponge/Commands.java | 3 + .../bluemap/sponge/MapUpdateHandler.java | 3 + .../bluemap/sponge/SpongePlugin.java | 19 +- settings.gradle | 2 + 17 files changed, 620 insertions(+), 22 deletions(-) create mode 100644 BlueMapPlugin/build.gradle rename {BlueMapSponge/src/main/java/de/bluecolored/bluemap/sponge => BlueMapPlugin/src/main/java/de/bluecolored/bluemap/plugin}/MapType.java (98%) create mode 100644 BlueMapPlugin/src/main/java/de/bluecolored/bluemap/plugin/MapUpdateHandler.java create mode 100644 BlueMapPlugin/src/main/java/de/bluecolored/bluemap/plugin/Plugin.java rename {BlueMapSponge/src/main/java/de/bluecolored/bluemap/sponge => BlueMapPlugin/src/main/java/de/bluecolored/bluemap/plugin}/RenderManager.java (96%) rename {BlueMapSponge/src/main/java/de/bluecolored/bluemap/sponge => BlueMapPlugin/src/main/java/de/bluecolored/bluemap/plugin}/RenderTask.java (96%) rename {BlueMapSponge/src/main/java/de/bluecolored/bluemap/sponge => BlueMapPlugin/src/main/java/de/bluecolored/bluemap/plugin}/RenderTicket.java (96%) create mode 100644 BlueMapPlugin/src/main/java/de/bluecolored/bluemap/plugin/serverinterface/CommandSource.java create mode 100644 BlueMapPlugin/src/main/java/de/bluecolored/bluemap/plugin/serverinterface/ServerEventListener.java create mode 100644 BlueMapPlugin/src/main/java/de/bluecolored/bluemap/plugin/serverinterface/ServerInterface.java create mode 100644 BlueMapPlugin/src/main/java/de/bluecolored/bluemap/plugin/serverinterface/TextColor.java diff --git a/BlueMapBukkit/build.gradle b/BlueMapBukkit/build.gradle index 1dff7203..ae8fa2fd 100644 --- a/BlueMapBukkit/build.gradle +++ b/BlueMapBukkit/build.gradle @@ -13,5 +13,5 @@ repositories { dependencies { shadow "org.bukkit:bukkit:1.14.4-R0.1-SNAPSHOT" //compile group: 'org.bstats', name: 'bstats-sponge-lite', version: '1.5' - compile project(':BlueMapCore') + compile project(':BlueMapPlugin') } diff --git a/BlueMapPlugin/build.gradle b/BlueMapPlugin/build.gradle new file mode 100644 index 00000000..d8406125 --- /dev/null +++ b/BlueMapPlugin/build.gradle @@ -0,0 +1,3 @@ +dependencies { + compile project(':BlueMapCore') +} diff --git a/BlueMapSponge/src/main/java/de/bluecolored/bluemap/sponge/MapType.java b/BlueMapPlugin/src/main/java/de/bluecolored/bluemap/plugin/MapType.java similarity index 98% rename from BlueMapSponge/src/main/java/de/bluecolored/bluemap/sponge/MapType.java rename to BlueMapPlugin/src/main/java/de/bluecolored/bluemap/plugin/MapType.java index 5789e42d..68dd4f89 100644 --- a/BlueMapSponge/src/main/java/de/bluecolored/bluemap/sponge/MapType.java +++ b/BlueMapPlugin/src/main/java/de/bluecolored/bluemap/plugin/MapType.java @@ -22,7 +22,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package de.bluecolored.bluemap.sponge; +package de.bluecolored.bluemap.plugin; import java.io.IOException; diff --git a/BlueMapPlugin/src/main/java/de/bluecolored/bluemap/plugin/MapUpdateHandler.java b/BlueMapPlugin/src/main/java/de/bluecolored/bluemap/plugin/MapUpdateHandler.java new file mode 100644 index 00000000..6d16977a --- /dev/null +++ b/BlueMapPlugin/src/main/java/de/bluecolored/bluemap/plugin/MapUpdateHandler.java @@ -0,0 +1,102 @@ +package de.bluecolored.bluemap.plugin; + +import java.util.Iterator; +import java.util.UUID; + +import com.flowpowered.math.vector.Vector2i; +import com.flowpowered.math.vector.Vector3i; +import com.google.common.collect.Multimap; +import com.google.common.collect.MultimapBuilder; + +import de.bluecolored.bluemap.plugin.serverinterface.ServerEventListener; + +public class MapUpdateHandler implements ServerEventListener { + + public Multimap updateBuffer; + + public MapUpdateHandler() { + updateBuffer = MultimapBuilder.hashKeys().hashSetValues().build(); + } + + @Override + public void onWorldSaveToDisk(UUID world) { + RenderManager renderManager = Plugin.getInstance().getRenderManager(); + + synchronized (updateBuffer) { + Iterator iterator = updateBuffer.keys().iterator(); + while (iterator.hasNext()) { + MapType map = iterator.next(); + if (map.getWorld().getUUID().equals(world)) { + renderManager.createTickets(map, updateBuffer.get(map)); + iterator.remove(); + } + } + + } + } + + @Override + public void onBlockChange(UUID world, Vector3i blockPos) { + synchronized (updateBuffer) { + updateBlock(world, blockPos); + } + } + + @Override + public void onChunkFinishedGeneration(UUID world, Vector2i chunkPos) { + int x = chunkPos.getX(); + int z = chunkPos.getY(); + + // also update the chunks around, because they might be modified or not rendered yet due to finalizations + for (int dx = -1; dx <= 1; dx++) { + for (int dz = -1; dz <= 1; dz++) { + updateChunk(world, new Vector2i(x + dx, z + dz)); + } + } + } + + private void updateChunk(UUID world, Vector2i chunkPos) { + Vector3i min = new Vector3i(chunkPos.getX() * 16, 0, chunkPos.getY() * 16); + Vector3i max = min.add(15, 255, 15); + + Vector3i xmin = new Vector3i(min.getX(), 0, max.getY()); + Vector3i xmax = new Vector3i(max.getX(), 255, min.getY()); + + //update all corners so we always update all tiles containing this chunk + synchronized (updateBuffer) { + updateBlock(world, min); + updateBlock(world, max); + updateBlock(world, xmin); + updateBlock(world, xmax); + } + } + + private void updateBlock(UUID world, Vector3i pos){ + synchronized (updateBuffer) { + for (MapType mapType : Plugin.getInstance().getMapTypes()) { + if (mapType.getWorld().getUUID().equals(world)) { + mapType.getWorld().invalidateChunkCache(mapType.getWorld().blockPosToChunkPos(pos)); + + Vector2i tile = mapType.getTileRenderer().getHiresModelManager().posToTile(pos); + updateBuffer.put(mapType, tile); + } + } + } + } + + public int getUpdateBufferCount() { + return updateBuffer.size(); + } + + public void flushTileBuffer() { + RenderManager renderManager = Plugin.getInstance().getRenderManager(); + + synchronized (updateBuffer) { + for (MapType map : updateBuffer.keySet()) { + renderManager.createTickets(map, updateBuffer.get(map)); + } + updateBuffer.clear(); + } + } + +} diff --git a/BlueMapPlugin/src/main/java/de/bluecolored/bluemap/plugin/Plugin.java b/BlueMapPlugin/src/main/java/de/bluecolored/bluemap/plugin/Plugin.java new file mode 100644 index 00000000..118c7d9e --- /dev/null +++ b/BlueMapPlugin/src/main/java/de/bluecolored/bluemap/plugin/Plugin.java @@ -0,0 +1,295 @@ +package de.bluecolored.bluemap.plugin; + +import java.io.DataInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.TimeUnit; +import java.util.zip.GZIPInputStream; + +import org.apache.commons.io.FileUtils; +import org.spongepowered.api.Sponge; + +import com.flowpowered.math.vector.Vector2i; + +import de.bluecolored.bluemap.core.BlueMap; +import de.bluecolored.bluemap.core.config.ConfigManager; +import de.bluecolored.bluemap.core.config.MainConfig; +import de.bluecolored.bluemap.core.config.MainConfig.MapConfig; +import de.bluecolored.bluemap.core.logger.Logger; +import de.bluecolored.bluemap.core.mca.MCAWorld; +import de.bluecolored.bluemap.core.metrics.Metrics; +import de.bluecolored.bluemap.core.render.RenderSettings; +import de.bluecolored.bluemap.core.render.TileRenderer; +import de.bluecolored.bluemap.core.render.hires.HiresModelManager; +import de.bluecolored.bluemap.core.render.lowres.LowresModelManager; +import de.bluecolored.bluemap.core.resourcepack.ResourcePack; +import de.bluecolored.bluemap.core.web.BlueMapWebServer; +import de.bluecolored.bluemap.core.web.WebFilesManager; +import de.bluecolored.bluemap.core.web.WebSettings; +import de.bluecolored.bluemap.core.world.SlicedWorld; +import de.bluecolored.bluemap.core.world.World; +import de.bluecolored.bluemap.plugin.serverinterface.ServerInterface; +import de.bluecolored.bluemap.sponge.Commands; +import de.bluecolored.bluemap.sponge.MapUpdateHandler; +import de.bluecolored.bluemap.sponge.SpongePlugin; +import net.querz.nbt.CompoundTag; +import net.querz.nbt.NBTUtil; + +public class Plugin { + + public static final String PLUGIN_ID = "bluemap"; + public static final String PLUGIN_NAME = "BlueMap"; + public static final String PLUGIN_VERSION = BlueMap.VERSION; + + private static Plugin instance; + private ServerInterface serverInterface; + + private MainConfig config; + private ResourcePack resourcePack; + + private Map worlds; + private Map maps; + + private MapUpdateHandler updateHandler; + + private RenderManager renderManager; + private BlueMapWebServer webServer; + + private boolean loaded = false; + + public Plugin() { + instance = this; + } + + public synchronized void load() { + if (loaded) return; + unload(); //ensure nothing is left running (from a failed load or something) + + //register reload command in case bluemap crashes during loading + Sponge.getCommandManager().register(this, new Commands(this).createStandaloneReloadCommand(), "bluemap"); + + //load configs + URL defaultSpongeConfig = SpongePlugin.class.getResource("/bluemap-sponge.conf"); + URL spongeConfigDefaults = SpongePlugin.class.getResource("/bluemap-sponge-defaults.conf"); + ConfigManager configManager = new ConfigManager(getConfigPath().toFile(), defaultSpongeConfig, spongeConfigDefaults); + configManager.loadMainConfig(); + config = configManager.getMainConfig(); + + //load resources + File defaultResourceFile = config.getDataPath().resolve("minecraft-client-" + ResourcePack.MINECRAFT_CLIENT_VERSION + ".jar").toFile(); + File resourceExtensionsFile = config.getDataPath().resolve("resourceExtensions.zip").toFile(); + File textureExportFile = config.getWebDataPath().resolve("textures.json").toFile(); + + if (!defaultResourceFile.exists()) { + handleMissingResources(defaultResourceFile, configManager.getMainConfigFile()); + unload(); + + Sponge.getCommandManager().register(this, new Commands(this).createStandaloneReloadCommand(), "bluemap"); + return; + } + + resourceExtensionsFile.delete(); + FileUtils.copyURLToFile(SpongePlugin.class.getResource("/resourceExtensions.zip"), resourceExtensionsFile, 10000, 10000); + + //find more resource packs + File resourcePackFolder = getConfigPath().resolve("resourcepacks").toFile(); + resourcePackFolder.mkdirs(); + File[] resourcePacks = resourcePackFolder.listFiles(); + Arrays.sort(resourcePacks); //load resource packs in alphabetical order so you can reorder them by renaming + + List resources = new ArrayList<>(resourcePacks.length + 1); + resources.add(defaultResourceFile); + for (File file : resourcePacks) resources.add(file); + resources.add(resourceExtensionsFile); + + resourcePack = new ResourcePack(); + if (textureExportFile.exists()) resourcePack.loadTextureFile(textureExportFile); + resourcePack.load(resources); + resourcePack.saveTextureFile(textureExportFile); + + configManager.loadResourceConfigs(resourcePack); + + //load maps + for (MapConfig mapConfig : config.getMapConfigs()) { + String id = mapConfig.getId(); + String name = mapConfig.getName(); + + File worldFolder = new File(mapConfig.getWorldPath()); + if (!worldFolder.exists() || !worldFolder.isDirectory()) { + Logger.global.logError("Failed to load map '" + id + "': '" + worldFolder.getCanonicalPath() + "' does not exist or is no directory!", new IOException()); + continue; + } + + UUID worldUUID; + try { + CompoundTag levelSponge = (CompoundTag) NBTUtil.readTag(new File(worldFolder, "level_sponge.dat")); + CompoundTag spongeData = levelSponge.getCompoundTag("SpongeData"); + long most = spongeData.getLong("UUIDMost"); + long least = spongeData.getLong("UUIDLeast"); + worldUUID = new UUID(most, least); + } catch (Exception e) { + Logger.global.logError("Failed to load map '" + id + "': Failed to read level_sponge.dat", e); + continue; + } + + World world = worlds.get(worldUUID); + if (world == null) { + try { + world = MCAWorld.load(worldFolder.toPath(), worldUUID, configManager.getBlockIdConfig(), configManager.getBlockPropertiesConfig(), configManager.getBiomeConfig()); + worlds.put(worldUUID, world); + } catch (IOException e) { + Logger.global.logError("Failed to load map '" + id + "': Failed to read level.dat", e); + continue; + } + } + + //slice world to render edges if configured + if (mapConfig.isRenderEdges() && !(mapConfig.getMin().equals(RenderSettings.DEFAULT_MIN) && mapConfig.getMax().equals(RenderSettings.DEFAULT_MAX))) { + world = new SlicedWorld(world, mapConfig.getMin(), mapConfig.getMax()); + } + + HiresModelManager hiresModelManager = new HiresModelManager( + config.getWebDataPath().resolve(id).resolve("hires"), + resourcePack, + mapConfig, + new Vector2i(mapConfig.getHiresTileSize(), mapConfig.getHiresTileSize()), + getAsyncExecutor() + ); + + LowresModelManager lowresModelManager = new LowresModelManager( + config.getWebDataPath().resolve(id).resolve("lowres"), + new Vector2i(mapConfig.getLowresPointsPerLowresTile(), mapConfig.getLowresPointsPerLowresTile()), + new Vector2i(mapConfig.getLowresPointsPerHiresTile(), mapConfig.getLowresPointsPerHiresTile()) + ); + + TileRenderer tileRenderer = new TileRenderer(hiresModelManager, lowresModelManager); + + MapType mapType = new MapType(id, name, world, tileRenderer); + maps.put(id, mapType); + } + + //initialize render manager + renderManager = new RenderManager(config.getRenderThreadCount()); + renderManager.start(); + + //load render-manager state + try { + File saveFile = config.getDataPath().resolve("rmstate").toFile(); + saveFile.getParentFile().mkdirs(); + if (saveFile.exists()) { + try (DataInputStream in = new DataInputStream(new GZIPInputStream(new FileInputStream(saveFile)))) { + renderManager.readState(in, getMapTypes()); + } + } + saveFile.delete(); + } catch (IOException ex) { + Logger.global.logError("Failed to load render-manager state!", ex); + } + + //start map updater + this.updateHandler = new MapUpdateHandler(); + + //create/update webfiles + WebFilesManager webFilesManager = new WebFilesManager(config.getWebRoot()); + if (webFilesManager.needsUpdate()) { + webFilesManager.updateFiles(); + } + + WebSettings webSettings = new WebSettings(config.getWebDataPath().resolve("settings.json").toFile()); + webSettings.setAllEnabled(false); + for (MapType map : maps.values()) { + webSettings.setEnabled(true, map.getId()); + webSettings.setName(map.getName(), map.getId()); + webSettings.setFrom(map.getTileRenderer(), map.getId()); + } + int ordinal = 0; + for (MapConfig map : config.getMapConfigs()) { + if (!maps.containsKey(map.getId())) continue; //don't add not loaded maps + webSettings.setOrdinal(ordinal++, map.getId()); + webSettings.setHiresViewDistance(map.getHiresViewDistance(), map.getId()); + webSettings.setLowresViewDistance(map.getLowresViewDistance(), map.getId()); + } + webSettings.save(); + + //start webserver + if (config.isWebserverEnabled()) { + webServer = new BlueMapWebServer(config); + webServer.updateWebfiles(); + webServer.start(); + } + + //init commands + Sponge.getCommandManager().getOwnedBy(this).forEach(Sponge.getCommandManager()::removeMapping); + Sponge.getCommandManager().register(this, new Commands(this).createRootCommand(), "bluemap"); + + //metrics + Sponge.getScheduler().createTaskBuilder() + .async() + .delay(1, TimeUnit.MINUTES) + .interval(30, TimeUnit.MINUTES) + .execute(() -> { + if (Sponge.getMetricsConfigManager().areMetricsEnabled(this)) Metrics.sendReport("Sponge"); + }) + .submit(this); + + loaded = true; + } + + public synchronized void unload() { + + } + + public synchronized void reload() { + unload(); + load(); + } + + public ServerInterface getServerInterface() { + return serverInterface; + } + + public MainConfig getMainConfig() { + return config; + } + + public ResourcePack getResourcePack() { + return resourcePack; + } + + public World getWorld(UUID uuid){ + return worlds.get(uuid); + } + + public Collection getMapTypes(){ + return maps.values(); + } + + public RenderManager getRenderManager() { + return renderManager; + } + + public MapUpdateHandler getUpdateHandler() { + return updateHandler; + } + + public BlueMapWebServer getWebServer() { + return webServer; + } + + public boolean isLoaded() { + return loaded; + } + + public static Plugin getInstance() { + return instance; + } + +} diff --git a/BlueMapSponge/src/main/java/de/bluecolored/bluemap/sponge/RenderManager.java b/BlueMapPlugin/src/main/java/de/bluecolored/bluemap/plugin/RenderManager.java similarity index 96% rename from BlueMapSponge/src/main/java/de/bluecolored/bluemap/sponge/RenderManager.java rename to BlueMapPlugin/src/main/java/de/bluecolored/bluemap/plugin/RenderManager.java index 43e7be3b..abcbbd59 100644 --- a/BlueMapSponge/src/main/java/de/bluecolored/bluemap/sponge/RenderManager.java +++ b/BlueMapPlugin/src/main/java/de/bluecolored/bluemap/plugin/RenderManager.java @@ -1,4 +1,4 @@ -package de.bluecolored.bluemap.sponge; +package de.bluecolored.bluemap.plugin; import java.io.DataInputStream; import java.io.DataOutputStream; @@ -194,14 +194,14 @@ public void writeState(DataOutputStream out) throws IOException { } } - public void readState(DataInputStream in) throws IOException { + public void readState(DataInputStream in, Collection mapTypes) throws IOException { //read renderTickets int mapCount = in.readInt(); for (int i = 0; i < mapCount; i++) { String mapId = in.readUTF(); MapType mapType = null; - for (MapType map : SpongePlugin.getInstance().getMapTypes()) { + for (MapType map : mapTypes) { if (map.getId().equals(mapId)) { mapType = map; break; @@ -227,7 +227,7 @@ public void readState(DataInputStream in) throws IOException { int taskCount = in.readInt(); for (int i = 0; i < taskCount; i++) { try { - RenderTask task = RenderTask.read(in); + RenderTask task = RenderTask.read(in, mapTypes); addRenderTask(task); } catch (IOException ex) { Logger.global.logWarning("A render-task can not be loaded. It will be discared. (Error message: " + ex.toString() + ")"); diff --git a/BlueMapSponge/src/main/java/de/bluecolored/bluemap/sponge/RenderTask.java b/BlueMapPlugin/src/main/java/de/bluecolored/bluemap/plugin/RenderTask.java similarity index 96% rename from BlueMapSponge/src/main/java/de/bluecolored/bluemap/sponge/RenderTask.java rename to BlueMapPlugin/src/main/java/de/bluecolored/bluemap/plugin/RenderTask.java index 28710a29..8c43b0e9 100644 --- a/BlueMapSponge/src/main/java/de/bluecolored/bluemap/sponge/RenderTask.java +++ b/BlueMapPlugin/src/main/java/de/bluecolored/bluemap/plugin/RenderTask.java @@ -1,4 +1,4 @@ -package de.bluecolored.bluemap.sponge; +package de.bluecolored.bluemap.plugin; import java.io.DataInputStream; import java.io.DataOutputStream; @@ -159,12 +159,12 @@ public void write(DataOutputStream out) throws IOException { } } - public static RenderTask read(DataInputStream in) throws IOException { + public static RenderTask read(DataInputStream in, Collection mapTypes) throws IOException { String name = in.readUTF(); String mapId = in.readUTF(); MapType mapType = null; - for (MapType map : SpongePlugin.getInstance().getMapTypes()) { + for (MapType map : mapTypes) { if (map.getId().equals(mapId)) { mapType = map; break; diff --git a/BlueMapSponge/src/main/java/de/bluecolored/bluemap/sponge/RenderTicket.java b/BlueMapPlugin/src/main/java/de/bluecolored/bluemap/plugin/RenderTicket.java similarity index 96% rename from BlueMapSponge/src/main/java/de/bluecolored/bluemap/sponge/RenderTicket.java rename to BlueMapPlugin/src/main/java/de/bluecolored/bluemap/plugin/RenderTicket.java index 2f4d8cd9..2ec13bad 100644 --- a/BlueMapSponge/src/main/java/de/bluecolored/bluemap/sponge/RenderTicket.java +++ b/BlueMapPlugin/src/main/java/de/bluecolored/bluemap/plugin/RenderTicket.java @@ -1,4 +1,4 @@ -package de.bluecolored.bluemap.sponge; +package de.bluecolored.bluemap.plugin; import java.io.IOException; import java.util.Objects; diff --git a/BlueMapPlugin/src/main/java/de/bluecolored/bluemap/plugin/serverinterface/CommandSource.java b/BlueMapPlugin/src/main/java/de/bluecolored/bluemap/plugin/serverinterface/CommandSource.java new file mode 100644 index 00000000..e4a5d58f --- /dev/null +++ b/BlueMapPlugin/src/main/java/de/bluecolored/bluemap/plugin/serverinterface/CommandSource.java @@ -0,0 +1,106 @@ +package de.bluecolored.bluemap.plugin.serverinterface; + +import org.apache.commons.lang3.StringUtils; + +import net.querz.nbt.CompoundTag; +import net.querz.nbt.ListTag; +import net.querz.nbt.Tag; + +public interface CommandSource { + + default void sendMessage(String plainMessage) { + CompoundTag textTag = new CompoundTag(); + textTag.putString("text", plainMessage); + sendSerializedMessage(textTag); + } + + default void sendMessage(String plainMessage, char colorCodePrefix) { + sendSerializedMessage(parseColorCodes(plainMessage, colorCodePrefix)); + } + + default void sendMessage(Iterable> textTags) { + ListTag> textListTag = new ListTag<>(Tag.class); + for (Tag textTag : textTags) { + textListTag.add(textTag); + } + sendSerializedMessage(textListTag); + } + + default void sendMessage(Tag... textTags) { + ListTag> textListTag = new ListTag<>(Tag.class); + for (Tag textTag : textTags) { + textListTag.add(textTag); + } + sendSerializedMessage(textListTag); + } + + void sendSerializedMessage(Tag textListTag); + + static Tag parseColorCodes(String plainMessage, char colorCodePrefix) { + ListTag> tagList = new ListTag<>(Tag.class); + tagList.addString(""); + + if (plainMessage.isEmpty()) return tagList; + + TextColor color = TextColor.UNDEFINED; + boolean bold = false; + boolean italic = false; + boolean obfuscated = false; + boolean strikethrough = false; + boolean underlined = false; + + plainMessage = "r" + plainMessage; + + String[] parts = StringUtils.split(plainMessage, colorCodePrefix); + + for (String part : parts) { + if (part.isEmpty()) throw new IllegalArgumentException("There is a color code with no color-char!"); + String message = part.substring(1); + char code = part.charAt(0); + + switch (code) { + case 'r': + color = TextColor.UNDEFINED; + bold = false; + italic = false; + obfuscated = false; + strikethrough = false; + underlined = false; + case 'k': + obfuscated = true; + break; + case 'l': + bold = true; + break; + case 'm': + strikethrough = true; + break; + case 'n': + underlined = true; + break; + case 'o': + italic = true; + break; + default: + color = TextColor.ofColorCode(code); + break; + } + + if (message.isEmpty()) continue; + + CompoundTag textTag = new CompoundTag(); + textTag.putString("text", message); + if (color != TextColor.UNDEFINED) textTag.putString("color", color.getId()); + if (bold) textTag.putBoolean("bold", true); + if (italic) textTag.putBoolean("italic", true); + if (underlined) textTag.putBoolean("underlined", true); + if (strikethrough) textTag.putBoolean("strikethrough", true); + if (obfuscated) textTag.putBoolean("obfuscated", true); + + + } + + return tagList; + } + +} diff --git a/BlueMapPlugin/src/main/java/de/bluecolored/bluemap/plugin/serverinterface/ServerEventListener.java b/BlueMapPlugin/src/main/java/de/bluecolored/bluemap/plugin/serverinterface/ServerEventListener.java new file mode 100644 index 00000000..ee0679cf --- /dev/null +++ b/BlueMapPlugin/src/main/java/de/bluecolored/bluemap/plugin/serverinterface/ServerEventListener.java @@ -0,0 +1,16 @@ +package de.bluecolored.bluemap.plugin.serverinterface; + +import java.util.UUID; + +import com.flowpowered.math.vector.Vector2i; +import com.flowpowered.math.vector.Vector3i; + +public interface ServerEventListener { + + void onWorldSaveToDisk(UUID world); + + void onBlockChange(UUID world, Vector3i blockPos); + + void onChunkFinishedGeneration(UUID world, Vector2i chunkPos); + +} diff --git a/BlueMapPlugin/src/main/java/de/bluecolored/bluemap/plugin/serverinterface/ServerInterface.java b/BlueMapPlugin/src/main/java/de/bluecolored/bluemap/plugin/serverinterface/ServerInterface.java new file mode 100644 index 00000000..df42f064 --- /dev/null +++ b/BlueMapPlugin/src/main/java/de/bluecolored/bluemap/plugin/serverinterface/ServerInterface.java @@ -0,0 +1,24 @@ +package de.bluecolored.bluemap.plugin.serverinterface; + +import java.io.File; +import java.util.concurrent.ExecutorService; + +import de.bluecolored.bluemap.core.world.World; + +public interface ServerInterface { + + void registerListener(ServerEventListener listener); + + void unregisterAllListeners(); + + World createWorld(File worldFolder); + + ExecutorService getSyncExecutorService(); + + ExecutorService getAsyncExecutorService(); + + File getConfigFolder(); + + boolean isMetricsEnabled(boolean configValue); + +} diff --git a/BlueMapPlugin/src/main/java/de/bluecolored/bluemap/plugin/serverinterface/TextColor.java b/BlueMapPlugin/src/main/java/de/bluecolored/bluemap/plugin/serverinterface/TextColor.java new file mode 100644 index 00000000..c5e3281a --- /dev/null +++ b/BlueMapPlugin/src/main/java/de/bluecolored/bluemap/plugin/serverinterface/TextColor.java @@ -0,0 +1,47 @@ +package de.bluecolored.bluemap.plugin.serverinterface; + +public enum TextColor { + + UNDEFINED ("undefined", 'r'), + WHITE ("white", 'f'), + BLACK ("black", '0'), + YELLOW ("yellow", 'e'), + GOLD ("gold", '6'), + AQUA ("aqua", 'b'), + DARK_AQUA ("dark_aqua", '3'), + BLUE ("blue", '9'), + DARK_BLUE ("dark_blue", '1'), + LIGHT_PURPLE ("light_purple", 'd'), + DARK_PURPLE ("dark_purple", '5'), + RED ("red", 'c'), + DARK_RED ("dark_red", '4'), + GREEN ("green", 'a'), + DARK_GREEN ("dark_green", '2'), + GRAY ("gray", '7'), + DARK_GRAY ("dark_gray", '8'); + + private final String id; + private final char colorCode; + + private TextColor(String id, char colorCode) { + this.id = id; + this.colorCode = colorCode; + } + + public String getId() { + return id; + } + + public char getColorCode() { + return colorCode; + } + + public static TextColor ofColorCode(char code) { + for (TextColor color : values()) { + if (color.colorCode == code) return color; + } + + throw new IllegalArgumentException("'" + code + "' isn't a valid color-code!"); + } + +} diff --git a/BlueMapSponge/build.gradle b/BlueMapSponge/build.gradle index a1dbf64d..0c96c272 100644 --- a/BlueMapSponge/build.gradle +++ b/BlueMapSponge/build.gradle @@ -1,5 +1,5 @@ dependencies { shadow "org.spongepowered:spongeapi:7.1.0-SNAPSHOT" compile group: 'org.bstats', name: 'bstats-sponge-lite', version: '1.5' - compile project(':BlueMapCore') + compile project(':BlueMapPlugin') } diff --git a/BlueMapSponge/src/main/java/de/bluecolored/bluemap/sponge/Commands.java b/BlueMapSponge/src/main/java/de/bluecolored/bluemap/sponge/Commands.java index d7d7221e..e4d6cec4 100644 --- a/BlueMapSponge/src/main/java/de/bluecolored/bluemap/sponge/Commands.java +++ b/BlueMapSponge/src/main/java/de/bluecolored/bluemap/sponge/Commands.java @@ -34,6 +34,9 @@ import de.bluecolored.bluemap.core.render.hires.HiresModelManager; import de.bluecolored.bluemap.core.world.Block; import de.bluecolored.bluemap.core.world.World; +import de.bluecolored.bluemap.plugin.MapType; +import de.bluecolored.bluemap.plugin.RenderManager; +import de.bluecolored.bluemap.plugin.RenderTask; public class Commands { diff --git a/BlueMapSponge/src/main/java/de/bluecolored/bluemap/sponge/MapUpdateHandler.java b/BlueMapSponge/src/main/java/de/bluecolored/bluemap/sponge/MapUpdateHandler.java index 529b6d0e..6cf59554 100644 --- a/BlueMapSponge/src/main/java/de/bluecolored/bluemap/sponge/MapUpdateHandler.java +++ b/BlueMapSponge/src/main/java/de/bluecolored/bluemap/sponge/MapUpdateHandler.java @@ -20,6 +20,9 @@ import com.google.common.collect.Multimap; import com.google.common.collect.MultimapBuilder; +import de.bluecolored.bluemap.plugin.MapType; +import de.bluecolored.bluemap.plugin.RenderManager; + public class MapUpdateHandler { public Multimap updateBuffer; diff --git a/BlueMapSponge/src/main/java/de/bluecolored/bluemap/sponge/SpongePlugin.java b/BlueMapSponge/src/main/java/de/bluecolored/bluemap/sponge/SpongePlugin.java index 96458db5..4438baa4 100644 --- a/BlueMapSponge/src/main/java/de/bluecolored/bluemap/sponge/SpongePlugin.java +++ b/BlueMapSponge/src/main/java/de/bluecolored/bluemap/sponge/SpongePlugin.java @@ -54,13 +54,11 @@ import org.spongepowered.api.event.game.GameReloadEvent; import org.spongepowered.api.event.game.state.GameStartingServerEvent; import org.spongepowered.api.event.game.state.GameStoppingEvent; -import org.spongepowered.api.plugin.Plugin; import org.spongepowered.api.scheduler.SpongeExecutorService; import org.spongepowered.api.world.storage.WorldProperties; import com.flowpowered.math.vector.Vector2i; -import de.bluecolored.bluemap.core.BlueMap; import de.bluecolored.bluemap.core.config.ConfigManager; import de.bluecolored.bluemap.core.config.MainConfig; import de.bluecolored.bluemap.core.config.MainConfig.MapConfig; @@ -78,22 +76,21 @@ import de.bluecolored.bluemap.core.web.WebSettings; import de.bluecolored.bluemap.core.world.SlicedWorld; import de.bluecolored.bluemap.core.world.World; +import de.bluecolored.bluemap.plugin.MapType; +import de.bluecolored.bluemap.plugin.Plugin; +import de.bluecolored.bluemap.plugin.RenderManager; import net.querz.nbt.CompoundTag; import net.querz.nbt.NBTUtil; -@Plugin( - id = SpongePlugin.PLUGIN_ID, - name = SpongePlugin.PLUGIN_NAME, +@org.spongepowered.api.plugin.Plugin( + id = Plugin.PLUGIN_ID, + name = Plugin.PLUGIN_NAME, authors = { "Blue (Lukas Rieger)" }, description = "This plugin provides a fully 3D map of your world for your browser!", - version = SpongePlugin.PLUGIN_VERSION + version = Plugin.PLUGIN_VERSION ) public class SpongePlugin { - public static final String PLUGIN_ID = "bluemap"; - public static final String PLUGIN_NAME = "BlueMap"; - public static final String PLUGIN_VERSION = BlueMap.VERSION; - private static SpongePlugin instance; @Inject @@ -246,7 +243,7 @@ public synchronized void load() throws ExecutionException, IOException, Interrup saveFile.getParentFile().mkdirs(); if (saveFile.exists()) { try (DataInputStream in = new DataInputStream(new GZIPInputStream(new FileInputStream(saveFile)))) { - renderManager.readState(in); + renderManager.readState(in, getMapTypes()); } } saveFile.delete(); diff --git a/settings.gradle b/settings.gradle index 3c519531..261e1aa9 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,10 +1,12 @@ rootProject.name = 'BlueMap' include ':BlueMapCore' include ':BlueMapCLI' +include ':BlueMapPlugin' include ':BlueMapSponge' include ':BlueMapBukkit' project(':BlueMapCore').projectDir = "$rootDir/BlueMapCore" as File project(':BlueMapCLI').projectDir = "$rootDir/BlueMapCLI" as File +project(':BlueMapPlugin').projectDir = "$rootDir/BlueMapPlugin" as File project(':BlueMapSponge').projectDir = "$rootDir/BlueMapSponge" as File project(':BlueMapBukkit').projectDir = "$rootDir/BlueMapBukkit" as File \ No newline at end of file