diff --git a/core/pom.xml b/core/pom.xml
index 5c1bdbd..b2d281c 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -41,6 +41,12 @@
1.21.1-R0.1-SNAPSHOT
compile
+
+ io.papermc.paper
+ paper-api
+ 1.21.1-R0.1-SNAPSHOT
+ provided
+
com.comphenix.protocol
ProtocolLib
@@ -66,6 +72,11 @@
fastboard
2.1.3
+
+ net.kyori
+ adventure-api
+ 4.17.0
+
com.google.guava
guava
diff --git a/core/src/main/java/org/ef3d0c3e/sheepwars/events/TeamChangeEvent.java b/core/src/main/java/org/ef3d0c3e/sheepwars/events/TeamChangeEvent.java
new file mode 100644
index 0000000..fd61027
--- /dev/null
+++ b/core/src/main/java/org/ef3d0c3e/sheepwars/events/TeamChangeEvent.java
@@ -0,0 +1,35 @@
+package org.ef3d0c3e.sheepwars.events;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import org.bukkit.event.Event;
+import org.bukkit.event.HandlerList;
+import org.ef3d0c3e.sheepwars.player.CPlayer;
+import org.ef3d0c3e.sheepwars.teams.Team;
+
+import javax.annotation.Nullable;
+
+
+@AllArgsConstructor
+public class TeamChangeEvent extends Event
+{
+ private static final HandlerList HANDLERS_LIST = new HandlerList();
+
+ public static HandlerList getHandlerList()
+ {
+ return HANDLERS_LIST;
+ }
+ @Override
+ public HandlerList getHandlers()
+ {
+ return HANDLERS_LIST;
+ }
+
+ @Getter
+ final private CPlayer player;
+ @Getter
+ final private @Nullable Team oldTeam;
+ @Getter
+ final private @Nullable Team newTeam;
+}
+
diff --git a/core/src/main/java/org/ef3d0c3e/sheepwars/game/Game.java b/core/src/main/java/org/ef3d0c3e/sheepwars/game/Game.java
index fdd1e68..ed8f322 100644
--- a/core/src/main/java/org/ef3d0c3e/sheepwars/game/Game.java
+++ b/core/src/main/java/org/ef3d0c3e/sheepwars/game/Game.java
@@ -9,6 +9,8 @@ import org.ef3d0c3e.sheepwars.level.LevelFactory;
import org.ef3d0c3e.sheepwars.level.lobby.LobbyLevel;
import org.ef3d0c3e.sheepwars.packets.PacketListenerFactory;
+import java.util.Random;
+
public class Game {
private static void changePhase(WantsListen.Target phase)
{
@@ -28,6 +30,12 @@ public class Game {
//@Getter
//private static GameLevel level;
+ private static final Random random = new Random();
+ public static int nextInt()
+ {
+ return random.nextInt();
+ }
+
/**
* Sets default phase to lobby
diff --git a/core/src/main/java/org/ef3d0c3e/sheepwars/hologram/HologramItemComponent.java b/core/src/main/java/org/ef3d0c3e/sheepwars/hologram/HologramItemComponent.java
new file mode 100644
index 0000000..7fd3641
--- /dev/null
+++ b/core/src/main/java/org/ef3d0c3e/sheepwars/hologram/HologramItemComponent.java
@@ -0,0 +1,61 @@
+package org.ef3d0c3e.sheepwars.hologram;
+
+import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
+import com.github.retrooper.packetevents.util.Vector3d;
+import com.github.retrooper.packetevents.wrapper.PacketWrapper;
+import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityMetadata;
+import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerSpawnEntity;
+import lombok.NonNull;
+import org.bukkit.Location;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.util.Vector;
+import org.ef3d0c3e.sheepwars.packets.EntityMetadata;
+import org.ef3d0c3e.sheepwars.packets.ItemProjectileMetadata;
+import org.ef3d0c3e.sheepwars.player.CPlayer;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
+import java.util.UUID;
+
+/**
+ * Represent a text component
+ */
+public abstract class HologramItemComponent extends HologramComponent
+{
+ protected HologramItemComponent(@NonNull Vector offset)
+ {
+ super(offset);
+ }
+
+ protected abstract @NonNull ItemStack getItem(final @NonNull CPlayer cp);
+
+ protected int getNetworkOffset() { return 1; }
+
+ protected @NonNull List> build(final @NonNull Location location, final int networkId, final @NonNull CPlayer cp)
+ {
+ // Spawn
+ final Location loc = location.clone().add(getOffset());
+ final WrapperPlayServerSpawnEntity spawn = new WrapperPlayServerSpawnEntity(
+ networkId, Optional.of(UUID.randomUUID()),
+ EntityTypes.ITEM,
+ new Vector3d(loc.getX(), loc.getY(), loc.getZ()),
+ loc.getYaw(), 0.f, loc.getPitch(),
+ 0,
+ Optional.empty()
+ );
+
+ // Metadata
+ final WrapperPlayServerEntityMetadata meta = new WrapperPlayServerEntityMetadata(
+ networkId,
+ Arrays.asList(
+ new EntityMetadata.NoGravity(true).into(),
+ new EntityMetadata.Silent(true).into(),
+ new ItemProjectileMetadata.Item(getItem(cp)).into()
+ )
+ );
+
+
+ return List.of(spawn, meta);
+ }
+}
diff --git a/core/src/main/java/org/ef3d0c3e/sheepwars/hologram/HologramTextComponent.java b/core/src/main/java/org/ef3d0c3e/sheepwars/hologram/HologramTextComponent.java
index a4ddfda..029b40d 100644
--- a/core/src/main/java/org/ef3d0c3e/sheepwars/hologram/HologramTextComponent.java
+++ b/core/src/main/java/org/ef3d0c3e/sheepwars/hologram/HologramTextComponent.java
@@ -14,6 +14,7 @@ import lombok.NonNull;
import net.kyori.adventure.text.Component;
import org.bukkit.Location;
import org.bukkit.util.Vector;
+import org.ef3d0c3e.sheepwars.packets.ArmorStandMetadata;
import org.ef3d0c3e.sheepwars.packets.EntityMetadata;
import org.ef3d0c3e.sheepwars.player.CPlayer;
@@ -54,7 +55,10 @@ public abstract class HologramTextComponent extends HologramComponent
.into(),
new EntityMetadata.NoGravity(true).into(),
new EntityMetadata.CustomNameVisible(true).into(),
- new EntityMetadata.CustomName(getText(cp)).into()
+ new EntityMetadata.CustomName(getText(cp)).into(),
+ new ArmorStandMetadata.Status()
+ .isMarker(true)
+ .into()
)
);
diff --git a/core/src/main/java/org/ef3d0c3e/sheepwars/level/lobby/LobbyEvents.java b/core/src/main/java/org/ef3d0c3e/sheepwars/level/lobby/LobbyEvents.java
index ca34cf2..f56f725 100644
--- a/core/src/main/java/org/ef3d0c3e/sheepwars/level/lobby/LobbyEvents.java
+++ b/core/src/main/java/org/ef3d0c3e/sheepwars/level/lobby/LobbyEvents.java
@@ -15,11 +15,18 @@ import org.bukkit.event.entity.*;
import org.bukkit.event.entity.EntityDismountEvent;
import org.bukkit.event.entity.EntityMountEvent;
import org.bukkit.event.inventory.CraftItemEvent;
+import org.bukkit.event.inventory.InventoryClickEvent;
+import org.bukkit.event.inventory.InventoryDragEvent;
+import org.bukkit.event.inventory.InventoryInteractEvent;
import org.bukkit.event.player.PlayerDropItemEvent;
+import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerMoveEvent;
+import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import org.ef3d0c3e.sheepwars.events.*;
import org.ef3d0c3e.sheepwars.game.Game;
+import org.ef3d0c3e.sheepwars.items.IItem;
+import org.ef3d0c3e.sheepwars.player.skin.SkinItem;
import java.util.UUID;
@@ -33,10 +40,11 @@ public class LobbyEvents implements Listener
ev.getPlayer().getHandle().teleport(Game.getLobby().getSpawn());
final PlayerInventory inv = ev.getPlayer().getHandle().getInventory();
+ inv.clear();
//inv.setItem(0, TeamItem.getItem(ev.getPlayer()));
//inv.setItem(1, KitItem.getItem(ev.getPlayer()));
- //inv.setItem(4, RocketItem.getItem(ev.getPlayer()));
- //inv.setItem(7, SkinItem.getItem(ev.getPlayer()));
+ inv.setItem(4, RocketItem.getItem(ev.getPlayer()));
+ inv.setItem(7, SkinItem.getItem(ev.getPlayer()));
}
/*
@@ -54,15 +62,15 @@ public class LobbyEvents implements Listener
final ItemStack replace = KitItem.getItem(ev.getPlayer());
if (!ItemBase.replace(ev.getPlayer().getHandle().getInventory(), KitItem.ITEM, replace))
ev.getPlayer().getHandle().getInventory().setItem(1, replace);
- }
+ }*/
@EventHandler
public void onSkinChange(final SkinChangeEvent ev)
{
final ItemStack replace = SkinItem.getItem(ev.getPlayer());
- if (!ItemBase.replace(ev.getPlayer().getHandle().getInventory(), SkinItem.ITEM, replace))
+ if (!IItem.replace(ev.getPlayer().getHandle().getInventory(), SkinItem.ITEM, replace))
ev.getPlayer().getHandle().getInventory().setItem(7, replace);
- }*/
+ }
// Cancel all unwanted events
@EventHandler
@@ -74,6 +82,20 @@ public class LobbyEvents implements Listener
ev.setCancelled(true);
}
+ @EventHandler
+ public void onInventoryDrag(final InventoryDragEvent ev)
+ {
+ if (ev.getInventory().equals(ev.getWhoClicked().getInventory()))
+ ev.setCancelled(true);
+ }
+
+ @EventHandler
+ public void onInventoryClick(final InventoryClickEvent ev)
+ {
+ if (ev.getInventory().equals(ev.getWhoClicked().getInventory()))
+ ev.setCancelled(true);
+ }
+
@EventHandler
public void onFoodLevelChange(final FoodLevelChangeEvent ev)
{
diff --git a/core/src/main/java/org/ef3d0c3e/sheepwars/level/lobby/LobbyHologram.java b/core/src/main/java/org/ef3d0c3e/sheepwars/level/lobby/LobbyHologram.java
new file mode 100644
index 0000000..dd8c420
--- /dev/null
+++ b/core/src/main/java/org/ef3d0c3e/sheepwars/level/lobby/LobbyHologram.java
@@ -0,0 +1,82 @@
+package org.ef3d0c3e.sheepwars.level.lobby;
+
+import lombok.NonNull;
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.TextComponent;
+import net.kyori.adventure.text.format.TextColor;
+import net.kyori.adventure.text.format.TextDecoration;
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.event.EventHandler;
+import org.bukkit.util.Vector;
+import org.bukkit.inventory.ItemStack;
+import org.ef3d0c3e.sheepwars.events.WantsListen;
+import org.ef3d0c3e.sheepwars.hologram.Hologram;
+import org.ef3d0c3e.sheepwars.hologram.HologramComponent;
+import org.ef3d0c3e.sheepwars.hologram.HologramItemComponent;
+import org.ef3d0c3e.sheepwars.hologram.HologramTextComponent;
+import org.ef3d0c3e.sheepwars.player.CPlayer;
+
+public class LobbyHologram extends Hologram {
+ private static final int NETWORK_ID = 0xFF877710;
+ private final Location location;
+
+ public LobbyHologram(final Location location)
+ {
+ super(NETWORK_ID);
+ this.location = location;
+
+ // Center item
+ addComponent(new HologramItemComponent(new Vector(0, 0, 0))
+ {
+ final ItemStack item = new ItemStack(Material.WHITE_WOOL);
+
+ @Override
+ protected @NonNull ItemStack getItem(@NonNull CPlayer cp)
+ {
+ return item;
+ }
+ });
+
+ // Left item
+ addComponent(new HologramItemComponent(new Vector(0.9, 0, 0))
+ {
+ final ItemStack item = new ItemStack(Material.IRON_SWORD);
+
+ @Override
+ protected @NonNull ItemStack getItem(@NonNull CPlayer cp)
+ {
+ return item;
+ }
+ });
+
+ // Right item
+ addComponent(new HologramItemComponent(new Vector(-0.9, 0, 0))
+ {
+ final ItemStack item = new ItemStack(Material.BOW);
+
+ @Override
+ protected @NonNull ItemStack getItem(@NonNull CPlayer cp)
+ {
+ return item;
+ }
+ });
+
+ // Title
+ addComponent(new HologramTextComponent(new Vector(0, 0.4, 0)) {
+ final static Component title = Component.text("SheepWars")
+ .color(TextColor.color(140, 187, 64))
+ .decorate(TextDecoration.BOLD);
+
+ @Override @NonNull
+ protected Component getText(@NonNull CPlayer cp) {
+ return title;
+ }
+ });
+ }
+
+ @Override
+ public @NonNull Location getLocation(@NonNull CPlayer cp) {
+ return location;
+ }
+}
diff --git a/core/src/main/java/org/ef3d0c3e/sheepwars/level/lobby/LobbyLevel.java b/core/src/main/java/org/ef3d0c3e/sheepwars/level/lobby/LobbyLevel.java
index a297ba6..609b0de 100644
--- a/core/src/main/java/org/ef3d0c3e/sheepwars/level/lobby/LobbyLevel.java
+++ b/core/src/main/java/org/ef3d0c3e/sheepwars/level/lobby/LobbyLevel.java
@@ -16,11 +16,13 @@ import lombok.Getter;
import lombok.NonNull;
import org.bukkit.*;
import org.ef3d0c3e.sheepwars.SheepWars;
+import org.ef3d0c3e.sheepwars.hologram.HologramFactory;
import org.ef3d0c3e.sheepwars.level.Level;
import org.ef3d0c3e.sheepwars.level.VoidBiomeProvider;
import org.ef3d0c3e.sheepwars.level.VoidChunkGenerator;
import org.ef3d0c3e.sheepwars.npc.NPCFactory;
import org.ef3d0c3e.sheepwars.player.skin.SkinNPC;
+import org.ef3d0c3e.sheepwars.teams.TeamNPC;
import java.io.*;
@@ -32,9 +34,9 @@ public class LobbyLevel extends Level
private Location spawn;
//@Getter
- //private LobbyHologram hologram;
+ private LobbyHologram hologram;
private SkinNPC skinNpc;
- //private TeamNPC teamNpc;
+ private TeamNPC teamNpc;
//private KitNPC kitNpc;
/**
@@ -51,18 +53,16 @@ public class LobbyLevel extends Level
{
spawn = config.SPAWN.getLocation(getHandle());
- /*
hologram = new LobbyHologram(config.INFO.getLocation(getHandle()));
HologramFactory.register(hologram);
- */
skinNpc = new SkinNPC(config.SKIN.getLocation(getHandle()));
NPCFactory.register(skinNpc);
- /*
teamNpc = new TeamNPC(config.TEAM.getLocation(getHandle()));
NPCFactory.register(teamNpc);
+ /*
kitNpc = new KitNPC(config.KIT.getLocation(getHandle()));
NPCFactory.register(kitNpc);
*/
diff --git a/core/src/main/java/org/ef3d0c3e/sheepwars/level/lobby/RocketItem.java b/core/src/main/java/org/ef3d0c3e/sheepwars/level/lobby/RocketItem.java
new file mode 100644
index 0000000..7aa241a
--- /dev/null
+++ b/core/src/main/java/org/ef3d0c3e/sheepwars/level/lobby/RocketItem.java
@@ -0,0 +1,59 @@
+package org.ef3d0c3e.sheepwars.level.lobby;
+
+import lombok.NonNull;
+import org.bukkit.Material;
+import org.bukkit.Sound;
+import org.bukkit.block.Block;
+import org.bukkit.block.BlockFace;
+import org.bukkit.entity.Player;
+import org.bukkit.event.block.Action;
+import org.bukkit.inventory.EquipmentSlot;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.meta.ItemMeta;
+import org.bukkit.util.Vector;
+import org.ef3d0c3e.sheepwars.items.IItem;
+import org.ef3d0c3e.sheepwars.items.ItemFactory;
+import org.ef3d0c3e.sheepwars.player.CPlayer;
+
+import java.text.MessageFormat;
+
+public class RocketItem extends IItem
+{
+ public RocketItem()
+ {
+ super();
+ }
+
+ @Override
+ protected boolean onInteract(final Player p, final ItemStack item, final Action action, final EquipmentSlot hand, final Block clicked, final BlockFace face)
+ {
+ if (p.getCooldown(item.getType()) != 0) return true;
+
+ p.getLocation().getWorld().playSound(p.getLocation(), Sound.ENTITY_FIREWORK_ROCKET_LAUNCH, 12.f, 1.f);
+ p.setVelocity(p.getVelocity()
+ .clone().add(new Vector(0.0, 0.8, 0.0)));
+
+ p.setCooldown(item.getType(), 30);
+ return true;
+ }
+
+ @Override
+ protected boolean onDrop(final Player p, final ItemStack item) { return true; }
+
+ static final public RocketItem ITEM = new RocketItem();
+ /**
+ * Gets item for player
+ * @param cp Player to get item for
+ * @return Item
+ */
+ public static @NonNull ItemStack getItem(final CPlayer cp)
+ {
+ final ItemStack item = new ItemStack(Material.FIREWORK_ROCKET);
+ final ItemMeta meta = item.getItemMeta();
+ meta.setDisplayName(MessageFormat.format("§a{0} §7{1}", cp.getLocale().ITEMS_ROCKET, cp.getLocale().ITEMS_RIGHTCLICK));
+ item.setItemMeta(meta);
+
+ ItemFactory.registerItem(ITEM);
+ return ITEM.apply(item);
+ }
+}
diff --git a/core/src/main/java/org/ef3d0c3e/sheepwars/locale/Locale.java b/core/src/main/java/org/ef3d0c3e/sheepwars/locale/Locale.java
index fbb7523..0d29f48 100644
--- a/core/src/main/java/org/ef3d0c3e/sheepwars/locale/Locale.java
+++ b/core/src/main/java/org/ef3d0c3e/sheepwars/locale/Locale.java
@@ -69,6 +69,8 @@ public class Locale
public String TEAM_PICKER;
public String TEAM_NPCNAME;
public String TEAM_NPCCURRENT;
+ public String TEAM_RED;
+ public String TEAM_BLUE;
// Kits
public String KIT_PICKER;
diff --git a/core/src/main/java/org/ef3d0c3e/sheepwars/npc/PlayerNPC.java b/core/src/main/java/org/ef3d0c3e/sheepwars/npc/PlayerNPC.java
index 7095bbe..f178206 100644
--- a/core/src/main/java/org/ef3d0c3e/sheepwars/npc/PlayerNPC.java
+++ b/core/src/main/java/org/ef3d0c3e/sheepwars/npc/PlayerNPC.java
@@ -4,7 +4,6 @@ import com.comphenix.protocol.wrappers.EnumWrappers;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.protocol.entity.data.EntityData;
import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
-import com.github.retrooper.packetevents.protocol.npc.NPC;
import com.github.retrooper.packetevents.protocol.player.GameMode;
import com.github.retrooper.packetevents.protocol.player.TextureProperty;
import com.github.retrooper.packetevents.protocol.player.UserProfile;
@@ -15,8 +14,8 @@ import lombok.Getter;
import lombok.NonNull;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
-import org.bukkit.Bukkit;
import org.bukkit.Location;
+import org.ef3d0c3e.sheepwars.packets.ArmorStandMetadata;
import org.ef3d0c3e.sheepwars.packets.EntityMetadata;
import org.ef3d0c3e.sheepwars.packets.PlayerMetadata;
import org.ef3d0c3e.sheepwars.player.CPlayer;
@@ -139,7 +138,7 @@ public abstract class PlayerNPC
final WrapperPlayServerSpawnEntity spawn = new WrapperPlayServerSpawnEntity(
networkId+i+1, Optional.of(UUID.randomUUID()),
EntityTypes.ARMOR_STAND,
- new Vector3d(loc.getX(), loc.getY()+(tags.size()-i-1)*0.3, loc.getZ()),
+ new Vector3d(loc.getX(), loc.getY()+(tags.size()-i-1)*0.3+1.80, loc.getZ()),
0.f, 0.f, 0.f,
0,
Optional.empty()
@@ -153,7 +152,10 @@ public abstract class PlayerNPC
.into(),
new EntityMetadata.NoGravity(true).into(),
new EntityMetadata.CustomNameVisible(true).into(),
- new EntityMetadata.CustomName(tag).into()
+ new EntityMetadata.CustomName(tag).into(),
+ new ArmorStandMetadata.Status()
+ .isMarker(true)
+ .into()
)
);
diff --git a/core/src/main/java/org/ef3d0c3e/sheepwars/packets/ArmorStandMetadata.java b/core/src/main/java/org/ef3d0c3e/sheepwars/packets/ArmorStandMetadata.java
index a7dc408..c98815f 100644
--- a/core/src/main/java/org/ef3d0c3e/sheepwars/packets/ArmorStandMetadata.java
+++ b/core/src/main/java/org/ef3d0c3e/sheepwars/packets/ArmorStandMetadata.java
@@ -28,18 +28,18 @@ public class ArmorStandMetadata {
}
public Status hasArms(boolean v) {
- value = (byte)(value | (v ? 0b10 : 0b0));
- return this;
- }
-
- public Status hasBasePlate(boolean v) {
value = (byte)(value | (v ? 0b100 : 0b0));
return this;
}
- public Status isMarker(boolean v) {
+ public Status hasBasePlate(boolean v) {
value = (byte)(value | (v ? 0b1000 : 0b0));
return this;
}
+
+ public Status isMarker(boolean v) {
+ value = (byte)(value | (v ? 0b10000 : 0b0));
+ return this;
+ }
}
}
diff --git a/core/src/main/java/org/ef3d0c3e/sheepwars/packets/ItemProjectileMetadata.java b/core/src/main/java/org/ef3d0c3e/sheepwars/packets/ItemProjectileMetadata.java
new file mode 100644
index 0000000..4de1f19
--- /dev/null
+++ b/core/src/main/java/org/ef3d0c3e/sheepwars/packets/ItemProjectileMetadata.java
@@ -0,0 +1,25 @@
+package org.ef3d0c3e.sheepwars.packets;
+
+import com.github.retrooper.packetevents.protocol.entity.data.EntityData;
+import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
+import io.github.retrooper.packetevents.util.SpigotConversionUtil;
+import org.bukkit.inventory.ItemStack;
+
+public class ItemProjectileMetadata {
+ public static class Item implements IntoEntityData {
+ @Override
+ public EntityData into() {
+ return new EntityData(
+ 8,
+ EntityDataTypes.ITEMSTACK,
+ SpigotConversionUtil.fromBukkitItemStack(value)
+ );
+ }
+
+ ItemStack value;
+
+ public Item(final ItemStack value) {
+ this.value = value;
+ }
+ }
+}
diff --git a/core/src/main/java/org/ef3d0c3e/sheepwars/player/CPlayer.java b/core/src/main/java/org/ef3d0c3e/sheepwars/player/CPlayer.java
index 98a62f9..5a2410a 100644
--- a/core/src/main/java/org/ef3d0c3e/sheepwars/player/CPlayer.java
+++ b/core/src/main/java/org/ef3d0c3e/sheepwars/player/CPlayer.java
@@ -13,6 +13,7 @@ import org.ef3d0c3e.sheepwars.events.CPlayerJoinEvent;
import org.ef3d0c3e.sheepwars.events.CPlayerQuitEvent;
import org.ef3d0c3e.sheepwars.events.WantsListen;
import org.ef3d0c3e.sheepwars.locale.Locale;
+import org.ef3d0c3e.sheepwars.teams.Team;
import javax.annotation.Nullable;
import java.text.MessageFormat;
@@ -95,17 +96,6 @@ public class CPlayer {
if (cp.isOnline()) f.operation(cp);
}
- /**
- * The player handle
- */
- @Getter
- private Player handle;
- /**
- * The OfflinePlayer handle
- */
- @Getter
- private OfflinePlayer offlinePlayer;
-
/**
* The locale configured for the player
*/
@@ -117,6 +107,17 @@ public class CPlayer {
@Getter
private CosmeticManager cosmetics = new CosmeticManager(this);
+ /**
+ * The player handle
+ */
+ @Getter
+ private Player handle;
+ /**
+ * The OfflinePlayer handle
+ */
+ @Getter
+ private OfflinePlayer offlinePlayer;
+
/**
* Updates the player handle
* @param handle New handle
@@ -143,6 +144,21 @@ public class CPlayer {
return offlinePlayer.isOnline();
}
+ /**
+ * The player's team
+ * May not be null in lobby phase, null in game phase means spectator i.e. joined after the game started
+ */
+ @Getter
+ private Team team = null;
+
+ /**
+ * @note Don't call! Use {@link Team.setPlayerTeam(cp, team)}
+ * @param team New team
+ */
+ public void setTeam(Team team) {
+ this.team = team;
+ }
+
/**
* Events for the player wrapper
* When a player joins or quits
diff --git a/core/src/main/java/org/ef3d0c3e/sheepwars/player/CosmeticManager.java b/core/src/main/java/org/ef3d0c3e/sheepwars/player/CosmeticManager.java
index f1d9a4b..0c42f73 100644
--- a/core/src/main/java/org/ef3d0c3e/sheepwars/player/CosmeticManager.java
+++ b/core/src/main/java/org/ef3d0c3e/sheepwars/player/CosmeticManager.java
@@ -3,6 +3,7 @@ package org.ef3d0c3e.sheepwars.player;
import lombok.Getter;
import lombok.NonNull;
import lombok.Setter;
+import net.kyori.adventure.text.Component;
import org.bukkit.Bukkit;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
@@ -61,10 +62,11 @@ public class CosmeticManager {
final CPlayer cp = CPlayer.get(ev.getPlayer());
String message;
- //if (cp.getTeam() == null)
+ if (cp.getTeam() == null)
message = MessageFormat.format("§f{0}§8:§7 {1}", cp.getHandle().getName(), ev.getMessage());
- //else
- //message = MessageFormat.format("{0} | {1}§8:§7 {2}", cp.getTeam().getColoredName(), cp.getHandle().getName(), ev.getMessage());
+ else {
+ message = MessageFormat.format("{0} | {1}§8:§7 {2}", cp.getTeam().getName(cp), cp.getHandle().getName(), ev.getMessage());
+ }
Bukkit.broadcastMessage(message);
}
diff --git a/core/src/main/java/org/ef3d0c3e/sheepwars/player/skin/SkinItem.java b/core/src/main/java/org/ef3d0c3e/sheepwars/player/skin/SkinItem.java
new file mode 100644
index 0000000..fe694b3
--- /dev/null
+++ b/core/src/main/java/org/ef3d0c3e/sheepwars/player/skin/SkinItem.java
@@ -0,0 +1,58 @@
+package org.ef3d0c3e.sheepwars.player.skin;
+
+import lombok.NonNull;
+import org.bukkit.block.Block;
+import org.bukkit.block.BlockFace;
+import org.bukkit.entity.Player;
+import org.bukkit.event.block.Action;
+import org.bukkit.inventory.EquipmentSlot;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.meta.ItemMeta;
+import org.ef3d0c3e.sheepwars.Util;
+import org.ef3d0c3e.sheepwars.items.IItem;
+import org.ef3d0c3e.sheepwars.items.ItemFactory;
+import org.ef3d0c3e.sheepwars.player.CPlayer;
+
+import java.text.MessageFormat;
+
+public class SkinItem extends IItem
+{
+ public SkinItem()
+ {
+ super();
+ }
+
+ @Override
+ protected boolean onInteract(final Player p, final ItemStack item, final Action action, final EquipmentSlot hand, final Block clicked, final BlockFace face)
+ {
+ p.openInventory(new SkinMenu(CPlayer.get(p)).getInventory());
+ return true;
+ }
+
+ @Override
+ protected boolean onDrop(final Player p, final ItemStack item) { return true; }
+
+ static final public SkinItem ITEM = new SkinItem();
+ /**
+ * Gets item for player
+ * @param cp Player to get item for
+ * @return Item
+ */
+ public static @NonNull ItemStack getItem(final CPlayer cp)
+ {
+ final ItemStack item = (cp.getCosmetics().getCurrentSkin() == null)
+ ? cp.getCosmetics().getOriginalSkin().getDisplayItem()
+ : cp.getCosmetics().getCurrentSkin().getDisplayItem();
+ final ItemMeta meta = item.getItemMeta();
+ if (cp.getCosmetics().getCurrentSkin() == null)
+ meta.setDisplayName(MessageFormat.format("§a{0} §7{1}", cp.getLocale().ITEMS_SKIN, cp.getLocale().ITEMS_RIGHTCLICK));
+ else
+ meta.setDisplayName(MessageFormat.format("§a{0} §8: §6{1} §7{2}", cp.getLocale().ITEMS_SKIN, cp.getCosmetics().getCurrentSkin().getName(), cp.getLocale().ITEMS_RIGHTCLICK));
+ meta.setLore(Util.coloredLore("§7", cp.getLocale().ITEMS_SKINLORE));
+ item.setItemMeta(meta);
+
+ ItemFactory.registerItem(ITEM);
+ return ITEM.apply(item);
+ }
+}
+
diff --git a/core/src/main/java/org/ef3d0c3e/sheepwars/teams/Team.java b/core/src/main/java/org/ef3d0c3e/sheepwars/teams/Team.java
new file mode 100644
index 0000000..249ecd0
--- /dev/null
+++ b/core/src/main/java/org/ef3d0c3e/sheepwars/teams/Team.java
@@ -0,0 +1,120 @@
+package org.ef3d0c3e.sheepwars.teams;
+
+import com.comphenix.protocol.wrappers.WrappedChatComponent;
+import io.github.retrooper.packetevents.util.SpigotConversionUtil;
+import jline.internal.Nullable;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NonNull;
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.format.TextColor;
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.ef3d0c3e.sheepwars.events.CPlayerJoinEvent;
+import org.ef3d0c3e.sheepwars.events.TeamChangeEvent;
+import org.ef3d0c3e.sheepwars.events.WantsListen;
+import org.ef3d0c3e.sheepwars.player.CPlayer;
+import org.ef3d0c3e.sheepwars.game.Game;
+
+import java.util.HashSet;
+
+@AllArgsConstructor
+public abstract class Team {
+ @Getter
+ private final ChatColor chatColor;
+ @Getter
+ private final TextColor color;
+ private HashSet players;
+
+ private Team(final ChatColor chatColor, final TextColor color)
+ {
+ this.chatColor = chatColor;
+ this.color = color;
+ players = new HashSet<>();
+ }
+
+
+ public abstract String getName(final CPlayer cp);
+
+ public Component getColoredName(final CPlayer cp)
+ {
+ return Component.text(getName(cp))
+ .color(TextColor.color(color));
+ }
+
+ /**
+ * Executes lambda for each member of the team
+ * @param f Lambda to execute for each member
+ */
+ public void forEachMember(final CPlayer.ForEachPlayer f)
+ {
+ for (final CPlayer cp : players)
+ f.operation(cp);
+ }
+
+ /**
+ * Executes lambda for each member of the team
+ * @param pre Player predicate
+ * @param f Lambda to execute for each member
+ */
+ public void forEachMember(final CPlayer.PlayerPredicate pre, final CPlayer.ForEachPlayer f)
+ {
+ for (final CPlayer cp : players)
+ if (pre.operation(cp)) f.operation(cp);
+ }
+
+ public int count() {
+ return players.size();
+ }
+
+ /**
+ * Sets the player's team
+ * @param cp The player to change the team of
+ * @param team The new team
+ */
+ public static void setPlayerTeam(final @NonNull CPlayer cp, final @Nullable Team team) {
+ final Team oldTeam = cp.getTeam();
+ if (oldTeam != null) oldTeam.players.remove(cp);
+
+ cp.setTeam(team);
+ if (team != null) team.players.add(cp);
+ if (team != oldTeam)
+ Bukkit.getPluginManager().callEvent(new TeamChangeEvent(cp, oldTeam, team));
+ }
+
+ public static Team RED = new Team(ChatColor.RED, TextColor.color(255, 0, 0)) {
+ @Override
+ public String getName(CPlayer cp) {
+ return cp.getLocale().TEAM_RED;
+ }
+ };
+
+ public static Team BLUE = new Team(ChatColor.BLUE, TextColor.color(0, 0, 255)) {
+ @Override
+ public String getName(CPlayer cp) {
+ return cp.getLocale().TEAM_BLUE;
+ }
+ };
+
+ @WantsListen(phase = WantsListen.Target.Lobby)
+ public static class Events implements Listener
+ {
+ @EventHandler
+ public void onJoin(final CPlayerJoinEvent ev)
+ {
+ if (RED.count() < BLUE.count())
+ {
+ Team.setPlayerTeam(ev.getPlayer(), RED);
+ }
+ else if (BLUE.count() < RED.count()) {
+ Team.setPlayerTeam(ev.getPlayer(), BLUE);
+ }
+ // Random team
+ else {
+ Team.setPlayerTeam(ev.getPlayer(), Game.nextInt() % 2 == 0 ? RED : BLUE);
+ }
+ }
+ }
+}
diff --git a/core/src/main/java/org/ef3d0c3e/sheepwars/teams/TeamNPC.java b/core/src/main/java/org/ef3d0c3e/sheepwars/teams/TeamNPC.java
new file mode 100644
index 0000000..8464a3f
--- /dev/null
+++ b/core/src/main/java/org/ef3d0c3e/sheepwars/teams/TeamNPC.java
@@ -0,0 +1,108 @@
+package org.ef3d0c3e.sheepwars.teams;
+
+import com.comphenix.protocol.wrappers.EnumWrappers;
+import com.google.common.collect.Lists;
+import com.mojang.authlib.properties.Property;
+import lombok.NonNull;
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.format.TextColor;
+import net.kyori.adventure.text.format.TextDecoration;
+import org.bukkit.Location;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.scheduler.BukkitRunnable;
+import org.ef3d0c3e.sheepwars.SheepWars;
+import org.ef3d0c3e.sheepwars.events.TeamChangeEvent;
+import org.ef3d0c3e.sheepwars.events.WantsListen;
+import org.ef3d0c3e.sheepwars.npc.NPCFactory;
+import org.ef3d0c3e.sheepwars.npc.PlayerNPC;
+import org.ef3d0c3e.sheepwars.player.CPlayer;
+
+import java.util.List;
+
+public class TeamNPC extends PlayerNPC {
+ private static final int NETWORK_ID = 0xFF777720;
+ private final Location location;
+
+ public TeamNPC(Location location) {
+ super(NETWORK_ID);
+ this.location = location;
+ }
+
+ @Override
+ protected @NonNull String getName() {
+ return "skin";
+ }
+
+ @Override
+ protected @NonNull List getNametag(@NonNull CPlayer cp) {
+ if (cp.getCosmetics().getCurrentSkin() == null)
+ return Lists.newArrayList(
+ Component.text(cp.getLocale().TEAM_NPCNAME)
+ .color(TextColor.color(207, 50, 200))
+ .decorate(TextDecoration.BOLD));
+ else
+ return Lists.newArrayList(
+ Component.text(cp.getLocale().TEAM_NPCNAME)
+ .color(TextColor.color(207, 50, 200))
+ .decorate(TextDecoration.BOLD),
+ Component.text(cp.getLocale().TEAM_NPCCURRENT)
+ .color(TextColor.color(85, 85, 127))
+ .decorate(TextDecoration.UNDERLINED),
+ Component.text(cp.getCosmetics().getCurrentSkin().getName())
+ .color(TextColor.color(180, 85, 120))
+ );
+ }
+
+ @Override
+ protected @NonNull Property getTextures(@NonNull CPlayer cp) {
+ return new Property("textures",
+ "ewogICJ0aW1lc3RhbXAiIDogMTcwMTk1OTQ2MjQ4NSwKICAicHJvZmlsZUlkIiA6ICJmODY0ZjY3ZGJlN2Y0OTBlYTZlODQzMjg2M2NkZWMxOCIsCiAgInByb2ZpbGVOYW1lIiA6ICJCb3lmcmllbmQ1MDY1IiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzIzMDgwZWZlMzdkNTk0ZjU0ZjNjMTgxYmRlNTBlMTI4ZWQyZjQyYmVkOGQzNjk3N2Y4ZTQwNmRmZDY0ZWZkZmQiCiAgICB9CiAgfQp9",
+ "hB0+1tCYxTvdjYlYS7wtwqbf30CNa/8BmkrpWv7mA0MFiQIikInm+rZEZbyHFFOba8Dc5Ee9hC/pu4rHwBqXN4XjsFELFqUHymKnhOSNmUfY7aA0rn+CaNrJOP7LSrajSN+r7qgRsXUph/7yEaTpMhWwu+nfzbxtaS7e8WqjqHtMYdjWg30HSTqrSYzmobo9wh3twbuEFil8dCTdG3A9YkICfhYeuAgwDENGe220ThPC4HJsyPS1NCAkuwfGHKFyjqomUkPm0o6ijnb4I5naSvGFFLqvjJDFQ2dwui8TacykoLj+Mou3NnSTawcutBD10HiMF/mgssZTsINim1Da4uOZR9FsShiAk5Z4nq7unh0vPdH+lgCoTaN5tD0DCmrZt5OLSEqpzx62EoYRWM5nUXRISVHKKADpra424O9zSytOCwjGGvYVg6uB6lOOb+Gm1+VDEU+7QzwhpYiMFaqiofZDJw7LNQ0EZcbbbTUFfUE7/d/X4sb2AGQno7RGVAdWrz/Kszf6/ri+Wru4GRHZBaS3LVnxXU4FUL7P9yF3ZPrpNZIt14f1WSWmk1ltGnwNwK8HfSRfo7uWZtDVZZWOeJA1bqTYMDP9n1hIHYgrLdIEmXpGK3RVytYeKbQVLWbTtPKTzPMhDaDyQkwGint0HgFm3jS29sRejdAMF81Hjt4=");
+ }
+
+ @Override
+ protected @NonNull Location getLocation(@NonNull CPlayer cp) {
+ return location;
+ }
+
+ @Override
+ protected boolean sendPredicate(@NonNull CPlayer cp) {
+ return cp.getHandle().getWorld() == location.getWorld();
+ }
+
+ @Override
+ protected void onInteract(@NonNull CPlayer cp, EnumWrappers.Hand hand, boolean sneaking) {
+ new BukkitRunnable() {
+ @Override
+ public void run() {
+ if (!cp.isOnline()) return;
+
+ if (cp.getTeam() == Team.RED) {
+ Team.setPlayerTeam(cp, Team.BLUE);
+ } else {
+ Team.setPlayerTeam(cp, Team.RED);
+ }
+ }
+ }.runTask(SheepWars.getPlugin());
+ }
+
+ @Override
+ protected void update(final @NonNull CPlayer cp) {
+ // Resend nametag
+ removeNametag(cp, 3);
+ sendNametag(cp);
+
+ // Resend skin
+ sendInfo(cp, true);
+ }
+
+ @WantsListen(phase = WantsListen.Target.Lobby)
+ public static class Events implements Listener {
+ @EventHandler
+ public void onTeamChange(final TeamChangeEvent ev) {
+ ((TeamNPC) NPCFactory.get(NETWORK_ID)).update(ev.getPlayer());
+ }
+ }
+
+}
diff --git a/core/src/main/resources/exports/lobby.yml b/core/src/main/resources/exports/lobby.yml
index e6a7089..f063462 100644
--- a/core/src/main/resources/exports/lobby.yml
+++ b/core/src/main/resources/exports/lobby.yml
@@ -1,7 +1,7 @@
offset: [0, 64, 0]
spawn: [0.5, 65, 0.5, 0, 0]
limbo: 55
-info: [0.5, 59.5, 20.5, 0, 0]
+info: [0.5, 60.5, 20.5, 0, 0]
skin: [2.5, 58, 40.5, -179.9, 0]
team: [6.5, 58, 39.5, -179.9, 0]
kit: [-1.5, 58, 40.5, -179.9, 0]
diff --git a/core/src/main/resources/exports/locales/fr.yml b/core/src/main/resources/exports/locales/fr.yml
index 4a1fcc8..22728f5 100644
--- a/core/src/main/resources/exports/locales/fr.yml
+++ b/core/src/main/resources/exports/locales/fr.yml
@@ -55,7 +55,8 @@ team:
picker: "Choisissez une équipe"
npcname: "Choisissez une équipe"
npccurrent: "Votre équipe:"
-
+ red: "Rouge"
+ blue: "Bleue"
kit:
picker: "Choisissez un kit"
npcname: "Choisissez un kit"
diff --git a/pom.xml b/pom.xml
index d80ef7d..9880b6c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -40,6 +40,10 @@
sonatype
https://oss.sonatype.org/content/groups/public/
+
+ papermc
+ https://repo.papermc.io/repository/maven-public/
+
diff --git a/spigot-1.21.0/src/main/java/org/ef3d0c3e/sheepwars/v1_21_R0/Skin.java b/spigot-1.21.0/src/main/java/org/ef3d0c3e/sheepwars/v1_21_R0/Skin.java
index 7a4a3ac..a226386 100644
--- a/spigot-1.21.0/src/main/java/org/ef3d0c3e/sheepwars/v1_21_R0/Skin.java
+++ b/spigot-1.21.0/src/main/java/org/ef3d0c3e/sheepwars/v1_21_R0/Skin.java
@@ -1,7 +1,9 @@
package org.ef3d0c3e.sheepwars.v1_21_R0;
import com.github.retrooper.packetevents.PacketEvents;
+import com.github.retrooper.packetevents.protocol.chat.RemoteChatSession;
import com.github.retrooper.packetevents.protocol.player.GameMode;
+import com.github.retrooper.packetevents.protocol.player.PublicProfileKey;
import com.github.retrooper.packetevents.protocol.player.TextureProperty;
import com.github.retrooper.packetevents.protocol.player.UserProfile;
import com.github.retrooper.packetevents.protocol.world.Difficulty;
@@ -14,7 +16,9 @@ import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerPl
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerRespawn;
import com.mojang.authlib.properties.Property;
import com.mojang.authlib.properties.PropertyMap;
+import io.github.retrooper.packetevents.util.SpigotConversionUtil;
import lombok.NonNull;
+import net.kyori.adventure.text.Component;
import net.minecraft.core.GlobalPos;
import net.minecraft.core.Holder;
import net.minecraft.network.protocol.game.ClientboundRespawnPacket;
@@ -67,6 +71,9 @@ public class Skin implements SkinVersionWrapper
cp.getHandle().getUniqueId()
);
+ final ServerPlayer p = ((CraftPlayer)cp.getHandle()).getHandle();
+ final net.minecraft.network.chat.RemoteChatSession chatSession = p.getChatSession();
+
// Add info packet
final WrapperPlayServerPlayerInfoUpdate info = new WrapperPlayServerPlayerInfoUpdate(
WrapperPlayServerPlayerInfoUpdate.Action.ADD_PLAYER,
@@ -85,14 +92,19 @@ public class Skin implements SkinVersionWrapper
true,
cp.getHandle().getPing(),
GameMode.getById(cp.getHandle().getGameMode().getValue()),
- null,
- null
+ Component.text(cp.getHandle().getName()),
+ // FIXME: This is not correct as the player chat session is still invalid
+ new RemoteChatSession(chatSession.sessionId(), new PublicProfileKey(
+ chatSession.profilePublicKey().data().expiresAt(),
+ chatSession.profilePublicKey().data().key(),
+ chatSession.profilePublicKey().data().keySignature()
+ )
+ )
)
);
// Respawn packet
final ServerLevel level = ((CraftWorld)loc.getWorld()).getHandle();
- final ServerPlayer p = ((CraftPlayer)cp.getHandle()).getHandle();
final WrapperPlayServerRespawn respawn = new WrapperPlayServerRespawn(
new Dimension(level.getLevel().dimensionType().hashCode()),