|
|
|
@ -1,14 +1,27 @@
|
|
|
|
|
package nautilus.game.arcade.game.games.uhc;
|
|
|
|
|
|
|
|
|
|
import java.lang.reflect.Field;
|
|
|
|
|
import java.lang.reflect.Method;
|
|
|
|
|
import java.util.ArrayList;
|
|
|
|
|
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 java.util.concurrent.ConcurrentHashMap;
|
|
|
|
|
import java.util.concurrent.ExecutorService;
|
|
|
|
|
import java.util.concurrent.Executors;
|
|
|
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
|
import java.util.concurrent.atomic.AtomicBoolean;
|
|
|
|
|
import java.util.concurrent.atomic.AtomicInteger;
|
|
|
|
|
|
|
|
|
|
import com.mineplex.spigot.ChunkPreLoadEvent;
|
|
|
|
|
import fr.neatmonster.nocheatplus.checks.CheckType;
|
|
|
|
|
import fr.neatmonster.nocheatplus.checks.access.IViolationInfo;
|
|
|
|
|
import fr.neatmonster.nocheatplus.hooks.NCPHook;
|
|
|
|
|
import fr.neatmonster.nocheatplus.hooks.NCPHookManager;
|
|
|
|
|
import mineplex.core.common.Pair;
|
|
|
|
|
import mineplex.core.common.util.C;
|
|
|
|
|
import mineplex.core.common.util.F;
|
|
|
|
|
import mineplex.core.common.util.NautHashMap;
|
|
|
|
@ -34,38 +47,35 @@ import mineplex.minecraft.game.core.damage.CustomDamageEvent;
|
|
|
|
|
import mineplex.serverdata.Utility;
|
|
|
|
|
import nautilus.game.arcade.ArcadeManager;
|
|
|
|
|
import nautilus.game.arcade.GameType;
|
|
|
|
|
import nautilus.game.arcade.events.GamePrepareCountdownCommence;
|
|
|
|
|
import nautilus.game.arcade.events.GameStateChangeEvent;
|
|
|
|
|
import nautilus.game.arcade.events.PlayerPrepareTeleportEvent;
|
|
|
|
|
import nautilus.game.arcade.game.Game;
|
|
|
|
|
import nautilus.game.arcade.game.GameTeam;
|
|
|
|
|
import nautilus.game.arcade.game.TeamGame;
|
|
|
|
|
import nautilus.game.arcade.game.Game.GameState;
|
|
|
|
|
import nautilus.game.arcade.kit.Kit;
|
|
|
|
|
|
|
|
|
|
import net.minecraft.server.v1_8_R3.BiomeCache;
|
|
|
|
|
import net.minecraft.server.v1_8_R3.ChunkCoordIntPair;
|
|
|
|
|
import net.minecraft.server.v1_8_R3.ChunkProviderServer;
|
|
|
|
|
import net.minecraft.server.v1_8_R3.EmptyChunk;
|
|
|
|
|
import net.minecraft.server.v1_8_R3.ExceptionWorldConflict;
|
|
|
|
|
import net.minecraft.server.v1_8_R3.ChunkRegionLoader;
|
|
|
|
|
import net.minecraft.server.v1_8_R3.FileIOThread;
|
|
|
|
|
import net.minecraft.server.v1_8_R3.IChunkLoader;
|
|
|
|
|
import net.minecraft.server.v1_8_R3.IChunkProvider;
|
|
|
|
|
import net.minecraft.server.v1_8_R3.LongHashMap;
|
|
|
|
|
import net.minecraft.server.v1_8_R3.MinecraftServer;
|
|
|
|
|
import net.minecraft.server.v1_8_R3.NBTTagCompound;
|
|
|
|
|
import net.minecraft.server.v1_8_R3.World;
|
|
|
|
|
import net.minecraft.server.v1_8_R3.WorldChunkManager;
|
|
|
|
|
import net.minecraft.server.v1_8_R3.WorldServer;
|
|
|
|
|
import org.bukkit.Bukkit;
|
|
|
|
|
import org.bukkit.ChatColor;
|
|
|
|
|
import org.bukkit.Chunk;
|
|
|
|
|
import org.bukkit.Difficulty;
|
|
|
|
|
import org.bukkit.Location;
|
|
|
|
|
import org.bukkit.Material;
|
|
|
|
|
import org.bukkit.Sound;
|
|
|
|
|
import org.bukkit.World;
|
|
|
|
|
import org.bukkit.WorldBorder;
|
|
|
|
|
import org.bukkit.World.Environment;
|
|
|
|
|
import org.bukkit.block.Block;
|
|
|
|
|
import org.bukkit.block.BlockFace;
|
|
|
|
|
import org.bukkit.craftbukkit.v1_8_R3.CraftWorld;
|
|
|
|
|
import org.bukkit.craftbukkit.v1_8_R3.generator.NormalChunkGenerator;
|
|
|
|
|
import org.bukkit.craftbukkit.v1_8_R3.util.LongHash;
|
|
|
|
|
import org.bukkit.enchantments.Enchantment;
|
|
|
|
|
import org.bukkit.entity.Entity;
|
|
|
|
@ -74,24 +84,27 @@ import org.bukkit.entity.Ghast;
|
|
|
|
|
import org.bukkit.entity.LivingEntity;
|
|
|
|
|
import org.bukkit.entity.Monster;
|
|
|
|
|
import org.bukkit.entity.Player;
|
|
|
|
|
import org.bukkit.entity.Villager;
|
|
|
|
|
import org.bukkit.event.EventHandler;
|
|
|
|
|
import org.bukkit.event.EventPriority;
|
|
|
|
|
import org.bukkit.event.block.BlockBreakEvent;
|
|
|
|
|
import org.bukkit.event.block.BlockPlaceEvent;
|
|
|
|
|
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
|
|
|
|
import org.bukkit.event.entity.EntityDamageEvent;
|
|
|
|
|
import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
|
|
|
|
|
import org.bukkit.event.entity.EntityDeathEvent;
|
|
|
|
|
import org.bukkit.event.entity.EntityExplodeEvent;
|
|
|
|
|
import org.bukkit.event.entity.EntityRegainHealthEvent;
|
|
|
|
|
import org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason;
|
|
|
|
|
import org.bukkit.event.entity.EntitySpawnEvent;
|
|
|
|
|
import org.bukkit.event.entity.PlayerDeathEvent;
|
|
|
|
|
import org.bukkit.event.inventory.PrepareItemCraftEvent;
|
|
|
|
|
import org.bukkit.event.player.PlayerChangedWorldEvent;
|
|
|
|
|
import org.bukkit.event.player.AsyncPlayerPreLoginEvent;
|
|
|
|
|
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
|
|
|
|
|
import org.bukkit.event.player.PlayerInteractEntityEvent;
|
|
|
|
|
import org.bukkit.event.player.PlayerItemConsumeEvent;
|
|
|
|
|
import org.bukkit.event.player.PlayerJoinEvent;
|
|
|
|
|
import org.bukkit.event.player.PlayerKickEvent;
|
|
|
|
|
import org.bukkit.event.player.PlayerLoginEvent;
|
|
|
|
|
import org.bukkit.event.player.PlayerPickupItemEvent;
|
|
|
|
|
import org.bukkit.event.player.PlayerPortalEvent;
|
|
|
|
|
import org.bukkit.event.player.PlayerQuitEvent;
|
|
|
|
@ -107,10 +120,16 @@ import org.bukkit.potion.PotionEffect;
|
|
|
|
|
import org.bukkit.potion.PotionEffectType;
|
|
|
|
|
import org.bukkit.scoreboard.DisplaySlot;
|
|
|
|
|
import org.bukkit.scoreboard.Objective;
|
|
|
|
|
import org.spigotmc.WatchdogThread;
|
|
|
|
|
import org.spigotmc.AsyncCatcher;
|
|
|
|
|
|
|
|
|
|
public class UHC extends TeamGame
|
|
|
|
|
public class UHC extends TeamGame implements NCPHook
|
|
|
|
|
{
|
|
|
|
|
// The view distance of UHC. The amount of time and ram needed grows polynomially
|
|
|
|
|
private static final int VIEW_DISTANCE = 5;
|
|
|
|
|
|
|
|
|
|
// The number of threads to use for reading chunks from disk
|
|
|
|
|
private static final int THREADS_FOR_CHUNK_LOADING = 4;
|
|
|
|
|
|
|
|
|
|
private NautHashMap<Player, Player> _teamReqs = new NautHashMap<Player, Player>();
|
|
|
|
|
|
|
|
|
|
private NautHashMap<String, Long> _deathTime = new NautHashMap<String, Long>();
|
|
|
|
@ -145,6 +164,14 @@ public class UHC extends TeamGame
|
|
|
|
|
private double _previousBorder = 1000;
|
|
|
|
|
private long _borderStartedMoving;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private volatile boolean _isDecorating = false;
|
|
|
|
|
private volatile boolean _allowSpawning = true;
|
|
|
|
|
private int _teleportedPlayers = -1;
|
|
|
|
|
private int _totalPlayers = 0;
|
|
|
|
|
private AtomicInteger actual = new AtomicInteger();
|
|
|
|
|
private AtomicInteger expected = new AtomicInteger(23000); // Most likely it'll be around 23000
|
|
|
|
|
|
|
|
|
|
public UHC(ArcadeManager manager)
|
|
|
|
|
{
|
|
|
|
|
this(manager, GameType.UHC);
|
|
|
|
@ -157,7 +184,7 @@ public class UHC extends TeamGame
|
|
|
|
|
DamageDealt
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public UHC(ArcadeManager manager, GameType type)
|
|
|
|
|
{
|
|
|
|
|
super(manager, type,
|
|
|
|
@ -181,7 +208,7 @@ public class UHC extends TeamGame
|
|
|
|
|
|
|
|
|
|
this.GameTimeout = 10800000;
|
|
|
|
|
|
|
|
|
|
this.DamagePvP = false;
|
|
|
|
|
this.DamagePvP = true;
|
|
|
|
|
|
|
|
|
|
this.DeathDropItems = true;
|
|
|
|
|
|
|
|
|
@ -213,8 +240,6 @@ public class UHC extends TeamGame
|
|
|
|
|
|
|
|
|
|
this.WorldBoundaryKill = false;
|
|
|
|
|
|
|
|
|
|
this.TickPerTeleport = 3;
|
|
|
|
|
|
|
|
|
|
this.GemBoosterEnabled = false;
|
|
|
|
|
this.GemDoubleEnabled = false;
|
|
|
|
|
this.GemHunterEnabled = false;
|
|
|
|
@ -243,6 +268,8 @@ public class UHC extends TeamGame
|
|
|
|
|
|
|
|
|
|
_createTime = System.currentTimeMillis();
|
|
|
|
|
_serverTime = Utility.currentTimeMillis();
|
|
|
|
|
|
|
|
|
|
NCPHookManager.addHook(CheckType.ALL, this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
@ -274,23 +301,6 @@ public class UHC extends TeamGame
|
|
|
|
|
border.setWarningTime(-99);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@EventHandler
|
|
|
|
|
public void onDamage(CustomDamageEvent event)
|
|
|
|
|
{
|
|
|
|
|
if (!IsLive())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (UtilTime.elapsed(getGameLiveTime(), 20000))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (!(event.GetDamageeEntity() instanceof Player))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
event.SetCancelled("Spawn Invincibility");
|
|
|
|
|
event.GetDamageeEntity().setFireTicks(0);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@EventHandler
|
|
|
|
|
public void onSecond(UpdateEvent event)
|
|
|
|
|
{
|
|
|
|
@ -479,6 +489,333 @@ public class UHC extends TeamGame
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TimingManager.stop("UHC Spawn Generation");
|
|
|
|
|
|
|
|
|
|
Location spawn = GetRandomSpawn(WorldData.World.getSpawnLocation());
|
|
|
|
|
WorldData.World.setSpawnLocation(spawn.getBlockX(), spawn.getBlockY(), spawn.getBlockZ());
|
|
|
|
|
|
|
|
|
|
WorldServer worldServer = ((CraftWorld) WorldData.World).getHandle();
|
|
|
|
|
|
|
|
|
|
// Update view distance
|
|
|
|
|
worldServer.spigotConfig.viewDistance = VIEW_DISTANCE;
|
|
|
|
|
worldServer.getPlayerChunkMap().a(VIEW_DISTANCE);
|
|
|
|
|
|
|
|
|
|
if (Runtime.getRuntime().maxMemory() / 1024 / 1024 < 2048)
|
|
|
|
|
{
|
|
|
|
|
Announce(C.cGreen + C.Bold + "Skipping spawn pregeneration", false);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Ensures the server does not tick us
|
|
|
|
|
worldServer.getMinecraftServer().worlds.remove(worldServer);
|
|
|
|
|
|
|
|
|
|
_allowSpawning = false;
|
|
|
|
|
|
|
|
|
|
new Thread(() ->
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
TimingManager.start("UHC Chunk Loading");
|
|
|
|
|
|
|
|
|
|
ChunkProviderServer chunkProviderServer = worldServer.chunkProviderServer;
|
|
|
|
|
|
|
|
|
|
Field chunkLoaderField = chunkProviderServer.getClass().getDeclaredField("chunkLoader");
|
|
|
|
|
chunkLoaderField.setAccessible(true);
|
|
|
|
|
|
|
|
|
|
ChunkRegionLoader loader = (ChunkRegionLoader) chunkLoaderField.get(chunkProviderServer);
|
|
|
|
|
|
|
|
|
|
Map<Long, net.minecraft.server.v1_8_R3.Chunk> loaded = new ConcurrentHashMap<>();
|
|
|
|
|
Map<Long, NBTTagCompound> compounds = new ConcurrentHashMap<>();
|
|
|
|
|
|
|
|
|
|
// Step 1: Read all the required chunks from the disk
|
|
|
|
|
// We're going to read all the required chunks from disk async
|
|
|
|
|
{
|
|
|
|
|
Set<Pair<Integer, Integer>> coordPairs = new HashSet<>();
|
|
|
|
|
|
|
|
|
|
// Special case for 0, 0
|
|
|
|
|
{
|
|
|
|
|
int x = spawn.getBlockX() >> 4;
|
|
|
|
|
int z = spawn.getBlockZ() >> 4;
|
|
|
|
|
|
|
|
|
|
for (int dx = -VIEW_DISTANCE; dx <= VIEW_DISTANCE; dx++)
|
|
|
|
|
{
|
|
|
|
|
for (int dz = -VIEW_DISTANCE; dz <= VIEW_DISTANCE; dz++)
|
|
|
|
|
{
|
|
|
|
|
coordPairs.add(Pair.create(x + dx, z + dz));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// All the team spawns
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < GetTeamList().size(); i++)
|
|
|
|
|
{
|
|
|
|
|
GameTeam team = GetTeamList().get(i);
|
|
|
|
|
for (Location l : team.GetSpawns())
|
|
|
|
|
{
|
|
|
|
|
int x = l.getChunk().getX();
|
|
|
|
|
int z = l.getChunk().getZ();
|
|
|
|
|
|
|
|
|
|
for (int dx = -VIEW_DISTANCE; dx <= VIEW_DISTANCE; dx++)
|
|
|
|
|
{
|
|
|
|
|
for (int dz = -VIEW_DISTANCE; dz <= VIEW_DISTANCE; dz++)
|
|
|
|
|
{
|
|
|
|
|
coordPairs.add(Pair.create(x + dx, z + dz));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Sigh... I don't want this to be here but it needs to be set somewhere...
|
|
|
|
|
// Multiply by 3 because there are 3 stages
|
|
|
|
|
expected.set(coordPairs.size() * 3);
|
|
|
|
|
|
|
|
|
|
// Load them now
|
|
|
|
|
ExecutorService chunkLoaders = Executors.newFixedThreadPool(THREADS_FOR_CHUNK_LOADING);
|
|
|
|
|
|
|
|
|
|
for (Pair<Integer, Integer> coords : coordPairs)
|
|
|
|
|
{
|
|
|
|
|
chunkLoaders.submit(() ->
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
Object[] data = loader.loadChunk(worldServer, coords.getLeft(), coords.getRight());
|
|
|
|
|
if (data != null)
|
|
|
|
|
{
|
|
|
|
|
NBTTagCompound compound = (NBTTagCompound) data[1];
|
|
|
|
|
net.minecraft.server.v1_8_R3.Chunk chunk = (net.minecraft.server.v1_8_R3.Chunk) data[0];
|
|
|
|
|
loaded.put(LongHash.toLong(coords.getLeft(), coords.getRight()), chunk);
|
|
|
|
|
compounds.put(LongHash.toLong(coords.getLeft(), coords.getRight()), compound);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
System.out.println("Failed to load chunk " + coords.getLeft() + "," + coords.getRight());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Throwable t)
|
|
|
|
|
{
|
|
|
|
|
t.printStackTrace();
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
actual.getAndIncrement();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
chunkLoaders.shutdown();
|
|
|
|
|
|
|
|
|
|
// We've got plenty of time to wait
|
|
|
|
|
System.out.println("Finished submitting tasks to executor, waiting...");
|
|
|
|
|
chunkLoaders.awaitTermination(1, TimeUnit.DAYS);
|
|
|
|
|
|
|
|
|
|
System.out.println("Loaded: " + loaded.size() + " and coords: " + coordPairs.size());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Step 2: Recreate structures, update neighbors, load entities
|
|
|
|
|
// This step should be super quick so there's no point in scheduling it elsewhere
|
|
|
|
|
// Code is plain copypasted from ChunkIOProvider
|
|
|
|
|
{
|
|
|
|
|
for (net.minecraft.server.v1_8_R3.Chunk chunk : loaded.values())
|
|
|
|
|
{
|
|
|
|
|
NBTTagCompound compound = compounds.get(LongHash.toLong(chunk.locX, chunk.locZ));
|
|
|
|
|
loader.loadEntities(chunk, compound.getCompound("Level"), worldServer);
|
|
|
|
|
chunk.setLastSaved(chunkProviderServer.world.getTime());
|
|
|
|
|
if (chunkProviderServer.chunkProvider != null)
|
|
|
|
|
{
|
|
|
|
|
chunkProviderServer.chunkProvider.recreateStructures(chunk, chunk.locX, chunk.locZ);
|
|
|
|
|
}
|
|
|
|
|
for (int x = -2; x < 3; ++x)
|
|
|
|
|
{
|
|
|
|
|
for (int z = -2; z < 3; ++z)
|
|
|
|
|
{
|
|
|
|
|
if (x != 0 || z != 0)
|
|
|
|
|
{
|
|
|
|
|
net.minecraft.server.v1_8_R3.Chunk neighbor = loaded.get(LongHash.toLong(chunk.locX + x, chunk.locZ + z));
|
|
|
|
|
if (neighbor != null)
|
|
|
|
|
{
|
|
|
|
|
neighbor.setNeighborLoaded(-x, -z);
|
|
|
|
|
chunk.setNeighborLoaded(x, z);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
actual.getAndIncrement();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AtomicBoolean lockCompleted = new AtomicBoolean(false);
|
|
|
|
|
Object lock = new Object();
|
|
|
|
|
|
|
|
|
|
// Hop back onto the main thread
|
|
|
|
|
Manager.runSync(() ->
|
|
|
|
|
{
|
|
|
|
|
// We want to add all the chunks to the chunkmap so that the server is not out of sync
|
|
|
|
|
for (Map.Entry<Long, net.minecraft.server.v1_8_R3.Chunk> ent : loaded.entrySet())
|
|
|
|
|
{
|
|
|
|
|
ent.getValue().addEntities();
|
|
|
|
|
chunkProviderServer.chunks.put(ent.getKey(), ent.getValue());
|
|
|
|
|
}
|
|
|
|
|
lockCompleted.set(true);
|
|
|
|
|
synchronized (lock)
|
|
|
|
|
{
|
|
|
|
|
lock.notifyAll();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (!lockCompleted.get())
|
|
|
|
|
{
|
|
|
|
|
synchronized (lock)
|
|
|
|
|
{
|
|
|
|
|
lock.wait();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!lockCompleted.get())
|
|
|
|
|
{
|
|
|
|
|
throw new IllegalStateException("Lock was not completed");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Step 3: Decorate the chunks. This step must be performed async as otherwise the server lags way too hard
|
|
|
|
|
// Notes: Do not allow the server to tick the world. If this is allowed EntityTracker will raise CME
|
|
|
|
|
// NextTickList will also raise errors
|
|
|
|
|
// And worst case the server will crash
|
|
|
|
|
{
|
|
|
|
|
// Live life on the edge
|
|
|
|
|
AsyncCatcher.enabled = false;
|
|
|
|
|
_isDecorating = true;
|
|
|
|
|
int x = 0;
|
|
|
|
|
for (net.minecraft.server.v1_8_R3.Chunk chunk : loaded.values())
|
|
|
|
|
{
|
|
|
|
|
loadNearby(chunkProviderServer, chunkProviderServer, chunk.locX, chunk.locZ, worldServer, chunk);
|
|
|
|
|
x++;
|
|
|
|
|
if (x % 100 == 0)
|
|
|
|
|
{
|
|
|
|
|
System.out.println(x);
|
|
|
|
|
}
|
|
|
|
|
actual.getAndIncrement();
|
|
|
|
|
}
|
|
|
|
|
TimingManager.stop("UHC Chunk Loading");
|
|
|
|
|
_isDecorating = false;
|
|
|
|
|
AsyncCatcher.enabled = true;
|
|
|
|
|
|
|
|
|
|
System.out.println("Expected: " + expected.get() + ", actual: " + actual.get());
|
|
|
|
|
|
|
|
|
|
Manager.runSync(() ->
|
|
|
|
|
{
|
|
|
|
|
World world = worldServer.getWorld();
|
|
|
|
|
for (Entity entity : world.getLivingEntities())
|
|
|
|
|
{
|
|
|
|
|
if (!(entity instanceof Player) && !(entity instanceof Villager))
|
|
|
|
|
{
|
|
|
|
|
entity.remove();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// You may tick again
|
|
|
|
|
worldServer.getMinecraftServer().worlds.add(worldServer);
|
|
|
|
|
|
|
|
|
|
// Well, if they're not equal, not much we can do. We've hit the end
|
|
|
|
|
actual.set(expected.get());
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Throwable t)
|
|
|
|
|
{
|
|
|
|
|
t.printStackTrace();
|
|
|
|
|
}
|
|
|
|
|
}, "Chunk Loader").start();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Plain copypasted from Chunk, but modified so that it doesn't load surrounding chunks if they're nonexistant
|
|
|
|
|
// This decorates the chunks. Do not remove!
|
|
|
|
|
public void loadNearby(ChunkProviderServer ichunkprovider, ChunkProviderServer ichunkprovider1, int i, int j, net.minecraft.server.v1_8_R3.World world, net.minecraft.server.v1_8_R3.Chunk chunk1)
|
|
|
|
|
{
|
|
|
|
|
boolean flag = ichunkprovider.isChunkLoaded(i, j - 1);
|
|
|
|
|
boolean flag1 = ichunkprovider.isChunkLoaded(i + 1, j);
|
|
|
|
|
boolean flag2 = ichunkprovider.isChunkLoaded(i, j + 1);
|
|
|
|
|
boolean flag3 = ichunkprovider.isChunkLoaded(i - 1, j);
|
|
|
|
|
boolean flag4 = ichunkprovider.isChunkLoaded(i - 1, j - 1);
|
|
|
|
|
boolean flag5 = ichunkprovider.isChunkLoaded(i + 1, j + 1);
|
|
|
|
|
boolean flag6 = ichunkprovider.isChunkLoaded(i - 1, j + 1);
|
|
|
|
|
boolean flag7 = ichunkprovider.isChunkLoaded(i + 1, j - 1);
|
|
|
|
|
if (flag1 && flag2 && flag5)
|
|
|
|
|
{
|
|
|
|
|
if (!chunk1.isDone())
|
|
|
|
|
{
|
|
|
|
|
ichunkprovider.getChunkAt(ichunkprovider1, i, j);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ichunkprovider.a(ichunkprovider1, chunk1, i, j);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
net.minecraft.server.v1_8_R3.Chunk chunk;
|
|
|
|
|
if (flag3 && flag2 && flag6)
|
|
|
|
|
{
|
|
|
|
|
chunk = ichunkprovider.getChunkIfLoaded(i - 1, j);
|
|
|
|
|
if (chunk != null)
|
|
|
|
|
{
|
|
|
|
|
if (!chunk.isDone())
|
|
|
|
|
{
|
|
|
|
|
ichunkprovider.getChunkAt(ichunkprovider1, i - 1, j);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ichunkprovider.a(ichunkprovider1, chunk, i - 1, j);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (flag && flag1 && flag7)
|
|
|
|
|
{
|
|
|
|
|
chunk = ichunkprovider.getChunkIfLoaded(i, j - 1);
|
|
|
|
|
if (chunk != null)
|
|
|
|
|
{
|
|
|
|
|
if (!chunk.isDone())
|
|
|
|
|
{
|
|
|
|
|
ichunkprovider.getChunkAt(ichunkprovider1, i, j - 1);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ichunkprovider.a(ichunkprovider1, chunk, i, j - 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (flag4 && flag && flag3)
|
|
|
|
|
{
|
|
|
|
|
chunk = ichunkprovider.getChunkIfLoaded(i - 1, j - 1);
|
|
|
|
|
if (chunk != null)
|
|
|
|
|
{
|
|
|
|
|
if (!chunk.isDone())
|
|
|
|
|
{
|
|
|
|
|
ichunkprovider.getChunkAt(ichunkprovider1, i - 1, j - 1);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ichunkprovider.a(ichunkprovider1, chunk, i - 1, j - 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@EventHandler
|
|
|
|
|
public void on(EntitySpawnEvent event)
|
|
|
|
|
{
|
|
|
|
|
// Don't allow entity spawns while decorating, period
|
|
|
|
|
if (_isDecorating || !_allowSpawning)
|
|
|
|
|
{
|
|
|
|
|
if (event.getLocation().getWorld().getUID() == WorldData.World.getUID())
|
|
|
|
|
{
|
|
|
|
|
event.setCancelled(true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private boolean areSpawnsGenerated()
|
|
|
|
|
{
|
|
|
|
|
return actual.get() == expected.get();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@EventHandler
|
|
|
|
@ -675,7 +1012,7 @@ public class UHC extends TeamGame
|
|
|
|
|
while (!stopGen)
|
|
|
|
|
{
|
|
|
|
|
long now = System.currentTimeMillis();
|
|
|
|
|
if ((now - last) >= 4000)
|
|
|
|
|
if ((now - last) >= 10 * 1000)
|
|
|
|
|
{
|
|
|
|
|
Announce(C.cGreen + C.Bold + "Generating Map: " + C.cWhite + getMapLoadETA() + " Remaining...", false);
|
|
|
|
|
last = now;
|
|
|
|
@ -745,6 +1082,170 @@ public class UHC extends TeamGame
|
|
|
|
|
}, "WorldGen Thread").start();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@EventHandler
|
|
|
|
|
public void on(ChunkUnloadEvent event)
|
|
|
|
|
{
|
|
|
|
|
if (IsLive())
|
|
|
|
|
return;
|
|
|
|
|
event.setCancelled(true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private volatile boolean _isTeleporting = false;
|
|
|
|
|
|
|
|
|
|
@EventHandler
|
|
|
|
|
public void on(ChunkPreLoadEvent event)
|
|
|
|
|
{
|
|
|
|
|
if (_isTeleporting)
|
|
|
|
|
{
|
|
|
|
|
System.out.println("WARNING: TRIED TO LOAD CHUNK WHILE TELEPORTING: " + event.getX() + " " + event.getZ());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@EventHandler(priority = EventPriority.MONITOR)
|
|
|
|
|
public void on(PlayerKickEvent event)
|
|
|
|
|
{
|
|
|
|
|
// Don't kick players while teleporting. Probably NCP trying to kick for fly or something
|
|
|
|
|
if (_isTeleporting)
|
|
|
|
|
{
|
|
|
|
|
event.setCancelled(true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@EventHandler(priority = EventPriority.LOW)
|
|
|
|
|
public void PlayerPrepare(GameStateChangeEvent event)
|
|
|
|
|
{
|
|
|
|
|
final Game game = event.GetGame();
|
|
|
|
|
|
|
|
|
|
if (event.GetState() != GameState.Prepare)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
_isTeleporting = true;
|
|
|
|
|
|
|
|
|
|
List<Player> players = game.GetPlayers(true);
|
|
|
|
|
|
|
|
|
|
Location zero = WorldData.World.getSpawnLocation();
|
|
|
|
|
|
|
|
|
|
for (Player player : players)
|
|
|
|
|
{
|
|
|
|
|
player.teleport(zero);
|
|
|
|
|
|
|
|
|
|
// Heal
|
|
|
|
|
player.setHealth(player.getMaxHealth());
|
|
|
|
|
// Resistance and regen
|
|
|
|
|
player.addPotionEffect(new PotionEffect(PotionEffectType.REGENERATION, 30 * 20, 128), true);
|
|
|
|
|
player.addPotionEffect(new PotionEffect(PotionEffectType.DAMAGE_RESISTANCE, 30 * 20, 128), true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Announce(C.cGreen + C.Bold + "Please wait while you are teleported to your spawn", false);
|
|
|
|
|
|
|
|
|
|
_totalPlayers = players.size();
|
|
|
|
|
|
|
|
|
|
Map<UUID, Location> teleportedLocations = new HashMap<>();
|
|
|
|
|
|
|
|
|
|
AtomicInteger id = new AtomicInteger();
|
|
|
|
|
id.set(UtilServer.getServer().getScheduler().runTaskTimer(Manager.getPlugin(), () ->
|
|
|
|
|
{
|
|
|
|
|
_teleportedPlayers++;
|
|
|
|
|
if (_teleportedPlayers >= players.size())
|
|
|
|
|
{
|
|
|
|
|
Manager.runSyncLater(() ->
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
for (Player player : players)
|
|
|
|
|
{
|
|
|
|
|
GameTeam team = game.GetTeam(player);
|
|
|
|
|
if (team != null)
|
|
|
|
|
{
|
|
|
|
|
if (teleportedLocations.get(player.getUniqueId()) != null)
|
|
|
|
|
{
|
|
|
|
|
team.SpawnTeleport(player, teleportedLocations.get(player.getUniqueId()));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Heal
|
|
|
|
|
player.setHealth(player.getMaxHealth());
|
|
|
|
|
// Resistance and regen
|
|
|
|
|
player.addPotionEffect(new PotionEffect(PotionEffectType.REGENERATION, 30 * 20, 128), true);
|
|
|
|
|
player.addPotionEffect(new PotionEffect(PotionEffectType.DAMAGE_RESISTANCE, 30 * 20, 128), true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
game.AnnounceGame();
|
|
|
|
|
game.StartPrepareCountdown();
|
|
|
|
|
|
|
|
|
|
//Event
|
|
|
|
|
GamePrepareCountdownCommence gamePrepareCountdownCommence = new GamePrepareCountdownCommence(game);
|
|
|
|
|
UtilServer.getServer().getPluginManager().callEvent(gamePrepareCountdownCommence);
|
|
|
|
|
|
|
|
|
|
_isTeleporting = false;
|
|
|
|
|
|
|
|
|
|
Manager.runSyncLater(() ->
|
|
|
|
|
{
|
|
|
|
|
for (Player player : players)
|
|
|
|
|
{
|
|
|
|
|
player.removePotionEffect(PotionEffectType.DAMAGE_RESISTANCE);
|
|
|
|
|
player.removePotionEffect(PotionEffectType.REGENERATION);
|
|
|
|
|
}
|
|
|
|
|
}, 10 * 20L);
|
|
|
|
|
// Yes, right now they're both set to 10 seconds, but this may change in the future
|
|
|
|
|
Manager.runSyncLater(() ->
|
|
|
|
|
{
|
|
|
|
|
_allowSpawning = true;
|
|
|
|
|
}, 10 * 20L);
|
|
|
|
|
}
|
|
|
|
|
}, 3 * 20L);
|
|
|
|
|
Bukkit.getServer().getScheduler().cancelTask(id.get());
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Player player = players.get(_teleportedPlayers);
|
|
|
|
|
GameTeam team = game.GetTeam(player);
|
|
|
|
|
|
|
|
|
|
// This could happen if the player left (and rejoined) while teleporting
|
|
|
|
|
// Team maps based on player as a key
|
|
|
|
|
if (team != null)
|
|
|
|
|
{
|
|
|
|
|
// Save where they teleported
|
|
|
|
|
teleportedLocations.put(player.getUniqueId(), team.SpawnTeleport(player));
|
|
|
|
|
|
|
|
|
|
// Update scoreboard
|
|
|
|
|
_scoreObj.getScore(player).setScore((int) player.getMaxHealth());
|
|
|
|
|
|
|
|
|
|
game.addPlayerInTime(player);
|
|
|
|
|
|
|
|
|
|
Manager.Clear(player);
|
|
|
|
|
UtilInv.Clear(player);
|
|
|
|
|
|
|
|
|
|
// Heal
|
|
|
|
|
player.setHealth(player.getMaxHealth());
|
|
|
|
|
// Resistance and regen
|
|
|
|
|
player.addPotionEffect(new PotionEffect(PotionEffectType.REGENERATION, 30 * 20, 128), true);
|
|
|
|
|
player.addPotionEffect(new PotionEffect(PotionEffectType.DAMAGE_RESISTANCE, 30 * 20, 128), true);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
game.ValidateKit(player, game.GetTeam(player));
|
|
|
|
|
|
|
|
|
|
if (game.GetKit(player) != null)
|
|
|
|
|
game.GetKit(player).ApplyKit(player);
|
|
|
|
|
|
|
|
|
|
//Event
|
|
|
|
|
PlayerPrepareTeleportEvent playerStateEvent = new PlayerPrepareTeleportEvent(game, player);
|
|
|
|
|
UtilServer.getServer().getPluginManager().callEvent(playerStateEvent);
|
|
|
|
|
}
|
|
|
|
|
}, 4 * 20L, 4L).getTaskId());
|
|
|
|
|
|
|
|
|
|
//Spectators Move
|
|
|
|
|
for (Player player : UtilServer.getPlayers())
|
|
|
|
|
{
|
|
|
|
|
if (Manager.GetGame().IsAlive(player))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
Manager.addSpectator(player, true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@EventHandler
|
|
|
|
|
public void WorldBoundaryYLimit(BlockPlaceEvent event)
|
|
|
|
|
{
|
|
|
|
@ -758,10 +1259,14 @@ public class UHC extends TeamGame
|
|
|
|
|
|
|
|
|
|
public Location GetRandomSpawn(Location around)
|
|
|
|
|
{
|
|
|
|
|
// Sometimes getting a random spawn at 0,0 hangs forever
|
|
|
|
|
int tries = 0;
|
|
|
|
|
|
|
|
|
|
Location loc = null;
|
|
|
|
|
|
|
|
|
|
while (loc == null)
|
|
|
|
|
{
|
|
|
|
|
tries++;
|
|
|
|
|
Block block = null;
|
|
|
|
|
|
|
|
|
|
// Get Team Location
|
|
|
|
@ -776,8 +1281,8 @@ public class UHC extends TeamGame
|
|
|
|
|
// Get Radius Location
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
block = UtilBlock.getHighest(WorldData.World, around.getBlockX() - 4 + UtilMath.r(8), around.getBlockZ() - 4
|
|
|
|
|
+ UtilMath.r(8), null);
|
|
|
|
|
block = UtilBlock.getHighest(WorldData.World, around.getBlockX() - 4 + UtilMath.r(tries < 10 ? 8 : 30), around.getBlockZ() - 4
|
|
|
|
|
+ UtilMath.r(tries < 10 ? 8 : 30), null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check Validity
|
|
|
|
@ -786,6 +1291,9 @@ public class UHC extends TeamGame
|
|
|
|
|
if (block.getRelative(BlockFace.DOWN).isLiquid())
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (block.getRelative(BlockFace.DOWN).getType() == Material.AIR)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
// Suffocated
|
|
|
|
|
if (block.getType() != Material.AIR || block.getRelative(BlockFace.UP).getType() != Material.AIR)
|
|
|
|
|
continue;
|
|
|
|
@ -1273,8 +1781,18 @@ public class UHC extends TeamGame
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Scoreboard.WriteBlank();
|
|
|
|
|
Scoreboard.Write(C.cYellow + C.Bold + "Time");
|
|
|
|
|
Scoreboard.Write(UtilTime.MakeStr(System.currentTimeMillis() - GetStateTime()));
|
|
|
|
|
if (GetState() == GameState.Prepare)
|
|
|
|
|
{
|
|
|
|
|
Scoreboard.Write(C.cYellow + C.Bold + "Status");
|
|
|
|
|
int players = _teleportedPlayers + 1;
|
|
|
|
|
if (players > _totalPlayers) players = _totalPlayers;
|
|
|
|
|
Scoreboard.Write("Teleporting Players (" + players + "/" + _totalPlayers + ")");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Scoreboard.Write(C.cYellow + C.Bold + "Time");
|
|
|
|
|
Scoreboard.Write(UtilTime.MakeStr(System.currentTimeMillis() - GetStateTime()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Scoreboard.WriteBlank();
|
|
|
|
|
Scoreboard.Write(C.cYellow + C.Bold + "Borders");
|
|
|
|
@ -1584,8 +2102,8 @@ public class UHC extends TeamGame
|
|
|
|
|
if (visible)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(visible)
|
|
|
|
|
|
|
|
|
|
if (visible)
|
|
|
|
|
setOreType(vein);
|
|
|
|
|
|
|
|
|
|
// Remove Vein
|
|
|
|
@ -1609,15 +2127,15 @@ public class UHC extends TeamGame
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void setOreType(ArrayList<Block> blocks)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public boolean isMapLoaded()
|
|
|
|
|
{
|
|
|
|
|
return _mapLoaded;
|
|
|
|
|
return _mapLoaded && areSpawnsGenerated();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public String getMapLoadPercent()
|
|
|
|
@ -1625,6 +2143,23 @@ public class UHC extends TeamGame
|
|
|
|
|
return (int) (_mapLoadPercent * 100) + "%";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public String getSpawnGenPercent()
|
|
|
|
|
{
|
|
|
|
|
return UtilMath.clamp((int) ((actual.get() * 1.0 / expected.get()) * 100), 0, 100) + "%";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public String getObjectiveName(boolean _colorTick)
|
|
|
|
|
{
|
|
|
|
|
if (!getMapLoadPercent().equals("100%"))
|
|
|
|
|
{
|
|
|
|
|
return getMapLoadPercent() + " " + (_colorTick ? ChatColor.GREEN : ChatColor.YELLOW) + "§l" + "Generating Map";
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return getSpawnGenPercent() + " " + (_colorTick ? ChatColor.GREEN : ChatColor.YELLOW) + "§l" + "Generating Spawns";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public String getMapLoadETA()
|
|
|
|
|
{
|
|
|
|
|
int chunksToGo = _chunkTotal - _chunksLoaded;
|
|
|
|
@ -1768,4 +2303,26 @@ public class UHC extends TeamGame
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public String getHookName()
|
|
|
|
|
{
|
|
|
|
|
return "UHC Hook";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public String getHookVersion()
|
|
|
|
|
{
|
|
|
|
|
return "0.0.1";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public boolean onCheckFailure(CheckType checkType, Player player, IViolationInfo iViolationInfo)
|
|
|
|
|
{
|
|
|
|
|
if (GetState() == GameState.Prepare)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|