herobrine-2/src/main/java/net/theprogrammersworld/herobrine/Herobrine.java

402 lines
14 KiB
Java

package net.theprogrammersworld.herobrine;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.WorldCreator;
import org.bukkit.command.CommandExecutor;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.server.ServerLoadEvent;
import org.bukkit.metadata.FixedMetadataValue;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.plugin.java.JavaPlugin;
import net.minecraft.core.Holder;
import net.minecraft.core.MappedRegistry;
import net.minecraft.core.Registry;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.MobCategory;
import net.theprogrammersworld.herobrine.AI.AICore;
import net.theprogrammersworld.herobrine.AI.Core.CoreType;
import net.theprogrammersworld.herobrine.AI.extensions.GraveyardWorld;
import net.theprogrammersworld.herobrine.NPC.NPCCore;
import net.theprogrammersworld.herobrine.NPC.AI.Path;
import net.theprogrammersworld.herobrine.NPC.AI.PathManager;
import net.theprogrammersworld.herobrine.NPC.Entity.HumanNPC;
import net.theprogrammersworld.herobrine.commands.CmdExecutor;
import net.theprogrammersworld.herobrine.entity.CustomSkeleton;
import net.theprogrammersworld.herobrine.entity.CustomZombie;
import net.theprogrammersworld.herobrine.entity.EntityManager;
import net.theprogrammersworld.herobrine.listeners.BlockListener;
import net.theprogrammersworld.herobrine.listeners.EntityListener;
import net.theprogrammersworld.herobrine.listeners.InventoryListener;
import net.theprogrammersworld.herobrine.listeners.PlayerListener;
import net.theprogrammersworld.herobrine.listeners.WorldListener;
public class Herobrine extends JavaPlugin implements Listener {
private static Herobrine pluginCore;
private AICore aicore;
private ConfigDB configdb;
private Support support;
private EntityManager entMng;
private PathManager pathMng;
private NPCCore NPCman;
public HumanNPC HerobrineNPC;
public long HerobrineEntityID;
public boolean isInitDone = false;
private int pathUpdateINT = 0;
public static String versionStr = "UNDEFINED";
public static boolean isNPCDisabled = false;
public static int HerobrineHP = 200;
public static int HerobrineMaxHP = 200;
public static final boolean isDebugging = false;
public static boolean AvailableWorld = false;
public static List<Material> AllowedBlocks = new ArrayList<Material>();
public Map<Player, Long> PlayerApple = new HashMap<Player, Long>();
public static Logger log = Logger.getLogger("Minecraft");
@Override
public void onEnable() {
boolean continueWithEnable = true;
// Check a server class name to determine if the plugin is compatible with the Spigot server version.
// If it is not, print an error message and disable the plugin.
if (continueWithEnable) {
try {
Class.forName("org.bukkit.craftbukkit.v1_20_R1.CraftArt");
} catch (ClassNotFoundException e) {
Bukkit.getServer().getConsoleSender().sendMessage(ChatColor.RED + "This version of Herobrine is not "
+ "compatible with this server's Spigot version and will be disabled.");
continueWithEnable = false;
getServer().getPluginManager().disablePlugin(this);
}
}
if (continueWithEnable) {
// Custom Entity Injection
if (!isNPCDisabled) {
try {
addCustomEntity("mzombie", CustomZombie::new, MobCategory.MONSTER);
addCustomEntity("mskeleton", CustomSkeleton::new, MobCategory.MONSTER);
} catch (Exception e) {
e.printStackTrace();
getServer().getPluginManager().disablePlugin(this);
}
} else {
log.warning("[Herobrine] Custom NPCs have been disabled due to an incompatibility error.");
}
getServer().getPluginManager().registerEvents(this, this);
}
}
@EventHandler
public void onServerLoad(ServerLoadEvent event) {
PluginDescriptionFile pdf = this.getDescription();
versionStr = pdf.getVersion();
isInitDone = true;
Herobrine.pluginCore = this;
this.configdb = new ConfigDB(log);
this.NPCman = new NPCCore(this);
// Initialize PathManager
this.pathMng = new PathManager();
// Initialize AICore
this.aicore = new AICore();
// Initialize EntityManager
this.entMng = new EntityManager();
// Config loading
configdb.Startup();
configdb.Reload();
// Graveyard World
if (this.configdb.UseGraveyardWorld == true && Bukkit.getServer().getWorld(configdb.HerobrineWorldName) == null) {
WorldCreator wc = new WorldCreator(configdb.HerobrineWorldName);
wc.generateStructures(false);
org.bukkit.WorldType type = org.bukkit.WorldType.FLAT;
wc.type(type);
wc.createWorld();
GraveyardWorld.Create();
/* Starting with Minecraft 1.18, the Y coordinate used for the flat world generated for Herobrine's Graveyard is -61 instead of 3.
* This elevation change required graveyard generation as well as Herobrine and player location management to be shifted down to
* accommodate it. This change is only applied to graveyard worlds generated on 1.18 or newer, however, and would cause graveyards
* generated on older versions to not show Herobrine or the player in the right place. To work around this, we use this conditional
* to set a "graveyardYCoord" configuration variable. By default, the value is set for a graveyard generated by 1.18 or newer. This
* conditional will check the position of the graveyard to determine if the value should be set for a pre-1.18 graveyard. */
if (Bukkit.getServer().getWorld(configdb.HerobrineWorldName).getBlockAt(0, 3, 0).getType() == Material.MYCELIUM) {
configdb.graveyardYCoord = 4;
}
}
// Spawn Herobrine
Location nowloc = new Location((World) Bukkit.getServer().getWorlds().get(0), (float) 0, (float) -100,
(float) 0);
nowloc.setYaw((float) 1);
nowloc.setPitch((float) 1);
HerobrineSpawn(nowloc);
HerobrineNPC.setItemInHand(configdb.ItemInHand.getItemStack());
getServer().getPluginManager().registerEvents(new EntityListener(this), this);
getServer().getPluginManager().registerEvents(new BlockListener(), this);
getServer().getPluginManager().registerEvents(new InventoryListener(), this);
getServer().getPluginManager().registerEvents(new PlayerListener(this), this);
getServer().getPluginManager().registerEvents(new WorldListener(), this);
// Init Block Types
AllowedBlocks.add(Material.AIR);
AllowedBlocks.add(Material.SNOW);
AllowedBlocks.add(Material.RAIL);
AllowedBlocks.add(Material.ACTIVATOR_RAIL);
AllowedBlocks.add(Material.DETECTOR_RAIL);
AllowedBlocks.add(Material.POWERED_RAIL);
AllowedBlocks.add(Material.DEAD_BUSH);
AllowedBlocks.add(Material.DANDELION);
AllowedBlocks.add(Material.POPPY);
AllowedBlocks.add(Material.ACACIA_PRESSURE_PLATE);
AllowedBlocks.add(Material.BIRCH_PRESSURE_PLATE);
AllowedBlocks.add(Material.DARK_OAK_PRESSURE_PLATE);
AllowedBlocks.add(Material.HEAVY_WEIGHTED_PRESSURE_PLATE);
AllowedBlocks.add(Material.JUNGLE_PRESSURE_PLATE);
AllowedBlocks.add(Material.LIGHT_WEIGHTED_PRESSURE_PLATE);
AllowedBlocks.add(Material.OAK_PRESSURE_PLATE);
AllowedBlocks.add(Material.SPRUCE_PRESSURE_PLATE);
AllowedBlocks.add(Material.STONE_PRESSURE_PLATE);
AllowedBlocks.add(Material.VINE);
AllowedBlocks.add(Material.TORCH);
AllowedBlocks.add(Material.REDSTONE);
AllowedBlocks.add(Material.REDSTONE_TORCH);
AllowedBlocks.add(Material.LEVER);
AllowedBlocks.add(Material.STONE_BUTTON);
AllowedBlocks.add(Material.LADDER);
pathUpdateINT = Bukkit.getServer().getScheduler().scheduleSyncRepeatingTask(this, new Runnable() {
public void run() {
if (Herobrine.getPluginCore().getAICore().getCoreTypeNow().equals(CoreType.ANY) ||
Herobrine.getPluginCore().getAICore().getCoreTypeNow().equals(CoreType.RANDOM_POSITION)) {
pathMng.setPath(new Path(Utils.getRandomGen().nextInt(15) - 7f, Utils.getRandomGen().nextInt(15) - 7f, Herobrine.getPluginCore()));
}
}
}, 1 * 200L, 1 * 200L);
Bukkit.getServer().getScheduler().scheduleSyncRepeatingTask(this, new Runnable() {
public void run() {
pathMng.update();
}
}, 1 * 5L, 1 * 5L);
// Command Executors
this.getCommand("hb").setExecutor((CommandExecutor) new CmdExecutor(this));
this.getCommand("hero").setExecutor((CommandExecutor) new CmdExecutor(this));
// Support initialize
this.support = new Support();
// If the plugin configuration has updated checking turned on, start the thread responsible for performing the check.
if(configdb.CheckForUpdates)
new Thread(new UpdateScanner()).start();
}
@Override
public void onDisable() {
if (isInitDone) {
this.entMng.killAllMobs();
Bukkit.getServer().getScheduler().cancelTask(pathUpdateINT);
NPCman.DisableTask();
aicore.Stop_BD();
aicore.Stop_CG();
aicore.Stop_MAIN();
aicore.Stop_RC();
aicore.Stop_RM();
aicore.Stop_RP();
aicore.Stop_RS();
aicore.disableAll();
}
}
public java.io.InputStream getInputStreamData(String src) {
return Herobrine.class.getResourceAsStream(src);
}
public AICore getAICore() {
return this.aicore;
}
public EntityManager getEntityManager() {
return this.entMng;
}
public static Herobrine getPluginCore() {
return Herobrine.pluginCore;
}
public void HerobrineSpawn(Location loc) {
HerobrineNPC = (HumanNPC) NPCman.spawnHumanNPC(ChatColor.WHITE + "Herobrine", loc);
HerobrineNPC.getBukkitEntity().setMetadata("NPC", new FixedMetadataValue(this, true));
HerobrineEntityID = HerobrineNPC.getBukkitEntity().getEntityId();
}
public void HerobrineRemove() {
HerobrineEntityID = 0;
HerobrineNPC = null;
NPCman.removeAll();
}
public ConfigDB getConfigDB() {
return this.configdb;
}
public String getVersionStr() {
return versionStr;
}
public Support getSupport() {
return this.support;
}
public PathManager getPathManager() {
return this.pathMng;
}
public boolean canAttackPlayer(Player player, Player sender) {
boolean opCheck = true;
boolean creativeCheck = true;
boolean ignoreCheck = true;
if (!configdb.AttackOP && player.isOp()) {
opCheck = false;
}
if (!configdb.AttackCreative && player.getGameMode() == GameMode.CREATIVE) {
creativeCheck = false;
}
if (configdb.UseIgnorePermission && player.hasPermission("herobrine.ignore")) {
ignoreCheck = false;
}
if (opCheck && creativeCheck && ignoreCheck) {
return true;
} else {
if(sender == null){
if (!opCheck)
log.info("[Herobrine] " + player.getDisplayName() + " is an OP.");
else if (!creativeCheck)
log.info("[Herobrine] " + player.getDisplayName() + " is in creative mode.");
else if (!ignoreCheck)
log.info("[Herobrine] " + player.getDisplayName() + " has ignore permission.");
}else{
if (!opCheck)
sender.sendMessage(ChatColor.RED + "[Herobrine] " + player.getDisplayName() + " is an OP.");
else if (!creativeCheck)
sender.sendMessage(ChatColor.RED + "[Herobrine] " + player.getDisplayName() + " is in creative mode.");
else if (!ignoreCheck)
sender.sendMessage(ChatColor.RED + "[Herobrine] " + player.getDisplayName() + " has ignore permission.");
}
return false;
}
}
public boolean canAttackPlayerNoMSG(Player player) {
boolean opCheck = true;
boolean creativeCheck = true;
boolean ignoreCheck = true;
if (!configdb.AttackOP && player.isOp()) {
opCheck = false;
}
if (!configdb.AttackCreative && player.getGameMode() == GameMode.CREATIVE) {
creativeCheck = false;
}
if (configdb.UseIgnorePermission && player.hasPermission("herobrine.ignore")) {
ignoreCheck = false;
}
if (opCheck && creativeCheck && ignoreCheck) {
return true;
} else {
return false;
}
}
public String getAvailableWorldString() {
if (AvailableWorld) {
return "Yes";
} else {
return "No";
}
}
private static <T extends Entity> void addCustomEntity(String customName, EntityType.EntityFactory<T> _func, MobCategory enumCreatureType) {
// Registers a custom entity. Adapted from https://www.spigotmc.org/threads/handling-custom-entity-registry-on-spigot-1-13.353426/#post-3447111
// As of 1.18.2, this function was updated to unfreeze and freeze the entity registry when adding a new custom entity. Additionally, a conditional
// check was added to prevent the plugin from crashing due to an attempt to add the same custom entity twice.
if (!BuiltInRegistries.ENTITY_TYPE.getOptional(new ResourceLocation(customName)).isPresent()) {
unfreezeRegistry();
EntityType.Builder<?> entity = EntityType.Builder.of(_func, enumCreatureType);
entity.noSummon();
Registry.register(BuiltInRegistries.ENTITY_TYPE, customName, entity.build(customName));
BuiltInRegistries.ENTITY_TYPE.freeze();
}
}
private static void unfreezeRegistry() {
// As of 1.18.2, registries are frozen once NMS is done adding to them, so we have to do some super hacky things to add custom entities now.
// Adapted from https://github.com/iSach/UltraCosmetics/blob/7f8bbfd2a540559888b89dae7eee4dec482ab7c9/v1_18_R2/src/main/java/be/isach/ultracosmetics/
// v1_18_R2/customentities/CustomEntities.java#L75-L104
// Obfuscated fields are from https://github.com/iSach/UltraCosmetics/blob/master/v1_19_R1/src/main/java/be/isach/ultracosmetics/v1_19_R1/ObfuscatedFields.java
final String INTRUSIVE_HOLDER_CACHE = "m";
final String FROZEN = "l";
Class<?> registryClass = MappedRegistry.class;
try {
Field intrusiveHolderCache = registryClass.getDeclaredField(INTRUSIVE_HOLDER_CACHE);
intrusiveHolderCache.setAccessible(true);
intrusiveHolderCache.set(BuiltInRegistries.ENTITY_TYPE, new IdentityHashMap<EntityType<?>, Holder.Reference<EntityType<?>>>());
Field frozen = registryClass.getDeclaredField(FROZEN);
frozen.setAccessible(true);
frozen.set(BuiltInRegistries.ENTITY_TYPE, false);
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
e.printStackTrace();
return;
}
}
}