Jump to content

Recommended Posts

Posted

Hi, I've created a capability that gives the player up to 6 slots of "attack styles", with the first 3 given values by default, and the others empty/null by default. I have an enum which contains different attack styles, and different values for each one. Depending on what Tiered item you wield, each slot can be changed to a different attack style.

This is the event handler that runs a LivingEquipmentChangeEvent everytime you change whats in the player's mainhand:

package lk1905.gielinorcraft.events;

import lk1905.gielinorcraft.Gielinorcraft;
import lk1905.gielinorcraft.api.combat.AttackStyles;
import lk1905.gielinorcraft.capability.attackstyle.AttackStyleCapability;
import lk1905.gielinorcraft.capability.attackstyle.IAttackStyle;
import lk1905.gielinorcraft.network.PacketHandler;
import lk1905.gielinorcraft.network.StringPacket;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.inventory.EquipmentSlotType;
import net.minecraft.item.AxeItem;
import net.minecraft.item.BowItem;
import net.minecraft.item.CrossbowItem;
import net.minecraft.item.HoeItem;
import net.minecraft.item.Item;
import net.minecraft.item.PickaxeItem;
import net.minecraft.item.ShovelItem;
import net.minecraft.item.SwordItem;
import net.minecraft.item.TieredItem;
import net.minecraftforge.event.entity.living.LivingEquipmentChangeEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;

@Mod.EventBusSubscriber(modid = Gielinorcraft.MODID, bus = Mod.EventBusSubscriber.Bus.FORGE)
public class EquipmentEventHandler {

	@SubscribeEvent
	public static void onWield(LivingEquipmentChangeEvent event) {
		LivingEntity entity = event.getEntityLiving();
		IAttackStyle style = entity.getCapability(AttackStyleCapability.STYLE_CAP).orElse(null);
		
		Item to = event.getTo().getItem();
		Item from = event.getFrom().getItem();
		
		if(to instanceof TieredItem) {
			if(event.getSlot() == EquipmentSlotType.OFFHAND && entity instanceof PlayerEntity) {
				if(entity instanceof ServerPlayerEntity && !(entity.world.isRemote)) {
					PacketHandler.sendTo(new StringPacket("You cannot wield this item in your offhand."), (ServerPlayerEntity) entity);
				}
			}
		}
		
		if(event.getSlot() == EquipmentSlotType.MAINHAND && entity.getHeldItemMainhand().getItem() == to) {
			if(entity instanceof ServerPlayerEntity && !(entity.world.isRemote)) {
				for(int i = 0; i < 6; i++) {
					PacketHandler.sendTo(new StringPacket("Attack Style: "
							+ style.getStyleName(i) + ", " + style.getStyleDescription(i)), (ServerPlayerEntity) entity);
				}
				PacketHandler.sendTo(new StringPacket("Active Style: " + style.getActiveStyle().getName()
						+ ", " + style.getActiveStyle().getDescription()), (ServerPlayerEntity) entity);
				style.sync((ServerPlayerEntity) entity);
			}
			if(entity.getHeldItemMainhand().getItem() instanceof SwordItem) {
				style.setAttackStyle(0, AttackStyles.ACCURATE_STAB);
				style.setAttackStyle(1, AttackStyles.AGGRESSIVE_STAB);
				style.setAttackStyle(2, AttackStyles.AGGRESSIVE_SLASH);
				style.setAttackStyle(3, AttackStyles.DEFENSIVE_STAB);
				style.setAttackStyle(4, AttackStyles.EMPTY);
				style.setAttackStyle(5, AttackStyles.EMPTY);							
			}else if(entity.getHeldItemMainhand().getItem() instanceof AxeItem) {
				style.setAttackStyle(0, AttackStyles.ACCURATE_SLASH);
				style.setAttackStyle(1, AttackStyles.AGGRESSIVE_SLASH);
				style.setAttackStyle(2, AttackStyles.AGGRESSIVE_CRUSH);
				style.setAttackStyle(3, AttackStyles.DEFENSIVE_SLASH);
				style.setAttackStyle(4, AttackStyles.EMPTY);
				style.setAttackStyle(5, AttackStyles.EMPTY);
			}else if(entity.getHeldItemMainhand().getItem() instanceof PickaxeItem) {
				style.setAttackStyle(0, AttackStyles.ACCURATE_STAB);
				style.setAttackStyle(1, AttackStyles.AGGRESSIVE_STAB);
				style.setAttackStyle(2, AttackStyles.AGGRESSIVE_CRUSH);
				style.setAttackStyle(3, AttackStyles.DEFENSIVE_STAB);
				style.setAttackStyle(4, AttackStyles.EMPTY);
				style.setAttackStyle(5, AttackStyles.EMPTY);
			}else if(entity.getHeldItemMainhand().getItem() instanceof ShovelItem) {
				style.setAttackStyle(0, AttackStyles.ACCURATE_CRUSH);
				style.setAttackStyle(1, AttackStyles.AGGRESSIVE_CRUSH);
				style.setAttackStyle(2, AttackStyles.AGGRESSIVE_SLASH);
				style.setAttackStyle(3, AttackStyles.DEFENSIVE_CRUSH);
				style.setAttackStyle(4, AttackStyles.EMPTY);
				style.setAttackStyle(5, AttackStyles.EMPTY);
			}else if(entity.getHeldItemMainhand().getItem() instanceof HoeItem) {
				style.setAttackStyle(0, AttackStyles.ACCURATE_SLASH);
				style.setAttackStyle(1, AttackStyles.AGGRESSIVE_SLASH);
				style.setAttackStyle(2, AttackStyles.AGGRESSIVE_STAB);
				style.setAttackStyle(3, AttackStyles.DEFENSIVE_SLASH);
				style.setAttackStyle(4, AttackStyles.EMPTY);
				style.setAttackStyle(5, AttackStyles.EMPTY);
			}else if(entity.getHeldItemMainhand().getItem() instanceof BowItem || entity.getHeldItemMainhand().getItem() instanceof CrossbowItem) {
				style.setAttackStyle(0, AttackStyles.RANGED_ACCURATE);
				style.setAttackStyle(1, AttackStyles.RANGED_RAPID);
				style.setAttackStyle(2, AttackStyles.RANGED_LONG);
				style.setAttackStyle(3, AttackStyles.EMPTY);
				style.setAttackStyle(4, AttackStyles.EMPTY);
				style.setAttackStyle(5, AttackStyles.EMPTY);
			}else {
				style.setAttackStyle(0, AttackStyles.ACCURATE_CRUSH);
				style.setAttackStyle(1, AttackStyles.AGGRESSIVE_CRUSH);
				style.setAttackStyle(2, AttackStyles.DEFENSIVE_CRUSH);
				style.setAttackStyle(3, AttackStyles.EMPTY);
				style.setAttackStyle(4, AttackStyles.EMPTY);
				style.setAttackStyle(5, AttackStyles.EMPTY);
			}
		}
		
		if(from instanceof TieredItem && !(to instanceof TieredItem)) {
			style.setAttackStyle(0, AttackStyles.ACCURATE_CRUSH);
			style.setAttackStyle(1, AttackStyles.AGGRESSIVE_CRUSH);
			style.setAttackStyle(2, AttackStyles.DEFENSIVE_CRUSH);
			style.setAttackStyle(3, AttackStyles.EMPTY);
			style.setAttackStyle(4, AttackStyles.EMPTY);
			style.setAttackStyle(5, AttackStyles.EMPTY);		
			if(entity instanceof ServerPlayerEntity && !(entity.world.isRemote)) {
				style.sync((ServerPlayerEntity) entity);
				PacketHandler.sendTo(new StringPacket("Weapon is no longer being wielded."), (ServerPlayerEntity) entity);
			}
		}
	}
}

 

Which then sets the Attack style for each slot, done by this capability class:

package lk1905.gielinorcraft.capability.attackstyle;

import lk1905.gielinorcraft.api.combat.AttackStyles;
import lk1905.gielinorcraft.api.combat.IAttackStyles;
import lk1905.gielinorcraft.api.events.AttackStyleEvent;
import lk1905.gielinorcraft.network.PacketHandler;
import lk1905.gielinorcraft.network.attackstyle.AttackStyleCapPacket;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.nbt.CompoundNBT;
import net.minecraftforge.common.MinecraftForge;

public class AttackStyle implements IAttackStyle{

	private final IAttackStyles[] style;
	private IAttackStyles activeStyle;
	private final LivingEntity entity;
	private int activeId;
	
	public AttackStyle(LivingEntity entity) {
		style = new IAttackStyles[6];
		this.entity = entity;
		
		style[0] = AttackStyles.ACCURATE_CRUSH;
		style[1] = AttackStyles.AGGRESSIVE_CRUSH;
		style[2] = AttackStyles.DEFENSIVE_CRUSH;
		style[3] = AttackStyles.EMPTY;
		style[4] = AttackStyles.EMPTY;
		style[5] = AttackStyles.EMPTY;
		
		setActiveStyle(0);
			
		if(activeStyle == AttackStyles.EMPTY) {
			setActiveStyle(0);
		}
	}
	
	@Override
	public void setAttackStyle(int slot, IAttackStyles style) {
		if(this.style[slot] != style) {
			this.style[slot] = style;
			MinecraftForge.EVENT_BUS.post(new AttackStyleEvent(entity, slot, style));
		}
	}

	@Override
	public IAttackStyles getAttackStyle(int slot) {
		return style[slot];
	}

	@Override
	public void setActiveStyle(int slot) {
		activeStyle = style[slot];
		activeId = slot;	
	}

	@Override
	public IAttackStyles getActiveStyle() {
		return activeStyle;
	}
	
	@Override
	public void setStyleName(int slot, String name) {
		name = style[slot].getName();
	}
	
	@Override
	public String getStyleName(int slot) {
		return style[slot].getName();
	}
	
	@Override
	public void setStyleDescription(int slot, String description) {
		description = style[slot].getDescription();
	}
	
	@Override
	public String getStyleDescription(int slot) {
		return style[slot].getDescription();
	}
	
	@Override
	public void setStyleId(int slot, int id) {
		id = style[slot].getStyleId();
	}
	
	@Override
	public int getStyleId(int slot) {
		return style[slot].getStyleId();
	}
	
	@Override
	public int getActiveStyleId() {
		return activeId;
	}

	@Override
	public LivingEntity getEntity() {
		return entity;
	}

	@Override
	public CompoundNBT serializeNBT() {
		CompoundNBT data = new CompoundNBT();
		data.putInt("active_style", activeId);
		return data;
	}

	@Override
	public void deserializeNBT(CompoundNBT data) {
		setActiveStyle(data.getInt("active_style"));
	}

	@Override
	public void sync(ServerPlayerEntity player) {
		if(entity instanceof ServerPlayerEntity) {
			PacketHandler.sendTo(new AttackStyleCapPacket(serializeNBT()), player);
		}
	}
}

 

Which then runs an AttackStyleEvent (custom event) for each slot:

package lk1905.gielinorcraft.api.events;

import javax.annotation.Nonnull;

import lk1905.gielinorcraft.api.combat.IAttackStyles;
import net.minecraft.entity.LivingEntity;
import net.minecraftforge.eventbus.api.Event;

public class AttackStyleEvent extends Event{

	private final LivingEntity entity;
	private final int slot;
	private final IAttackStyles style;
	
	public AttackStyleEvent(LivingEntity entity, int slot, IAttackStyles style) {
		this.entity = entity;
		this.slot = slot;
		this.style = style;
	}
	
	@Nonnull
	public LivingEntity getEntity() {
		return entity;
	}
	
	@Nonnull
	public int getSlot() {
		return slot;
	}
	
	public IAttackStyles getStyle() {
		return style;
	}
}

 

I have an event handler for this event:

	@SubscribeEvent
	public static void onAttackStyleChange(AttackStyleEvent event) {
		if(!event.getEntity().world.isRemote) {
			PacketHandler.sendTo(new ChangeStylePacket(event.getSlot(), event.getStyle().getStyleId(),
					event.getStyle().getName(), event.getStyle().getDescription()), (ServerPlayerEntity) event.getEntity());
		}
	}

 

Which runs this packet, which is supposed to sync to the client:

package lk1905.gielinorcraft.network.attackstyle;

import java.util.function.Supplier;

import lk1905.gielinorcraft.capability.attackstyle.AttackStyleCapability;
import net.minecraft.client.Minecraft;
import net.minecraft.network.PacketBuffer;
import net.minecraftforge.fml.network.NetworkEvent;

public class ChangeStylePacket {

	private final int slot;
	private final int id;
	private final String name;
	private final String descript;
	
	public ChangeStylePacket(int slot, int id, String name, String descript) {
		this.slot = slot;
		this.id = id;
		this.name = name;
		this.descript = descript;
	}
	
	public static void encode(ChangeStylePacket msg, PacketBuffer buf) {
		buf.writeInt(msg.slot);
		buf.writeInt(msg.id);
		buf.writeString(msg.name);
		buf.writeString(msg.descript);
	}
	
	public static ChangeStylePacket decode(PacketBuffer buf) {
		return new ChangeStylePacket(buf.readInt(), buf.readInt(), buf.readString(), buf.readString());
	}
	
	public static class Handler{
		public static void handle(final ChangeStylePacket msg, Supplier<NetworkEvent.Context> ctx) {
			ctx.get().enqueueWork(() -> {
				
				Minecraft mc = Minecraft.getInstance();
				
				mc.player.getCapability(AttackStyleCapability.STYLE_CAP).ifPresent(cap -> {
					cap.setStyleId(msg.slot, msg.id);
					cap.setStyleName(msg.slot, msg.name);
					cap.setStyleDescription(msg.slot, msg.descript);
				});
			});
			ctx.get().setPacketHandled(true);
		}
	}
}

 

On the client end, I have a gui/screen, that contains buttons for each non-empty slot, which you click to set that slot as "active":

package lk1905.gielinorcraft.client.gui.screen;

import com.mojang.blaze3d.matrix.MatrixStack;

import lk1905.gielinorcraft.Gielinorcraft;
import lk1905.gielinorcraft.api.combat.AttackStyles;
import lk1905.gielinorcraft.api.skill.ISkills;
import lk1905.gielinorcraft.capability.attackstyle.AttackStyleCapability;
import lk1905.gielinorcraft.capability.attackstyle.IAttackStyle;
import lk1905.gielinorcraft.capability.skill.SkillCapability;
import lk1905.gielinorcraft.client.gui.widget.AttackStyleButton;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.text.StringTextComponent;

public class AttackStyleScreen extends Screen{

	private Minecraft mc = Minecraft.getInstance();
	private final ResourceLocation TEXTURE = new ResourceLocation(Gielinorcraft.MODID, "textures/gui/combat.png");
	private AttackStyleButton[] styleButton;
	private String[] styleName;
	
	private PlayerEntity player = mc.player;
	private ISkills skillCap = player.getCapability(SkillCapability.SKILL_CAP).orElse(null);
	private IAttackStyle styleCap = player.getCapability(AttackStyleCapability.STYLE_CAP).orElse(null);
	
	private final int xSize = 134;
	private final int ySize = 163;
	
	private int guiLeft;
	private int guiTop;
	
	public AttackStyleScreen() {
		super(new StringTextComponent("Combat styles"));
		styleButton = new AttackStyleButton[6];
		styleName = new String[6];
	}

	@Override
	public boolean isPauseScreen() {
		return false;
	}
	
	@Override
	public void init() {
		guiLeft = (width - xSize) / 2;
		guiTop = (height - ySize) / 2;
		
		for(int i = 0; i < 6; i++) {
			if(styleCap.getAttackStyle(i) == AttackStyles.EMPTY) {
				styleButton[i] = null;
				styleName[i] = null;
			}else {
				styleButton[0] = new AttackStyleButton((width / 2) - 57, height / 2 - 45, 0);
				styleButton[1] = new AttackStyleButton((width / 2) + 1, height / 2 - 45, 1);
				styleButton[2] = new AttackStyleButton((width / 2) - 57, height / 2 - 18, 2);
				styleButton[3] = new AttackStyleButton((width / 2) + 1, height / 2 - 18, 3);
				styleButton[4] = new AttackStyleButton((width / 2) - 57, height / 2 + 9, 4);
				styleButton[5] = new AttackStyleButton((width / 2) + 1, height / 2 + 9, 5);
				
				styleName[i] = styleCap.getStyleName(i);
			}
			if(styleButton[i] != null) {
				this.addButton(styleButton[i]);
			}
		}
	}
	
	@Override
	public void render(final MatrixStack stack, final int mouseX, final int mouseY, final float partialTicks) {
		renderBackground(stack);
		super.render(stack, mouseX, mouseY, partialTicks);
		stack.push();
		stack.scale(1F, 1F, 1F);
		mc.getTextureManager().bindTexture(TEXTURE);
		this.blit(stack, guiLeft, guiTop, 0, 0, xSize, ySize);
		drawCenteredString(stack, font, "Combat level: " + skillCap.getCombatLevel(), width / 2, (height / 2) - 70, 111111);

		for(int i = 0; i < 6; i++) {
			if(styleButton[i] != null) {
				styleButton[i].renderButton(stack, mouseX, mouseY, partialTicks);
				
				if(styleButton[i].isHovered()) {
					this.renderTooltip(stack, new StringTextComponent(styleCap.getStyleDescription(i)), mouseX, mouseY);
					buttons.clear();
					this.init();
				}
			}
			if(styleName[i] != null) {
				drawCenteredString(stack, font, styleName[0], width / 2 - 30, height / 2 - 40, 0xFFFFFF);
				drawCenteredString(stack, font, styleName[1], width / 2 + 29, height / 2 - 40, 0xFFFFFF);
				drawCenteredString(stack, font, styleName[2], width / 2 - 30, height / 2 - 13, 0xFFFFFF);
				drawCenteredString(stack, font, styleName[3], width / 2 + 29, height / 2 - 13, 0xFFFFFF);
				drawCenteredString(stack, font, styleName[4], width / 2 - 30, height / 2 + 14, 0xFFFFFF);
				drawCenteredString(stack, font, styleName[5], width / 2 + 29, height / 2 + 14, 0xFFFFFF);
			}
		}
		stack.pop();
	}
}

 

If you need to look at any more classes, my github is here.

I know for certain that every thing works server-side, and I know the active slot syncs, as it isn't affected by which style exists in that slot (unless the slot is empty/null, in which it then sets slot 0 as the active slot), but the client-side does not change, the screen's buttons do not update to the new style, it only ever has the default styles set.

Is anyone able to see what I'm missing or doing wrong? thanks.

Posted

Wouldn't that mean that the names/buttons aren't being grabbed once, but every single time I open the screen, which means it should open with the new buttons/names the next time I open it?

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.