Merge branch 'dev' into dev

This commit is contained in:
Kam authored and GitHub committed 2025-03-06 02:19:17 -05:00
commit 43c940f7ed
799 files changed
+49724 -13791

No files matched your search

+2 -2
View File
@@ -172,7 +172,7 @@ public class CmdClone extends ChMcLogger {
entity.setPosition(posX + 0.5, posY + 1, posZ + 0.5);
if(entity instanceof EntityNPCInterface){
EntityNPCInterface npc = (EntityNPCInterface) entity;
npc.ai.startPos = new int[]{MathHelper.floor_double(posX), MathHelper.floor_double(posY), MathHelper.floor_double(posZ)};
npc.ais.startPos = new int[]{MathHelper.floor_double(posX), MathHelper.floor_double(posY), MathHelper.floor_double(posZ)};
if(newname != null && !newname.isEmpty())
npc.display.name = newname.replaceAll("%", " "); // like name, newname must use % in place of space to keep a logical way
}
@@ -274,7 +274,7 @@ public class CmdClone extends ChMcLogger {
entity.setPosition(posX + 0.5 + x, yy + 1, posZ + 0.5 + z);
if(entity instanceof EntityNPCInterface){
EntityNPCInterface npc = (EntityNPCInterface) entity;
npc.ai.startPos = new int[]{xx, yy, zz};
npc.ais.startPos = new int[]{xx, yy, zz};
if(newname != null && !newname.isEmpty())
npc.display.name = newname.replaceAll("%", " "); // like name, newname must use % in place of space to keep a logical way
}
+4 -3
View File
@@ -5,15 +5,16 @@ import foxz.commandhelper.annotations.Command;
import foxz.commandhelper.annotations.SubCommand;
import foxz.commandhelper.permissions.OpOnly;
import foxz.commandhelper.permissions.PlayerOnly;
import kamkeel.npcs.network.PacketHandler;
import kamkeel.npcs.network.enums.EnumConfigOperation;
import kamkeel.npcs.network.packets.data.ConfigCommandPacket;
import net.minecraft.block.Block;
import net.minecraft.block.BlockIce;
import net.minecraft.block.BlockLeavesBase;
import net.minecraft.block.BlockVine;
import net.minecraft.entity.player.EntityPlayerMP;
import noppes.npcs.CustomNpcs;
import noppes.npcs.Server;
import noppes.npcs.config.ConfigMain;
import noppes.npcs.constants.EnumPacketClient;
import noppes.npcs.controllers.ChunkController;
import java.util.Arrays;
@@ -207,6 +208,6 @@ public class CmdConfig extends ChMcLogger {
for(int i = 0; i < args.length; i++){
font += " " + args[i];
}
Server.sendData((EntityPlayerMP)this.pcParam, EnumPacketClient.CONFIG, 0, font.trim(), size);
PacketHandler.Instance.sendToPlayer(new ConfigCommandPacket(EnumConfigOperation.FONT, font.trim(), size), (EntityPlayerMP)this.pcParam);
}
}
+1 -1
View File
@@ -5,12 +5,12 @@ import foxz.commandhelper.annotations.Command;
import foxz.commandhelper.annotations.SubCommand;
import foxz.commandhelper.permissions.OpOnly;
import foxz.commandhelper.permissions.ParamCheck;
import kamkeel.npcs.controllers.SyncController;
import net.minecraft.command.CommandBase;
import net.minecraft.entity.player.EntityPlayer;
import noppes.npcs.NoppesUtilServer;
import noppes.npcs.client.EntityUtil;
import noppes.npcs.controllers.DialogController;
import noppes.npcs.controllers.SyncController;
import noppes.npcs.controllers.data.Dialog;
import noppes.npcs.controllers.data.DialogOption;
import noppes.npcs.controllers.data.PlayerData;
+2 -2
View File
@@ -50,7 +50,7 @@ public class CmdNpc extends ChMcLogger {
posZ = CommandBase.func_110666_a(pcParam, selectedNpc.posZ, args[2]);
}
selectedNpc.ai.startPos = new int[]{MathHelper.floor_double(posX), MathHelper.floor_double(posY), MathHelper.floor_double(posZ)};
selectedNpc.ais.startPos = new int[]{MathHelper.floor_double(posX), MathHelper.floor_double(posY), MathHelper.floor_double(posZ)};
}
@SubCommand(
@@ -144,7 +144,7 @@ public class CmdNpc extends ChMcLogger {
if(args.length > 0)
npc.display.name = args[0];
npc.setPositionAndRotation(player.posX, player.posY, player.posZ, player.cameraYaw, player.cameraPitch);
npc.ai.startPos = new int[]{MathHelper.floor_double(player.posX),MathHelper.floor_double(player.posY),MathHelper.floor_double(player.posZ)};
npc.ais.startPos = new int[]{MathHelper.floor_double(player.posX),MathHelper.floor_double(player.posY),MathHelper.floor_double(player.posZ)};
pw.spawnEntityInWorld(npc);
npc.setHealth(npc.getMaxHealth());
NoppesUtilServer.sendOpenGui(player, EnumGuiType.MainMenuDisplay, npc);
+5 -5
View File
@@ -5,11 +5,11 @@ import foxz.commandhelper.annotations.Command;
import foxz.commandhelper.annotations.SubCommand;
import foxz.commandhelper.permissions.OpOnly;
import foxz.commandhelper.permissions.ParamCheck;
import kamkeel.npcs.controllers.SyncController;
import kamkeel.npcs.network.packets.data.AchievementPacket;
import kamkeel.npcs.network.packets.data.ChatAlertPacket;
import net.minecraft.entity.player.EntityPlayerMP;
import noppes.npcs.Server;
import noppes.npcs.constants.EnumPacketClient;
import noppes.npcs.controllers.QuestController;
import noppes.npcs.controllers.SyncController;
import noppes.npcs.controllers.data.PlayerData;
import noppes.npcs.controllers.data.Quest;
import noppes.npcs.controllers.data.QuestData;
@@ -58,8 +58,8 @@ public class CmdQuest extends ChMcLogger{
playerdata.questData.activeQuests.put(questid, questdata);
playerdata.save();
if(playerdata.player != null){
Server.sendData((EntityPlayerMP)playerdata.player, EnumPacketClient.MESSAGE, "quest.newquest", quest.title);
Server.sendData((EntityPlayerMP)playerdata.player, EnumPacketClient.CHAT, "quest.newquest", ": ", quest.title);
AchievementPacket.sendAchievement((EntityPlayerMP) playerdata.player, false, "quest.newquest", quest.title);
ChatAlertPacket.sendChatAlert((EntityPlayerMP) playerdata.player, "quest.newquest", ": ", quest.title);
}
playerdata.updateClient = true;
}
@@ -1,153 +0,0 @@
package kamkeel.command;
import net.minecraft.command.CommandBase;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.server.MinecraftServer;
import noppes.npcs.CustomNpcsPermissions;
import noppes.npcs.scripted.CustomNPCsException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class CommandKamkeel extends CommandBase{
public Map<String, CommandKamkeelBase> map = new HashMap<String, CommandKamkeelBase>();
public HelpCommand help = new HelpCommand(this);
public String[] alias = {"kam"};
public CommandKamkeel(){
registerCommand(help);
registerCommand(new ScriptCommand());
registerCommand(new SlayCommand());
registerCommand(new QuestCommand());
registerCommand(new QuestCategoryCommand());
registerCommand(new DialogCommand());
registerCommand(new DialogCategoryCommand());
registerCommand(new FactionCommand());
registerCommand(new NpcCommand());
registerCommand(new CloneCommand());
registerCommand(new ConfigCommand());
registerCommand(new AnimationCommand());
registerCommand(new OverlayCommand());
registerCommand(new CommandCommand());
}
public void registerCommand(CommandKamkeelBase command){
String name = command.getCommandName().toLowerCase();
if(map.containsKey(name))
throw new CustomNPCsException("Already a subcommand with the name: " + name);
map.put(name, command);
}
@Override
public String getCommandName() {
return "kamkeel";
}
@Override
public List getCommandAliases()
{
return Arrays.asList(alias);
}
@Override
public String getCommandUsage(ICommandSender sender) {
return "Use as /kamkeel subcommand";
}
@Override
public void processCommand(ICommandSender sender, String[] args) throws CommandException {
if(args.length == 0){
help.processCommand(sender, args);
return;
}
CommandKamkeelBase command = getCommand(args);
if(command == null)
throw new CommandException("Unknown command " + args[0]);
args = Arrays.copyOfRange(args, 1, args.length);
if(command.subcommands.isEmpty() || !command.runSubCommands()){
if(!canSendCommand(sender, command))
throw new CommandException("You are not allowed to use this command: " + command);
command.canRun(sender, command.getUsage(), args);
command.processCommand(sender, args);
return;
}
if(args.length == 0){
help.processCommand(sender, new String[]{command.getCommandName()});
return;
}
command.processSubCommand(sender, args[0], Arrays.copyOfRange(args, 1, args.length));
}
@Override
public List addTabCompletionOptions(ICommandSender sender, String[] args){
if(args.length == 1)
return CommandBase.getListOfStringsMatchingLastWord(args, map.keySet().toArray(new String[map.size()]));
CommandKamkeelBase command = getCommand(args);
if(command == null)
return null;
if(args.length == 2 && command.runSubCommands())
return CommandBase.getListOfStringsMatchingLastWord(args, command.subcommands.keySet().toArray(new String[command.subcommands.keySet().size()]));
String[] useArgs = command.getUsage().split(" ");
if(command.runSubCommands()) {
Method m = command.subcommands.get(args[1].toLowerCase());
if(m != null) {
useArgs = m.getAnnotation(CommandKamkeelBase.SubCommand.class).usage().split(" ");
}
}
if(args.length <= useArgs.length + 2) {
if(args.length - 3 >= 0){
String usage = useArgs[args.length - 3];
if(usage.equals("<player>") || usage.equals("[player]")) {
return CommandBase.getListOfStringsMatchingLastWord(args, MinecraftServer.getServer().getAllUsernames());
}
}
}
return command.addTabCompletionOptions(sender, Arrays.copyOfRange(args, 1, args.length));
}
public CommandKamkeelBase getCommand(String[] args){
if(args.length == 0)
return null;
return map.get(args[0].toLowerCase());
}
@Override
public int getRequiredPermissionLevel(){
return 2;
}
public static String getCommandPermission(String command){
return "cnpc.kamkeel." + command.toLowerCase();
}
public static String getUniversalPermission(){
return "cnpc.kamkeel.*";
}
public static boolean canSendCommand(ICommandSender sender, CommandKamkeelBase command){
if(sender.canCommandSenderUseCommand(command.getRequiredPermissionLevel(), getUniversalPermission())){
return true;
}
if(sender.canCommandSenderUseCommand(command.getRequiredPermissionLevel(), getCommandPermission(command.getCommandName()))){
return true;
}
if(sender instanceof EntityPlayer){
return CustomNpcsPermissions.hasCustomPermission((EntityPlayer) sender, getCommandPermission(command.getCommandName()));
}
return false;
}
}
@@ -1,70 +0,0 @@
package kamkeel.command.profile;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender;
import net.minecraft.util.ChatComponentTranslation;
import java.lang.reflect.Method;
import java.util.Map.Entry;
public class CommandHelpProfile extends CommandProfileBase {
private CommandProfile parent;
public CommandHelpProfile(CommandProfile parent){
this.parent = parent;
}
@Override
public String getCommandName() {
return "help";
}
@Override
public String getDescription() {
return "help [command]";
}
@Override
public void processCommand(ICommandSender sender, String[] args) throws CommandException {
if(args.length == 0){
sendMessage(sender, "\u00A78------ \u00A7aProfile Commands \u00A78------");
for(Entry<String, CommandProfileBase> entry : parent.map.entrySet()){
sendMessage(sender, "\u00A77> " + "\u00A7e" + entry.getKey() + "\u00A78: \u00A77" + entry.getValue().getCommandUsage(sender));
}
return;
}
CommandProfileBase command = parent.getCommand(args);
if(command == null){
sendError(sender, "Unknown command " + args[0]);
return;
}
if(command.subcommands.isEmpty()){
sender.addChatMessage(new ChatComponentTranslation(command.getCommandUsage(sender)));
return;
}
Method m = null;
if(args.length > 1){
m = command.subcommands.get(args[1].toLowerCase());
}
if(m == null){
sendMessage(sender, "\u00A78------ \u00A7a" + command.getCommandName().toUpperCase() + " SubCommands \u00A78------");
sendMessage(sender, "\u00A77Usage: \u00A76" + command.getUsage());
for(Entry<String, Method> entry : command.subcommands.entrySet()){
sender.addChatMessage(new ChatComponentTranslation("\u00A77> " + "\u00A7e" + entry.getKey() + "\u00A78: \u00A77" + entry.getValue().getAnnotation(SubCommand.class).desc()));
}
sender.addChatMessage(new ChatComponentTranslation("\u00A78Permission:\u00A77 " + CommandProfile.getCommandPermission(command.getCommandName())));
}
else{
sendMessage(sender, "\u00A78------ \u00A7b" + command.getCommandName().toUpperCase() + "." + args[1].toUpperCase() + " Command \u00A78------");
SubCommand sc = m.getAnnotation(SubCommand.class);
sender.addChatMessage(new ChatComponentTranslation("\u00A77" + sc.desc()));
if(!sc.usage().isEmpty())
sender.addChatMessage(new ChatComponentTranslation("\u00A77Usage: \u00A76" + sc.usage()));
sender.addChatMessage(new ChatComponentTranslation("\u00A78Permission:\u00A77 " + getSubCommandPermission(args[1])));
}
}
}
@@ -1,61 +0,0 @@
package kamkeel.command.profile;
import kamkeel.controllers.ProfileController;
import kamkeel.controllers.data.Profile;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
public class CommandProfileChange extends CommandProfileBase {
@Override
public String getCommandName() {
return "change";
}
@Override
public String getDescription() {
return "change profiles";
}
@Override
public String getUsage() {
return "<number>";
}
@Override
public boolean runSubCommands(){
return false;
}
@Override
public void processCommand(ICommandSender sender, String[] args) throws CommandException {
if(!(sender instanceof EntityPlayer)){
sendError(sender, "This command can only be sent by a player");
return;
}
int slotID;
try {
slotID = Integer.parseInt(args[0]);
} catch (NumberFormatException ex) {
sendError(sender, "Slot ID must be a number: " + args[1]);
return;
}
// TODO: Check if the player has permission to switch to this slot
EntityPlayerMP player = (EntityPlayerMP) sender;
Profile profile = ProfileController.activeProfiles.get(player.getUniqueID());
if(profile == null){
sendError(sender, "Could not find a valid profile file");
return;
}
ProfileController.changePlayerSlot(player, slotID);
// TODO: Add Cooldown to successful operation
sendResult(sender, String.format("Switched to Slot \u00A7b%d\u00A77", slotID));
}
}
@@ -1,176 +0,0 @@
package kamkeel.controllers;
import kamkeel.controllers.data.IProfileData;
import kamkeel.controllers.data.Profile;
import kamkeel.controllers.data.Slot;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.CompressedStreamTools;
import net.minecraft.nbt.NBTTagCompound;
import noppes.npcs.CustomNpcs;
import noppes.npcs.LogWriter;
import noppes.npcs.util.CustomNPCsThreader;
import noppes.npcs.util.NBTJsonUtil;
import java.io.File;
import java.io.FileOutputStream;
import java.util.HashMap;
import java.util.UUID;
public class ProfileController {
public static HashMap<String, IProfileData> profileTypes;
public static HashMap<UUID, Profile> activeProfiles;
public static String profile_directory = "profiles";
public ProfileController(){
profileTypes = new HashMap<>();
activeProfiles = new HashMap<>();
}
/**
* Register during ServerStartEvent()
*
* @param type - IProfile Type to always Save/Load
* @return true/false if profile was successfully added
*/
public static boolean registerProfileType(IProfileData type){
if(profileTypes.containsKey(type.getTagName()))
return false;
profileTypes.put(type.getTagName(), type);
return true;
}
public static File getProfileDir(){
try{
File file = new File(CustomNpcs.getWorldSaveDirectory(), profile_directory);
if(!file.exists())
file.mkdir();
return file;
}
catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static synchronized void login(EntityPlayer player){
if(player == null)
return;
Profile profile;
if(activeProfiles.containsKey(player.getUniqueID())){
profile = activeProfiles.get(player.getUniqueID());
profile.player = player;
} else {
NBTTagCompound profileCompound = load(player);
profile = new Profile(player, profileCompound);
activeProfiles.put(player.getUniqueID(), profile);
}
}
public static synchronized NBTTagCompound load(EntityPlayer player) {
File saveDir = getProfileDir();
String filename = player.getUniqueID().toString();
filename += ".dat";
try {
File file = new File(saveDir, filename);
if(file.exists()){
return NBTJsonUtil.loadNBTData(file);
}
} catch (Exception e) {
LogWriter.error("Error loading profile file: " + filename, e);
}
return new NBTTagCompound();
}
public static synchronized void save(EntityPlayer player, Profile profile) {
CustomNPCsThreader.customNPCThread.execute(() -> {
final NBTTagCompound compound = profile.writeToNBT();
final String filename = player.getUniqueID() + ".dat";
try {
File saveDir = getProfileDir();
File file = new File(saveDir, filename + "_new");
File file1 = new File(saveDir, filename);
CompressedStreamTools.writeCompressed(compound, new FileOutputStream(file));
if(file1.exists()){
file1.delete();
}
file.renameTo(file1);
} catch (Exception e) {
LogWriter.except(e);
}
});
}
public static void changeSlot(EntityPlayer player, int slotNumber){
if(!activeProfiles.containsKey(player.getUniqueID()))
return;
Profile profile = activeProfiles.get(player.getUniqueID());
if(profile.currentID == slotNumber)
return;
// Saves Current Slot Data
saveSlotData(player);
// Sets Player to New Slot
changePlayerSlot(player, slotNumber);
// Save Slot File
save(player, profile);
}
public static void saveSlotData(EntityPlayer player){
if(!activeProfiles.containsKey(player.getUniqueID()))
return;
NBTTagCompound dataCompound;
Slot slot;
Profile profile = activeProfiles.get(player.getUniqueID());
if(!profile.slots.isEmpty() && profile.slots.containsKey(profile.currentID)){
slot = profile.slots.get(profile.currentID);
dataCompound = (NBTTagCompound) slot.getCompound().copy();
} else {
slot = new Slot(profile.currentID, "Slot " + profile.currentID);
dataCompound = new NBTTagCompound();
slot.setCompound(dataCompound);
}
for(IProfileData profileData : profileTypes.values()){
NBTTagCompound cloned = (NBTTagCompound) profileData.getCurrentNBT(player).copy();
dataCompound.setTag(profileData.getTagName(), cloned);
}
slot.setCompound(dataCompound);
}
public static void changePlayerSlot(EntityPlayer player, int id){
if(!activeProfiles.containsKey(player.getUniqueID()))
return;
NBTTagCompound slotCompound;
Slot slot;
Profile profile = activeProfiles.get(player.getUniqueID());
if(!profile.slots.isEmpty() && profile.slots.containsKey(id)){
slot = profile.slots.get(id);
slotCompound = (NBTTagCompound) slot.getCompound().copy();
} else {
slot = new Slot(id, "Slot " + id);
slotCompound = new NBTTagCompound();
slot.setCompound(slotCompound);
}
slot.setLastLoaded(System.currentTimeMillis());
profile.slots.put(id, slot);
for(IProfileData profileData : profileTypes.values()){
profileData.setNBT(player, slotCompound.getCompoundTag(profileData.getTagName()));
profileData.save(player);
}
profile.currentID = id;
}
}
@@ -1,39 +0,0 @@
package kamkeel.controllers.data;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.NBTTagCompound;
import noppes.npcs.controllers.data.PlayerData;
public class CNPCData implements IProfileData {
@Override
public String getTagName() {
return "CustomNPC+";
}
@Override
public NBTTagCompound getCurrentNBT(EntityPlayer player) {
PlayerData customNPCData = PlayerData.get(player);
return customNPCData.getNBT();
}
@Override
public void save(EntityPlayer player) {
PlayerData customNPCData = PlayerData.get(player);
customNPCData.save();
}
@Override
public void setNBT(EntityPlayer player, NBTTagCompound replace) {
PlayerData customNPCData = PlayerData.get(player);
if(replace.hasNoTags()){
PlayerData newData = new PlayerData();
newData.player = player;
customNPCData.setNBT((NBTTagCompound) newData.getNBT().copy());
}
else {
customNPCData.setNBT(replace);
}
customNPCData.updateClient = true;
}
}
@@ -1,29 +0,0 @@
package kamkeel.controllers.data;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.NBTTagCompound;
public interface IProfileData {
/**
* Do not use the tag: - Name, lastLoaded, ID
*
* @return The Save Tag utilized in the Profile
*/
public String getTagName();
/**
* @return NBTTagCompound of their Current Data for a given Entity Player
*/
public NBTTagCompound getCurrentNBT(EntityPlayer player);
/**
* Called immediately after setNBT() Replaces existing NBT
*/
public void save(EntityPlayer player);
/**
* Replaces their Current Data operation when changing Profiles
*/
public void setNBT(EntityPlayer player, NBTTagCompound replace);
}
@@ -1,57 +0,0 @@
package kamkeel.controllers.data;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.NBTTagCompound;
import java.util.HashMap;
import java.util.Set;
public class Profile {
public EntityPlayer player;
public int currentID;
public HashMap<Integer, Slot> slots = new HashMap<>();
public Profile(EntityPlayer player, NBTTagCompound compound){
this.player = player;
if(compound.hasKey("CurrentID")){
this.currentID = compound.getInteger("CurrentID");
} else {
this.currentID = 1;
}
if (compound.hasKey("Slots")) {
// Load Slots
NBTTagCompound slotsCompound = compound.getCompoundTag("Slots");
for (String key : (Set<String>) slotsCompound.func_150296_c()) {
int slotID = Integer.parseInt(key);
NBTTagCompound slotNBT = slotsCompound.getCompoundTag(key);
Slot slot = Slot.fromNBT(slotID, slotNBT);
slots.put(slotID, slot);
}
}
}
public NBTTagCompound writeToNBT() {
NBTTagCompound fullCompound = new NBTTagCompound();
if(this.player != null)
fullCompound.setString("Name", player.getCommandSenderName());
fullCompound.setInteger("CurrentID", currentID);
if(!slots.isEmpty()){
NBTTagCompound slotsCompound = new NBTTagCompound();
for (HashMap.Entry<Integer, Slot> entry : slots.entrySet()) {
int id = entry.getKey();
Slot slot = entry.getValue();
slot.setId(id);
NBTTagCompound slotTag = slot.toNBT();
slotsCompound.setTag(String.valueOf(id), slotTag);
}
fullCompound.setTag("Slots", slotsCompound);
}
return fullCompound;
}
}
@@ -1,72 +0,0 @@
package kamkeel.controllers.data;
import kamkeel.controllers.ProfileController;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.NBTTagCompound;
public class Slot {
private int id;
private String name;
private long lastLoaded;
private NBTTagCompound compound;
public Slot(int id, String name) {
this.id = id;
this.name = name;
}
public Slot(int id, String name, NBTTagCompound compound, long last) {
this.id = id;
this.name = name;
this.compound = compound;
this.lastLoaded = last;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public long getLastLoaded() {
return lastLoaded;
}
public void setLastLoaded(long lastLoaded) {
this.lastLoaded = lastLoaded;
}
public NBTTagCompound getCompound() {
return compound;
}
public void setCompound(NBTTagCompound compound) {
this.compound = compound;
}
public NBTTagCompound toNBT() {
NBTTagCompound slotNBT = new NBTTagCompound();
slotNBT.setString("Name", name);
slotNBT.setLong("LastLoaded", lastLoaded);
slotNBT.setTag("Data", compound);
return slotNBT;
}
public static Slot fromNBT(int id, NBTTagCompound slotNBT) {
String name = slotNBT.getString("Name");
long lastLoaded = slotNBT.getLong("LastLoaded");
NBTTagCompound compound = slotNBT.getCompoundTag("Data");
return new Slot(id, name, compound, lastLoaded);
}
}
@@ -1,39 +0,0 @@
package kamkeel.network;
import kamkeel.network.enums.EnumPacketType;
import java.util.Hashtable;
import java.util.Map;
public class PacketChannel {
private String channelName;
private EnumPacketType channelType;
public Map<Integer, AbstractPacket> packets = new Hashtable<>();
public PacketChannel(String channelName, EnumPacketType channelType) {
this.channelName = channelName;
this.channelType = channelType;
}
public String getChannelName() {
return channelName;
}
public void setChannelName(String channelName) {
this.channelName = channelName;
}
public EnumPacketType getChannelType() {
return channelType;
}
public void setChannelType(EnumPacketType channelType) {
this.channelType = channelType;
}
public void registerPacket(Enum ord, AbstractPacket packet) {
this.packets.put(ord.ordinal(), packet);
}
}
@@ -1,76 +0,0 @@
package kamkeel.network;
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import cpw.mods.fml.common.network.FMLEventChannel;
import cpw.mods.fml.common.network.FMLNetworkEvent;
import cpw.mods.fml.common.network.NetworkRegistry;
import cpw.mods.fml.common.network.internal.FMLProxyPacket;
import cpw.mods.fml.relauncher.Side;
import io.netty.buffer.ByteBuf;
import kamkeel.network.enums.EnumPacketType;
import kamkeel.util.ByteBufUtils;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.network.NetHandlerPlayServer;
import noppes.npcs.CustomNpcs;
import java.util.*;
public final class PacketHandler {
public static PacketHandler Instance;
public Map<EnumPacketType, FMLEventChannel> channels = new Hashtable<>();
public final static PacketChannel INFO_PACKET = new PacketChannel("CNPC+|Info", EnumPacketType.INFO);
public final static PacketChannel DATA_PACKET = new PacketChannel("CNPC+|Data", EnumPacketType.DATA);
public final static PacketChannel CLIENT_PACKET = new PacketChannel("CNPC+|Client", EnumPacketType.CLIENT);
public final static PacketChannel LARGE_PACKET = new PacketChannel("CNPC+|Large", EnumPacketType.LARGE);
public final static List<PacketChannel> packetChannels = new ArrayList<>();
public PacketHandler() {
// Register Channels
packetChannels.add(INFO_PACKET);
packetChannels.add(DATA_PACKET);
packetChannels.add(CLIENT_PACKET);
this.registerChannels();
// Register Info Packets
// Register Data Packets
// Register Client Packets
// Register Packets
// map.put(PingPacket.packetName, new PingPacket());
}
public void registerChannels() {
FMLEventChannel eventChannel;
for (PacketChannel channel : packetChannels) {
eventChannel = NetworkRegistry.INSTANCE.newEventDrivenChannel(channel.getChannelName());
eventChannel.register(this);
channels.put(channel.getChannelType(), eventChannel);
}
}
public PacketChannel getPacketChannel(EnumPacketType type){
PacketChannel packetChannel;
switch (type){
case DATA:
packetChannel = DATA_PACKET;
break;
case INFO:
packetChannel = INFO_PACKET;
break;
case LARGE:
packetChannel = LARGE_PACKET;
break;
default:
packetChannel = CLIENT_PACKET;
break;
}
return packetChannel;
}
}
@@ -1,4 +0,0 @@
package kamkeel.network.enums;
public enum EnumClientPacket {
}
@@ -1,4 +0,0 @@
package kamkeel.network.enums;
public enum EnumDataPacket {
}
@@ -1,5 +0,0 @@
package kamkeel.network.enums;
public enum EnumInfoPacket {
LOGIN,
}
@@ -1,5 +0,0 @@
package kamkeel.network.enums;
public enum EnumPacketType {
INFO, DATA, CLIENT, LARGE
}
@@ -1,40 +0,0 @@
package kamkeel.network.packets;
import io.netty.buffer.ByteBuf;
import kamkeel.network.AbstractPacket;
import kamkeel.network.PacketChannel;
import kamkeel.network.PacketHandler;
import kamkeel.network.enums.EnumInfoPacket;
import kamkeel.util.ByteBufUtils;
import net.minecraft.entity.player.EntityPlayer;
import java.io.IOException;
public final class LoginPacket extends AbstractPacket {
public static final String packetName = "CNPC+|LoginPacket";
public LoginPacket() {}
@Override
public Enum getType() {
return EnumInfoPacket.LOGIN;
}
@Override
public PacketChannel getChannel() {
return PacketHandler.INFO_PACKET;
}
@Override
public void sendData(ByteBuf out) throws IOException {
// ByteBufUtils.writeUTF8String(out, this.data.player.getCommandSenderName());
// ByteBufUtils.writeNBT(out,this.data.saveFromNBT(new NBTTagCompound()));
}
@Override
public void receiveData(ByteBuf in, EntityPlayer player) throws IOException {
String playerName = ByteBufUtils.readUTF8String(in);
}
}
@@ -0,0 +1,72 @@
package kamkeel.npcs;
import kamkeel.npcs.controllers.AttributeController;
import kamkeel.npcs.controllers.data.attribute.AttributeDefinition;
import kamkeel.npcs.controllers.data.attribute.AttributeValueType;
import kamkeel.npcs.controllers.data.attribute.requirement.types.QuestActiveRequirement;
import kamkeel.npcs.controllers.data.attribute.requirement.types.QuestCompletedRequirement;
import kamkeel.npcs.controllers.data.attribute.requirement.RequirementCheckerRegistry;
/**
* ModAttributes registers the core attributes (both non–magic and magic–based).
*/
public class CustomAttributes {
public static final String HEALTH_KEY = "health";
public static final String MAIN_ATTACK_KEY = "main_attack";
public static final String MAIN_ATTACK_BOOST_KEY = "main_attack_boost";
public static final String NEUTRAL_KEY = "neutral";
public static final String NEUTRAL_BOOST_KEY = "neutral_boost";
public static final String CRITICAL_DAMAGE_KEY = "critical_damage";
public static final String CRITICAL_CHANCE_KEY = "critical_chance";
public static final String MAGIC_DAMAGE_KEY = "magic_damage";
public static final String MAGIC_BOOST_KEY = "magic_boost";
public static final String MAGIC_DEFENSE_KEY = "magic_defense";
public static final String MAGIC_RESISTANCE_KEY = "magic_resistance";
public static AttributeDefinition MAIN_ATTACK;
public static AttributeDefinition MAIN_BOOST;
public static AttributeDefinition NEUTRAL_ATTACK;
public static AttributeDefinition NEUTRAL_BOOST;
public static AttributeDefinition HEALTH;
public static AttributeDefinition CRITICAL_CHANCE;
public static AttributeDefinition CRITICAL_DAMAGE;
public static AttributeDefinition MAGIC_DAMAGE;
public static AttributeDefinition MAGIC_BOOST;
public static AttributeDefinition MAGIC_DEFENSE;
public static AttributeDefinition MAGIC_RESISTANCE;
public CustomAttributes(){
HEALTH = AttributeController.registerAttribute(HEALTH_KEY, "Health", 'c', AttributeValueType.FLAT, AttributeDefinition.AttributeSection.BASE);
MAIN_ATTACK = AttributeController.registerAttribute(MAIN_ATTACK_KEY, "Main Attack Damage", '4', AttributeValueType.FLAT, AttributeDefinition.AttributeSection.BASE);
MAIN_BOOST = AttributeController.registerAttribute(MAIN_ATTACK_BOOST_KEY, "Main Attack Damage", '4', AttributeValueType.PERCENT, AttributeDefinition.AttributeSection.MODIFIER);
NEUTRAL_ATTACK = AttributeController.registerAttribute(NEUTRAL_KEY, "Neutral Damage", '6', AttributeValueType.FLAT, AttributeDefinition.AttributeSection.BASE);
NEUTRAL_BOOST = AttributeController.registerAttribute(NEUTRAL_BOOST_KEY, "Neutral Damage", '6', AttributeValueType.PERCENT, AttributeDefinition.AttributeSection.MODIFIER);
CRITICAL_CHANCE = AttributeController.registerAttribute(CRITICAL_CHANCE_KEY, "Critical Chance", '6', AttributeValueType.PERCENT, AttributeDefinition.AttributeSection.INFO);
CRITICAL_DAMAGE = AttributeController.registerAttribute(CRITICAL_DAMAGE_KEY, "Critical Damage", '6', AttributeValueType.FLAT, AttributeDefinition.AttributeSection.INFO);
MAGIC_DAMAGE = AttributeController.registerAttribute(MAGIC_DAMAGE_KEY, "Magic Damage", '3', AttributeValueType.MAGIC, AttributeDefinition.AttributeSection.BASE);
MAGIC_BOOST = AttributeController.registerAttribute(MAGIC_BOOST_KEY, "Magic Damage", '3', AttributeValueType.MAGIC, AttributeDefinition.AttributeSection.MODIFIER);
MAGIC_DEFENSE = AttributeController.registerAttribute(MAGIC_DEFENSE_KEY, "Magic Defense", 'b', AttributeValueType.MAGIC, AttributeDefinition.AttributeSection.BASE);
MAGIC_RESISTANCE = AttributeController.registerAttribute(MAGIC_RESISTANCE_KEY, "Magic Resistance", 'b', AttributeValueType.MAGIC, AttributeDefinition.AttributeSection.MODIFIER);
// TODO: Attributes
// Durability Attribute
// Unique Name Attribute
// Requirement
RequirementCheckerRegistry.registerChecker(new QuestCompletedRequirement());
RequirementCheckerRegistry.registerChecker(new QuestActiveRequirement());
// TODO: Requirements
// Player Requirement : Soulbound UUID
// Profile Requirement : Slot Number
}
}
@@ -1,7 +1,7 @@
package kamkeel.addon;
package kamkeel.npcs.addon;
import kamkeel.addon.client.DBCClient;
import kamkeel.addon.client.GeckoAddonClient;
import kamkeel.npcs.addon.client.DBCClient;
import kamkeel.npcs.addon.client.GeckoAddonClient;
public class AddonManager {
public static AddonManager Instance;
@@ -1,6 +1,6 @@
package kamkeel.addon;
package kamkeel.npcs.addon;
import io.netty.buffer.ByteBuf;
import cpw.mods.fml.common.Loader;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
@@ -22,6 +22,10 @@ public class DBCAddon {
instance = this;
}
public static boolean IsAvailable() {
return Loader.isModLoaded("npcdbc");
}
public void dbcCopyData(EntityLivingBase copied, EntityLivingBase entity){}
// AI / STATS
@@ -1,4 +1,4 @@
package kamkeel.addon;
package kamkeel.npcs.addon;
import net.minecraft.entity.EntityLivingBase;
@@ -17,4 +17,4 @@ public class GeckoAddon {
public void geckoCopyData(EntityLivingBase copied, EntityLivingBase entity){}
}
}
@@ -1,15 +1,9 @@
package kamkeel.addon.client;
package kamkeel.npcs.addon.client;
import io.netty.buffer.ByteBuf;
import net.minecraft.client.model.ModelBase;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import noppes.npcs.client.gui.mainmenu.GuiNpcStats;
import noppes.npcs.client.gui.model.GuiCreationScreen;
import noppes.npcs.client.gui.player.inventory.GuiCNPCInventory;
import noppes.npcs.client.gui.util.GuiNPCInterface2;
import noppes.npcs.client.gui.util.GuiNpcButton;
import noppes.npcs.client.model.ModelMPM;
import noppes.npcs.entity.EntityNPCInterface;
public class DBCClient {
@@ -39,7 +33,4 @@ public class DBCClient {
public GuiNPCInterface2 manageCustomForms(EntityNPCInterface npcInterface){ return null; }
// Manage Custom Forms
public GuiNPCInterface2 manageCustomAuras(EntityNPCInterface npcInterface){ return null; }
// Inventory GUI
public GuiCNPCInventory inventoryGUI(){ return null; }
}
@@ -1,4 +1,4 @@
package kamkeel.addon.client;
package kamkeel.npcs.addon.client;
import net.minecraft.client.model.ModelBase;
import net.minecraft.entity.EntityLivingBase;
@@ -1,4 +1,4 @@
package kamkeel.command;
package kamkeel.npcs.command;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender;
@@ -9,6 +9,9 @@ import noppes.npcs.controllers.data.PlayerData;
import java.util.List;
import static kamkeel.npcs.util.ColorUtil.sendError;
import static kamkeel.npcs.util.ColorUtil.sendResult;
public class AnimationCommand extends CommandKamkeelBase {
@Override
@@ -0,0 +1,245 @@
package kamkeel.npcs.command;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender;
import net.minecraft.item.ItemStack;
import net.minecraft.entity.player.EntityPlayer;
import kamkeel.npcs.controllers.AttributeController;
import kamkeel.npcs.controllers.data.attribute.AttributeDefinition;
import kamkeel.npcs.controllers.data.attribute.AttributeValueType;
import kamkeel.npcs.util.AttributeItemUtil;
import noppes.npcs.controllers.MagicController;
import static kamkeel.npcs.util.ColorUtil.sendError;
import static kamkeel.npcs.util.ColorUtil.sendResult;
public class AttributeCommand extends CommandKamkeelBase {
@Override
public String getCommandName() {
return "attribute";
}
@Override
public String getDescription() {
return "Manage attributes on your held item";
}
@SubCommand(
name = "list",
usage = "[page]",
desc = "Lists all available attributes"
)
public void list(ICommandSender sender, String[] args) throws CommandException {
// Get all registered attributes.
List<AttributeDefinition> defs = new ArrayList<AttributeDefinition>(AttributeController.getAllAttributes());
if(defs.isEmpty()){
sendError(sender, "No attributes found.");
return;
}
// Sort attributes by display name.
Collections.sort(defs, new Comparator<AttributeDefinition>() {
@Override
public int compare(AttributeDefinition a, AttributeDefinition b) {
return a.getKey().compareToIgnoreCase(b.getKey());
}
});
// Determine which page to show.
int page = 1;
if(args.length > 0) {
try {
page = Integer.parseInt(args[0]);
} catch(NumberFormatException e) {
// If parsing fails, default to page 1.
}
}
int perPage = 10;
int total = defs.size();
int totalPages = (int)Math.ceil(total / (double) perPage);
if(page < 1) page = 1;
if(page > totalPages) page = totalPages;
int startIndex = (page - 1) * perPage;
int endIndex = Math.min(startIndex + perPage, total);
sendResult(sender, "--------------------");
sendResult(sender, "Attributes (Page " + page + "/" + totalPages + "):");
for (int i = startIndex; i < endIndex; i++) {
AttributeDefinition def = defs.get(i);
// First line: numbered display name.
sendResult(sender, (i + 1) + ". " + def.getDisplayName());
// Second line: key and value type.
sendResult(sender, " - " + def.getKey() + ", " + def.getValueType());
}
sendResult(sender, "--------------------");
}
@SubCommand(
name = "apply",
usage = "<attribute> <value> [magicID]",
desc = "Applies an attribute to your held item. For magic attributes, provide a magicID."
)
public void apply(ICommandSender sender, String[] args) throws CommandException {
if(!(sender instanceof EntityPlayer)){
sendError(sender, "Only players can use this command.");
return;
}
EntityPlayer player = (EntityPlayer)sender;
ItemStack held = player.getHeldItem();
if(held == null){
sendError(sender, "You are not holding an item.");
return;
}
String attrKey = args[0];
AttributeDefinition def = AttributeController.getAttribute(attrKey);
if(def == null){
sendError(sender, "Unknown attribute: " + attrKey);
return;
}
// Check if this is a magic attribute.
if(def.getValueType() == AttributeValueType.MAGIC) {
if(args.length < 3){
sendError(sender, "Usage for magic attribute: apply <attribute> <value> <magicID>");
return;
}
int magicId;
float value;
try {
value = Float.parseFloat(args[1]);
magicId = Integer.parseInt(args[2]);
} catch(NumberFormatException e) {
sendError(sender, "Invalid number format for magicID or value.");
return;
}
if(MagicController.getInstance().getMagic(magicId) == null){
sendError(sender, "No Magic Found for Magic ID %d", magicId);
return;
}
AttributeItemUtil.writeMagicAttribute(held, attrKey, magicId, value);
sendResult(sender, "Applied magic attribute " + attrKey + " with magicID " + magicId + " and value " + value + " to held item.");
} else {
if(args.length < 2){
sendError(sender, "Usage: <attribute> <value>");
return;
}
float value;
try {
value = Float.parseFloat(args[1]);
} catch(NumberFormatException e) {
sendError(sender, "Invalid number format for value.");
return;
}
AttributeItemUtil.applyAttribute(held, attrKey, value);
sendResult(sender, "Applied attribute " + attrKey + " with value " + value + " to held item.");
}
}
@SubCommand(
name = "remove",
usage = "<attribute> [magicID)",
desc = "Removes an attribute from your held item. For magic attributes, provide a magicID."
)
public void remove(ICommandSender sender, String[] args) throws CommandException {
if(!(sender instanceof EntityPlayer)){
sendError(sender, "Only players can use this command.");
return;
}
EntityPlayer player = (EntityPlayer)sender;
ItemStack held = player.getHeldItem();
if(held == null){
sendError(sender, "You are not holding an item.");
return;
}
String attrKey = args[0];
AttributeDefinition def = AttributeController.getAttribute(attrKey);
if(def == null){
sendError(sender, "Unknown attribute: " + attrKey);
return;
}
if(def.getValueType() == AttributeValueType.MAGIC) {
if(args.length < 2){
sendError(sender, "Usage for magic attribute: remove <attribute> <magicID>");
return;
}
int magicId;
try {
magicId = Integer.parseInt(args[1]);
} catch(NumberFormatException e) {
sendError(sender, "Invalid magicID format.");
return;
}
if(MagicController.getInstance().getMagic(magicId) == null){
sendError(sender, "No Magic Found for Magic ID %d", magicId);
return;
}
AttributeItemUtil.removeMagicAttribute(held, attrKey, magicId);
sendResult(sender, "Removed magic attribute " + attrKey + " (magicID " + magicId + ") from held item.");
} else {
AttributeItemUtil.removeAttribute(held, attrKey);
sendResult(sender, "Removed attribute " + attrKey + " from held item.");
}
}
@SubCommand(
name = "requirement",
usage = "<apply|remove> <requirement> [value]",
desc = "Apply or remove a requirement from your held item."
)
public void requirement(ICommandSender sender, String[] args) throws CommandException {
if (!(sender instanceof EntityPlayer)) {
sendError(sender, "Only players can use this command.");
return;
}
EntityPlayer player = (EntityPlayer) sender;
ItemStack held = player.getHeldItem();
if (held == null) {
sendError(sender, "You are not holding an item.");
return;
}
if (args.length < 2) {
sendError(sender, "Usage: requirement <apply|remove> <requirementKey> [value]");
return;
}
String action = args[0];
String reqKey = args[1];
if (action.equalsIgnoreCase("apply")) {
if (args.length < 3) {
sendError(sender, "Usage: requirement apply <requirementKey> <value>");
return;
}
String valueStr = args[2];
Object value;
try {
value = Integer.parseInt(valueStr);
} catch (NumberFormatException e1) {
try {
value = Float.parseFloat(valueStr);
} catch (NumberFormatException e2) {
value = valueStr;
}
}
AttributeItemUtil.applyRequirement(held, reqKey, value);
sendResult(sender, "Applied requirement " + reqKey + " with value " + value + " to held item.");
} else if (action.equalsIgnoreCase("remove")) {
AttributeItemUtil.removeRequirement(held, reqKey);
sendResult(sender, "Removed requirement " + reqKey + " from held item.");
} else {
sendError(sender, "Invalid action. Use apply or remove.");
}
}
}
@@ -1,8 +1,7 @@
package kamkeel.command;
package kamkeel.npcs.command;
import foxz.utils.Utils;
import net.minecraft.block.Block;
import net.minecraft.command.CommandBase;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender;
import net.minecraft.entity.Entity;
@@ -18,6 +17,8 @@ import noppes.npcs.entity.EntityNPCInterface;
import java.util.List;
import static kamkeel.npcs.util.ColorUtil.*;
public class CloneCommand extends CommandKamkeelBase {
@Override
@@ -180,9 +181,9 @@ public class CloneCommand extends CommandKamkeelBase {
return;
}
try{
posX = CommandBase.func_110666_a(sender, posX, par[0]);
posY = CommandBase.func_110665_a(sender, posY, par[1].trim(), 0, 0);
posZ = CommandBase.func_110666_a(sender, posZ, par[2]);
posX = func_110666_a(sender, posX, par[0]);
posY = func_110665_a(sender, posY, par[1].trim(), 0, 0);
posZ = func_110666_a(sender, posZ, par[2]);
} catch(NumberFormatException ex){
sendError(sender, "Location should be in numbers");
return;
@@ -204,7 +205,7 @@ public class CloneCommand extends CommandKamkeelBase {
entity.setPosition(posX + 0.5, posY + 1, posZ + 0.5);
if(entity instanceof EntityNPCInterface){
EntityNPCInterface npc = (EntityNPCInterface) entity;
npc.ai.startPos = new int[]{MathHelper.floor_double(posX), MathHelper.floor_double(posY), MathHelper.floor_double(posZ)};
npc.ais.startPos = new int[]{MathHelper.floor_double(posX), MathHelper.floor_double(posY), MathHelper.floor_double(posZ)};
if(newname != null && !newname.isEmpty())
npc.display.name = newname.replaceAll("%", " "); // like name, newname must use % in place of space to keep a logical way
}
@@ -272,9 +273,9 @@ public class CloneCommand extends CommandKamkeelBase {
return;
}
try{
posX = CommandBase.func_110666_a(sender, posX, par[0]);
posY = CommandBase.func_110665_a(sender, posY, par[1].trim(), 0, 0);
posZ = CommandBase.func_110666_a(sender, posZ, par[2]);
posX = func_110666_a(sender, posX, par[0]);
posY = func_110665_a(sender, posY, par[1].trim(), 0, 0);
posZ = func_110666_a(sender, posZ, par[2]);
} catch(NumberFormatException ex){
sendError(sender, "Location should be in numbers");
return;
@@ -310,7 +311,7 @@ public class CloneCommand extends CommandKamkeelBase {
entity.setPosition(posX + 0.5 + x, yy + 1, posZ + 0.5 + z);
if(entity instanceof EntityNPCInterface){
EntityNPCInterface npc = (EntityNPCInterface) entity;
npc.ai.startPos = new int[]{xx, yy, zz};
npc.ais.startPos = new int[]{xx, yy, zz};
if(newname != null && !newname.isEmpty())
npc.display.name = newname.replaceAll("%", " "); // like name, newname must use % in place of space to keep a logical way
}
@@ -1,4 +1,4 @@
package kamkeel.command;
package kamkeel.npcs.command;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender;
@@ -10,6 +10,9 @@ import noppes.npcs.api.IWorld;
import noppes.npcs.scripted.NpcAPI;
import noppes.npcs.scripted.event.CustomNPCsEvent;
import static kamkeel.npcs.util.ColorUtil.sendError;
import static kamkeel.npcs.util.ColorUtil.sendMessage;
public class CommandCommand extends CommandKamkeelBase {
@Override
@@ -0,0 +1,173 @@
package kamkeel.npcs.command;
import kamkeel.npcs.controllers.data.attribute.requirement.RequirementCheckerRegistry;
import net.minecraft.command.CommandBase;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.server.MinecraftServer;
import noppes.npcs.CustomNpcsPermissions;
import kamkeel.npcs.controllers.AttributeController;
import kamkeel.npcs.controllers.data.attribute.AttributeDefinition;
import noppes.npcs.config.ConfigMain;
import noppes.npcs.scripted.CustomNPCsException;
import java.lang.reflect.Method;
import java.util.*;
import static kamkeel.npcs.command.EffectCommand.getSortedEffectNames;
public class CommandKamkeel extends CommandBase{
public Map<String, CommandKamkeelBase> map = new HashMap<String, CommandKamkeelBase>();
public HelpCommand help = new HelpCommand(this);
public String[] alias = {"kam"};
public CommandKamkeel(){
registerCommand(help);
registerCommand(new ScriptCommand());
registerCommand(new SlayCommand());
registerCommand(new QuestCommand());
registerCommand(new QuestCategoryCommand());
registerCommand(new DialogCommand());
registerCommand(new DialogCategoryCommand());
registerCommand(new FactionCommand());
registerCommand(new NpcCommand());
registerCommand(new CloneCommand());
registerCommand(new ConfigCommand());
registerCommand(new AnimationCommand());
registerCommand(new OverlayCommand());
registerCommand(new CommandCommand());
registerCommand(new EffectCommand());
if(ConfigMain.AttributesEnabled)
registerCommand(new AttributeCommand());
}
public void registerCommand(CommandKamkeelBase command){
String name = command.getCommandName().toLowerCase();
if(map.containsKey(name))
throw new CustomNPCsException("Already a subcommand with the name: " + name);
map.put(name, command);
}
@Override
public String getCommandName() {
return "kamkeel";
}
@Override
public List getCommandAliases()
{
return Arrays.asList(alias);
}
@Override
public String getCommandUsage(ICommandSender sender) {
return "Use as /kamkeel subcommand";
}
@Override
public void processCommand(ICommandSender sender, String[] args) throws CommandException {
if(args.length == 0){
help.processCommand(sender, args);
return;
}
CommandKamkeelBase command = getCommand(args);
if(command == null)
throw new CommandException("Unknown command " + args[0]);
args = Arrays.copyOfRange(args, 1, args.length);
if(command.subcommands.isEmpty() || !command.runSubCommands()){
if(!canSendCommand(sender, command))
throw new CommandException("You are not allowed to use this command: " + command);
command.canRun(sender, command.getUsage(), args);
command.processCommand(sender, args);
return;
}
if(args.length == 0){
help.processCommand(sender, new String[]{command.getCommandName()});
return;
}
command.processSubCommand(sender, args[0], Arrays.copyOfRange(args, 1, args.length));
}
@Override
public List addTabCompletionOptions(ICommandSender sender, String[] args){
if(args.length == 1)
return CommandBase.getListOfStringsMatchingLastWord(args, map.keySet().toArray(new String[map.size()]));
CommandKamkeelBase command = getCommand(args);
if(command == null)
return null;
if(args.length == 2 && command.runSubCommands())
return CommandBase.getListOfStringsMatchingLastWord(args, command.subcommands.keySet().toArray(new String[command.subcommands.keySet().size()]));
String[] useArgs = command.getUsage().split(" ");
if(command.runSubCommands()) {
Method m = command.subcommands.get(args[1].toLowerCase());
if(m != null) {
useArgs = m.getAnnotation(CommandKamkeelBase.SubCommand.class).usage().split(" ");
}
}
if(args.length <= useArgs.length + 2) {
if(args.length - 3 >= 0){
String usage = useArgs[args.length - 3];
if(usage.equals("<player>") || usage.equals("[player]")) {
return CommandBase.getListOfStringsMatchingLastWord(args, MinecraftServer.getServer().getAllUsernames());
}
else if(usage.equals("<attribute>")) {
List<String> keys = new ArrayList<>();
for (AttributeDefinition def : AttributeController.getAllAttributes()) {
keys.add(def.getKey());
}
return CommandBase.getListOfStringsMatchingLastWord(args, keys.toArray(new String[keys.size()]));
} else if (usage.equals("<requirement>")) {
List<String> keys = new ArrayList<>(RequirementCheckerRegistry.getAllKeys());
return CommandBase.getListOfStringsMatchingLastWord(args, keys.toArray(new String[keys.size()]));
} else if(usage.equals("<effectName>")){
List<String> keys = getSortedEffectNames();
return CommandBase.getListOfStringsMatchingLastWord(args, keys.toArray(new String[keys.size()]));
}
}
}
return command.addTabCompletionOptions(sender, Arrays.copyOfRange(args, 1, args.length));
}
public CommandKamkeelBase getCommand(String[] args){
if(args.length == 0)
return null;
return map.get(args[0].toLowerCase());
}
@Override
public int getRequiredPermissionLevel(){
return 2;
}
public static String getCommandPermission(String command){
return "cnpc.kamkeel." + command.toLowerCase();
}
public static String getUniversalPermission(){
return "cnpc.kamkeel.*";
}
public static boolean canSendCommand(ICommandSender sender, CommandKamkeelBase command){
if(sender.canCommandSenderUseCommand(command.getRequiredPermissionLevel(), getUniversalPermission())){
return true;
}
if(sender.canCommandSenderUseCommand(command.getRequiredPermissionLevel(), getCommandPermission(command.getCommandName()))){
return true;
}
if(sender instanceof EntityPlayer){
return CustomNpcsPermissions.hasCustomPermission((EntityPlayer) sender, getCommandPermission(command.getCommandName()));
}
return false;
}
}
@@ -1,10 +1,9 @@
package kamkeel.command;
package kamkeel.npcs.command;
import net.minecraft.command.CommandBase;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.ChatComponentTranslation;
import noppes.npcs.CustomNpcsPermissions;
import java.lang.annotation.ElementType;
@@ -55,18 +54,6 @@ public abstract class CommandKamkeelBase extends CommandBase{
return !subcommands.isEmpty();
}
protected static void sendMessage(ICommandSender sender, String message, Object... obs) {
sender.addChatMessage(new ChatComponentTranslation(message, obs));
}
protected static void sendResult(ICommandSender sender, String message, Object... obs) {
sender.addChatMessage(new ChatComponentTranslation("\u00A76[\u00A7eCNPC+\u00A76]\u00A77 " + message, obs));
}
protected static void sendError(ICommandSender sender, String message, Object... obs) {
sender.addChatMessage(new ChatComponentTranslation("\u00A76[\u00A7eCNPC+\u00A76]\u00A74 Error:\u00A7c " + message, obs));
}
@Retention(value = RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface SubCommand {
@@ -1,6 +1,9 @@
package kamkeel.command;
package kamkeel.npcs.command;
import foxz.utils.Market;
import kamkeel.npcs.network.PacketHandler;
import kamkeel.npcs.network.enums.EnumConfigOperation;
import kamkeel.npcs.network.packets.data.ConfigCommandPacket;
import net.minecraft.block.Block;
import net.minecraft.block.BlockIce;
import net.minecraft.block.BlockLeavesBase;
@@ -10,15 +13,16 @@ import net.minecraft.command.ICommandSender;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.util.ResourceLocation;
import noppes.npcs.CustomNpcs;
import noppes.npcs.Server;
import noppes.npcs.config.ConfigMain;
import noppes.npcs.constants.EnumPacketClient;
import noppes.npcs.controllers.ChunkController;
import noppes.npcs.controllers.PlayerDataController;
import java.util.Arrays;
import java.util.Set;
import static kamkeel.npcs.util.ColorUtil.sendError;
import static kamkeel.npcs.util.ColorUtil.sendResult;
public class ConfigCommand extends CommandKamkeelBase {
@@ -291,8 +295,7 @@ public class ConfigCommand extends CommandKamkeelBase {
for(int i = 0; i < args.length; i++){
font += " " + args[i];
}
Server.sendData((EntityPlayerMP)sender, EnumPacketClient.CONFIG, 0, font.trim(), size);
PacketHandler.Instance.sendToPlayer(new ConfigCommandPacket(EnumConfigOperation.FONT, font.trim(), size), (EntityPlayerMP)sender);
}
}
@@ -1,4 +1,4 @@
package kamkeel.command;
package kamkeel.npcs.command;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender;
@@ -11,6 +11,9 @@ import noppes.npcs.controllers.data.PlayerData;
import java.util.Collection;
import java.util.List;
import static kamkeel.npcs.util.ColorUtil.sendError;
import static kamkeel.npcs.util.ColorUtil.sendResult;
public class DialogCategoryCommand extends CommandKamkeelBase {
@Override
@@ -1,5 +1,6 @@
package kamkeel.command;
package kamkeel.npcs.command;
import kamkeel.npcs.controllers.SyncController;
import net.minecraft.command.CommandBase;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender;
@@ -10,7 +11,6 @@ import noppes.npcs.constants.EnumAvailabilityDialog;
import noppes.npcs.constants.EnumAvailabilityQuest;
import noppes.npcs.controllers.DialogController;
import noppes.npcs.controllers.PlayerDataController;
import noppes.npcs.controllers.SyncController;
import noppes.npcs.controllers.data.Availability;
import noppes.npcs.controllers.data.Dialog;
import noppes.npcs.controllers.data.DialogOption;
@@ -20,6 +20,9 @@ import noppes.npcs.entity.EntityDialogNpc;
import java.util.Collection;
import java.util.List;
import static kamkeel.npcs.util.ColorUtil.sendError;
import static kamkeel.npcs.util.ColorUtil.sendResult;
public class DialogCommand extends CommandKamkeelBase {
@Override
@@ -0,0 +1,345 @@
package kamkeel.npcs.command;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender;
import noppes.npcs.controllers.CustomEffectController;
import noppes.npcs.controllers.PlayerDataController;
import noppes.npcs.controllers.data.CustomEffect;
import noppes.npcs.controllers.data.PlayerData;
import noppes.npcs.scripted.event.PlayerEvent.EffectEvent.ExpirationType;
import java.util.*;
import static kamkeel.npcs.util.ColorUtil.sendError;
import static kamkeel.npcs.util.ColorUtil.sendResult;
public class EffectCommand extends CommandKamkeelBase {
@Override
public String getDescription() {
return "Custom Effect operations";
}
@Override
public String getCommandName() {
return "effect";
}
// List command with pagination
@SubCommand(desc = "Lists all Effects", usage = "[page]")
public void list(ICommandSender sender, String[] args) throws CommandException {
CustomEffectController controller = CustomEffectController.getInstance();
if (controller.indexMapper.isEmpty()) {
sendError(sender, "No effects found.");
return;
}
// Flatten effects into a list
List<EffectEntry> effectsList = new ArrayList<>();
for (Map.Entry<Integer, HashMap<Integer, CustomEffect>> entry : controller.indexMapper.entrySet()) {
int idx = entry.getKey();
Map<Integer, CustomEffect> effects = entry.getValue();
if (effects == null || effects.isEmpty())
continue;
for (Map.Entry<Integer, CustomEffect> effectEntry : effects.entrySet()) {
int id = effectEntry.getKey();
CustomEffect effect = effectEntry.getValue();
effectsList.add(new EffectEntry(idx, id, effect));
}
}
// Sort by index then by effect ID
Collections.sort(effectsList, Comparator.comparingInt((EffectEntry e) -> e.index)
.thenComparingInt(e -> e.id));
// Determine page number
int page = 1;
if (args.length > 0) {
try {
page = Integer.parseInt(args[0]);
} catch (NumberFormatException e) {
// default to page 1
}
}
int perPage = 10;
int total = effectsList.size();
int totalPages = (int) Math.ceil(total / (double) perPage);
if (page < 1) page = 1;
if (page > totalPages) page = totalPages;
int startIndex = (page - 1) * perPage;
int endIndex = Math.min(startIndex + perPage, total);
sendResult(sender, "--------------------");
sendResult(sender, "Effects (Page " + page + "/" + totalPages + "):");
for (int i = startIndex; i < endIndex; i++) {
EffectEntry entry = effectsList.get(i);
sendResult(sender, String.format("\u00a7b%s \u00a77(ID: %d, INDEX: %d)",
entry.effect.getName(),
entry.id,
entry.index));
}
sendResult(sender, "--------------------");
}
// Give effect by name.
// Usage: <player> <time> <effectName>
@SubCommand(desc = "Gives an effect to a player", usage = "<player> <time> <effectName>")
public void give(ICommandSender sender, String[] args) throws CommandException {
if (args.length < 3) {
sendError(sender, "Usage: <player> <time> <effectName>");
return;
}
String playername = args[0];
int time;
try {
time = Integer.parseInt(args[1]);
} catch (NumberFormatException e) {
sendError(sender, "Invalid time: " + args[1]);
return;
}
// Join all remaining arguments as the effect name.
StringBuilder sb = new StringBuilder();
for (int i = 2; i < args.length; i++) {
sb.append(args[i]).append(i < args.length - 1 ? " " : "");
}
String effectName = sb.toString();
List<EffectEntry> matches = findEffectsByName(effectName);
if (matches.isEmpty()) {
sendError(sender, "Unknown effect: " + effectName);
return;
}
if (matches.size() > 1) {
StringBuilder ambig = new StringBuilder();
ambig.append("Ambiguous effect name '").append(effectName).append("'. Multiple matches: ");
for (EffectEntry match : matches) {
ambig.append(match.effect.getName())
.append(" (ID: ").append(match.id)
.append(", INDEX: ").append(match.index)
.append("), ");
}
sendError(sender, ambig.substring(0, ambig.length() - 2));
return;
}
EffectEntry match = matches.get(0);
List<PlayerData> players = PlayerDataController.Instance.getPlayersData(sender, playername);
if (players.isEmpty()) {
sendError(sender, "Unknown player: " + playername);
return;
}
for (PlayerData pdata : players) {
CustomEffectController.getInstance().applyEffect(pdata.player, match.id, time, (byte) 1, match.index);
sendResult(sender, String.format("%s §agiven to §7'§b%s§7'", match.effect.getName(), pdata.playername));
if (sender != pdata.player) {
sendResult(pdata.player, String.format("Effect §7%s §aadded.", match.effect.getName()));
}
}
}
// Remove effect by name.
// Usage: <player> <effectName>
@SubCommand(desc = "Removes an effect from a player", usage = "<player> <effectName>")
public void remove(ICommandSender sender, String[] args) throws CommandException {
if (args.length < 2) {
sendError(sender, "Usage: <player> <effectName>");
return;
}
String playername = args[0];
// Join all remaining arguments as the effect name.
StringBuilder sb = new StringBuilder();
for (int i = 1; i < args.length; i++) {
sb.append(args[i]).append(i < args.length - 1 ? " " : "");
}
String effectName = sb.toString();
List<EffectEntry> matches = findEffectsByName(effectName);
if (matches.isEmpty()) {
sendError(sender, "Unknown effect: " + effectName);
return;
}
if (matches.size() > 1) {
StringBuilder ambig = new StringBuilder();
ambig.append("Ambiguous effect name '").append(effectName).append("'. Multiple matches: ");
for (EffectEntry match : matches) {
ambig.append(match.effect.getName())
.append(" (ID: ").append(match.id)
.append(", INDEX: ").append(match.index)
.append("), ");
}
sendError(sender, ambig.substring(0, ambig.length() - 2));
return;
}
EffectEntry match = matches.get(0);
List<PlayerData> players = PlayerDataController.Instance.getPlayersData(sender, playername);
if (players.isEmpty()) {
sendError(sender, "Unknown player: " + playername);
return;
}
for (PlayerData pdata : players) {
CustomEffectController.getInstance().removeEffect(pdata.player, match.id, match.index, ExpirationType.REMOVED);
sendResult(sender, String.format("Effect %s removed from %s", match.effect.getName(), pdata.playername));
}
}
// Give effect by ID.
// Usage: <player> <time> <effectId> [index]
@SubCommand(desc = "Gives an effect to a player by ID", usage = "<player> <time> <effectId> [index]")
public void giveId(ICommandSender sender, String[] args) throws CommandException {
if (args.length < 3) {
sendError(sender, "Usage: <player> <time> <effectId> [index]");
return;
}
String playername = args[0];
int time;
try {
time = Integer.parseInt(args[1]);
} catch (NumberFormatException e) {
sendError(sender, "Invalid time: " + args[1]);
return;
}
int effectId;
int index = 0;
try {
effectId = Integer.parseInt(args[2]);
} catch (NumberFormatException e) {
sendError(sender, "Invalid effect ID: " + args[2]);
return;
}
if (args.length > 3) {
try {
index = Integer.parseInt(args[3]);
} catch (NumberFormatException e) {
index = 0;
}
}
List<PlayerData> players = PlayerDataController.Instance.getPlayersData(sender, playername);
if (players.isEmpty()) {
sendError(sender, "Unknown player: " + playername);
return;
}
CustomEffect effect = CustomEffectController.getInstance().get(effectId, index);
if (effect == null) {
sendError(sender, "Unknown effect with ID: " + effectId + " and index " + index);
return;
}
for (PlayerData pdata : players) {
CustomEffectController.getInstance().applyEffect(pdata.player, effectId, time, (byte) 1, index);
sendResult(sender, String.format("Effect %d given to %s", effectId, pdata.playername));
}
}
// Remove effect by ID.
// Usage: <player> <effectId> [index]
@SubCommand(desc = "Removes an effect from a player by ID", usage = "<player> <effectId> [index]")
public void removeId(ICommandSender sender, String[] args) throws CommandException {
if (args.length < 2) {
sendError(sender, "Usage: <player> <effectId> [index]");
return;
}
String playername = args[0];
int effectId;
int index = 0;
try {
effectId = Integer.parseInt(args[1]);
} catch (NumberFormatException e) {
sendError(sender, "Invalid effect ID: " + args[1]);
return;
}
if (args.length > 2) {
try {
index = Integer.parseInt(args[2]);
} catch (NumberFormatException e) {
index = 0;
}
}
List<PlayerData> players = PlayerDataController.Instance.getPlayersData(sender, playername);
if (players.isEmpty()) {
sendError(sender, "Unknown player: " + playername);
return;
}
CustomEffect effect = CustomEffectController.getInstance().get(effectId, index);
if (effect == null) {
sendError(sender, "Unknown effect with ID: " + effectId + " and index " + index);
return;
}
for (PlayerData pdata : players) {
CustomEffectController.getInstance().removeEffect(pdata.player, effectId, index, ExpirationType.REMOVED);
sendResult(sender, String.format("Effect %d removed from %s", effectId, pdata.playername));
}
}
private static class EffectEntry {
int index;
int id;
CustomEffect effect;
public EffectEntry(int index, int id, CustomEffect effect) {
this.index = index;
this.id = id;
this.effect = effect;
}
}
// Helper method to find effects by name.
private List<EffectEntry> findEffectsByName(String name) {
List<EffectEntry> matches = new ArrayList<>();
CustomEffectController controller = CustomEffectController.getInstance();
for (Map.Entry<Integer, HashMap<Integer, CustomEffect>> entry : controller.indexMapper.entrySet()) {
int idx = entry.getKey();
Map<Integer, CustomEffect> effects = entry.getValue();
if (effects == null) continue;
for (Map.Entry<Integer, CustomEffect> effectEntry : effects.entrySet()) {
int id = effectEntry.getKey();
CustomEffect effect = effectEntry.getValue();
if (effect.getName().equalsIgnoreCase(name)) {
List<EffectEntry> exact = new ArrayList<>();
exact.add(new EffectEntry(idx, id, effect));
return exact;
} else if (effect.getName().toLowerCase().contains(name.toLowerCase())) {
matches.add(new EffectEntry(idx, id, effect));
}
}
}
return matches;
}
public static List<String> getSortedEffectNames() {
List<EffectEntry> entries = new ArrayList<>();
CustomEffectController controller = CustomEffectController.getInstance();
for (Map.Entry<Integer, HashMap<Integer, CustomEffect>> indexEntry : controller.indexMapper.entrySet()) {
int index = indexEntry.getKey();
Map<Integer, CustomEffect> effects = indexEntry.getValue();
if (effects != null) {
for (Map.Entry<Integer, CustomEffect> effectEntry : effects.entrySet()) {
int id = effectEntry.getKey();
CustomEffect effect = effectEntry.getValue();
entries.add(new EffectEntry(index, id, effect));
}
}
}
// Sort entries by index then by effect ID.
entries.sort(Comparator.comparingInt((EffectEntry e) -> e.index)
.thenComparingInt(e -> e.id));
List<String> effectNames = new ArrayList<>();
for (EffectEntry entry : entries) {
effectNames.add(entry.effect.getName());
}
return effectNames;
}
}
@@ -1,6 +1,5 @@
package kamkeel.command;
package kamkeel.npcs.command;
import net.minecraft.command.CommandBase;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender;
import noppes.npcs.controllers.FactionController;
@@ -12,6 +11,9 @@ import noppes.npcs.controllers.data.PlayerFactionData;
import java.util.Arrays;
import java.util.List;
import static kamkeel.npcs.util.ColorUtil.sendError;
import static kamkeel.npcs.util.ColorUtil.sendResult;
public class FactionCommand extends CommandKamkeelBase {
public Faction selectedFaction;
@@ -153,7 +155,7 @@ public class FactionCommand extends CommandKamkeelBase {
@Override
public List addTabCompletionOptions(ICommandSender par1, String[] args) {
if(args.length == 3){
return CommandBase.getListOfStringsMatchingLastWord(args, new String[]{"add", "subtract", "set", "reset", "drop", "create"});
return getListOfStringsMatchingLastWord(args, new String[]{"add", "subtract", "set", "reset", "drop", "create"});
}
return null;
}
@@ -1,4 +1,4 @@
package kamkeel.command;
package kamkeel.npcs.command;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender;
@@ -7,6 +7,9 @@ import net.minecraft.util.ChatComponentTranslation;
import java.lang.reflect.Method;
import java.util.Map.Entry;
import static kamkeel.npcs.util.ColorUtil.sendError;
import static kamkeel.npcs.util.ColorUtil.sendMessage;
public class HelpCommand extends CommandKamkeelBase{
private CommandKamkeel parent;
@@ -42,7 +45,7 @@ public class HelpCommand extends CommandKamkeelBase{
}
if(command.subcommands.isEmpty()){
sender.addChatMessage(new ChatComponentTranslation(command.getCommandUsage(sender)));
sendMessage(sender, (command.getCommandUsage(sender)));
return;
}
@@ -54,17 +57,17 @@ public class HelpCommand extends CommandKamkeelBase{
sendMessage(sender, "\u00A78------ \u00A7a" + command.getCommandName().toUpperCase() + " SubCommands \u00A78------");
sendMessage(sender, "\u00A77Usage: \u00A76" + command.getUsage());
for(Entry<String, Method> entry : command.subcommands.entrySet()){
sender.addChatMessage(new ChatComponentTranslation("\u00A77> " + "\u00A7e" + entry.getKey() + "\u00A78: \u00A77" + entry.getValue().getAnnotation(SubCommand.class).desc()));
sendMessage(sender, ("\u00A77> " + "\u00A7e" + entry.getKey() + "\u00A78: \u00A77" + entry.getValue().getAnnotation(SubCommand.class).desc()));
}
sender.addChatMessage(new ChatComponentTranslation("\u00A78Permission:\u00A77 " + CommandKamkeel.getCommandPermission(command.getCommandName())));
sendMessage(sender, ("\u00A78Permission:\u00A77 " + CommandKamkeel.getCommandPermission(command.getCommandName())));
}
else{
sendMessage(sender, "\u00A78------ \u00A7b" + command.getCommandName().toUpperCase() + "." + args[1].toUpperCase() + " Command \u00A78------");
SubCommand sc = m.getAnnotation(SubCommand.class);
sender.addChatMessage(new ChatComponentTranslation("\u00A77" + sc.desc()));
sendMessage(sender, ("\u00A77" + sc.desc()));
if(!sc.usage().isEmpty())
sender.addChatMessage(new ChatComponentTranslation("\u00A77Usage: \u00A76" + sc.usage()));
sender.addChatMessage(new ChatComponentTranslation("\u00A78Permission:\u00A77 " + getSubCommandPermission(args[1])));
sendMessage(sender, ("\u00A77Usage: \u00A76" + sc.usage()));
sendMessage(sender, ("\u00A78Permission:\u00A77 " + getSubCommandPermission(args[1])));
}
}
}
@@ -1,4 +1,4 @@
package kamkeel.command;
package kamkeel.npcs.command;
import net.minecraft.command.CommandBase;
import net.minecraft.command.CommandException;
@@ -22,6 +22,9 @@ import org.apache.commons.lang3.ArrayUtils;
import java.util.Arrays;
import java.util.List;
import static kamkeel.npcs.util.ColorUtil.sendError;
import static kamkeel.npcs.util.ColorUtil.sendResult;
public class NpcCommand extends CommandKamkeelBase {
public EntityNPCInterface selectedNpc;
@@ -93,7 +96,7 @@ public class NpcCommand extends CommandKamkeelBase {
posZ = CommandBase.func_110666_a(sender, selectedNpc.posZ, args[2]);
}
selectedNpc.ai.startPos = new int[]{MathHelper.floor_double(posX), MathHelper.floor_double(posY), MathHelper.floor_double(posZ)};
selectedNpc.ais.startPos = new int[]{MathHelper.floor_double(posX), MathHelper.floor_double(posY), MathHelper.floor_double(posZ)};
sendResult(sender, String.format("Set NPC \u00A7e%s\u00A77 Home to \u00A7b[%.1f] [%.1f] [%.1f]\u00A77", selectedNpc.display.name, posX, posY, posZ));
}
@@ -199,7 +202,7 @@ public class NpcCommand extends CommandKamkeelBase {
if(args.length > 0)
npc.display.name = args[0];
npc.setPositionAndRotation(player.posX, player.posY, player.posZ, player.cameraYaw, player.cameraPitch);
npc.ai.startPos = new int[]{MathHelper.floor_double(player.posX),MathHelper.floor_double(player.posY),MathHelper.floor_double(player.posZ)};
npc.ais.startPos = new int[]{MathHelper.floor_double(player.posX),MathHelper.floor_double(player.posY),MathHelper.floor_double(player.posZ)};
pw.spawnEntityInWorld(npc);
npc.setHealth(npc.getMaxHealth());
NoppesUtilServer.sendOpenGui(player, EnumGuiType.MainMenuDisplay, npc);
@@ -1,4 +1,4 @@
package kamkeel.command;
package kamkeel.npcs.command;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender;
@@ -9,6 +9,9 @@ import noppes.npcs.controllers.data.SkinOverlay;
import java.util.List;
import static kamkeel.npcs.util.ColorUtil.sendError;
import static kamkeel.npcs.util.ColorUtil.sendResult;
public class OverlayCommand extends CommandKamkeelBase {
@Override
@@ -1,12 +1,16 @@
package kamkeel.command;
package kamkeel.npcs.command;
import kamkeel.npcs.controllers.ProfileController;
import kamkeel.npcs.network.packets.data.AchievementPacket;
import kamkeel.npcs.network.packets.data.ChatAlertPacket;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender;
import net.minecraft.entity.player.EntityPlayerMP;
import noppes.npcs.Server;
import noppes.npcs.constants.EnumPacketClient;
import noppes.npcs.config.ConfigMain;
import noppes.npcs.constants.EnumProfileSync;
import noppes.npcs.constants.EnumQuestRepeat;
import noppes.npcs.controllers.PlayerDataController;
import noppes.npcs.controllers.PlayerQuestController;
import noppes.npcs.controllers.QuestController;
import noppes.npcs.controllers.data.PlayerData;
import noppes.npcs.controllers.data.Quest;
@@ -16,6 +20,9 @@ import noppes.npcs.controllers.data.QuestData;
import java.util.Collection;
import java.util.List;
import static kamkeel.npcs.util.ColorUtil.sendError;
import static kamkeel.npcs.util.ColorUtil.sendResult;
public class QuestCategoryCommand extends CommandKamkeelBase {
@Override
@@ -82,19 +89,24 @@ public class QuestCategoryCommand extends CommandKamkeelBase {
int count = 0;
for(PlayerData playerdata : data){
count = 0;
for(Quest quest : questCategory.quests.values()){
if(playerdata.questData.activeQuests.containsKey(quest.id)){
playerdata.questData.activeQuests.remove(quest.id);
playerdata.questData.activeQuests.remove(quest.id);
long completeTime;
if(quest.repeat == EnumQuestRepeat.RLDAILY || quest.repeat == EnumQuestRepeat.RLWEEKLY || quest.repeat == EnumQuestRepeat.RLCUSTOM){
completeTime = System.currentTimeMillis();
playerdata.questData.finishedQuests.put(quest.id, completeTime);
} else {
completeTime = sender.getEntityWorld().getTotalWorldTime();
playerdata.questData.finishedQuests.put(quest.id, completeTime);
}
if(quest.repeat == EnumQuestRepeat.RLDAILY || quest.repeat == EnumQuestRepeat.RLWEEKLY)
playerdata.questData.finishedQuests.put(quest.id, System.currentTimeMillis());
else
playerdata.questData.finishedQuests.put(quest.id, sender.getEntityWorld().getTotalWorldTime());
if(ConfigMain.ProfilesEnabled && playerdata.player != null && quest.profileOptions.enableOptions && quest.profileOptions.completeControl == EnumProfileSync.Shared)
ProfileController.Instance.shareQuestCompletion(playerdata.player, quest.id, completeTime);;
if(playerdata.player != null){
Server.sendData((EntityPlayerMP)playerdata.player, EnumPacketClient.MESSAGE, "quest.completed", quest.title);
Server.sendData((EntityPlayerMP)playerdata.player, EnumPacketClient.CHAT, "quest.completed", ": ", quest.title);
AchievementPacket.sendAchievement((EntityPlayerMP) playerdata.player, false, "quest.completed", quest.title);
ChatAlertPacket.sendChatAlert((EntityPlayerMP) playerdata.player, "quest.completed", ": ", quest.title);
}
count++;
}
@@ -185,8 +197,8 @@ public class QuestCategoryCommand extends CommandKamkeelBase {
count++;
if(playerdata.player != null && questData.sendAlerts){
Server.sendData((EntityPlayerMP)playerdata.player, EnumPacketClient.MESSAGE, "quest.newquest", quest.title);
Server.sendData((EntityPlayerMP)playerdata.player, EnumPacketClient.CHAT, "quest.newquest", ": ", quest.title);
AchievementPacket.sendAchievement((EntityPlayerMP) playerdata.player, false, "quest.newquest", quest.title);
ChatAlertPacket.sendChatAlert((EntityPlayerMP) playerdata.player, "quest.newquest", ": ", quest.title);
}
}
}
@@ -1,19 +1,20 @@
package kamkeel.command;
package kamkeel.npcs.command;
import net.minecraft.command.CommandBase;
import kamkeel.npcs.controllers.ProfileController;
import kamkeel.npcs.controllers.SyncController;
import kamkeel.npcs.network.packets.data.AchievementPacket;
import kamkeel.npcs.network.packets.data.ChatAlertPacket;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.server.MinecraftServer;
import noppes.npcs.Server;
import noppes.npcs.api.handler.data.IQuestObjective;
import noppes.npcs.constants.EnumPacketClient;
import noppes.npcs.config.ConfigMain;
import noppes.npcs.constants.EnumProfileSync;
import noppes.npcs.constants.EnumQuestCompletion;
import noppes.npcs.constants.EnumQuestRepeat;
import noppes.npcs.controllers.PlayerDataController;
import noppes.npcs.controllers.QuestController;
import noppes.npcs.controllers.SyncController;
import noppes.npcs.controllers.data.Party;
import noppes.npcs.controllers.data.PlayerData;
import noppes.npcs.controllers.data.Quest;
@@ -23,6 +24,9 @@ import noppes.npcs.util.ValueUtil;
import java.util.Collection;
import java.util.List;
import static kamkeel.npcs.util.ColorUtil.sendError;
import static kamkeel.npcs.util.ColorUtil.sendResult;
public class QuestCommand extends CommandKamkeelBase {
@Override
@@ -67,8 +71,8 @@ public class QuestCommand extends CommandKamkeelBase {
playerdata.questData.activeQuests.put(questid, questdata);
playerdata.save();
if(playerdata.player != null && questdata.sendAlerts){
Server.sendData((EntityPlayerMP)playerdata.player, EnumPacketClient.MESSAGE, "quest.newquest", quest.title);
Server.sendData((EntityPlayerMP)playerdata.player, EnumPacketClient.CHAT, "quest.newquest", ": ", quest.title);
AchievementPacket.sendAchievement((EntityPlayerMP) playerdata.player, false, "quest.newquest", quest.title);
ChatAlertPacket.sendChatAlert((EntityPlayerMP) playerdata.player, "quest.newquest", ": ", quest.title);
}
playerdata.updateClient = true;
sendResult(sender, String.format("Started Quest \u00A7e%d\u00A77 for Player '\u00A7b%s\u00A77'", questid, playerdata.playername));
@@ -102,19 +106,23 @@ public class QuestCommand extends CommandKamkeelBase {
return;
}
for(PlayerData playerdata : data){
if(playerdata.questData.activeQuests.containsKey(questid)){
playerdata.questData.activeQuests.remove(questid);
playerdata.questData.activeQuests.remove(questid);
long completeTime;
if(quest.repeat == EnumQuestRepeat.RLDAILY || quest.repeat == EnumQuestRepeat.RLWEEKLY || quest.repeat == EnumQuestRepeat.RLCUSTOM){
completeTime = System.currentTimeMillis();
playerdata.questData.finishedQuests.put(quest.id, completeTime);
} else {
completeTime = sender.getEntityWorld().getTotalWorldTime();
playerdata.questData.finishedQuests.put(quest.id, completeTime);
}
if(quest.repeat == EnumQuestRepeat.RLDAILY || quest.repeat == EnumQuestRepeat.RLWEEKLY)
playerdata.questData.finishedQuests.put(quest.id, System.currentTimeMillis());
else
playerdata.questData.finishedQuests.put(quest.id, sender.getEntityWorld().getTotalWorldTime());
if(ConfigMain.ProfilesEnabled && playerdata.player != null && quest.profileOptions.enableOptions && quest.profileOptions.completeControl == EnumProfileSync.Shared)
ProfileController.Instance.shareQuestCompletion(playerdata.player, quest.id, completeTime);
playerdata.save();
if(playerdata.player != null){
Server.sendData((EntityPlayerMP)playerdata.player, EnumPacketClient.MESSAGE, "quest.completed", quest.title);
Server.sendData((EntityPlayerMP)playerdata.player, EnumPacketClient.CHAT, "quest.completed", ": ", quest.title);
AchievementPacket.sendAchievement((EntityPlayerMP) playerdata.player, false, "quest.completed", quest.title);
ChatAlertPacket.sendChatAlert((EntityPlayerMP) playerdata.player, "quest.completed", ": ", quest.title);
}
playerdata.updateClient = true;
sendResult(sender, String.format("Finished Quest \u00A7e%d\u00A77 for Player '\u00A7b%s\u00A77'", questid, playerdata.playername));
@@ -192,7 +200,7 @@ public class QuestCommand extends CommandKamkeelBase {
usage = "<player> <quest> [objective] [value]"
)
public void objective(ICommandSender sender, String[] args) throws CommandException {
EntityPlayer player = CommandBase.getPlayer(sender, args[0]);
EntityPlayer player = getPlayer(sender, args[0]);
int questid;
try {
questid = Integer.parseInt(args[1]);
@@ -1,8 +1,11 @@
package kamkeel.command;
package kamkeel.npcs.command;
import net.minecraft.command.ICommandSender;
import noppes.npcs.controllers.ScriptController;
import static kamkeel.npcs.util.ColorUtil.sendError;
import static kamkeel.npcs.util.ColorUtil.sendResult;
public class ScriptCommand extends CommandKamkeelBase {
@@ -1,6 +1,5 @@
package kamkeel.command;
package kamkeel.npcs.command;
import net.minecraft.command.CommandBase;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender;
import net.minecraft.entity.Entity;
@@ -21,6 +20,8 @@ import noppes.npcs.entity.EntityNPCInterface;
import java.util.*;
import static kamkeel.npcs.util.ColorUtil.sendResult;
public class SlayCommand extends CommandKamkeelBase {
public Map<String, Class<?>> SlayMap = new LinkedHashMap<String, Class<?>>();
@@ -134,6 +135,6 @@ public class SlayCommand extends CommandKamkeelBase {
@Override
public List addTabCompletionOptions(ICommandSender sender, String[] args){
return CommandBase.getListOfStringsMatchingLastWord(args, SlayMap.keySet().toArray(new String[SlayMap.size()]));
return getListOfStringsMatchingLastWord(args, SlayMap.keySet().toArray(new String[SlayMap.size()]));
}
}
@@ -0,0 +1,93 @@
package kamkeel.npcs.command.profile;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.ChatComponentTranslation;
import noppes.npcs.CustomNpcsPermissions;
import java.lang.reflect.Method;
import java.util.Map.Entry;
import static kamkeel.npcs.util.ColorUtil.sendError;
import static kamkeel.npcs.util.ColorUtil.sendMessage;
public class CommandHelpProfile extends CommandProfileBase {
private CommandProfile parent;
public CommandHelpProfile(CommandProfile parent){
this.parent = parent;
}
@Override
public String getCommandName() {
return "help";
}
@Override
public String getDescription() {
return "help [command]";
}
@Override
public void processCommand(ICommandSender sender, String[] args) throws CommandException {
if(args.length == 0){
sendMessage(sender, "\u00A78------ \u00A7aProfile Commands \u00A78------");
for(Entry<String, CommandProfileBase> entry : parent.map.entrySet()){
sendMessage(sender, "\u00A77> " + "\u00A7e" + entry.getKey() + "\u00A78: \u00A77"
+ entry.getValue().getCommandUsage(sender));
}
return;
}
CommandProfileBase command = parent.getCommand(args);
if(command == null){
sendError(sender, "Unknown command " + args[0]);
return;
}
if(command.subcommands.isEmpty()){
sendMessage(sender, (command.getCommandUsage(sender)));
return;
}
Method m = null;
if(args.length > 1){
m = command.subcommands.get(args[1].toLowerCase());
}
if(m == null){
sendMessage(sender, "\u00A78------ \u00A7a" + command.getCommandName().toUpperCase()
+ " SubCommands \u00A78------");
sendMessage(sender, "\u00A77Usage: \u00A76" + command.getUsage());
for(Entry<String, Method> entry : command.subcommands.entrySet()){
SubCommand sc = entry.getValue().getAnnotation(SubCommand.class);
// For players, only list subcommands if they have permission; for console, show all.
if(!(sender instanceof EntityPlayer) || command.canSendCommand(sender, sc, entry.getKey())){
sendMessage(sender, ("\u00A77> "
+ "\u00A7e" + entry.getKey()
+ "\u00A78: \u00A77" + sc.desc()));
}
}
// Show permission node only if sender is console or has permission.
if(!(sender instanceof EntityPlayer) ||
CustomNpcsPermissions.hasPermission((EntityPlayer)sender, CustomNpcsPermissions.PROFILE_ADMIN)){
sendMessage(sender, ("\u00A78Permission:\u00A77 "
+ CommandProfile.getCommandPermission(command.getCommandName())));
}
}
else{
sendMessage(sender, "\u00A78------ \u00A7b" + command.getCommandName().toUpperCase()
+ "." + args[1].toUpperCase() + " Command \u00A78------");
SubCommand sc = m.getAnnotation(SubCommand.class);
sendMessage(sender, ("\u00A77" + sc.desc()));
if(!sc.usage().isEmpty()){
sendMessage(sender, ("\u00A77Usage: \u00A76" + sc.usage()));
}
if(!(sender instanceof EntityPlayer) ||
CustomNpcsPermissions.hasPermission((EntityPlayer)sender, CustomNpcsPermissions.PROFILE_ADMIN)){
sendMessage(sender, ("\u00A78Permission:\u00A77 "
+ getSubCommandPermission(args[1])));
}
}
}
}
@@ -1,4 +1,4 @@
package kamkeel.command.profile;
package kamkeel.npcs.command.profile;
import net.minecraft.command.CommandBase;
import net.minecraft.command.CommandException;
@@ -23,6 +23,12 @@ public class CommandProfile extends CommandBase {
public CommandProfile(){
registerCommand(help);
registerCommand(new CommandProfileChange());
registerCommand(new CommandProfileCreate());
registerCommand(new CommandProfileRemove());
registerCommand(new CommandProfileAdmin());
registerCommand(new CommandProfileRegion());
registerCommand(new CommandProfileList());
registerCommand(new CommandProfileRename());
}
public void registerCommand(CommandProfileBase command){
@@ -84,7 +90,7 @@ public class CommandProfile extends CommandBase {
if(command == null)
return null;
if(args.length == 2 && command.runSubCommands())
return CommandBase.getListOfStringsMatchingLastWord(args, command.subcommands.keySet().toArray(new String[command.subcommands.keySet().size()]));
return getListOfStringsMatchingLastWord(args, command.subcommands.keySet().toArray(new String[command.subcommands.keySet().size()]));
String[] useArgs = command.getUsage().split(" ");
if(command.runSubCommands()) {
Method m = command.subcommands.get(args[1].toLowerCase());
@@ -95,7 +101,8 @@ public class CommandProfile extends CommandBase {
if(args.length <= useArgs.length + 2) {
if(args.length - 3 >= 0){
String usage = useArgs[args.length - 3];
if(usage.equals("<player>") || usage.equals("[player]")) {
if(usage.equals("<player>") || usage.equals("[player]") || usage.equals("<targetPlayer>")
|| usage.equals("<sourcePlayer>") || usage.equals("<destinationPlayer>")) {
return CommandBase.getListOfStringsMatchingLastWord(args, MinecraftServer.getServer().getAllUsernames());
}
}
@@ -111,7 +118,7 @@ public class CommandProfile extends CommandBase {
@Override
public int getRequiredPermissionLevel(){
return 0;
return 4;
}
public static String getCommandPermission(String command){
@@ -0,0 +1,259 @@
package kamkeel.npcs.command.profile;
import kamkeel.npcs.controllers.ProfileController;
import kamkeel.npcs.controllers.data.profile.EnumProfileOperation;
import noppes.npcs.api.handler.data.ISlot;
import kamkeel.npcs.controllers.data.profile.Profile;
import kamkeel.npcs.controllers.data.profile.ProfileOperation;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender;
import java.io.File;
import java.util.Map;
import java.util.UUID;
import static kamkeel.npcs.util.ColorUtil.*;
public class CommandProfileAdmin extends CommandProfileBase {
@Override
public String getCommandName() {
return "admin";
}
@Override
public String getDescription() {
return "Admin profile management: clone, remove, change, list, rename, and rollback profiles.";
}
@Override
public String getUsage() {
return "<subcommand>";
}
@SubCommand(
desc = "Clone a slot from one player's profile to another's.",
usage = "<sourcePlayer> <destinationPlayer> <sourceSlot> <destinationSlot> [temp]"
)
public void clone(ICommandSender sender, String[] args) throws CommandException {
if(args.length < 4) {
sendError(sender, "Usage: /profile admin clone <sourcePlayer> <destinationPlayer> <sourceSlot> <destinationSlot> [temp]");
return;
}
String sourcePlayer = args[0];
String destinationPlayer = args[1];
int sourceSlot, destinationSlot;
try {
sourceSlot = Integer.parseInt(args[2]);
destinationSlot = Integer.parseInt(args[3]);
} catch (NumberFormatException ex) {
sendError(sender, "Slot IDs must be numbers.");
return;
}
boolean temporary = (args.length >= 5 && args[4].equalsIgnoreCase("temp"));
ProfileOperation result = ProfileController.Instance.cloneSlot(sourcePlayer, sourceSlot, destinationSlot, temporary);
if(result.getResult() == EnumProfileOperation.SUCCESS) {
sendResult(sender, "Successfully cloned slot %d from %s to slot %d for %s.", sourceSlot, sourcePlayer, destinationSlot, destinationPlayer);
} else if(result.getResult() == EnumProfileOperation.LOCKED) {
// Detail message for admins – note: using result.getMessage() for further details.
sendError(sender, "Clone failed for %s: Profile is locked. Details: %s", sourcePlayer, result.getMessage());
} else if(result.getResult() == EnumProfileOperation.ERROR) {
sendError(sender, "Error cloning slot for %s: %s", sourcePlayer, result.getMessage());
} else {
sendError(sender, "Unexpected error cloning slot: %s", result.getMessage());
}
}
@SubCommand(
desc = "Remove a specified slot from a player's profile.",
usage = "<targetPlayer> <slotId>"
)
public void remove(ICommandSender sender, String[] args) throws CommandException {
if(args.length < 2) {
sendError(sender, "Usage: /profile admin remove <targetPlayer> <slotId>");
return;
}
String targetPlayer = args[0];
int slotId;
try {
slotId = Integer.parseInt(args[1]);
} catch(NumberFormatException ex) {
sendError(sender, "Slot ID must be a number.");
return;
}
ProfileOperation result = ProfileController.Instance.removeSlot(targetPlayer, slotId);
if(result.getResult() == EnumProfileOperation.SUCCESS) {
sendResult(sender, "Successfully removed slot %d from %s.", slotId, targetPlayer);
} else if(result.getResult() == EnumProfileOperation.LOCKED) {
sendError(sender, "Remove failed for %s: Profile is locked. Details: %s", targetPlayer, result.getMessage());
} else if(result.getResult() == EnumProfileOperation.ERROR) {
sendError(sender, "Error removing slot %d from %s: %s", slotId, targetPlayer, result.getMessage());
} else {
sendError(sender, "Unexpected error during removal: %s", result.getMessage());
}
}
@SubCommand(
desc = "Change a specified player's active slot.",
usage = "<targetPlayer> <newSlotId>"
)
public void change(ICommandSender sender, String[] args) throws CommandException {
if(args.length < 2) {
sendError(sender, "Usage: /profile admin change <targetPlayer> <newSlotId>");
return;
}
String targetPlayer = args[0];
int newSlotId;
try {
newSlotId = Integer.parseInt(args[1]);
} catch(NumberFormatException ex) {
sendError(sender, "Slot ID must be a number.");
return;
}
ProfileOperation result = ProfileController.Instance.changeSlot(targetPlayer, newSlotId);
if(result.getResult() == EnumProfileOperation.SUCCESS) {
sendResult(sender, "Successfully changed %s's active slot to %d.", targetPlayer, newSlotId);
} else if(result.getResult() == EnumProfileOperation.LOCKED) {
sendError(sender, "Change failed for %s: Profile is locked. Details: %s", targetPlayer, result.getMessage());
} else if(result.getResult() == EnumProfileOperation.ERROR) {
sendError(sender, "Error changing active slot for %s: %s", targetPlayer, result.getMessage());
} else {
sendError(sender, "Unexpected error during change: %s", result.getMessage());
}
}
@SubCommand(
desc = "Create a new slot for a specified player's profile.",
usage = "<targetPlayer>"
)
public void create(ICommandSender sender, String[] args) throws CommandException {
if(args.length < 1) {
sendError(sender, "Usage: /profile admin create <targetPlayer>");
return;
}
String targetPlayer = args[0];
Profile profile = ProfileController.Instance.getProfile(targetPlayer);
if(profile == null) {
sendError(sender, "Profile not found for player: %s", targetPlayer);
return;
}
ProfileOperation result = ProfileController.Instance.createSlotInternal(profile);
if(result.getResult() == EnumProfileOperation.SUCCESS) {
sendResult(sender, "New slot created successfully for %s.", targetPlayer);
} else if(result.getResult() == EnumProfileOperation.LOCKED) {
sendError(sender, "Create failed for %s: Profile is locked. Details: %s", targetPlayer, result.getMessage());
} else if(result.getResult() == EnumProfileOperation.ERROR) {
sendError(sender, "Error creating new slot for %s: %s", targetPlayer, result.getMessage());
} else {
sendError(sender, "Unexpected error during slot creation: %s", result.getMessage());
}
}
@SubCommand(
desc = "List all slots (IDs and names) for a specified player's profile.",
usage = "<targetPlayer>"
)
public void list(ICommandSender sender, String[] args) throws CommandException {
if(args.length < 1) {
sendError(sender, "Usage: /profile admin list <targetPlayer>");
return;
}
String targetPlayer = args[0];
Profile profile = ProfileController.Instance.getProfile(targetPlayer);
if(profile == null) {
sendError(sender, "Profile not found for player: %s", targetPlayer);
return;
}
sendMessage(sender, "Profile Slots for %s:", targetPlayer);
for(Map.Entry<Integer, ISlot> entry : profile.getSlots().entrySet()) {
int id = entry.getKey();
String name = entry.getValue().getName();
String prefix = (id == profile.currentSlotId) ? "* " : "- ";
sendMessage(sender, prefix + "Slot " + id + ": " + name);
}
}
@SubCommand(
desc = "Rename a specified player's slot.",
usage = "<targetPlayer> <slotId> <newName>"
)
public void rename(ICommandSender sender, String[] args) throws CommandException {
if(args.length < 3) {
sendError(sender, "Usage: /profile admin rename <targetPlayer> <slotId> <newName>");
return;
}
String targetPlayer = args[0];
int slotId;
try {
slotId = Integer.parseInt(args[1]);
} catch(NumberFormatException ex) {
sendError(sender, "Slot ID must be a number.");
return;
}
StringBuilder sb = new StringBuilder();
for(int i = 2; i < args.length; i++){
if(i > 2) sb.append(" ");
sb.append(args[i]);
}
String newName = sb.toString().trim();
if(newName.length() > 20) {
newName = newName.substring(0, 20);
}
if(!newName.matches("[A-Za-z ]+")){
sendError(sender, "Invalid name. Only alphabetic characters and spaces are allowed.");
return;
}
Profile profile = ProfileController.Instance.getProfile(targetPlayer);
if(profile == null) {
sendError(sender, "Profile not found for player: %s", targetPlayer);
return;
}
if(profile.isLocked()) {
sendError(sender, "Profile for %s is locked. Please try again later.", targetPlayer);
return;
}
if(!profile.getSlots().containsKey(slotId)) {
sendError(sender, "Slot %d not found in %s's profile.", slotId, targetPlayer);
return;
}
profile.getSlots().get(slotId).setName(newName);
if(profile.getPlayer() != null) {
ProfileController.Instance.save(profile.player, profile);
} else {
UUID uuid = ProfileController.Instance.getUUIDFromUsername(targetPlayer);
if(uuid != null)
ProfileController.Instance.saveOffline(profile, uuid);
}
sendResult(sender, "Successfully renamed slot %d for %s to '%s'.", slotId, targetPlayer, newName);
}
@SubCommand(
desc = "Rollback a player's profile to one of their backups.",
usage = "<targetPlayer> <backupFileName>"
)
public void rollback(ICommandSender sender, String[] args) throws CommandException {
if(args.length < 2) {
sendError(sender, "Usage: /profile admin rollback <targetPlayer> <backupFileName>");
return;
}
String targetPlayer = args[0];
String backupFileName = args[1] + ".dat";
Profile profile = ProfileController.Instance.getProfile(targetPlayer);
if(profile == null || profile.player == null)
return;
File backupDir = new File(ProfileController.getBackupDir(), profile.getPlayer().getUniqueID().toString());
File backupFile = new File(backupDir, backupFileName);
if(!backupFile.exists()){
sendError(sender, "Backup file %s not found for player %s.", backupFileName, targetPlayer);
return;
}
boolean success = ProfileController.Instance.rollbackProfile(targetPlayer, backupFile);
if(success) {
sendResult(sender, "Successfully rolled back %s's profile to backup %s.", targetPlayer, backupFileName);
} else {
sendError(sender, "Failed to rollback %s's profile.", targetPlayer);
}
}
}
@@ -1,10 +1,9 @@
package kamkeel.command.profile;
package kamkeel.npcs.command.profile;
import net.minecraft.command.CommandBase;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.ChatComponentTranslation;
import noppes.npcs.CustomNpcsPermissions;
import java.lang.annotation.ElementType;
@@ -55,19 +54,7 @@ public abstract class CommandProfileBase extends CommandBase{
return !subcommands.isEmpty();
}
protected static void sendMessage(ICommandSender sender, String message, Object... obs) {
sender.addChatMessage(new ChatComponentTranslation(message, obs));
}
protected static void sendResult(ICommandSender sender, String message, Object... obs) {
sender.addChatMessage(new ChatComponentTranslation("\u00A76[\u00A7eCNPC+\u00A76]\u00A77 " + message, obs));
}
protected static void sendError(ICommandSender sender, String message, Object... obs) {
sender.addChatMessage(new ChatComponentTranslation("\u00A76[\u00A7eCNPC+\u00A76]\u00A74 Error:\u00A7c " + message, obs));
}
@Retention(value = RetentionPolicy.RUNTIME)
@Retention(value = RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface SubCommand {
@@ -0,0 +1,64 @@
package kamkeel.npcs.command.profile;
import kamkeel.npcs.controllers.ProfileController;
import kamkeel.npcs.controllers.data.profile.EnumProfileOperation;
import kamkeel.npcs.controllers.data.profile.ProfileOperation;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender;
import net.minecraft.entity.player.EntityPlayer;
import static kamkeel.npcs.util.ColorUtil.sendError;
import static kamkeel.npcs.util.ColorUtil.sendResult;
public class CommandProfileChange extends CommandProfileBase {
@Override
public String getCommandName() {
return "change";
}
@Override
public String getDescription() {
return "Change your active profile slot.";
}
@Override
public String getUsage() {
return "<slotId>";
}
@Override
public boolean runSubCommands() {
return false;
}
@Override
public void processCommand(ICommandSender sender, String[] args) throws CommandException {
if(!(sender instanceof EntityPlayer)) {
sendError(sender, "This command can only be used by a player.");
return;
}
if(args.length < 1) {
sendError(sender, "Usage: " + getUsage());
return;
}
int slotId;
try {
slotId = Integer.parseInt(args[0]);
} catch(NumberFormatException ex) {
sendError(sender, "Slot ID must be a number: " + args[0]);
return;
}
EntityPlayer player = (EntityPlayer)sender;
ProfileOperation result = ProfileController.Instance.changeSlot(player, slotId);
if(result.getResult() == EnumProfileOperation.SUCCESS) {
sendResult(sender, "Successfully changed profile slot to %d.", slotId);
} else if(result.getResult() == EnumProfileOperation.LOCKED) {
sendError(sender, "Profile is locked. Details: %s", result.getMessage());
} else if(result.getResult() == EnumProfileOperation.ERROR) {
sendError(sender, "Error changing your profile slot: %s", result.getMessage());
} else {
sendError(sender, "Unexpected error: %s", result.getMessage());
}
}
}
@@ -0,0 +1,57 @@
package kamkeel.npcs.command.profile;
import kamkeel.npcs.controllers.ProfileController;
import kamkeel.npcs.controllers.data.profile.EnumProfileOperation;
import kamkeel.npcs.controllers.data.profile.ProfileOperation;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender;
import net.minecraft.entity.player.EntityPlayer;
import static kamkeel.npcs.util.ColorUtil.sendError;
import static kamkeel.npcs.util.ColorUtil.sendResult;
public class CommandProfileCreate extends CommandProfileBase {
@Override
public String getCommandName() {
return "create";
}
@Override
public String getDescription() {
return "Create a new profile slot.";
}
@Override
public String getUsage() {
return "";
}
@Override
public boolean runSubCommands() {
return false;
}
@Override
public void processCommand(ICommandSender sender, String[] args) throws CommandException {
if(!(sender instanceof EntityPlayer)) {
sendError(sender, "This command can only be used by a player.");
return;
}
EntityPlayer player = (EntityPlayer)sender;
if(ProfileController.Instance.getProfile(player) == null) {
sendError(sender, "Profile not found.");
return;
}
ProfileOperation result = ProfileController.Instance.createSlotInternal(ProfileController.Instance.getProfile(player));
if(result.getResult() == EnumProfileOperation.SUCCESS) {
sendResult(sender, "New profile slot created successfully.");
} else if(result.getResult() == EnumProfileOperation.LOCKED) {
sendError(sender, "Profile is locked. Details: %s", result.getMessage());
} else if(result.getResult() == EnumProfileOperation.ERROR) {
sendError(sender, "Error creating new profile slot: %s", result.getMessage());
} else {
sendError(sender, "Unexpected error: %s", result.getMessage());
}
}
}
@@ -0,0 +1,55 @@
package kamkeel.npcs.command.profile;
import kamkeel.npcs.controllers.ProfileController;
import noppes.npcs.api.handler.data.ISlot;
import kamkeel.npcs.controllers.data.profile.Profile;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender;
import net.minecraft.entity.player.EntityPlayer;
import java.util.Map;
import static kamkeel.npcs.util.ColorUtil.sendError;
import static kamkeel.npcs.util.ColorUtil.sendMessage;
public class CommandProfileList extends CommandProfileBase {
@Override
public String getCommandName() {
return "list";
}
@Override
public String getDescription() {
return "List all your current profile slots (IDs and names).";
}
@Override
public String getUsage() {
return ""; // No extra parameters.
}
@Override
public void processCommand(ICommandSender sender, String[] args) throws CommandException {
if(!(sender instanceof EntityPlayer)) {
sendError(sender, "This command can only be used by a player.");
return;
}
EntityPlayer player = (EntityPlayer)sender;
Profile profile = ProfileController.Instance.getProfile(player);
if(profile == null) {
sendError(sender, "Profile not found.");
return;
}
if(profile.getSlots().isEmpty()){
sendMessage(sender, "No slots found. Using default slot 0.");
}
sendMessage(sender, "Your Profile Slots:");
for(Map.Entry<Integer, ISlot> entry : profile.getSlots().entrySet()) {
int id = entry.getKey();
String name = entry.getValue().getName();
String prefix = (id == profile.currentSlotId) ? "* " : "- ";
sendMessage(sender, prefix + "Slot " + id + ": " + name);
}
}
}
@@ -0,0 +1,159 @@
package kamkeel.npcs.command.profile;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender;
import noppes.npcs.config.ConfigMain;
import java.util.ArrayList;
import java.util.List;
import static kamkeel.npcs.util.ColorUtil.*;
public class CommandProfileRegion extends CommandProfileBase {
@Override
public String getCommandName() {
return "region";
}
@Override
public String getDescription() {
return "Manage profile region switching and restricted regions";
}
@Override
public String getUsage() {
return "<subcommand>";
}
@SubCommand(
desc = "Enable region-based profile switching",
usage = ""
)
public void enable(ICommandSender sender, String[] args) throws CommandException {
ConfigMain.RegionProfileSwitching = true;
ConfigMain.RegionProfileSwitchingProperty.set(true);
if(ConfigMain.config.hasChanged()){
ConfigMain.config.save();
}
sendResult(sender, "Profile region switching enabled.");
}
@SubCommand(
desc = "Disable region-based profile switching",
usage = ""
)
public void disable(ICommandSender sender, String[] args) throws CommandException {
ConfigMain.RegionProfileSwitching = false;
ConfigMain.RegionProfileSwitchingProperty.set(false);
if(ConfigMain.config.hasChanged()){
ConfigMain.config.save();
}
sendResult(sender, "Profile region switching disabled.");
}
@SubCommand(
desc = "Add a new region. Format: DIM, X1, Y1, Z1, X2, Y2, Z2",
usage = "<dim> <x1> <y1> <z1> <x2> <y2> <z2>"
)
public void add(ICommandSender sender, String[] args) throws CommandException {
if(args.length < 1){
sendError(sender, "Usage: /profile region add <DIM, X1, Y1, Z1, X2, Y2, Z2>");
return;
}
// Combine args in case the region data was split by spaces
String regionStr = String.join(" ", args).trim();
String[] parts = regionStr.split(",");
if(parts.length != 7){
sendError(sender, "Invalid region format. Must contain 7 integers separated by commas.");
return;
}
List<Integer> regionList = new ArrayList<>();
try {
for(String part : parts){
regionList.add(Integer.parseInt(part.trim()));
}
} catch(NumberFormatException e){
sendError(sender, "Invalid number format in region data.");
return;
}
ConfigMain.RestrictedProfileRegions.add(regionList);
// Update config property value
List<String> regionStrings = new ArrayList<>();
for(List<Integer> region : ConfigMain.RestrictedProfileRegions) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < region.size(); i++) {
if(i > 0) sb.append(", ");
sb.append(region.get(i));
}
regionStrings.add(sb.toString());
}
ConfigMain.RestrictedProfileRegionsProperty.set(regionStrings.toArray(new String[0]));
if(ConfigMain.config.hasChanged()){
ConfigMain.config.save();
}
sendResult(sender, "Region added successfully.");
}
@SubCommand(
desc = "Remove a region by its index (1-based).",
usage = "<index>"
)
public void remove(ICommandSender sender, String[] args) throws CommandException {
if(args.length < 1){
sendError(sender, "Usage: /profile region remove <index>");
return;
}
int index;
try {
index = Integer.parseInt(args[0]);
} catch(NumberFormatException e){
sendError(sender, "Index must be a number.");
return;
}
index = index - 1; // Convert to 0-based index
if(index < 0 || index >= ConfigMain.RestrictedProfileRegions.size()){
sendError(sender, "Invalid index. Must be between 1 and " + ConfigMain.RestrictedProfileRegions.size());
return;
}
ConfigMain.RestrictedProfileRegions.remove(index);
// Update config property value
List<String> regionStrings = new ArrayList<>();
for(List<Integer> region : ConfigMain.RestrictedProfileRegions) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < region.size(); i++) {
if(i > 0) sb.append(", ");
sb.append(region.get(i));
}
regionStrings.add(sb.toString());
}
ConfigMain.RestrictedProfileRegionsProperty.set(regionStrings.toArray(new String[0]));
if(ConfigMain.config.hasChanged()){
ConfigMain.config.save();
}
sendResult(sender, "Region removed successfully.");
}
@SubCommand(
desc = "List all restricted profile regions.",
usage = ""
)
public void list(ICommandSender sender, String[] args) throws CommandException {
if(ConfigMain.RestrictedProfileRegions.isEmpty()){
sendMessage(sender, "No restricted profile regions configured.");
return;
}
sendMessage(sender, "Restricted Profile Regions:");
int i = 1;
for(List<Integer> region : ConfigMain.RestrictedProfileRegions) {
StringBuilder sb = new StringBuilder();
sb.append(i).append(": ");
for (int j = 0; j < region.size(); j++) {
if(j > 0) sb.append(", ");
sb.append(region.get(j));
}
sendMessage(sender, sb.toString());
i++;
}
}
}
@@ -0,0 +1,64 @@
package kamkeel.npcs.command.profile;
import kamkeel.npcs.controllers.ProfileController;
import kamkeel.npcs.controllers.data.profile.EnumProfileOperation;
import kamkeel.npcs.controllers.data.profile.ProfileOperation;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender;
import net.minecraft.entity.player.EntityPlayer;
import static kamkeel.npcs.util.ColorUtil.sendError;
import static kamkeel.npcs.util.ColorUtil.sendResult;
public class CommandProfileRemove extends CommandProfileBase {
@Override
public String getCommandName() {
return "remove";
}
@Override
public String getDescription() {
return "Remove a slot from your profile. You cannot remove your active slot.";
}
@Override
public String getUsage() {
return "<slotId>";
}
@Override
public boolean runSubCommands() {
return false;
}
@Override
public void processCommand(ICommandSender sender, String[] args) throws CommandException {
if(!(sender instanceof EntityPlayer)) {
sendError(sender, "This command can only be used by a player.");
return;
}
if(args.length < 1) {
sendError(sender, "Usage: " + getUsage());
return;
}
int slotId;
try {
slotId = Integer.parseInt(args[0]);
} catch(NumberFormatException ex) {
sendError(sender, "Slot ID must be a number: " + args[0]);
return;
}
EntityPlayer player = (EntityPlayer)sender;
ProfileOperation result = ProfileController.Instance.removeSlot(player, slotId);
if(result.getResult() == EnumProfileOperation.SUCCESS) {
sendResult(sender, "Successfully removed slot %d from your profile.", slotId);
} else if(result.getResult() == EnumProfileOperation.LOCKED) {
sendError(sender, "Profile is locked. Details: %s", result.getMessage());
} else if(result.getResult() == EnumProfileOperation.ERROR) {
sendError(sender, "Error removing slot: %s", result.getMessage());
} else {
sendError(sender, "Unexpected error: %s", result.getMessage());
}
}
}
@@ -0,0 +1,71 @@
package kamkeel.npcs.command.profile;
import kamkeel.npcs.controllers.ProfileController;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender;
import net.minecraft.entity.player.EntityPlayer;
import static kamkeel.npcs.util.ColorUtil.sendError;
import static kamkeel.npcs.util.ColorUtil.sendResult;
public class CommandProfileRename extends CommandProfileBase {
@Override
public String getCommandName() {
return "rename";
}
@Override
public String getDescription() {
return "Rename one of your profile slots. Only letters and spaces are allowed (max 20 characters).";
}
@Override
public String getUsage() {
return "<slotId> <newName>";
}
@Override
public void processCommand(ICommandSender sender, String[] args) throws CommandException {
if(!(sender instanceof EntityPlayer)) {
sendError(sender, "This command can only be used by a player.");
return;
}
if(args.length < 2) {
sendError(sender, "Usage: " + getUsage());
return;
}
int slotId;
try {
slotId = Integer.parseInt(args[0]);
} catch(NumberFormatException ex) {
sendError(sender, "Slot ID must be a number.");
return;
}
StringBuilder sb = new StringBuilder();
for(int i = 1; i < args.length; i++){
if(i > 1) sb.append(" ");
sb.append(args[i]);
}
String newName = sb.toString().trim();
if(newName.length() > 20) {
newName = newName.substring(0, 20);
}
if(!newName.matches("[A-Za-z ]+")){
sendError(sender, "Invalid name. Only alphabetic characters and spaces are allowed.");
return;
}
EntityPlayer player = (EntityPlayer)sender;
if(ProfileController.Instance.getProfile(player) == null) {
sendError(sender, "Profile not found.");
return;
}
if(!ProfileController.Instance.getProfile(player).getSlots().containsKey(slotId)) {
sendError(sender, "Slot %d not found in your profile.", slotId);
return;
}
ProfileController.Instance.getProfile(player).getSlots().get(slotId).setName(newName);
ProfileController.Instance.save(player, ProfileController.Instance.getProfile(player));
sendResult(sender, "Successfully renamed slot %d to '%s'.", slotId, newName);
}
}
@@ -0,0 +1,78 @@
package kamkeel.npcs.controllers;
import net.minecraft.entity.player.EntityPlayer;
import kamkeel.npcs.controllers.data.attribute.AttributeDefinition;
import kamkeel.npcs.controllers.data.attribute.AttributeValueType;
import kamkeel.npcs.CustomAttributes;
import kamkeel.npcs.controllers.data.attribute.tracker.PlayerAttributeTracker;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
* AttributeController is the central registry for attribute definitions.
* It ensures that keys are unique.
*/
public class AttributeController {
public AttributeController Instance;
public CustomAttributes attributes;
// Tracking Player Attributes
private static final Map<UUID, PlayerAttributeTracker> trackers = new HashMap<>();
private static final Map<String, AttributeDefinition> definitions = new HashMap<>();
public AttributeController(){
this.Instance = this;
definitions.clear();
trackers.clear();
attributes = new CustomAttributes();
}
public static AttributeDefinition registerAttribute(String key, String displayName, char colorCode, AttributeValueType valueType, AttributeDefinition.AttributeSection section) {
if (definitions.containsKey(key)) {
throw new IllegalArgumentException("Attribute already registered with key: " + key);
}
AttributeDefinition def = new AttributeDefinition(key, displayName, colorCode, valueType, section);
definitions.put(key, def);
return def;
}
public static AttributeDefinition registerAttribute(AttributeDefinition definition) {
if (definitions.containsKey(definition.getKey())) {
throw new IllegalArgumentException("Attribute already registered with key: " + definition.getKey());
} else {
definitions.put(definition.getKey(), definition);
return definition;
}
}
public static AttributeDefinition getAttribute(String key) {
return definitions.get(key);
}
public static Collection<AttributeDefinition> getAllAttributes() {
return definitions.values();
}
public static PlayerAttributeTracker getTracker(EntityPlayer player) {
return trackers.computeIfAbsent(player.getUniqueID(), id -> new PlayerAttributeTracker(id));
}
public static void removeTracker(UUID playerId) {
trackers.remove(playerId);
}
/**
* Update all trackers (e.g. called every 10 ticks for all online players).
*/
public static void updateAllTrackers(Iterable<EntityPlayer> players) {
for (EntityPlayer player : players) {
PlayerAttributeTracker tracker = getTracker(player);
tracker.updateIfChanged(player);
}
}
}
@@ -0,0 +1,795 @@
package kamkeel.npcs.controllers;
import kamkeel.npcs.controllers.data.profile.*;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.CompressedStreamTools;
import net.minecraft.nbt.NBTTagCompound;
import noppes.npcs.CustomNpcs;
import noppes.npcs.CustomNpcsPermissions;
import noppes.npcs.LogWriter;
import noppes.npcs.NoppesUtilServer;
import noppes.npcs.api.entity.IPlayer;
import noppes.npcs.api.handler.IPlayerData;
import noppes.npcs.api.handler.data.IProfile;
import noppes.npcs.api.handler.IProfileHandler;
import noppes.npcs.api.handler.data.ISlot;
import noppes.npcs.config.ConfigMain;
import noppes.npcs.controllers.QuestController;
import noppes.npcs.controllers.data.PlayerData;
import noppes.npcs.controllers.data.PlayerQuestData;
import noppes.npcs.util.CustomNPCsThreader;
import noppes.npcs.util.NBTJsonUtil;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.*;
import static noppes.npcs.CustomNpcsPermissions.PROFILE_REGION_BYPASS;
import static noppes.npcs.CustomNpcsPermissions.hasPermission;
public class ProfileController implements IProfileHandler {
// Message constants
private static final String MSG_PLAYER_NOT_FOUND = "Player not found.";
private static final String MSG_PROFILE_LOCKED_CLONE = "Profile is locked; cannot clone slot.";
private static final String MSG_SOURCE_SLOT_NOT_EXIST = "Source slot does not exist.";
private static final String MSG_CANNOT_CLONE_CURRENT = "Cannot clone to the current active slot.";
private static final String MSG_INVALID_DEST_SLOT = "Invalid destination slot id.";
private static final String MSG_CLONE_SUCCESS = "Slot cloned successfully.";
private static final String MSG_PROFILE_LOCKED_REMOVE = "Profile is locked; cannot remove slot.";
private static final String MSG_CANNOT_REMOVE_ACTIVE = "Cannot remove the currently active slot.";
private static final String MSG_SLOT_NOT_EXIST = "Slot does not exist.";
private static final String MSG_REMOVE_SUCCESS = "Slot removed successfully.";
private static final String MSG_PROFILE_LOCKED_CREATE = "Profile is locked; cannot create slot.";
private static final String MSG_MAX_SLOTS_REACHED = "Maximum allowed slots reached.";
private static final String MSG_NEW_SLOT_CREATED = "New slot created successfully.";
private static final String MSG_PROFILE_LOCKED_CHANGE = "Profile is locked; cannot change slot.";
private static final String MSG_SLOT_ALREADY_ACTIVE = "Slot is already active.";
private static final String MSG_REGION_NOT_ALLOWED = "Profile switching not allowed from your current location.";
private static final String MSG_CHANGE_SUCCESS = "Slot changed successfully.";
public static Map<String, IProfileData> profileTypes = new HashMap<>();
public static Map<UUID, Profile> activeProfiles = new HashMap<>();
public static String profile_directory = "profiles";
public static ProfileController Instance;
public ProfileController() {
Instance = this;
profileTypes = new HashMap<>();
activeProfiles = new HashMap<>();
}
public static boolean registerProfileType(IProfileData type) {
if (profileTypes.containsKey(type.getTagName()))
return false;
profileTypes.put(type.getTagName(), type);
return true;
}
public static File getProfileDir() {
try {
File file = new File(CustomNpcs.getWorldSaveDirectory(), profile_directory);
if (!file.exists())
file.mkdir();
return file;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static File getBackupDir() {
File base = getProfileDir();
File backup = new File(base, "backup");
if (!backup.exists()) {
backup.mkdir();
}
return backup;
}
public synchronized void login(EntityPlayer player) {
if(!ConfigMain.ProfilesEnabled)
return;
if (player == null)
return;
Profile profile;
if (activeProfiles.containsKey(player.getUniqueID())) {
profile = activeProfiles.get(player.getUniqueID());
profile.player = player;
} else {
NBTTagCompound compound = load(player);
profile = new Profile(player, compound);
if (profile.getSlots().isEmpty()) {
Slot defaultSlot = new Slot(0, "Default Slot");
defaultSlot.setLastLoaded(System.currentTimeMillis());
profile.getSlots().put(0, defaultSlot);
profile.currentSlotId = 0;
saveSlotData(player);
}
profile.player = player;
activeProfiles.put(player.getUniqueID(), profile);
verifySlotQuests(profile.player);
save(player, profile);
}
}
public synchronized NBTTagCompound load(EntityPlayer player) {
File saveDir = getProfileDir();
String filename = player.getUniqueID().toString() + ".dat";
try {
File file = new File(saveDir, filename);
if (file.exists()) {
return NBTJsonUtil.loadNBTData(file);
}
} catch (Exception e) {
LogWriter.error("Error loading profile file: " + filename, e);
}
return new NBTTagCompound();
}
public synchronized NBTTagCompound load(UUID uuid) {
File saveDir = getProfileDir();
String filename = uuid.toString() + ".dat";
try {
File file = new File(saveDir, filename);
if (file.exists()) {
return NBTJsonUtil.loadNBTData(file);
}
} catch (Exception e) {
LogWriter.error("Error loading profile file: " + filename, e);
}
return new NBTTagCompound();
}
public synchronized void saveOffline(Profile profile, UUID uuid) {
profile.setLocked(true);
CustomNPCsThreader.customNPCThread.execute(() -> {
final NBTTagCompound compound = profile.writeToNBT();
final String filename = uuid.toString() + ".dat";
try {
File saveDir = getProfileDir();
File fileNew = new File(saveDir, filename + "_new");
File fileOld = new File(saveDir, filename);
CompressedStreamTools.writeCompressed(compound, new FileOutputStream(fileNew));
if (fileOld.exists()) {
fileOld.delete();
}
fileNew.renameTo(fileOld);
backupProfile(uuid, compound);
} catch (Exception e) {
LogWriter.except(e);
} finally {
profile.setLocked(false);
}
});
}
public synchronized void save(EntityPlayer player, Profile profile) {
profile.setLocked(true);
CustomNPCsThreader.customNPCThread.execute(() -> {
final NBTTagCompound compound = profile.writeToNBT();
final String filename = player.getUniqueID() + ".dat";
try {
File saveDir = getProfileDir();
File fileNew = new File(saveDir, filename + "_new");
File fileOld = new File(saveDir, filename);
CompressedStreamTools.writeCompressed(compound, new FileOutputStream(fileNew));
if (fileOld.exists()) {
fileOld.delete();
}
fileNew.renameTo(fileOld);
if (ConfigMain.AllowProfileBackups) {
backupProfile(player.getUniqueID(), compound);
}
} catch (Exception e) {
LogWriter.except(e);
} finally {
profile.setLocked(false);
}
});
}
private void backupProfile(UUID uuid, NBTTagCompound compound) {
try {
File backupDir = new File(getBackupDir(), uuid.toString());
if (!backupDir.exists()) {
backupDir.mkdirs();
}
String dateStr = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
File backupFile = new File(backupDir, dateStr + ".dat");
CompressedStreamTools.writeCompressed(compound, new FileOutputStream(backupFile));
File[] backups = backupDir.listFiles((dir, name) -> name.endsWith(".dat"));
if (backups != null && backups.length > ConfigMain.ProfileBackupAmount) {
Arrays.sort(backups, Comparator.comparingLong(File::lastModified));
for (int i = 0; i < backups.length - ConfigMain.ProfileBackupAmount; i++) {
backups[i].delete();
}
}
} catch (Exception e) {
LogWriter.except(e);
}
}
public boolean rollbackProfile(String username, File backupFile) {
UUID uuid = getUUIDFromUsername(username);
if (uuid == null)
return false;
try (FileInputStream fis = new FileInputStream(backupFile)) {
NBTTagCompound compound = CompressedStreamTools.readCompressed(fis);
File saveDir = getProfileDir();
File mainFile = new File(saveDir, uuid.toString() + ".dat");
File fileNew = new File(saveDir, uuid.toString() + "_new");
CompressedStreamTools.writeCompressed(compound, new FileOutputStream(fileNew));
if (mainFile.exists()) {
mainFile.delete();
}
fileNew.renameTo(mainFile);
EntityPlayer player = NoppesUtilServer.getPlayerByName(username);
Profile newProfile;
if (player != null) {
newProfile = new Profile(player, compound);
activeProfiles.put(uuid, newProfile);
loadSlotData(player);
} else {
newProfile = new Profile(null, compound);
activeProfiles.put(uuid, newProfile);
}
return true;
} catch (Exception e) {
LogWriter.except(e);
return false;
}
}
public synchronized void logout(EntityPlayer player) {
if (player != null) {
activeProfiles.remove(player.getUniqueID());
}
}
public Profile getProfile(EntityPlayer player) {
if (player == null)
return null;
if (!activeProfiles.containsKey(player.getUniqueID()))
login(player);
return activeProfiles.get(player.getUniqueID());
}
public Profile getProfile(UUID uuid) {
if (activeProfiles.containsKey(uuid))
return activeProfiles.get(uuid);
NBTTagCompound compound = load(uuid);
return new Profile(null, compound);
}
public Profile getProfile(String username) {
EntityPlayer player = NoppesUtilServer.getPlayerByName(username);
if (player != null) {
return getProfile(player);
} else {
UUID uuid = getUUIDFromUsername(username);
if (uuid == null)
return null;
return getProfile(uuid);
}
}
public UUID getUUIDFromUsername(String username) {
try {
URL url = new URL("https://api.mojang.com/users/profiles/minecraft/" + username);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("GET");
con.setConnectTimeout(5000);
con.setReadTimeout(5000);
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
StringBuilder temp = new StringBuilder();
String line;
while ((line = in.readLine()) != null) {
temp.append(line);
}
in.close();
con.disconnect();
String response = temp.toString();
if (response.contains("\"id\"")) {
int idIndex = response.indexOf("\"id\"");
int colonIndex = response.indexOf(":", idIndex);
int quoteStart = response.indexOf("\"", colonIndex);
int quoteEnd = response.indexOf("\"", quoteStart + 1);
String idString = response.substring(quoteStart + 1, quoteEnd);
idString = idString.replaceFirst(
"(\\p{XDigit}{8})(\\p{XDigit}{4})(\\p{XDigit}{4})(\\p{XDigit}{4})(\\p{XDigit}+)",
"$1-$2-$3-$4-$5"
);
return UUID.fromString(idString);
}
} catch (IOException e) {
LogWriter.error("Error retrieving UUID for " + username, e);
}
return null;
}
private int getNextAvailableTempSlot(Profile profile) {
int id = -1;
while (profile.getSlots().containsKey(id)) {
id--;
}
return id;
}
private ProfileOperation cloneSlotInternal(Profile profile, int sourceSlotId, int destinationSlotId, boolean temporary) {
if (profile.isLocked()) {
return ProfileOperation.locked(MSG_PROFILE_LOCKED_CLONE);
}
if (profile.player != null) {
List<IProfileData> dataList = new ArrayList<>(profileTypes.values());
dataList.sort(Comparator.comparingInt(IProfileData::getSwitchPriority));
for (IProfileData pd : dataList) {
if (pd.verifySwitch(profile.player).getResult() != EnumProfileOperation.SUCCESS) {
return pd.verifySwitch(profile.player);
}
}
}
if (!profile.getSlots().containsKey(sourceSlotId)) {
return ProfileOperation.error(MSG_SOURCE_SLOT_NOT_EXIST);
}
if (destinationSlotId == profile.getCurrentSlotId()) {
return ProfileOperation.error(MSG_CANNOT_CLONE_CURRENT);
}
if (temporary) {
destinationSlotId = getNextAvailableTempSlot(profile);
} else {
if (destinationSlotId <= 0) {
return ProfileOperation.error(MSG_INVALID_DEST_SLOT);
}
}
ISlot sourceSlot = profile.getSlots().get(sourceSlotId);
Map<String, NBTTagCompound> newComponents = new HashMap<>();
for (String key : sourceSlot.getComponents().keySet()) {
newComponents.put(key, (NBTTagCompound) sourceSlot.getComponentData(key).copy());
}
Slot clonedSlot = new Slot(destinationSlotId, "Cloned Slot " + destinationSlotId, System.currentTimeMillis(), temporary, newComponents);
profile.getSlots().put(destinationSlotId, clonedSlot);
return ProfileOperation.success(MSG_CLONE_SUCCESS);
}
private ProfileOperation removeSlotInternal(Profile profile, int slotId) {
if (profile.isLocked()) {
return ProfileOperation.locked(MSG_PROFILE_LOCKED_REMOVE);
}
if (slotId == profile.getCurrentSlotId()) {
return ProfileOperation.error(MSG_CANNOT_REMOVE_ACTIVE);
}
if (!profile.getSlots().containsKey(slotId)) {
return ProfileOperation.error(MSG_SLOT_NOT_EXIST);
}
profile.getSlots().remove(slotId);
return ProfileOperation.success(MSG_REMOVE_SUCCESS);
}
public ProfileOperation createSlotInternal(Profile profile) {
if (profile.isLocked()) {
return ProfileOperation.locked(MSG_PROFILE_LOCKED_CREATE);
}
int newSlotId = 0;
while (profile.getSlots().containsKey(newSlotId)) {
newSlotId++;
}
if (!allowSlotPermission(profile.player)) {
return ProfileOperation.error(MSG_MAX_SLOTS_REACHED);
}
if (profile.player != null) {
List<IProfileData> dataList = new ArrayList<>(profileTypes.values());
dataList.sort(Comparator.comparingInt(IProfileData::getSwitchPriority));
for (IProfileData pd : dataList) {
if (pd.verifySwitch(profile.player).getResult() != EnumProfileOperation.SUCCESS) {
return pd.verifySwitch(profile.player);
}
}
}
Slot newSlot = new Slot(newSlotId, "Slot " + newSlotId);
newSlot.setLastLoaded(System.currentTimeMillis());
profile.getSlots().put(newSlotId, newSlot);
if(profile.player != null){
verifySlotQuests(profile.player);
save(profile.player, profile);
}
return ProfileOperation.success(MSG_NEW_SLOT_CREATED);
}
private ProfileOperation changeSlotInternal(Profile profile, int newSlotId) {
if (profile.isLocked()) {
return ProfileOperation.locked(MSG_PROFILE_LOCKED_CHANGE);
}
if (profile.getCurrentSlotId() == newSlotId) {
return ProfileOperation.error(MSG_SLOT_ALREADY_ACTIVE);
}
if (!profile.getSlots().containsKey(newSlotId)) {
return ProfileOperation.error(MSG_SLOT_NOT_EXIST);
}
if (profile.player != null) {
if (ConfigMain.RegionProfileSwitching) {
boolean allowed = hasPermission(profile.player, PROFILE_REGION_BYPASS);
if (!allowed) {
int playerDim = profile.player.dimension;
int playerX = (int) profile.player.posX;
int playerY = (int) profile.player.posY;
int playerZ = (int) profile.player.posZ;
for (List<Integer> region : ConfigMain.RestrictedProfileRegions) {
if (region.size() == 7) {
int dim = region.get(0);
int x1 = Math.min(region.get(1), region.get(4));
int y1 = Math.min(region.get(2), region.get(5));
int z1 = Math.min(region.get(3), region.get(6));
int x2 = Math.max(region.get(1), region.get(4));
int y2 = Math.max(region.get(2), region.get(5));
int z2 = Math.max(region.get(3), region.get(6));
if (playerDim == dim &&
playerX >= x1 && playerX <= x2 &&
playerY >= y1 && playerY <= y2 &&
playerZ >= z1 && playerZ <= z2) {
allowed = true;
break;
}
}
}
}
if (!allowed) {
return ProfileOperation.error(MSG_REGION_NOT_ALLOWED);
}
}
List<IProfileData> dataList = new ArrayList<>(profileTypes.values());
dataList.sort(Comparator.comparingInt(IProfileData::getSwitchPriority));
for (IProfileData pd : dataList) {
if (pd.verifySwitch(profile.player).getResult() != EnumProfileOperation.SUCCESS) {
return pd.verifySwitch(profile.player);
}
}
saveSlotData(profile.player);
profile.currentSlotId = newSlotId;
loadSlotData(profile.player);
PlayerData pdata = PlayerData.get(profile.player);
pdata.profileSlot = newSlotId;
pdata.save();
if(ConfigMain.AttributesEnabled)
AttributeController.getTracker(profile.player).recalcAttributes(profile.player);
} else {
return ProfileOperation.error(MSG_PLAYER_NOT_FOUND);
}
return ProfileOperation.success(MSG_CHANGE_SUCCESS);
}
public ProfileOperation cloneSlot(EntityPlayer player, int sourceSlotId, int destinationSlotId, boolean temporary) {
Profile profile = getProfile(player);
if (profile == null)
return ProfileOperation.error(MSG_PLAYER_NOT_FOUND);
ProfileOperation result = cloneSlotInternal(profile, sourceSlotId, destinationSlotId, temporary);
if (result.getResult() == EnumProfileOperation.SUCCESS && player != null) {
save(player, profile);
}
return result;
}
public ProfileOperation cloneSlot(UUID uuid, int sourceSlotId, int destinationSlotId, boolean temporary) {
Profile profile = getProfile(uuid);
if (profile == null)
return ProfileOperation.error(MSG_PLAYER_NOT_FOUND);
ProfileOperation result = cloneSlotInternal(profile, sourceSlotId, destinationSlotId, temporary);
if (result.getResult() == EnumProfileOperation.SUCCESS) {
if (profile.player != null)
save(profile.player, profile);
else
saveOffline(profile, uuid);
}
return result;
}
public ProfileOperation cloneSlot(String username, int sourceSlotId, int destinationSlotId, boolean temporary) {
Profile profile = getProfile(username);
if (profile == null)
return ProfileOperation.error(MSG_PLAYER_NOT_FOUND);
ProfileOperation result = cloneSlotInternal(profile, sourceSlotId, destinationSlotId, temporary);
if (result.getResult() == EnumProfileOperation.SUCCESS) {
if (profile.player != null)
save(profile.player, profile);
else {
UUID uuid = getUUIDFromUsername(username);
if (uuid != null)
saveOffline(profile, uuid);
}
}
return result;
}
public ProfileOperation removeSlot(EntityPlayer player, int slotId) {
Profile profile = getProfile(player);
if (profile == null)
return ProfileOperation.error(MSG_PLAYER_NOT_FOUND);
ProfileOperation result = removeSlotInternal(profile, slotId);
if (result.getResult() == EnumProfileOperation.SUCCESS && player != null) {
save(player, profile);
}
return result;
}
public ProfileOperation removeSlot(String username, int slotId) {
Profile profile = getProfile(username);
if (profile == null)
return ProfileOperation.error(MSG_PLAYER_NOT_FOUND);
ProfileOperation result = removeSlotInternal(profile, slotId);
if (result.getResult() == EnumProfileOperation.SUCCESS) {
if (profile.player != null)
save(profile.player, profile);
else {
UUID uuid = getUUIDFromUsername(username);
if (uuid != null)
saveOffline(profile, uuid);
}
}
return result;
}
public ProfileOperation changeSlot(EntityPlayer player, int newSlotId) {
Profile profile = getProfile(player);
if (profile == null)
return ProfileOperation.error(MSG_PLAYER_NOT_FOUND);
ProfileOperation result = changeSlotInternal(profile, newSlotId);
if (result.getResult() == EnumProfileOperation.SUCCESS && player != null)
save(player, profile);
return result;
}
public ProfileOperation changeSlot(String username, int newSlotId) {
Profile profile = getProfile(username);
if (profile == null)
return ProfileOperation.error(MSG_PLAYER_NOT_FOUND);
ProfileOperation result = changeSlotInternal(profile, newSlotId);
if (result.getResult() == EnumProfileOperation.SUCCESS) {
if (profile.player != null)
save(profile.player, profile);
else {
UUID uuid = getUUIDFromUsername(username);
if (uuid != null)
saveOffline(profile, uuid);
}
}
return result;
}
public void saveSlotData(EntityPlayer player) {
if (player == null || !activeProfiles.containsKey(player.getUniqueID()))
return;
Profile profile = activeProfiles.get(player.getUniqueID());
if (profile.isLocked()) {
return;
}
ISlot slot = profile.getSlots().get(profile.getCurrentSlotId());
if (slot == null) {
slot = new Slot(profile.getCurrentSlotId(), "Slot " + profile.getCurrentSlotId());
profile.getSlots().put(profile.getCurrentSlotId(), slot);
}
for (IProfileData profileData : profileTypes.values()) {
NBTTagCompound cloned = (NBTTagCompound) profileData.getCurrentNBT(player).copy();
slot.setComponentData(profileData.getTagName(), cloned);
}
slot.setLastLoaded(System.currentTimeMillis());
}
public void loadSlotData(EntityPlayer player) {
if (player == null || !activeProfiles.containsKey(player.getUniqueID()))
return;
Profile profile = activeProfiles.get(player.getUniqueID());
ISlot slot = profile.getSlots().get(profile.getCurrentSlotId());
if (slot == null)
return;
for (IProfileData profileData : profileTypes.values()) {
NBTTagCompound data;
if (slot.getComponents().containsKey(profileData.getTagName()))
data = slot.getComponentData(profileData.getTagName());
else
data = new NBTTagCompound();
profileData.setNBT(player, data);
}
for (IProfileData profileData : profileTypes.values()) {
profileData.save(player);
}
}
public List<ProfileInfoEntry> getProfileInfo(EntityPlayer player, int slotId) {
List<ProfileInfoEntry> infoList = new ArrayList<>();
Profile profile = getProfile(player);
if (profile == null)
return infoList;
List<IProfileData> dataList = new ArrayList<>(profileTypes.values());
dataList.sort(Comparator.comparingInt(IProfileData::getSwitchPriority));
if (slotId == profile.getCurrentSlotId()) {
for (IProfileData pd : dataList) {
NBTTagCompound currentNBT = pd.getCurrentNBT(player);
List<ProfileInfoEntry> subInfo = pd.getInfo(player, currentNBT);
infoList.addAll(subInfo);
}
} else {
if (!profile.getSlots().containsKey(slotId))
return infoList;
ISlot slot = profile.getSlots().get(slotId);
for (IProfileData pd : dataList) {
if (slot.getComponents().containsKey(pd.getTagName())) {
NBTTagCompound sub = slot.getComponentData(pd.getTagName());
List<ProfileInfoEntry> subInfo = pd.getInfo(player, sub);
infoList.addAll(subInfo);
}
}
}
return infoList;
}
public boolean allowSlotPermission(EntityPlayer player) {
Profile profile = getProfile(player);
int currentSlots = profile.getSlots().size();
if (CustomNpcsPermissions.hasCustomPermission(player, "customnpcs.profile.max.*")) {
return true;
}
int highestAllowed = 0;
for (int i = 1; i <= 50; i++) {
String perm = "customnpcs.profile.max." + i;
if (CustomNpcsPermissions.hasCustomPermission(player, perm)) {
highestAllowed = i;
}
}
if (highestAllowed == 0) {
highestAllowed = 1;
}
return currentSlots < highestAllowed;
}
@Override
public IProfile getProfile(IPlayer player) {
if(player == null || player.getMCEntity() == null)
return null;
return getProfile((EntityPlayer) player.getMCEntity());
}
@Override
public boolean changeSlot(IPlayer player, int slotID) {
if(player == null || player.getMCEntity() == null)
return false;
EntityPlayer entityPlayer = (EntityPlayer) player.getMCEntity();
ProfileOperation profileOperation = changeSlot(entityPlayer, slotID);
return profileOperation.getResult() == EnumProfileOperation.SUCCESS;
}
@Override
public boolean hasSlot(IPlayer player, int slotID) {
if(player == null || player.getMCEntity() == null)
return false;
EntityPlayer entityPlayer = (EntityPlayer) player.getMCEntity();
Profile profile = getProfile(entityPlayer);
if(profile == null)
return false;
return profile.getSlots().containsKey(slotID);
}
@Override
public boolean removeSlot(IPlayer player, int slotID) {
if(player == null || player.getMCEntity() == null)
return false;
EntityPlayer entityPlayer = (EntityPlayer) player.getMCEntity();
ProfileOperation profileOperation = removeSlot(entityPlayer, slotID);
return profileOperation.getResult() == EnumProfileOperation.SUCCESS;
}
@Override
public IPlayerData getSlotPlayerData(IPlayer player, int slotID) {
PlayerData playerData;
if(player == null || player.getMCEntity() == null)
return null;
EntityPlayer entityPlayer = (EntityPlayer) player.getMCEntity();
Profile profile = getProfile(entityPlayer);
if(profile == null)
return null;
return getSlotPlayerData(entityPlayer, slotID);
}
@Override
public void saveSlotData(IPlayer player) {
if(player == null || player.getMCEntity() == null)
return;
EntityPlayer entityPlayer = (EntityPlayer) player.getMCEntity();
saveSlotData(entityPlayer);
}
public IPlayerData getSlotPlayerData(EntityPlayer player, int slotID) {
PlayerData playerData;
Profile profile = getProfile(player);
if(profile == null)
return null;
if(profile.currentSlotId == slotID){
playerData = PlayerData.get(player);
} else {
Slot slot = (Slot) profile.getSlots().get(slotID);
playerData = getSlotPlayerData(player, slot);
}
return playerData;
}
public PlayerData getSlotPlayerData(EntityPlayer player, Slot slot) {
if(slot == null)
return null;
PlayerData playerData = new PlayerData();
playerData.player = player;
NBTTagCompound compound = slot.getComponentData(new CNPCData().getTagName());
if(compound == null)
compound = new NBTTagCompound();
playerData.setNBT(compound);
return playerData;
}
public void verifySlotQuests(EntityPlayer player) {
Profile profile = getProfile(player);
if (profile == null) {
return;
}
Map<Integer, Long> universalFinished = new HashMap<>();
for (Integer questId : QuestController.Instance.sharedQuests.keySet()) {
long maxTime = 0;
for (ISlot slot : profile.getSlots().values()) {
IPlayerData data = getSlotPlayerData(player, slot.getId());
if (data == null) {
continue;
}
PlayerQuestData questData = (PlayerQuestData) data.getQuestData();
Long t = questData.finishedQuests.get(questId);
if (t != null && t > maxTime) {
maxTime = t;
}
}
if (maxTime > 0) {
universalFinished.put(questId, maxTime);
}
}
// Push the universal shared completion times into every slot.
for (ISlot slot : profile.getSlots().values()) {
IPlayerData data = getSlotPlayerData(player, slot.getId());
if (data != null) {
PlayerData playerData = (PlayerData) data;
PlayerQuestData questData = (PlayerQuestData) data.getQuestData();
questData.finishedQuests.putAll(universalFinished);
slot.setComponentData(new CNPCData().getTagName(), playerData.getNBT());
}
}
}
public void shareQuestCompletion(EntityPlayer player, int questId, long completeTime) {
Profile profile = getProfile(player);
if (profile == null) {
return;
}
for (ISlot slot : profile.getSlots().values()) {
IPlayerData playerData = getSlotPlayerData(player, slot.getId());
if (playerData != null) {
PlayerQuestData questData = (PlayerQuestData) playerData.getQuestData();
Long existing = questData.finishedQuests.get(questId);
if (existing == null || completeTime > existing) {
questData.finishedQuests.put(questId, completeTime);
}
playerData.save();
}
}
save(player, profile);
}
}
@@ -0,0 +1,676 @@
package kamkeel.npcs.controllers;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import kamkeel.npcs.addon.DBCAddon;
import kamkeel.npcs.network.PacketHandler;
import kamkeel.npcs.network.enums.EnumSyncAction;
import kamkeel.npcs.network.enums.EnumSyncType;
import kamkeel.npcs.network.packets.data.LoginPacket;
import kamkeel.npcs.network.packets.data.large.SyncEffectPacket;
import kamkeel.npcs.network.packets.data.large.SyncPacket;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import noppes.npcs.client.ClientCacheHandler;
import noppes.npcs.controllers.*;
import noppes.npcs.controllers.data.*;
import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap;
public class SyncController {
public static void syncPlayer(EntityPlayerMP player){
// Login Packet
PacketHandler.Instance.sendToPlayer(new LoginPacket(), player);
// 1) Factions
PacketHandler.Instance.sendToPlayer(new SyncPacket(
EnumSyncType.FACTION,
EnumSyncAction.RELOAD,
-1,
factionsNBT()
), player);
// 2) Dialog Categories
PacketHandler.Instance.sendToPlayer(new SyncPacket(
EnumSyncType.DIALOG_CATEGORY,
EnumSyncAction.RELOAD,
-1,
dialogCategoriesNBT()
), player);
// 3) Quest Categories
PacketHandler.Instance.sendToPlayer(new SyncPacket(
EnumSyncType.QUEST_CATEGORY,
EnumSyncAction.RELOAD,
-1,
questCategoriesNBT()
), player);
// 4) Workbench Recipes
PacketHandler.Instance.sendToPlayer(new SyncPacket(
EnumSyncType.WORKBENCH_RECIPES,
EnumSyncAction.RELOAD,
-1,
workbenchNBT()
), player);
// 5) Carpentry Recipes
PacketHandler.Instance.sendToPlayer(new SyncPacket(
EnumSyncType.CARPENTRY_RECIPES,
EnumSyncAction.RELOAD,
-1,
carpentryNBT()
), player);
PacketHandler.Instance.sendToPlayer(new SyncPacket(
EnumSyncType.ANVIL_RECIPES,
EnumSyncAction.RELOAD,
-1,
anvilNBT()
), player);
PacketHandler.Instance.sendToPlayer(new SyncPacket(
EnumSyncType.CUSTOM_EFFECTS,
EnumSyncAction.RELOAD,
-1,
customEffectsNBT()
), player);
PacketHandler.Instance.sendToPlayer(new SyncPacket(
EnumSyncType.MAGIC,
EnumSyncAction.RELOAD,
-1,
magicsNBT()
), player);
PacketHandler.Instance.sendToPlayer(new SyncPacket(
EnumSyncType.MAGIC_CYCLE,
EnumSyncAction.RELOAD,
-1,
magicCyclesNBT()
), player);
DBCAddon.instance.syncPlayer(player);
syncPlayerData(player, false);
}
public static NBTTagCompound workbenchNBT(){
RecipeController controller = RecipeController.Instance;
NBTTagList list = new NBTTagList();
NBTTagCompound compound = new NBTTagCompound();
for(RecipeCarpentry recipe : controller.globalRecipes.values()){
list.appendTag(recipe.writeNBT());
}
compound.setTag("recipes", list);
return compound;
}
public static NBTTagCompound carpentryNBT(){
RecipeController controller = RecipeController.Instance;
NBTTagList list = new NBTTagList();
NBTTagCompound compound = new NBTTagCompound();
for(RecipeCarpentry recipe : controller.carpentryRecipes.values()){
list.appendTag(recipe.writeNBT());
}
compound.setTag("recipes", list);
return compound;
}
public static NBTTagCompound anvilNBT(){
RecipeController controller = RecipeController.Instance;
NBTTagList list = new NBTTagList();
NBTTagCompound compound = new NBTTagCompound();
for(RecipeAnvil recipe : controller.anvilRecipes.values()){
list.appendTag(recipe.writeNBT());
}
compound.setTag("recipes", list);
return compound;
}
public static NBTTagCompound factionsNBT(){
NBTTagList list = new NBTTagList();
NBTTagCompound compound = new NBTTagCompound();
for(Faction faction : FactionController.getInstance().factions.values()){
NBTTagCompound factioNBT = new NBTTagCompound();
faction.writeNBT(factioNBT);
list.appendTag(factioNBT);
}
compound.setTag("Factions", list);
return compound;
}
public static NBTTagCompound dialogCategoriesNBT(){
NBTTagCompound compound = new NBTTagCompound();
NBTTagList categoryList = new NBTTagList();
for(DialogCategory category : DialogController.Instance.categories.values()){
NBTTagCompound questCompound = new NBTTagCompound();
NBTTagList dialogList = new NBTTagList();
for(int dialogID : category.dialogs.keySet()){
Dialog quest = category.dialogs.get(dialogID);
dialogList.appendTag(quest.writeToNBT(new NBTTagCompound()));
}
questCompound.setTag("Data", dialogList);
questCompound.setTag("CatNBT", category.writeSmallNBT(new NBTTagCompound()));
categoryList.appendTag(questCompound);
}
compound.setTag("DialogCategories", categoryList);
return compound;
}
public static NBTTagCompound questCategoriesNBT(){
NBTTagCompound compound = new NBTTagCompound();
NBTTagList categoryList = new NBTTagList();
for(QuestCategory category : QuestController.Instance.categories.values()){
NBTTagCompound questCompound = new NBTTagCompound();;
NBTTagList questList = new NBTTagList();
for(int questID : category.quests.keySet()){
Quest quest = category.quests.get(questID);
questList.appendTag(quest.writeToNBT(new NBTTagCompound()));
}
questCompound.setTag("Data", questList);
questCompound.setTag("CatNBT", category.writeSmallNBT(new NBTTagCompound()));
categoryList.appendTag(questCompound);
}
compound.setTag("QuestCategories", categoryList);
return compound;
}
public static NBTTagCompound customEffectsNBT(){
NBTTagList list = new NBTTagList();
NBTTagCompound compound = new NBTTagCompound();
for (CustomEffect effect : CustomEffectController.getInstance().getCustomEffects().values()) {
list.appendTag(effect.writeToNBT(false));
}
compound.setTag("Data", list);
return compound;
}
public static NBTTagCompound magicsNBT(){
NBTTagList list = new NBTTagList();
NBTTagCompound compound = new NBTTagCompound();
for (Magic magic : MagicController.getInstance().magics.values()) {
NBTTagCompound magicCompound = new NBTTagCompound();
magic.writeNBT(magicCompound);
list.appendTag(magicCompound);
}
compound.setTag("Data", list);
return compound;
}
public static NBTTagCompound magicCyclesNBT(){
NBTTagList list = new NBTTagList();
NBTTagCompound compound = new NBTTagCompound();
for (MagicCycle cycle : MagicController.getInstance().cycles.values()) {
NBTTagCompound cycleCompound = new NBTTagCompound();
cycle.writeNBT(cycleCompound);
list.appendTag(cycleCompound);
}
compound.setTag("Data", list);
return compound;
}
public static void syncPlayerData(EntityPlayerMP player, boolean update){
PlayerData data = PlayerData.get(player);
if(data != null){
if(update){
PacketHandler.Instance.sendToPlayer(new SyncPacket(
EnumSyncType.PLAYERDATA,
EnumSyncAction.UPDATE,
-1,
data.getSyncNBT())
, player);
} else {
PacketHandler.Instance.sendToPlayer(new SyncPacket(
EnumSyncType.PLAYERDATA,
EnumSyncAction.RELOAD,
-1,
data.getSyncNBTFull()), player);
}
}
}
public static void syncRemove(EnumSyncType enumSyncType, int id){
PacketHandler.Instance.sendToAll(new SyncPacket(
enumSyncType,
EnumSyncAction.REMOVE,
id,
new NBTTagCompound()
));
}
public static void syncAllDialogs() {
PacketHandler.Instance.sendToAll(new SyncPacket(
EnumSyncType.DIALOG_CATEGORY,
EnumSyncAction.RELOAD,
-1,
dialogCategoriesNBT()
));
}
public static void syncAllQuests() {
PacketHandler.Instance.sendToAll(new SyncPacket(
EnumSyncType.QUEST_CATEGORY,
EnumSyncAction.RELOAD,
-1,
questCategoriesNBT()
));
}
public static void syncAllWorkbenchRecipes() {
PacketHandler.Instance.sendToAll(new SyncPacket(
EnumSyncType.WORKBENCH_RECIPES,
EnumSyncAction.RELOAD,
-1,
workbenchNBT()
));
}
public static void syncAllCarpentryRecipes() {
PacketHandler.Instance.sendToAll(new SyncPacket(
EnumSyncType.CARPENTRY_RECIPES,
EnumSyncAction.RELOAD,
-1,
carpentryNBT()
));
}
public static void syncAllAnvilRecipes() {
PacketHandler.Instance.sendToAll(new SyncPacket(
EnumSyncType.ANVIL_RECIPES,
EnumSyncAction.RELOAD,
-1,
anvilNBT()
));
}
public static void syncAllCustomEffects() {
PacketHandler.Instance.sendToAll(new SyncPacket(
EnumSyncType.CUSTOM_EFFECTS,
EnumSyncAction.RELOAD,
-1,
customEffectsNBT()
));
}
@SideOnly(Side.CLIENT)
public static void clientSync(EnumSyncType enumSyncType, NBTTagCompound fullCompound) {
switch (enumSyncType){
case FACTION: {
NBTTagList list = fullCompound.getTagList("Factions", 10);
for (int i = 0; i < list.tagCount(); i++) {
Faction faction = new Faction();
faction.readNBT(list.getCompoundTagAt(i));
FactionController.getInstance().factionsSync.put(faction.id, faction);
}
FactionController.getInstance().factions = FactionController.getInstance().factionsSync;
FactionController.getInstance().factionsSync = new HashMap<Integer, Faction>();
break;
}
case DIALOG_CATEGORY: {
if(!fullCompound.hasNoTags()){
NBTTagList categories = fullCompound.getTagList("DialogCategories", 10);
for(int j = 0; j < fullCompound.getTagList("DialogCategories", 10).tagCount(); j++) {
NBTTagCompound categoryCompound = categories.getCompoundTagAt(j);
if(categoryCompound.hasNoTags())
continue;
DialogCategory category = new DialogCategory();
category.readSmallNBT(categoryCompound.getCompoundTag("CatNBT"));
NBTTagList dialogList = categoryCompound.getTagList("Data", 10);
if(DialogController.Instance.categoriesSync.containsKey(category.id)){
category = DialogController.Instance.categoriesSync.get(category.id);
category.readSmallNBT(categoryCompound.getCompoundTag("CatNBT"));
}
for(int i = 0; i < dialogList.tagCount(); i++)
{
Dialog dialog = new Dialog();
dialog.readNBT(dialogList.getCompoundTagAt(i));
dialog.category = category;
category.dialogs.put(dialog.id, dialog);
}
DialogController.Instance.categoriesSync.put(category.id, category);
}
}
HashMap<Integer, Dialog> dialogs = new HashMap<Integer, Dialog>();
for(DialogCategory category : DialogController.Instance.categoriesSync.values()){
for(Dialog dialog : category.dialogs.values()){
dialogs.put(dialog.id, dialog);
}
}
DialogController.Instance.categories = DialogController.Instance.categoriesSync;
DialogController.Instance.dialogs = dialogs;
DialogController.Instance.categoriesSync = new HashMap<Integer, DialogCategory>();
break;
}
case QUEST_CATEGORY: {
if(!fullCompound.hasNoTags()){
NBTTagList categories = fullCompound.getTagList("QuestCategories", 10);
for(int j = 0; j < fullCompound.getTagList("QuestCategories", 10).tagCount(); j++) {
NBTTagCompound categoryCompound = categories.getCompoundTagAt(j);
if(categoryCompound.hasNoTags())
continue;
QuestCategory category = new QuestCategory();
category.readSmallNBT(categoryCompound.getCompoundTag("CatNBT"));
NBTTagList questList = categoryCompound.getTagList("Data", 10);
if(QuestController.Instance.categoriesSync.containsKey(category.id)){
category = QuestController.Instance.categoriesSync.get(category.id);
category.readSmallNBT(categoryCompound.getCompoundTag("CatNBT"));
}
for(int i = 0; i < questList.tagCount(); i++)
{
Quest quest = new Quest();
quest.readNBT(questList.getCompoundTagAt(i));
quest.category = category;
category.quests.put(quest.id, quest);
}
QuestController.Instance.categoriesSync.put(category.id, category);
}
}
HashMap<Integer,Quest> quests = new HashMap<Integer, Quest>();
for(QuestCategory category : QuestController.Instance.categoriesSync.values()){
for(Quest quest : category.quests.values()){
quests.put(quest.id, quest);
}
}
QuestController.Instance.categories = QuestController.Instance.categoriesSync;
QuestController.Instance.quests = quests;
QuestController.Instance.categoriesSync = new HashMap<Integer, QuestCategory>();
break;
}
case PLAYERDATA: {
ClientCacheHandler.playerData.setSyncNBTFull(fullCompound);
break;
}
case MAGIC: {
NBTTagList list = fullCompound.getTagList("Data", 10);
MagicController mc = MagicController.getInstance();
mc.magicSync.clear();
for (int i = 0; i < list.tagCount(); i++) {
Magic magic = new Magic();
magic.readNBT(list.getCompoundTagAt(i));
mc.magicSync.put(magic.id, magic);
}
mc.magics.clear();
mc.magics.putAll(mc.magicSync);
mc.magicSync.clear();
break;
}
case MAGIC_CYCLE: {
NBTTagList list = fullCompound.getTagList("Data", 10);
MagicController mc = MagicController.getInstance();
mc.cyclesSync.clear();
for (int i = 0; i < list.tagCount(); i++) {
MagicCycle cycle = new MagicCycle();
cycle.readNBT(list.getCompoundTagAt(i));
mc.cyclesSync.put(cycle.id, cycle);
}
mc.cycles.clear();
mc.cycles.putAll(mc.cyclesSync);
mc.cyclesSync.clear();
break;
}
case WORKBENCH_RECIPES: {
NBTTagList list = fullCompound.getTagList("recipes", 10);
if(list == null)
return;
for(int i = 0; i < list.tagCount(); i++)
{
RecipeCarpentry recipe = RecipeCarpentry.read(list.getCompoundTagAt(i));
RecipeController.syncRecipes.put(recipe.id,recipe);
}
RecipeController.reloadGlobalRecipes(RecipeController.syncRecipes);
RecipeController.syncRecipes = new HashMap<Integer, RecipeCarpentry>();
break;
}
case CARPENTRY_RECIPES: {
NBTTagList list = fullCompound.getTagList("recipes", 10);
if(list == null)
return;
for(int i = 0; i < list.tagCount(); i++)
{
RecipeCarpentry recipe = RecipeCarpentry.read(list.getCompoundTagAt(i));
RecipeController.syncRecipes.put(recipe.id,recipe);
}
RecipeController.Instance.carpentryRecipes = RecipeController.syncRecipes;
RecipeController.syncRecipes = new HashMap<Integer, RecipeCarpentry>();
break;
}
case ANVIL_RECIPES: {
NBTTagList list = fullCompound.getTagList("recipes", 10);
if(list == null)
return;
for(int i = 0; i < list.tagCount(); i++)
{
RecipeAnvil recipe = RecipeAnvil.read(list.getCompoundTagAt(i));
RecipeController.syncAnvilRecipes.put(recipe.id, recipe);
}
RecipeController.Instance.anvilRecipes = RecipeController.syncAnvilRecipes;
RecipeController.syncAnvilRecipes = new HashMap<Integer, RecipeAnvil>();
break;
}
case CUSTOM_EFFECTS: {
NBTTagList list = fullCompound.getTagList("Data", 10);
CustomEffectController ce = CustomEffectController.getInstance();
ce.customEffectsSync.clear();
for (int i = 0; i < list.tagCount(); i++) {
CustomEffect effect = new CustomEffect();
effect.readFromNBT(list.getCompoundTagAt(i));
ClientCacheHandler.getImageData(effect.icon);
ce.customEffectsSync.put(effect.id, effect);
}
ce.getCustomEffects().clear();
ce.getCustomEffects().putAll(ce.customEffectsSync);
ce.customEffectsSync.clear();
break;
}
}
}
/**
* Update Related Tasks
*/
@SideOnly(Side.CLIENT)
public static void clientUpdate(EnumSyncType enumSyncType, int category_id, NBTTagCompound compound) {
switch (enumSyncType){
case FACTION: {
Faction faction = new Faction();
faction.readNBT(compound);
FactionController.getInstance().factions.put(faction.id, faction);
break;
}
case DIALOG: {
DialogCategory category = DialogController.Instance.categories.get(category_id);
Dialog dialog = new Dialog();
dialog.category = category;
dialog.readNBT(compound);
DialogController.Instance.dialogs.put(dialog.id, dialog);
category.dialogs.put(dialog.id, dialog);
break;
}
case QUEST: {
QuestCategory category = QuestController.Instance.categories.get(category_id);
Quest quest = new Quest();
quest.category = category;
quest.readNBT(compound);
QuestController.Instance.quests.put(quest.id, quest);
category.quests.put(quest.id, quest);
break;
}
case QUEST_CATEGORY: {
QuestCategory category = new QuestCategory();
category.readSmallNBT(compound.getCompoundTag("CatNBT"));
NBTTagList list = compound.getTagList("Data", 10);
if(QuestController.Instance.categoriesSync.containsKey(category.id)){
category = QuestController.Instance.categoriesSync.get(category.id);
category.readSmallNBT(compound.getCompoundTag("CatNBT"));
}
for(int i = 0; i < list.tagCount(); i++)
{
Quest quest = new Quest();
quest.readNBT(list.getCompoundTagAt(i));
quest.category = category;
category.quests.put(quest.id, quest);
}
QuestController.Instance.categories.put(category.id, category);
break;
}
case DIALOG_CATEGORY: {
DialogCategory category = new DialogCategory();
category.readSmallNBT(compound.getCompoundTag("CatNBT"));
NBTTagList list = compound.getTagList("Data", 10);
if(DialogController.Instance.categoriesSync.containsKey(category.id)){
category = DialogController.Instance.categoriesSync.get(category.id);
category.readSmallNBT(compound.getCompoundTag("CatNBT"));
}
for(int i = 0; i < list.tagCount(); i++)
{
Dialog dialog = new Dialog();
dialog.readNBT(list.getCompoundTagAt(i));
dialog.category = category;
category.dialogs.put(dialog.id, dialog);
}
DialogController.Instance.categories.put(category.id, category);
break;
}
case MAGIC_CYCLE: {
MagicCycle cycle = new MagicCycle();
cycle.readNBT(compound);
MagicController.getInstance().cycles.put(cycle.id, cycle);
break;
}
case MAGIC: {
Magic magic = new Magic();
magic.readNBT(compound);
MagicController.getInstance().magics.put(magic.id, magic);
break;
}
case PLAYERDATA: {
ClientCacheHandler.playerData.setSyncNBT(compound);
break;
}
case CUSTOM_EFFECTS: {
CustomEffect effect = new CustomEffect();
effect.readFromNBT(compound);
ClientCacheHandler.getImageData(effect.icon);
CustomEffectController.Instance.getCustomEffects().put(effect.id, effect);
break;
}
}
}
public static void syncUpdate(EnumSyncType type, int cat, NBTTagCompound compound) {
PacketHandler.Instance.sendToAll(new SyncPacket(
type,
EnumSyncAction.UPDATE,
cat,
compound
));
}
public static NBTTagCompound updateQuestCat(QuestCategory questCategory) {
NBTTagCompound questCompound = new NBTTagCompound();
NBTTagList questList = new NBTTagList();
for(int questID : questCategory.quests.keySet()){
Quest quest = questCategory.quests.get(questID);
questList.appendTag(quest.writeToNBT(new NBTTagCompound()));
}
questCompound.setTag("Data", questList);
questCompound.setTag("CatNBT", questCategory.writeSmallNBT(new NBTTagCompound()));
return questCompound;
}
public static NBTTagCompound updateDialogCat(DialogCategory dialogCategory) {
NBTTagCompound dialogCompound = new NBTTagCompound();
NBTTagList dialogList = new NBTTagList();
for(int questID : dialogCategory.dialogs.keySet()){
Dialog dialog = dialogCategory.dialogs.get(questID);
dialogList.appendTag(dialog.writeToNBT(new NBTTagCompound()));
}
dialogCompound.setTag("Data", dialogList);
dialogCompound.setTag("CatNBT", dialogCategory.writeSmallNBT(new NBTTagCompound()));
return dialogCompound;
}
@SideOnly(Side.CLIENT)
public static void clientSyncRemove(EnumSyncType enumSyncType, int id) {
switch (enumSyncType){
case FACTION:
FactionController.getInstance().factions.remove(id);
break;
case DIALOG:
Dialog dialog = DialogController.Instance.dialogs.remove(id);
if(dialog != null) {
dialog.category.dialogs.remove(id);
}
break;
case DIALOG_CATEGORY:
DialogCategory dialogCategory = DialogController.Instance.categories.remove(id);
if(dialogCategory != null) {
DialogController.Instance.dialogs.keySet().removeAll(dialogCategory.dialogs.keySet());
}
break;
case QUEST:
Quest quest = QuestController.Instance.quests.remove(id);
if(quest != null) {
quest.category.quests.remove(id);
}
break;
case QUEST_CATEGORY:
QuestCategory questCategory = QuestController.Instance.categories.remove(id);
if(questCategory != null) {
QuestController.Instance.quests.keySet().removeAll(questCategory.quests.keySet());
}
break;
case MAGIC:
for(MagicCycle cycle : MagicController.getInstance().cycles.values()){
cycle.associations.remove(id);
}
MagicController.getInstance().cycles.remove(id);
break;
case MAGIC_CYCLE:
MagicController.getInstance().cycles.remove(id);
break;
case CUSTOM_EFFECTS:
CustomEffectController.Instance.getCustomEffects().remove(id);
break;
}
}
public static void syncEffects(EntityPlayerMP playerMP){
ConcurrentHashMap<EffectKey, PlayerEffect> playerEffects = CustomEffectController.getInstance().getPlayerEffects(playerMP);
PlayerData playerData = PlayerData.get(playerMP);
playerData.effectData.setEffects(playerEffects);
NBTTagCompound compound = playerData.getPlayerEffects();
PacketHandler.Instance.sendToPlayer(new SyncEffectPacket(compound), playerMP);
}
@SideOnly(Side.CLIENT)
public static void clientSyncEffects(NBTTagCompound compound) {
PlayerData playerData = PlayerData.get(Minecraft.getMinecraft().thePlayer);
if(playerData != null){
playerData.setPlayerEffects(compound);
}
}
}
@@ -0,0 +1,55 @@
package kamkeel.npcs.controllers.data.attribute;
public class AttributeDefinition {
private final String key;
private String translationKey;// e.g., "main_attack_flat"
private final String displayName; // Human‑readable name
private final char colorCode;
private final AttributeValueType attributeValueType;
private final AttributeSection section;
public AttributeDefinition(String key, String displayName, char colorCode, AttributeValueType attributeValueType, AttributeSection section) {
this.key = key;
this.translationKey = "rpgcore:attribute." + key;
this.displayName = displayName;
this.attributeValueType = attributeValueType;
this.section = section;
this.colorCode = colorCode;
}
public String getKey() {
return key;
}
public String getDisplayName() {
return displayName;
}
public String getTranslationKey() {
return translationKey;
}
public void setTranslationKey(String translationKey) {
this.translationKey = translationKey;
}
public AttributeValueType getValueType() {
return attributeValueType;
}
public AttributeSection getSection() {
return section;
}
public char getColorCode() {
return colorCode;
}
public enum AttributeSection {
BASE,
MODIFIER,
STATS,
INFO,
EXTRA;
}
}
@@ -0,0 +1,7 @@
package kamkeel.npcs.controllers.data.attribute;
public enum AttributeValueType {
FLAT, // e.g., +10 Health or +3 Damage
PERCENT, // e.g., +0.25 means +25% bonus
MAGIC // Represents a container of magic–based values (summed up as a float)
}
@@ -0,0 +1,10 @@
package kamkeel.npcs.controllers.data.attribute;
/**
* IAttributeInstance represents an instance of an attribute (with a base value and applied modifiers).
*/
public interface ICustomAttribute {
AttributeDefinition getAttribute();
float getValue();
void setValue(float value);
}
@@ -0,0 +1,27 @@
package kamkeel.npcs.controllers.data.attribute;
public class PlayerAttribute implements ICustomAttribute {
private final AttributeDefinition attribute;
private float baseValue;
public PlayerAttribute(AttributeDefinition attribute, float baseValue) {
this.attribute = attribute;
this.baseValue = baseValue;
}
@Override
public AttributeDefinition getAttribute() {
return attribute;
}
@Override
public float getValue() {
return baseValue;
}
@Override
public void setValue(float value) {
this.baseValue = value;
}
}
@@ -0,0 +1,29 @@
package kamkeel.npcs.controllers.data.attribute;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
/**
* CustomAttributeMap holds a set of attribute instances for an entity (or item).
*/
public class PlayerAttributeMap {
private final Map<AttributeDefinition, ICustomAttribute> map = new HashMap<>();
public ICustomAttribute registerAttribute(AttributeDefinition attribute, float baseValue) {
if (map.containsKey(attribute)) {
throw new IllegalArgumentException("Attribute already registered: " + attribute.getKey());
}
ICustomAttribute instance = new PlayerAttribute(attribute, baseValue);
map.put(attribute, instance);
return instance;
}
public ICustomAttribute getAttributeInstance(AttributeDefinition attribute) {
return map.get(attribute);
}
public Collection<ICustomAttribute> getAllAttributes() {
return map.values();
}
}
@@ -0,0 +1,21 @@
package kamkeel.npcs.controllers.data.attribute.requirement;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.NBTTagCompound;
public interface IRequirementChecker {
public String getKey();
public String getTranslation();
String getTooltipValue(NBTTagCompound nbt);
void apply(NBTTagCompound nbt, Object value);
/**
* Checks the requirement in the provided NBT.
* Return false if the requirement isn’t met.
*/
boolean check(EntityPlayer player, NBTTagCompound nbt);
}
@@ -0,0 +1,41 @@
package kamkeel.npcs.controllers.data.attribute.requirement;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.NBTTagCompound;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class RequirementCheckerRegistry {
private static final Map<String, IRequirementChecker> checkers = new HashMap<>();
public static void registerChecker(IRequirementChecker checker) {
if (!checkers.containsKey(checker.getKey())) {
checkers.put(checker.getKey(), checker);
}
}
/**
* Loops over all registered requirement keys.
* For each key present in the NBT, its checker must return true.
*/
public static boolean checkRequirements(EntityPlayer player, NBTTagCompound nbt) {
for (Map.Entry<String, IRequirementChecker> entry : checkers.entrySet()) {
String reqKey = entry.getKey();
if (nbt.hasKey(reqKey)) {
if (!entry.getValue().check(player, nbt)) {
return false;
}
}
}
return true;
}
public static Set<String> getAllKeys() {
return checkers.keySet();
}
public static IRequirementChecker getChecker(String key) {
return checkers.get(key);
}
}
@@ -0,0 +1,47 @@
package kamkeel.npcs.controllers.data.attribute.requirement.types;
import kamkeel.npcs.controllers.data.attribute.requirement.IRequirementChecker;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.NBTTagCompound;
import noppes.npcs.controllers.QuestController;
import noppes.npcs.controllers.data.PlayerData;
public class QuestActiveRequirement implements IRequirementChecker {
@Override
public String getKey() {
return "cnpc_quest_active";
}
@Override
public String getTranslation() {
return "quest.active";
}
@Override
public String getTooltipValue(NBTTagCompound nbt) {
if(nbt.hasKey(getKey())) {
int questID = nbt.getInteger(getKey());
if(QuestController.Instance.get(questID) != null) {
return QuestController.Instance.get(questID).getName();
}
}
return "null";
}
@Override
public void apply(NBTTagCompound nbt, Object value) {
if(value instanceof Integer) {
nbt.setInteger(getKey(), (Integer) value);
}
}
@Override
public boolean check(EntityPlayer player, NBTTagCompound nbt) {
if(nbt.hasKey(getKey())) {
int questID = nbt.getInteger(getKey());
return PlayerData.get(player).questData.hasActiveQuest(questID);
}
return true;
}
}
@@ -0,0 +1,47 @@
package kamkeel.npcs.controllers.data.attribute.requirement.types;
import kamkeel.npcs.controllers.data.attribute.requirement.IRequirementChecker;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.NBTTagCompound;
import noppes.npcs.controllers.QuestController;
import noppes.npcs.controllers.data.PlayerData;
public class QuestCompletedRequirement implements IRequirementChecker {
@Override
public String getKey() {
return "cnpc_quest_completed";
}
@Override
public String getTranslation() {
return "quest.quest";
}
@Override
public String getTooltipValue(NBTTagCompound nbt) {
if(nbt.hasKey(getKey())) {
int questID = nbt.getInteger(getKey());
if(QuestController.Instance.get(questID) != null) {
return QuestController.Instance.get(questID).getName();
}
}
return "null";
}
@Override
public void apply(NBTTagCompound nbt, Object value) {
if(value instanceof Integer) {
nbt.setInteger(getKey(), (Integer) value);
}
}
@Override
public boolean check(EntityPlayer player, NBTTagCompound nbt) {
if(nbt.hasKey(getKey())) {
int questID = nbt.getInteger(getKey());
return PlayerData.get(player).questData.hasFinishedQuest(questID);
}
return true;
}
}
@@ -0,0 +1,27 @@
package kamkeel.npcs.controllers.data.attribute.tracker;
import java.util.ArrayList;
import java.util.List;
import net.minecraft.entity.player.EntityPlayer;
public class AttributeRecalcEvent {
private static final List<IAttributeRecalcListener> listeners = new ArrayList<>();
/**
* Allows other mods to register a listener that is called after attribute recalculation.
*/
public static void registerListener(IAttributeRecalcListener listener) {
if (listener != null && !listeners.contains(listener)) {
listeners.add(listener);
}
}
/**
* Posts an event to all registered listeners.
*/
public static void post(EntityPlayer player, PlayerAttributeTracker tracker) {
for (IAttributeRecalcListener listener : listeners) {
listener.onAttributesRecalculated(player, tracker);
}
}
}
@@ -0,0 +1,10 @@
package kamkeel.npcs.controllers.data.attribute.tracker;
import net.minecraft.entity.player.EntityPlayer;
/**
* Implement this interface to receive a callback after a player's attributes have been recalculated.
*/
public interface IAttributeRecalcListener {
void onAttributesRecalculated(EntityPlayer player, PlayerAttributeTracker tracker);
}
@@ -0,0 +1,169 @@
package kamkeel.npcs.controllers.data.attribute.tracker;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.Map.Entry;
import kamkeel.npcs.CustomAttributes;
import kamkeel.npcs.controllers.AttributeController;
import kamkeel.npcs.controllers.data.attribute.AttributeDefinition;
import kamkeel.npcs.controllers.data.attribute.ICustomAttribute;
import kamkeel.npcs.controllers.data.attribute.PlayerAttributeMap;
import kamkeel.npcs.controllers.data.attribute.requirement.RequirementCheckerRegistry;
import kamkeel.npcs.util.AttributeAttackUtil;
import kamkeel.npcs.util.AttributeItemUtil;
import net.minecraft.entity.SharedMonsterAttributes;
import net.minecraft.entity.ai.attributes.AttributeModifier;
import net.minecraft.entity.ai.attributes.IAttributeInstance;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
public class PlayerAttributeTracker {
public static UUID healthUUID = UUID.fromString("48a0ad75-2cf8-4838-ad2f-9a0aadc57dfe");
private final UUID playerId;
private PlayerAttributeMap playerAttributes = new PlayerAttributeMap();
public float extraHealth = 0;
public float maximumOutput = 0.0f;
public final Map<Integer, Float> magicDamage = new HashMap<>();
public final Map<Integer, Float> magicBoost = new HashMap<>();
public final Map<Integer, Float> magicDefense = new HashMap<>();
public final Map<Integer, Float> magicResistance = new HashMap<>();
private PlayerEquipmentTracker equipmentTracker = new PlayerEquipmentTracker();
public PlayerAttributeTracker(UUID playerId) {
this.playerId = playerId;
// Initial recalc with base damage 0.
recalcAttributes(null);
}
public PlayerAttributeMap getPlayerAttributes() {
return playerAttributes;
}
public void recalcAttributes(EntityPlayer player) {
// Reset aggregated attributes and magic maps.
playerAttributes = new PlayerAttributeMap();
magicDamage.clear();
magicBoost.clear();
magicDefense.clear();
magicResistance.clear();
if (player != null) {
// Update equipment tracker.
PlayerEquipmentTracker currentEquip = new PlayerEquipmentTracker();
currentEquip.updateFrom(player);
ItemStack[] equipment = new ItemStack[] { currentEquip.heldItem, currentEquip.boots, currentEquip.leggings, currentEquip.chestplate, currentEquip.helmet };
for (ItemStack piece : equipment) {
if (piece != null) {
if (piece.stackTagCompound != null && piece.stackTagCompound.hasKey(AttributeItemUtil.TAG_RPGCORE)) {
NBTTagCompound rpgCore = piece.stackTagCompound.getCompoundTag(AttributeItemUtil.TAG_RPGCORE);
if (rpgCore.hasKey(AttributeItemUtil.TAG_REQUIREMENTS)) {
NBTTagCompound reqTag = rpgCore.getCompoundTag(AttributeItemUtil.TAG_REQUIREMENTS);
if (!RequirementCheckerRegistry.checkRequirements(player, reqTag)) {
continue;
}
}
}
for (Entry<String, Float> entry : AttributeItemUtil.readAttributes(piece).entrySet()) {
String key = entry.getKey();
float value = entry.getValue();
AttributeDefinition def = AttributeController.getAttribute(key);
if (def != null) {
ICustomAttribute inst = playerAttributes.getAttributeInstance(def);
if (inst == null) {
inst = playerAttributes.registerAttribute(def, 0.0f);
}
inst.setValue(inst.getValue() + value);
}
}
// Process Magic
// OFFENSIVE MAGIC
Map<Integer, Float> magicFlat = AttributeItemUtil.readMagicAttributeMap(piece, CustomAttributes.MAGIC_DAMAGE_KEY);
for (Entry<Integer, Float> entry : magicFlat.entrySet()) {
int magicId = entry.getKey();
float value = entry.getValue();
magicDamage.put(magicId, magicDamage.getOrDefault(magicId, 0.0f) + value);
}
Map<Integer, Float> magicPercent = AttributeItemUtil.readMagicAttributeMap(piece, CustomAttributes.MAGIC_BOOST_KEY);
for (Entry<Integer, Float> entry : magicPercent.entrySet()) {
int magicId = entry.getKey();
float value = entry.getValue();
magicBoost.put(magicId, magicBoost.getOrDefault(magicId, 0.0f) + value);
}
// DEFENSIVE MAGIC
Map<Integer, Float> magicDefFlat = AttributeItemUtil.readMagicAttributeMap(piece, CustomAttributes.MAGIC_DEFENSE_KEY);
for (Entry<Integer, Float> entry : magicDefFlat.entrySet()) {
int magicId = entry.getKey();
float value = entry.getValue();
magicDefense.put(magicId, magicDefense.getOrDefault(magicId, 0.0f) + value);
}
Map<Integer, Float> magicResist = AttributeItemUtil.readMagicAttributeMap(piece, CustomAttributes.MAGIC_RESISTANCE_KEY);
for (Entry<Integer, Float> entry : magicResist.entrySet()) {
int magicId = entry.getKey();
float value = entry.getValue();
magicResistance.put(magicId, magicResistance.getOrDefault(magicId, 0.0f) + value);
}
}
}
equipmentTracker = currentEquip;
maximumOutput = AttributeAttackUtil.calculateMaximumOutput(this);
extraHealth = getAttributeValue(CustomAttributes.HEALTH);
updatePlayerMaxHealth(player);
// Post Recalculation Event to Listeners
AttributeRecalcEvent.post(player, this);
}
}
/**
* Updates the player's maximum health attribute by applying a custom attribute modifier.
* In this system, the aggregated HEALTH attribute is treated as bonus health on top of a base of 20.
*
* @param player The EntityPlayer whose max health should be updated.
*/
public void updatePlayerMaxHealth(EntityPlayer player) {
float bonusHealth = extraHealth;
IAttributeInstance maxHealthAttr = player.getAttributeMap().getAttributeInstance(SharedMonsterAttributes.maxHealth);
try {
AttributeModifier old = maxHealthAttr.getModifier(healthUUID);
if (old != null) {
maxHealthAttr.removeModifier(old);
}
} catch (Exception ignored) {}
if (bonusHealth != 0) {
maxHealthAttr.applyModifier(new AttributeModifier(healthUUID, "RPGCoreHealthBonus", bonusHealth, 0));
}
// Ensure the player's current health does not exceed the new maximum.
float currentHealth = player.getHealth();
if (currentHealth > maxHealthAttr.getAttributeValue()) {
player.setHealth((float) maxHealthAttr.getAttributeValue());
}
}
/**
* Checks if the player's equipment has changed and recalculates attributes if needed.
*/
public void updateIfChanged(EntityPlayer player) {
PlayerEquipmentTracker currentEquip = new PlayerEquipmentTracker();
currentEquip.updateFrom(player);
if (!equipmentTracker.equals(player)) {
recalcAttributes(player);
}
}
public float getAttributeValue(AttributeDefinition def) {
ICustomAttribute inst = playerAttributes.getAttributeInstance(def);
return inst != null ? inst.getValue() : 0.0f;
}
}
@@ -0,0 +1,66 @@
package kamkeel.npcs.controllers.data.attribute.tracker;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import kamkeel.npcs.util.AttributeItemUtil;
public class PlayerEquipmentTracker {
public ItemStack heldItem;
public ItemStack helmet;
public ItemStack chestplate;
public ItemStack leggings;
public ItemStack boots;
/**
* Updates the stored equipment based on the player's current held item and armor.
*/
public void updateFrom(EntityPlayer player) {
heldItem = copyIfNotNull(player.getHeldItem());
ItemStack[] armor = player.inventory.armorInventory;
// Armor inventory order: 0=boots, 1=leggings, 2=chestplate, 3=helmet.
boots = copyIfNotNull(armor[0]);
leggings = copyIfNotNull(armor[1]);
chestplate = copyIfNotNull(armor[2]);
helmet = copyIfNotNull(armor[3]);
}
/**
* Compares the stored equipment with the player's current equipment.
* Ignores changes like durability by comparing the item and the CNPCAttributes NBT only.
*/
public boolean equals(EntityPlayer player) {
if (player == null) return false;
if (!areItemStacksEquivalent(heldItem, player.getHeldItem())) return false;
ItemStack[] armor = player.inventory.armorInventory;
if (!areItemStacksEquivalent(boots, armor[0])) return false;
if (!areItemStacksEquivalent(leggings, armor[1])) return false;
if (!areItemStacksEquivalent(chestplate, armor[2])) return false;
if (!areItemStacksEquivalent(helmet, armor[3])) return false;
return true;
}
/**
* Returns a copy of the given ItemStack, or null if it is null.
*/
private ItemStack copyIfNotNull(ItemStack stack) {
return (stack == null) ? null : stack.copy();
}
/**
* Compares two ItemStacks for equivalence, ignoring durability differences.
* It checks if the items are the same and if the "CNPCAttributes" NBT compound is equal.
*/
private boolean areItemStacksEquivalent(ItemStack a, ItemStack b) {
if (a == b) return true;
if (a == null || b == null) return false;
if (a.getItem() != b.getItem()) return false;
NBTTagCompound tagA = a.stackTagCompound;
NBTTagCompound tagB = b.stackTagCompound;
String attrA = (tagA != null && tagA.hasKey(AttributeItemUtil.TAG_RPGCORE))
? tagA.getCompoundTag(AttributeItemUtil.TAG_RPGCORE).toString() : "";
String attrB = (tagB != null && tagB.hasKey(AttributeItemUtil.TAG_RPGCORE))
? tagB.getCompoundTag(AttributeItemUtil.TAG_RPGCORE).toString() : "";
return attrA.equals(attrB);
}
}
@@ -0,0 +1,72 @@
package kamkeel.npcs.controllers.data.profile;
import kamkeel.npcs.controllers.SyncController;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.nbt.NBTTagCompound;
import noppes.npcs.controllers.data.PlayerData;
import java.util.ArrayList;
import java.util.List;
public class CNPCData implements IProfileData {
@Override
public String getTagName() {
return "CNPC+";
}
@Override
public NBTTagCompound getCurrentNBT(EntityPlayer player) {
PlayerData customNPCData = PlayerData.get(player);
return customNPCData.getNBT();
}
@Override
public void save(EntityPlayer player) {
PlayerData customNPCData = PlayerData.get(player);
customNPCData.save();
SyncController.syncPlayerData((EntityPlayerMP) player, false);
}
@Override
public void setNBT(EntityPlayer player, NBTTagCompound replace) {
PlayerData customNPCData = PlayerData.get(player);
if(replace.hasNoTags()){
PlayerData newData = new PlayerData();
newData.player = player;
customNPCData.setNBT((NBTTagCompound) newData.getNBT().copy());
}
else {
customNPCData.setNBT(replace);
}
customNPCData.updateClient = true;
}
@Override
public int getSwitchPriority() {
return 0;
}
@Override
public ProfileOperation verifySwitch(EntityPlayer player) {
PlayerData playerData = PlayerData.get(player);
if(playerData.partyUUID != null)
return ProfileOperation.error("Cannot switch while in Party");
return ProfileOperation.success("");
}
@Override
public List<ProfileInfoEntry> getInfo(EntityPlayer player, NBTTagCompound compound) {
PlayerData playerData = new PlayerData();
playerData.player = player;
playerData.setNBT(compound);
List<ProfileInfoEntry> info = new ArrayList<>();
info.add(new ProfileInfoEntry("profile.info.quest.finished", 0x60fa57, playerData.questData.finishedQuests.size(), 0xFFFFFF));
info.add(new ProfileInfoEntry("profile.info.quest.active", 0xf75336, playerData.questData.activeQuests.size(), 0xFFFFFF));
info.add(new ProfileInfoEntry("profile.info.dialog.read", 0x47acf5, playerData.dialogData.dialogsRead.size(), 0xFFFFFF));
return info;
}
}
@@ -0,0 +1,7 @@
package kamkeel.npcs.controllers.data.profile;
public enum EnumProfileOperation {
SUCCESS,
ERROR,
LOCKED
}
@@ -0,0 +1,52 @@
package kamkeel.npcs.controllers.data.profile;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.NBTTagCompound;
import java.util.List;
public interface IProfileData {
/**
* Do not use the tags: Name, lastLoaded, ID.
* @return The save tag utilized in the Profile.
*/
public String getTagName();
/**
* @return NBTTagCompound of the current data for a given EntityPlayer.
*/
public NBTTagCompound getCurrentNBT(EntityPlayer player);
/**
* Called immediately after setNBT() to replace existing NBT.
*/
public void save(EntityPlayer player);
/**
* Replaces the current data operation when changing profiles.
*/
public void setNBT(EntityPlayer player, NBTTagCompound replace);
/**
* Returns the priority for this ProfileData's verification check.
* Lower numbers run first.
*/
public int getSwitchPriority();
/**
* Called before a profile switch occurs.
* @param player The player switching profiles.
* @return true if allowed, false if not.
*/
public ProfileOperation verifySwitch(EntityPlayer player);
/**
* NEW: Builds and returns a list of informational strings about this profile data,
* based on the provided NBTTagCompound from the slot.
* @param player The player in question.
* @param compound The NBT data from the slot under this profile data's tag.
* @return A list of InfoEntry with information
*/
public List<ProfileInfoEntry> getInfo(EntityPlayer player, NBTTagCompound compound);
}
@@ -0,0 +1,92 @@
package kamkeel.npcs.controllers.data.profile;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.NBTTagCompound;
import noppes.npcs.NoppesUtilServer;
import noppes.npcs.api.entity.IPlayer;
import noppes.npcs.api.handler.data.IProfile;
import noppes.npcs.api.handler.data.ISlot;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class Profile implements IProfile {
public EntityPlayer player;
public int currentSlotId;
private Map<Integer, ISlot> slots = new HashMap<>();
private boolean locked = false;
public Profile(EntityPlayer player, NBTTagCompound compound) {
this.player = player;
if(compound.hasKey("CurrentSlotId")){
this.currentSlotId = compound.getInteger("CurrentSlotId");
} else {
this.currentSlotId = 0;
}
if(compound.hasKey("Slots")){
NBTTagCompound slotsCompound = compound.getCompoundTag("Slots");
Set<String> keys = slotsCompound.func_150296_c();
for(String key : keys) {
try {
int slotId = Integer.parseInt(key);
NBTTagCompound slotNBT = slotsCompound.getCompoundTag(key);
ISlot slot = Slot.fromNBT(slotId, slotNBT);
slots.put(slotId, slot);
} catch (NumberFormatException e) {
// Skip keys that are not valid slot IDs.
}
}
}
}
public Profile(EntityPlayer player) {
this.player = player;
this.currentSlotId = 0;
// Create a default slot.
Slot defaultSlot = new Slot(0, "Default Slot");
defaultSlot.setLastLoaded(System.currentTimeMillis());
slots.put(0, defaultSlot);
}
@Override
public IPlayer getPlayer() {
return NoppesUtilServer.getIPlayer(player);
}
@Override
public int getCurrentSlotId() {
return currentSlotId;
}
@Override
public Map<Integer, ISlot> getSlots() {
return slots;
}
public boolean isLocked() {
return locked;
}
public void setLocked(boolean locked) {
this.locked = locked;
}
@Override
public NBTTagCompound writeToNBT() {
NBTTagCompound compound = new NBTTagCompound();
if(player != null)
compound.setString("Name", player.getCommandSenderName());
compound.setInteger("CurrentSlotId", currentSlotId);
NBTTagCompound slotsCompound = new NBTTagCompound();
for(Map.Entry<Integer, ISlot> entry : slots.entrySet()) {
// Save only non-temporary slots.
if(entry.getValue().isTemporary())
continue;
slotsCompound.setTag(String.valueOf(entry.getKey()), entry.getValue().toNBT());
}
compound.setTag("Slots", slotsCompound);
return compound;
}
}
@@ -0,0 +1,50 @@
package kamkeel.npcs.controllers.data.profile;
import net.minecraft.nbt.NBTTagCompound;
public class ProfileInfoEntry {
private String label;
private String result;
private int labelColor;
private int resultColor;
public ProfileInfoEntry() {}
public ProfileInfoEntry(String label, int labelColor, String result, int resultColor) {
this.label = label;
this.result = result;
this.labelColor = labelColor;
this.resultColor = resultColor;
}
public ProfileInfoEntry(String label, int labelColor, int result, int resultColor) {
this(label, labelColor, String.valueOf(result), resultColor);
}
public ProfileInfoEntry(String label, String result) {
this(label, 0xFFFFFF, result, 0xFFFFFF);
}
public NBTTagCompound writeToNBT() {
NBTTagCompound tag = new NBTTagCompound();
tag.setString("Label", label);
tag.setInteger("LabelColor", labelColor);
tag.setString("Result", result);
tag.setInteger("ResultColor", resultColor);
return tag;
}
public static ProfileInfoEntry readFromNBT(NBTTagCompound tag) {
return new ProfileInfoEntry(
tag.getString("Label"),
tag.getInteger("LabelColor"),
tag.getString("Result"),
tag.getInteger("ResultColor")
);
}
public String getLabel() { return label; }
public String getResult() { return result; }
public int getLabelColor() { return labelColor; }
public int getResultColor() { return resultColor; }
}
@@ -0,0 +1,31 @@
package kamkeel.npcs.controllers.data.profile;
public class ProfileOperation {
private final EnumProfileOperation result;
private final String message;
public ProfileOperation(EnumProfileOperation result, String message) {
this.result = result;
this.message = message;
}
public EnumProfileOperation getResult() {
return result;
}
public String getMessage() {
return message;
}
public static ProfileOperation success(String message) {
return new ProfileOperation(EnumProfileOperation.SUCCESS, message);
}
public static ProfileOperation error(String message) {
return new ProfileOperation(EnumProfileOperation.ERROR, message);
}
public static ProfileOperation locked(String message) {
return new ProfileOperation(EnumProfileOperation.LOCKED, message);
}
}
@@ -0,0 +1,114 @@
package kamkeel.npcs.controllers.data.profile;
import net.minecraft.nbt.NBTTagCompound;
import noppes.npcs.api.handler.data.ISlot;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class Slot implements ISlot {
private int id;
private String name;
private long lastLoaded;
private boolean temporary;
private Map<String, NBTTagCompound> components = new HashMap<>();
public Slot(int id, String name) {
this.id = id;
this.name = name;
}
public Slot(int id, String name, long lastLoaded, boolean temporary, Map<String, NBTTagCompound> components) {
this.id = id;
this.name = name;
this.lastLoaded = lastLoaded;
this.temporary = temporary;
this.components = components;
}
@Override
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Override
public String getName() {
return name;
}
@Override
public void setName(String name) {
this.name = name;
}
@Override
public long getLastLoaded() {
return lastLoaded;
}
@Override
public void setLastLoaded(long time) {
this.lastLoaded = time;
}
@Override
public boolean isTemporary() {
return temporary;
}
@Override
public void setTemporary(boolean temporary) {
this.temporary = temporary;
}
@Override
public Map<String, NBTTagCompound> getComponents() {
return components;
}
@Override
public void setComponentData(String key, NBTTagCompound data) {
components.put(key, data);
}
@Override
public NBTTagCompound getComponentData(String key) {
return components.get(key);
}
@Override
public NBTTagCompound toNBT() {
NBTTagCompound slotNBT = new NBTTagCompound();
slotNBT.setString("Name", name);
slotNBT.setLong("LastLoaded", lastLoaded);
slotNBT.setBoolean("Temporary", temporary);
NBTTagCompound compCompound = new NBTTagCompound();
for (Map.Entry<String, NBTTagCompound> entry : components.entrySet()) {
compCompound.setTag(entry.getKey(), entry.getValue());
}
slotNBT.setTag("Components", compCompound);
return slotNBT;
}
public static Slot fromNBT(int id, NBTTagCompound slotNBT) {
String name = slotNBT.getString("Name");
long lastLoaded = slotNBT.getLong("LastLoaded");
boolean temporary = slotNBT.getBoolean("Temporary");
Slot slot = new Slot(id, name);
slot.setLastLoaded(lastLoaded);
slot.setTemporary(temporary);
if (slotNBT.hasKey("Components")) {
NBTTagCompound compCompound = slotNBT.getCompoundTag("Components");
Set<String> keys = compCompound.func_150296_c();
for (String key : keys) {
slot.setComponentData(key, compCompound.getCompoundTag(key));
}
}
return slot;
}
}
@@ -1,4 +1,4 @@
package kamkeel.developer;
package kamkeel.npcs.developer;
import java.util.HashSet;
import java.util.UUID;
@@ -1,17 +1,20 @@
package kamkeel.network;
package kamkeel.npcs.network;
import cpw.mods.fml.common.network.NetworkRegistry;
import cpw.mods.fml.common.network.internal.FMLProxyPacket;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import net.minecraft.entity.player.EntityPlayer;
import noppes.npcs.CustomNpcs;
import noppes.npcs.LogWriter;
import noppes.npcs.CustomNpcsPermissions;
import noppes.npcs.entity.EntityNPCInterface;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
public abstract class AbstractPacket {
public EntityNPCInterface npc;
public FMLProxyPacket generatePacket() {
PacketChannel packetChannel = getChannel();
ByteBuf buf = Unpooled.buffer();
@@ -19,13 +22,37 @@ public abstract class AbstractPacket {
buf.writeInt(packetChannel.getChannelType().ordinal());
buf.writeInt(getType().ordinal());
sendData(buf);
return new FMLProxyPacket(buf, getChannel().getChannelName());
} catch (Exception ignored) {}
return new FMLProxyPacket(buf, packetChannel.getChannelName());
} catch (Exception e) {
// For debugging, you might want to log it
e.printStackTrace();
}
return null;
}
public List<FMLProxyPacket> generatePackets() {
FMLProxyPacket single = generatePacket();
if (single == null) {
return Collections.emptyList();
}
return Collections.singletonList(single);
}
public abstract Enum getType();
public abstract PacketChannel getChannel();
public CustomNpcsPermissions.Permission getPermission(){
return null;
}
public boolean needsNPC(){
return false;
}
public void setNPC(EntityNPCInterface npc){
this.npc = npc;
}
public abstract void sendData(ByteBuf out) throws IOException;
//"player" on the server side is the client who sent this packet
@@ -0,0 +1,161 @@
package kamkeel.npcs.network;
import cpw.mods.fml.common.network.internal.FMLProxyPacket;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import net.minecraft.entity.player.EntityPlayer;
import noppes.npcs.LogWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
public abstract class LargeAbstractPacket extends AbstractPacket {
private static final Map<UUID, PacketStorage> packetChunks = new ConcurrentHashMap<>();
private static final int CHUNK_SIZE = 10000;
/**
* Create multiple FMLProxyPacket objects, each containing up to CHUNK_SIZE bytes.
*/
@Override
public List<FMLProxyPacket> generatePackets() {
List<FMLProxyPacket> packets = new ArrayList<>();
PacketChannel packetChannel = getChannel();
byte[] fullData;
try {
fullData = getData();
} catch (IOException e) {
e.printStackTrace();
return packets;
}
int totalSize = fullData.length;
UUID packetId = UUID.randomUUID();
// Break data into CHUNK_SIZE chunks
for (int offset = 0; offset < totalSize; offset += CHUNK_SIZE) {
int chunkSize = Math.min(CHUNK_SIZE, totalSize - offset);
ByteBuf chunkBuf = Unpooled.buffer();
chunkBuf.writeInt(packetChannel.getChannelType().ordinal());
chunkBuf.writeInt(getType().ordinal());
chunkBuf.writeLong(packetId.getMostSignificantBits());
chunkBuf.writeLong(packetId.getLeastSignificantBits());
chunkBuf.writeInt(totalSize);
chunkBuf.writeInt(offset);
chunkBuf.writeInt((totalSize + CHUNK_SIZE - 1) / CHUNK_SIZE);
chunkBuf.writeBytes(fullData, offset, chunkSize);
FMLProxyPacket proxyPacket = new FMLProxyPacket(chunkBuf, packetChannel.getChannelName());
packets.add(proxyPacket);
}
return packets;
}
@Override
public void receiveData(ByteBuf in, EntityPlayer player) throws IOException {
UUID packetId = null;
PacketStorage storage = null;
ByteBuf chunk = null;
ByteBuf completeData = null;
try {
// Read UUID from the buffer
long mostSigBits = in.readLong();
long leastSigBits = in.readLong();
packetId = new UUID(mostSigBits, leastSigBits);
// Read packet metadata
int totalSize = in.readInt();
int offset = in.readInt();
int totalChunks = in.readInt(); // Debugging info
int chunkSize = Math.min(CHUNK_SIZE, totalSize - offset);
// Basic validation to ensure the chunk won't overwrite out of bounds
if (chunkSize <= 0 || offset < 0 || (offset + chunkSize) > totalSize) {
throw new IndexOutOfBoundsException("Invalid chunk size/offset: chunkSize="
+ chunkSize + ", offset=" + offset + ", totalSize=" + totalSize);
}
// Read the exact chunk data
chunk = in.readBytes(chunkSize);
// Store the received chunk in a PacketStorage
storage = packetChunks.computeIfAbsent(packetId, k -> new PacketStorage(Unpooled.buffer(totalSize), 0, totalSize));
// Write this chunk into the buffer at the correct offset
storage.data.setBytes(offset, chunk);
storage.receivedSoFar += chunkSize;
// If we've received all bytes, finalize
if (storage.receivedSoFar >= totalSize) {
packetChunks.remove(packetId);
completeData = storage.data.copy(0, totalSize);
try {
handleCompleteData(completeData, player);
} finally {
completeData.release();
}
storage.data.release();
}
} catch (Exception e) {
// Log the exception with contextual information
LogWriter.error("Error in receiveData for packetId " + (packetId != null ? packetId.toString() : "null") + ": " + e.getMessage());
e.printStackTrace();
// If storage was created but the packet is incomplete, release storage.data
if (storage != null && storage.receivedSoFar < storage.totalSize) {
storage.data.release();
if (packetId != null) {
packetChunks.remove(packetId);
}
}
throw e; // Rethrow the exception after logging
} finally {
// Ensure that 'chunk' is released if it was allocated
if (chunk != null && chunk.refCnt() > 0) {
chunk.release();
}
// Ensure that 'completeData' is released if it was created and not yet released
if (completeData != null && completeData.refCnt() > 0) {
completeData.release();
}
}
}
protected abstract byte[] getData() throws IOException;
protected abstract void handleCompleteData(ByteBuf data, EntityPlayer player) throws IOException;
@Override
public final FMLProxyPacket generatePacket() {return null;}
@Override
public void sendData(ByteBuf out) throws IOException {}
/**
* Simple storage class to keep track of partial data and how many bytes we've received so far.
*/
private static class PacketStorage {
final ByteBuf data;
int receivedSoFar;
final int totalSize;
PacketStorage(ByteBuf data, int receivedSoFar, int totalSize) {
this.data = data;
this.receivedSoFar = receivedSoFar;
this.totalSize = totalSize;
}
}
}
@@ -0,0 +1,43 @@
package kamkeel.npcs.network;
import kamkeel.npcs.network.enums.EnumChannelType;
import java.util.Hashtable;
import java.util.Map;
public class PacketChannel {
private String channelName;
private EnumChannelType channelType;
public Map<Integer, AbstractPacket> packets = new Hashtable<>();
public PacketChannel(String channelName, EnumChannelType channelType) {
this.channelName = channelName;
this.channelType = channelType;
}
public String getChannelName() {
return channelName;
}
public void setChannelName(String channelName) {
this.channelName = channelName;
}
public EnumChannelType getChannelType() {
return channelType;
}
public void setChannelType(EnumChannelType channelType) {
this.channelType = channelType;
}
public void registerPacket(AbstractPacket packet) {
if(packets.containsKey(packet.getType().ordinal())){
System.out.println("Packet ID: " + packet.getType().ordinal() + " is already registered in " + this.channelName);
return;
}
this.packets.put(packet.getType().ordinal(), packet);
}
}
@@ -0,0 +1,8 @@
package kamkeel.npcs.network;
public class PacketClient extends PacketHandler {
public static void sendClient(AbstractPacket packet){
PacketHandler.Instance.sendToServer(packet);
}
}
@@ -0,0 +1,589 @@
package kamkeel.npcs.network;
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import cpw.mods.fml.common.network.FMLEventChannel;
import cpw.mods.fml.common.network.FMLNetworkEvent;
import cpw.mods.fml.common.network.NetworkRegistry;
import cpw.mods.fml.common.network.internal.FMLProxyPacket;
import cpw.mods.fml.relauncher.Side;
import io.netty.buffer.ByteBuf;
import kamkeel.npcs.network.enums.EnumChannelType;
import kamkeel.npcs.network.packets.data.*;
import kamkeel.npcs.network.packets.data.gui.*;
import kamkeel.npcs.network.packets.data.large.*;
import kamkeel.npcs.network.packets.data.npc.*;
import kamkeel.npcs.network.packets.data.script.ScriptOverlayClosePacket;
import kamkeel.npcs.network.packets.data.script.ScriptOverlayDataPacket;
import kamkeel.npcs.network.packets.data.script.ScriptedParticlePacket;
import kamkeel.npcs.network.packets.player.*;
import kamkeel.npcs.network.packets.request.*;
import kamkeel.npcs.network.packets.request.animation.AnimationGetPacket;
import kamkeel.npcs.network.packets.request.animation.AnimationRemovePacket;
import kamkeel.npcs.network.packets.request.animation.AnimationSavePacket;
import kamkeel.npcs.network.packets.request.animation.AnimationsGetPacket;
import kamkeel.npcs.network.packets.request.bank.BankGetPacket;
import kamkeel.npcs.network.packets.request.bank.BankRemovePacket;
import kamkeel.npcs.network.packets.request.bank.BankSavePacket;
import kamkeel.npcs.network.packets.request.bank.BanksGetPacket;
import kamkeel.npcs.network.packets.request.clone.*;
import kamkeel.npcs.network.packets.player.customgui.CustomGuiButtonPacket;
import kamkeel.npcs.network.packets.player.customgui.CustomGuiClosePacket;
import kamkeel.npcs.network.packets.player.customgui.CustomGuiUnfocusedPacket;
import kamkeel.npcs.network.packets.player.customgui.CustomScrollClickPacket;
import kamkeel.npcs.network.packets.request.dialog.*;
import kamkeel.npcs.network.packets.request.effects.EffectGetPacket;
import kamkeel.npcs.network.packets.request.effects.EffectRemovePacket;
import kamkeel.npcs.network.packets.request.effects.EffectSavePacket;
import kamkeel.npcs.network.packets.request.effects.EffectsGetPacket;
import kamkeel.npcs.network.packets.request.faction.*;
import kamkeel.npcs.network.packets.request.feather.DimensionTeleportPacket;
import kamkeel.npcs.network.packets.request.item.ColorBrushPacket;
import kamkeel.npcs.network.packets.request.item.ColorSetPacket;
import kamkeel.npcs.network.packets.request.jobs.JobGetPacket;
import kamkeel.npcs.network.packets.request.jobs.JobSavePacket;
import kamkeel.npcs.network.packets.request.jobs.JobSpawnerAddPacket;
import kamkeel.npcs.network.packets.request.jobs.JobSpawnerRemovePacket;
import kamkeel.npcs.network.packets.request.linked.*;
import kamkeel.npcs.network.packets.request.magic.*;
import kamkeel.npcs.network.packets.request.mainmenu.*;
import kamkeel.npcs.network.packets.request.naturalspawns.NaturalSpawnGetAllPacket;
import kamkeel.npcs.network.packets.request.naturalspawns.NaturalSpawnGetPacket;
import kamkeel.npcs.network.packets.request.naturalspawns.NaturalSpawnRemovePacket;
import kamkeel.npcs.network.packets.request.naturalspawns.NaturalSpawnSavePacket;
import kamkeel.npcs.network.packets.request.npc.*;
import kamkeel.npcs.network.packets.request.party.*;
import kamkeel.npcs.network.packets.request.pather.MovingPathGetPacket;
import kamkeel.npcs.network.packets.request.pather.MovingPathSavePacket;
import kamkeel.npcs.network.packets.request.playerdata.*;
import kamkeel.npcs.network.packets.request.profile.*;
import kamkeel.npcs.network.packets.request.quest.*;
import kamkeel.npcs.network.packets.request.recipe.RecipeGetPacket;
import kamkeel.npcs.network.packets.request.recipe.RecipeRemovePacket;
import kamkeel.npcs.network.packets.request.recipe.RecipeSavePacket;
import kamkeel.npcs.network.packets.request.recipe.RecipesGetPacket;
import kamkeel.npcs.network.packets.request.role.RoleCompanionUpdatePacket;
import kamkeel.npcs.network.packets.request.role.RoleGetPacket;
import kamkeel.npcs.network.packets.request.role.RoleSavePacket;
import kamkeel.npcs.network.packets.request.script.*;
import kamkeel.npcs.network.packets.request.script.item.ItemScriptErrorPacket;
import kamkeel.npcs.network.packets.request.script.item.ItemScriptPacket;
import kamkeel.npcs.network.packets.request.script.item.LinkedItemScriptPacket;
import kamkeel.npcs.network.packets.request.tags.*;
import kamkeel.npcs.network.packets.request.transform.TransformGetPacket;
import kamkeel.npcs.network.packets.request.transform.TransformLoadPacket;
import kamkeel.npcs.network.packets.request.transform.TransformSavePacket;
import kamkeel.npcs.network.packets.request.transport.*;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.network.NetHandlerPlayServer;
import noppes.npcs.CustomNpcs;
import noppes.npcs.CustomNpcsPermissions;
import noppes.npcs.LogWriter;
import noppes.npcs.NoppesUtilServer;
import noppes.npcs.config.ConfigMain;
import noppes.npcs.entity.EntityNPCInterface;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
public class PacketHandler {
public static PacketHandler Instance;
// Channels
public Map<EnumChannelType, FMLEventChannel> channels = new Hashtable<>();
// Client to Server
public static final PacketChannel REQUEST_PACKET = new PacketChannel("CNPC+|Req", EnumChannelType.REQUEST);
// Client to Server - Typically information
public static final PacketChannel PLAYER_PACKET = new PacketChannel("CNPC+|Player", EnumChannelType.PLAYER);
// Server to Client
public static final PacketChannel DATA_PACKET = new PacketChannel("CNPC+|Data", EnumChannelType.DATA);
public static final List<PacketChannel> packetChannels = new ArrayList<>();
public PacketHandler() {
// Register Channels
packetChannels.add(REQUEST_PACKET);
packetChannels.add(PLAYER_PACKET);
packetChannels.add(DATA_PACKET);
this.registerDataPackets();
this.registerRequestPackets();
this.registerPlayerPackets();
}
public void registerRequestPackets(){
// NPC Packets
REQUEST_PACKET.registerPacket(new NpcClosePacket());
REQUEST_PACKET.registerPacket(new NpcDeletePacket());
// Script Packets
REQUEST_PACKET.registerPacket(new BlockScriptPacket());
REQUEST_PACKET.registerPacket(new EventScriptPacket());
REQUEST_PACKET.registerPacket(new ForgeScriptPacket());
REQUEST_PACKET.registerPacket(new GlobalNPCScriptPacket());
REQUEST_PACKET.registerPacket(new ItemScriptPacket());
REQUEST_PACKET.registerPacket(new ItemScriptErrorPacket());
REQUEST_PACKET.registerPacket(new LinkedItemScriptPacket());
REQUEST_PACKET.registerPacket(new NPCScriptPacket());
REQUEST_PACKET.registerPacket(new PlayerScriptPacket());
REQUEST_PACKET.registerPacket(new ScriptInfoPacket());
REQUEST_PACKET.registerPacket(new EffectScriptPacket());
// Cloner Packets
REQUEST_PACKET.registerPacket(new CloneListPacket());
REQUEST_PACKET.registerPacket(new SpawnMobPacket());
REQUEST_PACKET.registerPacket(new MobSpawnerPacket());
REQUEST_PACKET.registerPacket(new ClonePreSavePacket());
REQUEST_PACKET.registerPacket(new CloneSavePacket());
REQUEST_PACKET.registerPacket(new CloneRemovePacket());
REQUEST_PACKET.registerPacket(new CloneTagListPacket());
REQUEST_PACKET.registerPacket(new CloneAllTagsPacket());
REQUEST_PACKET.registerPacket(new CloneAllTagsShortPacket());
// Linked Packets
REQUEST_PACKET.registerPacket(new LinkedGetAllPacket());
REQUEST_PACKET.registerPacket(new LinkedGetPacket());
REQUEST_PACKET.registerPacket(new LinkedNPCRemovePacket());
REQUEST_PACKET.registerPacket(new LinkedSetPacket());
REQUEST_PACKET.registerPacket(new LinkedNPCAddPacket());
REQUEST_PACKET.registerPacket(new LinkedItemSavePacket());
REQUEST_PACKET.registerPacket(new LinkedItemRemovePacket());
REQUEST_PACKET.registerPacket(new LinkedItemBuildPacket());
// Bank Packets
REQUEST_PACKET.registerPacket(new BanksGetPacket());
REQUEST_PACKET.registerPacket(new BankGetPacket());
REQUEST_PACKET.registerPacket(new BankRemovePacket());
REQUEST_PACKET.registerPacket(new BankSavePacket());
// Recipe Packets
REQUEST_PACKET.registerPacket(new RecipesGetPacket());
REQUEST_PACKET.registerPacket(new RecipeGetPacket());
REQUEST_PACKET.registerPacket(new RecipeRemovePacket());
REQUEST_PACKET.registerPacket(new RecipeSavePacket());
// Natural Spawn Packets
REQUEST_PACKET.registerPacket(new NaturalSpawnGetAllPacket());
REQUEST_PACKET.registerPacket(new NaturalSpawnGetPacket());
REQUEST_PACKET.registerPacket(new NaturalSpawnSavePacket());
REQUEST_PACKET.registerPacket(new NaturalSpawnRemovePacket());
// Dialog Category Packets
REQUEST_PACKET.registerPacket(new DialogCategorySavePacket());
REQUEST_PACKET.registerPacket(new DialogCategoryRemovePacket());
REQUEST_PACKET.registerPacket(new DialogCategoryGetPacket());
REQUEST_PACKET.registerPacket(new DialogCategoriesGetPacket());
// Dialog Packets
REQUEST_PACKET.registerPacket(new DialogSavePacket());
REQUEST_PACKET.registerPacket(new DialogRemovePacket());
REQUEST_PACKET.registerPacket(new DialogsGetPacket());
REQUEST_PACKET.registerPacket(new DialogGetPacket());
REQUEST_PACKET.registerPacket(new DialogNpcGetPacket());
REQUEST_PACKET.registerPacket(new DialogNpcSetPacket());
REQUEST_PACKET.registerPacket(new DialogNpcRemovePacket());
// Quest Category Packets
REQUEST_PACKET.registerPacket(new QuestCategorySavePacket());
REQUEST_PACKET.registerPacket(new QuestCategoryRemovePacket());
REQUEST_PACKET.registerPacket(new QuestCategoryGetPacket());
REQUEST_PACKET.registerPacket(new QuestCategoriesGetPacket());
// Quest Packets
REQUEST_PACKET.registerPacket(new QuestOpenGuiPacket());
REQUEST_PACKET.registerPacket(new QuestSavePacket());
REQUEST_PACKET.registerPacket(new QuestRemovePacket());
REQUEST_PACKET.registerPacket(new QuestDialogGetTitlePacket());
REQUEST_PACKET.registerPacket(new QuestLogToServerPacket());
REQUEST_PACKET.registerPacket(new QuestUntrackPacket());
REQUEST_PACKET.registerPacket(new QuestGetPacket());
REQUEST_PACKET.registerPacket(new QuestsGetPacket());
// Faction Packets
REQUEST_PACKET.registerPacket(new FactionSavePacket());
REQUEST_PACKET.registerPacket(new FactionRemovePacket());
REQUEST_PACKET.registerPacket(new FactionSetPacket());
REQUEST_PACKET.registerPacket(new FactionGetPacket());
REQUEST_PACKET.registerPacket(new FactionsGetPacket());
// Tag Packets
REQUEST_PACKET.registerPacket(new TagsGetPacket());
REQUEST_PACKET.registerPacket(new TagGetPacket());
REQUEST_PACKET.registerPacket(new TagsNpcGetPacket());
REQUEST_PACKET.registerPacket(new TagSetPacket());
REQUEST_PACKET.registerPacket(new TagSavePacket());
REQUEST_PACKET.registerPacket(new TagRemovePacket());
// PlayerData Packets
REQUEST_PACKET.registerPacket(new PlayerDataGetNamesPacket());
REQUEST_PACKET.registerPacket(new PlayerDataRemovePacket());
REQUEST_PACKET.registerPacket(new PlayerDataGetInfoPacket());
REQUEST_PACKET.registerPacket(new PlayerDataRemoveInfoPacket());
REQUEST_PACKET.registerPacket(new PlayerDataMapRegenPacket());
// Main Menu Packets
REQUEST_PACKET.registerPacket(new MainmenuDisplayGetPacket());
REQUEST_PACKET.registerPacket(new MainmenuDisplaySavePacket());
REQUEST_PACKET.registerPacket(new MainmenuStatsGetPacket());
REQUEST_PACKET.registerPacket(new MainmenuStatsSavePacket());
REQUEST_PACKET.registerPacket(new MainmenuAIGetPacket());
REQUEST_PACKET.registerPacket(new MainmenuAISavePacket());
REQUEST_PACKET.registerPacket(new MainmenuAdvancedGetPacket());
REQUEST_PACKET.registerPacket(new MainmenuAdvancedSavePacket());
REQUEST_PACKET.registerPacket(new MainmenuAdvancedMarkDataPacket());
REQUEST_PACKET.registerPacket(new MainmenuInvGetPacket());
REQUEST_PACKET.registerPacket(new MainmenuInvSavePacket());
// Transport Packets
REQUEST_PACKET.registerPacket(new TransportCategoriesGetPacket());
REQUEST_PACKET.registerPacket(new TransportCategorySavePacket());
REQUEST_PACKET.registerPacket(new TransportCategoryRemovePacket());
REQUEST_PACKET.registerPacket(new TransportRemovePacket());
REQUEST_PACKET.registerPacket(new TransportsGetPacket());
REQUEST_PACKET.registerPacket(new TransportSavePacket());
REQUEST_PACKET.registerPacket(new TransportGetLocationPacket());
// Remote Packets Packets
REQUEST_PACKET.registerPacket(new RemoteMainMenuPacket());
REQUEST_PACKET.registerPacket(new RemoteGlobalMenuPacket());
REQUEST_PACKET.registerPacket(new RemoteDeletePacket());
REQUEST_PACKET.registerPacket(new RemoteNpcsGetPacket());
REQUEST_PACKET.registerPacket(new RemoteFreezeGetPacket());
REQUEST_PACKET.registerPacket(new RemoteFreezePacket());
REQUEST_PACKET.registerPacket(new RemoteResetPacket());
REQUEST_PACKET.registerPacket(new RemoteTpToNpcPacket());
// Job Packets
REQUEST_PACKET.registerPacket(new JobGetPacket());
REQUEST_PACKET.registerPacket(new JobSavePacket());
REQUEST_PACKET.registerPacket(new JobSpawnerAddPacket());
REQUEST_PACKET.registerPacket(new JobSpawnerRemovePacket());
// Role Packets
REQUEST_PACKET.registerPacket(new RoleCompanionUpdatePacket());
REQUEST_PACKET.registerPacket(new RoleSavePacket());
REQUEST_PACKET.registerPacket(new RoleGetPacket());
// Transform Packets
REQUEST_PACKET.registerPacket(new TransformSavePacket());
REQUEST_PACKET.registerPacket(new TransformGetPacket());
REQUEST_PACKET.registerPacket(new TransformLoadPacket());
// Trader Packets
REQUEST_PACKET.registerPacket(new TraderMarketSavePacket());
// Party Packets
REQUEST_PACKET.registerPacket(new PartySavePacket());
REQUEST_PACKET.registerPacket(new PartyInfoPacket());
REQUEST_PACKET.registerPacket(new PartyDisbandPacket());
REQUEST_PACKET.registerPacket(new PartySetLeaderPacket());
REQUEST_PACKET.registerPacket(new PartyKickPacket());
REQUEST_PACKET.registerPacket(new PartyLeavePacket());
REQUEST_PACKET.registerPacket(new PartySetQuestPacket());
REQUEST_PACKET.registerPacket(new PartyInvitePacket());
REQUEST_PACKET.registerPacket(new PartyAcceptInvitePacket());
REQUEST_PACKET.registerPacket(new PartyIgnoreInvitePacket());
REQUEST_PACKET.registerPacket(new PartyLogToServerPacket());
// Animation Packets
REQUEST_PACKET.registerPacket(new AnimationsGetPacket());
REQUEST_PACKET.registerPacket(new AnimationGetPacket());
REQUEST_PACKET.registerPacket(new AnimationRemovePacket());
REQUEST_PACKET.registerPacket(new AnimationSavePacket());
// Moving Path
REQUEST_PACKET.registerPacket(new MovingPathSavePacket());
REQUEST_PACKET.registerPacket(new MovingPathGetPacket());
// Tool Packets
REQUEST_PACKET.registerPacket(new ColorBrushPacket());
REQUEST_PACKET.registerPacket(new ColorSetPacket());
// Custom Effect Packets
REQUEST_PACKET.registerPacket(new EffectGetPacket());
REQUEST_PACKET.registerPacket(new EffectsGetPacket());
REQUEST_PACKET.registerPacket(new EffectSavePacket());
REQUEST_PACKET.registerPacket(new EffectRemovePacket());
// Profile Packets
REQUEST_PACKET.registerPacket(new ProfileGetPacket());
REQUEST_PACKET.registerPacket(new ProfileGetInfoPacket());
REQUEST_PACKET.registerPacket(new ProfileCreatePacket());
REQUEST_PACKET.registerPacket(new ProfileRemovePacket());
REQUEST_PACKET.registerPacket(new ProfileRenamePacket());
REQUEST_PACKET.registerPacket(new ProfileChangePacket());
// Job Packets
REQUEST_PACKET.registerPacket(new MagicCycleRemovePacket());
REQUEST_PACKET.registerPacket(new MagicCycleSavePacket());
REQUEST_PACKET.registerPacket(new MagicGetAllPacket());
REQUEST_PACKET.registerPacket(new MagicSavePacket());
REQUEST_PACKET.registerPacket(new MagicRemovePacket());
REQUEST_PACKET.registerPacket(new MagicGetPacket());
// Other Packets
REQUEST_PACKET.registerPacket(new IsGuiOpenInform());
REQUEST_PACKET.registerPacket(new GuiRequestPacket());
REQUEST_PACKET.registerPacket(new DimensionsGetPacket());
REQUEST_PACKET.registerPacket(new MerchantUpdatePacket());
REQUEST_PACKET.registerPacket(new ModelDataSavePacket());
REQUEST_PACKET.registerPacket(new MailOpenSetupPacket());
REQUEST_PACKET.registerPacket(new TileEntityGetPacket());
REQUEST_PACKET.registerPacket(new TileEntitySavePacket());
REQUEST_PACKET.registerPacket(new MountPacket());
REQUEST_PACKET.registerPacket(new DimensionTeleportPacket());
}
public void registerDataPackets(){
// Data Packets
DATA_PACKET.registerPacket(new LoginPacket());
DATA_PACKET.registerPacket(new AchievementPacket());
DATA_PACKET.registerPacket(new ChatAlertPacket());
DATA_PACKET.registerPacket(new ChatBubblePacket());
DATA_PACKET.registerPacket(new ConfigCommandPacket());
DATA_PACKET.registerPacket(new DisableMouseInputPacket());
DATA_PACKET.registerPacket(new MarkDataPacket());
DATA_PACKET.registerPacket(new OverlayQuestTrackingPacket());
DATA_PACKET.registerPacket(new ParticlePacket());
DATA_PACKET.registerPacket(new PlayerUpdateSkinOverlaysPacket());
DATA_PACKET.registerPacket(new QuestCompletionPacket());
DATA_PACKET.registerPacket(new ScrollSelectedPacket());
DATA_PACKET.registerPacket(new SoundManagementPacket());
DATA_PACKET.registerPacket(new SwingPlayerArmPacket());
DATA_PACKET.registerPacket(new UpdateAnimationsPacket());
DATA_PACKET.registerPacket(new VillagerListPacket());
DATA_PACKET.registerPacket(new PlayerDataInfoPacket());
// Data | GUI Packets
DATA_PACKET.registerPacket(new GuiClosePacket());
DATA_PACKET.registerPacket(new GuiOpenPacket());
DATA_PACKET.registerPacket(new GuiErrorPacket());
DATA_PACKET.registerPacket(new GuiRedstonePacket());
DATA_PACKET.registerPacket(new GuiTeleporterPacket());
DATA_PACKET.registerPacket(new GuiWaypointPacket());
DATA_PACKET.registerPacket(new IsGuiOpenPacket());
DATA_PACKET.registerPacket(new GuiOpenBookPacket());
// Data | NPC Packets
DATA_PACKET.registerPacket(new DeleteNpcPacket());
DATA_PACKET.registerPacket(new EditNpcPacket());
DATA_PACKET.registerPacket(new UpdateNpcPacket());
DATA_PACKET.registerPacket(new DialogPacket());
DATA_PACKET.registerPacket(new RolePacket());
DATA_PACKET.registerPacket(new WeaponNpcPacket());
// Data | Script Packets
DATA_PACKET.registerPacket(new ScriptedParticlePacket());
DATA_PACKET.registerPacket(new ScriptOverlayClosePacket());
DATA_PACKET.registerPacket(new ScriptOverlayDataPacket());
// Data | Large Packets
DATA_PACKET.registerPacket(new ClonerPacket());
DATA_PACKET.registerPacket(new ScrollDataPacket());
DATA_PACKET.registerPacket(new ScrollListPacket());
DATA_PACKET.registerPacket(new SyncPacket());
DATA_PACKET.registerPacket(new SyncEffectPacket());
DATA_PACKET.registerPacket(new GuiDataPacket());
DATA_PACKET.registerPacket(new PartyDataPacket());
}
public void registerPlayerPackets() {
PLAYER_PACKET.registerPacket(new FollowerPacket());
PLAYER_PACKET.registerPacket(new TransportPacket());
PLAYER_PACKET.registerPacket(new BankActionPacket());
PLAYER_PACKET.registerPacket(new DialogSelectPacket());
PLAYER_PACKET.registerPacket(new CheckPlayerValue());
PLAYER_PACKET.registerPacket(new MailActionPacket());
PLAYER_PACKET.registerPacket(new MailActionPacket.MailSendPacket());
PLAYER_PACKET.registerPacket(new SaveSignPacket());
PLAYER_PACKET.registerPacket(new SaveBookPacket());
PLAYER_PACKET.registerPacket(new CompanionActionPacket());
PLAYER_PACKET.registerPacket(new GetNPCRole());
PLAYER_PACKET.registerPacket(new InputDevicePacket());
PLAYER_PACKET.registerPacket(new ScreenSizePacket());
// CustomGUI Packets
PLAYER_PACKET.registerPacket(new CustomGuiButtonPacket());
PLAYER_PACKET.registerPacket(new CustomGuiClosePacket());
PLAYER_PACKET.registerPacket(new CustomGuiUnfocusedPacket());
PLAYER_PACKET.registerPacket(new CustomScrollClickPacket());
}
public void registerChannels() {
for (PacketChannel channel : packetChannels) {
FMLEventChannel eventChannel =
NetworkRegistry.INSTANCE.newEventDrivenChannel(channel.getChannelName());
eventChannel.register(this);
channels.put(channel.getChannelType(), eventChannel);
}
}
public PacketChannel getPacketChannel(EnumChannelType type) {
return packetChannels.stream()
.filter(channel -> channel.getChannelType() == type)
.findFirst()
.orElse(null);
}
public FMLEventChannel getEventChannel(AbstractPacket abstractPacket){
PacketChannel packetChannel = getPacketChannel(abstractPacket.getChannel().getChannelType());
if (packetChannel == null) {
return null;
}
return channels.get(packetChannel.getChannelType());
}
@SubscribeEvent
public void onServerPacket(FMLNetworkEvent.ServerCustomPacketEvent event) {
handlePacket(event.packet, ((NetHandlerPlayServer) event.handler).playerEntity, Side.SERVER);
}
@SubscribeEvent
public void onClientPacket(FMLNetworkEvent.ClientCustomPacketEvent event) {
handlePacket(event.packet, CustomNpcs.proxy.getPlayer(), Side.CLIENT);
}
private void handlePacket(FMLProxyPacket packet, EntityPlayer player, Side side) {
ByteBuf buf = packet.payload();
try {
int packetTypeOrdinal = buf.readInt();
EnumChannelType packetType = EnumChannelType.values()[packetTypeOrdinal];
PacketChannel packetChannel = getPacketChannel(packetType);
if (packetChannel == null) {
LogWriter.error("Error: Packet channel is null for packet type: " + packetType);
return;
}
int packetId = buf.readInt();
AbstractPacket abstractPacket = packetChannel.packets.get(packetId);
if (abstractPacket == null) {
LogWriter.error("Error: Abstract packet is null for packet ID: " + packetId);
return;
}
if(side == Side.SERVER){
if(abstractPacket.getChannel() == REQUEST_PACKET && ConfigMain.OpsOnly && !NoppesUtilServer.isOp(player)){
LogWriter.error(String.format("%s tried to use CNPC+ without being an op", player.getCommandSenderName()));
return;
}
// Check if permission is allowed
if(abstractPacket.getPermission() != null && !CustomNpcsPermissions.hasPermission(player, abstractPacket.getPermission())){
return;
}
// Check for required NPC
EntityNPCInterface npc = NoppesUtilServer.getEditingNpc(player);
if(abstractPacket.needsNPC() && npc == null){
return;
}
abstractPacket.setNPC(npc);
}
// Let the packet parse the rest
abstractPacket.receiveData(buf, player);
} catch (IndexOutOfBoundsException e) {
LogWriter.error("Error: IndexOutOfBoundsException in handlePacket: " + e.getMessage());
e.printStackTrace();
} catch (Exception e) {
LogWriter.error("Error: Exception in handlePacket: " + e.getMessage());
e.printStackTrace();
}
}
/**
* Sends every FMLProxyPacket produced by packet.generatePackets()
*/
private void sendAllPackets(AbstractPacket packet, SendAction action) {
// get all generated FMLProxyPacket objects (could be 1 for normal, or many for large)
List<FMLProxyPacket> proxyPackets = packet.generatePackets();
if (proxyPackets.isEmpty()) {
LogWriter.error("Warning: No packets generated for " + packet.getClass().getName());
}
for (FMLProxyPacket proxy : proxyPackets) {
action.send(proxy);
}
}
// ------------------------------------------------------------------------
// Public API methods for sending
public void sendToPlayer(AbstractPacket packet, EntityPlayerMP player) {
FMLEventChannel eventChannel = getEventChannel(packet);
if (eventChannel == null) {
LogWriter.error("Error: Event channel is null for packet: " + packet.getClass().getName());
return;
}
sendAllPackets(packet, p -> eventChannel.sendTo(p, player));
}
public void sendToServer(AbstractPacket packet) {
FMLEventChannel eventChannel = getEventChannel(packet);
if (eventChannel == null) {
LogWriter.error("Error: Event channel is null for packet: " + packet.getClass().getName());
return;
}
sendAllPackets(packet, eventChannel::sendToServer);
}
public void sendToAll(AbstractPacket packet) {
FMLEventChannel eventChannel = getEventChannel(packet);
if (eventChannel == null) {
LogWriter.error("Error: Event channel is null for packet: " + packet.getClass().getName());
return;
}
sendAllPackets(packet, eventChannel::sendToAll);
}
public void sendToDimension(AbstractPacket packet, final int dimensionId) {
FMLEventChannel eventChannel = getEventChannel(packet);
if (eventChannel == null) {
LogWriter.error("Error: Event channel is null for packet: " + packet.getClass().getName());
return;
}
sendAllPackets(packet, p -> eventChannel.sendToDimension(p, dimensionId));
}
public void sendTracking(AbstractPacket packet, final Entity entity) {
FMLEventChannel eventChannel = getEventChannel(packet);
if (eventChannel == null) {
LogWriter.error("Error: Event channel is null for packet: " + packet.getClass().getName());
return;
}
final NetworkRegistry.TargetPoint point = new NetworkRegistry.TargetPoint(entity.dimension, entity.posX, entity.posY, entity.posZ, 60);
sendAllPackets(packet, p -> eventChannel.sendToAllAround(p, point));
}
// Simple functional interface to unify the "send" action
private interface SendAction {
void send(FMLProxyPacket proxy);
}
}
@@ -0,0 +1,242 @@
package kamkeel.npcs.network;
import io.netty.buffer.ByteBuf;
import kamkeel.npcs.network.enums.EnumItemPacketType;
import kamkeel.npcs.network.packets.data.large.GuiDataPacket;
import kamkeel.npcs.util.ByteBufUtils;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import noppes.npcs.CustomItems;
import noppes.npcs.LogWriter;
import noppes.npcs.NBTTags;
import noppes.npcs.controllers.ScriptContainer;
import noppes.npcs.controllers.ScriptController;
import noppes.npcs.controllers.data.IScriptHandler;
import java.io.IOException;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
public class PacketUtil {
public static boolean verifyItemPacket(EnumItemPacketType type, EntityPlayer player) {
if (player == null)
return false;
ItemStack item = player.inventory.getCurrentItem();
if (item == null) {
LogWriter.error(String.format("%s attempted to utilize a %s Packet without an item, they could be a hacker",
player.getCommandSenderName(), type));
return false;
}
switch (type) {
case WAND:
if (item.getItem() != CustomItems.wand) {
LogWriter.error(String.format("%s attempted to utilize a %s Packet without a Wand, they could be a hacker",
player.getCommandSenderName(), type));
return false;
}
break;
case MOUNTER:
if (item.getItem() != CustomItems.mount) {
LogWriter.error(String.format("%s attempted to utilize a %s Packet without a Mounter, they could be a hacker",
player.getCommandSenderName(), type));
return false;
}
break;
case CLONER:
if (item.getItem() != CustomItems.cloner) {
LogWriter.error(String.format("%s attempted to utilize a %s Packet without a Cloner, they could be a hacker",
player.getCommandSenderName(), type));
return false;
}
break;
case TELEPORTER:
if (item.getItem() != CustomItems.teleporter) {
LogWriter.error(String.format("%s attempted to utilize a %s Packet without a Teleporter, they could be a hacker",
player.getCommandSenderName(), type));
return false;
}
break;
case SCRIPTER:
if (item.getItem() != CustomItems.scripter) {
LogWriter.error(String.format("%s attempted to utilize a %s Packet without a Scripter, they could be a hacker",
player.getCommandSenderName(), type));
return false;
}
break;
case PATHER:
if (item.getItem() != CustomItems.moving) {
LogWriter.error(String.format("%s attempted to utilize a %s Packet without a Pather, they could be a hacker",
player.getCommandSenderName(), type));
return false;
}
break;
case BLOCK:
if (item.getItem() == Item.getItemFromBlock(CustomItems.waypoint)
|| item.getItem() == Item.getItemFromBlock(CustomItems.border)
|| item.getItem() == Item.getItemFromBlock(CustomItems.redstoneBlock)) {
LogWriter.error(String.format("%s attempted to utilize a %s Packet without a valid Block, they could be a hacker",
player.getCommandSenderName(), type));
return false;
}
break;
case BRUSH:
if (item.getItem() != CustomItems.tool || item.getItemDamage() != 1) {
LogWriter.error(String.format("%s attempted to utilize a %s Packet without a Pather, they could be a hacker",
player.getCommandSenderName(), type));
return false;
}
break;
}
return true;
}
/**
* New method that accepts multiple EnumItemPacketTypes.
* It returns true if any one of the provided types is valid.
* If none are valid, a merged error message is logged.
*/
public static boolean verifyItemPacket(EntityPlayer player, EnumItemPacketType... types) {
if (player == null)
return false;
ItemStack item = player.inventory.getCurrentItem();
if (item == null) {
LogWriter.error(String.format("%s attempted to utilize a Packet without an item. Expected one of: %s, they could be a hacker",
player.getCommandSenderName(), getExpectedItemNames(types)));
return false;
}
for (EnumItemPacketType type : types) {
if (isValidItemForType(item, type)) {
return true;
}
}
// None passed; log one merged error message listing all expected items.
LogWriter.error(String.format("%s attempted to utilize a Packet without a valid item. Expected one of: %s, they could be a hacker",
player.getCommandSenderName(), getExpectedItemNames(types)));
return false;
}
private static boolean isValidItemForType(ItemStack item, EnumItemPacketType type) {
if(item == null || item.getItem() == null)
return false;
switch (type) {
case WAND:
return item.getItem() == CustomItems.wand;
case MOUNTER:
return item.getItem() == CustomItems.mount;
case CLONER:
return item.getItem() == CustomItems.cloner;
case TELEPORTER:
return item.getItem() == CustomItems.teleporter;
case SCRIPTER:
return item.getItem() == CustomItems.scripter;
case PATHER:
return item.getItem() == CustomItems.moving;
case BLOCK:
// For BLOCK, the item is valid as long as it is NOT one of these blocks.
return !(item.getItem() == Item.getItemFromBlock(CustomItems.waypoint)
|| item.getItem() == Item.getItemFromBlock(CustomItems.border)
|| item.getItem() == Item.getItemFromBlock(CustomItems.redstoneBlock));
case BRUSH:
return item.getItem() == CustomItems.tool && item.getItemDamage() == 1;
default:
return false;
}
}
/**
* Builds a comma‐separated list of expected item names for the given types.
*/
private static String getExpectedItemNames(EnumItemPacketType... types) {
Set<String> expectedNames = new LinkedHashSet<>();
for (EnumItemPacketType type : types) {
expectedNames.add(getExpectedItemName(type));
}
return String.join(", ", expectedNames);
}
/**
* Returns the expected item name for the given EnumItemPacketType.
*/
private static String getExpectedItemName(EnumItemPacketType type) {
switch (type) {
case WAND:
return "Wand";
case MOUNTER:
return "Mounter";
case CLONER:
return "Cloner";
case TELEPORTER:
return "Teleporter";
case SCRIPTER:
return "Scripter";
case PATHER:
return "Pather";
case BLOCK:
return "valid Block";
case BRUSH:
return "Paintbrush";
default:
return type.toString();
}
}
public static void getScripts(IScriptHandler data, EntityPlayerMP player) {
NBTTagCompound compound = new NBTTagCompound();
compound.setBoolean("ScriptEnabled", data.getEnabled());
compound.setString("ScriptLanguage", data.getLanguage());
compound.setTag("Languages", ScriptController.Instance.nbtLanguages());
compound.setTag("ScriptConsole", NBTTags.NBTLongStringMap(data.getConsoleText()));
GuiDataPacket.sendGuiData(player, compound);
List<ScriptContainer> containers = data.getScripts();
for (int i = 0; i < containers.size(); i++) {
ScriptContainer container = containers.get(i);
NBTTagCompound tabCompound = new NBTTagCompound();
tabCompound.setInteger("Tab",i);
tabCompound.setTag("Script",container.writeToNBT(new NBTTagCompound()));
tabCompound.setInteger("TotalScripts",containers.size());
GuiDataPacket.sendGuiData(player, tabCompound);
}
}
public static void saveScripts(IScriptHandler data, ByteBuf buffer) throws IOException {
int tab = buffer.readInt();
int totalScripts = buffer.readInt();
if (totalScripts == 0) {
data.getScripts().clear();
}
if (tab >= 0) {
if (data.getScripts().size() > totalScripts) {
data.setScripts(data.getScripts().subList(0,totalScripts));
} else while (data.getScripts().size() < totalScripts) {
data.getScripts().add(new ScriptContainer(data));
}
NBTTagCompound tabCompound = ByteBufUtils.readNBT(buffer);
ScriptContainer script = new ScriptContainer(data);
script.readFromNBT(tabCompound);
data.getScripts().set(tab,script);
} else {
NBTTagCompound compound = ByteBufUtils.readNBT(buffer);
data.setLanguage(compound.getString("ScriptLanguage"));
if (!ScriptController.Instance.languages.containsKey(data.getLanguage())) {
if (!ScriptController.Instance.languages.isEmpty()) {
data.setLanguage((String) ScriptController.Instance.languages.keySet().toArray()[0]);
} else {
data.setLanguage("ECMAScript");
}
}
data.setEnabled(compound.getBoolean("ScriptEnabled"));
}
}
}
@@ -0,0 +1,8 @@
package kamkeel.npcs.network.enums;
public enum EnumChannelType {
REQUEST,
PLAYER,
DATA,
INFO
}
@@ -0,0 +1,5 @@
package kamkeel.npcs.network.enums;
public enum EnumConfigOperation {
FONT,
}
@@ -0,0 +1,61 @@
package kamkeel.npcs.network.enums;
// Packets to the Client
public enum EnumDataPacket {
// Synchronization
SYNC,
SYNC_EFFECTS,
CONFIG_COMMAND,
// Messages
CHAT_ALERT,
ACHIEVEMENT,
CHATBUBBLE,
SOUND,
DIALOG,
QUEST_COMPLETION,
// NPC
EDIT_NPC,
UPDATE_NPC,
ROLE_NPC,
DELETE_NPC,
CLONE_NPC,
WEAPON_NPC,
// Data
SCROLL_LIST,
SCROLL_DATA,
SCROLL_GROUP,
SCROLL_SELECTED,
PARTY_DATA,
// GUI
GUI_OPEN,
GUI_REDSTONE,
GUI_WAYPOINT,
GUI_TELEPORTER,
GUI_BOOK,
GUI_DATA,
PLAYER_DATA,
GUI_ERROR,
GUI_CLOSE,
ISGUIOPEN,
// Visual
SCRIPTED_PARTICLE,
PARTICLE,
PLAYER_UPDATE_SKIN_OVERLAYS,
UPDATE_ANIMATIONS,
SCRIPT_OVERLAY_DATA,
SCRIPT_OVERLAY_CLOSE,
OVERLAY_QUEST_TRACKING,
MARK_DATA,
// Other
VILLAGER_LIST,
SWING_PLAYER_ARM,
DISABLE_MOUSE_INPUT,
LOGIN,
}
@@ -0,0 +1,12 @@
package kamkeel.npcs.network.enums;
public enum EnumItemPacketType {
WAND,
MOUNTER,
CLONER,
TELEPORTER,
SCRIPTER,
PATHER,
BLOCK,
BRUSH
}
@@ -0,0 +1,22 @@
package kamkeel.npcs.network.enums;
public enum EnumPlayerPacket {
FollowerAction,
Transport,
BankAction,
DialogSelect,
GetPlayerValue,
MailBoxAction,
MailSend,
SaveSign,
SaveBook,
CompanionAction,
GetRole,
InputDevice,
ScreenSize,
CustomGuiButton,
CustomGuiScrollClick,
CustomGuiClose,
CustomGuiUnfocused,
}
@@ -0,0 +1,200 @@
package kamkeel.npcs.network.enums;
public enum EnumRequestPacket {
NPCDelete,
RemoteMainMenu,
RemoteGlobalMenu,
NpcClose,
RemoteDelete,
RemoteFreeze,
RemoteFreezeGet,
RemoteReset,
SpawnMob,
MobSpawner,
DimensionsGet,
MainmenuAISave,
MainmenuAIGet,
MainmenuInvSave,
MainmenuInvGet,
MainmenuStatsSave,
MainmenuStatsGet,
MainmenuDisplaySave,
MainmenuDisplayGet,
ModelDataSave,
MainmenuAdvancedSave,
MainmenuAdvancedGet,
MainmenuAdvancedMarkData,
DialogNpcSet,
DialogNpcRemove,
DialogNpcGet,
DialogCategorySave,
DialogCategoriesGet,
DialogCategoryRemove,
DialogCategoryGet,
DialogSave,
DialogsGet,
DialogGet,
DialogRemove,
TransportSave,
TransportCategoriesGet,
TransportCategorySave,
TransportCategoryRemove,
TransportRemove,
TransportGetLocation,
TransportsGet,
FactionSet,
FactionSave,
FactionsGet,
FactionGet,
FactionRemove,
TagSet,
TagSave,
TagsGet,
TagGet,
NpcTagsGet,
TagRemove,
QuestUntrack,
QuestLogToServer,
QuestCategorySave,
QuestCategoriesGet,
QuestRemove,
QuestCategoryRemove,
QuestRewardSave,
QuestSave,
QuestsGetFromQuest,
QuestsGet,
QuestDialogGetTitle,
QuestOpenGui,
QuestGet,
RecipeSave,
RecipeRemove,
RecipesGet,
RecipeGet,
NaturalSpawnSave,
NaturalSpawnGet,
NaturalSpawnRemove,
NaturalSpawnGetAll,
MerchantUpdate,
MountPacket,
MovingPathSave,
MovingPathGet,
AnimationsGet,
AnimationGet,
AnimationRemove,
AnimationSave,
RemoteNpcsGet,
RemoteTpToNpc,
TileEntitySave,
TileEntityGet,
Gui,
IsGuiOpen,
CacheAnimation,
PartyLogToServer,
PartySave,
PartyInfo,
PartyDisband,
PartyKick,
PartyLeave,
PartyInvite,
PartyAcceptInvite,
PartyIgnoreInvite,
PartySetLeader,
PartySetQuest,
LinkedNPCRemove,
LinkedNPCAdd,
LinkedGetAll,
LinkedSet,
LinkedGet,
LinkedItemSave,
LinkedItemRemove,
LinkedItemBuild,
LinkedItemScript,
BankGet,
BanksGet,
BankSave,
BankRemove,
QuestCategoryGet,
PlayerDataInfo,
PlayerDataGetNames,
PlayerDataDelete,
PlayerDataRemove,
PlayerDataMapRegen,
JobSave,
JobGet,
JobSpawnerAdd,
JobSpawnerRemove,
RoleCompanionUpdate,
RoleSave,
RoleGet,
MailOpenSetup,
TransformSave,
TransformGet,
TransformLoad,
TraderMarketSave,
CloneList,
CloneSave,
CloneRemove,
CloneTagList,
CloneAllTags,
CloneAllTagsShort,
ClonePreSave,
EventScript,
PlayerScript,
ForgeScript,
GlobalNPCScript,
ItemScript,
ItemScriptError,
BlockScript,
NPCScript,
ScriptInfo,
EffectScript,
DimensionTeleport,
EffectList,
EffectGet,
EffectScriptGet,
EffectRemove,
EffectSave,
ColorSet,
ColorBrush,
ProfileGet,
ProfileGetAll,
ProfileGetInfo,
ProfileCreate,
ProfileRemove,
ProfileRename,
ProfileChange,
MagicCycleRemove,
MagicCycleSave,
MagicGetAll,
MagicRemove,
MagicGet, MagicSave
}
@@ -0,0 +1,12 @@
package kamkeel.npcs.network.enums;
public enum EnumSoundOperation {
CONTINUE_SOUNDS,
PAUSE_SOUNDS,
PLAY_MUSIC,
PLAY_SOUND,
PLAY_SOUND_TO,
PLAY_SOUND_TO_NO_ID,
STOP_SOUND_FOR,
STOP_SOUNDS
}
@@ -0,0 +1,7 @@
package kamkeel.npcs.network.enums;
public enum EnumSyncAction {
RELOAD,
UPDATE,
REMOVE
}
@@ -0,0 +1,16 @@
package kamkeel.npcs.network.enums;
public enum EnumSyncType {
FACTION,
DIALOG,
DIALOG_CATEGORY,
QUEST,
QUEST_CATEGORY,
PLAYERDATA,
MAGIC,
MAGIC_CYCLE,
WORKBENCH_RECIPES,
CARPENTRY_RECIPES,
ANVIL_RECIPES,
CUSTOM_EFFECTS
}
@@ -0,0 +1,76 @@
package kamkeel.npcs.network.packets.data;
import cpw.mods.fml.common.ObfuscationReflectionHelper;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import io.netty.buffer.ByteBuf;
import kamkeel.npcs.network.AbstractPacket;
import kamkeel.npcs.network.PacketChannel;
import kamkeel.npcs.network.PacketHandler;
import kamkeel.npcs.network.enums.EnumDataPacket;
import kamkeel.npcs.util.ByteBufUtils;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.achievement.GuiAchievement;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.init.Items;
import net.minecraft.stats.Achievement;
import net.minecraft.util.StatCollector;
import noppes.npcs.CustomItems;
import noppes.npcs.client.MessageAchievement;
import noppes.npcs.config.ConfigClient;
import java.io.IOException;
public final class AchievementPacket extends AbstractPacket {
public static final String packetName = "Data|Achievement";
private boolean isParty;
private String description;
private String message;
public AchievementPacket() {
}
public AchievementPacket(boolean isParty, String description, String message) {
this.isParty = isParty;
this.description = description;
this.message = message;
}
public static void sendAchievement(EntityPlayerMP playerMP, boolean isParty, String description, String message) {
AchievementPacket packet = new AchievementPacket(isParty, description, message);
PacketHandler.Instance.sendToPlayer(packet, playerMP);
}
@Override
public Enum getType() {
return EnumDataPacket.ACHIEVEMENT;
}
@Override
public PacketChannel getChannel() {
return PacketHandler.DATA_PACKET;
}
@Override
public void sendData(ByteBuf out) throws IOException {
out.writeBoolean(this.isParty);
ByteBufUtils.writeString(out, this.description);
ByteBufUtils.writeString(out, this.message);
}
@SideOnly(Side.CLIENT)
@Override
public void receiveData(ByteBuf in, EntityPlayer player) throws IOException {
if (!ConfigClient.BannerAlerts)
return;
boolean isNotParty = !in.readBoolean();
String description = StatCollector.translateToLocal(ByteBufUtils.readString(in));
String message = ByteBufUtils.readString(in);
Achievement ach = isNotParty ? new MessageAchievement(message, description) : new MessageAchievement(CustomItems.bag == null ? Items.paper : CustomItems.bag, message, description);
Minecraft.getMinecraft().guiAchievement.func_146256_a(ach);
ObfuscationReflectionHelper.setPrivateValue(GuiAchievement.class, Minecraft.getMinecraft().guiAchievement, ach.getDescription(), 4);
}
}
@@ -0,0 +1,76 @@
package kamkeel.npcs.network.packets.data;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import io.netty.buffer.ByteBuf;
import kamkeel.npcs.network.AbstractPacket;
import kamkeel.npcs.network.PacketChannel;
import kamkeel.npcs.network.PacketHandler;
import kamkeel.npcs.network.enums.EnumDataPacket;
import kamkeel.npcs.util.ByteBufUtils;
import kamkeel.npcs.util.ColorUtil;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.util.IChatComponent;
import net.minecraft.util.StatCollector;
import noppes.npcs.config.ConfigClient;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public final class ChatAlertPacket extends AbstractPacket {
public static final String packetName = "Data|ChatAlert";
private Object[] objects;
public ChatAlertPacket() {
}
public ChatAlertPacket(final Object... obs) {
this.objects = obs;
}
public static void sendChatAlert(EntityPlayerMP playerMP, final Object... obs) {
ChatAlertPacket packet = new ChatAlertPacket(obs);
PacketHandler.Instance.sendToPlayer(packet, playerMP);
}
@Override
public Enum getType() {
return EnumDataPacket.CHAT_ALERT;
}
@Override
public PacketChannel getChannel() {
return PacketHandler.DATA_PACKET;
}
@Override
public void sendData(ByteBuf out) throws IOException {
ByteBufUtils.fillBuffer(out, this.objects);
}
@SideOnly(Side.CLIENT)
@Override
public void receiveData(ByteBuf in, EntityPlayer player) throws IOException {
if (!ConfigClient.ChatAlerts)
return;
// Read all objects (sent as strings) from the buffer.
List<String> parts = new ArrayList<>();
String part;
while ((part = ByteBufUtils.readString(in)) != null && !part.isEmpty()) {
parts.add(part);
}
StringBuilder finalMessage = new StringBuilder();
for (String s : parts) {
finalMessage.append(StatCollector.translateToLocal(s));
}
String text = finalMessage.toString();
IChatComponent comp = ColorUtil.assembleComponent(text);
player.addChatMessage(comp);
}
}
@@ -0,0 +1,70 @@
package kamkeel.npcs.network.packets.data;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import io.netty.buffer.ByteBuf;
import kamkeel.npcs.network.AbstractPacket;
import kamkeel.npcs.network.PacketChannel;
import kamkeel.npcs.network.PacketHandler;
import kamkeel.npcs.network.enums.EnumDataPacket;
import kamkeel.npcs.util.ByteBufUtils;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.ChatComponentTranslation;
import noppes.npcs.NoppesStringUtils;
import noppes.npcs.client.RenderChatMessages;
import noppes.npcs.entity.EntityNPCInterface;
import java.io.IOException;
public final class ChatBubblePacket extends AbstractPacket {
public static final String packetName = "Data|ChatBubble";
private int entityId;
private String text;
private boolean hideText;
public ChatBubblePacket() {
}
public ChatBubblePacket(int entityId, String text, boolean hideText) {
this.entityId = entityId;
this.text = text;
this.hideText = hideText;
}
@Override
public Enum getType() {
return EnumDataPacket.CHATBUBBLE;
}
@Override
public PacketChannel getChannel() {
return PacketHandler.DATA_PACKET;
}
@Override
public void sendData(ByteBuf out) throws IOException {
out.writeInt(this.entityId);
ByteBufUtils.writeString(out, this.text);
out.writeBoolean(this.hideText);
}
@SideOnly(Side.CLIENT)
@Override
public void receiveData(ByteBuf in, EntityPlayer player) throws IOException {
Entity entity = Minecraft.getMinecraft().theWorld.getEntityByID(in.readInt());
if (!(entity instanceof EntityNPCInterface))
return;
EntityNPCInterface npc = (EntityNPCInterface) entity;
if (npc.messages == null)
npc.messages = new RenderChatMessages();
String text = NoppesStringUtils.formatText(ByteBufUtils.readString(in), player, npc);
npc.messages.addMessage(text, npc);
if (in.readBoolean())
player.addChatMessage(new ChatComponentTranslation(npc.getCommandSenderName() + ": " + text));
}
}
@@ -0,0 +1,57 @@
package kamkeel.npcs.network.packets.data;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import kamkeel.npcs.network.LargeAbstractPacket;
import kamkeel.npcs.network.PacketChannel;
import kamkeel.npcs.network.PacketHandler;
import kamkeel.npcs.network.enums.EnumDataPacket;
import kamkeel.npcs.util.ByteBufUtils;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.NBTTagCompound;
import noppes.npcs.client.NoppesUtil;
import noppes.npcs.client.gui.GuiNpcMobSpawnerAdd;
import java.io.IOException;
public final class ClonerPacket extends LargeAbstractPacket {
public static final String packetName = "Data|Clone";
private NBTTagCompound compound;
public ClonerPacket() {
}
public ClonerPacket(NBTTagCompound comp) {
this.compound = comp;
}
@Override
public Enum getType() {
return EnumDataPacket.CLONE_NPC;
}
@Override
public PacketChannel getChannel() {
return PacketHandler.DATA_PACKET;
}
@Override
protected byte[] getData() throws IOException {
ByteBuf buffer = Unpooled.buffer();
ByteBufUtils.writeBigNBT(buffer, compound);
byte[] bytes = new byte[buffer.readableBytes()];
buffer.readBytes(bytes);
return bytes;
}
@SideOnly(Side.CLIENT)
@Override
protected void handleCompleteData(ByteBuf data, EntityPlayer player) throws IOException {
NBTTagCompound nbt = ByteBufUtils.readBigNBT(data);
NoppesUtil.openGUI(player, new GuiNpcMobSpawnerAdd(nbt));
}
}
@@ -0,0 +1,78 @@
package kamkeel.npcs.network.packets.data;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import io.netty.buffer.ByteBuf;
import kamkeel.npcs.network.AbstractPacket;
import kamkeel.npcs.network.PacketChannel;
import kamkeel.npcs.network.PacketHandler;
import kamkeel.npcs.network.enums.EnumConfigOperation;
import kamkeel.npcs.network.enums.EnumDataPacket;
import kamkeel.npcs.util.ByteBufUtils;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.ChatComponentTranslation;
import noppes.npcs.client.ClientProxy;
import noppes.npcs.client.ClientProxy.FontContainer;
import noppes.npcs.config.ConfigClient;
import java.io.IOException;
public final class ConfigCommandPacket extends AbstractPacket {
public static final String packetName = "Data|ConfigCommand";
private EnumConfigOperation configOperation;
private Object[] objects;
public ConfigCommandPacket() {
}
public ConfigCommandPacket(EnumConfigOperation operation, Object... obs) {
this.configOperation = operation;
this.objects = obs;
}
@Override
public Enum getType() {
return EnumDataPacket.CONFIG_COMMAND;
}
@Override
public PacketChannel getChannel() {
return PacketHandler.DATA_PACKET;
}
@Override
public void sendData(ByteBuf out) throws IOException {
out.writeInt(this.configOperation.ordinal());
ByteBufUtils.fillBuffer(out, objects);
}
@SideOnly(Side.CLIENT)
@Override
public void receiveData(ByteBuf in, EntityPlayer player) throws IOException {
EnumConfigOperation configType = EnumConfigOperation.values()[in.readInt()];
if (configType == EnumConfigOperation.FONT) { // Font Configuration
String font = ByteBufUtils.readString(in);
if(font == null)
return;
int size = in.readInt();
if (!font.isEmpty()) {
ConfigClient.FontType = font;
ConfigClient.FontSize = size;
ClientProxy.Font = new FontContainer(ConfigClient.FontType, ConfigClient.FontSize);
ConfigClient.FontTypeProperty.set(ConfigClient.FontType);
ConfigClient.FontSizeProperty.set(ConfigClient.FontSize);
if (ConfigClient.config.hasChanged()) {
ConfigClient.config.save();
}
player.addChatMessage(new ChatComponentTranslation("Font set to %s", ClientProxy.Font.getName()));
} else {
player.addChatMessage(new ChatComponentTranslation("Current font is %s", ClientProxy.Font.getName()));
}
}
}
}
@@ -0,0 +1,62 @@
package kamkeel.npcs.network.packets.data;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import io.netty.buffer.ByteBuf;
import kamkeel.npcs.network.AbstractPacket;
import kamkeel.npcs.network.PacketChannel;
import kamkeel.npcs.network.PacketHandler;
import kamkeel.npcs.network.enums.EnumDataPacket;
import kamkeel.npcs.util.ByteBufUtils;
import net.minecraft.entity.player.EntityPlayer;
import noppes.npcs.client.ClientEventHandler;
import java.io.IOException;
public final class DisableMouseInputPacket extends AbstractPacket {
public static final String packetName = "Data|DisableMouseInput";
private long duration;
private String keys;
public DisableMouseInputPacket() {
}
public DisableMouseInputPacket(long duration, String keys) {
this.duration = duration;
this.keys = keys;
}
@Override
public Enum getType() {
return EnumDataPacket.DISABLE_MOUSE_INPUT;
}
@Override
public PacketChannel getChannel() {
return PacketHandler.DATA_PACKET;
}
@Override
public void sendData(ByteBuf out) throws IOException {
out.writeLong(this.duration);
ByteBufUtils.writeString(out, this.keys);
}
@SideOnly(Side.CLIENT)
@Override
public void receiveData(ByteBuf in, EntityPlayer player) throws IOException {
long duration = in.readLong();
String parsedButtons = ByteBufUtils.readString(in);
if (parsedButtons == null || parsedButtons.isEmpty()) {
ClientEventHandler.disabledButtonTimes.put(-1, duration);
return;
}
String[] buttonIds = parsedButtons.split(";");
for (String button : buttonIds) {
ClientEventHandler.disabledButtonTimes.put(Integer.parseInt(button), duration);
}
}
}
@@ -0,0 +1,42 @@
package kamkeel.npcs.network.packets.data;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import io.netty.buffer.ByteBuf;
import kamkeel.npcs.network.AbstractPacket;
import kamkeel.npcs.network.PacketChannel;
import kamkeel.npcs.network.PacketHandler;
import kamkeel.npcs.network.enums.EnumDataPacket;
import net.minecraft.entity.player.EntityPlayer;
import noppes.npcs.client.ClientCacheHandler;
import noppes.npcs.config.ConfigMain;
import java.io.IOException;
public final class LoginPacket extends AbstractPacket {
public static final String packetName = "CNPC+|Login";
public LoginPacket() {}
@Override
public Enum getType() {
return EnumDataPacket.LOGIN;
}
@Override
public PacketChannel getChannel() {
return PacketHandler.DATA_PACKET;
}
@Override
public void sendData(ByteBuf out) throws IOException {
out.writeBoolean(ConfigMain.PartiesEnabled);
out.writeBoolean(ConfigMain.ProfilesEnabled);
}
@SideOnly(Side.CLIENT)
@Override
public void receiveData(ByteBuf in, EntityPlayer player) throws IOException {
ClientCacheHandler.allowParties = in.readBoolean();
ClientCacheHandler.allowProfiles = in.readBoolean();
}
}
Loaded 100 of 799 files, more files were not shown because too many files have changed in this diff. Show more