Skip to content

Instantly share code, notes, and snippets.

@Namnodorel
Last active November 6, 2019 15:32
Show Gist options
  • Save Namnodorel/fbf72c7ae871115d78c9a6aa76c693b6 to your computer and use it in GitHub Desktop.
Save Namnodorel/fbf72c7ae871115d78c9a6aa76c693b6 to your computer and use it in GitHub Desktop.
import net.citizensnpcs.api.CitizensAPI;
import net.citizensnpcs.api.event.NPCSpawnEvent;
import net.citizensnpcs.api.npc.NPC;
import org.bukkit.Bukkit;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.plugin.Plugin;
import pl.betoncraft.betonquest.*;
import pl.betoncraft.betonquest.api.QuestEvent;
import pl.betoncraft.betonquest.config.Config;
import pl.betoncraft.betonquest.config.ConfigPackage;
import pl.betoncraft.betonquest.utils.PlayerConverter;
import java.util.HashMap;
import java.util.HashSet;
public class NPCHider implements Listener, Runnable{
private static NPCHider instance;
private EntityHider hider;
private HashMap<Integer, HashSet<ConditionID>> npcs;
private ConfigurationSection configSection;
private Integer updateInterval;
public static void init(Plugin plugin){
if(instance == null){
instance = new NPCHider(plugin);
}
}
private NPCHider(Plugin plugin){
configSection = BetonQuest.getInstance().getConfig().getConfigurationSection("hide_npcs");
if (configSection == null){
return;
}
hider = new EntityHider(plugin, EntityHider.Policy.BLACKLIST);
npcs = new HashMap<>();
loadFromConfig();
Bukkit.getScheduler().scheduleSyncRepeatingTask(plugin, this, 0L, 20 * updateInterval);
}
private void loadFromConfig(){
for(ConfigPackage cfgPackage : Config.getPackages().values()){
if(cfgPackage.getCustom().getConfig() == null || cfgPackage.getCustom().getConfig().getConfigurationSection("hide_npcs") == null){
continue;
}
for (String npcID : cfgPackage.getCustom().getConfig().getConfigurationSection("hide_npcs").getKeys(false)) {
try {
int id = Integer.parseInt(npcID);
NPC npc = CitizensAPI.getNPCRegistry().getById(id);
if(npc != null){
HashSet<ConditionID> conditions = new HashSet<>();
String conditionsString = cfgPackage.getCustom().getConfig().getConfigurationSection("hide_npcs").getString(npcID);
for(String condition : conditionsString.split(",")){
conditions.add(new ConditionID(cfgPackage, condition));
}
if(npcs.containsKey(id)){
npcs.get(id).addAll(conditions);
}else{
npcs.put(id, conditions);
}
}else{
System.out.println("[NPCHider]: An NPC with the id " + npcID + " does not exist!");
}
} catch (NumberFormatException e) {
System.err.println("[NPCHider]: Given NPC ID " + npcID + " is not a valid number!");
} catch (ObjectNotFoundException e){
System.err.println("[NPCHider]: " + e.getMessage());
}
}
}
updateInterval = configSection.getInt("updateInterval");
}
//These methods check the conditions and apply according visibilities immediately,
//and need to go through more or less entities and conditions depending on how specific
//the arguments are
public void applyVisibility(Player p, Integer npcID){
boolean hidden = true;
if(npcs.get(npcID).isEmpty()){
hidden = false;
}else{
for(ConditionID condition : npcs.get(npcID)){
if(!BetonQuest.condition(PlayerConverter.getID(p), condition)){
hidden = false;
break;
}
}
}
NPC npc = CitizensAPI.getNPCRegistry().getById(npcID);
if(npc.isSpawned()){
if(hidden){
hider.hideEntity(p, npc.getEntity());
}else{
hider.showEntity(p, npc.getEntity());
}
}
}
public void applyVisibility(Player p){
for(Integer npcID : npcs.keySet()){
applyVisibility(p, npcID);
}
}
public void applyVisibility(NPC npc){
for(Player p : Bukkit.getOnlinePlayers()){
applyVisibility(p, npc.getId());
}
}
public void applyVisibility(){
for(Player p : Bukkit.getOnlinePlayers()){
for(Integer npcID : npcs.keySet()){
applyVisibility(p, npcID);
}
}
}
public static NPCHider getInstance() {
return instance;
}
@Override
public void run() {
applyVisibility();
}
//We want to have the visibility applied immediately, NPCs shouldn't spawn, stay there for a second and only then disappear
@EventHandler
public void onNPCSpawn(NPCSpawnEvent event) {
applyVisibility(event.getNPC());
}
@EventHandler
public void onPlayerJoin(PlayerJoinEvent event) {
applyVisibility(event.getPlayer());
}
//Optional; in case something changed and the updated visibilities need to be applied immediately for that player
public static class UpdateVisibilityNowEvent extends QuestEvent {
public UpdateVisibilityNowEvent(Instruction instruction) throws InstructionParseException {
super(instruction);
}
@Override
public void run(String id) throws QuestRuntimeException {
NPCHider.getInstance().applyVisibility(PlayerConverter.getPlayer(id));
}
}
//Optional; I implemented it because in some cases there are temporary NPCs which shouldn't be
//Visible to everyone
public static class WriteHideConditionEvent extends QuestEvent {
private Integer npcID;
private HashSet<ConditionID> conditions;
public WriteHideConditionEvent(Instruction instruction) throws InstructionParseException {
super(instruction);
super.staticness = true;
super.persistent = true;
npcID = instruction.getInt();
conditions = new HashSet<>();
conditions.addAll(instruction.getList(instruction.getOptional("cons"), instruction::getCondition));
}
@Override
public void run(String s) throws QuestRuntimeException {
NPC npc = CitizensAPI.getNPCRegistry().getById(npcID);
if(npc != null){
NPCHider.getInstance().npcs.put(npcID, conditions);
NPCHider.getInstance().applyVisibility(npc);
}else{
System.out.println("[NPCHider]: An NPC with the id " + npcID + " does not exist!");
}
}
}
}
@Namnodorel
Copy link
Author

Namnodorel commented Oct 26, 2017

@MWFIAE Might be true, but I have yet to come across a problem that needs less thought put into it :P Messing with entities, packets and NMS has been a big headache for me multiple times.

Since I have no new big project planned currently nothing too specific, but Terasology looks promising to me if I want "Minecraft, just programmed better". If just sockets and rendering are the problem, I would love to try out libgdx some day. I mean, you can literally make a game in Java and it runs on anything from iPhone to Windows... A dream come true! :D And since it's an engine there's no need to mess with low-level stuff.

@Co0sh Great ^^ I'm glad to help. I've recently tried DungeonsXL (the description looked very good), but since it is so very very early access and more built for minigame-like dungeons that instances in an RPG I decided not to use it. You might still find it interesting though :) I especially liked the multiple (and random, if you want to) floors and signs to place stuff like spawners and checkpoints in the dungeon/instance.

@MWFIAE
Copy link

MWFIAE commented Oct 27, 2017

@Namnodorel
I messed with Unity and Unreal-Engine a few times in the past which are even better equipped engines, but the problem with the whole moddeling/texturing/etc. still remains and I'm not very good with this artist stuff :p

@Co0sh
Nah, you don't have time for spam.
I already try to help all the other people in the issues so that you have more time to resolve my own issues and implementing features I could make good use of :3 (selfish me :3 )

@Namnodorel
Copy link
Author

@MWFIAE Me neither, but that can be learned. I found https://cgcookie.com/ to be a good resource for learning to model stuff. And you can still use the plenty of presets existing- in MC, you're using a number of "presets" as well, right? :D

@MWFIAE
Copy link

MWFIAE commented Oct 28, 2017

@Namnodorel looks good, will take a look at it sometime if I have some real free time :)
Yeah, but it's not the same, as all presets are from the same source and don't look wild mixed... You know what I mean, right?

@Namnodorel
Copy link
Author

Namnodorel commented Oct 29, 2017

@MWFIAE Yes, kinda. You can get them to look quite similar if you are picky about which presets you use. Buut of course it takes significantly more time to find the right stuff.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment