mirror of
https://github.com/BlueMap-Minecraft/BlueMap.git
synced 2024-11-22 18:45:21 +01:00
Port the plugin to sponge 8
This commit is contained in:
parent
a23178f772
commit
ede84722fb
40
implementations/sponge-8.0.0/build.gradle
Normal file
40
implementations/sponge-8.0.0/build.gradle
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
dependencies {
|
||||||
|
shadow "org.spongepowered:spongeapi:8.0.0-SNAPSHOT"
|
||||||
|
|
||||||
|
compile group: 'org.bstats', name: 'bstats-sponge-lite', version: '1.5'
|
||||||
|
|
||||||
|
compile (project(':BlueMapCommon')) {
|
||||||
|
//exclude dependencies provided by sponge
|
||||||
|
exclude group: 'com.google.guava', module: 'guava'
|
||||||
|
exclude group: 'com.google.code.gson', module: 'gson'
|
||||||
|
exclude group: 'org.apache.commons', module: 'commons-lang3'
|
||||||
|
exclude group: 'javax.inject'
|
||||||
|
exclude group: 'com.google.inject'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
build.dependsOn shadowJar {
|
||||||
|
destinationDirectory = file '../../build/release'
|
||||||
|
archiveFileName = "BlueMap-${version}-sponge-8.0.0.jar"
|
||||||
|
|
||||||
|
relocate 'net.querz.nbt', 'de.bluecolored.shadow.querz.nbt'
|
||||||
|
relocate 'org.apache.commons.io', 'de.bluecolored.shadow.apache.commons.io'
|
||||||
|
relocate 'com.mojang.brigadier', 'de.bluecolored.shadow.mojang.brigadier'
|
||||||
|
relocate 'com.github.benmanes.caffeine', 'de.bluecolored.shadow.benmanes.caffeine'
|
||||||
|
relocate 'com.google.errorprone', 'de.bluecolored.shadow.google.errorprone'
|
||||||
|
relocate 'ninja.leaping.configurate', 'de.bluecolored.shadow.ninja.leaping.configurate'
|
||||||
|
relocate 'org.aopalliance', 'de.bluecolored.shadow.aopalliance'
|
||||||
|
relocate 'com.typesafe.config', 'de.bluecolored.shadow.typesafe.config'
|
||||||
|
relocate 'org.checkerframework', 'de.bluecolored.shadow.checkerframework'
|
||||||
|
relocate 'org.codehaus', 'de.bluecolored.shadow.codehaus'
|
||||||
|
}
|
||||||
|
|
||||||
|
processResources {
|
||||||
|
from(sourceSets.main.resources.srcDirs) {
|
||||||
|
include 'META-INF/plugins.json'
|
||||||
|
|
||||||
|
expand (
|
||||||
|
version: project.version
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
package de.bluecolored.bluemap.sponge8;
|
||||||
|
|
||||||
|
import de.bluecolored.bluemap.common.plugin.serverinterface.ServerEventListener;
|
||||||
|
import de.bluecolored.bluemap.common.plugin.text.Text;
|
||||||
|
import org.spongepowered.api.ResourceKey;
|
||||||
|
import org.spongepowered.api.Sponge;
|
||||||
|
import org.spongepowered.api.adventure.SpongeComponents;
|
||||||
|
import org.spongepowered.api.block.BlockSnapshot;
|
||||||
|
import org.spongepowered.api.data.Transaction;
|
||||||
|
import org.spongepowered.api.event.Listener;
|
||||||
|
import org.spongepowered.api.event.Order;
|
||||||
|
import org.spongepowered.api.event.block.ChangeBlockEvent;
|
||||||
|
import org.spongepowered.api.event.message.PlayerChatEvent;
|
||||||
|
import org.spongepowered.api.event.network.ServerSideConnectionEvent;
|
||||||
|
import org.spongepowered.api.event.world.chunk.ChunkEvent;
|
||||||
|
import org.spongepowered.api.world.server.ServerLocation;
|
||||||
|
import org.spongepowered.api.world.server.ServerWorld;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public class EventForwarder {
|
||||||
|
|
||||||
|
private ServerEventListener listener;
|
||||||
|
|
||||||
|
public EventForwarder(ServerEventListener listener) {
|
||||||
|
this.listener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Use ChunkSaveToDisk as it is the preferred event to use and more reliable on the chunk actually saved to disk
|
||||||
|
@Listener(order = Order.POST)
|
||||||
|
public void onWorldSaveToDisk(SaveWorldEvent evt) {
|
||||||
|
listener.onWorldSaveToDisk(evt.getTargetWorld().getUniqueId());
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Listener(order = Order.POST)
|
||||||
|
public void onChunkSaveToDisk(ChunkEvent.Save.Pre evt) {
|
||||||
|
ResourceKey worldKey = evt.chunkWorld();
|
||||||
|
Optional<ServerWorld> world = Sponge.server().worldManager().world(worldKey);
|
||||||
|
if (world.isPresent()) {
|
||||||
|
listener.onChunkSaveToDisk(world.get().uniqueId(), SpongePlugin.fromSpongePoweredVector(evt.targetChunk().chunkPosition().toVector2(true)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Listener(order = Order.POST)
|
||||||
|
public void onBlockChange(ChangeBlockEvent.All evt) {
|
||||||
|
for (Transaction<BlockSnapshot> tr : evt.transactions()) {
|
||||||
|
if(!tr.isValid()) continue;
|
||||||
|
|
||||||
|
Optional<ServerLocation> ow = tr.finalReplacement().location();
|
||||||
|
if (ow.isPresent()) {
|
||||||
|
listener.onBlockChange(ow.get().world().uniqueId(), SpongePlugin.fromSpongePoweredVector(ow.get().position().toInt()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO event missing in Sponge
|
||||||
|
// @Listener(order = Order.POST)
|
||||||
|
// public void onChunkFinishedGeneration(PopulateChunkEvent.Post evt) {
|
||||||
|
// Vector3i chunkPos = evt.getTargetChunk().getPosition();
|
||||||
|
// listener.onChunkFinishedGeneration(evt.getTargetChunk().getWorld().getUniqueId(), new Vector2i(chunkPos.getX(), chunkPos.getZ()));
|
||||||
|
// }
|
||||||
|
|
||||||
|
@Listener(order = Order.POST)
|
||||||
|
public void onPlayerJoin(ServerSideConnectionEvent.Join evt) {
|
||||||
|
listener.onPlayerJoin(evt.player().uniqueId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Listener(order = Order.POST)
|
||||||
|
public void onPlayerLeave(ServerSideConnectionEvent.Disconnect evt) {
|
||||||
|
listener.onPlayerJoin(evt.player().uniqueId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Listener(order = Order.POST)
|
||||||
|
public void onPlayerChat(PlayerChatEvent evt) {
|
||||||
|
listener.onChatMessage(Text.of(SpongeComponents.plainSerializer().serialize(evt.message())));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
package de.bluecolored.bluemap.sponge8;
|
||||||
|
|
||||||
|
import de.bluecolored.bluemap.core.logger.AbstractLogger;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
|
public class Log4J2Logger extends AbstractLogger {
|
||||||
|
|
||||||
|
private Logger out;
|
||||||
|
|
||||||
|
public Log4J2Logger(Logger out) {
|
||||||
|
this.out = out;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void logError(String message, Throwable throwable) {
|
||||||
|
out.error(message, throwable);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void logWarning(String message) {
|
||||||
|
out.warn(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void logInfo(String message) {
|
||||||
|
out.info(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void logDebug(String message) {
|
||||||
|
if (out.isDebugEnabled()) out.debug(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void noFloodDebug(String message) {
|
||||||
|
if (out.isDebugEnabled()) super.noFloodDebug(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void noFloodDebug(String key, String message) {
|
||||||
|
if (out.isDebugEnabled()) super.noFloodDebug(key, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
package de.bluecolored.bluemap.sponge8;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import net.kyori.adventure.audience.Audience;
|
||||||
|
import org.spongepowered.api.adventure.SpongeComponents;
|
||||||
|
import org.spongepowered.api.service.permission.Subject;
|
||||||
|
import org.spongepowered.api.world.Locatable;
|
||||||
|
|
||||||
|
import com.flowpowered.math.vector.Vector3d;
|
||||||
|
|
||||||
|
import de.bluecolored.bluemap.common.plugin.Plugin;
|
||||||
|
import de.bluecolored.bluemap.common.plugin.serverinterface.CommandSource;
|
||||||
|
import de.bluecolored.bluemap.common.plugin.text.Text;
|
||||||
|
import de.bluecolored.bluemap.core.world.World;
|
||||||
|
|
||||||
|
public class SpongeCommandSource implements CommandSource {
|
||||||
|
|
||||||
|
private Plugin plugin;
|
||||||
|
private Audience audience;
|
||||||
|
private Subject subject;
|
||||||
|
|
||||||
|
public SpongeCommandSource(Plugin plugin, Audience audience, Subject subject) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
this.subject = subject;
|
||||||
|
this.audience = audience;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendMessage(Text text) {
|
||||||
|
audience.sendMessage(SpongeComponents.gsonSerializer().deserialize(text.toJSONString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasPermission(String permission) {
|
||||||
|
return subject.hasPermission(permission);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<Vector3d> getPosition() {
|
||||||
|
if (audience instanceof Locatable) {
|
||||||
|
return Optional.of(SpongePlugin.fromSpongePoweredVector(((Locatable) audience).location().position()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<World> getWorld() {
|
||||||
|
if (audience instanceof Locatable) {
|
||||||
|
return Optional.ofNullable(plugin.getWorld(((Locatable) audience).serverLocation().world().uniqueId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,161 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
package de.bluecolored.bluemap.sponge8;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
|
import net.kyori.adventure.audience.Audience;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
import org.spongepowered.api.command.Command;
|
||||||
|
import org.spongepowered.api.command.CommandCause;
|
||||||
|
import org.spongepowered.api.command.CommandResult;
|
||||||
|
import org.spongepowered.api.command.parameter.ArgumentReader;
|
||||||
|
import org.spongepowered.api.service.permission.Subject;
|
||||||
|
|
||||||
|
import com.mojang.brigadier.CommandDispatcher;
|
||||||
|
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||||
|
import com.mojang.brigadier.suggestion.Suggestion;
|
||||||
|
import com.mojang.brigadier.suggestion.Suggestions;
|
||||||
|
import com.mojang.brigadier.tree.CommandNode;
|
||||||
|
|
||||||
|
import de.bluecolored.bluemap.common.plugin.Plugin;
|
||||||
|
import de.bluecolored.bluemap.common.plugin.commands.Commands;
|
||||||
|
|
||||||
|
public class SpongeCommands {
|
||||||
|
|
||||||
|
private CommandDispatcher<Subject> dispatcher;
|
||||||
|
|
||||||
|
public SpongeCommands(final Plugin plugin) {
|
||||||
|
this.dispatcher = new CommandDispatcher<>();
|
||||||
|
|
||||||
|
// register commands
|
||||||
|
// this assumes that every Subject will also be an Audience
|
||||||
|
new Commands<>(plugin, dispatcher, subject -> new SpongeCommandSource(plugin, (Audience) subject, subject));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<SpongeCommandProxy> getRootCommands(){
|
||||||
|
Collection<SpongeCommandProxy> rootCommands = new ArrayList<>();
|
||||||
|
|
||||||
|
for (CommandNode<Subject> node : this.dispatcher.getRoot().getChildren()) {
|
||||||
|
rootCommands.add(new SpongeCommandProxy(node.getName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return rootCommands;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SpongeCommandProxy implements Command.Raw {
|
||||||
|
|
||||||
|
private String label;
|
||||||
|
|
||||||
|
protected SpongeCommandProxy(String label) {
|
||||||
|
this.label = label;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLabel() {
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommandResult process(CommandCause cause, ArgumentReader.Mutable arguments) {
|
||||||
|
String command = label;
|
||||||
|
if (!arguments.input().isEmpty()) {
|
||||||
|
command += " " + arguments.input();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return CommandResult.builder().result(dispatcher.execute(command, cause.subject())).build();
|
||||||
|
} catch (CommandSyntaxException ex) {
|
||||||
|
cause.audience().sendMessage(Component.text(ex.getRawMessage().getString(), NamedTextColor.RED));
|
||||||
|
|
||||||
|
String context = ex.getContext();
|
||||||
|
if (context != null) cause.audience().sendMessage(Component.text(context, NamedTextColor.GRAY));
|
||||||
|
|
||||||
|
return CommandResult.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> suggestions(CommandCause cause, ArgumentReader.Mutable arguments) {
|
||||||
|
String command = label;
|
||||||
|
if (!arguments.input().isEmpty()) {
|
||||||
|
command += " " + arguments.input();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> completions = new ArrayList<>();
|
||||||
|
|
||||||
|
try {
|
||||||
|
Suggestions suggestions = dispatcher.getCompletionSuggestions(dispatcher.parse(command, cause.subject())).get(100, TimeUnit.MILLISECONDS);
|
||||||
|
for (Suggestion suggestion : suggestions.getList()) {
|
||||||
|
String text = suggestion.getText();
|
||||||
|
|
||||||
|
if (text.indexOf(' ') == -1) {
|
||||||
|
completions.add(text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (InterruptedException ignore) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
} catch (ExecutionException | TimeoutException ignore) {}
|
||||||
|
|
||||||
|
completions.sort(String::compareToIgnoreCase);
|
||||||
|
return completions;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canExecute(CommandCause cause) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<Component> shortDescription(CommandCause cause) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<Component> extendedDescription(CommandCause cause) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Component usage(CommandCause cause) {
|
||||||
|
CommandNode<Subject> node = dispatcher.getRoot().getChild(label);
|
||||||
|
if (node == null) return Component.text("/" + label);
|
||||||
|
|
||||||
|
List<Component> lines = new ArrayList<>();
|
||||||
|
for (String usageString : dispatcher.getSmartUsage(node, cause.subject()).values()) {
|
||||||
|
lines.add(Component.text("/" + label + " ", NamedTextColor.WHITE).append(Component.text(usageString, NamedTextColor.GRAY)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Component.join(Component.newline(), lines);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,143 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
package de.bluecolored.bluemap.sponge8;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import com.flowpowered.math.vector.Vector3d;
|
||||||
|
import org.spongepowered.api.Sponge;
|
||||||
|
import org.spongepowered.api.data.Keys;
|
||||||
|
import org.spongepowered.api.effect.potion.PotionEffect;
|
||||||
|
import org.spongepowered.api.effect.potion.PotionEffectTypes;
|
||||||
|
import org.spongepowered.api.entity.living.player.gamemode.GameMode;
|
||||||
|
import org.spongepowered.api.entity.living.player.gamemode.GameModes;
|
||||||
|
|
||||||
|
import de.bluecolored.bluemap.common.plugin.serverinterface.Gamemode;
|
||||||
|
import de.bluecolored.bluemap.common.plugin.serverinterface.Player;
|
||||||
|
import de.bluecolored.bluemap.common.plugin.text.Text;
|
||||||
|
import org.spongepowered.api.entity.living.player.server.ServerPlayer;
|
||||||
|
|
||||||
|
public class SpongePlayer implements Player {
|
||||||
|
|
||||||
|
private static final Map<GameMode, Gamemode> GAMEMODE_MAP = new HashMap<>(5);
|
||||||
|
static {
|
||||||
|
GAMEMODE_MAP.put(GameModes.ADVENTURE.get(), Gamemode.ADVENTURE);
|
||||||
|
GAMEMODE_MAP.put(GameModes.SURVIVAL.get(), Gamemode.SURVIVAL);
|
||||||
|
GAMEMODE_MAP.put(GameModes.CREATIVE.get(), Gamemode.CREATIVE);
|
||||||
|
GAMEMODE_MAP.put(GameModes.SPECTATOR.get(), Gamemode.SPECTATOR);
|
||||||
|
GAMEMODE_MAP.put(GameModes.NOT_SET.get(), Gamemode.SURVIVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
private UUID uuid;
|
||||||
|
private Text name;
|
||||||
|
private UUID world;
|
||||||
|
private Vector3d position;
|
||||||
|
private boolean online;
|
||||||
|
private boolean sneaking;
|
||||||
|
private boolean invisible;
|
||||||
|
private Gamemode gamemode;
|
||||||
|
|
||||||
|
public SpongePlayer(UUID playerUUID) {
|
||||||
|
this.uuid = playerUUID;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UUID getUuid() {
|
||||||
|
return this.uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Text getName() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UUID getWorld() {
|
||||||
|
return this.world;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Vector3d getPosition() {
|
||||||
|
return this.position;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isOnline() {
|
||||||
|
return this.online;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSneaking() {
|
||||||
|
return this.sneaking;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isInvisible() {
|
||||||
|
return this.invisible;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Gamemode getGamemode() {
|
||||||
|
return this.gamemode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* API access, only call on server thread!
|
||||||
|
*/
|
||||||
|
public void update() {
|
||||||
|
ServerPlayer player = Sponge.server().player(uuid).orElse(null);
|
||||||
|
if (player == null) {
|
||||||
|
this.online = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.gamemode = GAMEMODE_MAP.get(player.get(Keys.GAME_MODE).orElse(GameModes.NOT_SET.get()));
|
||||||
|
if (this.gamemode == null) this.gamemode = Gamemode.SURVIVAL;
|
||||||
|
|
||||||
|
boolean invis = player.get(Keys.VANISH).orElse(false);
|
||||||
|
if (!invis && player.get(Keys.IS_INVISIBLE).orElse(false)) invis = true;
|
||||||
|
if (!invis) {
|
||||||
|
Optional<List<PotionEffect>> effects = player.get(Keys.POTION_EFFECTS);
|
||||||
|
if (effects.isPresent()) {
|
||||||
|
for (PotionEffect effect : effects.get()) {
|
||||||
|
if (effect.type().equals(PotionEffectTypes.INVISIBILITY.get()) && effect.duration() > 0) invis = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.invisible = invis;
|
||||||
|
|
||||||
|
this.name = Text.of(player.name());
|
||||||
|
this.online = player.isOnline();
|
||||||
|
this.position = SpongePlugin.fromSpongePoweredVector(player.position());
|
||||||
|
this.sneaking = player.get(Keys.IS_SNEAKING).orElse(false);
|
||||||
|
this.world = player.world().uniqueId();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,323 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
package de.bluecolored.bluemap.sponge8;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
|
||||||
|
import com.flowpowered.math.vector.Vector2i;
|
||||||
|
import com.flowpowered.math.vector.Vector3d;
|
||||||
|
import com.flowpowered.math.vector.Vector3i;
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import org.spongepowered.api.Platform;
|
||||||
|
import org.spongepowered.api.ResourceKey;
|
||||||
|
import org.spongepowered.api.Server;
|
||||||
|
import org.spongepowered.api.Sponge;
|
||||||
|
import org.spongepowered.api.adventure.SpongeComponents;
|
||||||
|
import org.spongepowered.api.command.Command;
|
||||||
|
import org.spongepowered.api.config.ConfigDir;
|
||||||
|
import org.spongepowered.api.event.Listener;
|
||||||
|
import org.spongepowered.api.event.lifecycle.RefreshGameEvent;
|
||||||
|
import org.spongepowered.api.event.lifecycle.RegisterCommandEvent;
|
||||||
|
import org.spongepowered.api.event.lifecycle.StartedEngineEvent;
|
||||||
|
import org.spongepowered.api.event.lifecycle.StoppingEngineEvent;
|
||||||
|
import org.spongepowered.api.event.network.ServerSideConnectionEvent;
|
||||||
|
import org.spongepowered.api.scheduler.ScheduledTask;
|
||||||
|
import org.spongepowered.api.scheduler.Task;
|
||||||
|
import org.spongepowered.api.util.Ticks;
|
||||||
|
import org.spongepowered.api.util.Tristate;
|
||||||
|
import org.spongepowered.api.world.server.ServerWorld;
|
||||||
|
|
||||||
|
import de.bluecolored.bluemap.common.plugin.Plugin;
|
||||||
|
import de.bluecolored.bluemap.common.plugin.serverinterface.Player;
|
||||||
|
import de.bluecolored.bluemap.common.plugin.serverinterface.ServerEventListener;
|
||||||
|
import de.bluecolored.bluemap.common.plugin.serverinterface.ServerInterface;
|
||||||
|
import de.bluecolored.bluemap.core.MinecraftVersion;
|
||||||
|
import de.bluecolored.bluemap.core.logger.Logger;
|
||||||
|
import de.bluecolored.bluemap.core.resourcepack.ParseResourceException;
|
||||||
|
import de.bluecolored.bluemap.sponge8.SpongeCommands.SpongeCommandProxy;
|
||||||
|
import org.spongepowered.plugin.PluginContainer;
|
||||||
|
|
||||||
|
@org.spongepowered.plugin.jvm.Plugin(Plugin.PLUGIN_ID)
|
||||||
|
public class SpongePlugin implements ServerInterface {
|
||||||
|
|
||||||
|
private final PluginContainer pluginContainer;
|
||||||
|
@Inject
|
||||||
|
@ConfigDir(sharedRoot = false)
|
||||||
|
private Path configurationDir;
|
||||||
|
|
||||||
|
// TODO Bstats needs updating
|
||||||
|
// @Inject
|
||||||
|
// @SuppressWarnings("unused")
|
||||||
|
// private MetricsLite2 metrics;
|
||||||
|
|
||||||
|
private Plugin pluginInstance;
|
||||||
|
private SpongeCommands commands;
|
||||||
|
|
||||||
|
private Map<File, UUID> worldUUIDs = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
private ExecutorService asyncExecutor;
|
||||||
|
private ExecutorService syncExecutor;
|
||||||
|
|
||||||
|
private int playerUpdateIndex = 0;
|
||||||
|
private Map<UUID, Player> onlinePlayerMap;
|
||||||
|
private List<SpongePlayer> onlinePlayerList;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public SpongePlugin(org.apache.logging.log4j.Logger logger, PluginContainer pluginContainer) {
|
||||||
|
Logger.global = new Log4J2Logger(logger);
|
||||||
|
this.pluginContainer = pluginContainer;
|
||||||
|
|
||||||
|
this.onlinePlayerMap = new ConcurrentHashMap<>();
|
||||||
|
this.onlinePlayerList = Collections.synchronizedList(new ArrayList<>());
|
||||||
|
|
||||||
|
final String versionFromSponge = Sponge.platform().container(Platform.Component.GAME).getMetadata().getVersion();
|
||||||
|
MinecraftVersion version = MinecraftVersion.MC_1_16;
|
||||||
|
try {
|
||||||
|
version = MinecraftVersion.fromVersionString(versionFromSponge);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
Logger.global.logWarning("Failed to find a matching version for version-name '" + versionFromSponge + "'! Using latest known sponge-version: " + version.getVersionString());
|
||||||
|
}
|
||||||
|
|
||||||
|
this.pluginInstance = new Plugin(version, "sponge", this);
|
||||||
|
this.commands = new SpongeCommands(pluginInstance);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Listener
|
||||||
|
public void onRegisterCommands(final RegisterCommandEvent<Command.Raw> event) {
|
||||||
|
//register commands
|
||||||
|
for(SpongeCommandProxy command : commands.getRootCommands()) {
|
||||||
|
event.register(this.pluginContainer, command, command.getLabel());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Listener
|
||||||
|
public void onServerStart(StartedEngineEvent<Server> evt) {
|
||||||
|
asyncExecutor = evt.game().asyncScheduler().createExecutor(pluginContainer);
|
||||||
|
syncExecutor = evt.engine().scheduler().createExecutor(pluginContainer);
|
||||||
|
|
||||||
|
//start updating players
|
||||||
|
Task task = Task.builder()
|
||||||
|
.interval(Ticks.of(1))
|
||||||
|
.execute(this::updateSomePlayers)
|
||||||
|
.plugin(pluginContainer)
|
||||||
|
.build();
|
||||||
|
evt.engine().scheduler().submit(task);
|
||||||
|
|
||||||
|
asyncExecutor.execute(() -> {
|
||||||
|
try {
|
||||||
|
Logger.global.logInfo("Loading...");
|
||||||
|
pluginInstance.load();
|
||||||
|
if (pluginInstance.isLoaded()) Logger.global.logInfo("Loaded!");
|
||||||
|
} catch (IOException | ParseResourceException | RuntimeException e) {
|
||||||
|
Logger.global.logError("Failed to load!", e);
|
||||||
|
pluginInstance.unload();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Listener
|
||||||
|
public void onServerStop(StoppingEngineEvent<Server> evt) {
|
||||||
|
Logger.global.logInfo("Stopping...");
|
||||||
|
evt.engine().scheduler().tasksByPlugin(pluginContainer).forEach(ScheduledTask::cancel);
|
||||||
|
pluginInstance.unload();
|
||||||
|
Logger.global.logInfo("Saved and stopped!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Listener
|
||||||
|
public void onServerReload(RefreshGameEvent evt) {
|
||||||
|
asyncExecutor.execute(() -> {
|
||||||
|
try {
|
||||||
|
Logger.global.logInfo("Reloading...");
|
||||||
|
pluginInstance.reload();
|
||||||
|
Logger.global.logInfo("Reloaded!");
|
||||||
|
} catch (IOException | ParseResourceException | RuntimeException e) {
|
||||||
|
Logger.global.logError("Failed to load!", e);
|
||||||
|
pluginInstance.unload();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Listener
|
||||||
|
public void onPlayerJoin(ServerSideConnectionEvent.Join evt) {
|
||||||
|
SpongePlayer player = new SpongePlayer(evt.player().uniqueId());
|
||||||
|
onlinePlayerMap.put(evt.player().uniqueId(), player);
|
||||||
|
onlinePlayerList.add(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Listener
|
||||||
|
public void onPlayerLeave(ServerSideConnectionEvent.Disconnect evt) {
|
||||||
|
UUID playerUUID = evt.player().uniqueId();
|
||||||
|
onlinePlayerMap.remove(playerUUID);
|
||||||
|
synchronized (onlinePlayerList) {
|
||||||
|
onlinePlayerList.removeIf(p -> p.getUuid().equals(playerUUID));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerListener(ServerEventListener listener) {
|
||||||
|
Sponge.eventManager().registerListeners(this.pluginContainer, new EventForwarder(listener));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unregisterAllListeners() {
|
||||||
|
Sponge.eventManager().unregisterPluginListeners(this.pluginContainer);
|
||||||
|
Sponge.eventManager().registerListeners(this.pluginContainer, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UUID getUUIDForWorld(File worldFolder) throws IOException {
|
||||||
|
// this logic derives the the world key from the folder structure
|
||||||
|
final Pattern customDimension = Pattern.compile(".+/dimensions/([a-z0-9_.-]+)/([a-z0-9._-]+)$".replace("/", File.separator));
|
||||||
|
final Matcher matcher = customDimension.matcher(worldFolder.toString());
|
||||||
|
final ResourceKey key;
|
||||||
|
if (matcher.matches()) {
|
||||||
|
key = ResourceKey.of(matcher.group(1), matcher.group(2));
|
||||||
|
} else if ("DIM-1".equals(worldFolder.getName())) {
|
||||||
|
key = ResourceKey.minecraft("the_nether");
|
||||||
|
} else if ("DIM1".equals(worldFolder.getName())) {
|
||||||
|
key = ResourceKey.minecraft("the_end");
|
||||||
|
} else {
|
||||||
|
// assume it's the main world
|
||||||
|
key = Sponge.server().worldManager().defaultWorld().key();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Sponge.server().worldManager().world(key)
|
||||||
|
.map(ServerWorld::uniqueId)
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getWorldName(UUID worldUUID) {
|
||||||
|
return getServerWorld(worldUUID)
|
||||||
|
.map(serverWorld -> serverWorld
|
||||||
|
.properties()
|
||||||
|
.displayName()
|
||||||
|
.map(SpongeComponents.plainSerializer()::serialize)
|
||||||
|
.orElse(serverWorld.key().asString()))
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Optional<ServerWorld> getServerWorld(UUID worldUUID) {
|
||||||
|
return Sponge.server().worldManager().worldKey(worldUUID).flatMap(k -> Sponge.server().worldManager().world(k));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public File getConfigFolder() {
|
||||||
|
return configurationDir.toFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<Player> getOnlinePlayers() {
|
||||||
|
return onlinePlayerMap.values();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<Player> getPlayer(UUID uuid) {
|
||||||
|
return Optional.ofNullable(onlinePlayerMap.get(uuid));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMetricsEnabled(boolean configValue) {
|
||||||
|
if (pluginContainer != null) {
|
||||||
|
Tristate metricsEnabled = Sponge.metricsConfigManager().collectionState(pluginContainer);
|
||||||
|
if (metricsEnabled != Tristate.UNDEFINED) {
|
||||||
|
return metricsEnabled == Tristate.TRUE ? true : false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Sponge.metricsConfigManager().globalCollectionState().asBoolean();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean persistWorldChanges(UUID worldUUID) throws IOException, IllegalArgumentException {
|
||||||
|
try {
|
||||||
|
return syncExecutor.submit(() -> {
|
||||||
|
ServerWorld world = getServerWorld(worldUUID).orElse(null);
|
||||||
|
if (world == null) throw new IllegalArgumentException("There is no world with this uuid: " + worldUUID);
|
||||||
|
world.save();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}).get();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
throw new IOException(e);
|
||||||
|
} catch (ExecutionException e) {
|
||||||
|
Throwable t = e.getCause();
|
||||||
|
if (t instanceof IOException) throw (IOException) t;
|
||||||
|
if (t instanceof IllegalArgumentException) throw (IllegalArgumentException) t;
|
||||||
|
throw new IOException(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Only update some of the online players each tick to minimize performance impact on the server-thread.
|
||||||
|
* Only call this method on the server-thread.
|
||||||
|
*/
|
||||||
|
private void updateSomePlayers() {
|
||||||
|
int onlinePlayerCount = onlinePlayerList.size();
|
||||||
|
if (onlinePlayerCount == 0) return;
|
||||||
|
|
||||||
|
int playersToBeUpdated = onlinePlayerCount / 20; //with 20 tps, each player is updated once a second
|
||||||
|
if (playersToBeUpdated == 0) playersToBeUpdated = 1;
|
||||||
|
|
||||||
|
for (int i = 0; i < playersToBeUpdated; i++) {
|
||||||
|
playerUpdateIndex++;
|
||||||
|
if (playerUpdateIndex >= 20 && playerUpdateIndex >= onlinePlayerCount) playerUpdateIndex = 0;
|
||||||
|
|
||||||
|
if (playerUpdateIndex < onlinePlayerCount) {
|
||||||
|
onlinePlayerList.get(playerUpdateIndex).update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector3d fromSpongePoweredVector(org.spongepowered.math.vector.Vector3d vec) {
|
||||||
|
return new Vector3d(vec.getX(), vec.getY(), vec.getZ());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector3i fromSpongePoweredVector(org.spongepowered.math.vector.Vector3i vec) {
|
||||||
|
return new Vector3i(vec.getX(), vec.getY(), vec.getZ());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector2i fromSpongePoweredVector(org.spongepowered.math.vector.Vector2i vec) {
|
||||||
|
return new Vector2i(vec.getX(), vec.getY());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"plugins": [
|
||||||
|
{
|
||||||
|
"loader": "java_plain",
|
||||||
|
"id": "bluemap",
|
||||||
|
"name": "BlueMap",
|
||||||
|
"version": "${version}",
|
||||||
|
"main-class": "de.bluecolored.bluemap.sponge8.SpongePlugin",
|
||||||
|
"description": "A 3d-map of your Minecraft worlds view-able in your browser using three.js (WebGL)",
|
||||||
|
"links": {
|
||||||
|
"homepage": "https://bluecolo.red/bluemap",
|
||||||
|
"source": "https://github.com/BlueMap-Minecraft/BlueMap",
|
||||||
|
"issues": "https://github.com/BlueMap-Minecraft/BlueMap/issues"
|
||||||
|
},
|
||||||
|
"contributors": [
|
||||||
|
{
|
||||||
|
"name": "Blue (TBlueF, Lukas Rieger)",
|
||||||
|
"description": "Lead Developer"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dependencies": [
|
||||||
|
{
|
||||||
|
"id": "spongeapi",
|
||||||
|
"version": "8.0.0",
|
||||||
|
"load-order": "AFTER",
|
||||||
|
"optional": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,4 @@
|
|||||||
|
accept-download: false
|
||||||
|
renderThreadCount: -2
|
||||||
|
metrics: false
|
||||||
|
data: "bluemap"
|
@ -0,0 +1,24 @@
|
|||||||
|
## ##
|
||||||
|
## BlueMap ##
|
||||||
|
## Core-Config ##
|
||||||
|
## ##
|
||||||
|
|
||||||
|
# By changing the setting (accept-download) below to TRUE you are indicating that you have accepted mojang's EULA (https://account.mojang.com/documents/minecraft_eula),
|
||||||
|
# you confirm that you own a license to Minecraft (Java Edition)
|
||||||
|
# and you agree that BlueMap will download and use a minecraft-client file (depending on the minecraft-version) from mojangs servers (https://launcher.mojang.com/) for you.
|
||||||
|
# This file contains resources that belong to mojang and you must not redistribute it or do anything else that is not compliant with mojang's EULA.
|
||||||
|
# BlueMap uses resources in this file to generate the 3D-Models used for the map and texture them. (BlueMap will not work without those resources.)
|
||||||
|
# %datetime-iso%
|
||||||
|
accept-download: false
|
||||||
|
|
||||||
|
# This changes the amount of threads that BlueMap will use to render the maps.
|
||||||
|
# A higher value can improve render-speed but could impact performance on the host machine.
|
||||||
|
# This should be always below or equal to the number of available processor-cores.
|
||||||
|
# Zero or a negative value means the amount of of available processor-cores subtracted by the value.
|
||||||
|
# (So a value of -2 with 6 cores results in 4 render-processes)
|
||||||
|
# Default is -2
|
||||||
|
renderThreadCount: -2
|
||||||
|
|
||||||
|
# The folder where bluemap saves data-files it needs during runtime or to save e.g. the render-progress to resume it later.
|
||||||
|
# Default is "bluemap"
|
||||||
|
data: "bluemap"
|
@ -0,0 +1,5 @@
|
|||||||
|
liveUpdates: true
|
||||||
|
skinDownload: false
|
||||||
|
hiddenGameModes: []
|
||||||
|
hideInvisible: true
|
||||||
|
hideSneaking: false
|
@ -0,0 +1,27 @@
|
|||||||
|
## ##
|
||||||
|
## BlueMap ##
|
||||||
|
## Plugin-Config ##
|
||||||
|
## ##
|
||||||
|
|
||||||
|
# If the server should send live-updates and player-positions.
|
||||||
|
# This only works if the integrated webserver is enabled.
|
||||||
|
# Default is true
|
||||||
|
liveUpdates: true
|
||||||
|
|
||||||
|
# Download the skin from mojang-serves when a player joins your server, so it can be used for the player-markers.
|
||||||
|
# Default is false
|
||||||
|
skinDownload: false
|
||||||
|
|
||||||
|
# A list of gamemodes that will prevent a player from appearing on the map.
|
||||||
|
# Possible values are: survival, creative, spectator, adventure
|
||||||
|
hiddenGameModes: [
|
||||||
|
"spectator"
|
||||||
|
]
|
||||||
|
|
||||||
|
# If this is true, players that have an invisibility (potion-)effect will be hidden on the map.
|
||||||
|
# Default is true
|
||||||
|
hideInvisible: true
|
||||||
|
|
||||||
|
# If this is true, players that are sneaking will be hidden on the map.
|
||||||
|
# Default is false
|
||||||
|
hideSneaking: false
|
@ -0,0 +1,3 @@
|
|||||||
|
webroot: "bluemap/web"
|
||||||
|
useCookies: true
|
||||||
|
maps: []
|
@ -0,0 +1,126 @@
|
|||||||
|
## ##
|
||||||
|
## BlueMap ##
|
||||||
|
## Render-Config ##
|
||||||
|
## ##
|
||||||
|
|
||||||
|
# The folder (webroot) where the map-data and web-application files will be saved.
|
||||||
|
# Default is "bluemap/web"
|
||||||
|
webroot: "bluemap/web"
|
||||||
|
|
||||||
|
# If the web-application should use cookies to save the configurations of a user.
|
||||||
|
# Default is true
|
||||||
|
useCookies: true
|
||||||
|
|
||||||
|
# This is an array with multiple configured maps.
|
||||||
|
# You can define multiple maps, for different worlds with different render-settings here
|
||||||
|
maps: [
|
||||||
|
|
||||||
|
{
|
||||||
|
# The id of this map
|
||||||
|
# Should only contain word-charactes: [a-zA-Z0-9_]
|
||||||
|
# Changing this value breaks your existing renders.
|
||||||
|
id: "world"
|
||||||
|
|
||||||
|
# The name of this map
|
||||||
|
# This defines the display name of this map, you can change this at any time.
|
||||||
|
# Default is the id of this map
|
||||||
|
name: "World"
|
||||||
|
|
||||||
|
# The path to the save-folder of the world to render.
|
||||||
|
world: "world"
|
||||||
|
|
||||||
|
# The position on the world where the map will be centered if you open it.
|
||||||
|
# You can change this at any time.
|
||||||
|
# This defaults to the world-spawn if you don't set it.
|
||||||
|
#startPos: [500, -820]
|
||||||
|
|
||||||
|
# The color of thy sky as a hex-color
|
||||||
|
# You can change this at any time.
|
||||||
|
# Default is "#7dabff"
|
||||||
|
skyColor: "#7dabff"
|
||||||
|
|
||||||
|
# Defines the ambient light-strength that every block is recieving, regardless of the sunlight/blocklight.
|
||||||
|
# 0 is no ambient light, 1 is fully lighted.
|
||||||
|
# You can change this at any time.
|
||||||
|
# Default is 0
|
||||||
|
ambientLight: 0
|
||||||
|
|
||||||
|
# If this is false, BlueMap tries to omit all blocks that are not visible from above-ground.
|
||||||
|
# More specific: Block-Faces that have a sunlight/skylight value of 0 are removed.
|
||||||
|
# This improves the performance of the map on slower devices by a lot, but might cause some blocks to disappear that should normally be visible.
|
||||||
|
# Changing this value requires a re-render of the map.
|
||||||
|
# Default is false
|
||||||
|
renderCaves: false
|
||||||
|
|
||||||
|
# With the below values you can limit the map-render.
|
||||||
|
# This can be used to ignore the nethers ceiling or render only a certain part of a world.
|
||||||
|
# Changing this values might require a re-render of the map, already rendered tiles outside the limits will not be deleted.
|
||||||
|
# Default is no min or max value (= infinite bounds)
|
||||||
|
#minX: -4000
|
||||||
|
#maxX: 4000
|
||||||
|
#minZ: -4000
|
||||||
|
#maxZ: 4000
|
||||||
|
#minY: 50
|
||||||
|
#maxY: 126
|
||||||
|
|
||||||
|
# Using this, BlueMap pretends that every Block out of the defined render-bounds is AIR,
|
||||||
|
# this means you can see the blocks where the world is cut (instead of having a see-through/xray view).
|
||||||
|
# This has only an effect if you set some render-bounds above.
|
||||||
|
# Changing this value requires a re-render of the map.
|
||||||
|
# Default is true
|
||||||
|
renderEdges: true
|
||||||
|
|
||||||
|
# With this set to true, the generated files for this world are compressed using gzip to save A LOT of space.
|
||||||
|
# Files will be only 5% as big with compression!
|
||||||
|
# Note: If you are using NGINX or Apache to host your map, you can configure them to serve the compressed files directly.
|
||||||
|
# This is much better than disabling the compression.
|
||||||
|
# Changing this value requires a re-render of the map.
|
||||||
|
# Default is true
|
||||||
|
useCompression: true
|
||||||
|
|
||||||
|
# Normally BlueMap detects if a chunk has not yet generated it's light-data and omits rendering those chunks.
|
||||||
|
# If this is set to true BlueMap will render Chunks even if there is no light-data!
|
||||||
|
# This can be usefull for example if some mod prevents light-data from being saved correctly.
|
||||||
|
# However, this also has a few drawbacks:
|
||||||
|
# - For those chunks, every block will always be fully lit
|
||||||
|
# - Night-mode might not work correctly
|
||||||
|
# - Caves will always be rendered (ignoring the 'renderCaves' setting)
|
||||||
|
# Default is false
|
||||||
|
ignoreMissingLightData: false
|
||||||
|
}
|
||||||
|
|
||||||
|
# Here another example for the End-Map
|
||||||
|
# Things we don't want to change from default we can just omit
|
||||||
|
{
|
||||||
|
id: "end"
|
||||||
|
name: "End"
|
||||||
|
world: "world/DIM1"
|
||||||
|
|
||||||
|
# We dont want a blue sky in the end
|
||||||
|
skyColor: "#080010"
|
||||||
|
|
||||||
|
# In the end is no sky-light, so we need to enable this or we won't see anything.
|
||||||
|
renderCaves: true
|
||||||
|
|
||||||
|
# Same here, we don't want a dark map. But not completely lighted, so we see the effect of e.g torches.
|
||||||
|
ambientLight: 0.6
|
||||||
|
}
|
||||||
|
|
||||||
|
# Here another example for the Nether-Map
|
||||||
|
{
|
||||||
|
id: "nether"
|
||||||
|
name: "Nether"
|
||||||
|
world: "world/DIM-1"
|
||||||
|
|
||||||
|
skyColor: "#290000"
|
||||||
|
|
||||||
|
renderCaves: true
|
||||||
|
ambientLight: 0.6
|
||||||
|
|
||||||
|
# We slice the whole world at y:90 so every block above 90 will be air.
|
||||||
|
# This way we don't render the nethers ceiling.
|
||||||
|
maxY: 90
|
||||||
|
renderEdges: true
|
||||||
|
}
|
||||||
|
|
||||||
|
]
|
@ -0,0 +1,4 @@
|
|||||||
|
enabled: true
|
||||||
|
webroot: "bluemap/web"
|
||||||
|
port: 8100
|
||||||
|
maxConnectionCount: 100
|
@ -0,0 +1,29 @@
|
|||||||
|
## ##
|
||||||
|
## BlueMap ##
|
||||||
|
## Webserver-Config ##
|
||||||
|
## ##
|
||||||
|
|
||||||
|
# With this setting you can disable the integrated web-server.
|
||||||
|
# This is usefull if you want to only render the map-data for later use, or if you setup your own webserver.
|
||||||
|
# Default is enabled
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
# The webroot that the server will host to the web.
|
||||||
|
# Usually this should be set to the same directory like in the render.conf!
|
||||||
|
# Default is "bluemap/web"
|
||||||
|
webroot: "bluemap/web"
|
||||||
|
|
||||||
|
# The IP-Adress that the webserver binds to.
|
||||||
|
# Use "0.0.0.0" to bind to all available local adresses.
|
||||||
|
# If you only want to access it locally use "localhost".
|
||||||
|
# Default is "0.0.0.0"
|
||||||
|
#ip: "localhost"
|
||||||
|
#ip: "123.45.6.78"
|
||||||
|
|
||||||
|
# The port that the webserver listenes to.
|
||||||
|
# Default is 8100
|
||||||
|
port: 8100
|
||||||
|
|
||||||
|
# Max number of simultaneous connections that the webserver allows
|
||||||
|
# Default is 100
|
||||||
|
maxConnectionCount: 100
|
@ -18,6 +18,7 @@ include ':BlueMapCommon'
|
|||||||
|
|
||||||
include ':cli'
|
include ':cli'
|
||||||
include ':sponge-7.2.0'
|
include ':sponge-7.2.0'
|
||||||
|
include ':sponge-8.0.0'
|
||||||
include ':spigot'
|
include ':spigot'
|
||||||
|
|
||||||
include ':forge-1.16.2'
|
include ':forge-1.16.2'
|
||||||
@ -35,6 +36,7 @@ project(':BlueMapCommon').projectDir = "$rootDir/BlueMapCommon" as File
|
|||||||
|
|
||||||
project(':cli').projectDir = "$rootDir/implementations/cli" as File
|
project(':cli').projectDir = "$rootDir/implementations/cli" as File
|
||||||
project(':sponge-7.2.0').projectDir = "$rootDir/implementations/sponge-7.2.0" as File
|
project(':sponge-7.2.0').projectDir = "$rootDir/implementations/sponge-7.2.0" as File
|
||||||
|
project(':sponge-8.0.0').projectDir = "$rootDir/implementations/sponge-8.0.0" as File
|
||||||
project(':spigot').projectDir = "$rootDir/implementations/spigot" as File
|
project(':spigot').projectDir = "$rootDir/implementations/spigot" as File
|
||||||
|
|
||||||
project(':forge-1.16.2').projectDir = "$rootDir/implementations/forge-1.16.2" as File
|
project(':forge-1.16.2').projectDir = "$rootDir/implementations/forge-1.16.2" as File
|
||||||
|
Loading…
Reference in New Issue
Block a user