This commit is contained in:
ef3d0c3e 2024-08-10 12:42:30 +02:00
parent 9d5c79cf6c
commit 6d3c2ceff0
32 changed files with 1603 additions and 48 deletions

View file

@ -0,0 +1,100 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<artifactId>SheepWars</artifactId>
<groupId>org.ef3d0c3e.sheepwars</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>SheepWars-core</artifactId>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-shade-plugin</artifactId>
<version>3.6.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
<configuration>
<relocations>
<relocation>
<pattern>com.github.retrooper.packetevents</pattern>
<shadedPattern>org.ef3d0c3e.lib.packetevents.api</shadedPattern>
</relocation>
<relocation>
<pattern>io.github.retrooper.packetevents</pattern>
<shadedPattern>org.ef3d0c3e.lib.packetevents.impl</shadedPattern>
</relocation>
<relocation>
<pattern>de.cubbossa.cliententities.lib.packetevents.api</pattern>
<shadedPattern>org.ef3d0c3e.lib.packetevents.api</shadedPattern>
</relocation>
<relocation>
<pattern>de.cubbossa.cliententities.lib.packetevents.impl</pattern>
<shadedPattern>org.ef3d0c3e.lib.packetevents.impl</shadedPattern>
</relocation>
<relocation>
<pattern>fr.mrmicky.fastboard</pattern>
<shadedPattern>org.ef3d0c3e.lib.fastboard</shadedPattern>
</relocation>
</relocations>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot</artifactId>
<version>1.21.1-R0.1-SNAPSHOT</version>
<classifier>remapped-mojang</classifier>
<scope>provided</scope>
<exclusions>
<exclusion>
<artifactId>commons-lang</artifactId>
<groupId>commons-lang</groupId>
</exclusion>
<exclusion>
<artifactId>json-simple</artifactId>
<groupId>com.googlecode.json-simple</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.21.1-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.github.retrooper</groupId>
<artifactId>packetevents-spigot</artifactId>
<version>2.4.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.comphenix.protocol</groupId>
<artifactId>ProtocolLib</artifactId>
<version>5.2.0-SNAPSHOT-726</version>
<scope>system</scope>
<systemPath>${pom.basedir}/../libs/ProtocolLib.jar</systemPath>
</dependency>
<dependency>
<groupId>com.sk89q.worldedit</groupId>
<artifactId>worldedit-bukkit</artifactId>
<version>7.3.6</version>
<scope>system</scope>
<systemPath>${pom.basedir}/../libs/worldedit-bukkit-7.3.6-SNAPSHOT-dist.jar</systemPath>
</dependency>
</dependencies>
</project>

View file

@ -48,12 +48,18 @@
<scope>system</scope>
<systemPath>${pom.basedir}/../libs/ProtocolLib.jar</systemPath>
</dependency>
<dependency>
<groupId>com.github.retrooper</groupId>
<artifactId>packetevents-spigot</artifactId>
<version>2.4.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.sk89q.worldedit</groupId>
<artifactId>worldedit-bukkit</artifactId>
<version>7.3.5</version>
<version>7.3.6</version>
<scope>system</scope>
<systemPath>${pom.basedir}/../libs/worldedit-bukkit-7.3.5.jar</systemPath>
<systemPath>${pom.basedir}/../libs/worldedit-bukkit-7.3.6-SNAPSHOT-dist.jar</systemPath>
</dependency>
<dependency>
<groupId>fr.mrmicky</groupId>
@ -61,9 +67,9 @@
<version>2.1.3</version>
</dependency>
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>bukkit</artifactId>
<version>1.21.1-R0.1-SNAPSHOT</version>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>33.1.0-jre</version>
<scope>compile</scope>
</dependency>
</dependencies>

View file

@ -1,7 +1,8 @@
package org.ef3d0c3e.sheepwars;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.ProtocolManager;
import com.github.retrooper.packetevents.PacketEvents;
import io.github.retrooper.packetevents.factory.spigot.SpigotPacketEventsBuilder;
import org.ef3d0c3e.sheepwars.commands.CommandFactory;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.configuration.InvalidConfigurationException;
@ -15,6 +16,7 @@ import org.ef3d0c3e.sheepwars.events.EventListenerFactory;
import org.ef3d0c3e.sheepwars.game.Game;
import org.ef3d0c3e.sheepwars.level.VoidChunkGenerator;
import org.ef3d0c3e.sheepwars.locale.LocaleManager;
import org.ef3d0c3e.sheepwars.packets.PacketListenerFactory;
import org.ef3d0c3e.sheepwars.player.CPlayer;
import org.ef3d0c3e.sheepwars.versions.WrapperFactory;
import org.jetbrains.annotations.NotNull;
@ -22,7 +24,6 @@ import org.jetbrains.annotations.NotNull;
import java.io.*;
import java.text.MessageFormat;
import java.util.Enumeration;
import java.util.EventListener;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
@ -31,8 +32,6 @@ public final class SheepWars extends JavaPlugin
@Getter
private static Plugin plugin;
@Getter
private static ProtocolManager protocolManager;
@Getter
private static Config sheepWarsConfig;
@Getter
private static LocaleManager localeManager;
@ -87,7 +86,6 @@ public final class SheepWars extends JavaPlugin
{
throw new RuntimeException(e);
}
}
{
@ -136,22 +134,32 @@ public final class SheepWars extends JavaPlugin
e.printStackTrace();
}
PacketEvents.setAPI(SpigotPacketEventsBuilder.build(this));
PacketEvents.getAPI().load();
consoleMessage("--[ Setup done ]--");
}
@Override
public void onDisable() {
PacketEvents.getAPI().terminate();
consoleMessage("Plugin Disabled!");
}
@Override
public void onEnable() {
plugin = this;
protocolManager = ProtocolLibrary.getProtocolManager();
PacketEvents.getAPI().getSettings()
.debug(true)
.reEncodeByDefault(true);
PacketEvents.getAPI().init();
// Factories
try {
CommandFactory.registerCommands();
EventListenerFactory.create();
PacketListenerFactory.create();
}
catch (Exception e)
{

View file

@ -0,0 +1,4 @@
package org.ef3d0c3e.sheepwars;
public class Util {
}

View file

@ -0,0 +1,60 @@
package org.ef3d0c3e.sheepwars.commands;
import com.google.common.collect.Lists;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nullable;
import java.util.Arrays;
import java.util.List;
public class CmdSheepWars extends Command {
public CmdSheepWars()
{
super("sheepwars", "Plugin command", "/sheepwars", Arrays.asList("sw"));
setPermission("sw.admin");
}
@Override
public boolean execute(@NotNull CommandSender sender, @NotNull String s, @NotNull String[] args) {
if (!(sender instanceof Player))
{
sender.sendMessage("§cYou must be a player to execute this command.");
return false;
}
final Player p = (Player)sender;
final String category = args.length == 0 ? "help" : args[0];
if (category.equals("help"))
{
sender.sendMessage(" - §ahelp §fDisplays this page");
sender.sendMessage(" - §astart §fStarts the game");
sender.sendMessage(" - §adebug §7<option> §fFor developers");
}
return true;
}
@Override
public @Nullable List<String> tabComplete(final @NotNull CommandSender sender, final @NotNull String label, final @NotNull String[] args)
{
if (args.length == 0) return null;
else if (args.length == 1)
{
return Lists.newArrayList(
"help",
"start",
"debug"
);
}
else if (args[0].equals("debug"))
{
if (args.length == 2) return Lists.newArrayList("<poses>");
}
return null;
}
}

View file

@ -0,0 +1,107 @@
package org.ef3d0c3e.sheepwars.commands;
import org.bukkit.Bukkit;
import org.bukkit.command.*;
import org.bukkit.help.GenericCommandHelpTopic;
import org.bukkit.help.HelpTopic;
import org.bukkit.help.IndexHelpTopic;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.reflections.Reflections;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
public class CommandFactory implements CommandExecutor, TabCompleter
{
private static final HashMap<String, Command> COMMANDS;
static
{
COMMANDS = new HashMap<>();
// Find all commands and populate COMMANDS
Reflections refl = new Reflections("org.ef3d0c3e.sheepwars.commands");
Set<Class<? extends Command>> classes = refl.getSubTypesOf(Command.class);
for (Class C : classes)
{
try
{
final Command cmd;
cmd = (Command)(C.getDeclaredConstructor().newInstance());
COMMANDS.put(cmd.getName(), cmd);
}
catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e)
{
throw new RuntimeException(e);
}
}
}
/**
* @brief Registers all commands
*/
public static void registerCommands()
{
final CommandFactory executor = new CommandFactory();
// Get command map
CommandMap map = null;
try
{
Field cmdMap = Bukkit.getPluginManager().getClass().getDeclaredField("commandMap");
cmdMap.setAccessible(true);
map = (CommandMap)cmdMap.get(Bukkit.getPluginManager());
}
catch (Exception e)
{
e.printStackTrace();
return;
}
// Register commands
for (final Command cmd : COMMANDS.values())
map.register(cmd.getName(), cmd);
// Generate help
List<HelpTopic> cmdHelp = new ArrayList<>();
COMMANDS.forEach((name, cmd) -> cmdHelp.add(new GenericCommandHelpTopic(cmd)));
Bukkit.getHelpMap().addTopic(
new IndexHelpTopic(
"Hunt",
"Hunt minigame plugin",
"org.ef3d0c3e.hunt.help",
cmdHelp,
"Hunt plugin"
)
);
}
@Override
public boolean onCommand(final @NotNull CommandSender sender, final Command cmd, final @NotNull String label, final String[] args)
{
final Command bcmd = COMMANDS.get(cmd.getName().toLowerCase());
if (bcmd == null)
return false;
bcmd.execute(sender, label, args);
return true;
}
@Override
public @Nullable List<String> onTabComplete(final @NotNull CommandSender sender, final Command cmd, final @NotNull String label, final String[] args)
{
final Command bcmd = COMMANDS.get(cmd.getName().toLowerCase());
if (bcmd == null)
return null;
return bcmd.tabComplete(sender, label, args);
}
}

View file

@ -7,6 +7,7 @@ import org.ef3d0c3e.sheepwars.events.EventListenerFactory;
import org.ef3d0c3e.sheepwars.events.WantsListen;
import org.ef3d0c3e.sheepwars.level.LevelFactory;
import org.ef3d0c3e.sheepwars.level.lobby.LobbyLevel;
import org.ef3d0c3e.sheepwars.packets.PacketListenerFactory;
public class Game {
private static void changePhase(WantsListen.Target phase)
@ -15,8 +16,7 @@ public class Game {
EventListenerFactory.update(phase);
//TimedListenerFactory.update(phase);
//PacketListenerFactory.update(phase);
//RecipeFactory.update(phase);
PacketListenerFactory.update(phase);
}
@Getter
@ -43,7 +43,7 @@ public class Game {
//LevelFactory.add(level);
// Create lobby world
// Game level is created once it is needeed
// Game level is created once it is needed
// @see CmdHunt
new BukkitRunnable()
{

View file

@ -0,0 +1,47 @@
package org.ef3d0c3e.sheepwars.hologram;
import lombok.Getter;
import lombok.NonNull;
import org.bukkit.Location;
import org.ef3d0c3e.sheepwars.player.CPlayer;
import java.util.ArrayList;
public abstract class Hologram
{
@Getter
private final int networkId;
@Getter
private final ArrayList<HologramComponent> components;
/**
* Constructor
* @param networkId Base network id
*/
protected Hologram(final int networkId)
{
this.networkId = networkId;
components = new ArrayList<>();
}
/**
* Adds component to hologram
* @param component Component to add
*/
public void addComponent(final @NonNull HologramComponent component)
{
this.components.add(component);
}
/**
* Gets hologram location for player
* @param cp Player to get location for
* @return Hologram location
*/
public abstract @NonNull Location getLocation(final @NonNull CPlayer cp);
protected boolean sendPredicate(final @NonNull CPlayer cp)
{
return true;
}
}

View file

@ -0,0 +1,39 @@
package org.ef3d0c3e.sheepwars.hologram;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import lombok.Getter;
import lombok.NonNull;
import org.bukkit.Location;
import org.bukkit.util.Vector;
import org.ef3d0c3e.sheepwars.player.CPlayer;
import java.util.List;
/**
* Abstract class for a Hologram's component
*/
public abstract class HologramComponent
{
@Getter
private Vector offset;
protected HologramComponent(final @NonNull Vector offset)
{
this.offset = offset;
}
/**
* Gets the amount of network entity id that the component takes
* @return The number of entity id taken by the component
*/
protected abstract int getNetworkOffset();
/**
* Builds hologram packets
*
* @param networkId Base network id
* @param cp Player to build hologram component for
* @return Packets to display component
*/
protected abstract @NonNull List<PacketWrapper<?>> build(final @NonNull Location location, final int networkId, final @NonNull CPlayer cp);
}

View file

@ -0,0 +1,105 @@
package org.ef3d0c3e.sheepwars.hologram;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerDestroyEntities;
import lombok.NonNull;
import org.bukkit.Location;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.ef3d0c3e.sheepwars.SheepWars;
import org.ef3d0c3e.sheepwars.events.CPlayerJoinEvent;
import org.ef3d0c3e.sheepwars.events.WantsListen;
import org.ef3d0c3e.sheepwars.player.CPlayer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class HologramFactory
{
private static final HashMap<Integer, Hologram> registry = new HashMap<>();
public static void register(final @NonNull Hologram hologram)
{
registry.put(hologram.getNetworkId(), hologram);
}
public static void unregister(final @NonNull Hologram hologram)
{
registry.remove(hologram.getNetworkId());
}
/**
* Sends hologram to player
* @param hologram Hologram to send
* @param cp Player to send hologram to
*/
public static void send(final @NonNull Hologram hologram, final @NonNull CPlayer cp)
{
final List<HologramComponent> components = hologram.getComponents();
final Location location = hologram.getLocation(cp);
int networkId = hologram.getNetworkId();
for (final HologramComponent component : components)
{
// Build & send packets
for (final PacketWrapper<?> packet : component.build(location, networkId, cp))
PacketEvents.getAPI().getPlayerManager().sendPacket(cp.getHandle(), packet);
// Offset network id
networkId += component.getNetworkOffset();
}
}
/**
* Un-sends hologram to player
* @param hologram Hologram to un-send
* @param cp Player to un-send to
*/
public static void unsend(final @NonNull Hologram hologram, final @NonNull CPlayer cp)
{
int networkId = hologram.getNetworkId();
final List<HologramComponent> components = hologram.getComponents();
int size = 0;
for (final HologramComponent component : components)
{
size += component.getNetworkOffset();
}
final int[] list = new int[size];
int pos = 0;
for (final HologramComponent component : hologram.getComponents())
{
for (int i = 0; i < component.getNetworkOffset(); ++i) {
list[pos] = networkId + i;
++pos;
}
networkId += component.getNetworkOffset();
}
final WrapperPlayServerDestroyEntities remove = new WrapperPlayServerDestroyEntities();
remove.setEntityIds(list);
PacketEvents.getAPI().getPlayerManager().sendPacket(cp.getHandle(), remove);
}
@WantsListen(phase = WantsListen.Target.Always)
public static class HologramListener implements Listener
{
// TODO..., on chunk load request [something...]
@EventHandler
public void onJoin(final CPlayerJoinEvent ev)
{
final CPlayer cp = ev.getPlayer();
for (final Hologram hologram : registry.values())
{
if (!hologram.sendPredicate(cp)) continue;
send(hologram, cp);
}
}
}
}

View file

@ -0,0 +1,64 @@
package org.ef3d0c3e.sheepwars.hologram;
import com.comphenix.protocol.wrappers.WrappedChatComponent;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.protocol.entity.data.EntityData;
import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
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 com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerSpawnLivingEntity;
import lombok.NonNull;
import net.kyori.adventure.text.Component;
import org.bukkit.Location;
import org.bukkit.util.Vector;
import org.ef3d0c3e.sheepwars.packets.EntityMetadata;
import org.ef3d0c3e.sheepwars.player.CPlayer;
import java.util.*;
/**
* Represent a text component
*/
public abstract class HologramTextComponent extends HologramComponent
{
protected HologramTextComponent(@NonNull Vector offset)
{
super(offset);
}
protected abstract @NonNull Component getText(final @NonNull CPlayer cp);
protected int getNetworkOffset() { return 1; }
protected @NonNull List<PacketWrapper<?>> 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.ARMOR_STAND,
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.Status()
.isInvisible(true)
.into(),
new EntityMetadata.NoGravity(true).into(),
new EntityMetadata.CustomNameVisible(true).into(),
new EntityMetadata.CustomName(getText(cp)).into()
)
);
return List.of(spawn, meta);
}
}

View file

@ -0,0 +1,211 @@
package org.ef3d0c3e.sheepwars.items;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NonNull;
import org.bukkit.NamespacedKey;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.Item;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.entity.Sheep;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.enchantment.EnchantItemEvent;
import org.bukkit.event.entity.EntityPickupItemEvent;
import org.bukkit.event.entity.ItemDespawnEvent;
import org.bukkit.event.player.PlayerDropItemEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType;
import org.ef3d0c3e.sheepwars.SheepWars;
import org.ef3d0c3e.sheepwars.events.WantsListen;
import javax.annotation.Nullable;
import java.util.UUID;
// TODO: Add option to prevent using the item in crafting recipes
public abstract class IItem
{
/**
* UUID persistant tag
*/
static private final PersistentDataType<byte[], UUID> TAG_UUID = new UUIDItemTagType();
/**
* Key used to store item's id
*/
static protected final NamespacedKey KEY_ID = new NamespacedKey(SheepWars.getPlugin(), "hunt_uuid");
/**
* Item's id
*/
@Getter(AccessLevel.MODULE)
private UUID id;
/**
* Constructor
*/
public IItem()
{
this.id = UUID.randomUUID();
}
public IItem(final UUID id)
{
this.id = id;
}
/**
* Gets item's key
* @param item Item to get id of
* @return Item's id or null
*/
protected static @Nullable UUID getId(final ItemStack item)
{
final ItemMeta meta = item.getItemMeta();
if (meta == null)
return null;
final PersistentDataContainer container = meta.getPersistentDataContainer();
if (container == null)
return null;
return container.getOrDefault(KEY_ID, TAG_UUID, null);
}
public static boolean replace(final @NonNull Inventory inv, final @NonNull IItem item, final @NonNull ItemStack replace)
{
boolean replaced = false;
for (int i = 0; i < inv.getSize(); ++i)
{
if (inv.getItem(i) == null || inv.getItem(i).getItemMeta() == null) continue;
final IItem base = ItemFactory.getItem(inv.getItem(i));
if (base == null || base.getId() != item.getId()) continue;
inv.setItem(i, replace);
replaced = true;
}
return replaced;
}
/**
* Applies custom item to itemstack
* @param item Item to apply custom item to
* @return ItemStack
*/
public ItemStack apply(final ItemStack item)
{
final ItemStack custom = item.clone();
final ItemMeta meta = custom.getItemMeta();
meta.getPersistentDataContainer().set(KEY_ID, TAG_UUID, getId());
custom.setItemMeta(meta);
return custom;
}
protected abstract boolean onDrop(final Player p, final ItemStack item);
protected abstract boolean onInteract(final Player p, final ItemStack item, final Action action, final EquipmentSlot hand, final Block clicked, final BlockFace clickedFace);
protected boolean onEnchant(final EnchantItemEvent ev) { return true; }
protected boolean onPickup(final LivingEntity ent, final Item item, final int remaining) { return false; }
protected boolean onDespawn(final Item item) { return false; }
/**
* Events to handle custom items
* Note: Does not handle events related to entities/inventories not linked to a player
*/
@WantsListen(phase = WantsListen.Target.Always)
public static class Events implements Listener
{
/**
* Handles custom item interactions
* @param ev Event
*/
@EventHandler
public void onInteract(final PlayerInteractEvent ev)
{
if (ev.getItem() == null)
return;
final IItem item = ItemFactory.getItem(ev.getItem());
if (item == null)
return;
ev.setCancelled(item.onInteract(
ev.getPlayer(),
ev.getItem(),
ev.getAction(),
ev.getHand(),
ev.getClickedBlock(),
ev.getBlockFace()
));
}
/**
* Handles custom item dropping
* @param ev Event
*/
@EventHandler
public void onDrop(final PlayerDropItemEvent ev)
{
final ItemStack stack = ev.getItemDrop().getItemStack();
final IItem item = ItemFactory.getItem(stack);
if (item == null)
return;
ev.setCancelled(item.onDrop(ev.getPlayer(), stack));
}
/**
* Handles custom item enchant
* @param ev Event
*/
@EventHandler
public void onEnchant(final EnchantItemEvent ev)
{
final IItem item = ItemFactory.getItem(ev.getItem());
if (item == null)
return;
item.onEnchant(ev);
}
/**
* Handles custom item pickup
* @param ev Event
*/
@EventHandler
public void onPickup(final EntityPickupItemEvent ev)
{
final IItem item = ItemFactory.getItem(ev.getItem().getItemStack());
if (item == null)
return;
ev.setCancelled(item.onPickup(
ev.getEntity(),
ev.getItem(),
ev.getRemaining()
));
}
/**
* Handles custom item despawn
* @param ev Event
*/
@EventHandler
public void onDespawn(final ItemDespawnEvent ev)
{
final IItem item = ItemFactory.getItem(ev.getEntity().getItemStack());
if (item == null)
return;
ev.setCancelled(item.onDespawn(ev.getEntity()));
}
}
}

View file

@ -0,0 +1,38 @@
package org.ef3d0c3e.sheepwars.items;
import org.bukkit.inventory.ItemStack;
import javax.annotation.Nullable;
import java.util.HashMap;
import java.util.UUID;
/**
* Class used to register custom items
*/
public class ItemFactory
{
protected static HashMap<UUID, IItem> registry = new HashMap<>();
/**
* Gets custom item from itemstack
* @param item Item
* @return Custom item (null for normal item)
*/
public static @Nullable IItem getItem(final ItemStack item)
{
final UUID id = IItem.getId(item);
if (id == null)
return null;
return registry.get(id);
}
/**
* Registers custom item to registry
* @param item Item to register
*/
public static void registerItem(final IItem item)
{
registry.put(item.getId(), item);
}
}

View file

@ -0,0 +1,42 @@
package org.ef3d0c3e.sheepwars.items;
import org.bukkit.persistence.PersistentDataAdapterContext;
import org.bukkit.persistence.PersistentDataType;
import org.jetbrains.annotations.NotNull;
import java.nio.ByteBuffer;
import java.util.UUID;
public class UUIDItemTagType implements PersistentDataType<byte[], UUID>
{
@Override
public @NotNull Class<byte[]> getPrimitiveType()
{
return byte[].class;
}
@Override
public @NotNull Class<UUID> getComplexType()
{
return UUID.class;
}
@Override
public byte[] toPrimitive(UUID uuid, @NotNull PersistentDataAdapterContext context)
{
ByteBuffer buffer = ByteBuffer.allocate(16);
buffer.putLong(uuid.getLeastSignificantBits());
buffer.putLong(uuid.getMostSignificantBits());
return buffer.array();
}
@Override
public @NotNull UUID fromPrimitive(byte @NotNull [] bytes, @NotNull PersistentDataAdapterContext context)
{
ByteBuffer buffer = ByteBuffer.wrap(bytes);
long leastBits = buffer.getLong();
long mostBits = buffer.getLong();
return new UUID(mostBits, leastBits);
}
}

View file

@ -70,6 +70,8 @@ public abstract class Level
@WantsListen(phase = WantsListen.Target.Always)
public static class Events implements Listener
{
// FIXME: For the 'default' world, you need to remove it because
// we can't register it at the same time it gets loaded... (API limitation)
@EventHandler
public void onChunkLoad(final ChunkLoadEvent ev)
{
@ -88,6 +90,15 @@ public abstract class Level
public void onWorldInit(final WorldInitEvent ev)
{
ev.getWorld().setKeepSpawnInMemory(false);
final Level level = LevelFactory.get(ev.getWorld().getName());
if (level == null) return;
if (!level.initialized)
{
level.handle = Bukkit.getWorld(level.getWorldName());
level.postWorld();
level.initialized = true;
}
}
}
}

View file

@ -1,5 +1,12 @@
package org.ef3d0c3e.sheepwars.level.lobby;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.manager.player.PlayerManager;
import com.github.retrooper.packetevents.protocol.npc.NPC;
import com.github.retrooper.packetevents.protocol.player.User;
import com.github.retrooper.packetevents.protocol.player.UserProfile;
import com.github.retrooper.packetevents.protocol.world.Location;
import com.github.retrooper.packetevents.util.Vector3d;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
@ -14,6 +21,8 @@ import org.bukkit.inventory.PlayerInventory;
import org.ef3d0c3e.sheepwars.events.*;
import org.ef3d0c3e.sheepwars.game.Game;
import java.util.UUID;
@WantsListen(phase = WantsListen.Target.Lobby)
public class LobbyEvents implements Listener
{

View file

@ -19,6 +19,7 @@ import org.ef3d0c3e.sheepwars.SheepWars;
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 java.io.*;
@ -54,13 +55,13 @@ public class LobbyLevel extends Level
HologramFactory.register(hologram);
skinNpc = new SkinDisplayNPC(config.SKIN.getLocation(getHandle()));
NPCManager.register(skinNpc);
NPCFactory.register(skinNpc);
teamNpc = new TeamNPC(config.TEAM.getLocation(getHandle()));
NPCManager.register(teamNpc);
NPCFactory.register(teamNpc);
kitNpc = new KitNPC(config.KIT.getLocation(getHandle()));
NPCManager.register(kitNpc);
NPCFactory.register(kitNpc);
*/
}

View file

@ -0,0 +1,135 @@
package org.ef3d0c3e.sheepwars.npc;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.events.ListeningWhitelist;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.events.PacketListener;
import com.comphenix.protocol.injector.GamePhase;
import com.comphenix.protocol.wrappers.EnumWrappers;
import com.comphenix.protocol.wrappers.WrappedEnumEntityUseAction;
import lombok.NonNull;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.plugin.Plugin;
import org.ef3d0c3e.sheepwars.SheepWars;
import org.ef3d0c3e.sheepwars.events.CPlayerJoinEvent;
import org.ef3d0c3e.sheepwars.events.WantsListen;
import org.ef3d0c3e.sheepwars.player.CPlayer;
import javax.annotation.Nullable;
import java.util.HashMap;
public class NPCFactory
{
private static HashMap<Integer, PlayerNPC> registry = new HashMap<>();
/**
* Registers NPC into the registry
* @param npc NPC to register (does nothing if NPC's networkId is already registered)
*/
public static void register(final @NonNull PlayerNPC npc)
{
registry.put(npc.getNetworkId(), npc);
}
/**
* Unregisters NPC from the registry
* @param npc NPC to unregister
* @return npc on successful unregister, null otherwise
*/
public static @Nullable
PlayerNPC unregsiter(final @NonNull PlayerNPC npc)
{
return registry.remove(npc.getNetworkId());
}
/**
* Gets NPC from registry using network id
* @param eid's NPC network id
* @return NPC if found, null otherwise
*/
public static @Nullable PlayerNPC get(int eid)
{
return registry.get(eid);
}
@WantsListen(phase = WantsListen.Target.Always)
public static class NPCListener implements Listener
{
// TODO..., on chunk load request [something...]
@EventHandler
public void onJoin(final CPlayerJoinEvent ev)
{
final CPlayer cp = ev.getPlayer();
for (final PlayerNPC npc : registry.values())
{
if (!npc.sendPredicate(cp)) continue;
npc.sendInfo(cp, false);
npc.send(cp);
npc.sendNametag(cp);
}
}
}
@WantsListen(phase = WantsListen.Target.Always)
public static class NPCPacketListener implements PacketListener
{
@Override
public void onPacketSending(final PacketEvent packetEvent)
{
}
@Override
public void onPacketReceiving(final PacketEvent packetEvent)
{
final PacketContainer interact = packetEvent.getPacket();
final PlayerNPC npc = get(interact.getIntegers().read(0));
if (npc == null) return;
final CPlayer cp = CPlayer.get(packetEvent.getPlayer());
final Location npcLoc = npc.getLocation(cp);
if (!npcLoc.getWorld().equals(cp.getHandle().getWorld())) return; // Fake packet check
final double distSq = cp.getHandle().getLocation().distanceSquared(npcLoc);
if (distSq >= 49.0) return; // Reach check
final WrappedEnumEntityUseAction action = interact.getEnumEntityUseActions().read(0);
if (action.getAction().equals(EnumWrappers.EntityUseAction.INTERACT))
{
npc.onInteract(
cp,
action.getHand(),
interact.getBooleans().read(0)
);
}
}
@Override
public ListeningWhitelist getSendingWhitelist()
{
return ListeningWhitelist.EMPTY_WHITELIST;
}
private final ListeningWhitelist listeningWhitelist = ListeningWhitelist.newBuilder()
.gamePhase(GamePhase.PLAYING)
.types(PacketType.Play.Client.USE_ENTITY)
.build();
@Override
public ListeningWhitelist getReceivingWhitelist()
{
return listeningWhitelist;
}
@Override
public Plugin getPlugin()
{
return SheepWars.getPlugin();
}
}
}

View file

@ -0,0 +1,214 @@
package org.ef3d0c3e.sheepwars.npc;
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;
import com.github.retrooper.packetevents.util.Vector3d;
import com.github.retrooper.packetevents.wrapper.play.server.*;
import com.mojang.authlib.properties.Property;
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.EntityMetadata;
import org.ef3d0c3e.sheepwars.packets.PlayerMetadata;
import org.ef3d0c3e.sheepwars.player.CPlayer;
import java.util.*;
public abstract class PlayerNPC
{
/**
* The NPC's unique id
*/
@Getter
private final UUID uniqueId;
@Getter
private final int networkId;
/**
* Constructor
* @param networkId NPC (unique) network id
*/
public PlayerNPC(final int networkId)
{
uniqueId = UUID.randomUUID();
this.networkId = networkId;
}
protected abstract @NonNull String getName();
protected abstract @NonNull List<Component> getNametag(final @NonNull CPlayer cp);
protected abstract @NonNull Property getTextures(final @NonNull CPlayer cp);
protected abstract @NonNull Location getLocation(final @NonNull CPlayer cp);
protected abstract boolean sendPredicate(final @NonNull CPlayer cp);
protected @NonNull List<EntityData> getMetadata(final @NonNull CPlayer cp)
{
return List.of(
new PlayerMetadata.SkinParts()
.all()
.into()
);
}
/**
* Updates the NPC (resend metadata, skin profile etc...)
* @param cp Player to update NPC for
*/
protected void update(final @NonNull CPlayer cp) {}
// TODO: add more methods, such as inventory, potion effects...
/**
* Called when NPC is interacted with (Right click)
* @param cp Player that interacted
* @param hand Interacted hand
* @param sneaking Whether player is sneaking
*/
protected abstract void onInteract(final @NonNull CPlayer cp, final EnumWrappers.Hand hand, boolean sneaking);
protected void send(final @NonNull CPlayer cp)
{
// Spawn packet
final Location loc = getLocation(cp);
final WrapperPlayServerSpawnEntity spawn = new WrapperPlayServerSpawnEntity(
networkId, Optional.of(uniqueId),
EntityTypes.PLAYER,
new Vector3d(loc.getX(), loc.getY(), loc.getZ()),
loc.getPitch(), loc.getYaw(), loc.getYaw(),
0,
Optional.empty()
);
// metadata
final WrapperPlayServerEntityMetadata playerMeta = new WrapperPlayServerEntityMetadata(
networkId,
getMetadata(cp)
);
// Team packet (to hide the nametag)
final WrapperPlayServerTeams team = new WrapperPlayServerTeams(
"NPC-" + getName(),
WrapperPlayServerTeams.TeamMode.CREATE,
new WrapperPlayServerTeams.ScoreBoardTeamInfo(
Component.empty(),
null, null,
WrapperPlayServerTeams.NameTagVisibility.NEVER,
WrapperPlayServerTeams.CollisionRule.NEVER,
NamedTextColor.WHITE,
WrapperPlayServerTeams.OptionData.NONE
),
Collections.singletonList("NPC-" + getName())
);
PacketEvents.getAPI().getPlayerManager().sendPacket(cp.getHandle(), spawn);
PacketEvents.getAPI().getPlayerManager().sendPacket(cp.getHandle(), playerMeta);
PacketEvents.getAPI().getPlayerManager().sendPacket(cp.getHandle(), team);
}
/**
* Removes NPC nametag for player
* @note {@see sendNametag(cp)} should be called after this method
* @param cp Player
* @param number Number of nametags to remove
*/
protected void removeNametag(final @NonNull CPlayer cp, int number)
{
final int eids[] = new int[number];
for (int i = 0; i < number; ++i) eids[i] = getNetworkId() + i + 1;
final WrapperPlayServerDestroyEntities remove = new WrapperPlayServerDestroyEntities();
remove.setEntityIds(eids);
PacketEvents.getAPI().getPlayerManager().sendPacket(cp.getHandle(), remove);
}
protected void sendNametag(final @NonNull CPlayer cp)
{
final List<Component> tags = getNametag(cp);
int i = 0;
for (final Component tag : tags)
{
// Spawn
final Location loc = getLocation(cp);
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()),
0.f, 0.f, 0.f,
0,
Optional.empty()
);
// Metadata
final WrapperPlayServerEntityMetadata meta = new WrapperPlayServerEntityMetadata(
networkId+i+1,
Arrays.asList(
new EntityMetadata.Status()
.isInvisible(true)
.into(),
new EntityMetadata.NoGravity(true).into(),
new EntityMetadata.CustomNameVisible(true).into(),
new EntityMetadata.CustomName(tag).into()
)
);
PacketEvents.getAPI().getPlayerManager().sendPacket(cp.getHandle(), spawn);
PacketEvents.getAPI().getPlayerManager().sendPacket(cp.getHandle(), meta);
++i;
}
}
/**
* Sends player info (profile)
* @note Setting {@ref resend} to true will send a destroy packet and then resend the player packet
* @param cp Player to send to
* @param resend If true, will send a {@code PlayerInfoRemove} packet first
*/
protected void sendInfo(final @NonNull CPlayer cp, boolean resend)
{
// Remove any previously sent NPC
if (resend)
{
final WrapperPlayServerPlayerInfoRemove infoRemove = new WrapperPlayServerPlayerInfoRemove(getUniqueId());
final WrapperPlayServerDestroyEntities remove = new WrapperPlayServerDestroyEntities(networkId);
PacketEvents.getAPI().getPlayerManager().sendPacket(cp.getHandle(), infoRemove);
PacketEvents.getAPI().getPlayerManager().sendPacket(cp.getHandle(), remove);
}
final Property texture = getTextures(cp);
final WrapperPlayServerPlayerInfoUpdate info = new WrapperPlayServerPlayerInfoUpdate(
WrapperPlayServerPlayerInfoUpdate.Action.ADD_PLAYER,
new WrapperPlayServerPlayerInfoUpdate.PlayerInfo(
new UserProfile(
uniqueId,
"NPC-" + getName(),
List.of(
new TextureProperty(
texture.name(),
texture.value(),
texture.signature()
)
)
),
false,
0,
GameMode.SURVIVAL,
null,
null
)
);
PacketEvents.getAPI().getPlayerManager().sendPacket(cp.getHandle(), info);
// Also resend nametag
if (resend)
send(cp);
}
}

View file

@ -0,0 +1,45 @@
package org.ef3d0c3e.sheepwars.packets;
import com.github.retrooper.packetevents.protocol.entity.data.EntityData;
import com.github.retrooper.packetevents.protocol.entity.data.EntityDataType;
import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
import lombok.Getter;
public class ArmorStandMetadata {
public static class Status implements IntoEntityData {
@Override
public EntityData into() {
return new EntityData(
15,
EntityDataTypes.BYTE,
value
);
}
byte value;
public Status() {
this.value = 0;
}
public Status isSmall(boolean v) {
value = (byte)(value | (v ? 0b1 : 0b0));
return this;
}
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) {
value = (byte)(value | (v ? 0b1000 : 0b0));
return this;
}
}
}

View file

@ -0,0 +1,134 @@
package org.ef3d0c3e.sheepwars.packets;
import com.github.retrooper.packetevents.protocol.entity.data.EntityData;
import com.github.retrooper.packetevents.protocol.entity.data.EntityDataType;
import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
import lombok.AllArgsConstructor;
import lombok.Getter;
import net.kyori.adventure.text.Component;
import java.util.Optional;
public class EntityMetadata {
public static class Status implements IntoEntityData {
@Override
public EntityData into() {
return new EntityData(
0,
EntityDataTypes.BYTE,
value
);
}
byte value;
public Status() {
this.value = 0;
}
public Status onFire(boolean v) {
value = (byte)(value | (v ? 0b1 : 0b0));
return this;
}
public Status isCrouching(boolean v) {
value = (byte)(value | (v ? 0b10 : 0b0));
return this;
}
public Status isSprinting(boolean v) {
value = (byte)(value | (v ? 0b1000 : 0b0));
return this;
}
public Status isSwimming(boolean v) {
value = (byte)(value | (v ? 0b10000 : 0b0));
return this;
}
public Status isInvisible(boolean v) {
value = (byte)(value | (v ? 0b100000 : 0b0));
return this;
}
public Status isGlowing(boolean v) {
value = (byte)(value | (v ? 0b1000000 : 0b0));
return this;
}
public Status isElytraFlying(boolean v) {
value = (byte)(value | (v ? 0b10000000 : 0b0));
return this;
}
}
@AllArgsConstructor
public static class AirTicks implements IntoEntityData {
@Override
public EntityData into() {
return new EntityData(
1,
EntityDataTypes.INT,
value
);
}
int value;
}
@AllArgsConstructor
public static class CustomName implements IntoEntityData {
@Override
public EntityData into() {
return new EntityData(
2,
EntityDataTypes.OPTIONAL_ADV_COMPONENT,
Optional.of(value)
);
}
Component value;
}
@AllArgsConstructor
public static class CustomNameVisible implements IntoEntityData {
@Override
public EntityData into() {
return new EntityData(
3,
EntityDataTypes.BOOLEAN,
value
);
}
boolean value;
}
@AllArgsConstructor
public static class Silent implements IntoEntityData {
@Override
public EntityData into() {
return new EntityData(
4,
EntityDataTypes.BOOLEAN,
value
);
}
boolean value;
}
@AllArgsConstructor
public static class NoGravity implements IntoEntityData {
@Override
public EntityData into() {
return new EntityData(
5,
EntityDataTypes.BOOLEAN,
value
);
}
boolean value;
}
}

View file

@ -0,0 +1,9 @@
package org.ef3d0c3e.sheepwars.packets;
import com.github.retrooper.packetevents.protocol.entity.data.EntityData;
import com.github.retrooper.packetevents.protocol.entity.data.EntityDataType;
import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
interface IntoEntityData {
EntityData into();
}

View file

@ -0,0 +1,86 @@
package org.ef3d0c3e.sheepwars.packets;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.events.PacketListener;
import org.ef3d0c3e.sheepwars.SheepWars;
import org.ef3d0c3e.sheepwars.events.WantsListen;
import org.reflections.Reflections;
import java.lang.reflect.InvocationTargetException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class PacketListenerFactory
{
static private HashSet<Class<? extends PacketListener>> registrable = new HashSet<>();
static private HashSet<PacketListener> registered = new HashSet<>();
public static void create() throws Exception
{
final Reflections refl = new Reflections("org.ef3d0c3e.sheepwars");
final Set<Class<? extends PacketListener>> classes = refl.getSubTypesOf(PacketListener.class);
for (final Class<? extends PacketListener> clz : classes)
{
if (clz.getAnnotation(WantsListen.class) == null)
continue;
registrable.add(clz);
}
}
/**
* Registers all listeners for current phase
* Unregisters uneeded listeners
* @param phase Current phase
*/
public static void update(final WantsListen.Target phase)
{
// Un register
for (Iterator<PacketListener> it = registered.iterator(); it.hasNext();)
{
final PacketListener listener = it.next();
final WantsListen.Target target = listener.getClass().getAnnotation(WantsListen.class).phase();
if (target.isCompatible(phase)) continue;
ProtocolLibrary.getProtocolManager().removePacketListener(listener);
it.remove();
SheepWars.debugMessage("Unregistered " + listener.getClass().getName());
}
// Register
for (final Class<? extends PacketListener> clz : registrable)
{
final WantsListen.Target target = clz.getAnnotation(WantsListen.class).phase();
if (!target.isCompatible(phase)) continue;
boolean shouldRegister = true;
// Check if not already registered
for (final PacketListener l : registered)
{
if (!l.getClass().equals(clz)) continue;
shouldRegister = false;
break;
}
if (!shouldRegister) continue;
try
{
final PacketListener l = clz.getDeclaredConstructor().newInstance();
registered.add(l);
ProtocolLibrary.getProtocolManager().addPacketListener(l);
SheepWars.debugMessage("Registered " + l.getClass().getName());
}
catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e)
{
e.printStackTrace();
}
}
}
}

View file

@ -0,0 +1,65 @@
package org.ef3d0c3e.sheepwars.packets;
import com.github.retrooper.packetevents.protocol.entity.data.EntityData;
import com.github.retrooper.packetevents.protocol.entity.data.EntityDataType;
import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
import lombok.Getter;
public class PlayerMetadata {
public static class SkinParts implements IntoEntityData {
@Override
public EntityData into() {
return new EntityData(
17,
EntityDataTypes.BYTE,
value
);
}
byte value;
public SkinParts() {
this.value = 0;
}
public SkinParts cape(boolean v) {
value = (byte)(value | (v ? 0b1 : 0b0));
return this;
}
public SkinParts jacket(boolean v) {
value = (byte)(value | (v ? 0b10 : 0b0));
return this;
}
public SkinParts leftSleeve(boolean v) {
value = (byte)(value | (v ? 0b100 : 0b0));
return this;
}
public SkinParts rightSleeve(boolean v) {
value = (byte)(value | (v ? 0b1000 : 0b0));
return this;
}
public SkinParts leftPants(boolean v) {
value = (byte)(value | (v ? 0b10000 : 0b0));
return this;
}
public SkinParts rightPants(boolean v) {
value = (byte)(value | (v ? 0b100000 : 0b0));
return this;
}
public SkinParts hat(boolean v) {
value = (byte)(value | (v ? 0b1000000 : 0b0));
return this;
}
public SkinParts all() {
value = (byte)0xFF;
return this;
}
}
}

View file

@ -42,7 +42,6 @@ public class WrapperFactory
{
// Build version string (e.g: "1.20.2" -> "1_20_R2")
final String bukkitVersion = Bukkit.getVersion();
Bukkit.getConsoleSender().sendMessage("version=" + bukkitVersion);
Matcher matcher = Pattern.compile("\\(MC: (?<version>\\d)\\.(?<major>\\d+)(?:\\.(?<minor>\\d+))?\\)").matcher(bukkitVersion);
if (!matcher.find()) throw new RuntimeException("Could not determine minecraft version from Bukkit version: `" + bukkitVersion + "`");
String version;

View file

@ -2,7 +2,7 @@ name: SheepWars
version: '2.0α'
main: org.ef3d0c3e.sheepwars.SheepWars
api-version: 1.21
depend: [ ProtocolLib, WorldEdit ]
depend: [ ProtocolLib, WorldEdit, packetevents ]
authors: [ ef3d0c3e ]
load: STARTUP
description: The SheepWars minigame, for free, forever

View file

@ -9,6 +9,14 @@
<artifactId>SheepWars-dist</artifactId>
<build>
<plugins>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<finalName>SheepWars</finalName>
<outputDirectory>/home/baraquiel/Programming/Minecraft/Sheepwars211/plugins</outputDirectory>
</configuration>
</plugin>
<plugin>
<artifactId>maven-shade-plugin</artifactId>
<version>3.6.0</version>
@ -22,21 +30,21 @@
</executions>
<configuration>
<relocations>
<relocation>
<pattern>com.github.retrooper.packetevents</pattern>
<shadedPattern>org.ef3d0c3e.lib.packetevents.api</shadedPattern>
</relocation>
<relocation>
<pattern>io.github.retrooper.packetevents</pattern>
<shadedPattern>org.ef3d0c3e.lib.packetevents.impl</shadedPattern>
</relocation>
<relocation>
<pattern>fr.mrmicky.fastboard</pattern>
<shadedPattern>org.ef3d0c3e.sheepwars.fastboard</shadedPattern>
<shadedPattern>org.ef3d0c3e.lib.fastboard</shadedPattern>
</relocation>
</relocations>
</configuration>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<finalName>SheepWars</finalName>
<outputDirectory>/home/baraquiel/Programming/Minecraft/Sheepwars211/plugins</outputDirectory>
</configuration>
</plugin>
</plugins>
</build>
</project>

32
dist/pom.xml vendored
View file

@ -13,6 +13,15 @@
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<finalName>SheepWars</finalName>
<outputDirectory>/home/baraquiel/Programming/Minecraft/Sheepwars211/plugins</outputDirectory>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
@ -27,22 +36,21 @@
</executions>
<configuration>
<relocations>
<relocation>
<pattern>com.github.retrooper.packetevents</pattern>
<shadedPattern>org.ef3d0c3e.lib.packetevents.api</shadedPattern>
</relocation>
<relocation>
<pattern>io.github.retrooper.packetevents</pattern>
<shadedPattern>org.ef3d0c3e.lib.packetevents.impl</shadedPattern>
</relocation>
<relocation>
<pattern>fr.mrmicky.fastboard</pattern>
<shadedPattern>org.ef3d0c3e.sheepwars.fastboard</shadedPattern>
<shadedPattern>org.ef3d0c3e.lib.fastboard</shadedPattern>
</relocation>
</relocations>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<finalName>SheepWars</finalName>
<outputDirectory>/home/baraquiel/Programming/Minecraft/Sheepwars211/plugins</outputDirectory>
</configuration>
</plugin>
</plugins>
</build>
@ -54,10 +62,10 @@
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<!-- 1.21.1 -->
<!-- 1.21.0 -->
<dependency>
<groupId>org.ef3d0c3e.sheepwars</groupId>
<artifactId>SheepWars-spigot-1.21.1</artifactId>
<artifactId>SheepWars-spigot-1.21.0</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>

10
pom.xml
View file

@ -12,7 +12,7 @@
<packaging>pom</packaging>
<modules>
<module>core</module>
<module>spigot-1.21.1</module>
<module>spigot-1.21.0</module>
<module>dist</module>
</modules>
@ -24,6 +24,10 @@
</properties>
<repositories>
<repository>
<id>codemc-releases</id>
<url>https://repo.codemc.io/repository/maven-snapshots/</url>
</repository>
<repository>
<id>central</id>
<url>https://repo1.maven.org/maven2/</url>
@ -36,10 +40,6 @@
<id>sonatype</id>
<url>https://oss.sonatype.org/content/groups/public/</url>
</repository>
<repository>
<id>lukasalt-repo</id>
<url>https://repo.lukasa.lt/repository/maven-public/</url>
</repository>
</repositories>
<dependencies>

View file

@ -10,7 +10,7 @@
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>SheepWars-spigot-1.21.1</artifactId>
<artifactId>SheepWars-spigot-1.21.0</artifactId>
<properties>
<java.version>22</java.version>

View file

@ -1,4 +1,4 @@
package org.ef3d0c3e.sheepwars.v1_21_R1;
package org.ef3d0c3e.sheepwars.v1_21_R0;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.events.PacketContainer;