Merge branch 'master' of https://github.com/boy0001/FastAsyncWorldedit
This commit is contained in:
commit
fd83406e29
3
.gitignore
vendored
3
.gitignore
vendored
@ -19,6 +19,7 @@ gradle.log
|
|||||||
/forge189/build
|
/forge189/build
|
||||||
/forge1710/build
|
/forge1710/build
|
||||||
/sponge/build
|
/sponge/build
|
||||||
|
/sponge111/build
|
||||||
/bukkit/build
|
/bukkit/build
|
||||||
/bukkit0/build
|
/bukkit0/build
|
||||||
/bukkit19/build
|
/bukkit19/build
|
||||||
@ -27,4 +28,4 @@ build
|
|||||||
/mvn
|
/mvn
|
||||||
spigot-1.10
|
spigot-1.10
|
||||||
wiki_permissions.md
|
wiki_permissions.md
|
||||||
/textures
|
/textures
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
rootProject.name = 'FastAsyncWorldEdit'
|
rootProject.name = 'FastAsyncWorldEdit'
|
||||||
|
|
||||||
include 'core', 'bukkit', 'favs', 'nukkit', 'forge1710', 'forge189', 'forge194', 'forge110', 'forge111', 'sponge', 'forge112'
|
include 'core', 'bukkit', 'favs', 'nukkit', 'forge1710', 'forge189', 'forge194', 'forge110', 'forge111', 'sponge', 'forge112', 'sponge111'
|
2
sponge111/.gitignore
vendored
Normal file
2
sponge111/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
/.gradle/
|
||||||
|
/bin/
|
109
sponge111/build.gradle
Normal file
109
sponge111/build.gradle
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
buildscript {
|
||||||
|
repositories {
|
||||||
|
jcenter()
|
||||||
|
maven {
|
||||||
|
name = "forge"
|
||||||
|
url = "http://files.minecraftforge.net/maven"
|
||||||
|
}
|
||||||
|
maven {
|
||||||
|
name = 'minecrell'
|
||||||
|
url = 'http://repo.minecrell.net/releases'
|
||||||
|
}
|
||||||
|
maven {url = "https://oss.sonatype.org/content/repositories/snapshots/"}
|
||||||
|
maven {url = "http://repo.minecrell.net/snapshots"}
|
||||||
|
maven { url = "http://files.minecraftforge.net/maven" }
|
||||||
|
maven { url = "http://repo.minecrell.net/releases" }
|
||||||
|
maven { url = "https://oss.sonatype.org/content/repositories/snapshots/" }
|
||||||
|
}
|
||||||
|
dependencies {
|
||||||
|
classpath 'net.minecrell:VanillaGradle:2.0.3_1'
|
||||||
|
classpath 'net.minecraftforge.gradle:ForgeGradle:2.2-SNAPSHOT'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
id 'org.spongepowered.plugin' version '0.6'
|
||||||
|
}
|
||||||
|
|
||||||
|
apply plugin: 'net.minecrell.vanilla.server.library'
|
||||||
|
apply plugin: 'com.github.johnrengelman.shadow'
|
||||||
|
|
||||||
|
sourceCompatibility = 1.8
|
||||||
|
targetCompatibility = 1.8
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
flatDir {dirs 'lib'}
|
||||||
|
maven {
|
||||||
|
name = 'forge'
|
||||||
|
url = 'http://files.minecraftforge.net/maven'
|
||||||
|
}
|
||||||
|
maven {
|
||||||
|
name = "Sponge"
|
||||||
|
url = "https://repo.spongepowered.org/maven"
|
||||||
|
}
|
||||||
|
maven {
|
||||||
|
name = "Sponge Metrics"
|
||||||
|
url = "http://repo.mcstats.org/content/repositories/releases/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compile project(':core')
|
||||||
|
compile 'org.spongepowered:spongeapi:6.0.0-SNAPSHOT'
|
||||||
|
compile 'org.spongepowered:mixin:0.6.1-SNAPSHOT'
|
||||||
|
compile 'com.sk89q.worldedit:worldedit-sponge:6.1.7-SNAPSHOT'
|
||||||
|
compile name: 'worldedit-core-6.1.7-SNAPSHOT-dist'
|
||||||
|
}
|
||||||
|
|
||||||
|
minecraft {
|
||||||
|
version = "1.11"
|
||||||
|
mappings = "snapshot_20161116"
|
||||||
|
runDir = 'run'
|
||||||
|
}
|
||||||
|
|
||||||
|
project.archivesBaseName = "${project.archivesBaseName}-mc${minecraft.version}"
|
||||||
|
|
||||||
|
processResources {
|
||||||
|
from(sourceSets.main.resources.srcDirs) {
|
||||||
|
expand 'version': project.version,
|
||||||
|
'mcVersion': project.minecraft.version
|
||||||
|
exclude 'mcmod.info'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
shadowJar {
|
||||||
|
relocate 'org.yaml.snakeyaml', 'com.boydti.fawe.yaml'
|
||||||
|
dependencies {
|
||||||
|
include(dependency(':core'))
|
||||||
|
include(dependency('com.github.luben:zstd-jni:1.1.1'))
|
||||||
|
// include(dependency('org.javassist:javassist:3.22.0-CR1'))
|
||||||
|
include(dependency('co.aikar:fastutil-lite:1.0'))
|
||||||
|
include(dependency(name: 'worldedit-core-6.1.7-SNAPSHOT-dist'))
|
||||||
|
include(dependency('com.sk89q.worldedit:worldedit-sponge:6.1.7-SNAPSHOT'))
|
||||||
|
include(dependency('org.yaml:snakeyaml:1.16'))
|
||||||
|
}
|
||||||
|
archiveName = "${parent.name}-${project.name}-${parent.version}.jar"
|
||||||
|
destinationDir = file '../target'
|
||||||
|
}
|
||||||
|
shadowJar.doLast {
|
||||||
|
task ->
|
||||||
|
ant.checksum file: task.archivePath
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
reobf {
|
||||||
|
shadowJar {
|
||||||
|
mappingType = 'SEARGE'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
task deobfJar(type: Jar) {
|
||||||
|
from sourceSets.main.output
|
||||||
|
classifier = 'dev'
|
||||||
|
}
|
||||||
|
|
||||||
|
artifacts {
|
||||||
|
archives deobfJar
|
||||||
|
}
|
||||||
|
|
||||||
|
build.dependsOn(shadowJar)
|
BIN
sponge111/lib/worldedit-core-6.1.7-SNAPSHOT-dist.jar
Normal file
BIN
sponge111/lib/worldedit-core-6.1.7-SNAPSHOT-dist.jar
Normal file
Binary file not shown.
62
sponge111/src/main/java/com/boydti/fawe/SpongeCommand.java
Normal file
62
sponge111/src/main/java/com/boydti/fawe/SpongeCommand.java
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
package com.boydti.fawe;
|
||||||
|
|
||||||
|
import com.boydti.fawe.config.BBC;
|
||||||
|
import com.boydti.fawe.object.FaweCommand;
|
||||||
|
import com.boydti.fawe.object.FawePlayer;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import org.spongepowered.api.command.CommandCallable;
|
||||||
|
import org.spongepowered.api.command.CommandException;
|
||||||
|
import org.spongepowered.api.command.CommandResult;
|
||||||
|
import org.spongepowered.api.command.CommandSource;
|
||||||
|
import org.spongepowered.api.text.Text;
|
||||||
|
import org.spongepowered.api.world.Location;
|
||||||
|
import org.spongepowered.api.world.World;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Jesse on 4/2/2016.
|
||||||
|
*/
|
||||||
|
public class SpongeCommand implements CommandCallable {
|
||||||
|
|
||||||
|
private final FaweCommand cmd;
|
||||||
|
|
||||||
|
public SpongeCommand(final FaweCommand cmd) {
|
||||||
|
this.cmd = cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommandResult process(CommandSource source, String args) throws CommandException {
|
||||||
|
final FawePlayer plr = Fawe.imp().wrap(source);
|
||||||
|
if (!source.hasPermission(this.cmd.getPerm())) {
|
||||||
|
BBC.NO_PERM.send(plr, this.cmd.getPerm());
|
||||||
|
return CommandResult.success();
|
||||||
|
}
|
||||||
|
this.cmd.executeSafe(plr, args.split(" "));
|
||||||
|
return CommandResult.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getSuggestions(CommandSource source, String arguments, @Nullable Location<World> targetPosition) throws CommandException {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean testPermission(CommandSource source) {return true;}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<Text> getShortDescription(CommandSource source) {
|
||||||
|
return Optional.of(Text.of("Various"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<Text> getHelp(CommandSource source) {
|
||||||
|
return Optional.of(Text.of("/" + this.cmd));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Text getUsage(final CommandSource cmd) {
|
||||||
|
return Text.of("/<stream|wea|select>");
|
||||||
|
}
|
||||||
|
}
|
153
sponge111/src/main/java/com/boydti/fawe/sponge/FaweSponge.java
Normal file
153
sponge111/src/main/java/com/boydti/fawe/sponge/FaweSponge.java
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
package com.boydti.fawe.sponge;
|
||||||
|
|
||||||
|
import com.boydti.fawe.Fawe;
|
||||||
|
import com.boydti.fawe.IFawe;
|
||||||
|
import com.boydti.fawe.SpongeCommand;
|
||||||
|
import com.boydti.fawe.config.BBC;
|
||||||
|
import com.boydti.fawe.object.FaweCommand;
|
||||||
|
import com.boydti.fawe.object.FawePlayer;
|
||||||
|
import com.boydti.fawe.object.FaweQueue;
|
||||||
|
import com.boydti.fawe.regions.FaweMaskManager;
|
||||||
|
import com.boydti.fawe.util.MainUtil;
|
||||||
|
import com.boydti.fawe.util.TaskManager;
|
||||||
|
import com.sk89q.worldedit.sponge.chat.SpongeChatManager;
|
||||||
|
import com.sk89q.worldedit.world.World;
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.UUID;
|
||||||
|
import org.spongepowered.api.Sponge;
|
||||||
|
import org.spongepowered.api.entity.living.player.Player;
|
||||||
|
import org.spongepowered.api.profile.GameProfile;
|
||||||
|
import org.spongepowered.api.profile.GameProfileManager;
|
||||||
|
import org.spongepowered.api.text.serializer.TextSerializers;
|
||||||
|
|
||||||
|
|
||||||
|
import static org.spongepowered.api.Sponge.getGame;
|
||||||
|
|
||||||
|
public class FaweSponge implements IFawe {
|
||||||
|
|
||||||
|
public final SpongeMain plugin;
|
||||||
|
|
||||||
|
public FaweSponge instance;
|
||||||
|
|
||||||
|
public FaweSponge(SpongeMain plugin) {
|
||||||
|
instance = this;
|
||||||
|
this.plugin = plugin;
|
||||||
|
try {
|
||||||
|
Fawe.set(this);
|
||||||
|
Fawe.setupInjector();
|
||||||
|
com.sk89q.worldedit.sponge.SpongePlayer.inject();
|
||||||
|
Fawe.get().setChatManager(new SpongeChatManager());
|
||||||
|
} catch (final Throwable e) {
|
||||||
|
MainUtil.handleError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void debug(String message) {
|
||||||
|
message = BBC.color(message);
|
||||||
|
Sponge.getServer().getConsole().sendMessage(TextSerializers.LEGACY_FORMATTING_CODE.deserialize(BBC.color(message)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public File getDirectory() {
|
||||||
|
return new File("config/FastAsyncWorldEdit");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setupCommand(String label, FaweCommand cmd) {
|
||||||
|
getGame().getCommandManager().register(plugin, new SpongeCommand(cmd), label);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FawePlayer wrap(Object obj) {
|
||||||
|
if (obj.getClass() == String.class) {
|
||||||
|
String name = (String) obj;
|
||||||
|
FawePlayer existing = Fawe.get().getCachedPlayer(name);
|
||||||
|
if (existing != null) {
|
||||||
|
return existing;
|
||||||
|
}
|
||||||
|
Player player = Sponge.getServer().getPlayer(name).orElseGet(null);
|
||||||
|
return player != null ? new SpongePlayer(player) : null;
|
||||||
|
} else if (obj instanceof Player) {
|
||||||
|
Player player = (Player) obj;
|
||||||
|
FawePlayer existing = Fawe.get().getCachedPlayer(player.getName());
|
||||||
|
return existing != null ? existing : new SpongePlayer(player);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setupVault() {
|
||||||
|
debug("Permission hook not implemented yet!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TaskManager getTaskManager() {
|
||||||
|
return new SpongeTaskMan(plugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FaweQueue getNewQueue(World world, boolean fast) {
|
||||||
|
return new com.boydti.fawe.sponge.v1_11.SpongeQueue_1_11(getWorldName(world));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FaweQueue getNewQueue(String world, boolean fast) {
|
||||||
|
return new com.boydti.fawe.sponge.v1_11.SpongeQueue_1_11(world);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getWorldName(World world) {
|
||||||
|
return world.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<FaweMaskManager> getMaskManagers() {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startMetrics() {
|
||||||
|
try {
|
||||||
|
SpongeMetrics metrics = new SpongeMetrics(Sponge.getGame(), Sponge.getPluginManager().fromInstance(plugin).get());
|
||||||
|
metrics.start();
|
||||||
|
} catch (Throwable e) {
|
||||||
|
debug("[FAWE] &cFailed to load up metrics.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPlatform() {
|
||||||
|
return "sponge";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UUID getUUID(String name) {
|
||||||
|
try {
|
||||||
|
GameProfileManager pm = Sponge.getServer().getGameProfileManager();
|
||||||
|
GameProfile profile = pm.get(name).get();
|
||||||
|
return profile != null ? profile.getUniqueId() : null;
|
||||||
|
} catch (Exception e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName(UUID uuid) {
|
||||||
|
try {
|
||||||
|
GameProfileManager pm = Sponge.getServer().getGameProfileManager();
|
||||||
|
GameProfile profile = pm.get(uuid).get();
|
||||||
|
return profile != null ? profile.getName().orElse(null) : null;
|
||||||
|
} catch (Exception e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getBlocksHubApi() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,62 @@
|
|||||||
|
package com.boydti.fawe.sponge;
|
||||||
|
|
||||||
|
import com.boydti.fawe.Fawe;
|
||||||
|
import com.boydti.fawe.config.Settings;
|
||||||
|
import com.boydti.fawe.object.FawePlayer;
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.spongepowered.api.Game;
|
||||||
|
import org.spongepowered.api.Server;
|
||||||
|
import org.spongepowered.api.entity.living.player.Player;
|
||||||
|
import org.spongepowered.api.event.Listener;
|
||||||
|
import org.spongepowered.api.event.Order;
|
||||||
|
import org.spongepowered.api.event.game.state.GamePreInitializationEvent;
|
||||||
|
import org.spongepowered.api.event.network.ClientConnectionEvent;
|
||||||
|
import org.spongepowered.api.plugin.Plugin;
|
||||||
|
import org.spongepowered.api.plugin.PluginContainer;
|
||||||
|
import org.spongepowered.api.profile.GameProfileManager;
|
||||||
|
|
||||||
|
@Plugin(id = "fastasyncworldedit", name = " FastAsyncWorldEdit", description = "fawe", url = "https://github.com/boy0001/FastAsyncWorldedit", version = "development", authors = "Empire92")
|
||||||
|
public class SpongeMain {
|
||||||
|
@Inject
|
||||||
|
public PluginContainer plugin;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private Logger logger;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private Game game;
|
||||||
|
private Server server;
|
||||||
|
|
||||||
|
private GameProfileManager resolver;
|
||||||
|
|
||||||
|
public Game getGame() {
|
||||||
|
return this.game;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Server getServer() {
|
||||||
|
return this.server;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GameProfileManager getResolver() {
|
||||||
|
if (this.resolver == null) {
|
||||||
|
this.resolver = this.game.getServer().getGameProfileManager();
|
||||||
|
}
|
||||||
|
return this.resolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Listener(order = Order.PRE)
|
||||||
|
public void onGamePreInit(GamePreInitializationEvent event) {
|
||||||
|
this.server = this.game.getServer();
|
||||||
|
new FaweSponge(this);
|
||||||
|
Settings.IMP.QUEUE.PARALLEL_THREADS = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Listener
|
||||||
|
public void onQuit(ClientConnectionEvent.Disconnect event) {
|
||||||
|
Player player = event.getTargetEntity();
|
||||||
|
FawePlayer fp = FawePlayer.wrap(player);
|
||||||
|
fp.unregister();
|
||||||
|
Fawe.get().unregister(player.getName());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,519 @@
|
|||||||
|
package com.boydti.fawe.sponge;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2011-2013 Tyler Blair. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification, are
|
||||||
|
* permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||||
|
* conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||||
|
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||||
|
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||||
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* The views and conclusions contained in the software and documentation are those of the
|
||||||
|
* authors and contributors and should not be interpreted as representing official policies,
|
||||||
|
* either expressed or implied, of anybody else.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import com.boydti.fawe.Fawe;
|
||||||
|
import com.boydti.fawe.object.io.FastByteArrayOutputStream;
|
||||||
|
import com.boydti.fawe.util.MainUtil;
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.net.Proxy;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLConnection;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.zip.GZIPOutputStream;
|
||||||
|
import ninja.leaping.configurate.commented.CommentedConfigurationNode;
|
||||||
|
import ninja.leaping.configurate.hocon.HoconConfigurationLoader;
|
||||||
|
import ninja.leaping.configurate.loader.ConfigurationLoader;
|
||||||
|
import org.spongepowered.api.Game;
|
||||||
|
import org.spongepowered.api.plugin.PluginContainer;
|
||||||
|
import org.spongepowered.api.scheduler.Task;
|
||||||
|
|
||||||
|
public class SpongeMetrics {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current revision number
|
||||||
|
*/
|
||||||
|
private final static int REVISION = 7;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base url of the metrics domain
|
||||||
|
*/
|
||||||
|
private static final String BASE_URL = "http://report.mcstats.org";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The url used to report a server's status
|
||||||
|
*/
|
||||||
|
private static final String REPORT_URL = "/plugin/%s";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interval of time to ping (in minutes)
|
||||||
|
*/
|
||||||
|
private static final int PING_INTERVAL = 15;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The game data is being sent for
|
||||||
|
*/
|
||||||
|
private final Game game;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The plugin this metrics submits for
|
||||||
|
*/
|
||||||
|
private final PluginContainer plugin;
|
||||||
|
/**
|
||||||
|
* Lock for synchronization
|
||||||
|
*/
|
||||||
|
private final Object optOutLock = new Object();
|
||||||
|
/**
|
||||||
|
* The plugin configuration file
|
||||||
|
*/
|
||||||
|
private CommentedConfigurationNode config;
|
||||||
|
/**
|
||||||
|
* The configuration loader
|
||||||
|
*/
|
||||||
|
private ConfigurationLoader<CommentedConfigurationNode> configurationLoader;
|
||||||
|
/**
|
||||||
|
* The plugin configuration file
|
||||||
|
*/
|
||||||
|
private File configurationFile;
|
||||||
|
/**
|
||||||
|
* Unique server id
|
||||||
|
*/
|
||||||
|
private String guid;
|
||||||
|
/**
|
||||||
|
* Debug mode
|
||||||
|
*/
|
||||||
|
private boolean debug;
|
||||||
|
/**
|
||||||
|
* The scheduled task
|
||||||
|
*/
|
||||||
|
private volatile Task task = null;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public SpongeMetrics(final Game game, final PluginContainer plugin) throws IOException {
|
||||||
|
if (plugin == null) {
|
||||||
|
throw new IllegalArgumentException("Plugin cannot be null");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.game = game;
|
||||||
|
this.plugin = plugin;
|
||||||
|
|
||||||
|
loadConfiguration();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GZip compress a string of bytes
|
||||||
|
*
|
||||||
|
* @param input
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static byte[] gzip(final String input) {
|
||||||
|
final FastByteArrayOutputStream baos = new FastByteArrayOutputStream();
|
||||||
|
GZIPOutputStream gzos = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
gzos = new GZIPOutputStream(baos);
|
||||||
|
gzos.write(input.getBytes("UTF-8"));
|
||||||
|
} catch (final IOException e) {
|
||||||
|
MainUtil.handleError(e);
|
||||||
|
} finally {
|
||||||
|
if (gzos != null) {
|
||||||
|
try {
|
||||||
|
gzos.close();
|
||||||
|
} catch (final IOException ignore) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return baos.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends a json encoded key/value pair to the given string builder.
|
||||||
|
*
|
||||||
|
* @param json
|
||||||
|
* @param key
|
||||||
|
* @param value
|
||||||
|
* @throws java.io.UnsupportedEncodingException
|
||||||
|
*/
|
||||||
|
private static void appendJSONPair(final StringBuilder json, final String key, final String value) throws UnsupportedEncodingException {
|
||||||
|
boolean isValueNumeric = false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (value.equals("0") || !value.endsWith("0")) {
|
||||||
|
Double.parseDouble(value);
|
||||||
|
isValueNumeric = true;
|
||||||
|
}
|
||||||
|
} catch (final NumberFormatException e) {
|
||||||
|
isValueNumeric = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.charAt(json.length() - 1) != '{') {
|
||||||
|
json.append(',');
|
||||||
|
}
|
||||||
|
|
||||||
|
json.append(escapeJSON(key));
|
||||||
|
json.append(':');
|
||||||
|
|
||||||
|
if (isValueNumeric) {
|
||||||
|
json.append(value);
|
||||||
|
} else {
|
||||||
|
json.append(escapeJSON(value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Escape a string to create a valid JSON string
|
||||||
|
*
|
||||||
|
* @param text
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private static String escapeJSON(final String text) {
|
||||||
|
final StringBuilder builder = new StringBuilder();
|
||||||
|
|
||||||
|
builder.append('"');
|
||||||
|
for (int index = 0; index < text.length(); index++) {
|
||||||
|
final char chr = text.charAt(index);
|
||||||
|
|
||||||
|
switch (chr) {
|
||||||
|
case '"':
|
||||||
|
case '\\':
|
||||||
|
builder.append('\\');
|
||||||
|
builder.append(chr);
|
||||||
|
break;
|
||||||
|
case '\b':
|
||||||
|
builder.append("\\b");
|
||||||
|
break;
|
||||||
|
case '\t':
|
||||||
|
builder.append("\\t");
|
||||||
|
break;
|
||||||
|
case '\n':
|
||||||
|
builder.append("\\n");
|
||||||
|
break;
|
||||||
|
case '\r':
|
||||||
|
builder.append("\\r");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (chr < ' ') {
|
||||||
|
final String t = "000" + Integer.toHexString(chr);
|
||||||
|
builder.append("\\u" + t.substring(t.length() - 4));
|
||||||
|
} else {
|
||||||
|
builder.append(chr);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
builder.append('"');
|
||||||
|
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encode text as UTF-8
|
||||||
|
*
|
||||||
|
* @param text the text to encode
|
||||||
|
* @return the encoded text, as UTF-8
|
||||||
|
*/
|
||||||
|
private static String urlEncode(final String text) throws UnsupportedEncodingException {
|
||||||
|
return URLEncoder.encode(text, "UTF-8");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the configuration
|
||||||
|
*/
|
||||||
|
private void loadConfiguration() {
|
||||||
|
configurationFile = getConfigFile();
|
||||||
|
configurationLoader = HoconConfigurationLoader.builder().setFile(configurationFile).build();
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!configurationFile.exists()) {
|
||||||
|
configurationFile.createNewFile();
|
||||||
|
config = configurationLoader.load();
|
||||||
|
|
||||||
|
config.setComment("This contains settings for MCStats: http://mcstats.org");
|
||||||
|
config.getNode("mcstats.guid").setValue(UUID.randomUUID().toString());
|
||||||
|
config.getNode("mcstats.opt-out").setValue(false);
|
||||||
|
config.getNode("mcstats.debug").setValue(false);
|
||||||
|
|
||||||
|
configurationLoader.save(config);
|
||||||
|
} else {
|
||||||
|
config = configurationLoader.load();
|
||||||
|
}
|
||||||
|
|
||||||
|
guid = config.getNode("mcstats.guid").getString();
|
||||||
|
debug = config.getNode("mcstats.debug").getBoolean();
|
||||||
|
} catch (final IOException e) {
|
||||||
|
MainUtil.handleError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start measuring statistics. This will immediately create an async repeating task as the plugin and send the
|
||||||
|
* initial data to the metrics backend, and then after that it will post in increments of PING_INTERVAL * 1200
|
||||||
|
* ticks.
|
||||||
|
*
|
||||||
|
* @return True if statistics measuring is running, otherwise false.
|
||||||
|
*/
|
||||||
|
public boolean start() {
|
||||||
|
synchronized (optOutLock) {
|
||||||
|
// Did we opt out?
|
||||||
|
if (isOptOut()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is metrics already running?
|
||||||
|
if (task != null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Begin hitting the server with glorious data
|
||||||
|
final Task.Builder builder = game.getScheduler().createTaskBuilder();
|
||||||
|
builder.async().interval(PING_INTERVAL, TimeUnit.MINUTES).execute(new Runnable() {
|
||||||
|
|
||||||
|
private boolean firstPost = true;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
// This has to be synchronized or it can collide with the disable method.
|
||||||
|
synchronized (optOutLock) {
|
||||||
|
// Disable Task, if it is running and the server owner decided to opt-out
|
||||||
|
if (isOptOut() && (task != null)) {
|
||||||
|
task.cancel();
|
||||||
|
task = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We use the inverse of firstPost because if it is the first time we are posting,
|
||||||
|
// it is not a interval ping, so it evaluates to FALSE
|
||||||
|
// Each time thereafter it will evaluate to TRUE, i.e PING!
|
||||||
|
postPlugin(!firstPost);
|
||||||
|
|
||||||
|
// After the first post we set firstPost to false
|
||||||
|
// Each post thereafter will be a ping
|
||||||
|
firstPost = false;
|
||||||
|
} catch (final IOException e) {
|
||||||
|
if (debug) {
|
||||||
|
Fawe.debug("[Metrics] " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Has the server owner denied plugin metrics?
|
||||||
|
*
|
||||||
|
* @return true if metrics should be opted out of it
|
||||||
|
*/
|
||||||
|
public boolean isOptOut() {
|
||||||
|
synchronized (optOutLock) {
|
||||||
|
loadConfiguration();
|
||||||
|
|
||||||
|
return config.getNode("mcstats.opt-out").getBoolean();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enables metrics for the server by setting "opt-out" to false in the config file and starting the metrics task.
|
||||||
|
*
|
||||||
|
* @throws java.io.IOException
|
||||||
|
*/
|
||||||
|
public void enable() throws IOException {
|
||||||
|
// This has to be synchronized or it can collide with the check in the task.
|
||||||
|
synchronized (optOutLock) {
|
||||||
|
// Check if the server owner has already set opt-out, if not, set it.
|
||||||
|
if (isOptOut()) {
|
||||||
|
config.getNode("mcstats.opt-out").setValue(false);
|
||||||
|
configurationLoader.save(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable Task, if it is not running
|
||||||
|
if (task == null) {
|
||||||
|
start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disables metrics for the server by setting "opt-out" to true in the config file and canceling the metrics task.
|
||||||
|
*
|
||||||
|
* @throws java.io.IOException
|
||||||
|
*/
|
||||||
|
public void disable() throws IOException {
|
||||||
|
// This has to be synchronized or it can collide with the check in the task.
|
||||||
|
synchronized (optOutLock) {
|
||||||
|
// Check if the server owner has already set opt-out, if not, set it.
|
||||||
|
if (!isOptOut()) {
|
||||||
|
config.getNode("mcstats.opt-out").setValue(true);
|
||||||
|
configurationLoader.save(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disable Task, if it is running
|
||||||
|
if (task != null) {
|
||||||
|
task.cancel();
|
||||||
|
task = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the File object of the config file that should be used to store data such as the GUID and opt-out status
|
||||||
|
*
|
||||||
|
* @return the File object for the config file
|
||||||
|
*/
|
||||||
|
public File getConfigFile() {
|
||||||
|
// TODO configDir
|
||||||
|
final File configFolder = new File("config");
|
||||||
|
|
||||||
|
return new File(configFolder, "PluginMetrics.conf");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generic method that posts a plugin to the metrics website
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private void postPlugin(final boolean isPing) throws IOException {
|
||||||
|
// Server software specific section
|
||||||
|
final String pluginName = plugin.getName();
|
||||||
|
final boolean onlineMode = game.getServer().getOnlineMode(); // TRUE if online mode is enabled
|
||||||
|
final String pluginVersion = plugin.getVersion().get();
|
||||||
|
// TODO no visible way to get MC version at the moment
|
||||||
|
// TODO added by game.getPlatform().getMinecraftVersion() -- impl in 2.1
|
||||||
|
final String serverVersion = String.format("%s %s", "Sponge", game.getPlatform().getMinecraftVersion());
|
||||||
|
final int playersOnline = game.getServer().getOnlinePlayers().size();
|
||||||
|
|
||||||
|
// END server software specific section -- all code below does not use any code outside of this class / Java
|
||||||
|
|
||||||
|
// Construct the post data
|
||||||
|
final StringBuilder json = new StringBuilder(1024);
|
||||||
|
json.append('{');
|
||||||
|
|
||||||
|
// The plugin's description file containg all of the plugin data such as name, version, author, etc
|
||||||
|
appendJSONPair(json, "guid", guid);
|
||||||
|
appendJSONPair(json, "plugin_version", pluginVersion);
|
||||||
|
appendJSONPair(json, "server_version", serverVersion);
|
||||||
|
appendJSONPair(json, "players_online", Integer.toString(playersOnline));
|
||||||
|
|
||||||
|
// New data as of R6
|
||||||
|
final String osname = System.getProperty("os.name");
|
||||||
|
String osarch = System.getProperty("os.arch");
|
||||||
|
final String osversion = System.getProperty("os.version");
|
||||||
|
final String java_version = System.getProperty("java.version");
|
||||||
|
final int coreCount = Runtime.getRuntime().availableProcessors();
|
||||||
|
|
||||||
|
// normalize os arch .. amd64 -> x86_64
|
||||||
|
if (osarch.equals("amd64")) {
|
||||||
|
osarch = "x86_64";
|
||||||
|
}
|
||||||
|
|
||||||
|
appendJSONPair(json, "osname", osname);
|
||||||
|
appendJSONPair(json, "osarch", osarch);
|
||||||
|
appendJSONPair(json, "osversion", osversion);
|
||||||
|
appendJSONPair(json, "cores", Integer.toString(coreCount));
|
||||||
|
appendJSONPair(json, "auth_mode", onlineMode ? "1" : "0");
|
||||||
|
appendJSONPair(json, "java_version", java_version);
|
||||||
|
|
||||||
|
// If we're pinging, append it
|
||||||
|
if (isPing) {
|
||||||
|
appendJSONPair(json, "ping", "1");
|
||||||
|
}
|
||||||
|
|
||||||
|
// close json
|
||||||
|
json.append('}');
|
||||||
|
|
||||||
|
// Create the url
|
||||||
|
final URL url = new URL(BASE_URL + String.format(REPORT_URL, urlEncode(pluginName)));
|
||||||
|
|
||||||
|
// Connect to the website
|
||||||
|
URLConnection connection;
|
||||||
|
|
||||||
|
// Mineshafter creates a socks proxy, so we can safely bypass it
|
||||||
|
// It does not reroute POST requests so we need to go around it
|
||||||
|
if (isMineshafterPresent()) {
|
||||||
|
connection = url.openConnection(Proxy.NO_PROXY);
|
||||||
|
} else {
|
||||||
|
connection = url.openConnection();
|
||||||
|
}
|
||||||
|
|
||||||
|
final byte[] uncompressed = json.toString().getBytes();
|
||||||
|
final byte[] compressed = gzip(json.toString());
|
||||||
|
|
||||||
|
// Headers
|
||||||
|
connection.addRequestProperty("User-Agent", "MCStats/" + REVISION);
|
||||||
|
connection.addRequestProperty("Content-Type", "application/json");
|
||||||
|
connection.addRequestProperty("Content-Encoding", "gzip");
|
||||||
|
connection.addRequestProperty("Content-Length", Integer.toString(compressed.length));
|
||||||
|
connection.addRequestProperty("Accept", "application/json");
|
||||||
|
connection.addRequestProperty("Connection", "close");
|
||||||
|
|
||||||
|
connection.setDoOutput(true);
|
||||||
|
|
||||||
|
if (debug) {
|
||||||
|
Fawe.debug("[Metrics] Prepared request for " + pluginName + " uncompressed=" + uncompressed.length + " compressed=" + compressed.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the data
|
||||||
|
final OutputStream os = connection.getOutputStream();
|
||||||
|
os.write(compressed);
|
||||||
|
os.flush();
|
||||||
|
|
||||||
|
// Now read the response
|
||||||
|
final BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
|
||||||
|
String response = reader.readLine();
|
||||||
|
|
||||||
|
// close resources
|
||||||
|
os.close();
|
||||||
|
reader.close();
|
||||||
|
|
||||||
|
if ((response == null) || response.startsWith("ERR") || response.startsWith("7")) {
|
||||||
|
if (response == null) {
|
||||||
|
response = "null";
|
||||||
|
} else if (response.startsWith("7")) {
|
||||||
|
response = response.substring(response.startsWith("7,") ? 2 : 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IOException(response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if mineshafter is present. If it is, we need to bypass it to send POST requests
|
||||||
|
*
|
||||||
|
* @return true if mineshafter is installed on the server
|
||||||
|
*/
|
||||||
|
private boolean isMineshafterPresent() {
|
||||||
|
try {
|
||||||
|
Class.forName("mineshafter.MineServer");
|
||||||
|
return true;
|
||||||
|
} catch (final Exception e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,92 @@
|
|||||||
|
package com.boydti.fawe.sponge;
|
||||||
|
|
||||||
|
import com.boydti.fawe.config.BBC;
|
||||||
|
import com.boydti.fawe.object.FaweLocation;
|
||||||
|
import com.boydti.fawe.object.FawePlayer;
|
||||||
|
import com.boydti.fawe.wrappers.FakePlayer;
|
||||||
|
import com.sk89q.worldedit.WorldEdit;
|
||||||
|
import com.sk89q.worldedit.extension.platform.Capability;
|
||||||
|
import com.sk89q.worldedit.extension.platform.Platform;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.UUID;
|
||||||
|
import org.spongepowered.api.Sponge;
|
||||||
|
import org.spongepowered.api.entity.living.player.Player;
|
||||||
|
import org.spongepowered.api.text.Text;
|
||||||
|
import org.spongepowered.api.text.serializer.TextSerializers;
|
||||||
|
import org.spongepowered.api.text.title.Title;
|
||||||
|
import org.spongepowered.api.world.Location;
|
||||||
|
import org.spongepowered.api.world.World;
|
||||||
|
|
||||||
|
public class SpongePlayer extends FawePlayer<Player> {
|
||||||
|
public SpongePlayer(final Player parent) {
|
||||||
|
super(parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendTitle(String head, String sub) { // Not supported
|
||||||
|
Text headText = TextSerializers.LEGACY_FORMATTING_CODE.deserialize(BBC.color(head));
|
||||||
|
Text subText = TextSerializers.LEGACY_FORMATTING_CODE.deserialize(BBC.color(sub));
|
||||||
|
final Title title = Title.builder().title(headText).subtitle(subText).fadeIn(0).stay(60).fadeOut(20).build();
|
||||||
|
parent.sendTitle(title);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void resetTitle() { // Not supported
|
||||||
|
parent.resetTitle();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return this.parent.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UUID getUUID() {
|
||||||
|
return this.parent.getUniqueId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasPermission(final String perm) {
|
||||||
|
Object meta = getMeta(perm);
|
||||||
|
return meta instanceof Boolean ? (boolean) meta : this.parent.hasPermission(perm);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPermission(final String perm, final boolean flag) {
|
||||||
|
setMeta(perm, flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendMessage(final String message) {
|
||||||
|
this.parent.sendMessage(TextSerializers.LEGACY_FORMATTING_CODE.deserialize(BBC.color(message)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void executeCommand(final String cmd) {
|
||||||
|
Sponge.getGame().getCommandManager().process(this.parent, cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FaweLocation getLocation() {
|
||||||
|
Location<World> loc = this.parent.getLocation();
|
||||||
|
return new FaweLocation(loc.getExtent().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public com.sk89q.worldedit.entity.Player toWorldEditPlayer() {
|
||||||
|
if (WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.USER_COMMANDS) != null) {
|
||||||
|
for (Platform platform : WorldEdit.getInstance().getPlatformManager().getPlatforms()) {
|
||||||
|
return platform.matchPlayer(new FakePlayer(getName(), getUUID(), null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Class<?> clazz = Class.forName("com.sk89q.worldedit.sponge.SpongeWorldEdit");
|
||||||
|
Object spongeWorldEdit = clazz.getDeclaredMethod("inst").invoke(null);
|
||||||
|
Method methodGetPlayer = clazz.getMethod("wrapPlayer", org.spongepowered.api.entity.living.player.Player.class);
|
||||||
|
return (com.sk89q.worldedit.entity.Player) methodGetPlayer.invoke(spongeWorldEdit, this.parent);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,72 @@
|
|||||||
|
package com.boydti.fawe.sponge;
|
||||||
|
|
||||||
|
import com.boydti.fawe.util.TaskManager;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import org.spongepowered.api.Sponge;
|
||||||
|
import org.spongepowered.api.scheduler.Task;
|
||||||
|
|
||||||
|
public class SpongeTaskMan extends TaskManager {
|
||||||
|
|
||||||
|
private final SpongeMain plugin;
|
||||||
|
|
||||||
|
public SpongeTaskMan(SpongeMain plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final AtomicInteger i = new AtomicInteger();
|
||||||
|
|
||||||
|
private final ConcurrentHashMap<Integer, Task> tasks = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int repeat(Runnable runnable, int interval) {
|
||||||
|
int val = this.i.incrementAndGet();
|
||||||
|
Task.Builder builder = Sponge.getGame().getScheduler().createTaskBuilder();
|
||||||
|
Task.Builder built = builder.delayTicks(interval).intervalTicks(interval).execute(runnable);
|
||||||
|
Task task = built.submit(plugin);
|
||||||
|
this.tasks.put(val, task);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int repeatAsync(Runnable runnable, int interval) {
|
||||||
|
int val = this.i.incrementAndGet();
|
||||||
|
Task.Builder builder = Sponge.getGame().getScheduler().createTaskBuilder();
|
||||||
|
Task.Builder built = builder.delayTicks(interval).async().intervalTicks(interval).execute(runnable);
|
||||||
|
Task task = built.submit(plugin);
|
||||||
|
this.tasks.put(val, task);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void async(Runnable runnable) {
|
||||||
|
Task.Builder builder = Sponge.getGame().getScheduler().createTaskBuilder();
|
||||||
|
builder.async().execute(runnable).submit(plugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void task(Runnable runnable) {
|
||||||
|
Task.Builder builder = Sponge.getGame().getScheduler().createTaskBuilder();
|
||||||
|
builder.execute(runnable).submit(plugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void later(Runnable runnable, int delay) {
|
||||||
|
Task.Builder builder = Sponge.getGame().getScheduler().createTaskBuilder();
|
||||||
|
builder.delayTicks(delay).execute(runnable).submit(plugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void laterAsync(Runnable runnable, int delay) {
|
||||||
|
Task.Builder builder = Sponge.getGame().getScheduler().createTaskBuilder();
|
||||||
|
builder.async().delayTicks(delay).execute(runnable).submit(plugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cancel(int i) {
|
||||||
|
Task task = this.tasks.remove(i);
|
||||||
|
if (task != null) {
|
||||||
|
task.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
package com.boydti.fawe.sponge.v1_11;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import net.minecraft.world.gen.layer.GenLayer;
|
||||||
|
import net.minecraft.world.gen.layer.IntCache;
|
||||||
|
|
||||||
|
public class MutableGenLayer extends GenLayer {
|
||||||
|
|
||||||
|
private int biome;
|
||||||
|
|
||||||
|
public MutableGenLayer(long seed) {
|
||||||
|
super(seed);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MutableGenLayer set(int biome) {
|
||||||
|
this.biome = biome;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int[] getInts(int areaX, int areaY, int areaWidth, int areaHeight) {
|
||||||
|
int[] biomes = IntCache.getIntCache(areaWidth * areaHeight);
|
||||||
|
Arrays.fill(biomes, biome);
|
||||||
|
return biomes;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,402 @@
|
|||||||
|
package com.boydti.fawe.sponge.v1_11;
|
||||||
|
|
||||||
|
import com.boydti.fawe.Fawe;
|
||||||
|
import com.boydti.fawe.FaweCache;
|
||||||
|
import com.boydti.fawe.example.CharFaweChunk;
|
||||||
|
import com.boydti.fawe.object.FaweQueue;
|
||||||
|
import com.boydti.fawe.util.MainUtil;
|
||||||
|
import com.sk89q.jnbt.CompoundTag;
|
||||||
|
import com.sk89q.jnbt.DoubleTag;
|
||||||
|
import com.sk89q.jnbt.FloatTag;
|
||||||
|
import com.sk89q.jnbt.ListTag;
|
||||||
|
import com.sk89q.jnbt.StringTag;
|
||||||
|
import com.sk89q.jnbt.Tag;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.block.state.IBlockState;
|
||||||
|
import net.minecraft.entity.Entity;
|
||||||
|
import net.minecraft.entity.EntityList;
|
||||||
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
|
import net.minecraft.nbt.NBTTagCompound;
|
||||||
|
import net.minecraft.tileentity.TileEntity;
|
||||||
|
import net.minecraft.util.BitArray;
|
||||||
|
import net.minecraft.util.ClassInheritanceMultiMap;
|
||||||
|
import net.minecraft.util.ResourceLocation;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraft.world.chunk.BlockStateContainer;
|
||||||
|
import net.minecraft.world.chunk.BlockStatePaletteRegistry;
|
||||||
|
import net.minecraft.world.chunk.Chunk;
|
||||||
|
import net.minecraft.world.chunk.IBlockStatePalette;
|
||||||
|
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
|
||||||
|
|
||||||
|
public class SpongeChunk_1_11 extends CharFaweChunk<Chunk, SpongeQueue_1_11> {
|
||||||
|
|
||||||
|
public BlockStateContainer[] sectionPalettes;
|
||||||
|
|
||||||
|
public static Map<String, ResourceLocation> entityKeys;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A FaweSections object represents a chunk and the blocks that you wish to change in it.
|
||||||
|
*
|
||||||
|
* @param parent
|
||||||
|
* @param x
|
||||||
|
* @param z
|
||||||
|
*/
|
||||||
|
public SpongeChunk_1_11(FaweQueue parent, int x, int z) {
|
||||||
|
super(parent, x, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SpongeChunk_1_11(FaweQueue parent, int x, int z, char[][] ids, short[] count, short[] air, byte[] heightMap) {
|
||||||
|
super(parent, x, z, ids, count, air, heightMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CharFaweChunk copy(boolean shallow) {
|
||||||
|
SpongeChunk_1_11 copy;
|
||||||
|
if (shallow) {
|
||||||
|
copy = new SpongeChunk_1_11(getParent(), getX(), getZ(), ids, count, air, heightMap);
|
||||||
|
copy.biomes = biomes;
|
||||||
|
copy.chunk = chunk;
|
||||||
|
} else {
|
||||||
|
copy = new SpongeChunk_1_11(getParent(), getX(), getZ(), (char[][]) MainUtil.copyNd(ids), count.clone(), air.clone(), heightMap.clone());
|
||||||
|
copy.biomes = biomes;
|
||||||
|
copy.chunk = chunk;
|
||||||
|
copy.biomes = biomes.clone();
|
||||||
|
copy.chunk = chunk;
|
||||||
|
}
|
||||||
|
if (sectionPalettes != null) {
|
||||||
|
copy.sectionPalettes = new BlockStateContainer[16];
|
||||||
|
try {
|
||||||
|
Field fieldBits = BlockStateContainer.class.getDeclaredField("field_186021_b");
|
||||||
|
fieldBits.setAccessible(true);
|
||||||
|
Field fieldPalette = BlockStateContainer.class.getDeclaredField("field_186022_c");
|
||||||
|
fieldPalette.setAccessible(true);
|
||||||
|
Field fieldSize = BlockStateContainer.class.getDeclaredField("field_186024_e");
|
||||||
|
fieldSize.setAccessible(true);
|
||||||
|
for (int i = 0; i < sectionPalettes.length; i++) {
|
||||||
|
BlockStateContainer current = sectionPalettes[i];
|
||||||
|
if (current == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Clone palette
|
||||||
|
IBlockStatePalette currentPalette = (IBlockStatePalette) fieldPalette.get(current);
|
||||||
|
if (!(currentPalette instanceof BlockStatePaletteRegistry)) {
|
||||||
|
current.onResize(128, null);
|
||||||
|
}
|
||||||
|
BlockStateContainer paletteBlock = new BlockStateContainer();
|
||||||
|
currentPalette = (IBlockStatePalette) fieldPalette.get(current);
|
||||||
|
if (!(currentPalette instanceof BlockStatePaletteRegistry)) {
|
||||||
|
throw new RuntimeException("Palette must be global!");
|
||||||
|
}
|
||||||
|
fieldPalette.set(paletteBlock, currentPalette);
|
||||||
|
// Clone size
|
||||||
|
fieldSize.set(paletteBlock, fieldSize.get(current));
|
||||||
|
// Clone palette
|
||||||
|
BitArray currentBits = (BitArray) fieldBits.get(current);
|
||||||
|
BitArray newBits = new BitArray(1, 0);
|
||||||
|
for (Field field : BitArray.class.getDeclaredFields()) {
|
||||||
|
field.setAccessible(true);
|
||||||
|
Object currentValue = field.get(currentBits);
|
||||||
|
if (currentValue instanceof long[]) {
|
||||||
|
currentValue = ((long[]) currentValue).clone();
|
||||||
|
}
|
||||||
|
field.set(newBits, currentValue);
|
||||||
|
}
|
||||||
|
fieldBits.set(paletteBlock, newBits);
|
||||||
|
copy.sectionPalettes[i] = paletteBlock;
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
MainUtil.handleError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Chunk getNewChunk() {
|
||||||
|
World world = ((SpongeQueue_1_11) getParent()).getWorld();
|
||||||
|
return world.getChunkProvider().provideChunk(getX(), getZ());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void optimize() {
|
||||||
|
if (sectionPalettes != null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
char[][] arrays = getCombinedIdArrays();
|
||||||
|
char lastChar = Character.MAX_VALUE;
|
||||||
|
for (int layer = 0; layer < 16; layer++) {
|
||||||
|
if (getCount(layer) > 0) {
|
||||||
|
if (sectionPalettes == null) {
|
||||||
|
sectionPalettes = new BlockStateContainer[16];
|
||||||
|
}
|
||||||
|
BlockStateContainer palette = new BlockStateContainer();
|
||||||
|
char[] blocks = getIdArray(layer);
|
||||||
|
for (int y = 0; y < 16; y++) {
|
||||||
|
for (int z = 0; z < 16; z++) {
|
||||||
|
for (int x = 0; x < 16; x++) {
|
||||||
|
char combinedId = blocks[FaweCache.CACHE_J[y][z][x]];
|
||||||
|
if (combinedId > 1) {
|
||||||
|
palette.set(x, y, z, Block.getBlockById(combinedId >> 4).getStateFromMeta(combinedId & 0xF));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SpongeChunk_1_11 call() {
|
||||||
|
net.minecraft.world.chunk.Chunk nmsChunk = this.getChunk();
|
||||||
|
int bx = this.getX() << 4;
|
||||||
|
int bz = this.getZ() << 4;
|
||||||
|
nmsChunk.setModified(true);
|
||||||
|
net.minecraft.world.World nmsWorld = getParent().getWorld();
|
||||||
|
try {
|
||||||
|
boolean flag = !nmsWorld.provider.getHasNoSky();
|
||||||
|
// Sections
|
||||||
|
ExtendedBlockStorage[] sections = nmsChunk.getBlockStorageArray();
|
||||||
|
Map<BlockPos, TileEntity> tiles = nmsChunk.getTileEntityMap();
|
||||||
|
ClassInheritanceMultiMap<Entity>[] entities = nmsChunk.getEntityLists();
|
||||||
|
|
||||||
|
// Set heightmap
|
||||||
|
getParent().setHeightMap(this, heightMap);
|
||||||
|
|
||||||
|
// Remove entities
|
||||||
|
for (int i = 0; i < 16; i++) {
|
||||||
|
int count = this.getCount(i);
|
||||||
|
if (count == 0) {
|
||||||
|
continue;
|
||||||
|
} else if (count >= 4096) {
|
||||||
|
Collection<Entity> ents = entities[i];
|
||||||
|
if (!ents.isEmpty()) {
|
||||||
|
synchronized (SpongeChunk_1_11.class) {
|
||||||
|
entities[i] = new ClassInheritanceMultiMap<>(Entity.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
char[] array = this.getIdArray(i);
|
||||||
|
Collection<Entity> ents = new ArrayList<>(entities[i]);
|
||||||
|
synchronized (SpongeChunk_1_11.class) {
|
||||||
|
for (Entity entity : ents) {
|
||||||
|
if (entity instanceof EntityPlayer) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int x = ((int) Math.round(entity.posX) & 15);
|
||||||
|
int z = ((int) Math.round(entity.posZ) & 15);
|
||||||
|
int y = (int) Math.round(entity.posY);
|
||||||
|
if (array == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (y < 0 || y > 255 || array[FaweCache.CACHE_J[y][z][x]] != 0) {
|
||||||
|
nmsWorld.removeEntity(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Set entities
|
||||||
|
Set<UUID> createdEntities = new HashSet<>();
|
||||||
|
Set<CompoundTag> entitiesToSpawn = this.getEntities();
|
||||||
|
if (!entitiesToSpawn.isEmpty()) {
|
||||||
|
synchronized (SpongeChunk_1_11.class) {
|
||||||
|
for (CompoundTag nativeTag : entitiesToSpawn) {
|
||||||
|
Map<String, Tag> entityTagMap = nativeTag.getValue();
|
||||||
|
StringTag idTag = (StringTag) entityTagMap.get("Id");
|
||||||
|
ListTag posTag = (ListTag) entityTagMap.get("Pos");
|
||||||
|
ListTag rotTag = (ListTag) entityTagMap.get("Rotation");
|
||||||
|
if (idTag == null || posTag == null || rotTag == null) {
|
||||||
|
Fawe.debug("Unknown entity tag: " + nativeTag);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
List<Tag> value = posTag.getValue();
|
||||||
|
double x = ((DoubleTag) value.get(0)).getValue();
|
||||||
|
double y = ((DoubleTag) value.get(1)).getValue();
|
||||||
|
double z = ((DoubleTag) value.get(2)).getValue();
|
||||||
|
value = rotTag.getValue();
|
||||||
|
float yaw = ((FloatTag) value.get(0)).getValue();
|
||||||
|
float pitch = ((FloatTag) value.get(1)).getValue();
|
||||||
|
String id = idTag.getValue();
|
||||||
|
if (entityKeys == null) {
|
||||||
|
entityKeys = new HashMap<>();
|
||||||
|
for (ResourceLocation key : EntityList.getEntityNameList()) {
|
||||||
|
String currentId = EntityList.func_191302_a(key);
|
||||||
|
entityKeys.put(currentId, key);
|
||||||
|
entityKeys.put(key.getResourcePath(), key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ResourceLocation entityKey = entityKeys.get(id);
|
||||||
|
if (entityKey != null) {
|
||||||
|
Entity entity = EntityList.createEntityByIDFromName(entityKey, nmsWorld);
|
||||||
|
if (entity != null) {
|
||||||
|
NBTTagCompound tag = (NBTTagCompound) SpongeQueue_1_11.methodFromNative.invoke(SpongeQueue_1_11.adapter, nativeTag);
|
||||||
|
entity.readFromNBT(tag);
|
||||||
|
tag.removeTag("UUIDMost");
|
||||||
|
tag.removeTag("UUIDLeast");
|
||||||
|
entity.setPositionAndRotation(x, y, z, yaw, pitch);
|
||||||
|
nmsWorld.spawnEntityInWorld(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Run change task if applicable
|
||||||
|
if (getParent().getChangeTask() != null) {
|
||||||
|
CharFaweChunk previous = getParent().getPrevious(this, sections, tiles, entities, createdEntities, false);
|
||||||
|
getParent().getChangeTask().run(previous, this);
|
||||||
|
}
|
||||||
|
// Trim tiles
|
||||||
|
if (!tiles.isEmpty()) {
|
||||||
|
Set<Map.Entry<BlockPos, TileEntity>> entryset = tiles.entrySet();
|
||||||
|
Iterator<Map.Entry<BlockPos, TileEntity>> iterator = entryset.iterator();
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
Map.Entry<BlockPos, TileEntity> tile = iterator.next();
|
||||||
|
BlockPos pos = tile.getKey();
|
||||||
|
int lx = pos.getX() & 15;
|
||||||
|
int ly = pos.getY();
|
||||||
|
int lz = pos.getZ() & 15;
|
||||||
|
int j = FaweCache.CACHE_I[ly][lz][lx];
|
||||||
|
char[] array = this.getIdArray(j);
|
||||||
|
if (array == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int k = FaweCache.CACHE_J[ly][lz][lx];
|
||||||
|
if (array[k] != 0) {
|
||||||
|
synchronized (SpongeChunk_1_11.class) {
|
||||||
|
tile.getValue().invalidate();
|
||||||
|
iterator.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
HashSet<UUID> entsToRemove = this.getEntityRemoves();
|
||||||
|
if (!entsToRemove.isEmpty()) {
|
||||||
|
synchronized (SpongeChunk_1_11.class) {
|
||||||
|
for (int i = 0; i < entities.length; i++) {
|
||||||
|
Collection<Entity> ents = new ArrayList<>(entities[i]);
|
||||||
|
for (Entity entity : ents) {
|
||||||
|
if (entsToRemove.contains(entity.getUniqueID())) {
|
||||||
|
nmsWorld.removeEntity(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Efficiently merge sections
|
||||||
|
for (int j = 0; j < sections.length; j++) {
|
||||||
|
int count = this.getCount(j);
|
||||||
|
if (count == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final char[] array = this.getIdArray(j);
|
||||||
|
if (array == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int countAir = this.getAir(j);
|
||||||
|
ExtendedBlockStorage section = sections[j];
|
||||||
|
if (section == null) {
|
||||||
|
if (count == countAir) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (this.sectionPalettes != null && this.sectionPalettes[j] != null) {
|
||||||
|
section = sections[j] = new ExtendedBlockStorage(j << 4, flag);
|
||||||
|
getParent().setPalette(section, this.sectionPalettes[j]);
|
||||||
|
getParent().setCount(0, count - this.getAir(j), section);
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
sections[j] = section = new ExtendedBlockStorage(j << 4, flag);
|
||||||
|
}
|
||||||
|
} else if (count >= 4096) {
|
||||||
|
if (count == countAir) {
|
||||||
|
sections[j] = null;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (this.sectionPalettes != null && this.sectionPalettes[j] != null) {
|
||||||
|
getParent().setPalette(section, this.sectionPalettes[j]);
|
||||||
|
getParent().setCount(0, count - this.getAir(j), section);
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
sections[j] = section = new ExtendedBlockStorage(j << 4, flag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IBlockState existing;
|
||||||
|
int by = j << 4;
|
||||||
|
BlockStateContainer nibble = section.getData();
|
||||||
|
int nonEmptyBlockCount = 0;
|
||||||
|
for (int y = 0; y < 16; y++) {
|
||||||
|
for (int z = 0; z < 16; z++) {
|
||||||
|
for (int x = 0; x < 16; x++) {
|
||||||
|
char combinedId = array[FaweCache.CACHE_J[y][z][x]];
|
||||||
|
switch (combinedId) {
|
||||||
|
case 0:
|
||||||
|
continue;
|
||||||
|
case 1:
|
||||||
|
existing = nibble.get(x, y, z);
|
||||||
|
if (existing != SpongeQueue_1_11.air) {
|
||||||
|
if (existing.getLightValue() > 0) {
|
||||||
|
getParent().getRelighter().addLightUpdate(bx + x, by + y, bz + z);
|
||||||
|
}
|
||||||
|
nonEmptyBlockCount--;
|
||||||
|
}
|
||||||
|
nibble.set(x, y, z, SpongeQueue_1_11.air);
|
||||||
|
continue;
|
||||||
|
default:
|
||||||
|
existing = nibble.get(x, y, z);
|
||||||
|
if (existing != SpongeQueue_1_11.air) {
|
||||||
|
if (existing.getLightValue() > 0) {
|
||||||
|
getParent().getRelighter().addLightUpdate(bx + x, by + y, bz + z);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
nonEmptyBlockCount++;
|
||||||
|
}
|
||||||
|
nibble.set(x, y, z, Block.getBlockById(combinedId >> 4).getStateFromMeta(combinedId & 0xF));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
getParent().setCount(0, getParent().getNonEmptyBlockCount(section) + nonEmptyBlockCount, section);
|
||||||
|
}
|
||||||
|
// Set biomes
|
||||||
|
if (this.biomes != null) {
|
||||||
|
byte[] currentBiomes = nmsChunk.getBiomeArray();
|
||||||
|
for (int i = 0 ; i < this.biomes.length; i++) {
|
||||||
|
if (this.biomes[i] != 0) {
|
||||||
|
currentBiomes[i] = this.biomes[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Set tiles
|
||||||
|
Map<Short, CompoundTag> tilesToSpawn = this.getTiles();
|
||||||
|
|
||||||
|
for (Map.Entry<Short, CompoundTag> entry : tilesToSpawn.entrySet()) {
|
||||||
|
CompoundTag nativeTag = entry.getValue();
|
||||||
|
short blockHash = entry.getKey();
|
||||||
|
int x = (blockHash >> 12 & 0xF) + bx;
|
||||||
|
int y = (blockHash & 0xFF);
|
||||||
|
int z = (blockHash >> 8 & 0xF) + bz;
|
||||||
|
BlockPos pos = new BlockPos(x, y, z); // Set pos
|
||||||
|
TileEntity tileEntity = nmsWorld.getTileEntity(pos);
|
||||||
|
if (tileEntity != null) {
|
||||||
|
NBTTagCompound tag = (NBTTagCompound) SpongeQueue_1_11.methodFromNative.invoke(SpongeQueue_1_11.adapter, nativeTag);
|
||||||
|
tag.setInteger("x", pos.getX());
|
||||||
|
tag.setInteger("y", pos.getY());
|
||||||
|
tag.setInteger("z", pos.getZ());
|
||||||
|
tileEntity.readFromNBT(tag); // ReadTagIntoTile
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
MainUtil.handleError(e);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,671 @@
|
|||||||
|
package com.boydti.fawe.sponge.v1_11;
|
||||||
|
|
||||||
|
import com.boydti.fawe.FaweCache;
|
||||||
|
import com.boydti.fawe.example.CharFaweChunk;
|
||||||
|
import com.boydti.fawe.example.NMSMappedFaweQueue;
|
||||||
|
import com.boydti.fawe.object.FaweChunk;
|
||||||
|
import com.boydti.fawe.object.FawePlayer;
|
||||||
|
import com.boydti.fawe.object.brush.visualization.VisualChunk;
|
||||||
|
import java.util.concurrent.atomic.LongAdder;
|
||||||
|
import com.boydti.fawe.object.visitor.FaweChunkVisitor;
|
||||||
|
import com.boydti.fawe.sponge.SpongePlayer;
|
||||||
|
import com.boydti.fawe.util.MainUtil;
|
||||||
|
import com.boydti.fawe.util.MathMan;
|
||||||
|
import com.boydti.fawe.util.ReflectionUtils;
|
||||||
|
import com.sk89q.jnbt.CompoundTag;
|
||||||
|
import com.sk89q.jnbt.StringTag;
|
||||||
|
import com.sk89q.jnbt.Tag;
|
||||||
|
import com.sk89q.worldedit.sponge.SpongeWorldEdit;
|
||||||
|
import com.sk89q.worldedit.sponge.adapter.SpongeImplAdapter;
|
||||||
|
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.buffer.ByteBufAllocator;
|
||||||
|
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.ArrayDeque;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.block.BlockFalling;
|
||||||
|
import net.minecraft.block.state.IBlockState;
|
||||||
|
import net.minecraft.entity.Entity;
|
||||||
|
import net.minecraft.entity.EntityList;
|
||||||
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
|
import net.minecraft.entity.player.EntityPlayerMP;
|
||||||
|
import net.minecraft.init.Blocks;
|
||||||
|
import net.minecraft.nbt.NBTBase;
|
||||||
|
import net.minecraft.nbt.NBTTagCompound;
|
||||||
|
import net.minecraft.network.PacketBuffer;
|
||||||
|
import net.minecraft.network.play.server.SPacketChunkData;
|
||||||
|
import net.minecraft.network.play.server.SPacketMultiBlockChange;
|
||||||
|
import net.minecraft.server.management.PlayerChunkMap;
|
||||||
|
import net.minecraft.server.management.PlayerChunkMapEntry;
|
||||||
|
import net.minecraft.tileentity.TileEntity;
|
||||||
|
import net.minecraft.util.ClassInheritanceMultiMap;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.ChunkPos;
|
||||||
|
import net.minecraft.world.EnumSkyBlock;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraft.world.WorldServer;
|
||||||
|
import net.minecraft.world.biome.BiomeCache;
|
||||||
|
import net.minecraft.world.biome.BiomeProvider;
|
||||||
|
import net.minecraft.world.chunk.BlockStateContainer;
|
||||||
|
import net.minecraft.world.chunk.Chunk;
|
||||||
|
import net.minecraft.world.chunk.IChunkGenerator;
|
||||||
|
import net.minecraft.world.chunk.IChunkProvider;
|
||||||
|
import net.minecraft.world.chunk.NibbleArray;
|
||||||
|
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
|
||||||
|
import net.minecraft.world.gen.ChunkProviderOverworld;
|
||||||
|
import net.minecraft.world.gen.ChunkProviderServer;
|
||||||
|
import net.minecraft.world.storage.WorldInfo;
|
||||||
|
import org.spongepowered.api.Sponge;
|
||||||
|
|
||||||
|
public class SpongeQueue_1_11 extends NMSMappedFaweQueue<World, net.minecraft.world.chunk.Chunk, ExtendedBlockStorage[], ExtendedBlockStorage> {
|
||||||
|
|
||||||
|
protected final static Method methodFromNative;
|
||||||
|
protected final static Method methodToNative;
|
||||||
|
protected final static Field fieldTickingBlockCount;
|
||||||
|
protected final static Field fieldNonEmptyBlockCount;
|
||||||
|
|
||||||
|
protected final static Field fieldId2ChunkMap;
|
||||||
|
protected final static Field fieldChunkGenerator;
|
||||||
|
|
||||||
|
protected static Field fieldBiomes;
|
||||||
|
protected static Field fieldSeed;
|
||||||
|
protected static Field fieldBiomeCache;
|
||||||
|
protected static Field fieldBiomes2;
|
||||||
|
protected static Field fieldGenLayer1;
|
||||||
|
protected static Field fieldGenLayer2;
|
||||||
|
protected static ExtendedBlockStorage emptySection;
|
||||||
|
|
||||||
|
private static MutableGenLayer genLayer;
|
||||||
|
|
||||||
|
protected static final SpongeImplAdapter adapter;
|
||||||
|
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
emptySection = new ExtendedBlockStorage(0, true);
|
||||||
|
adapter = SpongeWorldEdit.inst().getAdapter();
|
||||||
|
methodFromNative = adapter.getClass().getDeclaredMethod("toNative", Tag.class);
|
||||||
|
methodToNative = adapter.getClass().getDeclaredMethod("fromNative", NBTBase.class);
|
||||||
|
methodFromNative.setAccessible(true);
|
||||||
|
methodToNative.setAccessible(true);
|
||||||
|
|
||||||
|
fieldId2ChunkMap = ChunkProviderServer.class.getDeclaredField("field_73244_f");
|
||||||
|
fieldChunkGenerator = ChunkProviderServer.class.getDeclaredField("field_186029_c");
|
||||||
|
fieldId2ChunkMap.setAccessible(true);
|
||||||
|
fieldChunkGenerator.setAccessible(true);
|
||||||
|
|
||||||
|
fieldBiomes = ChunkProviderOverworld.class.getDeclaredField("field_185981_C"); // biomesForGeneration
|
||||||
|
fieldBiomes.setAccessible(true);
|
||||||
|
fieldSeed = WorldInfo.class.getDeclaredField("field_76100_a"); // randomSeed
|
||||||
|
fieldSeed.setAccessible(true);
|
||||||
|
fieldBiomeCache = BiomeProvider.class.getDeclaredField("field_76942_f"); // biomeCache
|
||||||
|
fieldBiomeCache.setAccessible(true);
|
||||||
|
fieldBiomes2 = BiomeProvider.class.getDeclaredField("field_76943_g"); // biomesToSpawnIn
|
||||||
|
fieldBiomes2.setAccessible(true);
|
||||||
|
fieldGenLayer1 = BiomeProvider.class.getDeclaredField("field_76944_d"); // genBiomes
|
||||||
|
fieldGenLayer2 = BiomeProvider.class.getDeclaredField("field_76945_e"); // biomeIndexLayer
|
||||||
|
fieldGenLayer1.setAccessible(true);
|
||||||
|
fieldGenLayer2.setAccessible(true);
|
||||||
|
|
||||||
|
fieldTickingBlockCount = ExtendedBlockStorage.class.getDeclaredField("field_76683_c");
|
||||||
|
fieldNonEmptyBlockCount = ExtendedBlockStorage.class.getDeclaredField("field_76682_b");
|
||||||
|
fieldTickingBlockCount.setAccessible(true);
|
||||||
|
fieldNonEmptyBlockCount.setAccessible(true);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public SpongeQueue_1_11(com.sk89q.worldedit.world.World world) {
|
||||||
|
super(world);
|
||||||
|
getImpWorld();
|
||||||
|
}
|
||||||
|
|
||||||
|
public SpongeQueue_1_11(String world) {
|
||||||
|
super(world);
|
||||||
|
getImpWorld();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendBlockUpdate(FaweChunk chunk, FawePlayer... players) {
|
||||||
|
try {
|
||||||
|
PlayerChunkMap playerManager = ((WorldServer) getWorld()).getPlayerChunkMap();
|
||||||
|
boolean watching = false;
|
||||||
|
for (int i = 0; i < players.length; i++) {
|
||||||
|
EntityPlayerMP player = (EntityPlayerMP) ((SpongePlayer) players[i]).parent;
|
||||||
|
if (!playerManager.isPlayerWatchingChunk(player, chunk.getX(), chunk.getZ())) {
|
||||||
|
players[i] = null;
|
||||||
|
} else {
|
||||||
|
watching = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!watching) return;
|
||||||
|
final LongAdder size = new LongAdder();
|
||||||
|
if (chunk instanceof VisualChunk) {
|
||||||
|
size.add(((VisualChunk) chunk).size());
|
||||||
|
} else if (chunk instanceof CharFaweChunk) {
|
||||||
|
size.add(((CharFaweChunk) chunk).getTotalCount());
|
||||||
|
} else {
|
||||||
|
chunk.forEachQueuedBlock(new FaweChunkVisitor() {
|
||||||
|
@Override
|
||||||
|
public void run(int localX, int y, int localZ, int combined) {
|
||||||
|
size.add(1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (size.intValue() == 0) return;
|
||||||
|
SPacketMultiBlockChange packet = new SPacketMultiBlockChange();
|
||||||
|
ByteBuf byteBuf = ByteBufAllocator.DEFAULT.buffer();
|
||||||
|
final PacketBuffer buffer = new PacketBuffer(byteBuf);
|
||||||
|
buffer.writeInt(chunk.getX());
|
||||||
|
buffer.writeInt(chunk.getZ());
|
||||||
|
buffer.writeVarIntToBuffer(size.intValue());
|
||||||
|
chunk.forEachQueuedBlock(new FaweChunkVisitor() {
|
||||||
|
@Override
|
||||||
|
public void run(int localX, int y, int localZ, int combined) {
|
||||||
|
short index = (short) (localX << 12 | localZ << 8 | y);
|
||||||
|
buffer.writeShort(index);
|
||||||
|
buffer.writeVarIntToBuffer(combined);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
packet.readPacketData(buffer);
|
||||||
|
for (FawePlayer player : players) {
|
||||||
|
if (player != null) ((EntityPlayerMP) ((SpongePlayer) player).parent).connection.sendPacket(packet);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void saveChunk(Chunk chunk) {
|
||||||
|
chunk.setChunkModified();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ExtendedBlockStorage[] getSections(Chunk chunk) {
|
||||||
|
return chunk.getBlockStorageArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getBiome(Chunk chunk, int x, int z) {
|
||||||
|
return chunk.getBiomeArray()[((z & 15) << 4) + (x & 15)];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Chunk loadChunk(World world, int x, int z, boolean generate) {
|
||||||
|
ChunkProviderServer provider = (ChunkProviderServer) world.getChunkProvider();
|
||||||
|
if (generate) {
|
||||||
|
return provider.provideChunk(x, z);
|
||||||
|
} else {
|
||||||
|
return provider.loadChunk(x, z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ExtendedBlockStorage[] getCachedSections(World world, int cx, int cz) {
|
||||||
|
Chunk chunk = world.getChunkProvider().getLoadedChunk(cx, cz);
|
||||||
|
if (chunk != null) {
|
||||||
|
return chunk.getBlockStorageArray();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Chunk getCachedChunk(World world, int cx, int cz) {
|
||||||
|
return world.getChunkProvider().getLoadedChunk(cx, cz);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ExtendedBlockStorage getCachedSection(ExtendedBlockStorage[] ExtendedBlockStorages, int cy) {
|
||||||
|
return ExtendedBlockStorages[cy];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setHeightMap(FaweChunk chunk, byte[] heightMap) {
|
||||||
|
Chunk forgeChunk = (Chunk) chunk.getChunk();
|
||||||
|
if (forgeChunk != null) {
|
||||||
|
int[] otherMap = forgeChunk.getHeightMap();
|
||||||
|
for (int i = 0; i < heightMap.length; i++) {
|
||||||
|
int newHeight = heightMap[i] & 0xFF;
|
||||||
|
int currentHeight = otherMap[i];
|
||||||
|
if (newHeight > currentHeight) {
|
||||||
|
otherMap[i] = newHeight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos(0, 0, 0);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompoundTag getTileEntity(Chunk chunk, int x, int y, int z) {
|
||||||
|
Map<BlockPos, TileEntity> tiles = chunk.getTileEntityMap();
|
||||||
|
pos.setPos(x, y, z);
|
||||||
|
TileEntity tile = tiles.get(pos);
|
||||||
|
return tile != null ? getTag(tile) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompoundTag getTag(TileEntity tile) {
|
||||||
|
try {
|
||||||
|
NBTTagCompound tag = new NBTTagCompound();
|
||||||
|
tile.writeToNBT(tag); // readTagIntoEntity
|
||||||
|
CompoundTag result = (CompoundTag) methodToNative.invoke(SpongeQueue_1_11.adapter, tag);
|
||||||
|
return result;
|
||||||
|
} catch (Exception e) {
|
||||||
|
MainUtil.handleError(e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean regenerateChunk(net.minecraft.world.World world, int x, int z) {
|
||||||
|
IChunkProvider provider = world.getChunkProvider();
|
||||||
|
if (!(provider instanceof ChunkProviderServer)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
BlockFalling.fallInstantly = true;
|
||||||
|
try {
|
||||||
|
ChunkProviderServer chunkServer = (ChunkProviderServer) provider;
|
||||||
|
IChunkGenerator gen = (IChunkGenerator) fieldChunkGenerator.get(chunkServer);
|
||||||
|
long pos = ChunkPos.asLong(x, z);
|
||||||
|
Chunk mcChunk;
|
||||||
|
if (chunkServer.chunkExists(x, z)) {
|
||||||
|
mcChunk = chunkServer.loadChunk(x, z);
|
||||||
|
mcChunk.onChunkUnload();
|
||||||
|
}
|
||||||
|
PlayerChunkMap playerManager = ((WorldServer) getWorld()).getPlayerChunkMap();
|
||||||
|
List<EntityPlayerMP> oldWatchers = null;
|
||||||
|
if (chunkServer.chunkExists(x, z)) {
|
||||||
|
mcChunk = chunkServer.loadChunk(x, z);
|
||||||
|
PlayerChunkMapEntry entry = playerManager.getEntry(x, z);
|
||||||
|
if (entry != null) {
|
||||||
|
Field fieldPlayers = PlayerChunkMapEntry.class.getDeclaredField("field_187283_c");
|
||||||
|
fieldPlayers.setAccessible(true);
|
||||||
|
oldWatchers = (List<EntityPlayerMP>) fieldPlayers.get(entry);
|
||||||
|
playerManager.removeEntry(entry);
|
||||||
|
}
|
||||||
|
mcChunk.onChunkUnload();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Field droppedChunksSetField = chunkServer.getClass().getDeclaredField("field_73248_b");
|
||||||
|
droppedChunksSetField.setAccessible(true);
|
||||||
|
Set droppedChunksSet = (Set) droppedChunksSetField.get(chunkServer);
|
||||||
|
droppedChunksSet.remove(pos);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
MainUtil.handleError(e);
|
||||||
|
}
|
||||||
|
Long2ObjectMap<Chunk> id2ChunkMap = (Long2ObjectMap<Chunk>) fieldId2ChunkMap.get(chunkServer);
|
||||||
|
id2ChunkMap.remove(pos);
|
||||||
|
mcChunk = gen.provideChunk(x, z);
|
||||||
|
id2ChunkMap.put(pos, mcChunk);
|
||||||
|
if (mcChunk != null) {
|
||||||
|
mcChunk.onChunkLoad();
|
||||||
|
mcChunk.populateChunk(chunkServer, gen);
|
||||||
|
}
|
||||||
|
if (oldWatchers != null) {
|
||||||
|
for (EntityPlayerMP player : oldWatchers) {
|
||||||
|
playerManager.addPlayer(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
MainUtil.handleError(t);
|
||||||
|
return false;
|
||||||
|
} finally {
|
||||||
|
BlockFalling.fallInstantly = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean regenerateChunk(net.minecraft.world.World world, int x, int z, BaseBiome biome, Long seed) {
|
||||||
|
if (biome != null) {
|
||||||
|
try {
|
||||||
|
if (seed == null) {
|
||||||
|
seed = world.getSeed();
|
||||||
|
}
|
||||||
|
nmsWorld.getWorldInfo().getSeed();
|
||||||
|
boolean result;
|
||||||
|
ChunkProviderOverworld generator = new ChunkProviderOverworld(nmsWorld, seed, false, "");
|
||||||
|
net.minecraft.world.biome.Biome base = net.minecraft.world.biome.Biome.getBiome(biome.getId());
|
||||||
|
net.minecraft.world.biome.Biome[] existingBiomes = new net.minecraft.world.biome.Biome[256];
|
||||||
|
Arrays.fill(existingBiomes, base);
|
||||||
|
fieldBiomes.set(generator, existingBiomes);
|
||||||
|
boolean cold = base.getTemperature() <= 1;
|
||||||
|
IChunkGenerator existingGenerator = (IChunkGenerator) fieldChunkGenerator.get(nmsWorld.getChunkProvider());
|
||||||
|
long existingSeed = world.getSeed();
|
||||||
|
{
|
||||||
|
if (genLayer == null) genLayer = new MutableGenLayer(seed);
|
||||||
|
genLayer.set(biome.getId());
|
||||||
|
Object existingGenLayer1 = fieldGenLayer1.get(nmsWorld.provider.getBiomeProvider());
|
||||||
|
Object existingGenLayer2 = fieldGenLayer2.get(nmsWorld.provider.getBiomeProvider());
|
||||||
|
fieldGenLayer1.set(nmsWorld.provider.getBiomeProvider(), genLayer);
|
||||||
|
fieldGenLayer2.set(nmsWorld.provider.getBiomeProvider(), genLayer);
|
||||||
|
|
||||||
|
fieldSeed.set(nmsWorld.getWorldInfo(), seed);
|
||||||
|
|
||||||
|
ReflectionUtils.setFailsafeFieldValue(fieldBiomeCache, this.nmsWorld.provider.getBiomeProvider(), new BiomeCache(this.nmsWorld.provider.getBiomeProvider()));
|
||||||
|
|
||||||
|
ReflectionUtils.setFailsafeFieldValue(fieldChunkGenerator, this.nmsWorld.getChunkProvider(), generator);
|
||||||
|
|
||||||
|
result = regenerateChunk(world, x, z);
|
||||||
|
|
||||||
|
ReflectionUtils.setFailsafeFieldValue(fieldChunkGenerator, this.nmsWorld.getChunkProvider(), existingGenerator);
|
||||||
|
|
||||||
|
fieldSeed.set(nmsWorld.getWorldInfo(), existingSeed);
|
||||||
|
|
||||||
|
fieldGenLayer1.set(nmsWorld.provider.getBiomeProvider(), existingGenLayer1);
|
||||||
|
fieldGenLayer2.set(nmsWorld.provider.getBiomeProvider(), existingGenLayer2);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
} catch (Throwable e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return regenerateChunk(world, x, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getCombinedId4Data(ExtendedBlockStorage section, int x, int y, int z) {
|
||||||
|
IBlockState ibd = section.getData().get(x & 15, y & 15, z & 15);
|
||||||
|
Block block = ibd.getBlock();
|
||||||
|
int id = Block.getIdFromBlock(block);
|
||||||
|
if (FaweCache.hasData(id)) {
|
||||||
|
return (id << 4) + block.getMetaFromState(ibd);
|
||||||
|
} else {
|
||||||
|
return id << 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNonEmptyBlockCount(ExtendedBlockStorage section) throws IllegalAccessException {
|
||||||
|
return (int) fieldNonEmptyBlockCount.get(section);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCount(int tickingBlockCount, int nonEmptyBlockCount, ExtendedBlockStorage section) throws NoSuchFieldException, IllegalAccessException {
|
||||||
|
fieldTickingBlockCount.set(section, tickingBlockCount);
|
||||||
|
fieldNonEmptyBlockCount.set(section, nonEmptyBlockCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CharFaweChunk getPrevious(CharFaweChunk fs, ExtendedBlockStorage[] sections, Map<?, ?> tilesGeneric, Collection<?>[] entitiesGeneric, Set<UUID> createdEntities, boolean all) throws Exception {
|
||||||
|
Map<BlockPos, TileEntity> tiles = (Map<BlockPos, TileEntity>) tilesGeneric;
|
||||||
|
ClassInheritanceMultiMap<Entity>[] entities = (ClassInheritanceMultiMap<Entity>[]) entitiesGeneric;
|
||||||
|
CharFaweChunk previous = (CharFaweChunk) getFaweChunk(fs.getX(), fs.getZ());
|
||||||
|
char[][] idPrevious = previous.getCombinedIdArrays();
|
||||||
|
for (int layer = 0; layer < sections.length; layer++) {
|
||||||
|
if (fs.getCount(layer) != 0 || all) {
|
||||||
|
ExtendedBlockStorage section = sections[layer];
|
||||||
|
if (section != null) {
|
||||||
|
short solid = 0;
|
||||||
|
char[] previousLayer = idPrevious[layer] = new char[4096];
|
||||||
|
BlockStateContainer blocks = section.getData();
|
||||||
|
for (int j = 0; j < 4096; j++) {
|
||||||
|
int x = FaweCache.CACHE_X[0][j];
|
||||||
|
int y = FaweCache.CACHE_Y[0][j];
|
||||||
|
int z = FaweCache.CACHE_Z[0][j];
|
||||||
|
IBlockState ibd = blocks.get(x, y, z);
|
||||||
|
Block block = ibd.getBlock();
|
||||||
|
int combined = Block.getIdFromBlock(block);
|
||||||
|
if (FaweCache.hasData(combined)) {
|
||||||
|
combined = (combined << 4) + block.getMetaFromState(ibd);
|
||||||
|
} else {
|
||||||
|
combined = combined << 4;
|
||||||
|
}
|
||||||
|
if (combined > 1) {
|
||||||
|
solid++;
|
||||||
|
}
|
||||||
|
previousLayer[j] = (char) combined;
|
||||||
|
}
|
||||||
|
previous.count[layer] = solid;
|
||||||
|
previous.air[layer] = (short) (4096 - solid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (tiles != null) {
|
||||||
|
for (Map.Entry<BlockPos, TileEntity> entry : tiles.entrySet()) {
|
||||||
|
TileEntity tile = entry.getValue();
|
||||||
|
NBTTagCompound tag = new NBTTagCompound();
|
||||||
|
tile.writeToNBT(tag); // readTileEntityIntoTag
|
||||||
|
BlockPos pos = entry.getKey();
|
||||||
|
CompoundTag nativeTag = (CompoundTag) methodToNative.invoke(SpongeQueue_1_11.adapter, tag);
|
||||||
|
previous.setTile(pos.getX(), pos.getY(), pos.getZ(), nativeTag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (entities != null) {
|
||||||
|
for (Collection<Entity> entityList : entities) {
|
||||||
|
for (Entity ent : entityList) {
|
||||||
|
if (ent instanceof EntityPlayer || (!createdEntities.isEmpty() && createdEntities.contains(ent.getUniqueID()))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int x = ((int) Math.round(ent.posX) & 15);
|
||||||
|
int z = ((int) Math.round(ent.posZ) & 15);
|
||||||
|
int y = (int) Math.round(ent.posY);
|
||||||
|
int i = FaweCache.CACHE_I[y][z][x];
|
||||||
|
char[] array = fs.getIdArray(i);
|
||||||
|
if (array == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int j = FaweCache.CACHE_J[y][z][x];
|
||||||
|
if (array[j] != 0) {
|
||||||
|
String id = EntityList.getEntityString(ent);
|
||||||
|
if (id != null) {
|
||||||
|
NBTTagCompound tag = new NBTTagCompound();
|
||||||
|
ent.writeToNBT(tag); // readEntityIntoTag
|
||||||
|
CompoundTag nativeTag = (CompoundTag) methodToNative.invoke(SpongeQueue_1_11.adapter, tag);
|
||||||
|
Map<String, Tag> map = ReflectionUtils.getMap(nativeTag.getValue());
|
||||||
|
map.put("Id", new StringTag(id));
|
||||||
|
previous.setEntity(nativeTag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return previous;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final static IBlockState air = Blocks.AIR.getDefaultState();
|
||||||
|
|
||||||
|
public void setPalette(ExtendedBlockStorage section, BlockStateContainer palette) throws NoSuchFieldException, IllegalAccessException {
|
||||||
|
Field fieldSection = ExtendedBlockStorage.class.getDeclaredField("data");
|
||||||
|
fieldSection.setAccessible(true);
|
||||||
|
fieldSection.set(section, palette);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendChunk(int x, int z, int bitMask) {
|
||||||
|
Chunk chunk = getCachedChunk(getWorld(), x, z);
|
||||||
|
if (chunk != null) {
|
||||||
|
sendChunk(chunk, bitMask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void refreshChunk(FaweChunk fc) {
|
||||||
|
Chunk chunk = getCachedChunk(getWorld(), fc.getX(), fc.getZ());
|
||||||
|
if (chunk != null) {
|
||||||
|
sendChunk(chunk, fc.getBitMask());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendChunk(Chunk nmsChunk, int mask) {
|
||||||
|
if (!nmsChunk.isLoaded()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
ChunkPos pos = nmsChunk.getChunkCoordIntPair();
|
||||||
|
WorldServer w = (WorldServer) nmsChunk.getWorld();
|
||||||
|
PlayerChunkMap chunkMap = w.getPlayerChunkMap();
|
||||||
|
int x = pos.chunkXPos;
|
||||||
|
int z = pos.chunkZPos;
|
||||||
|
PlayerChunkMapEntry chunkMapEntry = chunkMap.getEntry(x, z);
|
||||||
|
if (chunkMapEntry == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final ArrayDeque<EntityPlayerMP> players = new ArrayDeque<>();
|
||||||
|
chunkMapEntry.hasPlayerMatching(input -> {
|
||||||
|
players.add(input);
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
boolean empty = false;
|
||||||
|
ExtendedBlockStorage[] sections = nmsChunk.getBlockStorageArray();
|
||||||
|
for (int i = 0; i < sections.length; i++) {
|
||||||
|
if (sections[i] == null) {
|
||||||
|
sections[i] = emptySection;
|
||||||
|
empty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mask == 0 || mask == 65535 && hasEntities(nmsChunk)) {
|
||||||
|
SPacketChunkData packet = new SPacketChunkData(nmsChunk, 65280);
|
||||||
|
for (EntityPlayerMP player : players) {
|
||||||
|
player.connection.sendPacket(packet);
|
||||||
|
}
|
||||||
|
mask = 255;
|
||||||
|
}
|
||||||
|
SPacketChunkData packet = new SPacketChunkData(nmsChunk, mask);
|
||||||
|
for (EntityPlayerMP player : players) {
|
||||||
|
player.connection.sendPacket(packet);
|
||||||
|
}
|
||||||
|
if (empty) {
|
||||||
|
for (int i = 0; i < sections.length; i++) {
|
||||||
|
if (sections[i] == emptySection) {
|
||||||
|
sections[i] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
MainUtil.handleError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasEntities(Chunk nmsChunk) {
|
||||||
|
ClassInheritanceMultiMap<Entity>[] entities = nmsChunk.getEntityLists();
|
||||||
|
for (int i = 0; i < entities.length; i++) {
|
||||||
|
ClassInheritanceMultiMap<Entity> slice = entities[i];
|
||||||
|
if (slice != null && !slice.isEmpty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FaweChunk<Chunk> getFaweChunk(int x, int z) {
|
||||||
|
return new SpongeChunk_1_11(this, x, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean removeLighting(ExtendedBlockStorage[] sections, RelightMode mode, boolean sky) {
|
||||||
|
if (mode == RelightMode.ALL) {
|
||||||
|
for (int i = 0; i < sections.length; i++) {
|
||||||
|
ExtendedBlockStorage section = sections[i];
|
||||||
|
if (section != null) {
|
||||||
|
section.setBlocklightArray(new NibbleArray());
|
||||||
|
if (sky) {
|
||||||
|
section.setSkylightArray(new NibbleArray());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasSky() {
|
||||||
|
return !nmsWorld.provider.getHasNoSky();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setFullbright(ExtendedBlockStorage[] sections) {
|
||||||
|
for (int i = 0; i < sections.length; i++) {
|
||||||
|
ExtendedBlockStorage section = sections[i];
|
||||||
|
if (section != null) {
|
||||||
|
byte[] bytes = section.getSkylightArray().getData();
|
||||||
|
Arrays.fill(bytes, (byte) 255);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void relight(int x, int y, int z) {
|
||||||
|
pos.setPos(x, y, z);
|
||||||
|
nmsWorld.checkLight(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected WorldServer nmsWorld;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public net.minecraft.world.World getImpWorld() {
|
||||||
|
if (nmsWorld != null || getWorldName() == null) {
|
||||||
|
return nmsWorld;
|
||||||
|
}
|
||||||
|
nmsWorld = (WorldServer) Sponge.getServer().getWorld(getWorldName()).get();
|
||||||
|
return nmsWorld;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setSkyLight(ExtendedBlockStorage section, int x, int y, int z, int value) {
|
||||||
|
section.getSkylightArray().set(x & 15, y & 15, z & 15, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setBlockLight(ExtendedBlockStorage section, int x, int y, int z, int value) {
|
||||||
|
section.getBlocklightArray().set(x & 15, y & 15, z & 15, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSkyLight(ExtendedBlockStorage section, int x, int y, int z) {
|
||||||
|
return section.getExtSkylightValue(x & 15, y & 15, z & 15);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getEmmittedLight(ExtendedBlockStorage section, int x, int y, int z) {
|
||||||
|
return section.getExtBlocklightValue(x & 15, y & 15, z & 15);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getOpacity(ExtendedBlockStorage section, int x, int y, int z) {
|
||||||
|
BlockStateContainer dataPalette = section.getData();
|
||||||
|
IBlockState ibd = dataPalette.get(x & 15, y & 15, z & 15);
|
||||||
|
return ibd.getLightOpacity();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getBrightness(ExtendedBlockStorage section, int x, int y, int z) {
|
||||||
|
BlockStateContainer dataPalette = section.getData();
|
||||||
|
IBlockState ibd = dataPalette.get(x & 15, y & 15, z & 15);
|
||||||
|
return ibd.getLightValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getOpacityBrightnessPair(ExtendedBlockStorage section, int x, int y, int z) {
|
||||||
|
BlockStateContainer dataPalette = section.getData();
|
||||||
|
IBlockState ibd = dataPalette.get(x & 15, y & 15, z & 15);
|
||||||
|
return MathMan.pair16(ibd.getLightOpacity(), ibd.getLightValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void relightBlock(int x, int y, int z) {
|
||||||
|
pos.setPos(x, y, z);
|
||||||
|
nmsWorld.checkLightFor(EnumSkyBlock.BLOCK, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void relightSky(int x, int y, int z) {
|
||||||
|
pos.setPos(x, y, z);
|
||||||
|
nmsWorld.checkLightFor(EnumSkyBlock.SKY, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public File getSaveFolder() {
|
||||||
|
return new File(((WorldServer) getWorld()).getSaveHandler().getWorldDirectory(), "region");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,329 @@
|
|||||||
|
package com.boydti.fawe.sponge.v1_11;
|
||||||
|
|
||||||
|
import com.boydti.fawe.FaweCache;
|
||||||
|
import com.boydti.fawe.config.Settings;
|
||||||
|
import com.boydti.fawe.example.CharFaweChunk;
|
||||||
|
import com.boydti.fawe.example.NMSMappedFaweQueue;
|
||||||
|
import com.boydti.fawe.object.FaweChunk;
|
||||||
|
import com.boydti.fawe.object.RunnableVal;
|
||||||
|
import com.boydti.fawe.util.MainUtil;
|
||||||
|
import com.boydti.fawe.util.TaskManager;
|
||||||
|
import com.sk89q.jnbt.CompoundTag;
|
||||||
|
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.block.state.IBlockState;
|
||||||
|
import net.minecraft.entity.Entity;
|
||||||
|
import net.minecraft.entity.EntityTracker;
|
||||||
|
import net.minecraft.entity.EntityTrackerEntry;
|
||||||
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
|
import net.minecraft.entity.player.EntityPlayerMP;
|
||||||
|
import net.minecraft.nbt.NBTBase;
|
||||||
|
import net.minecraft.nbt.NBTTagCompound;
|
||||||
|
import net.minecraft.network.play.server.S13PacketDestroyEntities;
|
||||||
|
import net.minecraft.network.play.server.S21PacketChunkData;
|
||||||
|
import net.minecraft.server.management.PlayerManager;
|
||||||
|
import net.minecraft.tileentity.TileEntity;
|
||||||
|
import net.minecraft.util.BlockPos;
|
||||||
|
import net.minecraft.util.ClassInheritanceMultiMap;
|
||||||
|
import net.minecraft.util.IntHashMap;
|
||||||
|
import net.minecraft.util.LongHashMap;
|
||||||
|
import net.minecraft.world.ChunkCoordIntPair;
|
||||||
|
import net.minecraft.world.WorldServer;
|
||||||
|
import net.minecraft.world.chunk.IChunkProvider;
|
||||||
|
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
|
||||||
|
import net.minecraft.world.gen.ChunkProviderServer;
|
||||||
|
import org.spongepowered.api.Sponge;
|
||||||
|
import org.spongepowered.api.block.BlockState;
|
||||||
|
import org.spongepowered.api.block.BlockTypes;
|
||||||
|
import org.spongepowered.api.world.Chunk;
|
||||||
|
import org.spongepowered.api.world.World;
|
||||||
|
import org.spongepowered.api.world.extent.UnmodifiableBlockVolume;
|
||||||
|
import org.spongepowered.api.world.extent.worker.MutableBlockVolumeWorker;
|
||||||
|
import org.spongepowered.api.world.extent.worker.procedure.BlockVolumeMapper;
|
||||||
|
|
||||||
|
public class SpongeQueue_ALL extends NMSMappedFaweQueue<World, net.minecraft.world.chunk.Chunk, ExtendedBlockStorage[], ExtendedBlockStorage> {
|
||||||
|
private Method methodToNative;
|
||||||
|
|
||||||
|
public SpongeQueue_ALL(String world) {
|
||||||
|
super(world);
|
||||||
|
try {
|
||||||
|
Class<?> converter = Class.forName("com.sk89q.worldedit.forge.NBTConverter");
|
||||||
|
this.methodToNative = converter.getDeclaredMethod("fromNative", NBTBase.class);
|
||||||
|
methodToNative.setAccessible(true);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void refreshChunk(FaweChunk fs) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void refreshChunk(World world, net.minecraft.world.chunk.Chunk nmsChunk) {
|
||||||
|
if (!nmsChunk.isLoaded()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
ChunkCoordIntPair pos = nmsChunk.getChunkCoordIntPair();
|
||||||
|
WorldServer w = (WorldServer) nmsChunk.getWorld();
|
||||||
|
PlayerManager chunkMap = w.getPlayerManager();
|
||||||
|
int x = pos.chunkXPos;
|
||||||
|
int z = pos.chunkZPos;
|
||||||
|
if (!chunkMap.hasPlayerInstance(x, z)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
EntityTracker tracker = w.getEntityTracker();
|
||||||
|
HashSet<EntityPlayerMP> players = new HashSet<>();
|
||||||
|
for (EntityPlayer player : w.playerEntities) {
|
||||||
|
if (player instanceof EntityPlayerMP) {
|
||||||
|
if (chunkMap.isPlayerWatchingChunk((EntityPlayerMP) player, x, z)) {
|
||||||
|
players.add((EntityPlayerMP) player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (players.size() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
HashSet<EntityTrackerEntry> entities = new HashSet<>();
|
||||||
|
ClassInheritanceMultiMap<Entity>[] entitieSlices = nmsChunk.getEntityLists();
|
||||||
|
IntHashMap<EntityTrackerEntry> entries = null;
|
||||||
|
for (Field field : tracker.getClass().getDeclaredFields()) {
|
||||||
|
if (field.getType() == IntHashMap.class) {
|
||||||
|
field.setAccessible(true);
|
||||||
|
entries = (IntHashMap<EntityTrackerEntry>) field.get(tracker);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (ClassInheritanceMultiMap<Entity> slice : entitieSlices) {
|
||||||
|
if (slice == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (Entity ent : slice) {
|
||||||
|
EntityTrackerEntry entry = entries != null ? entries.lookup(ent.getEntityId()) : null;
|
||||||
|
if (entry == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
entities.add(entry);
|
||||||
|
S13PacketDestroyEntities packet = new S13PacketDestroyEntities(ent.getEntityId());
|
||||||
|
for (EntityPlayerMP player : players) {
|
||||||
|
player.playerNetServerHandler.sendPacket(packet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Send chunks
|
||||||
|
S21PacketChunkData packet = new S21PacketChunkData(nmsChunk, false, 65535);
|
||||||
|
for (EntityPlayerMP player : players) {
|
||||||
|
player.playerNetServerHandler.sendPacket(packet);
|
||||||
|
}
|
||||||
|
// send ents
|
||||||
|
for (EntityTrackerEntry entry : entities) {
|
||||||
|
try {
|
||||||
|
TaskManager.IMP.later(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
for (EntityPlayerMP player : players) {
|
||||||
|
boolean result = entry.trackingPlayers.remove(player);
|
||||||
|
if (result && entry.trackedEntity != player) {
|
||||||
|
entry.updatePlayerEntity(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 2);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
MainUtil.handleError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
MainUtil.handleError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompoundTag getTileEntity(net.minecraft.world.chunk.Chunk chunk, int x, int y, int z) {
|
||||||
|
Map<BlockPos, TileEntity> tiles = chunk.getTileEntityMap();
|
||||||
|
TileEntity tile = tiles.get(new BlockPos(x, y, z));
|
||||||
|
return tile != null ? getTag(tile) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompoundTag getTag(TileEntity tile) {
|
||||||
|
try {
|
||||||
|
NBTTagCompound tag = new NBTTagCompound();
|
||||||
|
tile.readFromNBT(tag); // readTagIntoEntity
|
||||||
|
return (CompoundTag) methodToNative.invoke(null, tag);
|
||||||
|
} catch (Exception e) {
|
||||||
|
MainUtil.handleError(e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public net.minecraft.world.chunk.Chunk getChunk(World world, int x, int z) {
|
||||||
|
net.minecraft.world.chunk.Chunk chunk = ((net.minecraft.world.World) world).getChunkProvider().provideChunk(x, z);
|
||||||
|
if (chunk != null && !chunk.isLoaded()) {
|
||||||
|
chunk.onChunkLoad();
|
||||||
|
}
|
||||||
|
return chunk;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public char[] getCachedSection(ExtendedBlockStorage[] chunk, int cy) {
|
||||||
|
ExtendedBlockStorage value = chunk[cy];
|
||||||
|
return value == null ? null : value.getData();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public World getWorld(String world) {
|
||||||
|
return Sponge.getServer().getWorld(super.getWorldName()).get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isChunkLoaded(World world, int x, int z) {
|
||||||
|
net.minecraft.world.World nmsWorld = (net.minecraft.world.World) world;
|
||||||
|
IChunkProvider provider = nmsWorld.getChunkProvider();
|
||||||
|
return provider.chunkExists(x, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean regenerateChunk(World world, int x, int z, BaseBiome biome, Long seed) {
|
||||||
|
try {
|
||||||
|
net.minecraft.world.World nmsWorld = (net.minecraft.world.World) world;
|
||||||
|
IChunkProvider provider = nmsWorld.getChunkProvider();
|
||||||
|
if (!(provider instanceof ChunkProviderServer)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ChunkProviderServer chunkServer = (ChunkProviderServer) provider;
|
||||||
|
Field chunkProviderField = chunkServer.getClass().getDeclaredField("field_73246_d");
|
||||||
|
chunkProviderField.setAccessible(true);
|
||||||
|
IChunkProvider chunkProvider = (IChunkProvider) chunkProviderField.get(chunkServer);
|
||||||
|
long pos = ChunkCoordIntPair.chunkXZ2Int(x, z);
|
||||||
|
net.minecraft.world.chunk.Chunk mcChunk;
|
||||||
|
if (chunkServer.chunkExists(x, z)) {
|
||||||
|
mcChunk = chunkServer.loadChunk(x, z);
|
||||||
|
mcChunk.onChunkUnload();
|
||||||
|
}
|
||||||
|
Field droppedChunksSetField = chunkServer.getClass().getDeclaredField("field_73248_b");
|
||||||
|
droppedChunksSetField.setAccessible(true);
|
||||||
|
Set droppedChunksSet = (Set) droppedChunksSetField.get(chunkServer);
|
||||||
|
droppedChunksSet.remove(pos);
|
||||||
|
Field id2ChunkMapField = chunkServer.getClass().getDeclaredField("field_73244_f");
|
||||||
|
id2ChunkMapField.setAccessible(true);
|
||||||
|
LongHashMap<net.minecraft.world.chunk.Chunk> id2ChunkMap = (LongHashMap<net.minecraft.world.chunk.Chunk>) id2ChunkMapField.get(chunkServer);
|
||||||
|
id2ChunkMap.remove(pos);
|
||||||
|
mcChunk = chunkProvider.provideChunk(x, z);
|
||||||
|
id2ChunkMap.add(pos, mcChunk);
|
||||||
|
List<net.minecraft.world.chunk.Chunk> loadedChunks = chunkServer.func_152380_a();
|
||||||
|
loadedChunks.add(mcChunk);
|
||||||
|
if (mcChunk != null) {
|
||||||
|
mcChunk.onChunkLoad();
|
||||||
|
mcChunk.populateChunk(chunkProvider, chunkProvider, x, z);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} catch (Throwable e) {
|
||||||
|
MainUtil.handleError(e);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private BlockState AIR = BlockTypes.AIR.getDefaultState();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean setComponents(FaweChunk fc, RunnableVal<FaweChunk> changeTask) {
|
||||||
|
if (changeTask != null) {
|
||||||
|
Settings.IMP.HISTORY.COMBINE_STAGES = false;
|
||||||
|
throw new UnsupportedOperationException("Combine stages not supported");
|
||||||
|
}
|
||||||
|
SpongeChunk_1_8 fs = (SpongeChunk_1_8) fc;
|
||||||
|
net.minecraft.world.chunk.Chunk nmsChunk = fs.getChunk();
|
||||||
|
Chunk spongeChunk = (Chunk) nmsChunk;
|
||||||
|
|
||||||
|
char[][] ids = ((SpongeChunk_1_8) fc).getCombinedIdArrays();
|
||||||
|
MutableBlockVolumeWorker<? extends Chunk> blockWorker = spongeChunk.getBlockWorker();
|
||||||
|
blockWorker.map(new BlockVolumeMapper() {
|
||||||
|
@Override
|
||||||
|
public BlockState map(UnmodifiableBlockVolume volume, int xx, int y, int zz) {
|
||||||
|
int x = xx & 15;
|
||||||
|
int z = zz & 15;
|
||||||
|
int i = FaweCache.CACHE_I[y][z][x];
|
||||||
|
char[] array = ids[i];
|
||||||
|
if (array == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
int combinedId = array[FaweCache.CACHE_J[y][z][x]];
|
||||||
|
switch (combinedId) {
|
||||||
|
case 0:
|
||||||
|
return null;
|
||||||
|
case 1:
|
||||||
|
return AIR;
|
||||||
|
default:
|
||||||
|
int id = combinedId >> 4;
|
||||||
|
Block block = Block.getBlockById(id);
|
||||||
|
int data = combinedId & 0xf;
|
||||||
|
IBlockState ibd;
|
||||||
|
if (data != 0) {
|
||||||
|
ibd = block.getStateFromMeta(data);
|
||||||
|
} else {
|
||||||
|
ibd = block.getDefaultState();
|
||||||
|
}
|
||||||
|
return (BlockState) ibd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
sendChunk(fs, null);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCount(int tickingBlockCount, int nonEmptyBlockCount, ExtendedBlockStorage section) throws NoSuchFieldException, IllegalAccessException {
|
||||||
|
Class<? extends ExtendedBlockStorage> clazz = section.getClass();
|
||||||
|
Field fieldTickingBlockCount = clazz.getDeclaredField("field_76683_c");
|
||||||
|
Field fieldNonEmptyBlockCount = clazz.getDeclaredField("field_76682_b");
|
||||||
|
fieldTickingBlockCount.setAccessible(true);
|
||||||
|
fieldNonEmptyBlockCount.setAccessible(true);
|
||||||
|
fieldTickingBlockCount.set(section, tickingBlockCount);
|
||||||
|
fieldNonEmptyBlockCount.set(section, nonEmptyBlockCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FaweChunk<net.minecraft.world.chunk.Chunk> getFaweChunk(int x, int z) {
|
||||||
|
return new SpongeChunk_1_8(this, x, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CharFaweChunk getPrevious(CharFaweChunk fs, ExtendedBlockStorage[] sections, Map<?, ?> tilesGeneric, Collection<?>[] entitiesGeneric, Set<UUID> createdEntities, boolean all) throws Exception {
|
||||||
|
Settings.IMP.HISTORY.COMBINE_STAGES = false;
|
||||||
|
throw new UnsupportedOperationException("Combine stages not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean loadChunk(World world, int x, int z, boolean generate) {
|
||||||
|
return getCachedSections(world, x, z) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ExtendedBlockStorage[] getCachedSections(World world, int cx, int cz) {
|
||||||
|
net.minecraft.world.World nmsWorld = (net.minecraft.world.World) world;
|
||||||
|
IChunkProvider provider = nmsWorld.getChunkProvider();
|
||||||
|
net.minecraft.world.chunk.Chunk chunk = provider.provideChunk(cx, cz);
|
||||||
|
if (chunk == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (!chunk.isLoaded()) {
|
||||||
|
chunk.onChunkLoad();
|
||||||
|
}
|
||||||
|
return chunk.getBlockStorageArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getCombinedId4Data(char[] chars, int x, int y, int z) {
|
||||||
|
return chars[FaweCache.CACHE_J[y][z & 15][x & 15]];
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,233 @@
|
|||||||
|
/*
|
||||||
|
* WorldEdit, a Minecraft world manipulation toolkit
|
||||||
|
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||||
|
* Copyright (C) WorldEdit team and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
* Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sk89q.worldedit.sponge;
|
||||||
|
|
||||||
|
import com.flowpowered.math.vector.Vector3d;
|
||||||
|
import com.sk89q.util.StringUtil;
|
||||||
|
import com.sk89q.worldedit.Vector;
|
||||||
|
import com.sk89q.worldedit.WorldEditException;
|
||||||
|
import com.sk89q.worldedit.WorldVector;
|
||||||
|
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||||
|
import com.sk89q.worldedit.entity.BaseEntity;
|
||||||
|
import com.sk89q.worldedit.extension.platform.AbstractPlayerActor;
|
||||||
|
import com.sk89q.worldedit.extent.inventory.BlockBag;
|
||||||
|
import com.sk89q.worldedit.internal.LocalWorldAdapter;
|
||||||
|
import com.sk89q.worldedit.internal.cui.CUIEvent;
|
||||||
|
import com.sk89q.worldedit.session.SessionKey;
|
||||||
|
import com.sk89q.worldedit.util.Location;
|
||||||
|
import org.spongepowered.api.data.type.HandTypes;
|
||||||
|
import org.spongepowered.api.entity.living.player.Player;
|
||||||
|
import org.spongepowered.api.item.inventory.ItemStack;
|
||||||
|
import org.spongepowered.api.text.Text;
|
||||||
|
import org.spongepowered.api.text.format.TextColor;
|
||||||
|
import org.spongepowered.api.text.format.TextColors;
|
||||||
|
import org.spongepowered.api.text.serializer.TextSerializers;
|
||||||
|
import org.spongepowered.api.world.World;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class SpongePlayer extends AbstractPlayerActor {
|
||||||
|
|
||||||
|
private final Player player;
|
||||||
|
|
||||||
|
public SpongePlayer(SpongePlatform platform, Player player) {
|
||||||
|
this.player = player;
|
||||||
|
ThreadSafeCache.getInstance().getOnlineIds().add(getUniqueId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UUID getUniqueId() {
|
||||||
|
return player.getUniqueId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemInHand() {
|
||||||
|
Optional<ItemStack> is = this.player.getItemInHand(HandTypes.MAIN_HAND);
|
||||||
|
return is.isPresent() ? SpongeWorldEdit.inst().getAdapter().resolve(is.get().getItem()) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BaseBlock getBlockInHand() throws WorldEditException {
|
||||||
|
return new BaseBlock(getItemInHand(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return this.player.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BaseEntity getState() {
|
||||||
|
throw new UnsupportedOperationException("Cannot create a state from this object");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Location getLocation() {
|
||||||
|
org.spongepowered.api.world.Location<World> entityLoc = this.player.getLocation();
|
||||||
|
Vector3d entityRot = this.player.getRotation();
|
||||||
|
|
||||||
|
return SpongeWorldEdit.inst().getAdapter().adapt(entityLoc, entityRot);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WorldVector getPosition() {
|
||||||
|
Vector3d pos = this.player.getLocation().getPosition();
|
||||||
|
return new WorldVector(LocalWorldAdapter.adapt(SpongeWorldEdit.inst().getAdapter().getWorld(this.player.getWorld())), pos.getX(), pos.getY(), pos.getZ());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public com.sk89q.worldedit.world.World getWorld() {
|
||||||
|
return SpongeWorldEdit.inst().getAdapter().getWorld(player.getWorld());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getPitch() {
|
||||||
|
return getLocation().getPitch();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getYaw() {
|
||||||
|
return getLocation().getYaw();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void giveItem(int type, int amt) {
|
||||||
|
this.player.getInventory().offer(ItemStack.of(SpongeWorldEdit.inst().getAdapter().resolveItem(type), amt));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dispatchCUIEvent(CUIEvent event) {
|
||||||
|
String[] params = event.getParameters();
|
||||||
|
String send = event.getTypeId();
|
||||||
|
if (params.length > 0) {
|
||||||
|
send = send + "|" + StringUtil.joinString(params, "|");
|
||||||
|
}
|
||||||
|
|
||||||
|
String finalData = send;
|
||||||
|
CUIChannelHandler.getActiveChannel().sendTo(player, buffer -> buffer.writeBytes(finalData.getBytes(StandardCharsets.UTF_8)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void printRaw(String msg) {
|
||||||
|
for (String part : msg.split("\n")) {
|
||||||
|
this.player.sendMessage(TextSerializers.LEGACY_FORMATTING_CODE.deserialize(part));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void printDebug(String msg) {
|
||||||
|
sendColorized(msg, TextColors.GRAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void print(String msg) {
|
||||||
|
sendColorized(msg, TextColors.LIGHT_PURPLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void printError(String msg) {
|
||||||
|
sendColorized(msg, TextColors.RED);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendColorized(String msg, TextColor formatting) {
|
||||||
|
for (String part : msg.split("\n")) {
|
||||||
|
this.player.sendMessage(Text.of(formatting, TextSerializers.LEGACY_FORMATTING_CODE.deserialize(part)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPosition(Vector pos, float pitch, float yaw) {
|
||||||
|
org.spongepowered.api.world.Location<World> loc = new org.spongepowered.api.world.Location<>(
|
||||||
|
this.player.getWorld(), pos.getX(), pos.getY(), pos.getZ()
|
||||||
|
);
|
||||||
|
|
||||||
|
this.player.setLocationAndRotation(loc, new Vector3d(pitch, yaw, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] getGroups() {
|
||||||
|
return SpongeWorldEdit.inst().getPermissionsProvider().getGroups(this.player);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockBag getInventoryBlockBag() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasPermission(String perm) {
|
||||||
|
return SpongeWorldEdit.inst().getPermissionsProvider().hasPermission(player, perm);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public <T> T getFacet(Class<? extends T> cls) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SessionKey getSessionKey() {
|
||||||
|
return new SessionKeyImpl(player.getUniqueId(), player.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class SessionKeyImpl implements SessionKey {
|
||||||
|
// If not static, this will leak a reference
|
||||||
|
|
||||||
|
private final UUID uuid;
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
private SessionKeyImpl(UUID uuid, String name) {
|
||||||
|
this.uuid = uuid;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UUID getUniqueId() {
|
||||||
|
return uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isActive() {
|
||||||
|
// We can't directly check if the player is online because
|
||||||
|
// the list of players is not thread safe
|
||||||
|
return ThreadSafeCache.getInstance().getOnlineIds().contains(uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isPersistent() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Class<SpongePlayer> inject() {
|
||||||
|
return SpongePlayer.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,167 @@
|
|||||||
|
package com.sk89q.worldedit.sponge.chat;
|
||||||
|
|
||||||
|
import com.boydti.fawe.config.BBC;
|
||||||
|
import com.boydti.fawe.object.FawePlayer;
|
||||||
|
import com.boydti.fawe.sponge.SpongePlayer;
|
||||||
|
import com.boydti.fawe.util.chat.ChatManager;
|
||||||
|
import com.boydti.fawe.util.chat.Message;
|
||||||
|
import com.boydti.fawe.wrappers.FakePlayer;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.List;
|
||||||
|
import org.spongepowered.api.text.Text;
|
||||||
|
import org.spongepowered.api.text.action.TextActions;
|
||||||
|
import org.spongepowered.api.text.format.TextColor;
|
||||||
|
import org.spongepowered.api.text.format.TextColors;
|
||||||
|
import org.spongepowered.api.text.format.TextStyle;
|
||||||
|
import org.spongepowered.api.text.format.TextStyles;
|
||||||
|
import org.spongepowered.api.text.serializer.TextSerializers;
|
||||||
|
|
||||||
|
public class SpongeChatManager implements ChatManager<Text.Builder> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Text.Builder builder() {
|
||||||
|
return Text.builder();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void color(Message message, String color) {
|
||||||
|
TextColor tc = null;
|
||||||
|
TextStyle ts = null;
|
||||||
|
switch (color.charAt(1)) {
|
||||||
|
case 'a':
|
||||||
|
tc = TextColors.GREEN;
|
||||||
|
break;
|
||||||
|
case 'b':
|
||||||
|
tc = TextColors.AQUA;
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
tc = TextColors.RED;
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
tc = TextColors.LIGHT_PURPLE;
|
||||||
|
break;
|
||||||
|
case 'e':
|
||||||
|
tc = TextColors.YELLOW;
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
tc = TextColors.WHITE;
|
||||||
|
break;
|
||||||
|
case '1':
|
||||||
|
tc = TextColors.DARK_BLUE;
|
||||||
|
break;
|
||||||
|
case '2':
|
||||||
|
tc = TextColors.DARK_GREEN;
|
||||||
|
break;
|
||||||
|
case '3':
|
||||||
|
tc = TextColors.DARK_AQUA;
|
||||||
|
break;
|
||||||
|
case '4':
|
||||||
|
tc = TextColors.DARK_RED;
|
||||||
|
break;
|
||||||
|
case '5':
|
||||||
|
tc = TextColors.DARK_PURPLE;
|
||||||
|
break;
|
||||||
|
case '6':
|
||||||
|
tc = TextColors.GOLD;
|
||||||
|
break;
|
||||||
|
case '7':
|
||||||
|
tc = TextColors.GRAY;
|
||||||
|
break;
|
||||||
|
case '8':
|
||||||
|
tc = TextColors.DARK_GRAY;
|
||||||
|
break;
|
||||||
|
case '9':
|
||||||
|
tc = TextColors.BLUE;
|
||||||
|
break;
|
||||||
|
case '0':
|
||||||
|
tc = TextColors.BLACK;
|
||||||
|
break;
|
||||||
|
case 'k':
|
||||||
|
ts = TextStyles.OBFUSCATED;
|
||||||
|
break;
|
||||||
|
case 'l':
|
||||||
|
ts = TextStyles.BOLD;
|
||||||
|
break;
|
||||||
|
case 'm':
|
||||||
|
ts = TextStyles.UNDERLINE;
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
ts = TextStyles.STRIKETHROUGH;
|
||||||
|
break;
|
||||||
|
case 'o':
|
||||||
|
ts = TextStyles.ITALIC;
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
tc = TextColors.RESET;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (tc != null) {
|
||||||
|
apply(message, getChild(message).color(tc));
|
||||||
|
}
|
||||||
|
if (ts != null) {
|
||||||
|
apply(message, getChild(message).style(ts));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Text.Builder getChild(Message m) {
|
||||||
|
Text.Builder builder = m.$(this);
|
||||||
|
List<Text> children = builder.getChildren();
|
||||||
|
Text last = children.get(children.size() - 1);
|
||||||
|
builder.remove(last);
|
||||||
|
return Text.builder().append(last);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void apply(Message m, Text.Builder builder) {
|
||||||
|
m.$(this).append(builder.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tooltip(Message message, Message... tooltips) {
|
||||||
|
Text.Builder builder = Text.builder();
|
||||||
|
boolean lb = false;
|
||||||
|
for (Message tooltip : tooltips) {
|
||||||
|
if (lb) {
|
||||||
|
builder.append(Text.of("\n"));
|
||||||
|
}
|
||||||
|
builder.append(tooltip.$(this).build());
|
||||||
|
lb = true;
|
||||||
|
}
|
||||||
|
apply(message, getChild(message).onHover(TextActions.showText(builder.toText())));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void command(Message message, String command) {
|
||||||
|
apply(message, getChild(message).onClick(TextActions.runCommand(command)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void text(Message message, String text) {
|
||||||
|
message.$(this).append(TextSerializers.LEGACY_FORMATTING_CODE.deserialize(BBC.color(text)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void send(Message Message, FawePlayer player) {
|
||||||
|
if (player == FakePlayer.getConsole().toFawePlayer()) {
|
||||||
|
player.sendMessage(Message.$(this).build().toPlain());
|
||||||
|
} else {
|
||||||
|
((SpongePlayer) player).parent.sendMessage(Message.$(this).build());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void suggest(Message Message, String command) {
|
||||||
|
apply(Message, getChild(Message).onClick(TextActions.suggestCommand(command)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void link(Message message, String url) {
|
||||||
|
try {
|
||||||
|
if (!url.isEmpty()) {
|
||||||
|
apply(message, getChild(message).onClick(TextActions.openUrl(new URL(url))));
|
||||||
|
}
|
||||||
|
} catch (MalformedURLException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
0
sponge111/src/main/resources/config.yml
Normal file
0
sponge111/src/main/resources/config.yml
Normal file
Loading…
Reference in New Issue
Block a user