diff --git a/src/main/java/noppes/npcs/AnimationData.java b/src/main/java/noppes/npcs/AnimationData.java index 719f5a34a..fff9e2e3d 100644 --- a/src/main/java/noppes/npcs/AnimationData.java +++ b/src/main/java/noppes/npcs/AnimationData.java @@ -35,7 +35,7 @@ public class AnimationData implements IAnimationData { } public boolean isActive() { - if (!this.allowAnimation || this.animation == null || this.animation.currentFrame == this.animation.frames.size()) + if (!this.allowAnimation || this.animation == null || this.animation.currentFrame == this.animation.frames.size() || animation.currentFrame() == null) return false; if (this.parent instanceof DataDisplay) { diff --git a/src/main/java/noppes/npcs/PacketHandlerServer.java b/src/main/java/noppes/npcs/PacketHandlerServer.java index 6215d9bf6..4f14c0b31 100644 --- a/src/main/java/noppes/npcs/PacketHandlerServer.java +++ b/src/main/java/noppes/npcs/PacketHandlerServer.java @@ -857,6 +857,45 @@ public class PacketHandlerServer{ //NoppesUtilServer.sendRoleData(player, npc); } } + else if(type == EnumPacketServer.AnimationListGet) { + Server.sendData(player, EnumPacketClient.SCROLL_LIST, new ArrayList<>(AnimationController.instance.animations.keySet())); + } + else if(type == EnumPacketServer.AnimationGet) { + String animationName = Server.readString(buffer); + Animation animation = (Animation) AnimationController.instance.get(animationName); + if (animation != null) { + Server.sendData(player, EnumPacketClient.GUI_DATA, animation.writeToNBT()); + } + } + else if (type == EnumPacketServer.AnimationAdd) { + String name = "Animation"; + if (AnimationController.instance.has(name)) { + name += "_"; + int i = 1; + while (AnimationController.instance.has(name + i)) { + i++; + } + name += i; + } + Animation animation = new Animation(name); + animation.save(); + Server.sendData(player, EnumPacketClient.SCROLL_LIST, new ArrayList<>(AnimationController.instance.animations.keySet())); + } + else if (type == EnumPacketServer.AnimationDelete) { + String animationName = Server.readString(buffer); + AnimationController.instance.delete(animationName); + Server.sendData(player, EnumPacketClient.SCROLL_LIST, new ArrayList<>(AnimationController.instance.animations.keySet())); + } + else if (type == EnumPacketServer.AnimationSave) { + String prevName = Server.readString(buffer); + Animation animation = new Animation(); + animation.readFromNBT(Server.readNBT(buffer)); + if (prevName != null && !prevName.equals(animation.getName()) && AnimationController.instance.has(animation.getName())) { + animation.name = prevName; + } + animation.save(); + Server.sendData(player, EnumPacketClient.SCROLL_LIST, new ArrayList<>(AnimationController.instance.animations.keySet())); + } else blockPackets(type, buffer, player); diff --git a/src/main/java/noppes/npcs/client/ClientProxy.java b/src/main/java/noppes/npcs/client/ClientProxy.java index f284dd699..74538011e 100644 --- a/src/main/java/noppes/npcs/client/ClientProxy.java +++ b/src/main/java/noppes/npcs/client/ClientProxy.java @@ -247,6 +247,14 @@ public class ClientProxy extends CommonProxy { else if (gui == EnumGuiType.ManageTags) return new GuiNPCManageTags(npc); + else if (gui == EnumGuiType.ManageAnimations) { + EntityCustomNpc animNpc = new EntityCustomNpc(npc.worldObj); + animNpc.copyDataFrom(npc,true); + animNpc.display.showName = 1; + animNpc.display.showBossBar = 0; + return new GuiNPCManageAnimations(animNpc); + } + else if (gui == EnumGuiType.ManageLinked) return new GuiNPCManageLinkedNpc(npc); diff --git a/src/main/java/noppes/npcs/client/gui/global/GuiNPCManageAnimations.java b/src/main/java/noppes/npcs/client/gui/global/GuiNPCManageAnimations.java new file mode 100644 index 000000000..3ec59794e --- /dev/null +++ b/src/main/java/noppes/npcs/client/gui/global/GuiNPCManageAnimations.java @@ -0,0 +1,492 @@ +package noppes.npcs.client.gui.global; + +import net.minecraft.client.gui.GuiButton; +import net.minecraft.nbt.NBTTagCompound; +import noppes.npcs.AnimationData; +import noppes.npcs.client.Client; +import noppes.npcs.client.gui.util.*; +import noppes.npcs.constants.EnumAnimationPart; +import noppes.npcs.constants.EnumPacketServer; +import noppes.npcs.controllers.data.Animation; +import noppes.npcs.controllers.data.Frame; +import noppes.npcs.controllers.data.FramePart; +import noppes.npcs.entity.EntityCustomNpc; +import noppes.npcs.entity.EntityNPCInterface; + +import java.util.HashMap; +import java.util.Map; +import java.util.Vector; + +public class GuiNPCManageAnimations extends GuiModelInterface implements IScrollData, ITextfieldListener, ICustomScrollListener, IGuiData { + private Animation animation = null; + + private EnumAnimationPart editingPart = EnumAnimationPart.HEAD; + private int editingMode = 0; + private int frameIndex = 0; + public boolean playingAnimation = false; + private Frame prevFrame; + + private GuiCustomScroll scroll; + private String prevSelected = ""; + private long prevTick; + + public GuiNPCManageAnimations(EntityNPCInterface npc) { + super((EntityCustomNpc) npc); + Client.sendData(EnumPacketServer.AnimationListGet); + xOffset -= 20; + yOffset = -45; + npc.display.texture = "customnpcs:textures/entity/humanmale/AnimationBody.png"; + + AnimationData data = npc.display.animationData; + data.setEnabled(true); + } + + @Override + public void initGui() { + super.initGui(); + + if(scroll == null) + scroll = new GuiCustomScroll(this,0); + scroll.setSize(100, 175); + scroll.guiLeft = guiLeft - 20; + scroll.guiTop = guiTop + 15; + this.addScroll(scroll); + + this.addButton(new GuiNpcButton(1,guiLeft - 20, guiTop - 5, 45, 20, "gui.add")); + this.addButton(new GuiNpcButton(2,guiLeft + 30, guiTop - 5, 45, 20, "gui.remove")); + + if (animation != null) { + Frame editingFrame = this.editingFrame(); + if (editingFrame != null) { + if (editingFrame != prevFrame && prevFrame != null) { + HashMap frameParts = prevFrame.frameParts; + for (Map.Entry entry : frameParts.entrySet()) { + if (editingFrame.frameParts.containsKey(entry.getKey())) { + FramePart part = editingFrame.frameParts.get(entry.getKey()); + FramePart prevPart = prevFrame.frameParts.get(entry.getKey()); + part.prevRotations = prevPart.prevRotations; + part.prevPivots = prevPart.prevPivots; + part.partialRotationTick = prevPart.partialRotationTick; + part.partialPivotTick = prevPart.partialPivotTick; + } + } + } + } + prevFrame = editingFrame; + FramePart editingPart = this.editingPart(); + + AnimationData data = npc.display.animationData; + if (!playingAnimation) { + data.animation = new Animation(); + data.animation.smooth = animation.smooth; + data.animation.renderTicks = animation.renderTicks; + data.animation.loop = 0; + if (editingFrame != null) { + data.animation.frames.add(editingFrame); + } + } + + + for (Frame frame : animation.frames) { + frame.parent = animation; + if (!frame.isCustomized()) { + frame.speed = animation.speed; + frame.smooth = animation.smooth; + frame.renderTicks = animation.renderTicks; + } + for (Map.Entry entry : frame.frameParts.entrySet()) { + FramePart part = entry.getValue(); + part.parent = animation; + if (!part.isCustomized()) { + part.speed = frame.speed; + part.smooth = frame.smooth; + } + } + } + + editingMode %= 3; + if (animation.loop >= animation.frames.size()) { + animation.loop = -1; + } + + String animTexture = "customnpcs:textures/gui/animation.png"; + if (data.animation != null && data.animation.frames.size() > 0) { + if (!this.playingAnimation || data.animation.paused) {//Play + this.addLabel(new GuiNpcLabel(90, data.animation.paused ? "animation.paused" : "animation.stopped", guiLeft - 15, guiTop + 206, 0xFFFFFF)); + if (data.animation.paused) { + this.addLabel(new GuiNpcLabel(94, "", guiLeft + 21, guiTop + 206, 0xFFFFFF)); + } + this.addButton(new GuiTexturedButton(91, "", guiLeft + 35, guiTop + 200, 11, 20, animTexture, 18, 71)); + } else {//Pause + this.addLabel(new GuiNpcLabel(90, "animation.playing", guiLeft - 15, guiTop + 206, 0xFFFFFF)); + this.addLabel(new GuiNpcLabel(94, "", guiLeft + 20, guiTop + 206, 0xFFFFFF)); + this.addButton(new GuiTexturedButton(92, "", guiLeft + 35, guiTop + 200, 14, 20, animTexture, 0, 71)); + } + if (this.playingAnimation) {//Stop + this.addButton(new GuiTexturedButton(93, "", guiLeft + 55, guiTop + 200, 14, 20, animTexture, 33, 71)); + } + } + + + this.addLabel(new GuiNpcLabel(10, "animation.frames", guiLeft + 9 + 145, guiTop + 180, 0xFFFFFF)); + this.addButton(new GuiNpcButton(11, guiLeft - 20 + 145, guiTop + 191, 45, 20, "gui.add")); + if (animation.frames.size() > 0) { + frameIndex %= animation.frames.size(); + this.addButton(new GuiNpcButton(12, guiLeft + 30 + 145, guiTop + 191, 45, 20, "gui.remove")); + this.addButton(new GuiNpcButton(13, guiLeft - 3 + 145, guiTop + 210, 20, 20, "<")); + this.addButton(new GuiNpcButton(14, guiLeft + 17 + 145, guiTop + 210, 20, 20, "" + frameIndex)); + this.addButton(new GuiNpcButton(15, guiLeft + 37 + 145, guiTop + 210, 20, 20, ">")); + } + + this.addButton(new GuiNpcButton(20, guiLeft + 290, guiTop - 5, 75, 20, new String[]{"animation.animation", "animation.frame", "animation.framePart"}, editingMode)); + + if (editingMode == 0) { + //name - textfield + // Send the old animation name (string selected on the scroll). + // On the server side, if the new animation's name is different from the old one but already exists, + // do not change the name (set the name to the old animation name after the animation is read from NBT). + this.addTextField(new GuiNpcTextField(30, this, guiLeft + 270, guiTop + 18, 100, 15, animation.name)); + // + //speed - textfield + this.addLabel(new GuiNpcLabel(31, "stats.speed", guiLeft + 270, guiTop + 44, 0xFFFFFF)); + this.addTextField(new GuiNpcTextField(32, this, guiLeft + 310, guiTop + 40, 30, 15, animation.speed + "")); + this.getTextField(32).floatsOnly = true; + this.getTextField(32).setMinMaxDefaultFloat(0,Float.MAX_VALUE,1.0F); + // + //smooth - button + this.addLabel(new GuiNpcLabel(33, "animation.smoothing", guiLeft + 270, guiTop + 64, 0xFFFFFF)); + this.addButton(new GuiNpcButton(34, guiLeft + 325, guiTop + 58, 60, 20, new String[]{"animation.smooth", "animation.linear", "gui.none"}, animation.smooth)); + // + //ticks - button + this.addLabel(new GuiNpcLabel(35, "animation.tickType", guiLeft + 270, guiTop + 104, 0xFFFFFF)); + this.addButton(new GuiNpcButton(36, guiLeft + 325, guiTop + 98, 75, 20, new String[]{"animation.renderTicks", "animation.mcTicks"}, animation.renderTicks ? 0 : 1)); + // + //loop - button + this.addLabel(new GuiNpcLabel(37, "animation.loopStart", guiLeft + 270, guiTop + 84, 0xFFFFFF)); + this.addButton(new GuiNpcButton(38, guiLeft + 325, guiTop + 78, 75, 20, animation.loop == -1 ? "No Looping" : "Frame " + animation.loop)); + // + //whileStanding - button + this.addLabel(new GuiNpcLabel(39, "animation.whileStanding", guiLeft + 270, guiTop + 124, 0xFFFFFF)); + this.addButton(new GuiNpcButton(40, guiLeft + 345, guiTop + 118, 30, 20, new String[]{"gui.yes", "gui.no"}, animation.whileStanding ? 0 : 1)); + // + //whileAttacking - button + this.addLabel(new GuiNpcLabel(41, "animation.whileAttacking", guiLeft + 270, guiTop + 144, 0xFFFFFF)); + this.addButton(new GuiNpcButton(42, guiLeft + 345, guiTop + 138, 30, 20, new String[]{"gui.yes", "gui.no"}, animation.whileAttacking ? 0 : 1)); + // + //whileMoving - button + this.addLabel(new GuiNpcLabel(43, "animation.whileMoving", guiLeft + 270, guiTop + 164, 0xFFFFFF)); + this.addButton(new GuiNpcButton(44, guiLeft + 345, guiTop + 158, 30, 20, new String[]{"gui.yes", "gui.no"}, animation.whileMoving ? 0 : 1)); + + } else if (editingFrame != null) { + if (editingMode == 1) { + // + //duration - textfield + this.addLabel(new GuiNpcLabel(50, "animation.duration", guiLeft + 270, guiTop + 25, 0xFFFFFF)); + this.addTextField(new GuiNpcTextField(51, this, guiLeft + 330, guiTop + 21, 30, 15, editingFrame.duration + "")); + this.getTextField(51).integersOnly = true; + this.getTextField(51).setMinMaxDefaultFloat(0, Integer.MAX_VALUE, 10); + // + //customized - button, enables all the following options. + this.addLabel(new GuiNpcLabel(52, "animation.customized", guiLeft + 270, guiTop + 44, 0xFFFFFF)); + this.addButton(new GuiNpcButton(53, guiLeft + 325, guiTop + 38, 30, 20, new String[]{"gui.yes", "gui.no"}, editingFrame.isCustomized() ? 0 : 1)); + if (editingFrame.isCustomized()) { + // + //speed - textfield + this.addLabel(new GuiNpcLabel(31, "stats.speed", guiLeft + 270, guiTop + 64, 0xFFFFFF)); + this.addTextField(new GuiNpcTextField(32, this, guiLeft + 330, guiTop + 60, 30, 15, editingFrame.speed + "")); + this.getTextField(32).floatsOnly = true; + this.getTextField(32).setMinMaxDefaultFloat(0, Float.MAX_VALUE, 1.0F); + // + //smooth - button + this.addLabel(new GuiNpcLabel(33, "animation.smoothing", guiLeft + 270, guiTop + 84, 0xFFFFFF)); + this.addButton(new GuiNpcButton(34, guiLeft + 325, guiTop + 78, 60, 20, new String[]{"animation.smooth", "animation.linear", "gui.none"}, editingFrame.smooth)); + // + //ticks - button + this.addLabel(new GuiNpcLabel(35, "animation.tickType", guiLeft + 270, guiTop + 104, 0xFFFFFF)); + this.addButton(new GuiNpcButton(36, guiLeft + 325, guiTop + 98, 75, 20, new String[]{"animation.renderTicks", "animation.mcTicks"}, editingFrame.renderTicks ? 0 : 1)); + } + } else if (editingMode == 2) { + // + //6 body part textured buttons + //Add/remove part button + // 6 custom GUI textured buttons for each body part determine "this.currentPart (enum)". + // If the current frame doesn't have that part, the button will say "Add part" + // otherwise, the button will say "Remove", and more options for editing the part become available: + // + + //Head + this.addButton(new GuiTexturedButton(60, "",guiLeft + 270, guiTop + 18,22,23, animTexture,0,0)); + //Body + this.addButton(new GuiTexturedButton(61, "",guiLeft + 270, guiTop + 43,22,23, animTexture,24,0)); + //Right Arm + this.addButton(new GuiTexturedButton(62, "",guiLeft + 261, guiTop + 43,8,23, animTexture,48,0)); + //Left Arm + this.addButton(new GuiTexturedButton(63, "",guiLeft + 296, guiTop + 43,8,23, animTexture,48,0)); + //Right Leg + this.addButton(new GuiTexturedButton(64, "",guiLeft + 271, guiTop + 68,10,23, animTexture,58,0)); + //Left Leg + this.addButton(new GuiTexturedButton(65, "",guiLeft + 282, guiTop + 68,10,23, animTexture,58,0)); + //Full Body + this.addButton(new GuiTexturedButton(66, "",guiLeft + 310, guiTop + 20,17,23, animTexture,70,0)); + + for (int i = 0; i < 7; i++) { + if (this.buttons.containsKey(60 + i)) { + ((GuiTexturedButton) this.getButton(60 + i)).scale = 1.2F; + if (!editingFrame.frameParts.containsKey(EnumAnimationPart.values()[i])) { + ((GuiTexturedButton) this.getButton(60 + i)).textureX += 96; + } + } + } + + if (editingPart != null) { + //remove part button + this.addLabel(new GuiNpcLabel(67, editingPart.part.name(), guiLeft + 320, guiTop + 60, 0xFFFFFF)); + this.addButton(new GuiNpcButton(68, guiLeft + 315, guiTop + 75, 60, 20, "gui.remove")); + // + //rotation - 3 textfields + this.addLabel(new GuiNpcLabel(70, "animation.rotations", guiLeft + 270, guiTop + 105, 0xFFFFFF)); + this.addTextField(new GuiNpcTextField(71, this, guiLeft + 270, guiTop + 117, 35, 15, editingPart.rotation[0] + "")); + this.getTextField(71).floatsOnly = true; + this.getTextField(71).setMinMaxDefaultFloat(-Float.MAX_VALUE, Float.MAX_VALUE, 0); + this.addTextField(new GuiNpcTextField(72, this, guiLeft + 310, guiTop + 117, 35, 15, editingPart.rotation[1] + "")); + this.getTextField(72).floatsOnly = true; + this.getTextField(72).setMinMaxDefaultFloat(-Float.MAX_VALUE, Float.MAX_VALUE, 0); + this.addTextField(new GuiNpcTextField(73, this, guiLeft + 350, guiTop + 117, 35, 15, editingPart.rotation[2] + "")); + this.getTextField(73).floatsOnly = true; + this.getTextField(73).setMinMaxDefaultFloat(-Float.MAX_VALUE, Float.MAX_VALUE, 0); + // + //pivot - 3 textfields + this.addLabel(new GuiNpcLabel(80, "animation.pivots", guiLeft + 270, guiTop + 137, 0xFFFFFF)); + this.addTextField(new GuiNpcTextField(81, this, guiLeft + 270, guiTop + 149, 35, 15, editingPart.pivot[0] + "")); + this.getTextField(81).floatsOnly = true; + this.getTextField(81).setMinMaxDefaultFloat(-Float.MAX_VALUE, Float.MAX_VALUE, 0); + this.addTextField(new GuiNpcTextField(82, this, guiLeft + 310, guiTop + 149, 35, 15, editingPart.pivot[1] + "")); + this.getTextField(82).floatsOnly = true; + this.getTextField(82).setMinMaxDefaultFloat(-Float.MAX_VALUE, Float.MAX_VALUE, 0); + this.addTextField(new GuiNpcTextField(83, this, guiLeft + 350, guiTop + 149, 35, 15, editingPart.pivot[2] + "")); + this.getTextField(83).floatsOnly = true; + this.getTextField(83).setMinMaxDefaultFloat(-Float.MAX_VALUE, Float.MAX_VALUE, 0); + // + //customized - button, enables all the following options. + this.addLabel(new GuiNpcLabel(52, "animation.customized", guiLeft + 270, guiTop + 174, 0xFFFFFF)); + this.addButton(new GuiNpcButton(53, guiLeft + 325, guiTop + 168, 30, 20, new String[]{"gui.yes", "gui.no"}, editingPart.isCustomized() ? 0 : 1)); + if (editingPart.isCustomized()) { + // + //speed - textfield + this.addLabel(new GuiNpcLabel(31, "stats.speed", guiLeft + 270, guiTop + 194, 0xFFFFFF)); + this.addTextField(new GuiNpcTextField(32, this, guiLeft + 330, guiTop + 190, 30, 15, editingPart.speed + "")); + this.getTextField(32).floatsOnly = true; + this.getTextField(32).setMinMaxDefaultFloat(0, Float.MAX_VALUE, 1.0F); + // + //smooth - button + this.addLabel(new GuiNpcLabel(33, "animation.smoothing", guiLeft + 270, guiTop + 214, 0xFFFFFF)); + this.addButton(new GuiNpcButton(34, guiLeft + 325, guiTop + 208, 60, 20, new String[]{"animation.smooth", "animation.linear", "gui.none"}, editingPart.smooth)); + } + } + } + } else { + this.addLabel(new GuiNpcLabel(50, "animation.addFrame", guiLeft + 270, guiTop + 100, 0xFFFFFF)); + } + } + } + + private Frame editingFrame() { + if (this.animation == null || this.frameIndex >= this.animation.frames.size()) { + return null; + } + return animation.frames.get(this.frameIndex); + } + + private FramePart editingPart() { + Frame editingFrame = this.editingFrame(); + if (this.animation == null || editingFrame == null) { + return null; + } + return editingFrame.frameParts.get(this.editingPart); + } + + @Override + protected void actionPerformed(GuiButton guibutton){ + super.actionPerformed(guibutton); + Frame editingFrame = this.editingFrame(); + FramePart part = this.editingPart(); + int value = ((GuiNpcButton)guibutton).getValue(); + AnimationData data = npc.display.animationData; + + if (guibutton.id == 1) { + Client.sendData(EnumPacketServer.AnimationAdd); + frameIndex = 0; + } else if (guibutton.id == 2 && scroll.getSelected() != null) { + Client.sendData(EnumPacketServer.AnimationDelete, scroll.getSelected()); + this.playingAnimation = false; + data.animation = null; + animation = null; + frameIndex = 0; + } else if (guibutton.id == 11) { + if (frameIndex < animation.frames.size() - 1) { + animation.frames.add(frameIndex + 1, new Frame(10)); + } else { + animation.frames.add(new Frame(10)); + } + } else if (guibutton.id == 12) { + animation.frames.remove(frameIndex); + } else if (guibutton.id == 13 && frameIndex > 0) { + frameIndex--; + } else if (guibutton.id == 14 || guibutton.id == 15) { + frameIndex++; + } else if (guibutton.id == 20) { + editingMode++; + } else if (guibutton.id >= 60 && guibutton.id <= 66) {//Animation part buttons + EnumAnimationPart enumPart = EnumAnimationPart.values()[guibutton.id-60]; + if (editingFrame != null && !editingFrame.frameParts.containsKey(enumPart)) { + FramePart framePart = new FramePart(enumPart); + framePart.prevRotations = new float[]{0, 0, 0}; + editingFrame.addPart(framePart); + } + this.editingPart = enumPart; + } else if (guibutton.id == 68 && editingFrame != null) { + editingFrame.removePart(this.editingPart.name()); + } else if (guibutton.id == 53 && editingFrame != null) { + if (editingMode == 1) { + editingFrame.setCustomized(!editingFrame.isCustomized()); + } else if (editingMode == 2 && part != null) { + part.setCustomized(!part.isCustomized()); + } + } else if (guibutton.id == 34) { + if (editingMode == 0) { + animation.smooth = (byte) value; + } else if (editingMode == 1 && editingFrame != null) { + editingFrame.smooth = (byte) value; + } else if (editingMode == 2 && part != null) { + part.smooth = (byte) value; + } + } else if (guibutton.id == 36) { + if (editingMode == 0) { + animation.renderTicks = value == 0; + } else if (editingMode == 1 && editingFrame != null) { + editingFrame.renderTicks = value == 0; + } + } else if (guibutton.id == 38) { + animation.loop++; + } else if (guibutton.id == 40) { + animation.whileStanding = value == 0; + } else if (guibutton.id == 42) { + animation.whileAttacking = value == 0; + } else if (guibutton.id == 44) { + animation.whileMoving = value == 0; + } else if (guibutton.id == 91) { + if (!this.playingAnimation || !data.isActive()) { + animation.currentFrame = 0; + animation.currentFrameTime = 0; + for (Frame frame : animation.frames) { + for (FramePart framePart : frame.frameParts.values()) { + framePart.prevRotations = new float[]{0,0,0}; + framePart.prevPivots = new float[]{0, 0, 0}; + } + } + } + this.playingAnimation = true; + data.animation = animation; + data.animation.paused = false; + } else if (guibutton.id == 92) { + data.animation.paused = true; + } else if (guibutton.id == 93) { + this.playingAnimation = false; + data.animation.paused = false; + } + + initGui(); + } + + @Override + public void drawScreen(int par1, int par2, float par3) + { + super.drawScreen(par1,par2,par3); + AnimationData data = npc.display.animationData; + if (!data.isActive()) { + this.playingAnimation = false; + initGui(); + } else { + Frame currentFrame = (Frame) data.animation.currentFrame(); + long time = mc.theWorld.getWorldTime(); + if (time != prevTick) { + if (currentFrame != null && !currentFrame.renderTicks) { + data.animation.increaseTime(); + } + GuiNpcLabel label = this.getLabel(94); + if (label != null) { + label.label += "."; + if (label.label.length()%4 == 0) { + label.label = ""; + } + } + } + prevTick = time; + } + } + + @Override + public void customScrollClicked(int i, int j, int k, GuiCustomScroll scroll) { + if (scroll.id == 0) { + if (animation != null) { + if (!prevSelected.isEmpty()) { + Client.sendData(EnumPacketServer.AnimationSave, prevSelected, animation.writeToNBT()); + } + } + Client.sendData(EnumPacketServer.AnimationGet, scroll.getSelected()); + frameIndex = 0; + prevSelected = scroll.getSelected(); + } + } + + @Override + public void unFocused(GuiNpcTextField textfield) { + String text = textfield.getText(); + Frame frame = this.editingFrame(); + FramePart part = this.editingPart(); + + if (textfield.id == 30 && !text.isEmpty()) { + animation.name = text.replaceAll("[^a-zA-Z0-9_-]", "_"); + } else if (textfield.id == 32) { + if (editingMode == 0) { + animation.speed = textfield.getFloat(); + } else if (editingMode == 1 && frame != null) { + frame.speed = textfield.getFloat(); + } else if (editingMode == 2 && part != null) { + part.speed = textfield.getFloat(); + } + } else if (textfield.id == 51 && frame != null) { + frame.duration = textfield.getInteger(); + } else if (textfield.id >= 71 && textfield.id <= 73 && part != null) { + part.rotation[textfield.id-71] = textfield.getFloat(); + } else if (textfield.id >= 81 && textfield.id <= 83 && part != null) { + part.pivot[textfield.id-81] = textfield.getFloat(); + } + } + + @Override + public void setData(Vector list, HashMap data) { + scroll.setList(list); + initGui(); + } + + @Override + public void setSelected(String selected) { + + } + + @Override + public void setGuiData(NBTTagCompound compound) { + this.animation = new Animation(); + animation.readFromNBT(compound); + initGui(); + } + + @Override + public void onGuiClosed() { + super.onGuiClosed(); + if (animation != null) { + Client.sendData(EnumPacketServer.AnimationSave, prevSelected, animation.writeToNBT()); + } + } +} diff --git a/src/main/java/noppes/npcs/client/gui/mainmenu/GuiNPCGlobalMainMenu.java b/src/main/java/noppes/npcs/client/gui/mainmenu/GuiNPCGlobalMainMenu.java index f37ee68c9..6ed627a4c 100644 --- a/src/main/java/noppes/npcs/client/gui/mainmenu/GuiNPCGlobalMainMenu.java +++ b/src/main/java/noppes/npcs/client/gui/mainmenu/GuiNPCGlobalMainMenu.java @@ -19,17 +19,18 @@ public class GuiNPCGlobalMainMenu extends GuiNPCInterface2{ public void initGui(){ super.initGui(); int y = guiTop + 10; - this.addButton(new GuiNpcButton(2, guiLeft + 85, y, "global.banks")); - this.addButton(new GuiNpcButton(3, guiLeft + 85, y += 22, "menu.factions")); - this.addButton(new GuiNpcButton(4, guiLeft + 85, y += 22, "dialog.dialogs")); - this.addButton(new GuiNpcButton(11, guiLeft + 85, y += 22, "quest.quests")); - this.addButton(new GuiNpcButton(12, guiLeft + 85, y += 22, "global.transport")); - this.addButton(new GuiNpcButton(13, guiLeft + 85, y += 22, "global.playerdata")); - this.addButton(new GuiNpcButton(14, guiLeft + 85, y += 22, "global.recipes")); - this.addButton(new GuiNpcButton(15, guiLeft + 85, y += 22, NoppesStringUtils.translate("global.naturalspawn"))); - this.addButton(new GuiNpcButton(16, guiLeft + 85, y += 22, "global.linked")); - this.addButton(new GuiNpcButton(17, guiLeft + 85, y += 22, "menu.tags")); - + this.addButton(new GuiNpcButton(2, guiLeft + 5, y, "global.banks")); + this.addButton(new GuiNpcButton(3, guiLeft + 5, y += 22, "menu.factions")); + this.addButton(new GuiNpcButton(4, guiLeft + 5, y += 22, "dialog.dialogs")); + this.addButton(new GuiNpcButton(11, guiLeft + 5, y += 22, "quest.quests")); + this.addButton(new GuiNpcButton(12, guiLeft + 5, y += 22, "global.transport")); + this.addButton(new GuiNpcButton(13, guiLeft + 5, y += 22, "global.playerdata")); + this.addButton(new GuiNpcButton(14, guiLeft + 5, y += 22, "global.recipes")); + this.addButton(new GuiNpcButton(15, guiLeft + 5, y += 22, NoppesStringUtils.translate("global.naturalspawn"))); + this.addButton(new GuiNpcButton(16, guiLeft + 5, y += 22, "global.linked")); + y = guiTop + 10; + this.addButton(new GuiNpcButton(18, guiLeft + 210, y, "menu.animations")); + this.addButton(new GuiNpcButton(17, guiLeft + 210, y += 22, "menu.tags")); } @Override @@ -47,6 +48,9 @@ public class GuiNPCGlobalMainMenu extends GuiNPCInterface2{ if (id == 17) { NoppesUtil.requestOpenGUI(EnumGuiType.ManageTags); } + if (id == 18) { + NoppesUtil.requestOpenGUI(EnumGuiType.ManageAnimations); + } if (id == 4) { NoppesUtil.requestOpenGUI(EnumGuiType.ManageDialogs); } diff --git a/src/main/java/noppes/npcs/client/gui/util/GuiModelInterface.java b/src/main/java/noppes/npcs/client/gui/util/GuiModelInterface.java index 6bac8bd2b..31c03f588 100644 --- a/src/main/java/noppes/npcs/client/gui/util/GuiModelInterface.java +++ b/src/main/java/noppes/npcs/client/gui/util/GuiModelInterface.java @@ -23,6 +23,7 @@ public class GuiModelInterface extends GuiNPCInterface{ private static float zoomed = 60; public int xOffset = 0; + public int yOffset = 0; public EntityCustomNpc npc; @@ -37,17 +38,17 @@ public class GuiModelInterface extends GuiNPCInterface{ public void initGui() { super.initGui(); - addButton(unzoom = new GuiNpcButton(666, guiLeft + 148 + xOffset, guiTop + 200, 20, 20, "-")); - addButton(zoom = new GuiNpcButton(667, guiLeft + 214 + xOffset, guiTop + 200, 20, 20, "+")); - addButton(left = new GuiNpcButton(668, guiLeft + 170 + xOffset, guiTop + 200, 20, 20, "<")); - addButton(right = new GuiNpcButton(669, guiLeft + 192 + xOffset, guiTop + 200, 20, 20, ">")); + addButton(unzoom = new GuiNpcButton(666, guiLeft + 148 + xOffset, guiTop + 200 + yOffset, 20, 20, "-")); + addButton(zoom = new GuiNpcButton(667, guiLeft + 214 + xOffset, guiTop + 200 + yOffset, 20, 20, "+")); + addButton(left = new GuiNpcButton(668, guiLeft + 170 + xOffset, guiTop + 200 + yOffset, 20, 20, "<")); + addButton(right = new GuiNpcButton(669, guiLeft + 192 + xOffset, guiTop + 200 + yOffset, 20, 20, ">")); - addButton(new GuiNpcButton(66, width - 22, 2, 20, 20, "X")); + addButton(new GuiNpcButton(670, width - 22, 2, 20, 20, "X")); } @Override protected void actionPerformed(GuiButton btn) { - if(btn.id == 66){ + if(btn.id == 670){ close(); } } @@ -81,7 +82,7 @@ public class GuiModelInterface extends GuiNPCInterface{ EntityUtil.Copy(npc, entity); int l = guiLeft + 190 + xOffset; - int i1 = guiTop + 180; + int i1 = guiTop + 180 + yOffset; GL11.glEnable(GL11.GL_COLOR_MATERIAL); GL11.glPushMatrix(); GL11.glTranslatef(l, i1, 60F); diff --git a/src/main/java/noppes/npcs/client/gui/util/GuiNPCInterface.java b/src/main/java/noppes/npcs/client/gui/util/GuiNPCInterface.java index d83eca7c1..d7d057d16 100644 --- a/src/main/java/noppes/npcs/client/gui/util/GuiNPCInterface.java +++ b/src/main/java/noppes/npcs/client/gui/util/GuiNPCInterface.java @@ -27,7 +27,7 @@ public abstract class GuiNPCInterface extends GuiScreen public EntityClientPlayerMP player; public boolean drawDefaultBackground = true; public EntityNPCInterface npc; - private HashMap buttons = new HashMap(); + protected HashMap buttons = new HashMap(); private HashMap topbuttons = new HashMap(); private HashMap sidebuttons = new HashMap(); private HashMap textfields = new HashMap(); diff --git a/src/main/java/noppes/npcs/client/gui/util/GuiTexturedButton.java b/src/main/java/noppes/npcs/client/gui/util/GuiTexturedButton.java new file mode 100644 index 000000000..0e2dc39e2 --- /dev/null +++ b/src/main/java/noppes/npcs/client/gui/util/GuiTexturedButton.java @@ -0,0 +1,208 @@ +package noppes.npcs.client.gui.util; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.texture.ITextureObject; +import net.minecraft.client.renderer.texture.TextureManager; +import net.minecraft.client.resources.IResource; +import net.minecraft.util.ResourceLocation; +import noppes.npcs.client.ImageDownloadAlt; +import noppes.npcs.client.gui.custom.GuiCustom; +import noppes.npcs.client.renderer.ImageBufferDownloadAlt; +import org.lwjgl.opengl.GL11; + +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.io.InputStream; + +public class GuiTexturedButton extends GuiNpcButton { + ResourceLocation location; + public int textureX; + public int textureY; + boolean field_146123_n; + String label; + + public int color; + public float alpha; + public float scale; + + private int totalWidth, totalHeight; + private ImageDownloadAlt imageDownloadAlt = null; + private boolean isUrl = false; + private boolean gotWidthHeight = false; + + public GuiTexturedButton(int id, String buttonText, int x, int y) { + this(id, buttonText, x, y, 200, 20); + } + + public GuiTexturedButton(int id, String buttonText, int x, int y, int width, int height) { + this(id, buttonText, x, y, width, height, ""); + } + + public GuiTexturedButton(int buttonId, String buttonText, int x, int y, int width, int height, String texture) { + this(buttonId, buttonText, x, y, width, height, texture, 0, 0); + } + + public GuiTexturedButton(int buttonId, String buttonText, int x, int y, int width, int height, String texture, int textureX, int textureY) { + super(buttonId, x, y, width, height, buttonText); + this.textureX = textureX; + this.textureY = textureY; + this.label = buttonText; + this.scale = 1.0F; + this.color = 0xFFFFFF; + this.alpha = 1.0F; + if (texture != null && !texture.isEmpty()) { + this.location = new ResourceLocation(texture); + if(texture.startsWith("https://")){ + TextureManager texturemanager = Minecraft.getMinecraft().getTextureManager(); + ITextureObject object = new ImageDownloadAlt(null, texture, new ResourceLocation("customnpcs:textures/gui/invisible.png"), new ImageBufferDownloadAlt(true,false)); + texturemanager.loadTexture(this.location, object); + } else { + try { + this.getWidthHeight(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } else { + this.location = null; + } + } + + public void drawButton(Minecraft mc, int mouseX, int mouseY) + { + if (!this.visible) + { + return; + } + this.field_146123_n = mouseX >= this.xPosition && mouseY >= this.yPosition && mouseX < this.xPosition + this.width * this.scale && mouseY < this.yPosition + this.height * this.scale; + + if(imageDownloadAlt != null && isUrl && !gotWidthHeight){ + getURLWidthHeight(); + } + + if (this.location == null) { + totalWidth = totalHeight = 256; + textureX = textureY = 0; + } + + GL11.glPushMatrix(); + if (this.location != null) { + mc.getTextureManager().bindTexture(this.location); + this.drawTexturedModalRect(0, 0, this.textureX, this.textureY, this.width, this.height); + GL11.glTranslated(0.0D, 0.0D, 0.1D); + this.drawCenteredString(mc.fontRenderer, this.label, this.width / 2, (this.height - 8) / 2, this.color); + } else { + FontRenderer fontrenderer = mc.fontRenderer; + mc.getTextureManager().bindTexture(buttonTextures); + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + int k = this.getHoverState(this.field_146123_n); + GL11.glEnable(GL11.GL_BLEND); + OpenGlHelper.glBlendFunc(770, 771, 1, 0); + this.drawTexturedModalRect(0, 0, 0, 46 + k * 20, this.width / 2, this.height); + this.drawTexturedModalRect(this.width / 2, 0, 200 - this.width / 2, 46 + k * 20, this.width / 2, this.height); + this.mouseDragged(mc, mouseX, mouseY); + int l = 14737632; + + if (packedFGColour != 0) + { + l = packedFGColour; + } + else if (!this.enabled) + { + l = 10526880; + } + else if (this.field_146123_n) + { + l = 16777120; + } + + this.drawCenteredString(fontrenderer, this.displayString, this.xPosition + this.width / 2, this.yPosition + (this.height - 8) / 2, l); + } + GL11.glPopMatrix(); + } + + public void drawTexturedModalRect(int x, int y, int textureX, int textureY, int width, int height) + { + GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + GL11.glPushMatrix(); + float red = (color >> 16 & 255) / 255f; + float green = (color >> 8 & 255) / 255f; + float blue = (color & 255) / 255f; + GL11.glColor4f(red,green,blue,this.alpha); + + float u1 = (float)textureX/(float)totalWidth; + float u2 = u1 + (float)width/(float)totalWidth; + float v1 = (float)textureY/(float)totalHeight; + float v2 = v1 + (float)height/(float)totalHeight; + + if (this.location != null && this.enabled) { + if (this.field_146123_n) { + v1 = (float)(textureY + 2 * this.height)/(float)totalHeight; + } else { + v1 = (float)(textureY + this.height)/(float)totalHeight; + } + v2 = v1 + (float)height/(float)totalHeight; + } + + GL11.glTranslatef(x + this.xPosition - u1 * totalWidth * this.scale, y + this.yPosition - v1 * totalHeight * this.scale, (float)this.id); + + GL11.glScalef(this.scale,this.scale,1.0F); + GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + Tessellator tessellator = Tessellator.instance; + tessellator.startDrawingQuads(); + tessellator.setColorOpaque_F(1, 1, 1); + tessellator.setColorRGBA_F(red, green, blue, alpha); + tessellator.addVertexWithUV(u2 * totalWidth, v2 * totalHeight, 0, u2, v2); + tessellator.addVertexWithUV(u2 * totalWidth, v1 * totalHeight, 0, u2, v1); + tessellator.addVertexWithUV(u1 * totalWidth, v1 * totalHeight, 0, u1, v1); + tessellator.addVertexWithUV(u1 * totalWidth, v2 * totalHeight, 0, u1, v2); + tessellator.draw(); + GL11.glPopMatrix(); + } + + @Override + public boolean mousePressed(Minecraft minecraft, int i, int j) + { + return super.mousePressed(minecraft,i,j) || this.field_146123_n; + } + + public void getWidthHeight() throws IOException { + InputStream inputstream = null; + + try { + IResource iresource = Minecraft.getMinecraft().getResourceManager().getResource(this.location); + inputstream = iresource.getInputStream(); + BufferedImage bufferedimage = ImageIO.read(inputstream); + gotWidthHeight = true; + this.totalWidth = bufferedimage.getWidth(); + this.totalHeight = bufferedimage.getHeight(); + correctWidthHeight(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (inputstream != null) { + inputstream.close(); + } + } + } + + public void getURLWidthHeight(){ + if(imageDownloadAlt.getBufferedImage() != null) { + gotWidthHeight = true; + this.totalWidth = imageDownloadAlt.getBufferedImage().getWidth(); + this.totalHeight = imageDownloadAlt.getBufferedImage().getHeight(); + correctWidthHeight(); + } + } + + public void correctWidthHeight(){ + totalWidth = Math.max(totalWidth, 1); + totalHeight = Math.max(totalHeight, 1); + this.width = width < 0 ? totalWidth : width; + this.height = height < 0 ? totalHeight : height; + } +} diff --git a/src/main/java/noppes/npcs/constants/EnumGuiType.java b/src/main/java/noppes/npcs/constants/EnumGuiType.java index 14ebeb4a2..5d320c506 100644 --- a/src/main/java/noppes/npcs/constants/EnumGuiType.java +++ b/src/main/java/noppes/npcs/constants/EnumGuiType.java @@ -6,6 +6,7 @@ public enum EnumGuiType { MainMenuStats, ManageFactions, ManageTags, + ManageAnimations, MainMenuAdvanced, MainMenuGlobal, PlayerBankSmall, diff --git a/src/main/java/noppes/npcs/constants/EnumPacketServer.java b/src/main/java/noppes/npcs/constants/EnumPacketServer.java index 773e0b4f9..0cd8bea01 100644 --- a/src/main/java/noppes/npcs/constants/EnumPacketServer.java +++ b/src/main/java/noppes/npcs/constants/EnumPacketServer.java @@ -80,7 +80,9 @@ public enum EnumPacketServer { PlayerRider(CustomNpcsPermissions.TOOL_MOUNTER), SpawnRider(CustomNpcsPermissions.TOOL_MOUNTER), MovingPathSave(CustomNpcsPermissions.TOOL_PATHER,true), MovingPathGet(true), - DialogNpcGet, + DialogNpcGet, + + AnimationListGet, AnimationGet, AnimationAdd, AnimationDelete, AnimationSave, RecipesGet, RecipeGet, QuestOpenGui, PlayerDataGet, UpdateTrackedQuest, diff --git a/src/main/java/noppes/npcs/controllers/data/Animation.java b/src/main/java/noppes/npcs/controllers/data/Animation.java index 71e29216a..3d40fa60d 100644 --- a/src/main/java/noppes/npcs/controllers/data/Animation.java +++ b/src/main/java/noppes/npcs/controllers/data/Animation.java @@ -1,5 +1,7 @@ package noppes.npcs.controllers.data; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import noppes.npcs.api.handler.data.IAnimation; @@ -12,7 +14,7 @@ import java.util.ArrayList; public class Animation implements IAnimation { - public ArrayList frames = new ArrayList(); + public ArrayList frames = new ArrayList<>(); public int currentFrame = 0; public int currentFrameTime = 0; @@ -26,6 +28,9 @@ public class Animation implements IAnimation { public boolean whileAttacking = true; public boolean whileMoving = true; + //Client-sided + public boolean paused; + public Animation(){} public Animation(String name){ @@ -196,7 +201,11 @@ public class Animation implements IAnimation { return compound; } + @SideOnly(Side.CLIENT) public void increaseTime() { + if (paused) + return; + this.currentFrameTime++; if (this.currentFrameTime == this.currentFrame().getDuration()) { Frame prevFrame = (Frame) this.currentFrame(); diff --git a/src/main/java/noppes/npcs/controllers/data/FramePart.java b/src/main/java/noppes/npcs/controllers/data/FramePart.java index 927ff008c..7426899a0 100644 --- a/src/main/java/noppes/npcs/controllers/data/FramePart.java +++ b/src/main/java/noppes/npcs/controllers/data/FramePart.java @@ -8,7 +8,7 @@ import noppes.npcs.client.ClientEventHandler; import noppes.npcs.constants.EnumAnimationPart; public class FramePart implements IFramePart { - + public Animation parent; public EnumAnimationPart part; public float[] rotation = {0, 0, 0}; public float[] pivot = {0, 0, 0}; @@ -149,6 +149,9 @@ public class FramePart implements IFramePart { @SideOnly(Side.CLIENT) public void interpolateAngles() { + if (parent != null && parent.paused) + return; + float pi = (float) Math.PI / 180; if (this.smooth == 2) { this.prevRotations[0] = this.rotation[0] * pi; @@ -179,6 +182,9 @@ public class FramePart implements IFramePart { @SideOnly(Side.CLIENT) public void interpolateOffset() { + if (parent != null && parent.paused) + return; + if (this.smooth == 2) { this.prevPivots[0] = this.pivot[0]; this.prevPivots[1] = this.pivot[1]; diff --git a/src/main/resources/assets/customnpcs/lang/en_US.lang b/src/main/resources/assets/customnpcs/lang/en_US.lang index 4a0265d84..a79028259 100644 --- a/src/main/resources/assets/customnpcs/lang/en_US.lang +++ b/src/main/resources/assets/customnpcs/lang/en_US.lang @@ -389,6 +389,8 @@ menu.ai=AI menu.advanced=Advanced menu.global=Global menu.role=Role +menu.animations=Animations +menu.tags=Tags global.banks=Banks global.transport=Transport @@ -1020,6 +1022,29 @@ puppet.pivotY=Pivot Y puppet.pivotZ=Pivot Z puppet.fullAngles=Full Angles +animation.animation=Animation +animation.frame=Frame +animation.frames=Frames +animation.framePart=Frame Part +animation.smoothing=Smoothing +animation.linear=Linear +animation.smooth=Smooth +animation.loopStart=Loop Start +animation.tickType=Tick Type +animation.mcTicks=MC Ticks +animation.renderTicks=Render Ticks +animation.whileStanding=While Standing +animation.whileAttacking=While Attacking +animation.whileMoving=While Moving +animation.duration=Duration +animation.customized=Customized +animation.rotations=Rotations +animation.pivots=Pivots +animation.addFrame=Add a frame to continue! +animation.playing=Playing +animation.paused=Paused +animation.stopped=Stopped + guard.creepers=Attack Creepers guard.animals=Attack Animals guard.mobs=Attack Monsters diff --git a/src/main/resources/assets/customnpcs/textures/entity/humanmale/AnimationBody.png b/src/main/resources/assets/customnpcs/textures/entity/humanmale/AnimationBody.png new file mode 100644 index 000000000..61aa288d8 Binary files /dev/null and b/src/main/resources/assets/customnpcs/textures/entity/humanmale/AnimationBody.png differ diff --git a/src/main/resources/assets/customnpcs/textures/gui/animation.png b/src/main/resources/assets/customnpcs/textures/gui/animation.png new file mode 100644 index 000000000..2fe01853a Binary files /dev/null and b/src/main/resources/assets/customnpcs/textures/gui/animation.png differ