mirror of
https://github.com/TotalFreedomMC/TF-PlotSquared.git
synced 2024-12-23 00:15:06 +00:00
Added:
Commands: Music Subcommand Flags: notify-enter notify-leave item-drop invincible instabreak drop-protection forcefield heal feed greeting farewell
This commit is contained in:
parent
13a2d4234b
commit
f6deb20483
7 changed files with 482 additions and 5 deletions
|
@ -16,6 +16,12 @@ import org.bukkit.ChatColor;
|
|||
* @author Citymonstret
|
||||
*/
|
||||
public enum C {
|
||||
/*
|
||||
* Records
|
||||
*/
|
||||
RECORD_PLAY("&c%player &cstarted playing record &6%name"),
|
||||
NOTIFY_ENTER("&c%player ¢ered your plot (&6%plot&c)"),
|
||||
NOTIFY_LEAVE("&c%player &left your plot (&6%plot&c)"),
|
||||
/*
|
||||
* Swap
|
||||
*/
|
||||
|
|
|
@ -16,9 +16,7 @@ import com.intellectualcrafters.plot.events.PlotDeleteEvent;
|
|||
import com.intellectualcrafters.plot.generator.DefaultPlotManager;
|
||||
import com.intellectualcrafters.plot.generator.DefaultPlotWorld;
|
||||
import com.intellectualcrafters.plot.generator.WorldGenerator;
|
||||
import com.intellectualcrafters.plot.listeners.PlayerEvents;
|
||||
import com.intellectualcrafters.plot.listeners.WorldEditListener;
|
||||
import com.intellectualcrafters.plot.listeners.WorldGuardListener;
|
||||
import com.intellectualcrafters.plot.listeners.*;
|
||||
import com.intellectualcrafters.plot.uuid.PlotUUIDSaver;
|
||||
import com.intellectualcrafters.plot.uuid.UUIDSaver;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
|
@ -680,7 +678,9 @@ public class PlotMain extends JavaPlugin {
|
|||
});
|
||||
|
||||
getServer().getPluginManager().registerEvents(new PlayerEvents(), this);
|
||||
|
||||
PlotPlusListener.startRunnable(this);
|
||||
getServer().getPluginManager().registerEvents(new PlotPlusListener(), this);
|
||||
getServer().getPluginManager().registerEvents(new ForceFieldListener(this), this);
|
||||
defaultFlags();
|
||||
|
||||
|
||||
|
@ -1282,7 +1282,98 @@ public class PlotMain extends JavaPlugin {
|
|||
booleanFlags.put(Material.DROPPER, "dropper");
|
||||
}
|
||||
|
||||
private static void addPlusFlags() {
|
||||
List<String> booleanFlags = Arrays.asList(
|
||||
"notify-enter",
|
||||
"notify-leave",
|
||||
"item-drop",
|
||||
"invincible",
|
||||
"instabreak",
|
||||
"drop-protection",
|
||||
"forcefield"
|
||||
);
|
||||
List<String> intervalFlags = Arrays.asList(
|
||||
"feed",
|
||||
"heal"
|
||||
);
|
||||
List<String> stringFlags = Arrays.asList(
|
||||
"greeting",
|
||||
"farewell"
|
||||
);
|
||||
for(String flag : stringFlags) {
|
||||
FlagManager.addFlag(new AbstractFlag(flag) {
|
||||
@Override
|
||||
public String parseValue(String value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValueDesc() {
|
||||
return "Value must be a string, supports color codes (&)";
|
||||
}
|
||||
});
|
||||
}
|
||||
for(String flag : intervalFlags) {
|
||||
FlagManager.addFlag(new AbstractFlag(flag) {
|
||||
@Override
|
||||
public String parseValue(String value) {
|
||||
int seconds;
|
||||
int amount;
|
||||
String[] values = value.split(" ");
|
||||
if (values.length < 2) {
|
||||
seconds = 1;
|
||||
try {
|
||||
amount = Integer.parseInt(values[0]);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
amount = Integer.parseInt(values[0]);
|
||||
seconds = Integer.parseInt(values[1]);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return amount + " " + seconds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValueDesc() {
|
||||
return "Value(s) must be numeric. /plot set flag {flag} {amount} [seconds]";
|
||||
}
|
||||
});
|
||||
}
|
||||
for(String flag : booleanFlags) {
|
||||
FlagManager.addFlag(new AbstractFlag(flag) {
|
||||
@Override
|
||||
public String parseValue(String value) {
|
||||
switch (value) {
|
||||
case "on":
|
||||
case "1":
|
||||
case "true":
|
||||
case "enabled":
|
||||
return "true";
|
||||
case "off":
|
||||
case "0":
|
||||
case "false":
|
||||
case "disabled":
|
||||
return "false";
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValueDesc() {
|
||||
return "Value must be true/false, 1/0, on/off, enabled/disabled";
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static void defaultFlags() {
|
||||
addPlusFlags();
|
||||
FlagManager.addFlag(new AbstractFlag("fly") {
|
||||
@Override
|
||||
public String parseValue(String value) {
|
||||
|
|
|
@ -30,7 +30,7 @@ public class MainCommand implements CommandExecutor {
|
|||
private static SubCommand[] _subCommands = new SubCommand[] { new Claim(), new Paste(), new Copy(), new Clipboard(), new Auto(), new Home(), new Visit(),
|
||||
new TP(), new Set(), new Clear(), new Delete(), new SetOwner(), new Denied(), new Helpers(), new Trusted(),
|
||||
new Info(), new list(), new Help(), new Debug(), new Schematic(), new plugin(), new Inventory(), new Purge(),
|
||||
new Reload(), new Merge(), new Unlink(), new Kick(), new Setup(), new DebugClaimTest(), new Inbox(), new Comment(), new Swap() };
|
||||
new Reload(), new Merge(), new Unlink(), new Kick(), new Setup(), new DebugClaimTest(), new Inbox(), new Comment(), new Swap(), new MusicSubcommand() };
|
||||
|
||||
public static ArrayList<SubCommand> subCommands = new ArrayList<SubCommand>() {
|
||||
{
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
package com.intellectualcrafters.plot.commands;
|
||||
|
||||
import com.intellectualcrafters.plot.C;
|
||||
import com.intellectualcrafters.plot.PlayerFunctions;
|
||||
import com.intellectualcrafters.plot.Plot;
|
||||
import com.intellectualcrafters.plot.listeners.PlotPlusListener;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
|
||||
import java.util.Arrays;
|
||||
public class MusicSubcommand extends SubCommand {
|
||||
public MusicSubcommand() {
|
||||
super("music", "plots.music", "Play music in plot", "music", "mus", CommandCategory.ACTIONS, true);
|
||||
}
|
||||
@Override
|
||||
public boolean execute(Player player, String... args) {
|
||||
if(!PlayerFunctions.isInPlot(player)) {
|
||||
sendMessage(player, C.NOT_IN_PLOT);
|
||||
return true;
|
||||
}
|
||||
Plot plot = PlayerFunctions.getCurrentPlot(player);
|
||||
if(!plot.hasRights(player)) {
|
||||
sendMessage(player, C.NO_PLOT_PERMS);
|
||||
return true;
|
||||
}
|
||||
org.bukkit.inventory.Inventory inventory = Bukkit.createInventory(null, 9, ChatColor.RED + "Plot Jukebox");
|
||||
for(PlotPlusListener.RecordMeta meta : PlotPlusListener.RecordMeta.metaList) {
|
||||
ItemStack stack = new ItemStack(meta.getMaterial());
|
||||
ItemMeta itemMeta = stack.getItemMeta();
|
||||
itemMeta.setDisplayName(ChatColor.GOLD + meta.toString());
|
||||
itemMeta.setLore(Arrays.asList(ChatColor.GRAY + "Click to play the record"));
|
||||
stack.setItemMeta(itemMeta);
|
||||
inventory.addItem(stack);
|
||||
}
|
||||
player.openInventory(inventory);
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
package com.intellectualcrafters.plot.listeners;
|
||||
|
||||
import com.intellectualcrafters.plot.PlayerFunctions;
|
||||
import com.intellectualcrafters.plot.Plot;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerMoveEvent;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
/**
|
||||
* Created by Citymonstret on 2014-10-24.
|
||||
*/
|
||||
public class ForceFieldListener implements Listener {
|
||||
|
||||
private JavaPlugin plugin;
|
||||
public ForceFieldListener(JavaPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
plugin.getServer().getPluginManager().registerEvents(this, plugin);
|
||||
}
|
||||
private Set<Player> getNearbyPlayers(Player player, Plot plot) {
|
||||
Set<Player> players = new HashSet<>();
|
||||
Player oPlayer = null;
|
||||
for(Entity entity : player.getNearbyEntities(5d, 5d, 5d)) {
|
||||
if(!(entity instanceof Player) || (oPlayer = (Player) entity) == null || !PlayerFunctions.isInPlot(oPlayer) || !PlayerFunctions.getCurrentPlot(oPlayer).equals(plot)) {
|
||||
continue;
|
||||
}
|
||||
if(!plot.hasRights(oPlayer))
|
||||
players.add(oPlayer);
|
||||
}
|
||||
return players;
|
||||
}
|
||||
private Player hasNearbyPermitted(Player player, Plot plot) {
|
||||
Player oPlayer = null;
|
||||
for(Entity entity : player.getNearbyEntities(5d, 5d, 5d)) {
|
||||
if(!(entity instanceof Player) || (oPlayer = (Player) entity) == null || !PlayerFunctions.isInPlot(oPlayer) || !PlayerFunctions.getCurrentPlot(oPlayer).equals(plot)) {
|
||||
continue;
|
||||
}
|
||||
if(plot.hasRights(oPlayer))
|
||||
return oPlayer;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public Vector calculateVelocity(Player p, Player e) {
|
||||
Location playerLocation = p.getLocation();
|
||||
Location oPlayerLocation = e.getLocation();
|
||||
double
|
||||
playerX = playerLocation.getX(),
|
||||
playerY = playerLocation.getY(),
|
||||
playerZ = playerLocation.getZ(),
|
||||
oPlayerX = oPlayerLocation.getX(),
|
||||
oPlayerY = oPlayerLocation.getY(),
|
||||
oPlayerZ = oPlayerLocation.getZ(),
|
||||
x = 0d, y = 0d, z = 0d;
|
||||
if(playerX < oPlayerX)
|
||||
x = 1.0d;
|
||||
else if(playerX > oPlayerX)
|
||||
x = -1.0d;
|
||||
if(playerY < oPlayerY)
|
||||
y = 0.5d;
|
||||
else if(playerY > oPlayerY)
|
||||
y = -0.5d;
|
||||
if(playerZ < oPlayerZ)
|
||||
z = 1.0d;
|
||||
else if(playerZ > oPlayerZ)
|
||||
z = -1.0d;
|
||||
return new Vector(x, y, z);
|
||||
}
|
||||
@EventHandler
|
||||
public void onPlotEntry(PlayerMoveEvent event){
|
||||
Player player = event.getPlayer();
|
||||
if(!PlayerFunctions.isInPlot(player))
|
||||
return;
|
||||
Plot plot = PlayerFunctions.getCurrentPlot(player);
|
||||
if(!PlotListener.booleanFlag(plot, "forcefield"))
|
||||
if(plot.hasRights(player)) {
|
||||
Set<Player> players = getNearbyPlayers(player, plot);
|
||||
for(Player oPlayer : players) {
|
||||
oPlayer.setVelocity(calculateVelocity(player, oPlayer));
|
||||
}
|
||||
} else {
|
||||
Player oPlayer = hasNearbyPermitted(player, plot);
|
||||
if(oPlayer == null) return;
|
||||
player.setVelocity(calculateVelocity(oPlayer, player));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -123,6 +123,27 @@ public class PlotListener {
|
|||
}
|
||||
}
|
||||
|
||||
public static boolean booleanFlag(Plot plot, String flag) {
|
||||
return plot.settings.getFlag(flag) != null && getBooleanFlag(plot.settings.getFlag(flag).getValue()).equals("true");
|
||||
}
|
||||
|
||||
private static String getBooleanFlag(String value) {
|
||||
switch(value) {
|
||||
case "on":
|
||||
case "1":
|
||||
case "true":
|
||||
case "enabled":
|
||||
return "true";
|
||||
case "off":
|
||||
case "0":
|
||||
case "false":
|
||||
case "disabled":
|
||||
return "false";
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static GameMode getGameMode(String str) {
|
||||
switch (str) {
|
||||
case "creative":
|
||||
|
|
|
@ -0,0 +1,226 @@
|
|||
package com.intellectualcrafters.plot.listeners;
|
||||
|
||||
import com.intellectualcrafters.plot.C;
|
||||
import com.intellectualcrafters.plot.PlayerFunctions;
|
||||
import com.intellectualcrafters.plot.Plot;
|
||||
import com.intellectualcrafters.plot.events.PlayerEnterPlotEvent;
|
||||
import com.intellectualcrafters.plot.events.PlayerLeavePlotEvent;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.BlockDamageEvent;
|
||||
import org.bukkit.event.entity.EntityDamageEvent;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.event.player.PlayerDropItemEvent;
|
||||
import org.bukkit.event.player.PlayerPickupItemEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Created by Citymonstret on 2014-10-30.
|
||||
*/
|
||||
public class PlotPlusListener extends PlotListener implements Listener {
|
||||
|
||||
private static HashMap<String, Interval> feedRunnable = new HashMap<>();
|
||||
private static HashMap<String, Interval> healRunnable = new HashMap<>();
|
||||
|
||||
public static void startRunnable(JavaPlugin plugin) {
|
||||
plugin.getServer().getScheduler().scheduleSyncRepeatingTask(plugin, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
for(Map.Entry<String, Interval> entry : feedRunnable.entrySet()) {
|
||||
Interval value = entry.getValue();
|
||||
++value.count;
|
||||
if(value.count == value.interval) {
|
||||
value.count = 0;
|
||||
Player player = Bukkit.getPlayer(entry.getKey());
|
||||
int level = player.getFoodLevel();
|
||||
if(level != value.max) {
|
||||
player.setFoodLevel(Math.min(level + value.amount, value.max));
|
||||
}
|
||||
}
|
||||
}
|
||||
for(Map.Entry<String, Interval> entry : healRunnable.entrySet()) {
|
||||
Interval value = entry.getValue();
|
||||
++value.count;
|
||||
if(value.count == value.interval) {
|
||||
value.count = 0;
|
||||
Player player = Bukkit.getPlayer(entry.getKey());
|
||||
double level = player.getHealth();
|
||||
if(level != value.max) {
|
||||
player.setHealth(Math.min(level + value.amount, value.max));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 0l, 20l);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onInventoryClick(InventoryClickEvent event) {
|
||||
Player player = (Player) event.getWhoClicked();
|
||||
if(!event.getInventory().getName().equals(ChatColor.RED + "Plot Jukebox"))
|
||||
return;
|
||||
event.setCancelled(true);
|
||||
if(!isInPlot(player)) {
|
||||
PlayerFunctions.sendMessage(player, C.NOT_IN_PLOT);
|
||||
return;
|
||||
}
|
||||
Plot plot = getPlot(player);
|
||||
if(!plot.hasRights(player)) {
|
||||
PlayerFunctions.sendMessage(player, C.NO_PLOT_PERMS);
|
||||
return;
|
||||
}
|
||||
Set<Player> plotPlayers = new HashSet<>();
|
||||
for(Player p : player.getWorld().getPlayers()) {
|
||||
if(isInPlot(p) && getPlot(p).equals(plot))
|
||||
plotPlayers.add(p);
|
||||
}
|
||||
RecordMeta meta = null;
|
||||
for(RecordMeta m : RecordMeta.metaList) {
|
||||
if(m.getMaterial() == event.getCurrentItem().getType()) {
|
||||
meta = m;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(meta == null)
|
||||
return;
|
||||
for(Player p : plotPlayers) {
|
||||
p.playEffect(p.getLocation(), Effect.RECORD_PLAY, meta.getMaterial());
|
||||
PlayerFunctions.sendMessage(p, C.RECORD_PLAY.s().replaceAll("%player", player.getName()).replaceAll("%name", meta.toString()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH)
|
||||
public void onInteract(BlockDamageEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
if(player.getGameMode() != GameMode.SURVIVAL) return;
|
||||
if(!isInPlot(player)) return;
|
||||
Plot plot = getPlot(player);
|
||||
if(booleanFlag(plot, "instabreak"))
|
||||
event.getBlock().breakNaturally();
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH)
|
||||
public void onDamage(EntityDamageEvent event) {
|
||||
if(event.getEntityType() != EntityType.PLAYER)
|
||||
return;
|
||||
Player player = (Player) event.getEntity();
|
||||
if(!isInPlot(player)) return;
|
||||
if(booleanFlag(getPlot(player), "invincible"))
|
||||
event.setCancelled(true);
|
||||
}
|
||||
|
||||
@EventHandler public void onItemPickup(PlayerPickupItemEvent event) { if(isInPlot(event.getPlayer()) && !getPlot(event.getPlayer()).hasRights(event.getPlayer()) && booleanFlag(getPlot(event.getPlayer()), "drop-protection")) event.setCancelled(true); }
|
||||
|
||||
@EventHandler public void onItemDrop(PlayerDropItemEvent event) { if(isInPlot(event.getPlayer()) && !getPlot(event.getPlayer()).hasRights(event.getPlayer()) && booleanFlag(getPlot(event.getPlayer()), "item-drop")) event.setCancelled(true);}
|
||||
|
||||
@EventHandler
|
||||
public void onPlotEnter(PlayerEnterPlotEvent event) {
|
||||
Plot plot = event.getPlot();
|
||||
if(plot.settings.getFlag("greeting") != null) {
|
||||
event.getPlayer().sendMessage(ChatColor.translateAlternateColorCodes('&', plot.settings.getFlag("greeting").getValue()));
|
||||
}
|
||||
if(booleanFlag(plot, "notify-enter")) {
|
||||
if(plot.hasOwner()) {
|
||||
Player player = Bukkit.getPlayer(plot.getOwner());
|
||||
if(player == null) return;
|
||||
if(player.getUniqueId().equals(event.getPlayer().getUniqueId()))
|
||||
return;
|
||||
if(player.isOnline()) {
|
||||
PlayerFunctions.sendMessage(player,
|
||||
C.NOTIFY_ENTER
|
||||
.s()
|
||||
.replace("%player", event.getPlayer().getName())
|
||||
.replace("%plot", plot.getId().toString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@EventHandler
|
||||
public void onPlayerQuit(PlayerQuitEvent event) {
|
||||
if (feedRunnable.containsKey(event.getPlayer().getName()) ) {
|
||||
feedRunnable.remove(event.getPlayer().getName());
|
||||
}
|
||||
if (healRunnable.containsKey(event.getPlayer().getName()) ) {
|
||||
healRunnable.remove(event.getPlayer().getName());
|
||||
}
|
||||
}
|
||||
@EventHandler
|
||||
public void onPlotLeave(PlayerLeavePlotEvent event) {
|
||||
event.getPlayer().playEffect(event.getPlayer().getLocation(), Effect.RECORD_PLAY, 0);
|
||||
Plot plot = event.getPlot();
|
||||
if(plot.settings.getFlag("farewell") != null) {
|
||||
event.getPlayer().sendMessage(ChatColor.translateAlternateColorCodes('&', plot.settings.getFlag("farewell").getValue()));
|
||||
}
|
||||
if (feedRunnable.containsKey(event.getPlayer().getName()) ) {
|
||||
feedRunnable.remove(event.getPlayer().getName());
|
||||
}
|
||||
if (healRunnable.containsKey(event.getPlayer().getName()) ) {
|
||||
healRunnable.remove(event.getPlayer().getName());
|
||||
}
|
||||
if(booleanFlag(plot, "notify-leave")) {
|
||||
if(plot.hasOwner()) {
|
||||
Player player = Bukkit.getPlayer(plot.getOwner());
|
||||
if(player == null) return;
|
||||
if(player.getUniqueId().equals(event.getPlayer().getUniqueId()))
|
||||
return;
|
||||
if(player.isOnline()) {
|
||||
PlayerFunctions.sendMessage(player,
|
||||
C.NOTIFY_LEAVE
|
||||
.s()
|
||||
.replace("%player", event.getPlayer().getName())
|
||||
.replace("%plot", plot.getId().toString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class Interval {
|
||||
public int interval;
|
||||
public int amount;
|
||||
public int count = 0;
|
||||
public int max;
|
||||
public Interval(int interval, int amount, int max) {
|
||||
this.interval = interval;
|
||||
this.amount = amount;
|
||||
this.max = max;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Created by Citymonstret on 2014-10-22.
|
||||
*/
|
||||
public static class RecordMeta {
|
||||
public static List<RecordMeta> metaList = new ArrayList<>();
|
||||
static {
|
||||
for(int x = 3; x < 12; x++) {
|
||||
metaList.add(
|
||||
new RecordMeta(
|
||||
x + "",
|
||||
Material.valueOf("RECORD_" + x)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
private String name;
|
||||
private Material material;
|
||||
public RecordMeta(String name, Material material) {
|
||||
this.name = name;
|
||||
this.material = material;
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.name;
|
||||
}
|
||||
public Material getMaterial() {
|
||||
return this.material;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue