Fredashay's Villager Chat icon

Fredashay's Villager Chat -----

This plugin causes your villagers to spout random gibberish throughout the day.




Updated for Minecraft 1.20.
----------, Nov 11, 2023

Recompiled for 1.16

Also gave names to the villagers rather than numbers.

It generates the names randomly: consonant-vowel-consonant-vowel-consonant.
----------, Dec 19, 2020

Someone requested that the plugin create a sample villager chat .TXT file if one doesn't exist. So the first time you run the plugin, it will create a sample file "FredashaySpigotVillagerChat.txt" (if it doesn't exist) containing several sample villager chat messages.

As I said once before, each line of text is a separate villager chat post. Don't spread a villager chat post across two lines or put line break within a villager chat post, or the plugin will see it as separate chat posts.

Also, edit the TXT file only with a text editor like Notepad or VI. Don't use a word processor like MS Word or Wordpad, as these will put hidden meta characters in the file that will confuse the plugin.
----------, Oct 28, 2017

This plugin causes your villagers to spout random gibberish throughout the day.

You can have your villagers tell jokes, or if you're politically inclined have them spew left-wing or right-wing propaganda, or Bible quotes if you're running a religious server, or movie quotes, or adverts if your server is part of a business, or automotive advice, or whatever else warps your starship...

You can change various settings in the properties file to vary the frequency of the villager chats and add a random factor.

To install this plugin, copy the plugin JAR file to your server's plugins folder. Then create a text file with Notepad or VI in the home directory of your server (where all the .PROPERTIES files and such are) named "FredashayVillagerChat.txt". Fill this file with the things you want your villagers to say. Remember, each line break will create a new thing for a different villager, so don't break a single statement with a line break, but make sure there are line breaks between each villager's statements.

I currently run a Rainbow server, but I want greater functionality than the Rainbow API provides, so I've been learning Spigot. This is the first of several of my Rainbow plugins that I rewrote for Spigot.

Code (Text):

package FredashaySpigotVillagerChat;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.sql.Date;
import java.text.SimpleDateFormat;
import java.util.Properties;
import java.util.Random;
import java.util.logging.Logger;

import org.bukkit.ChatColor;
import org.bukkit.command.CommandExecutor;
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.PluginDescriptionFile;
import org.bukkit.plugin.java.JavaPlugin;

public class MyPlugin extends JavaPlugin implements Listener, CommandExecutor {
   private static Logger logger = null;
   private static PluginDescriptionFile pdfFile = null;
   private static Properties props = new Properties();
   final static int MAX_GIBBERISH = 1000;  
   private static String gibberishFileName = null;
   private static String propertiesFileName = null;  
   private static String[] gibberish = new String[MAX_GIBBERISH];
   private static int countGibberish = 0;
   private static boolean gibbering = false;
   private static long nextTime = 0;
   private static String lastPlayerName = " ";
   private static int frequency = 60;
   private static int afterJoin = 2;
   private static int giveOrTake = 10;
   private static ChatColor nameColor = ChatColor.RESET;
   
   @Override
    public void onEnable() {
       logger = Logger.getLogger("Minecraft");
       pdfFile = getDescription();
       getServer().getPluginManager().registerEvents(this, this);
       propertiesFileName = pdfFile.getName() + ".properties";  
       gibberishFileName = pdfFile.getName() + ".txt";
       getProperties(propertiesFileName);
       logger.info("[" + pdfFile.getName() + "] Frequency of villager gibberish is " + frequency + " minutes, give or take " + giveOrTake + " minutes. ");
       if (afterJoin > 0) {
           logger.info("[" + pdfFile.getName() + "] Villager gibberish will also occur " + afterJoin + " minutes after a player joins the game.  ");
           }
       if (nameColor == ChatColor.AQUA) logger.info("[" + pdfFile.getName() + "] Name color is 'lightaqua'. ");
       else if (nameColor == ChatColor.BLACK) logger.info("[" + pdfFile.getName() + "] Name color is 'black'. ");
       else if (nameColor == ChatColor.BLUE) logger.info("[" + pdfFile.getName() + "] Name color is 'lightblue'. ");
       else if (nameColor == ChatColor.DARK_AQUA) logger.info("[" + pdfFile.getName() + "] Name color is 'darkaqua'. ");
       else if (nameColor == ChatColor.DARK_BLUE) logger.info("[" + pdfFile.getName() + "] Name color is 'darkblue'. ");
       else if (nameColor == ChatColor.DARK_GRAY) logger.info("[" + pdfFile.getName() + "] Name color is 'darkgray'. ");
       else if (nameColor == ChatColor.DARK_GREEN) logger.info("[" + pdfFile.getName() + "] Name color is 'darkgreen'. ");
       else if (nameColor == ChatColor.DARK_PURPLE) logger.info("[" + pdfFile.getName() + "] Name color is 'darkpurple'. ");
       else if (nameColor == ChatColor.DARK_RED) logger.info("[" + pdfFile.getName() + "] Name color is 'darkred'. ");
       else if (nameColor == ChatColor.GOLD) logger.info("[" + pdfFile.getName() + "] Name color is 'darkyellow'. ");
       else if (nameColor == ChatColor.GRAY) logger.info("[" + pdfFile.getName() + "] Name color is 'lightgray'. ");
       else if (nameColor == ChatColor.GREEN) logger.info("[" + pdfFile.getName() + "] Name color is 'lightgreen'. ");
       else if (nameColor == ChatColor.LIGHT_PURPLE) logger.info("[" + pdfFile.getName() + "] Name color is 'lightpurple'. ");
       else if (nameColor == ChatColor.RED) logger.info("[" + pdfFile.getName() + "] Name color is 'lightred'. ");
       else if (nameColor == ChatColor.WHITE) logger.info("[" + pdfFile.getName() + "] Name color is 'white'. ");
       else if (nameColor == ChatColor.YELLOW) logger.info("[" + pdfFile.getName() + "] Name color is 'lightyellow'. ");
       String inputLine = null;
       countGibberish = 0;
       gibbering = false;
       try {  
           BufferedReader reader = new BufferedReader(new FileReader(gibberishFileName));
           inputLine = reader.readLine();        
           while (inputLine != null) {  
               if (inputLine.length() > 0) {
                   addGibberish(inputLine);              
                   }              
               inputLine = reader.readLine();
               }
           reader.close();      
           }
       catch (FileNotFoundException oops) {
           logger.info("[" + pdfFile.getName() + "] We could not find file '" + gibberishFileName + "' containing your villagers gibberish.  This is not a critical problem, only that your players won't get random gibberish messages during the day.");
           }
       catch (IOException oops) {
           logger.info("[" + pdfFile.getName() + "] We could not find file '" + gibberishFileName + "' containing your villagers gibberish.  This is not a critical problem, only that your players won't get random gibberish messages during the day.");
           }
       if (countGibberish > 0) {                      
           ticking();
           }      
        }  
   
   private void getProperties(String propertiesFileName) {
       InputStream input = null;
       try {
           input = new FileInputStream(propertiesFileName);
           props.load(input);
           }
       catch (FileNotFoundException ok) {
             saveProperties(propertiesFileName);
             }
       catch (IOException oops) {
           logger.info("[" + pdfFile.getName() + "] Error reading properties file '" + propertiesFileName + "'. ");          
           oops.printStackTrace(System.err);
           }
       finally {
           if (input != null) {
               try {
                   input.close();
                   }
               catch (IOException oops) {
                   oops.printStackTrace(System.err);
                   }
               }
           }
       if (props.getProperty("FREQUENCY") != null) {
           if (isNumeric(props.getProperty("FREQUENCY"))) {
                 frequency = toInteger(props.getProperty("FREQUENCY"));
                 if (frequency < 1) {
                     frequency = 1;
                     }
                 }
           }
       if (props.getProperty("GIVEORTAKE") != null) {
           if (isNumeric(props.getProperty("GIVEORTAKE"))) {
                 giveOrTake = toInteger(props.getProperty("GIVEORTAKE"));
                 if (giveOrTake < 0) {
                     giveOrTake = 0;
                     }
                 }
           }
       if (giveOrTake > frequency) {
           giveOrTake = frequency - 1;
           }
       if (props.getProperty("AFTERJOIN") != null) {
           if (isNumeric(props.getProperty("AFTERJOIN"))) {
                 afterJoin = toInteger(props.getProperty("AFTERJOIN"));
                 if (afterJoin < 0) {
                     afterJoin = 0;
                     }
                 }
           }
       if (props.getProperty("NAMECOLOR") != null) {
           if (props.getProperty("NAMECOLOR").length() > 0) {
               if (props.getProperty("NAMECOLOR").equalsIgnoreCase("")) nameColor = ChatColor.RESET;
               else if (props.getProperty("NAMECOLOR").equalsIgnoreCase(" ")) nameColor = ChatColor.RESET;
               else if (props.getProperty("NAMECOLOR").trim().equalsIgnoreCase("")) nameColor = ChatColor.RESET;
               else if (props.getProperty("NAMECOLOR").trim().equalsIgnoreCase(" ")) nameColor = ChatColor.RESET;
               else if (props.getProperty("NAMECOLOR").contains("black")) nameColor = ChatColor.BLACK;
               else if (props.getProperty("NAMECOLOR").contains("darkaqua")) nameColor = ChatColor.DARK_AQUA;
               else if (props.getProperty("NAMECOLOR").contains("darkblue")) nameColor = ChatColor.DARK_BLUE;
               else if (props.getProperty("NAMECOLOR").contains("darkgray")) nameColor = ChatColor.DARK_GRAY;
               else if (props.getProperty("NAMECOLOR").contains("darkgreen")) nameColor = ChatColor.DARK_GREEN;
               else if (props.getProperty("NAMECOLOR").contains("darkpurple")) nameColor = ChatColor.DARK_PURPLE;
               else if (props.getProperty("NAMECOLOR").contains("darkred")) nameColor = ChatColor.DARK_RED;
               else if (props.getProperty("NAMECOLOR").contains("darkyellow")) nameColor = ChatColor.GOLD;
               else if (props.getProperty("NAMECOLOR").contains("lightaqua")) nameColor = ChatColor.AQUA;
               else if (props.getProperty("NAMECOLOR").contains("lightblue")) nameColor = ChatColor.BLUE;
               else if (props.getProperty("NAMECOLOR").contains("lightgray")) nameColor = ChatColor.GRAY;
               else if (props.getProperty("NAMECOLOR").contains("lightgreen")) nameColor = ChatColor.GREEN;
               else if (props.getProperty("NAMECOLOR").contains("lightpurple")) nameColor = ChatColor.LIGHT_PURPLE;
               else if (props.getProperty("NAMECOLOR").contains("lightred")) nameColor = ChatColor.RED;              
               else if (props.getProperty("NAMECOLOR").contains("lightyellow")) nameColor = ChatColor.YELLOW;
               else if (props.getProperty("NAMECOLOR").contains("white")) nameColor = ChatColor.WHITE;              
               else if (props.getProperty("NAMECOLOR").contains("aqua")) nameColor = ChatColor.AQUA;
               else if (props.getProperty("NAMECOLOR").contains("blue")) nameColor = ChatColor.BLUE;
               else if (props.getProperty("NAMECOLOR").contains("gray")) nameColor = ChatColor.GRAY;
               else if (props.getProperty("NAMECOLOR").contains("green")) nameColor = ChatColor.GREEN;
               else if (props.getProperty("NAMECOLOR").contains("purple")) nameColor = ChatColor.LIGHT_PURPLE;
               else if (props.getProperty("NAMECOLOR").contains("red")) nameColor = ChatColor.RED;              
               else if (props.getProperty("NAMECOLOR").contains("yellow")) nameColor = ChatColor.YELLOW;
               else if (props.getProperty("NAMECOLOR").contains("gold")) nameColor = ChatColor.GOLD;
               else if (props.getProperty("NAMECOLOR").contains("violet")) nameColor = ChatColor.LIGHT_PURPLE;
               else if (props.getProperty("NAMECOLOR").contains("grey")) nameColor = ChatColor.GRAY;              
               else if (props.getProperty("NAMECOLOR").contains("cyan")) nameColor = ChatColor.BLUE;
               else if (props.getProperty("NAMECOLOR").contains("magenta")) nameColor = ChatColor.RED;
               else {
                   logger.info("[" + pdfFile.getName() + "] Color '" + props.getProperty("NAMECOLOR") + "' is not a valid color name.  Valid colors are: black, darkaqua, darkblue, darkgray, darkgreen, darkpurple, darkred, darkyellow, lightaqua, lightblue, lightgray, lightgreen, lightpurple, lightred, lightyellow, and white. ");
                   nameColor = ChatColor.RESET;
                   }
               }
           }
       }
   
   private void saveProperties(String propertiesFileName) {
       OutputStream output = null;
       try {
           output = new FileOutputStream(propertiesFileName);
           props.setProperty("FREQUENCY", Integer.toString(frequency));
           props.setProperty("GIVEORTAKE", Integer.toString(giveOrTake));
           props.setProperty("AFTERJOIN", Integer.toString(afterJoin));
           if (nameColor == ChatColor.AQUA) props.setProperty("NAMECOLOR", "lightaqua");
           else if (nameColor == ChatColor.BLACK) props.setProperty("NAMECOLOR", "black");          
           else if (nameColor == ChatColor.BLUE) props.setProperty("NAMECOLOR", "lightblue");
           else if (nameColor == ChatColor.DARK_AQUA) props.setProperty("NAMECOLOR", "darkaqua");
           else if (nameColor == ChatColor.DARK_BLUE) props.setProperty("NAMECOLOR", "darkblue");
           else if (nameColor == ChatColor.DARK_GRAY) props.setProperty("NAMECOLOR", "darkgray");
           else if (nameColor == ChatColor.DARK_GREEN) props.setProperty("NAMECOLOR", "darkgreen");
           else if (nameColor == ChatColor.DARK_PURPLE) props.setProperty("NAMECOLOR", "darkpurple");
           else if (nameColor == ChatColor.DARK_RED) props.setProperty("NAMECOLOR", "darkred");
           else if (nameColor == ChatColor.GOLD) props.setProperty("NAMECOLOR", "darkyellow");
           else if (nameColor == ChatColor.GRAY) props.setProperty("NAMECOLOR", "lightgray");
           else if (nameColor == ChatColor.GREEN) props.setProperty("NAMECOLOR", "lightgreen");
           else if (nameColor == ChatColor.LIGHT_PURPLE) props.setProperty("NAMECOLOR", "lightpurple");
           else if (nameColor == ChatColor.RED) props.setProperty("NAMECOLOR", "lightred");
           else if (nameColor == ChatColor.WHITE) props.setProperty("NAMECOLOR", "white");
           else if (nameColor == ChatColor.YELLOW) props.setProperty("NAMECOLOR", "lightyellow");
           else props.setProperty("NAMECOLOR", " ");
           props.store(output, null);
           }
       catch (IOException oops) {
           logger.info("[" + pdfFile.getName() + "] Error writing properties file '" + propertiesFileName + "'. ");
           oops.printStackTrace(System.err);
           }
       finally {
           try {
               output.close();
               }
           catch (IOException oops) {
               oops.printStackTrace(System.err);
               }
           }
       }
           
   private void addGibberish(String message) {
       if (countGibberish < MAX_GIBBERISH) {
           countGibberish = countGibberish + 1;      
           gibberish[countGibberish] = message.trim();
           }
       else {
           logger.info("[" + pdfFile.getName() + "] There is too much gibberish in '" + propertiesFileName + "'.  Maximum " + MAX_GIBBERISH + " lines of gibberish allowed. ");
           }
       }
   
   public void ticking() {
       getServer().getScheduler().scheduleSyncDelayedTask(this, new Runnable() {
           @Override
           public void run() {
               onTick();                              
               ticking();
               }
           }, 100 );
       }
   
   private void onTick() {
       Random random = new Random();      
       long timeNow = 0;
       int randu = 0;
       String message = null;
       String villager = null;
       timeNow = (long) Math.floor(System.currentTimeMillis() / 1000);
       if (gibbering) {
           if (timeNow > nextTime) {  
               if (countGibberish > 1) {
                   randu = random.nextInt(countGibberish - 1) + 1;
                   }
               else {
                   randu = 1;
                   }
               message = gibberish[randu];
               villager = "Villager #" + randu;
               // getServer().broadcastMessage(ChatColor.WHITE + "<" + ChatColor.LIGHT_PURPLE + "Villager #" + randu + ChatColor.WHITE + "> " + message + " ");            
               getServer().broadcastMessage("<" + nameColor + "Villager #" + randu + ChatColor.RESET + "> " + message + " ");              
               logMessage(villager, message);                              
               int int1 = frequency - giveOrTake;
               int int2 = random.nextInt(giveOrTake * 2);
               int int3 = (int1 + int2) * 60;
               nextTime = timeNow + int3;
               
               }
           }              
       }  
   
   private boolean isNumeric(String string) {
       double number = 0;
       if (number == 0) {
           try {          
               number = Double.parseDouble(string);              
               }  
           catch(NumberFormatException oops) {  
               return (false);  
               }
           }
       return (true);  
       }
   
   private int toInteger(String string) {
       int number = 0;
       try {
           number = Integer.parseInt(string.trim());
           }
       catch (NumberFormatException oops) {
           logger.info("[" + pdfFile.getName() + "] We tried to convert this to an integer number, '" + string + "'; it didn't end well.  ");
           logger.info("[" + pdfFile.getName() + "] " + oops.getMessage());
           oops.printStackTrace(System.err);
           number = 0;
           }
       return (number);
       }
       
   @EventHandler
   public void onPlayerJoin(PlayerJoinEvent event) {
       Player player = event.getPlayer();
       if (countGibberish > 0) {
           gibbering = true;                      
           }
       if (afterJoin > 0) {
           long timeNow = 0;
           timeNow = (long) Math.floor(System.currentTimeMillis() / 1000);                        
           if (!lastPlayerName.equalsIgnoreCase(player.getName())) {
               nextTime = timeNow + (afterJoin * 60);
               }                
           lastPlayerName = player.getName();  
           }          
       }
   
   private void logMessage(String villager, String message) {
       long currentUnixTime = 0;
       SimpleDateFormat mySdfDate = null;
       SimpleDateFormat mySdfTime = null;
       Date messageDateTime = null;
       String messagePrettyDate = null;
       String messagePrettyTime = null;  
       boolean logExists = false;
       
       currentUnixTime = System.currentTimeMillis();                                                                
       mySdfDate = new SimpleDateFormat("yyyy-MM-dd");
       mySdfTime = new SimpleDateFormat("HH:mm:ss");
       messageDateTime = new java.sql.Date(currentUnixTime);
       messagePrettyDate = mySdfDate.format(messageDateTime);
       messagePrettyTime = mySdfTime.format(messageDateTime);
       String logFileName = null;
       File logFile = null;
       logFileName = "FredashayChatLog-" + messagePrettyDate + ".csv";
       FileOutputStream logStream = null;      
       logFile = new File(logFileName);
       try {
           logExists = false;
           if (logFile.exists()) {
               logExists = true;
               }
           logStream = new FileOutputStream(logFile, true);
           if (!logExists) {
                 nyanCat(logStream, "Timestamp, Date, Time, Player Name, Player IP, Game World Location, Chat Message, ; ");
               }                                        
           nyanCat(logStream, currentUnixTime + ", " + messagePrettyDate + ", " +  messagePrettyTime + ", " + villager + ", " + getServer().getIp().toString() + ", Villager Village,\"" + message.replaceAll("\"", "''") + "\",; ");
           logStream.close();
           }
       catch (IOException oops) {
           logger.info("[" + pdfFile.getName() + "] Error writing Chat Log file '" + logFileName + "'. ");
           oops.printStackTrace(System.err);
           }
        }
   
    private void nyanCat(FileOutputStream fileStream, String output) throws IOException {
       try {
           String newline = System.getProperty("line.separator");
           output = output + newline;
           byte[] data = output.getBytes();
           fileStream.write(data, 0, data.length);
           }
       catch (IOException oops) {
           logger.info("[" + pdfFile.getName() + "] Error writing file. ");
           oops.printStackTrace(System.err);
           }
       }
       
    }
 
----------, Sep 30, 2017

Fixed out of bounds exception. If you have only 1 line of gibberish, it doesn't try to choose it at random. It'll only choose one at random if you have more than 1 line of gibberish.
----------, Sep 17, 2017

Resource Information
Author:
----------
Total Downloads: 569
First Release: Sep 17, 2017
Last Update: Nov 11, 2023
Category: ---------------
All-Time Rating:
2 ratings
Find more info at minecraft-server-list.com...
Version -----
Released: --------------------
Downloads: ------
Version Rating:
----------------------
-- ratings