Many changes

Fix spectator race condition
Refactor out cut clean into modules
Add combat log module
Add antixray module
This commit is contained in:
samczsun 2016-07-13 15:03:26 -04:00 committed by cnr
parent a7b30f4f59
commit 7dcf7378ef
20 changed files with 1917 additions and 654 deletions

View File

@ -0,0 +1,59 @@
package mineplex.core.common.util;
import org.bukkit.event.entity.EntityDamageEvent;
public class UtilParser
{
public static String parseDamageCause(EntityDamageEvent.DamageCause cause)
{
switch (cause)
{
case CONTACT:
return "Cactus";
case ENTITY_ATTACK:
return "Attack";
case PROJECTILE:
return "Ranged Weapon";
case SUFFOCATION:
return "Suffocation";
case FALL:
return "Fall";
case FIRE:
return "Fire";
case FIRE_TICK:
return "Burning";
case MELTING:
return "Melting";
case LAVA:
return "Lava";
case DROWNING:
return "Drowning";
case BLOCK_EXPLOSION:
return "Explosion";
case ENTITY_EXPLOSION:
return "Explosion";
case VOID:
return "Void";
case LIGHTNING:
return "Lightning";
case SUICIDE:
return "Suicide";
case STARVATION:
return "Hunger";
case POISON:
return "Poison";
case MAGIC:
return "Thrown Potion";
case WITHER:
return "Wither Effect";
case FALLING_BLOCK:
return "Falling Block";
case THORNS:
return "Thorns Enchantment";
case CUSTOM:
return "Custom";
default:
return "The Mighty defek7";
}
}
}

View File

@ -227,7 +227,8 @@ public class InventoryManager extends MiniDbClientPlugin<ClientInventory>
event.getInventory().setItem(1, new ItemStack(Material.INK_SACK, level, (byte) 4));
}
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
// fixme broken cast
// @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void onBlockBreak(BlockBreakEvent event)
{
if (event.getBlock().getType() != Material.ENCHANTMENT_TABLE)

View File

@ -204,6 +204,7 @@ public abstract class Game implements Listener
public boolean WorldLeavesDecay = false;
public boolean WorldSoilTrample = false;
public boolean WorldBoneMeal = false;
public boolean WorldChunkUnload = false;
public int HungerSet = -1;
public int HealthSet = -1;
@ -423,13 +424,14 @@ public abstract class Game implements Listener
System.out.println("Loading " + GetName() + "...");
}
public void registerModule(Module module)
public <T extends Module> T registerModule(T module)
{
if (!_modules.containsKey(module.getClass()))
{
module.initialize(this);
_modules.put(module.getClass(), module);
UtilServer.RegisterEvents(module);
module.initialize(this);
return module;
}
else
{
@ -437,6 +439,16 @@ public abstract class Game implements Listener
}
}
public void unregisterModule(Module module)
{
if (_modules.containsKey(module.getClass()) && _modules.get(module.getClass()) == module)
{
_modules.remove(module.getClass());
module.cleanup();
HandlerList.unregisterAll(module);
}
}
public void setKits(Kit[] kits)
{
_kits = kits;

View File

@ -1,33 +1,38 @@
package nautilus.game.arcade.game;
import mineplex.core.common.util.*;
import mineplex.core.common.util.UtilTime.*;
import mineplex.core.updater.*;
import mineplex.core.updater.event.*;
import nautilus.game.arcade.*;
import nautilus.game.arcade.events.*;
import nautilus.game.arcade.game.GameTeam.*;
import nautilus.game.arcade.kit.*;
import nautilus.game.arcade.stats.TeamDeathsStatTracker;
import nautilus.game.arcade.stats.TeamKillsStatTracker;
import mineplex.core.common.util.C;
import mineplex.core.common.util.NautHashMap;
import mineplex.core.common.util.UtilTime;
import mineplex.core.common.util.UtilTime.TimeUnit;
import mineplex.core.updater.UpdateType;
import mineplex.core.updater.event.UpdateEvent;
import nautilus.game.arcade.ArcadeManager;
import nautilus.game.arcade.GameType;
import nautilus.game.arcade.events.PlayerStateChangeEvent;
import nautilus.game.arcade.game.GameTeam.PlayerState;
import nautilus.game.arcade.kit.Kit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerLoginEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.Bukkit;
import org.bukkit.entity.*;
import org.bukkit.event.*;
import org.bukkit.event.player.*;
import java.util.*;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public abstract class TeamGame extends Game
{
public long RejoinTime = 120000;
protected ArrayList<GameTeam> _places = new ArrayList<GameTeam>();
private NautHashMap<String, Long> _rejoinTime = new NautHashMap<String, Long>();
protected NautHashMap<String, GameTeam> RejoinTeam = new NautHashMap<String, GameTeam>();
protected NautHashMap<String, Kit> RejoinKit = new NautHashMap<String, Kit>();
protected NautHashMap<String, Double> RejoinHealth = new NautHashMap<String, Double>();
protected long RejoinTime = 120000;
public NautHashMap<String, Long> RejoinTimes = new NautHashMap<String, Long>();
public NautHashMap<String, GameTeam> RejoinTeam = new NautHashMap<String, GameTeam>();
public NautHashMap<String, Kit> RejoinKit = new NautHashMap<String, Kit>();
public NautHashMap<String, Double> RejoinHealth = new NautHashMap<String, Double>();
public TeamGame(ArcadeManager manager, GameType gameType, Kit[] kits, String[] gameDesc)
{
@ -54,7 +59,7 @@ public abstract class TeamGame extends Game
return _places;
}
@EventHandler(priority = EventPriority.LOWEST)
@EventHandler(priority = EventPriority.LOW)
public void PlayerQuit(PlayerQuitEvent event)
{
if (!InProgress())
@ -79,7 +84,7 @@ public abstract class TeamGame extends Game
if (!QuitOut)
{
//Store
_rejoinTime.put(player.getName(), System.currentTimeMillis());
RejoinTimes.put(player.getName(), System.currentTimeMillis());
RejoinTeam.put(player.getName(), team);
if (GetKit(player) != null)
@ -102,7 +107,7 @@ public abstract class TeamGame extends Game
//Rejoined
GameTeam team = RejoinTeam.remove(event.getPlayer().getName());
if (team != null && _rejoinTime.remove(event.getPlayer().getName()) != null)
if (team != null && RejoinTimes.remove(event.getPlayer().getName()) != null)
{
team.AddPlayer(event.getPlayer(), true);
Announce(team.GetColor() + C.Bold + event.getPlayer().getName() + " has reconnected!", false);
@ -126,8 +131,6 @@ public abstract class TeamGame extends Game
// }
// }
// }, 20);
return;
}
}
@ -143,7 +146,21 @@ public abstract class TeamGame extends Game
if (RejoinHealth.containsKey(player.getName()))
{
double health = RejoinHealth.remove(player.getName());
player.setHealth(health);
if (health > 0)
{
getArcadeManager().runSyncLater(() ->
{
player.setHealth(health);
}, 1L);
}
}
if (GetLocationStore().containsKey(player.getName()))
{
getArcadeManager().runSyncLater(() ->
{
player.teleport(GetLocationStore().remove(player.getName()));
}, 1L);
}
}
@ -153,13 +170,13 @@ public abstract class TeamGame extends Game
if (event.getType() != UpdateType.SEC || QuitOut)
return;
Iterator<String> rejoinIterator = _rejoinTime.keySet().iterator();
Iterator<String> rejoinIterator = RejoinTimes.keySet().iterator();
while (rejoinIterator.hasNext())
{
String name = rejoinIterator.next();
if (!UtilTime.elapsed(_rejoinTime.get(name), RejoinTime))
if (!UtilTime.elapsed(RejoinTimes.get(name), RejoinTime))
continue;
rejoinIterator.remove();
@ -187,7 +204,7 @@ public abstract class TeamGame extends Game
}
else
{
_rejoinTime.put(toks[1], System.currentTimeMillis());
RejoinTimes.put(toks[1], System.currentTimeMillis());
event.getPlayer().sendMessage("Allowed " + toks[1] + " to rejoin!");
}

View File

@ -16,11 +16,12 @@ import mineplex.core.common.util.UtilBlock;
import mineplex.core.common.util.UtilEvent;
import mineplex.core.common.util.UtilInv;
import mineplex.core.common.util.UtilMath;
import mineplex.core.common.util.UtilParser;
import mineplex.core.common.util.UtilPlayer;
import mineplex.core.common.util.UtilServer;
import mineplex.core.common.util.UtilTextMiddle;
import mineplex.core.common.util.UtilTime;
import mineplex.core.common.util.UtilWorld;
import mineplex.core.itemstack.ItemBuilder;
import mineplex.core.itemstack.ItemStackFactory;
import mineplex.core.recharge.Recharge;
import mineplex.core.timing.TimingManager;
@ -38,14 +39,17 @@ import nautilus.game.arcade.game.GameTeam;
import nautilus.game.arcade.game.TeamGame;
import nautilus.game.arcade.game.games.uhc.helpers.ChunkLoadingThread;
import nautilus.game.arcade.game.games.uhc.helpers.WorldGenThread;
import nautilus.game.arcade.game.modules.OreVeinEditorModule;
import nautilus.game.arcade.game.modules.TeamModule;
import nautilus.game.arcade.game.modules.antixray.AntiXrayModule;
import nautilus.game.arcade.game.modules.combatlog.CombatLogModule;
import nautilus.game.arcade.game.modules.combatlog.CombatLogNPC;
import nautilus.game.arcade.kit.Kit;
import net.minecraft.server.v1_8_R3.Chunk;
import net.minecraft.server.v1_8_R3.MathHelper;
import net.minecraft.server.v1_8_R3.MinecraftServer;
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;
@ -54,9 +58,8 @@ import org.bukkit.World.Environment;
import org.bukkit.WorldBorder;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.craftbukkit.v1_8_R3.CraftChunk;
import org.bukkit.block.BlockState;
import org.bukkit.craftbukkit.v1_8_R3.CraftWorld;
import org.bukkit.craftbukkit.v1_8_R3.entity.CraftEntity;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
@ -68,7 +71,9 @@ import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.HandlerList;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.Action;
import org.bukkit.event.block.BlockGrowEvent;
import org.bukkit.event.block.BlockPistonExtendEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
@ -81,6 +86,7 @@ import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.PrepareItemCraftEvent;
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerItemConsumeEvent;
import org.bukkit.event.player.PlayerKickEvent;
import org.bukkit.event.player.PlayerPickupItemEvent;
@ -88,6 +94,7 @@ import org.bukkit.event.player.PlayerPortalEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.bukkit.event.world.ChunkUnloadEvent;
import org.bukkit.event.world.StructureGrowEvent;
import org.bukkit.inventory.CraftingInventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.ShapedRecipe;
@ -96,16 +103,17 @@ import org.bukkit.inventory.meta.SkullMeta;
import org.bukkit.material.MaterialData;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.scoreboard.DisplaySlot;
import org.bukkit.scoreboard.Objective;
import org.spigotmc.ActivationRange;
import java.lang.reflect.Field;
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.atomic.AtomicInteger;
@ -120,12 +128,27 @@ public class UHC extends TeamGame implements NCPHook
// The number of minutes after which PVP should be enabled
public static final int SAFE_TIME_IN_MINUTES = 11;
// The number of chunks to unload per tick
public static final int CHUNKS_UNLOAD_PER_TICK = 1;
// This is the region in which nothing can be done (block placing, flowing, etc)
public static final int SAFE_REGION = 36;
// The amount of damage to give from hitting the world border
public static final int WORLD_BORDER_DAMAGE = 5;
// The thread responsible for generating the world
private final WorldGenThread _worldGenThread = new WorldGenThread(this);
// The thread responsible for loading and decorating the world
private final ChunkLoadingThread _chunkLoadingThread = new ChunkLoadingThread(this);
// The chunks which we have prevented unloading
private final Set<Chunk> _loadedChunks = new HashSet<>();
// The task which will unload chunks periodically
private BukkitRunnable _chunkUnloadTask;
// The number of minutes passed in this game
private int _minutesSinceStart = 0;
@ -139,8 +162,6 @@ public class UHC extends TeamGame implements NCPHook
// Whether players are teleporting currently
private volatile boolean _isTeleporting = false;
private boolean xrayDebug;
// Border
private int _secondsSinceStart;
private HashMap<Integer, Double> _borderPositions = new HashMap<Integer, Double>();
@ -159,6 +180,11 @@ public class UHC extends TeamGame implements NCPHook
DamageTaken,
DamageDealt
);
registerModule(
new OreVeinEditorModule()
.removeNonAirVeins()
);
}
public UHC(ArcadeManager manager, GameType type)
@ -176,12 +202,12 @@ public class UHC extends TeamGame implements NCPHook
"Borders shrink over time", "Last player/team alive wins!"
});
_gamesRun++;
this.HideTeamSheep = true;
this.StrictAntiHack = true;
AnnounceStay = false;
this.GameTimeout = 10800000;
this.DamagePvP = false;
@ -229,6 +255,10 @@ public class UHC extends TeamGame implements NCPHook
WorldTimeSet = -1;
this.WorldLeavesDecay = true;
this.WorldBlockGrow = true;
this.WorldSoilTrample = true;
this.WorldBoneMeal = true;
this.WorldChunkUnload = true;
CraftRecipes();
@ -247,6 +277,31 @@ public class UHC extends TeamGame implements NCPHook
NCPHookManager.addHook(CheckType.ALL, this);
registerModule(new TeamModule());
registerModule(new AntiXrayModule())
.setEnabled(true)
.setUpdateOnDamage(true)
.setAntiTexturePacksAndFreecam(false)
.setUseProximityHider(false)
.setEngineMode(2)
.setInitialRadius(1)
.setUpdateRadius(2)
.setObfuscateBlocks(
Material.GOLD_ORE,
Material.IRON_ORE,
Material.LAPIS_ORE,
Material.DIAMOND_ORE,
Material.REDSTONE_ORE,
Material.GLOWING_REDSTONE_ORE,
Material.EMERALD_ORE
)
.setRandomBlocks(
Material.GOLD_ORE,
Material.IRON_ORE,
Material.LAPIS_ORE,
Material.DIAMOND_ORE,
Material.REDSTONE_ORE,
Material.EMERALD_ORE
);
}
@Override
@ -345,7 +400,7 @@ public class UHC extends TeamGame implements NCPHook
if (Manager.IsAlive(player))
{
Manager.GetDamage().NewDamageEvent(player, null, null, DamageCause.CUSTOM, 10, false, false, false,
Manager.GetDamage().NewDamageEvent(player, null, null, DamageCause.CUSTOM, WORLD_BORDER_DAMAGE, false, false, false,
"Nether Field", "Vaporize");
player.getWorld().playSound(loc, Sound.NOTE_BASS, 2f, 1f);
@ -358,6 +413,36 @@ public class UHC extends TeamGame implements NCPHook
}
}
}
if (getModule(CombatLogModule.class) != null)
{
for (CombatLogNPC npc : getModule(CombatLogModule.class).getAllNPCs())
{
LivingEntity ent = npc.getNPC();
Location loc = ent.getLocation();
// Bump Players Back In
if (loc.getX() > border || loc.getX() < -border || loc.getZ() > border || loc.getZ() < -border)
{
// Can't use recharge on entities; blame bad design (mapping by name instead of uuid)
// if (Recharge.Instance.use(ent, "Hit by Border", 1000, false, false))
{
Entity bottom = ent;
while (bottom.getVehicle() != null)
bottom = bottom.getVehicle();
UtilAction
.velocity(bottom, UtilAlg.getTrajectory2d(loc, GetSpectatorLocation()), 1.2, true, 0.4, 0, 10, true);
Manager.GetDamage().NewDamageEvent(ent, null, null, DamageCause.CUSTOM, WORLD_BORDER_DAMAGE, false, false, false,
"Nether Field", "Vaporize");
ent.getWorld().playSound(loc, Sound.NOTE_BASS, 2f, 1f);
ent.getWorld().playSound(loc, Sound.NOTE_BASS, 2f, 1f);
}
}
}
}
}
private ArrayList<Double> buildBorders(int seconds, double border, double leaveRemaining)
@ -517,7 +602,70 @@ public class UHC extends TeamGame implements NCPHook
this.DamagePvP = true;
this.CompassGiveItem = true;
this.QuitOut = true;
this.RejoinTime = 300000; // 5 minutes
registerModule(
new CombatLogModule()
.setSpawnForCreative(false)
.setCombatLogTime(300000)
.setOnDeathAction(npc ->
{
if (npc.getLastDamager() instanceof Player)
{
Player killer = (Player) npc.getLastDamager();
Announce(npc.getPlayerInfo().getTeamColor() + C.Bold + npc.getPlayerInfo().getName()
+ C.cGray + C.Bold + " was killed by " + getArcadeManager().GetColor(killer)
+ C.Bold + npc.getLastDamager().getName() + C.cGray + C.Bold + " while logged out.");
}
else
{
String cause = UtilParser.parseDamageCause(npc.getLastDamageCause());
if (npc.getLastDamager() != null)
{
cause = npc.getLastDamager().getName();
}
Announce(npc.getPlayerInfo().getTeamColor() + C.Bold + npc.getPlayerInfo().getName()
+ C.cGray + C.Bold + " was killed by " + cause + " while logged out.");
}
ItemStack stack = new ItemBuilder(Material.SKULL_ITEM)
.setData((byte) 3)
.setTitle(npc.getPlayerInfo().getTeamColor() + npc.getPlayerInfo().getName() + "'s Head")
.build();
SkullMeta meta = (SkullMeta) stack.getItemMeta();
meta.setOwner(npc.getPlayerInfo().getName());
stack.setItemMeta(meta);
npc.getNPC().getWorld().dropItemNaturally(npc.getNPC().getLocation(), stack);
Location location = npc.getNPC().getLocation();
for (ItemStack item : npc.getPlayerInfo().getItems())
{
location.getWorld().dropItemNaturally(location, item);
}
})
.setOnExpireAction(npc ->
{
ItemStack stack = new ItemBuilder(Material.SKULL_ITEM)
.setData((byte) 3)
.setTitle(npc.getPlayerInfo().getTeamColor() + npc.getPlayerInfo().getName() + "'s Head")
.build();
SkullMeta meta = (SkullMeta) stack.getItemMeta();
meta.setOwner(npc.getPlayerInfo().getName());
stack.setItemMeta(meta);
npc.getNPC().getWorld().dropItemNaturally(npc.getNPC().getLocation(), stack);
Location location = npc.getNPC().getLocation();
for (ItemStack item : npc.getPlayerInfo().getItems())
{
location.getWorld().dropItemNaturally(location, item);
}
})
);
}
}
@ -581,6 +729,27 @@ public class UHC extends TeamGame implements NCPHook
}
HandlerList.unregisterAll(_chunkLoadingThread);
NCPHookManager.removeHook(this);
if (_chunkUnloadTask != null)
{
try
{
_chunkUnloadTask.cancel();
}
catch (IllegalStateException ex)
{
// bukkit
}
}
Iterator<Chunk> iterator = _loadedChunks.iterator();
while (iterator.hasNext())
{
Chunk chunk = iterator.next();
WorldData.World.unloadChunk(chunk.getX(), chunk.getZ());
iterator.remove();
}
return;
}
@ -592,16 +761,13 @@ public class UHC extends TeamGame implements NCPHook
_worldGenThread.start();
}
@EventHandler (priority = EventPriority.MONITOR, ignoreCancelled = false)
@EventHandler(priority = EventPriority.MONITOR)
public void on(ChunkUnloadEvent event)
{
if (IsLive())
{
event.setCancelled(false);
}
else
if (!IsLive())
{
event.setCancelled(true);
_loadedChunks.add(event.getChunk());
}
}
@ -641,11 +807,11 @@ public class UHC extends TeamGame implements NCPHook
Location zero = WorldData.World.getSpawnLocation();
// fixme if you leave while teleporting you'll rejoin at 0,0
for (Player player : players)
{
player.teleport(zero);
player.hidePlayer(player);
// Heal
player.setHealth(player.getMaxHealth());
// Resistance and regen
@ -711,14 +877,31 @@ public class UHC extends TeamGame implements NCPHook
WorldData.World.setAutoSave(true);
int x = 0;
for (org.bukkit.Chunk chunk : WorldData.World.getLoadedChunks())
_chunkUnloadTask = new BukkitRunnable()
{
if (WorldData.World.unloadChunkRequest(chunk.getX(), chunk.getZ()))
@Override
public void run()
{
System.out.println("Requesting unload of chunk #" + (++x) + " " + chunk.getX() + " " + chunk.getZ());
Iterator<Chunk> iterator = _loadedChunks.iterator();
int amount = 0;
while (amount < CHUNKS_UNLOAD_PER_TICK && iterator.hasNext())
{
Chunk next = iterator.next();
if (WorldData.World.unloadChunkRequest(next.getX(), next.getZ()))
{
System.out.println("Requesting unload of chunk " + next.getX() + " " + next.getZ());
}
iterator.remove();
amount++;
}
if (_loadedChunks.size() == 0)
{
cancel();
}
}
}
};
}, 10 * 20L);
}
}, 5 * 20L);
@ -821,17 +1004,90 @@ public class UHC extends TeamGame implements NCPHook
return SpectatorSpawn;
}
// fixme flowing water and stuff
@EventHandler
public void WorldBoundaryYLimit(BlockPlaceEvent event)
public void preventBlockPlacement(BlockPlaceEvent event)
{
if (event.getBlock().getX() >= -36 && event.getBlock().getX() <= 36 && event.getBlock().getZ() >= -36
&& event.getBlock().getZ() <= 36)
if (isInSafeZone(event.getBlock().getLocation()))
{
UtilPlayer.message(event.getPlayer(), F.main("Game", "You cannot build this high near center of map."));
event.setCancelled(true);
}
}
@EventHandler
public void preventStructureGrow(StructureGrowEvent event)
{
Iterator<BlockState> blocks = event.getBlocks().iterator();
while (blocks.hasNext())
{
BlockState next = blocks.next();
if (isInSafeZone(next.getLocation()))
{
blocks.remove();
}
}
}
@EventHandler
public void preventBlockGrow(BlockGrowEvent event)
{
if (isInSafeZone(event.getBlock().getLocation()))
{
event.setCancelled(true);
}
}
@EventHandler
public void preventBoneMeal(PlayerInteractEvent event)
{
if (event.getAction() == Action.RIGHT_CLICK_BLOCK)
{
boolean isIllegal = false;
if (!isIllegal)
{
isIllegal = event.getPlayer().getItemInHand().getType() == Material.INK_SACK &&
event.getPlayer().getItemInHand().getData().getData() == (byte) 15;
}
if (!isIllegal)
{
isIllegal = event.getPlayer().getItemInHand().getType() == Material.WATER_BUCKET
|| event.getPlayer().getItemInHand().getType() == Material.LAVA_BUCKET;
}
if (isIllegal && isInSafeZone(event.getClickedBlock().getLocation()))
{
event.setCancelled(true);
}
}
}
@EventHandler
public void preventPistons(BlockPistonExtendEvent event)
{
boolean willBeUnsafe = false;
for (Block block : event.getBlocks())
{
if (isInSafeZone(block.getRelative(event.getDirection()).getLocation()))
{
willBeUnsafe = true;
break;
}
}
if (willBeUnsafe)
{
event.setCancelled(true);
}
}
private boolean isInSafeZone(Location location)
{
return location.getX() <= SAFE_REGION && location.getX() >= -SAFE_REGION
&& location.getZ() < SAFE_REGION && location.getZ() >= -SAFE_REGION;
}
// fixme world decoration means random spawns which were clear before might not be after
public Location GetRandomSpawn(Location around)
{
// Sometimes getting a random spawn at 0,0 hangs forever
@ -1019,7 +1275,7 @@ public class UHC extends TeamGame implements NCPHook
if (event.getType() != UpdateType.SLOW)
return;
HashMap<EntityType, ArrayList<Entity>> ents = new HashMap<EntityType, ArrayList<Entity>>();
Map<EntityType, ArrayList<Entity>> ents = new HashMap<>();
for (Entity ent : WorldData.World.getEntities())
{
@ -1573,82 +1829,12 @@ public class UHC extends TeamGame implements NCPHook
return true;
}
private static int _gamesRun = 0;
@EventHandler
public void on(PlayerCommandPreprocessEvent event)
{
if (event.getMessage().equals("/uhcentities"))
{
CoreClient client = getArcadeManager().GetClients().Get(event.getPlayer());
if (client.GetRank().has(Rank.DEVELOPER))
{
for (Entity entity : event.getPlayer().getNearbyEntities(5.0, 5.0, 5.0))
{
net.minecraft.server.v1_8_R3.Entity nms = ((CraftEntity) entity).getHandle();
String debug = "Entity: " + entity.getType() + " id:" + nms.getId() + " inac:" + ActivationRange.checkIfActive(nms);
debug += " at:" + nms.activatedTick + " dac:" + nms.defaultActivationState;
int x = MathHelper.floor(nms.locX);
int z = MathHelper.floor(nms.locZ);
net.minecraft.server.v1_8_R3.Chunk chunk = nms.world.getChunkIfLoaded(x >> 4, z >> 4);
debug += " c:" + chunk + " il:" + (chunk != null ? chunk.areNeighborsLoaded(1) : "null");
event.getPlayer().sendMessage(debug);
}
event.setCancelled(true);
}
}
else if (event.getMessage().equals("/uhcchunk"))
{
CoreClient client = getArcadeManager().GetClients().Get(event.getPlayer());
if (client.GetRank().has(Rank.DEVELOPER))
{
net.minecraft.server.v1_8_R3.Chunk chunk = ((CraftChunk) event.getPlayer().getLocation().getChunk()).getHandle();
try
{
Field neighbors = chunk.getClass().getDeclaredField("neighbors");
neighbors.setAccessible(true);
int n = neighbors.getInt(chunk);
for (int x = -1; x < 2; x++)
{
for (int z = -1; z < 2; z++)
{
if (x == 0 && z == 0)
{
continue;
}
int mask = 0x1 << (x * 5 + z + 12);
boolean should = chunk.world.getChunkIfLoaded(chunk.locX + x, chunk.locZ + z) != null;
boolean is = (n & mask) == mask;
if (is && should)
{
event.getPlayer().sendMessage(ChatColor.GREEN + "Chunk " + (chunk.locX + x) + "," + (chunk.locZ + z) + " (" + x + "," + z + ") is a neighbor");
}
else if (is && !should)
{
event.getPlayer().sendMessage(ChatColor.RED + "Chunk " + (chunk.locX + x) + "," + (chunk.locZ + z) + " (" + x + "," + z + ") is a neighbor but should not be");
}
else if (!is && should)
{
event.getPlayer().sendMessage(ChatColor.RED + "Chunk " + (chunk.locX + x) + "," + (chunk.locZ + z) + " (" + x + "," + z + ") is not a neighbor but should be");
}
else if (!is && !should)
{
event.getPlayer().sendMessage(ChatColor.GREEN + "Chunk " + (chunk.locX + x) + "," + (chunk.locZ + z) + " (" + x + "," + z + ") is not a neighbor");
}
}
}
}
catch (Throwable t)
{
t.printStackTrace();
}
event.setCancelled(true);
}
}
else if (event.getMessage().equals("/uhcgc"))
if (event.getMessage().equals("/uhcgc"))
{
CoreClient client = getArcadeManager().GetClients().Get(event.getPlayer());
if (client.GetRank().has(Rank.DEVELOPER))
@ -1658,53 +1844,6 @@ public class UHC extends TeamGame implements NCPHook
event.setCancelled(true);
}
}
else if (event.getMessage().equals("/uhcallchunks"))
{
CoreClient client = getArcadeManager().GetClients().Get(event.getPlayer());
if (client.GetRank().has(Rank.DEVELOPER))
{
for (Chunk chunk : ((CraftWorld) event.getPlayer().getWorld()).getHandle().chunkProviderServer.chunks.values())
{
try
{
Field neighbors = chunk.getClass().getDeclaredField("neighbors");
neighbors.setAccessible(true);
int n = neighbors.getInt(chunk);
for (int x = -1; x < 2; x++)
{
for (int z = -1; z < 2; z++)
{
if (x == 0 && z == 0)
{
continue;
}
int mask = 0x1 << (x * 5 + z + 12);
boolean should = chunk.world.getChunkIfLoaded(chunk.locX + x, chunk.locZ + z) != null;
boolean is = (n & mask) == mask;
if (is && !should)
{
event.getPlayer().sendMessage(ChatColor.RED + "Chunk " + (chunk.locX + x) + "," + (chunk.locZ + z) + " (" + x + "," + z + ") relative to " + (chunk.locX) + "," + chunk.locZ + " is a neighbor but should not be");
}
else if (!is && should)
{
event.getPlayer().sendMessage(ChatColor.RED + "Chunk " + (chunk.locX + x) + "," + (chunk.locZ + z) + " (" + x + "," + z + ") relative to " + (chunk.locX) + "," + chunk.locZ + " is not a neighbor but should be");
}
}
}
}
catch (Throwable t)
{
t.printStackTrace();
}
}
event.getPlayer().sendMessage("Done");
event.setCancelled(true);
}
}
else if (event.getMessage().equals("/uhcworlds"))
{
CoreClient client = getArcadeManager().GetClients().Get(event.getPlayer());
@ -1734,183 +1873,14 @@ public class UHC extends TeamGame implements NCPHook
event.setCancelled(true);
}
}
}
@EventHandler(priority = EventPriority.MONITOR)
public void xrayBlockBreak(BlockBreakEvent event)
{
if (event.isCancelled())
return;
if (xrayDebug)
TimingManager.start("Block Break");
int range = 3;
// Find Nearby Ores
ArrayList<Block> ores = findOres(event.getBlock(), range);
// Anti-Xray
removeNonAirVeins(generateVeins(ores));
if (xrayDebug)
TimingManager.stop("Block Break");
}
private ArrayList<Block> findOres(Block source, int range)
{
ArrayList<Block> ores = new ArrayList<Block>();
for (int x = -range; x <= range; x++)
for (int z = -range; z <= range; z++)
for (int y = -range; y <= range; y++)
{
Block block = source.getRelative(x, y, z);
findOreFromBlock(ores, block);
}
if (xrayDebug)
for (Block debug : ores)
System.out.println("Found " + debug.getType() + " at " + UtilWorld.locToStrClean(debug.getLocation()));
return ores;
}
public void findOreFromBlock(ArrayList<Block> ores, Block block)
{
if (ores.contains(block))
return;
if (isOre(block))
else if (event.getMessage().equals("/uhcgames"))
{
ores.add(block);
for (Block neighbour : UtilBlock.getSurrounding(block, true))
CoreClient client = getArcadeManager().GetClients().Get(event.getPlayer());
if (client.GetRank().has(Rank.DEVELOPER))
{
findOreFromBlock(ores, neighbour);
event.getPlayer().sendMessage("Games run: " + _gamesRun);
event.setCancelled(true);
}
}
}
public boolean isOre(Block block)
{
return (block.getType() == Material.IRON_ORE || block.getType() == Material.GOLD_ORE || block.getType() == Material.DIAMOND_ORE);
}
private ArrayList<ArrayList<Block>> generateVeins(ArrayList<Block> ores)
{
ArrayList<ArrayList<Block>> veins = new ArrayList<ArrayList<Block>>();
while (!ores.isEmpty())
{
Block block = ores.remove(0);
if (xrayDebug)
System.out.println("NEW VEIN - " + block.getType());
// Start New Vein
ArrayList<Block> vein = new ArrayList<Block>();
veins.add(vein);
vein.add(block);
// Find Vein Ores
boolean addedToVein = true;
while (addedToVein)
{
addedToVein = false;
Iterator<Block> oreIterator = ores.iterator();
while (oreIterator.hasNext())
{
Block ore = oreIterator.next();
boolean inVein = false;
// Check if in Vein
for (Block veinOre : vein)
{
// if (veinOre.getType() != ore.getType())
// continue;
if (UtilMath.offset(ore.getLocation(), veinOre.getLocation()) <= 2)
{
inVein = true;
break;
}
}
// Add to Vein
if (inVein)
{
vein.add(ore);
oreIterator.remove();
addedToVein = true;
}
}
}
if (xrayDebug)
for (Block veinOre : vein)
System.out.println(UtilWorld.locToStrClean(veinOre.getLocation()));
}
return veins;
}
private void removeNonAirVeins(ArrayList<ArrayList<Block>> oreVeins)
{
// Remove Non-Aired Veins
for (ArrayList<Block> vein : oreVeins)
{
boolean visible = false;
// Check if Air is near Vein
for (Block ore : vein)
{
for (Block visibleCheckBlock : UtilBlock.getSurrounding(ore, true))
{
if (visibleCheckBlock.getType() == Material.AIR || UtilBlock.isVisible(visibleCheckBlock))
{
visible = true;
}
if (visible)
break;
}
if (visible)
break;
}
if (visible)
setOreType(vein);
// Remove Vein
if (!visible)
{
if (xrayDebug)
System.out.println("DELETING VEIN;");
for (Block ore : vein)
{
if (xrayDebug)
System.out.println(ore.getType() + " " + UtilWorld.locToStrClean(ore.getLocation()));
ore.setType(Material.STONE);
}
}
else
{
if (xrayDebug)
System.out.println("VALID VEIN!");
}
}
}
public void setOreType(ArrayList<Block> blocks)
{
}
}

View File

@ -1,112 +1,63 @@
package nautilus.game.arcade.game.games.uhc.modes;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.entity.EntityDeathEvent;
import org.bukkit.inventory.ItemStack;
import mineplex.core.common.util.UtilInv;
import mineplex.core.common.util.UtilMath;
import mineplex.core.itemstack.ItemStackFactory;
import mineplex.core.itemstack.ItemBuilder;
import nautilus.game.arcade.ArcadeManager;
import nautilus.game.arcade.GameType;
import nautilus.game.arcade.events.GameStateChangeEvent;
import nautilus.game.arcade.game.games.uhc.UHC;
import nautilus.game.arcade.game.modules.CutCleanModule;
import nautilus.game.arcade.game.modules.ItemGiverModule;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
/**
* CutClean gamemode for UHC
/*
* The CutClean variant of UHC
*
* @author xXVevzZXx
* This is identical to UHC however iron and gold ore will immediately smelt
* and mob drops will be immediately cooked
*/
public class CutClean extends UHC
{
private int _steakAmount;
private HashMap<Material, Material> _oreDrops;
private HashMap<Material, Material> _drops;
// The amount of steak to give at the start of the game
private static final int STEAK_AMOUNT = 15;
public CutClean(ArcadeManager manager)
{
super(manager, GameType.Brawl);
_steakAmount = 15;
registerModule(new CutCleanModule()
.associateBlockDrop(
Material.GOLD_ORE,
new ItemBuilder(Material.GOLD_INGOT).build()
)
.associateBlockDrop(
Material.IRON_ORE,
new ItemBuilder(Material.IRON_INGOT).build()
)
.associateMobDrop(
Material.RAW_BEEF,
new ItemBuilder(Material.COOKED_BEEF).build()
)
.associateMobDrop(
Material.RAW_CHICKEN,
new ItemBuilder(Material.COOKED_CHICKEN).build()
)
.associateMobDrop(
Material.RAW_FISH,
new ItemBuilder(Material.COOKED_FISH).build()
)
.associateMobDrop(
Material.PORK,
new ItemBuilder(Material.GRILLED_PORK).build()
)
.associateMobDrop(
Material.RABBIT,
new ItemBuilder(Material.COOKED_RABBIT).build()
)
);
_oreDrops = new HashMap<>();
_oreDrops.put(Material.GOLD_ORE, Material.GOLD_INGOT);
_oreDrops.put(Material.IRON_ORE, Material.IRON_INGOT);
_drops = new HashMap<>();
_drops.put(Material.RAW_BEEF, Material.COOKED_BEEF);
_drops.put(Material.RAW_CHICKEN, Material.COOKED_CHICKEN);
_drops.put(Material.RAW_FISH, Material.COOKED_FISH);
_drops.put(Material.PORK, Material.GRILLED_PORK);
_drops.put(Material.RABBIT, Material.COOKED_RABBIT);
}
@EventHandler
public void giveSteak(GameStateChangeEvent event)
{
if (event.GetState() != GameState.Live)
return;
for (Player player : GetPlayers(true))
{
UtilInv.insert(player,
ItemStackFactory.Instance.CreateStack(Material.COOKED_BEEF, _steakAmount));
}
}
@EventHandler
public void smeltOres(BlockBreakEvent event)
{
for (Material mat : _oreDrops.keySet())
{
if (event.getBlock().getType() == mat)
{
event.setCancelled(true);
event.getBlock().setType(Material.AIR);
Bukkit.getScheduler().runTaskLater(Manager.getPlugin(), new Runnable()
{
@Override
public void run()
{
event.getBlock().getWorld().dropItem(
event.getBlock().getLocation().add(0.5, 0.2, 0.5),
new ItemStack(_oreDrops.get(mat)));
}
}, 1);
}
}
}
@EventHandler
public void smeltFood(EntityDeathEvent event)
{
List<ItemStack> drops = event.getDrops();
for (Material mat : _drops.keySet())
{
Iterator<ItemStack> itemIterator = drops.iterator();
while (itemIterator.hasNext())
{
ItemStack item = itemIterator.next();
if (item.getType() == mat)
{
itemIterator.remove();
drops.add(ItemStackFactory.Instance.CreateStack(_drops.get(mat),
1 + UtilMath.r(3)));
}
}
}
registerModule(new ItemGiverModule()
.withItem(new ItemStack(Material.COOKED_BEEF, STEAK_AMOUNT))
);
}
@Override
@ -114,5 +65,4 @@ public class CutClean extends UHC
{
return "Cut Clean";
}
}

View File

@ -1,103 +1,74 @@
package nautilus.game.arcade.game.games.uhc.modes;
import java.util.ArrayList;
import java.util.HashMap;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.inventory.ItemStack;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import mineplex.core.common.util.UtilBlock;
import mineplex.core.common.util.UtilItem;
import mineplex.core.common.util.UtilMath;
import mineplex.core.itemstack.ItemBuilder;
import nautilus.game.arcade.ArcadeManager;
import nautilus.game.arcade.GameType;
import nautilus.game.arcade.events.GameStateChangeEvent;
import nautilus.game.arcade.game.games.uhc.UHC;
import nautilus.game.arcade.game.modules.CutCleanModule;
import nautilus.game.arcade.game.modules.ItemGiverModule;
import nautilus.game.arcade.game.modules.OreVeinEditorModule;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.inventory.ItemStack;
import java.util.List;
import java.util.Set;
/**
* GodBattles gamemode for UHC
*
* @author xXVevzZXx
*/
public class GodBattles extends UHC
{
// The set of materials which will be considered as an ore
private static final Set<Material> ORE_MATERIALS = Sets.newHashSet(
Material.COAL_ORE,
Material.REDSTONE_ORE,
Material.IRON_ORE,
Material.GOLD_ORE,
Material.DIAMOND_ORE
);
private ArrayList<Material> _ores;
private HashMap<Material, Material> _oreDrops;
// The set of materials which will act as replacements
private static final List<Material> ORE_REPLACEMENTS = Lists.newArrayList(
Material.GOLD_ORE,
Material.DIAMOND_ORE
);
public GodBattles(ArcadeManager manager)
{
super(manager, GameType.Brawl);
_ores = new ArrayList<>();
registerModule(new CutCleanModule()
.associateBlockDrop(
Material.GOLD_ORE,
new ItemBuilder(Material.GOLD_BLOCK).build()
)
);
_ores.add(Material.GOLD_ORE);
_ores.add(Material.DIAMOND_ORE);
registerModule(new ItemGiverModule()
.withItem(UtilItem.makeUnbreakable(new ItemStack(Material.DIAMOND_PICKAXE)))
);
_oreDrops = new HashMap<>();
_oreDrops.put(Material.GOLD_ORE, Material.GOLD_BLOCK);
}
@EventHandler
public void blockOres(BlockBreakEvent event)
{
for (Material mat : _oreDrops.keySet())
{
if (event.getBlock().getType() == mat)
{
event.setCancelled(true);
event.getBlock().setType(Material.AIR);
Bukkit.getScheduler().runTaskLater(Manager.getPlugin(), new Runnable()
registerModule(new OreVeinEditorModule()
.useFilter(block -> ORE_MATERIALS.contains(block.getType()))
.useEditor(vein ->
{
@Override
public void run()
Material ore = ORE_REPLACEMENTS.get(UtilMath.r(ORE_REPLACEMENTS.size()));
for (Block block : vein)
{
event.getBlock().getWorld().dropItem(
event.getBlock().getLocation().add(0.5, 0.2, 0.5),
new ItemStack(_oreDrops.get(mat)));
if(!ORE_REPLACEMENTS.contains(block.getType()))
{
if(!UtilBlock.isVisible(block))
block.setType(ore);
}
}
}, 1);
}
}
}
@EventHandler
public void givePickaxe(GameStateChangeEvent event)
{
if(event.GetState() != GameState.Live)
return;
for (Player player : GetPlayers(true))
{
player.getInventory().addItem(UtilItem.makeUnbreakable(new ItemStack(Material.DIAMOND_PICKAXE)));
}
}
@Override
public void setOreType(ArrayList<Block> blocks)
{
Material ore = _ores.get(UtilMath.r(_ores.size()));
for (Block block : blocks)
{
if(block.getType() != Material.DIAMOND_ORE && block.getType() != Material.GOLD_ORE)
{
if(!UtilBlock.isVisible(block))
block.setType(ore);
}
}
}
@Override
public boolean isOre(Block block)
{
return (block.getType() == Material.COAL_ORE || block.getType() == Material.REDSTONE_ORE || block.getType() == Material.IRON_ORE || block.getType() == Material.GOLD_ORE || block.getType() == Material.DIAMOND_ORE);
})
);
}
@Override
@ -105,5 +76,4 @@ public class GodBattles extends UHC
{
return "God Battles";
}
}

View File

@ -0,0 +1,107 @@
package nautilus.game.arcade.game.modules;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.event.EventHandler;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.entity.EntityDeathEvent;
import org.bukkit.inventory.ItemStack;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumMap;
import java.util.Iterator;
import java.util.List;
/*
* This module will implement CutClean-esque features within the game.
*
* In particular, the CutCleanModule#associateBlockDrop and CutCleanModule#associateMobDrop methods will
* allow you to drop different items for each block and mob killed
*/
public class CutCleanModule extends Module
{
private final EnumMap<Material, List<ItemStack>> _blockDrops = new EnumMap<>(Material.class);
private final EnumMap<Material, List<ItemStack>> _mobDrops = new EnumMap<>(Material.class);
/*
* Associates a material with a list of drops.
*
* Every time a block of that material is broken, the drops given will be dropped instead
*
* fixme does not support data ids
*/
public CutCleanModule associateBlockDrop(Material block, ItemStack... drops)
{
if (_blockDrops.containsKey(block))
{
throw new IllegalStateException(block + " is already registered to " + _blockDrops.get(block));
}
_blockDrops.put(block, new ArrayList<>(Arrays.asList(drops)));
return this;
}
/*
* Associates a mob drop with a list of different drops
*
* Every time an item of the given type is dropped by a mob death, the alternative drops will be dropped instead
*/
public CutCleanModule associateMobDrop(Material drop, ItemStack... drops)
{
if (_mobDrops.containsKey(drop))
{
throw new IllegalStateException(drop + " is already registered to " + _mobDrops.get(drop));
}
_mobDrops.put(drop, new ArrayList<>(Arrays.asList(drops)));
return this;
}
@EventHandler
public void on(BlockBreakEvent event)
{
List<ItemStack> drops = _blockDrops.get(event.getBlock().getType());
if (drops == null)
{
return;
}
event.getBlock().setType(Material.AIR);
getGame().getArcadeManager().getScheduler().runTaskLater(getGame().getArcadeManager().getPlugin(), () ->
{
Location dropLocation = event.getBlock().getLocation().add(0.5, 0.2, 0.5);
for (ItemStack drop : drops)
{
event.getBlock().getWorld().dropItem(dropLocation, drop.clone());
}
}, 1L);
}
@EventHandler
public void on(EntityDeathEvent event)
{
List<ItemStack> drops = event.getDrops();
List<ItemStack> newDrops = new ArrayList<>();
Iterator<ItemStack> itemIterator = drops.iterator();
while (itemIterator.hasNext())
{
ItemStack item = itemIterator.next();
List<ItemStack> replacements = _mobDrops.get(item.getType());
if (replacements == null)
{
continue;
}
itemIterator.remove();
for (ItemStack replace : replacements)
{
newDrops.add(replace.clone());
}
}
drops.addAll(newDrops);
}
}

View File

@ -0,0 +1,55 @@
package nautilus.game.arcade.game.modules;
import mineplex.core.common.util.UtilInv;
import mineplex.core.common.util.UtilItem;
import nautilus.game.arcade.events.GameStateChangeEvent;
import nautilus.game.arcade.game.Game;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.inventory.ItemStack;
import java.util.ArrayList;
import java.util.List;
/*
* This module will give all players specific items at the start of the game
*/
public class ItemGiverModule extends Module
{
private final List<ItemStack> _itemsToGive = new ArrayList<>();
public ItemGiverModule withItem(ItemStack item)
{
_itemsToGive.add(item.clone());
return this;
}
public ItemGiverModule withItems(ItemStack... items)
{
List<ItemStack> clones = new ArrayList<>();
for (ItemStack item : items)
{
clones.add(item.clone());
}
_itemsToGive.addAll(clones);
return this;
}
@EventHandler
public void on(GameStateChangeEvent event)
{
if(event.GetState() != Game.GameState.Live)
return;
for (Player player : getGame().GetPlayers(true))
{
for (ItemStack toGive : _itemsToGive)
{
UtilInv.insert(player, toGive.clone());
}
}
}
}

View File

@ -1,13 +1,34 @@
package nautilus.game.arcade.game.modules;
import com.google.gson.JsonElement;
import nautilus.game.arcade.game.Game;
import nautilus.game.arcade.game.TeamGame;
import org.bukkit.event.Listener;
/*
* This is a Module
*
* A Module represents something which will enhance or change the way games can be played.
* Modules should function independent of which specific gamemode is being played.
* If you need game-specific features, put it into that Game implementation or refactor it into a separate class (not a module).
*
* Modules should never directly access other Modules via the Game instance.
* Instead, the game which requires cross-contamination should do so itself.
*
* Modules should be associated per-game. Do not make them static
*
* If your module is able to accept custom configuration, override the configure(JsonElement) method
* You can define the format of the json you wish to use.
* This custom configuration will be used to dynamically adjust gamemodes via Redis if needed
*/
public abstract class Module implements Listener
{
// The game this module belongs to
private Game _game;
/*
* Initializes this module with the specific game instance. You should never do this as {@link Game} does it for you
*/
public void initialize(Game game)
{
if (_game != null)
@ -15,13 +36,47 @@ public abstract class Module implements Listener
throw new IllegalArgumentException("Attempting to initialize module which has already been initialized for " + _game);
}
this._game = game;
this.setup();
}
/*
* This method is called once initialization is complete. Do whatever you need to do with the {@link Game} here
*/
protected void setup()
{
}
/*
* If this module can be configured via a JsonObject/JsonPrimitive, then override this method
* to implement that feature
*
* You can define how the JsonElement should be formatted.
*
* It is recommended to have a "force" boolean which will reset this module to a clean state
* (to allow extensive customization using json)
*/
public void configure(JsonElement element)
{
}
/*
* This method is called once this module is no longer needed.
* This could be because the game is over
* Or because this module was unregistered
*
* The {@link Game} will unregister this module as a listener for you.
* All you need to do is clean up after yourself
*/
public void cleanup()
{
}
/*
* Gets the game this module is associated with
*/
public Game getGame()
{
return this._game;

View File

@ -0,0 +1,219 @@
package nautilus.game.arcade.game.modules;
import mineplex.core.common.util.UtilBlock;
import mineplex.core.common.util.UtilMath;
import mineplex.core.common.util.UtilWorld;
import mineplex.core.timing.TimingManager;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.block.BlockBreakEvent;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;
/*
* This module will allow you to edit veins of ore live as players break them
*/
public class OreVeinEditorModule extends Module
{
// Initial range to look for veins
// For example, if I break a block at 0,0,0 and RANGE is 3
// Then this module will look for ores in the region of -3,-3,-3 to 3,3,3
private static final int RANGE = 3;
private boolean _debug = false;
private boolean _removeNonAirVeins = false;
private Predicate<Block> _predicateIsOre = block ->
(block.getType() == Material.IRON_ORE || block.getType() == Material.GOLD_ORE || block.getType() == Material.DIAMOND_ORE);
private Consumer<List<Block>> _consumerOreEditor = list ->
{
};
public OreVeinEditorModule debug()
{
this._debug = true;
return this;
}
public OreVeinEditorModule removeNonAirVeins()
{
this._removeNonAirVeins = true;
return this;
}
public OreVeinEditorModule useFilter(Predicate<Block> filter)
{
this._predicateIsOre = filter;
return this;
}
public OreVeinEditorModule useEditor(Consumer<List<Block>> editor)
{
this._consumerOreEditor = editor;
return this;
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void on(BlockBreakEvent event)
{
if (_debug)
TimingManager.start("Block Break");
// Find Nearby Ores
List<Block> ores = findOres(event.getBlock(), RANGE);
// Anti-Xray
removeNonAirVeins(generateVeins(ores));
if (_debug)
TimingManager.stop("Block Break");
}
// Searches in a range x range x range cube for ores
private List<Block> findOres(Block source, int range)
{
List<Block> ores = new ArrayList<>();
for (int x = -range; x <= range; x++)
for (int z = -range; z <= range; z++)
for (int y = -range; y <= range; y++)
findOreFromBlock(ores, source.getRelative(x, y, z));
if (_debug)
for (Block debug : ores)
System.out.println("Found " + debug.getType() + " at " + UtilWorld.locToStrClean(debug.getLocation()));
return ores;
}
// Checks if the current block is ore
// If so, then search all blocks around it to see if they are ores
private void findOreFromBlock(List<Block> ores, Block block)
{
if (ores.contains(block))
return;
if (_predicateIsOre.test(block))
{
ores.add(block);
for (Block neighbour : UtilBlock.getSurrounding(block, true))
{
findOreFromBlock(ores, neighbour);
}
}
}
private List<List<Block>> generateVeins(List<Block> ores)
{
List<List<Block>> veins = new ArrayList<>();
while (!ores.isEmpty())
{
Block block = ores.remove(0);
if (_debug)
System.out.println("NEW VEIN - " + block.getType());
// Start New Vein
List<Block> vein = new ArrayList<>();
veins.add(vein);
vein.add(block);
// Find Vein Ores
boolean addedToVein = true;
while (addedToVein)
{
addedToVein = false;
Iterator<Block> oreIterator = ores.iterator();
while (oreIterator.hasNext())
{
Block ore = oreIterator.next();
boolean inVein = false;
// Check if in Vein
// fixme is this a good algorithm?
for (Block veinOre : vein)
{
if (UtilMath.offset(ore.getLocation(), veinOre.getLocation()) <= 2)
{
inVein = true;
break;
}
}
// Add to Vein
if (inVein)
{
vein.add(ore);
oreIterator.remove();
addedToVein = true;
}
}
}
if (_debug)
for (Block veinOre : vein)
System.out.println(UtilWorld.locToStrClean(veinOre.getLocation()));
}
return veins;
}
private void removeNonAirVeins(List<List<Block>> oreVeins)
{
// Remove Non-Aired Veins
for (List<Block> vein : oreVeins)
{
boolean visible = false;
// Check if Air is near Vein
outer: for (Block ore : vein)
{
for (Block visibleCheckBlock : UtilBlock.getSurrounding(ore, true))
{
if (visibleCheckBlock.getType() == Material.AIR || UtilBlock.isVisible(visibleCheckBlock))
{
visible = true;
break outer;
}
}
}
if (visible)
_consumerOreEditor.accept(vein);
// Remove Vein
if (!visible && _removeNonAirVeins)
{
if (_debug)
System.out.println("DELETING VEIN;");
for (Block ore : vein)
{
if (_debug)
System.out.println(ore.getType() + " " + UtilWorld.locToStrClean(ore.getLocation()));
ore.setType(Material.STONE);
}
}
else
{
if (_debug)
System.out.println("VALID VEIN!");
}
}
}
}

View File

@ -1,7 +1,5 @@
package nautilus.game.arcade.game.modules;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import mineplex.core.common.util.F;
import mineplex.core.common.util.UtilPlayer;
import mineplex.core.recharge.Recharge;
@ -14,11 +12,14 @@ import org.bukkit.event.player.PlayerCommandPreprocessEvent;
import org.bukkit.event.player.PlayerInteractEntityEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.UUID;
public class TeamModule extends Module
{
private BiMap<UUID, UUID> _teamReqs = HashBiMap.create();
private Map<UUID, UUID> _teamReqs = new HashMap<>();
@EventHandler(priority = EventPriority.HIGH)
public void teamSelectInteract(PlayerInteractEntityEvent event)
@ -147,8 +148,15 @@ public class TeamModule extends Module
if (getGame().GetTeam(player) != null)
getGame().GetTeam(player).DisbandTeam();
_teamReqs.remove(player.getUniqueId());
_teamReqs.inverse().remove(player.getUniqueId());
Iterator<Map.Entry<UUID, UUID>> iterator = _teamReqs.entrySet().iterator();
while (iterator.hasNext())
{
Map.Entry<UUID, UUID> entry = iterator.next();
if (entry.getKey().equals(player.getUniqueId()) || entry.getValue().equals(player.getUniqueId()))
{
iterator.remove();
}
}
}
private GameTeam getEmptyTeam()

View File

@ -0,0 +1,111 @@
package nautilus.game.arcade.game.modules.antixray;
import mineplex.core.common.util.UtilServer;
import nautilus.game.arcade.game.modules.Module;
import org.bukkit.Material;
import org.bukkit.plugin.RegisteredServiceProvider;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
/*
* This module will enable antixray for this specific game
*
* NOTE: The game server must also have the Mineplex Orebfuscator plugin installed
*/
public class AntiXrayModule extends Module
{
private AntiXrayService _service;
@Override
protected void setup()
{
RegisteredServiceProvider<AntiXrayService> rsp = UtilServer.getServer().getServicesManager().getRegistration(AntiXrayService.class);
if (rsp == null)
{
getGame().unregisterModule(this);
System.out.println("!!!ERROR!!! AntiXray module was registered but the Mineplex Orebfuscator Service was not registered");
return;
}
AntiXrayService service = rsp.getProvider();
if (service == null)
{
getGame().unregisterModule(this);
System.out.println("!!!ERROR!!! AntiXray module was registered but the Mineplex Orebfuscator Service was null");
return;
}
_service = service;
}
@Override
public void cleanup()
{
_service.setEnabled(false);
}
public AntiXrayModule setEnabled(boolean enabled)
{
_service.setEnabled(enabled);
return this;
}
public AntiXrayModule setUpdateOnDamage(boolean updateOnDamage)
{
_service.setUpdateOnDamage(updateOnDamage);
return this;
}
public AntiXrayModule setEngineMode(int engineMode)
{
_service.setEngineMode(engineMode);
return this;
}
public AntiXrayModule setInitialRadius(int initialRadius)
{
_service.setInitialRadius(initialRadius);
return this;
}
public AntiXrayModule setUpdateRadius(int updateRadius)
{
_service.setUpdateRadius(updateRadius);
return this;
}
public AntiXrayModule setUseProximityHider(boolean useProximityHider)
{
_service.setUseProximityHider(useProximityHider);
return this;
}
public AntiXrayModule setAntiTexturePacksAndFreecam(boolean antiTexturePacksAndFreecam)
{
_service.setAntiTexturePacksAndFreecam(antiTexturePacksAndFreecam);
return this;
}
public AntiXrayModule setObfuscateBlocks(Material... materials)
{
return setObfuscateBlocks(Arrays.asList(materials));
}
public AntiXrayModule setObfuscateBlocks(List<Material> materials)
{
_service.setObfuscateBlocks(materials);
return this;
}
public AntiXrayModule setRandomBlocks(Material... materials)
{
return setRandomBlocks(Arrays.asList(materials));
}
public AntiXrayModule setRandomBlocks(List<Material> materials)
{
_service.setRandomBlocks(materials);
return this;
}
}

View File

@ -0,0 +1,27 @@
package nautilus.game.arcade.game.modules.antixray;
import org.bukkit.Material;
import java.util.Arrays;
import java.util.List;
public interface AntiXrayService
{
void setEnabled(boolean enabled);
void setUpdateOnDamage(boolean updateOnDamage);
void setEngineMode(int engineMode);
void setInitialRadius(int initialRadius);
void setUpdateRadius(int updateRadius);
void setUseProximityHider(boolean useProximityHider);
void setAntiTexturePacksAndFreecam(boolean antiTexturePacksAndFreecam);
void setObfuscateBlocks(List<Material> materials);
void setRandomBlocks(List<Material> materials);
}

View File

@ -0,0 +1,339 @@
package nautilus.game.arcade.game.modules.combatlog;
import mineplex.core.common.util.C;
import mineplex.core.common.util.F;
import mineplex.core.common.util.UtilEvent;
import mineplex.core.common.util.UtilParser;
import mineplex.core.common.util.UtilPlayer;
import mineplex.core.common.util.UtilServer;
import mineplex.core.updater.UpdateType;
import mineplex.core.updater.event.UpdateEvent;
import nautilus.game.arcade.game.GameTeam;
import nautilus.game.arcade.game.TeamGame;
import nautilus.game.arcade.game.modules.Module;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.GameMode;
import org.bukkit.Sound;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityDeathEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.world.ChunkUnloadEvent;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.UUID;
import java.util.function.Consumer;
/*
* This module will spawn combat log NPCs for players who disconnect
*/
public class CombatLogModule extends Module
{
// The map of player UUIDs to their combat log NPCs
private Map<UUID, CombatLogNPC> _logoutNpcs = new HashMap<>();
// The map of player UUIDs and who killed their combat logged NPC
private Map<UUID, String> _killedBy = new HashMap<>();
// The time that combat log npcs will stay spawned for, in milliseconds
private int _spawnTime = 60000;
// Whether to notify the combat logged player on join if they have been killed
private boolean _notifyPlayer = true;
// Whether to spawn a combat log NPC for creative players
private boolean _spawnForCreative = true;
// The action to take once a combat logged NPC has died
private Consumer<CombatLogNPC> _onKill = npc ->
{
};
// The action to take once a combat logged NPC has expired
private Consumer<CombatLogNPC> _onExpire = npc ->
{
};
private int _locationTaskId = -1;
protected void setup()
{
_locationTaskId = Bukkit.getScheduler().runTaskTimer(getGame().getArcadeManager().getPlugin(), () ->
{
for (CombatLogNPC npc : _logoutNpcs.values())
{
getGame().GetLocationStore().put(npc.getPlayerInfo().getName(), npc.getNPC().getLocation());
}
}, 0L, 1L).getTaskId();
}
public CombatLogModule setNotifyPlayer(boolean notifyPlayer)
{
this._notifyPlayer = notifyPlayer;
return this;
}
public CombatLogModule setSpawnForCreative(boolean spawnForCreative)
{
this._spawnForCreative = spawnForCreative;
return this;
}
public CombatLogModule setOnDeathAction(Consumer<CombatLogNPC> action)
{
this._onKill = action;
return this;
}
public CombatLogModule setOnExpireAction(Consumer<CombatLogNPC> action)
{
this._onExpire = action;
return this;
}
public CombatLogModule setCombatLogTime(int time)
{
this._spawnTime = time;
return this;
}
/*
* Spawns a combat log NPC for the given player if that player does not already have one
*/
public void spawnLogoutNpc(Player player)
{
if (hasLogoutNpc(player))
return;
if (player.getGameMode() == GameMode.CREATIVE && !_spawnForCreative)
return;
CombatLogNPC npc = new CombatLogNPC(this, player, getGame().getArcadeManager());
npc.spawn();
_logoutNpcs.put(player.getUniqueId(), npc);
System.out.println(String.format("Spawned combat log NPC for %s!", player.getName()));
}
public boolean hasLogoutNpc(Player player)
{
return _logoutNpcs.containsKey(player.getUniqueId());
}
public CombatLogNPC getLogoutNpc(Player player)
{
return _logoutNpcs.get(player.getUniqueId());
}
public void despawnLogoutNpc(Player player)
{
CombatLogNPC npc = getLogoutNpc(player);
if (npc != null)
{
npc.despawn();
_logoutNpcs.remove(player.getUniqueId());
System.out.println(String.format("Despawned combat log NPC for %s!", player.getName()));
}
}
@EventHandler(priority = EventPriority.LOWEST)
public void on(PlayerQuitEvent event)
{
if (getGame().InProgress() && getGame().IsAlive(event.getPlayer()))
{
spawnLogoutNpc(event.getPlayer());
}
}
@EventHandler
public void on(PlayerJoinEvent event)
{
if (hasLogoutNpc(event.getPlayer()))
{
despawnLogoutNpc(event.getPlayer());
}
if (_killedBy.containsKey(event.getPlayer().getUniqueId()))
{
String name = _killedBy.remove(event.getPlayer().getUniqueId());
if (_notifyPlayer && name != null)
{
UtilPlayer.message(event.getPlayer(), F.main("Combat Log", "While you were gone, you were killed by " + ChatColor.GREEN + name + C.mBody + "."));
}
}
}
@Override
public void cleanup()
{
System.out.println("Killing combat log NPCs");
for (CombatLogNPC npc : _logoutNpcs.values())
{
npc.despawn();
}
_logoutNpcs.clear();
_killedBy.clear();
}
@EventHandler
public void onChunkUnload(ChunkUnloadEvent event)
{
for (CombatLogNPC npc : _logoutNpcs.values())
{
if (npc.getNPC().getLocation().getChunk().equals(event.getChunk()))
{
event.setCancelled(true);
return;
}
}
}
@EventHandler(ignoreCancelled = true)
public void onEntityDeath(EntityDeathEvent event)
{
CombatLogNPC logoutNpc = getLogoutNpc(event.getEntity());
if (logoutNpc == null)
return;
_onKill.accept(logoutNpc);
logoutNpc.onDeath();
event.getDrops().clear(); // Clear the entity's item drops. If drops are wanted they can be added
if (logoutNpc.getLastDamager() != null)
{
_killedBy.put(logoutNpc.getPlayerInfo().getUniqueId(), logoutNpc.getLastDamager().getName());
}
else
{
_killedBy.put(logoutNpc.getPlayerInfo().getUniqueId(), UtilParser.parseDamageCause(logoutNpc.getLastDamageCause()));
}
if (getGame() instanceof TeamGame)
{
TeamGame teamGame = (TeamGame) getGame();
teamGame.RejoinTimes.remove(logoutNpc.getPlayerInfo().getName());
teamGame.RejoinKit.remove(logoutNpc.getPlayerInfo().getName());
teamGame.RejoinTeam.remove(logoutNpc.getPlayerInfo().getName());
teamGame.RejoinHealth.remove(logoutNpc.getPlayerInfo().getName());
}
}
@EventHandler(ignoreCancelled = true)
public void onEntityDamaged(EntityDamageEvent event)
{
CombatLogNPC logoutNpc = getLogoutNpc(event.getEntity());
if (logoutNpc != null)
{
LivingEntity damager = UtilEvent.GetDamagerEntity(event, true);
Player damagerPlayer = null;
if (damager instanceof Player)
{
damagerPlayer = (Player) damager;
}
if (getGame() instanceof TeamGame && damagerPlayer != null)
{
GameTeam damagerTeam = getGame().GetTeam(damagerPlayer);
if (damagerTeam == logoutNpc.getPlayerInfo().getTeam())
{
event.setCancelled(true);
return;
}
}
logoutNpc.getNPC().getWorld().playSound(logoutNpc.getNPC().getLocation(), Sound.HURT_FLESH, 1, 1);
if (getGame() instanceof TeamGame)
{
getGame().getArcadeManager().runSync(() ->
{
((TeamGame) getGame()).RejoinHealth.put(logoutNpc.getPlayerInfo().getName(), logoutNpc.getNPC().getHealth());
});
}
logoutNpc.handleDamageEvent(event);
}
}
@EventHandler
public void onUpdate(UpdateEvent event)
{
if (event.getType() == UpdateType.FASTER)
{
for (CombatLogNPC npc : _logoutNpcs.values())
{
npc.update();
}
}
if (event.getType() == UpdateType.SEC)
{
Iterator<CombatLogNPC> iterator = _logoutNpcs.values().iterator();
while (iterator.hasNext())
{
CombatLogNPC npc = iterator.next();
if (Bukkit.getPlayerExact(npc.getPlayerInfo().getName()) != null)
{
System.out.println("Removing NPC " + npc.getPlayerInfo().getName() + " for 1");
npc.despawn();
iterator.remove();
}
else if (!npc.isAlive())
{
System.out.println("Removing NPC " + npc.getPlayerInfo().getName() + " for 2");
npc.remove();
iterator.remove();
}
else if (npc.getAliveDuation() > this._spawnTime)
{
System.out.println("Removing NPC " + npc.getPlayerInfo().getName() + " for 3");
_onExpire.accept(npc);
npc.despawn();
iterator.remove();
}
}
}
}
private CombatLogNPC getLogoutNpc(Entity entity)
{
return getLogoutNpc(entity.getEntityId());
}
private CombatLogNPC getLogoutNpc(int entityId)
{
for (CombatLogNPC npc : _logoutNpcs.values())
{
if (npc.getNPC().getEntityId() == entityId)
{
return npc;
}
}
return null;
}
public int getSpawnTime()
{
return _spawnTime;
}
public Collection<CombatLogNPC> getAllNPCs()
{
return _logoutNpcs.values();
}
}

View File

@ -0,0 +1,183 @@
package nautilus.game.arcade.game.modules.combatlog;
import mineplex.core.common.util.UtilEnt;
import mineplex.core.common.util.UtilTime;
import mineplex.core.disguise.DisguiseManager;
import mineplex.core.disguise.disguises.DisguisePlayer;
import mineplex.core.hologram.Hologram;
import nautilus.game.arcade.ArcadeManager;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer;
import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.Creeper;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.metadata.FixedMetadataValue;
public class CombatLogNPC
{
private CombatLogModule _module;
private PlayerInfo _playerInfo;
private Hologram _hologram;
private DisguiseManager _disguiseManager;
private long _spawnDate;
private final long _endingTime;
private double _spawnHealth;
private double _maxHealth;
private LivingEntity _npc;
private EntityDamageEvent.DamageCause _lastDamageCause;
private Entity _lastDamager;
public CombatLogNPC(CombatLogModule module, Player player, ArcadeManager arcadeManager)
{
this._module = module;
_playerInfo = new PlayerInfo(player, arcadeManager);
_endingTime = System.currentTimeMillis() + this._module.getSpawnTime();
_disguiseManager = arcadeManager.GetDisguise();
_hologram = new Hologram(arcadeManager.getHologramManager(), player.getEyeLocation().add(0, 1, 0), "Quitting in " + UtilTime.MakeStr(Math.max(_endingTime - System.currentTimeMillis(), 0)));
_spawnDate = 0;
_spawnHealth = player.getHealth();
_maxHealth = player.getMaxHealth();
_hologram.start();
}
/**
* Called when the {@code _npc} associated with this CombatLogNPC is killed
* and thus drops all the owner's items.
*/
public void onDeath()
{
_disguiseManager.undisguise(_npc);
}
public void update()
{
_hologram.setText("Quitting in " + UtilTime.MakeStr(Math.max(_endingTime - System.currentTimeMillis(), 0)));
if (_npc != null)
{
_hologram.setLocation(_npc.getEyeLocation().add(0, 1, 0));
}
}
/**
* @return true, if the {@code _npc} associated with this CombatLogNPC is
* alive, false otherwise.
*/
public boolean isAlive()
{
return _npc != null && !_npc.isDead();
}
/**
* @return the amount of time (in milliseconds) that this npc has been alive
* an spawned in.
*/
public long getAliveDuation()
{
return System.currentTimeMillis() - _spawnDate;
}
public void spawn()
{
if (_npc != null) despawn();
_npc = spawnNpc(getPlayer());
_spawnDate = System.currentTimeMillis();
}
public void despawn()
{
if (_npc != null)
{
_npc.remove();
_npc = null;
_hologram.stop();
_hologram = null;
}
}
public void remove()
{
_hologram.stop();
_hologram = null;
}
public PlayerInfo getPlayerInfo()
{
return _playerInfo;
}
public Player getPlayer()
{
return _playerInfo.getPlayer();
}
private LivingEntity spawnNpc(Player player)
{
Location spawnLoc = player.getLocation();
LivingEntity skel = player.getWorld().spawn(spawnLoc, Creeper.class);
skel.setRemoveWhenFarAway(false);
skel.setMetadata("CombatLogNPC", new FixedMetadataValue(_disguiseManager.getPlugin(), player.getUniqueId().toString()));
skel.teleport(spawnLoc);
skel.setMaxHealth(_maxHealth);
skel.setHealth(_spawnHealth);
skel.setFallDistance(player.getFallDistance());
// fixme potion effects, mobs don't target, entity collision (setting to ghost disables arrows and fishing rods), logging while sleeping
// best solution to spawn EntityPlayer?
UtilEnt.Vegetate(skel);
UtilEnt.silence(skel, true);
skel.getEquipment().setHelmet(player.getInventory().getHelmet());
skel.getEquipment().setChestplate(player.getInventory().getChestplate());
skel.getEquipment().setLeggings(player.getInventory().getLeggings());
skel.getEquipment().setBoots(player.getInventory().getBoots());
skel.getEquipment().setItemInHand(player.getItemInHand());
// Disguise
DisguisePlayer disguise = new DisguisePlayer(skel, ((CraftPlayer) player).getHandle().getProfile());
_disguiseManager.disguise(disguise);
return skel;
}
public Entity getLastDamager()
{
return _lastDamager;
}
public LivingEntity getNPC()
{
return this._npc;
}
public void handleDamageEvent(EntityDamageEvent event)
{
this._lastDamageCause = event.getCause();
if (event instanceof EntityDamageByEntityEvent)
{
EntityDamageByEntityEvent entityDamageByEntityEvent = (EntityDamageByEntityEvent) event;
this._lastDamager = entityDamageByEntityEvent.getDamager();
}
else
{
this._lastDamager = null;
}
}
public EntityDamageEvent.DamageCause getLastDamageCause()
{
return _lastDamageCause;
}
}

View File

@ -0,0 +1,69 @@
package nautilus.game.arcade.game.modules.combatlog;
import mineplex.core.common.util.UtilInv;
import nautilus.game.arcade.ArcadeManager;
import nautilus.game.arcade.game.GameTeam;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
public class PlayerInfo
{
private String _playerName;
private UUID _playerUuid;
private List<ItemStack> _items;
private ChatColor _teamColor = ChatColor.GRAY;
private GameTeam _team;
public PlayerInfo(Player player, ArcadeManager arcadeManager)
{
_playerName = player.getName();
_playerUuid = player.getUniqueId();
_items = UtilInv.getItems(player);
_team = arcadeManager.GetGame().GetTeam(player);
if (_team != null)
{
_teamColor = _team.GetColor();
}
}
public String getName()
{
return _playerName;
}
public UUID getUniqueId()
{
return _playerUuid;
}
public Player getPlayer()
{
return Bukkit.getPlayerExact(_playerName);
}
public ChatColor getTeamColor()
{
return _teamColor;
}
public GameTeam getTeam()
{
return _team;
}
public List<ItemStack> getItems()
{
return this._items;
}
}

View File

@ -1,20 +1,27 @@
package nautilus.game.arcade.managers;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import mineplex.core.common.util.C;
import mineplex.core.common.util.F;
import mineplex.core.common.util.UtilMath;
import mineplex.core.common.util.UtilPlayer;
import mineplex.core.common.util.UtilServer;
import mineplex.core.common.util.UtilTextBottom;
import mineplex.core.packethandler.IPacketHandler;
import mineplex.core.packethandler.PacketHandler;
import mineplex.core.packethandler.PacketInfo;
import mineplex.core.updater.UpdateType;
import mineplex.core.updater.event.UpdateEvent;
import nautilus.game.arcade.ArcadeManager;
import nautilus.game.arcade.game.Game.GameState;
import net.minecraft.server.v1_8_R3.EntityPlayer;
import net.minecraft.server.v1_8_R3.EntityTracker;
import net.minecraft.server.v1_8_R3.EntityTrackerEntry;
import net.minecraft.server.v1_8_R3.NetworkManager;
import net.minecraft.server.v1_8_R3.PacketPlayOutCamera;
import net.minecraft.server.v1_8_R3.PacketPlayOutGameStateChange;
import net.minecraft.server.v1_8_R3.PacketPlayOutNamedEntitySpawn;
import net.minecraft.server.v1_8_R3.WorldSettings;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer;
import org.bukkit.entity.Entity;
@ -30,41 +37,37 @@ import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerToggleSneakEvent;
import org.bukkit.event.vehicle.VehicleDamageEvent;
import mineplex.core.common.util.C;
import mineplex.core.common.util.F;
import mineplex.core.common.util.UtilMath;
import mineplex.core.common.util.UtilPlayer;
import mineplex.core.common.util.UtilServer;
import mineplex.core.common.util.UtilTextBottom;
import mineplex.core.updater.UpdateType;
import mineplex.core.updater.event.UpdateEvent;
import nautilus.game.arcade.ArcadeManager;
import nautilus.game.arcade.game.Game.GameState;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
public class GameSpectatorManager implements Listener, IPacketHandler
{
private Set<UUID> _pendingSpectate = Collections.synchronizedSet(new HashSet<>());
// A map of a player UUID to the UUID of the entity they want to spectate
private Map<UUID, UUID> _pendingSpectate = Collections.synchronizedMap(new HashMap<>());
ArcadeManager Manager;
private ArcadeManager _manager;
public GameSpectatorManager(ArcadeManager manager)
{
Manager = manager;
_manager = manager;
Manager.getPluginManager().registerEvents(this, Manager.getPlugin());
_manager.getPluginManager().registerEvents(this, _manager.getPlugin());
Manager.getPacketHandler().addPacketHandler(this, PacketHandler.ListenerPriority.HIGH, PacketPlayOutNamedEntitySpawn.class);
_manager.getPacketHandler().addPacketHandler(this, PacketHandler.ListenerPriority.HIGH, PacketPlayOutNamedEntitySpawn.class);
}
@EventHandler(priority = EventPriority.LOW, ignoreCancelled=true)
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void interactCancel(PlayerInteractEvent event)
{
if (Manager.GetGame() == null)
if (_manager.GetGame() == null)
return;
Player player = event.getPlayer();
if (!Manager.GetGame().IsAlive(player))
if (!_manager.GetGame().IsAlive(player))
event.setCancelled(true);
processClick(player, event.getAction());
@ -72,45 +75,45 @@ public class GameSpectatorManager implements Listener, IPacketHandler
public void processClick(Player player, Action action)
{
if (Manager.GetGame() == null)
if (_manager.GetGame() == null)
return;
if(!Manager.GetGame().AllowEntitySpectate)
if (!_manager.GetGame().AllowEntitySpectate)
return;
if(!Manager.GetGame().IsLive())
if (!_manager.GetGame().IsLive())
return;
if(player.getGameMode() != GameMode.SPECTATOR)
if (player.getGameMode() != GameMode.SPECTATOR)
return;
if(player.getSpectatorTarget() == null)
if (player.getSpectatorTarget() == null)
return;
if(!(player.getSpectatorTarget() instanceof Player))
if (!(player.getSpectatorTarget() instanceof Player))
return;
List<Player> players = Manager.GetGame().GetPlayers(true);
List<Player> players = _manager.GetGame().GetPlayers(true);
int currentPlayer = 0;
for(Player otherPlayer : players)
for (Player otherPlayer : players)
{
currentPlayer++;
if(((Player) player.getSpectatorTarget()) == otherPlayer)
if (player.getSpectatorTarget() == otherPlayer)
break;
}
if(action == Action.LEFT_CLICK_AIR || action == Action.LEFT_CLICK_BLOCK)
if (action == Action.LEFT_CLICK_AIR || action == Action.LEFT_CLICK_BLOCK)
currentPlayer = currentPlayer - 2;
else
return;
if(currentPlayer < 0)
if (currentPlayer < 0)
currentPlayer = players.size() - 1;
if(currentPlayer >= players.size())
if (currentPlayer >= players.size())
currentPlayer = 0;
if(players.get(currentPlayer) == null)
if (players.get(currentPlayer) == null)
return;
Player specPlayer = players.get(currentPlayer);
@ -121,25 +124,25 @@ public class GameSpectatorManager implements Listener, IPacketHandler
@EventHandler(priority = EventPriority.LOW)
public void interactEntityCancel(PlayerInteractEntityEvent event)
{
if (Manager.GetGame() == null)
if (_manager.GetGame() == null)
return;
Player player = event.getPlayer();
if (Manager.GetGame().GetState() == GameState.Recruit)
if (_manager.GetGame().GetState() == GameState.Recruit)
{
if (Manager.getCosmeticManager().getMountManager().isMount(event.getRightClicked()))
if (_manager.getCosmeticManager().getMountManager().isMount(event.getRightClicked()))
{
return;
}
}
if (!Manager.GetGame().IsAlive(player))
if (!_manager.GetGame().IsAlive(player))
{
event.setCancelled(true);
if(Manager.GetGame().IsLive())
if (_manager.GetGame().IsLive())
{
if(Manager.GetGame().AllowEntitySpectate)
if (_manager.GetGame().AllowEntitySpectate)
{
setSpectating(player, event.getRightClicked());
}
@ -150,26 +153,25 @@ public class GameSpectatorManager implements Listener, IPacketHandler
@EventHandler
public void updateSpecEntitys(UpdateEvent event)
{
if(event.getType() != UpdateType.FASTER)
if (event.getType() != UpdateType.FASTER)
return;
if(Manager.GetGame() == null)
if (_manager.GetGame() == null)
return;
if(Manager.GetGame().IsLive() || Manager.GetGame().GetState() == GameState.End)
if (_manager.GetGame().IsLive() || _manager.GetGame().GetState() == GameState.End)
{
if(Manager.GetGame().AllowEntitySpectate)
if (_manager.GetGame().AllowEntitySpectate)
{
for(Player player : UtilServer.getPlayers())
for (Player player : UtilServer.getPlayers())
{
if (!Manager.GetGame().IsAlive(player))
if (!_manager.GetGame().IsAlive(player))
{
if(player.getGameMode() == GameMode.SPECTATOR)
if (player.getGameMode() == GameMode.SPECTATOR)
{
if(player.getSpectatorTarget() == null)
if (player.getSpectatorTarget() == null)
{
player.setGameMode(GameMode.SURVIVAL);
player.setAllowFlight(true);
despectate(player);
}
}
}
@ -181,28 +183,27 @@ public class GameSpectatorManager implements Listener, IPacketHandler
@EventHandler(priority = EventPriority.LOW)
public void spectatedEntityDeath(PlayerDeathEvent event)
{
if(Manager.GetGame() == null)
if (_manager.GetGame() == null)
return;
if(Manager.GetGame().IsLive() || Manager.GetGame().GetState() == GameState.End)
if (_manager.GetGame().IsLive() || _manager.GetGame().GetState() == GameState.End)
{
if(Manager.GetGame().AllowEntitySpectate)
if (_manager.GetGame().AllowEntitySpectate)
{
for(Player player : UtilServer.getPlayers())
for (Player player : UtilServer.getPlayers())
{
if (!Manager.GetGame().IsAlive(player))
if (!_manager.GetGame().IsAlive(player))
{
if(player.getGameMode() == GameMode.SPECTATOR)
if (player.getGameMode() == GameMode.SPECTATOR)
{
if(player.getSpectatorTarget() == event.getEntity())
if (player.getSpectatorTarget() == event.getEntity())
{
if(Manager.GetGame().GetPlayers(true).size() >= 1)
if (_manager.GetGame().GetPlayers(true).size() >= 1)
{
setSpectating(player, Manager.GetGame().GetPlayers(true).get(UtilMath.r(Manager.GetGame().GetPlayers(true).size())));
setSpectating(player, _manager.GetGame().GetPlayers(true).get(UtilMath.r(_manager.GetGame().GetPlayers(true).size())));
return;
}
player.setGameMode(GameMode.SURVIVAL);
player.setAllowFlight(true);
despectate(player);
}
}
}
@ -214,28 +215,53 @@ public class GameSpectatorManager implements Listener, IPacketHandler
@EventHandler(priority = EventPriority.LOW)
public void dismountEntity(PlayerToggleSneakEvent event)
{
if(Manager.GetGame() == null)
if (_manager.GetGame() == null)
return;
if(Manager.GetGame().IsLive() || Manager.GetGame().GetState() == GameState.End)
if (_manager.GetGame().IsLive() || _manager.GetGame().GetState() == GameState.End)
{
if(Manager.GetGame().AllowEntitySpectate)
if (_manager.GetGame().AllowEntitySpectate)
{
if(!Manager.GetGame().IsAlive(event.getPlayer()))
if (!_manager.GetGame().IsAlive(event.getPlayer()))
{
if(event.getPlayer().getGameMode() == GameMode.SPECTATOR)
if (event.getPlayer().getGameMode() == GameMode.SPECTATOR)
{
event.getPlayer().setGameMode(GameMode.SURVIVAL);
event.getPlayer().setAllowFlight(true);
despectate(event.getPlayer());
}
}
}
}
}
/*
* There's a reason this code is so complicated.
*
* Basically, when we want to set someone to spectate another entity, we send a PacketPlayOutCamera
* However, on the client side if the entity with the id as specified in PacketPlayOutCamera doesn't exist,
* the client simply ignores it
* This is alright if we're talking about small games like SSM or whatever, but in bigger games like SG and UHC
* the client does not get to keep the entire map loaded in memory
* Therefore, there is a chance that when we call Player#setSpectatorTarget, it has no effect because the client
* has not yet loaded the target
*
* To remedy this, we take a two pronged approach.
*
* First, we use Minecraft's internal EntityTracker to determine whether the client should have the entity loaded
* or not (if that's out of sync we're screwed anyways so oh well)
*
* If the client does have it loaded, then we simply use the Bukkit API to set the spectator target
*
* If the client doesn't have it loaded, we add it to a map of pending spectates and let the packet handler do the rest
*
* If at any point the client wants to stop spectating, we immediately replace the value in the map which notifies
* the packet handler to stop doing whatever it's doing.
*
* This is because the despectation code will work no matter what step of the spectating process is currently
* being executed
*/
public void setSpectating(Player player, Entity target)
{
if (Manager.GetGame().IsAlive(player))
if (_manager.GetGame().IsAlive(player))
{
return;
}
@ -245,66 +271,78 @@ public class GameSpectatorManager implements Listener, IPacketHandler
if (target instanceof Player)
{
playerTarget = (Player) target;
if (!Manager.GetGame().IsAlive(playerTarget))
if (!_manager.GetGame().IsAlive(playerTarget))
{
return;
}
}
_pendingSpectate.add(target.getUniqueId());
// Not finished last spectate
if (_pendingSpectate.containsKey(player.getUniqueId()))
return;
_pendingSpectate.put(player.getUniqueId(), target.getUniqueId());
EntityPlayer ep = ((CraftPlayer) player).getHandle();
EntityTracker tracker = ep.u().getTracker();
EntityTrackerEntry entry = tracker.trackedEntities.get(target.getEntityId());
// If the server is tracking this entity (eg the player should have it loaded) we can spectate right away
if (entry.trackedPlayers.contains(ep))
{
player.teleport(target.getLocation().add(0, 1, 0));
// If the player already has the entity loaded, we have to set it now
player.setGameMode(GameMode.SPECTATOR);
player.setSpectatorTarget(target);
if (playerTarget != null)
UtilTextBottom.display(C.cGray + "You are spectating " + F.elem(_manager.GetGame().GetTeam(playerTarget).GetColor() + playerTarget.getName()) + ".", player);
UtilPlayer.message(player, F.main("Game", "Sneak to stop spectating."));
_pendingSpectate.remove(player.getUniqueId());
}
// We still set spectating here even though it's pointless because of updateSpecEntites() above
player.teleport(target.getLocation().add(0, 1, 0));
// If the player already has the entity loaded, we have to set it now
// todo
// In the future, we could do some really cool stuff where we listen to all incoming and outgoing
// spawn/destroy packets and track whether the client has loaded the entity in memory
// However, that approach has the risk of desynchronization at which point we're screwed
player.setGameMode(GameMode.SPECTATOR);
player.setSpectatorTarget(target);
if (playerTarget != null)
UtilTextBottom.display(C.cGray + "You are spectating " + F.elem(Manager.GetGame().GetTeam(playerTarget).GetColor() + playerTarget.getName()) + ".", player);
UtilPlayer.message(player, F.main("Game", "Sneak to stop spectating."));
// And if the player did have the entity loaded, we also need to clean up after ourselves
// 20 ticks should be more than enough time considering we're just waiting for the server to attempt to
// send the packet
// and even if the server was lagging, the scheduler should be lagging too
Manager.runSyncLater(() ->
{
_pendingSpectate.remove(target.getUniqueId());
}, 20L);
}
@EventHandler(priority = EventPriority.LOW)
public void vehicleDamage(VehicleDamageEvent event)
{
if (Manager.GetGame() == null)
if (_manager.GetGame() == null)
return;
if (!(event.getAttacker() instanceof Player))
return;
Player player = (Player)event.getAttacker();
Player player = (Player) event.getAttacker();
if (!Manager.GetGame().IsAlive(player))
if (!_manager.GetGame().IsAlive(player))
event.setCancelled(true);
}
// Yes, there are a lot of checks for _pendingSpectate
// This is needed because if at any point (keeping in mind this code is not executed sequentially, but with delays)
// spectation needs to be aborted (signaled by replacing the value in _pendingSpectate)
// Then we need to stop spectating right away
// Otherwise the client will be out of sync
@Override
public void handle(PacketInfo packetInfo)
{
if (packetInfo.getPacket() instanceof PacketPlayOutNamedEntitySpawn)
{
PacketPlayOutNamedEntitySpawn packet = (PacketPlayOutNamedEntitySpawn) packetInfo.getPacket();
if (_pendingSpectate.remove(packet.b))
if (_pendingSpectate.get(packetInfo.getPlayer().getUniqueId()) == packet.b)
{
// Handle Minestrike spam race condition
if (Manager.GetGame().IsAlive(packetInfo.getPlayer()))
if (_manager.GetGame().IsAlive(packetInfo.getPlayer()))
{
_manager.runSync(() ->
{
_pendingSpectate.remove(packetInfo.getPlayer().getUniqueId());
});
return;
}
@ -313,31 +351,100 @@ public class GameSpectatorManager implements Listener, IPacketHandler
EntityPlayer ep = ((CraftPlayer) packetInfo.getPlayer()).getHandle();
NetworkManager manager = ep.playerConnection.networkManager;
if (_pendingSpectate.get(packetInfo.getPlayer().getUniqueId()) != packet.b)
return;
manager.a(packet, future ->
{
Manager.runSync(() ->
if (_pendingSpectate.get(packetInfo.getPlayer().getUniqueId()) != packet.b)
return;
_manager.runSync(() ->
{
PlayerGameModeChangeEvent event = new PlayerGameModeChangeEvent(packetInfo.getPlayer(), GameMode.SPECTATOR);
UtilServer.CallEvent(event);
if(event.isCancelled()) {
if (event.isCancelled())
{
_manager.runSync(() ->
{
_pendingSpectate.remove(packetInfo.getPlayer().getUniqueId());
});
return;
}
ep.playerInteractManager.setGameMode(WorldSettings.EnumGamemode.getById(GameMode.SPECTATOR.getValue()));
ep.fallDistance = 0.0F;
if (_pendingSpectate.get(packetInfo.getPlayer().getUniqueId()) != packet.b)
return;
manager.a(new PacketPlayOutCamera(ep), future1 ->
{
manager.a(new PacketPlayOutGameStateChange(3, (float)GameMode.SPECTATOR.getValue()), future2 ->
{
PacketPlayOutCamera p1 = new PacketPlayOutCamera();
p1.a = packet.a;
manager.handle(p1);
});
if (_pendingSpectate.get(packetInfo.getPlayer().getUniqueId()) != packet.b)
return;
manager.a(new PacketPlayOutGameStateChange(3, (float) GameMode.SPECTATOR.getValue()), future2 ->
{
if (_pendingSpectate.get(packetInfo.getPlayer().getUniqueId()) != packet.b)
return;
_manager.runSync(() ->
{
PacketPlayOutCamera p1 = new PacketPlayOutCamera();
p1.a = packet.a;
if (_pendingSpectate.get(packetInfo.getPlayer().getUniqueId()) != packet.b)
return;
manager.a(p1, future3 ->
{
_manager.runSync(() ->
{
Player playerTarget = Bukkit.getPlayer(packet.b);
if (playerTarget != null)
UtilTextBottom.display(C.cGray + "You are spectating " + F.elem(_manager.GetGame().GetTeam(playerTarget).GetColor() + playerTarget.getName()) + ".", packetInfo.getPlayer());
UtilPlayer.message(packetInfo.getPlayer(), F.main("Game", "Sneak to stop spectating."));
_pendingSpectate.remove(packetInfo.getPlayer().getUniqueId());
});
});
});
});
});
});
});
}
}
}
public void despectate(Player player)
{
// We want to override and tell any pending spectates that we are despectating now
_pendingSpectate.put(player.getUniqueId(), player.getUniqueId());
PlayerGameModeChangeEvent event = new PlayerGameModeChangeEvent(player, GameMode.SURVIVAL);
UtilServer.CallEvent(event);
if (event.isCancelled())
{
_pendingSpectate.remove(player.getUniqueId());
return;
}
EntityPlayer ep = ((CraftPlayer) player).getHandle();
ep.playerInteractManager.setGameMode(WorldSettings.EnumGamemode.getById(GameMode.SURVIVAL.getValue()));
ep.fallDistance = 0.0F;
NetworkManager manager = ep.playerConnection.networkManager;
manager.a(new PacketPlayOutCamera(ep), future1 ->
{
manager.a(new PacketPlayOutGameStateChange(3, (float) GameMode.SURVIVAL.getValue()), future2 ->
{
_manager.runSync(() ->
{
player.setAllowFlight(true);
_pendingSpectate.remove(player.getUniqueId());
});
});
});
}
}

View File

@ -75,8 +75,23 @@ public class GameWorldManager implements Listener
}
if (Manager.GetGame() != null)
{
if (Manager.GetGame().WorldData != null)
Manager.GetGame().WorldData.ChunkUnload(event);
{
if (Manager.GetGame().WorldChunkUnload)
{
return;
}
if (Manager.GetGame().WorldData.World == null)
return;
if (!event.getWorld().equals(Manager.GetGame().WorldData.World))
return;
event.setCancelled(true);
}
}
}
public void RegisterWorld(WorldData worldData)

View File

@ -450,17 +450,6 @@ public class WorldData
World = null;
}
public void ChunkUnload(ChunkUnloadEvent event)
{
if (World == null)
return;
if (!event.getWorld().equals(World))
return;
event.setCancelled(true);
}
public void ChunkLoad(ChunkPreLoadEvent event)
{