Skip to content
This repository was archived by the owner on Aug 12, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,18 @@ This project is not affiliated with Mojang AB, the original developers of Minecr
We would like to acknowledge the following projects and libraries that have inspired or contributed to the development of the NextForge Core Plugin:
- **Spigot & PaperMC**: For their contributions to the Minecraft server development community.
- **Bukkit**: For its foundational work in creating a plugin system for Minecraft.


## FancyNPCs Plugin

FancyNPCs provides a basic NPC system using the `/npc` command. Persistent NPCs are saved in `plugins/FancyNPCs/npcs.yml` unless marked as transient.

### Commands
- `/npc help [page]`
- `/npc create <name>` – create an NPC at your location
- `/npc copy <npc> <new_name>` – duplicate an existing NPC
- `/npc remove <npc>` – delete an NPC
- `/npc list` – list all NPCs
- `/npc info <npc>` – show information about an NPC

Other subcommands for customizing NPCs are available; use `/npc help` for details.
15 changes: 15 additions & 0 deletions fancynpcs/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
plugins {
id 'java-library'
id 'maven-publish'
id "io.papermc.paperweight.userdev"
id "com.gradleup.shadow"
}

dependencies {
implementation project(':')
}

java {
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
}
42 changes: 42 additions & 0 deletions fancynpcs/src/main/java/gg/nextforge/fancynpc/FancyNPCPlugin.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package gg.nextforge.fancynpc;

import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.plugin.java.JavaPlugin;

import java.io.File;

/**
* Bukkit plugin entry point for FancyNPCs.
*/
public class FancyNPCPlugin extends JavaPlugin {

private FileConfiguration messages;

@Override
public void onEnable() {
NPCManager.init(this);
loadMessages();
getCommand("npc").setExecutor(new NPCCommand(this));
getCommand("npc").setTabCompleter(new NPCTabCompleter());
}

@Override
public void onDisable() {
NPCManager.get().clearTransient();
NPCManager.get().saveAll();
}

/** Load messages.yml from disk */
private void loadMessages() {
File messagesFile = new File(getDataFolder(), "messages.yml");
if (!messagesFile.exists()) {
saveResource("messages.yml", false);
}
messages = YamlConfiguration.loadConfiguration(messagesFile);
}

public String msg(String key) {
return messages.getString(key, key);
}
}
35 changes: 35 additions & 0 deletions fancynpcs/src/main/java/gg/nextforge/fancynpc/NPC.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package gg.nextforge.fancynpc;

import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import org.bukkit.Location;
import org.bukkit.entity.Entity;

import java.util.List;
import java.util.Map;

/**
* Data holder for a single NPC.
*/
@Getter
@Setter
@Builder
public class NPC {
private String id;
private String type;
private String displayName;
private String skin;
private boolean glowing;
private boolean showInTab;
private boolean collidable;
private double scale;
private boolean transientNPC;
private int interactionCooldown;
private boolean turnToPlayer;
private double turnToPlayerDistance;
private Map<String, String> attributes;
private List<String> actions;
private Location location;
private Entity entity; // runtime only
}
121 changes: 121 additions & 0 deletions fancynpcs/src/main/java/gg/nextforge/fancynpc/NPCCommand.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package gg.nextforge.fancynpc;

import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.util.StringUtil;

import java.util.List;

/**
* Command executor handling /npc commands.
*/
public class NPCCommand implements CommandExecutor {

private final FancyNPCPlugin plugin;

public NPCCommand(FancyNPCPlugin plugin) {
this.plugin = plugin;
}

@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!sender.hasPermission("nextcore.npc")) {
sender.sendMessage("§cYou do not have permission to use this command.");
return true;
}
if (args.length == 0 || args[0].equalsIgnoreCase("help")) {
sender.sendMessage("§6FancyNPCs commands:");
sender.sendMessage("§e/npc create <name>");
sender.sendMessage("§e/npc copy <npc> <new_name>");
sender.sendMessage("§e/npc remove <npc>");
sender.sendMessage("§e/npc list");
sender.sendMessage("§e/npc info <npc>");
return true;
}
String sub = args[0].toLowerCase();
switch (sub) {
case "create":
return handleCreate(sender, args);
case "copy":
return handleCopy(sender, args);
case "remove":
return handleRemove(sender, args);
case "list":
return handleList(sender);
case "info":
return handleInfo(sender, args);
default:
sender.sendMessage(plugin.msg("error"));
return true;
}
}

private boolean handleCreate(CommandSender sender, String[] args) {
if (!(sender instanceof Player p)) {
sender.sendMessage(plugin.msg("error"));
return true;
}
if (args.length < 2) {
sender.sendMessage(plugin.msg("usage_create"));
return true;
}
String name = args[1];
Location loc = p.getLocation();
NPCManager.get().createNPC(name, EntityType.PLAYER, loc);
sender.sendMessage(plugin.msg("npc_created").replace("{name}", name));
return true;
}

private boolean handleCopy(CommandSender sender, String[] args) {
if (args.length < 3) {
sender.sendMessage(plugin.msg("usage_copy"));
return true;
}
NPC src = NPCManager.get().getNPC(args[1]);
if (src == null) {
sender.sendMessage(plugin.msg("error"));
return true;
}
NPCManager.get().createNPC(args[2], EntityType.valueOf(src.getType()), src.getLocation());
sender.sendMessage(plugin.msg("npc_created").replace("{name}", args[2]));
return true;
}

private boolean handleRemove(CommandSender sender, String[] args) {
if (args.length < 2) {
sender.sendMessage(plugin.msg("usage_remove"));
return true;
}
NPCManager.get().removeNPC(args[1]);
sender.sendMessage(plugin.msg("npc_removed").replace("{name}", args[1]));
return true;
}

private boolean handleList(CommandSender sender) {
List<String> ids = NPCManager.get().listNPCs();
sender.sendMessage("NPCs: " + String.join(", ", ids));
return true;
}

private boolean handleInfo(CommandSender sender, String[] args) {
if (args.length < 2) {
sender.sendMessage(plugin.msg("usage_info"));
return true;
}
NPC npc = NPCManager.get().getNPC(args[1]);
if (npc == null) {
sender.sendMessage(plugin.msg("error"));
return true;
}
sender.sendMessage("Type: " + npc.getType());
if (npc.getLocation() != null) {
sender.sendMessage("Location: " + npc.getLocation().toVector().toString());
}
return true;
}
}
Loading
Loading