Merge branch 'develop' of github.com:Mineplex-LLC/Minecraft-PC into update/basketball-game

This commit is contained in:
AlexTheCoder 2016-06-27 17:45:36 -04:00
commit ab315627ad
1076 changed files with 54843 additions and 16322 deletions

View File

@ -16,6 +16,10 @@
<groupId>com.mineplex</groupId>
<artifactId>spigot</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
</dependencies>
<build>

View File

@ -1,29 +1,40 @@
package mineplex.core.common;
import mineplex.core.common.util.C;
import org.bukkit.Material;
public enum CurrencyType
{
Tokens("Tokens", Material.EMERALD),
Coins("Treasure Shards", Material.PRISMARINE_SHARD),
Gems("Gems", Material.EMERALD),
Gold("Gold", Material.GOLD_NUGGET);
private String _prefix;
TOKEN("Tokens", "Token", C.cWhite, Material.EMERALD),
TREASURE_SHARD("Treasure Shards", "Treasure Shard", C.cAqua, Material.PRISMARINE_SHARD),
GEM("Gems", "Gem", C.cGreen, Material.EMERALD),
GOLD("Gold", "Gold", C.cGold, Material.GOLD_NUGGET);
private String _plural;
private String _single;
private String _color;
private Material _displayMaterial;
CurrencyType(String prefix, Material displayMaterial)
CurrencyType(String plural, String single, String color, Material displayMaterial)
{
_prefix = prefix;
_plural = plural;
_single = single;
_color = color;
_displayMaterial = displayMaterial;
}
public String Prefix()
@Deprecated
public String getPrefix()
{
return _prefix;
return _plural;
}
public String getString(int amount)
{
return _color + amount + " " + (amount == 1 ? _single : _plural);
}
public Material GetDisplayMaterial()
public Material getDisplayMaterial()
{
return _displayMaterial;
}

View File

@ -23,6 +23,16 @@ public class MaterialData
return new MaterialData(material, data);
}
public Material getMaterial()
{
return _material;
}
public byte getData()
{
return _data;
}
@Override
public boolean equals(Object o)
{

View File

@ -0,0 +1,48 @@
package mineplex.core.common;
import mineplex.core.common.block.schematic.Schematic;
import org.bukkit.Location;
import java.util.Comparator;
import java.util.Map;
import java.util.TreeMap;
/**
* Loads schematics based on an ordered input value. A good example of usage would be to load schematics in the
* ordering of a progress bar.
*
* @author Shaun Bennett
*/
public class SortedSchematicLoader<T>
{
private final TreeMap<T, Schematic> _schematicMap;
private final Location _pasteLocation;
private T _currentValue = null;
public SortedSchematicLoader(Location pasteLocation)
{
this(pasteLocation, null);
}
public SortedSchematicLoader(Location pasteLocation, Comparator<T> comparator)
{
_schematicMap = new TreeMap<>(comparator);
_pasteLocation = pasteLocation;
}
public void addSchematic(T minValue, Schematic schematic)
{
_schematicMap.put(minValue, schematic);
}
public void update(T value)
{
Map.Entry<T, Schematic> entry = _schematicMap.floorEntry(value);
if (entry != null && !entry.getKey().equals(_currentValue))
{
_currentValue = entry.getKey();
entry.getValue().paste(_pasteLocation, false);
}
}
}

View File

@ -0,0 +1,52 @@
package mineplex.core.common.animation;
import org.bukkit.util.Vector;
import java.util.Objects;
public class AnimationPoint
{
private final int _tick;
private final Vector _move;
private final Vector _dir;
public AnimationPoint(int tick, Vector move, Vector dir)
{
_tick = tick;
_move = move.clone();
_dir = dir.clone();
}
public Vector getMove()
{
return _move.clone();
}
public Vector getDirection()
{
return _dir.clone();
}
public int getTick()
{
return _tick;
}
@Override
public boolean equals(Object obj)
{
if(obj instanceof AnimationPoint) {
AnimationPoint point = (AnimationPoint) obj;
return point._tick == _tick && point._move.equals(_move);
}
return false;
}
@Override
public int hashCode()
{
return Objects.hash(_tick, _move);
}
}

View File

@ -0,0 +1,161 @@
package mineplex.core.common.animation;
import java.util.HashSet;
import java.util.PriorityQueue;
import java.util.Set;
import org.bukkit.Location;
import org.bukkit.plugin.Plugin;
import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.scheduler.BukkitTask;
import org.bukkit.util.Vector;
/**
* Self sufficient animator to animate task with steps using local vector logic
*/
public abstract class Animator
{
private final Plugin _plugin;
// private TreeSet<AnimationPoint> _points = new TreeSet<>((a, b) -> Integer.compare(a.getTick(), b.getTick()));
private Set<AnimationPoint> _points = new HashSet<>();
private PriorityQueue<AnimationPoint> _queue = new PriorityQueue<>((a, b) -> Integer.compare(a.getTick(), b.getTick()));
private AnimationPoint _prev;
private AnimationPoint _next;
private Location _baseLoc;
private int _tick = -1;
private boolean _repeat = false;
private BukkitTask _task;
public Animator(Plugin plugin)
{
_plugin = plugin;
}
public void addPoint(AnimationPoint point) {
_points.add(point);
}
public void removePoint(AnimationPoint point) {
_points.remove(point);
}
/**
* @return Returns a cloned list of the animator points for this instance.
*/
public Set<AnimationPoint> getSet() {
return new HashSet<AnimationPoint>(_points);
}
/**
* @return Returns the actual list of animator points used by this instance. As this is not a copy, editing this list will apply
* changes to the current instance.
*/
public Set<AnimationPoint> getSetRaw() {
return _points;
}
/**
* Start the animation at the given location. If the animator is already running then this call will be silently ignored.
* @param loc Location the animation will start relative too. The vector poitns will be added to relative to this location.
*/
public void start(Location loc)
{
if(isRunning()) return;
_queue.clear();
_queue.addAll(_points);
if(_queue.isEmpty()) return;
_baseLoc = loc.clone();
_next = _queue.peek();
_prev = new AnimationPoint(0, _next.getMove().clone(), _next.getDirection().clone());
_task = new BukkitRunnable()
{
public void run()
{
_tick++;
if(_next.getTick() < _tick)
{
_queue.remove();
_prev = _next;
_next = _queue.peek();
}
if(_queue.isEmpty())
{
if(_repeat)
{
Location clone = _baseLoc.clone();
stop();
start(clone);
}
else
{
finish(_baseLoc);
stop();
}
return;
}
Location prev = _baseLoc.clone().add(_prev.getMove());
Location next = _baseLoc.clone().add(_next.getMove());
prev.setDirection(_prev.getDirection());
double diff = ((double)_tick-_prev.getTick())/(_next.getTick()-_prev.getTick());
prev.add(next.clone().subtract(prev).toVector().multiply(diff));
Vector dirDiff = _next.getDirection().subtract(prev.getDirection());
dirDiff.multiply(diff);
prev.setDirection(prev.getDirection().add(dirDiff));
tick(prev);
}
}.runTaskTimer(_plugin, 0, 1);
}
public boolean isRunning()
{
return _task != null;
}
public void stop()
{
if(!isRunning()) return;
_task.cancel();
_task = null;
_tick = -1;
_baseLoc = null;
}
/**
* @return Returns true if the animation should repeat.
* @see #setRepeat(boolean)
*/
public boolean isRepeat()
{
return _repeat;
}
/**
* If the last animation point does not make the animation end up at the exact same location as the start
* then it might lead to unexpected results as it will re-start the animation from the end of the animation.
*/
public void setRepeat(boolean repeat)
{
_repeat = repeat;
}
protected abstract void tick(Location loc);
protected abstract void finish(Location loc);
}

View File

@ -0,0 +1,39 @@
package mineplex.core.common.animation;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.bukkit.plugin.Plugin;
import org.bukkit.util.Vector;
/**
* An implementation of the {@link Animator} which will teleport the provided entity along the animation path each tick.
*/
public class AnimatorEntity extends Animator
{
private final Entity _ent;
public AnimatorEntity(Plugin plugin, Entity ent)
{
super(plugin);
_ent = ent;
}
@Override
protected void tick(Location loc)
{
if(!_ent.isValid())
{
stop();
return;
}
_ent.setVelocity(new Vector(0,0,0));
_ent.teleport(loc);
}
@Override
protected void finish(Location loc) {}
}

View File

@ -0,0 +1,34 @@
package mineplex.core.common.api;
import com.google.gson.Gson;
/**
* @author Shaun Bennett
*/
public class ApiEndpoint
{
private static final String API_HOST = "10.33.53.12";
// private static final String API_HOST = "localhost";
// private static final int API_PORT = 3000;
private static final int API_PORT = 7979;
private Gson _gson;
private ApiWebCall _webCall;
public ApiEndpoint(String path, Gson gson)
{
String url = "http://" + API_HOST + ":" + API_PORT + path;
_webCall = new ApiWebCall(url, gson);
_gson = gson;
}
protected ApiWebCall getWebCall()
{
return _webCall;
}
public Gson getGson()
{
return _gson;
}
}

View File

@ -0,0 +1,17 @@
package mineplex.core.common.api;
import com.google.gson.FieldNamingStrategy;
import java.lang.reflect.Field;
/**
* @author Shaun Bennett
*/
public class ApiFieldNamingStrategy implements FieldNamingStrategy
{
@Override
public String translateName(Field field)
{
return (field.getName().startsWith("_") ? field.getName().substring(1) : field.getName());
}
}

View File

@ -0,0 +1,50 @@
package mineplex.core.common.api;
import java.util.Date;
/**
* @author Shaun Bennett
*/
public class ApiResponse implements HttpStatusCode
{
// These do not have _ prefix because of gson. Please do not add underscores!
private int statusCode;
private boolean success;
private String error;
public ApiResponse()
{
}
public boolean isSuccess()
{
return success;
}
public String getError()
{
return error;
}
@Override
public String toString()
{
return "ApiResponse{" +
"success=" + success +
", error='" + error + '\'' +
'}';
}
@Override
public int getStatusCode()
{
return statusCode;
}
@Override
public void setStatusCode(int statusCode)
{
this.statusCode = statusCode;
}
}

View File

@ -0,0 +1,102 @@
package mineplex.core.common.api;
import com.google.gson.Gson;
import org.apache.http.HttpEntity;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicHeader;
import org.apache.http.protocol.HTTP;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Type;
/**
* @author Shaun Bennett
*/
public class ApiWebCall
{
private String _url;
private Gson _gson;
private PoolingHttpClientConnectionManager _cm;
private CloseableHttpClient _httpClient;
public ApiWebCall(String url, Gson gson)
{
_url = url;
_gson = gson;
_cm = new PoolingHttpClientConnectionManager();
_cm.setMaxTotal(200);
_cm.setDefaultMaxPerRoute(20);
_httpClient = HttpClients.custom().setConnectionManager(_cm).build();
}
public <T> T get(String resource, Class<T> clazz)
{
return get(resource, (Type)clazz);
}
public <T> T get(String resource, Type type)
{
T returnData = null;
HttpGet httpGet = new HttpGet(_url + resource);
try (CloseableHttpResponse response = _httpClient.execute(httpGet)) {
returnData = parseResponse(response, type);
} catch (IOException e)
{
e.printStackTrace();
}
return returnData;
}
public <T> T post(String resource, Class<T> clazz, Object data)
{
T returnData = null;
HttpPost httpPost = new HttpPost(_url + resource);
try
{
if (data != null)
{
StringEntity params = new StringEntity(_gson.toJson(data));
params.setContentType(new BasicHeader(HTTP.CONTENT_TYPE, "application/json"));
httpPost.setEntity(params);
}
try (CloseableHttpResponse response = _httpClient.execute(httpPost))
{
returnData = parseResponse(response, clazz);
} catch (IOException e)
{
e.printStackTrace();
}
} catch (UnsupportedEncodingException e)
{
e.printStackTrace();
}
return returnData;
}
private <T> T parseResponse(CloseableHttpResponse response, Type type) throws IOException
{
HttpEntity entity = response.getEntity();
T parsed = _gson.fromJson(new InputStreamReader(entity.getContent()), type);
if (parsed instanceof HttpStatusCode && response.getStatusLine() != null)
{
((HttpStatusCode) parsed).setStatusCode(response.getStatusLine().getStatusCode());
}
return parsed;
}
}

View File

@ -0,0 +1,12 @@
package mineplex.core.common.api;
/**
* Interface used to also grab status code from ApiWebCall
* @author Shaun Bennett
*/
public interface HttpStatusCode
{
public int getStatusCode();
public void setStatusCode(int statusCode);
}

View File

@ -0,0 +1,36 @@
package mineplex.core.common.api;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
/**
* @author Shaun Bennett
*/
public class ListResponseType<Data> implements ParameterizedType
{
private Class<Data> _wrapped;
public ListResponseType(Class<Data> wrapped)
{
_wrapped = wrapped;
}
@Override
public Type[] getActualTypeArguments()
{
return new Type[] { _wrapped };
}
@Override
public Type getRawType()
{
return List.class;
}
@Override
public Type getOwnerType()
{
return null;
}
}

View File

@ -0,0 +1,126 @@
package mineplex.core.common.block;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.bukkit.Bukkit;
import org.bukkit.block.Block;
import org.bukkit.craftbukkit.v1_8_R3.CraftChunk;
import org.bukkit.entity.Player;
import org.bukkit.util.BlockVector;
import mineplex.core.common.util.MapUtil;
import mineplex.core.common.util.UtilPlayer;
import mineplex.core.common.util.UtilServer;
import net.minecraft.server.v1_8_R3.Chunk;
import net.minecraft.server.v1_8_R3.ChunkCoordIntPair;
import net.minecraft.server.v1_8_R3.PacketPlayOutMultiBlockChange;
import net.minecraft.server.v1_8_R3.PacketPlayOutMultiBlockChange.MultiBlockChangeInfo;
/**
* An agent used to easily record and send multi-block update packets to players. The agent handles if the packet should be a
* MultiBlock packet or a chunk update. It also supports blocks across multiple chunks.
*/
public class MultiBlockUpdaterAgent
{
private Map<Chunk, List<BlockVector>> _chunks = new HashMap<>();
/**
* Add a block to the list of blocks to send to the player. The agent supports blocks across different chunks and
* will not send duplicates.
* @param block The block to send. The block is stored using a BlockVector, meaning that when the send method is called, it will use
* the material and data found for the block at the moment you call the send method.
* @see #send(Collection)
*/
public void addBlock(Block block)
{
Chunk c = ((CraftChunk)block.getChunk()).getHandle();
List<BlockVector> list = _chunks.computeIfAbsent(c,chunk -> new ArrayList<>());
if(list.size() >= 64) return;
BlockVector bv = block.getLocation().toVector().toBlockVector();
if(list.contains(bv)) return;
list.add(bv);
}
/**
* Sends all the record blocks to all online players. Players out of range will not receive packets.
* @see #send(Collection)
*/
public void send()
{
send(UtilServer.getPlayersCollection());
}
/**
* Clear all blocks for this agent.
*/
public void reset()
{
_chunks.clear();
}
/**
* Send all the recorded blocks to the provided players. This will only send packets to players in range. If the blocks span multiple
* chunks then players will only receive block updates for chunks close to them.
* @param players The players which will the packets will be sent to.
*/
public void send(Collection<? extends Player> players)
{
for(Player p : players)
{
for(Chunk c : _chunks.keySet())
{
if(!p.getWorld().equals(c.bukkitChunk.getWorld())) continue;
int x = p.getLocation().getChunk().getX();
int z = p.getLocation().getChunk().getZ();
int chunkDist = Math.max(Math.abs(c.locX-x), Math.abs(c.locZ-z));
if(chunkDist > Bukkit.getViewDistance()) continue;
sendPacket(c, players);
}
}
}
private void sendPacket(Chunk c, Collection<? extends Player> players)
{
List<BlockVector> list = _chunks.get(c);
if(list == null) return;
if(list.size() >= 64)
{
for(Player p : players)
{
MapUtil.SendChunkForPlayer(c, p);
}
}
else
{
PacketPlayOutMultiBlockChange packet = new PacketPlayOutMultiBlockChange();
packet.a = new ChunkCoordIntPair(c.locX, c.locZ);
packet.b = new MultiBlockChangeInfo[list.size()];
for(int i = 0; i < list.size(); i++)
{
BlockVector bv = list.get(i);
short xyz = (short)((bv.getBlockX() & 0xF) << 12 | (bv.getBlockZ() & 0xF) << 8 | bv.getBlockY());
packet.b[i] = packet.new MultiBlockChangeInfo(xyz, c);
}
for(Player p : players)
{
UtilPlayer.sendPacket(p, packet);
}
}
}
}

View File

@ -3,6 +3,9 @@ package mineplex.core.common.block.schematic;
import org.bukkit.DyeColor;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.util.Vector;
import com.mysql.jdbc.Util;
import mineplex.core.common.block.DataLocationMap;
import mineplex.core.common.util.UtilBlock;
@ -14,23 +17,46 @@ public class Schematic
private final short _length;
private final short[] _blocks;
private final byte[] _blockData;
private final Vector _weOffset;
public Schematic(short width, short height, short length, short[] blocks, byte[] blockData)
public Schematic(short width, short height, short length, short[] blocks, byte[] blockData, Vector worldEditOffset)
{
_width = width;
_height = height;
_length = length;
_blocks = blocks;
_blockData = blockData;
_weOffset = worldEditOffset;
}
public Schematic(short width, short height, short length, short[] blocks, byte[] blockData)
{
this(width, height, length, blocks, blockData, null);
}
public DataLocationMap paste(Location originLocation)
{
return paste(originLocation, false);
}
public DataLocationMap paste(Location originLocation, boolean ignoreAir)
{
return paste(originLocation, ignoreAir, false);
}
public DataLocationMap paste(Location originLocation, boolean ignoreAir, boolean worldEditOffset)
{
if(worldEditOffset && hasWorldEditOffset())
{
originLocation = originLocation.clone().add(_weOffset);
}
DataLocationMap locationMap = new DataLocationMap();
int startX = originLocation.getBlockX();
int startY = originLocation.getBlockY();
int startZ = originLocation.getBlockZ();
UtilBlock.startQuickRecording();
for (int x = 0; x < _width; x++)
{
@ -86,6 +112,8 @@ public class Schematic
}
}
}
UtilBlock.stopQuickRecording();
return locationMap;
}
@ -141,6 +169,11 @@ public class Schematic
}
return false;
}
public boolean hasWorldEditOffset()
{
return _weOffset != null;
}
public int getSize()
{

View File

@ -6,8 +6,11 @@ import java.io.IOException;
import java.util.Map;
import java.util.zip.GZIPInputStream;
import org.bukkit.util.Vector;
import com.java.sk89q.jnbt.ByteArrayTag;
import com.java.sk89q.jnbt.CompoundTag;
import com.java.sk89q.jnbt.IntTag;
import com.java.sk89q.jnbt.NBTInputStream;
import com.java.sk89q.jnbt.NamedTag;
import com.java.sk89q.jnbt.ShortTag;
@ -36,6 +39,15 @@ public class UtilSchematic
byte[] addId = new byte[0];
short[] blocks = new short[blockId.length];
byte[] blockData = getChildTag(schematic, "Data", ByteArrayTag.class).getValue();
Vector weOffset = null;
if(schematic.containsKey("WEOffsetX") && schematic.containsKey("WEOffsetY") && schematic.containsKey("WEOffsetZ"))
{
int x = getChildTag(schematic, "WEOffsetX", IntTag.class).getValue();
int y = getChildTag(schematic, "WEOffsetY", IntTag.class).getValue();
int z = getChildTag(schematic, "WEOffsetZ", IntTag.class).getValue();
weOffset = new Vector(x, y, z);
}
if (schematic.containsKey("AddBlocks"))
{
@ -56,7 +68,7 @@ public class UtilSchematic
}
return new Schematic(width, height, length, blocks, blockData);
return new Schematic(width, height, length, blocks, blockData, weOffset);
}

View File

@ -0,0 +1,16 @@
package mineplex.core.common.shape;
import org.bukkit.Location;
/**
* Interface used by classes which can display visuals at provided locations.
*/
public interface CosmeticShape
{
/**
* Display a visual at the given location
* @param loc The location to display the visual at
*/
void display(Location loc);
}

View File

@ -0,0 +1,189 @@
package mineplex.core.common.shape;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.bukkit.util.Vector;
/**
* A simple 3D vector stored shape
*/
public class Shape
{
protected final static double DEFAULT_DENSITY = 1;
protected HashSet<Vector> _points = new HashSet<>();
public Shape(){}
public Shape(Collection<Vector> points){
this._points.addAll(points);
}
/**
* Rotate this shape along the X-axis
* @param radians Radians to rotate the shape
*/
public void rotateOnXAxis(double radians)
{
for(Vector v : _points)
{
double y = v.getY();
double z = v.getZ();
v.setY(y * Math.cos(radians) - z * Math.sin(radians));
v.setZ(y * Math.sin(radians) + z * Math.cos(radians));
}
}
/**
* Rotate this shape along the Y-axis
* @param radians Radians to rotate the shape
*/
public void rotateOnYAxis(double radians)
{
for(Vector v : _points)
{
double x = v.getX();
double z = v.getZ();
v.setX(x * Math.cos(radians) - z * Math.sin(radians));
v.setZ(x * Math.sin(radians) + z * Math.cos(radians));
}
}
/**
* Rotate this shape along the Z-axis
* @param radians Radians to rotate the shape
*/
public void rotateOnZAxis(double radians)
{
for(Vector v : _points)
{
double x = v.getX();
double y = v.getY();
v.setX(x * Math.cos(radians) - y * Math.sin(radians));
v.setY(x * Math.sin(radians) + y * Math.cos(radians));
}
}
/**
* Offsets all the points based on the given vector
* @param v
*/
public void add(Vector v)
{
for(Vector p : _points) p.add(v);
}
public void addPoint(Vector v)
{
_points.add(v);
}
public boolean removePoint(Vector v)
{
return _points.remove(v);
}
public Set<Vector> getPoints()
{
return new HashSet<>(_points);
}
/**
* Multiply all the points by m.
* If m > 1 then the shape will become larger.
* If m < 1 then the shape will become smaller.
* If m = 1 then the shape will stay the same.
* If m < 0 then the shape will become inverted.
* @param m
*/
public void multiply(double m)
{
for(Vector v : _points) v.multiply(m);
}
public Shape clone() {
List<Vector> list = new ArrayList<>();
for(Vector p : _points)
{
list.add(p.clone());
}
return new Shape(list);
}
public Vector getMidPoint()
{
return getMaxAABBCorner().subtract(getMinAABBCorner()).multiply(0.5);
}
public Vector getMaxAABBCorner()
{
Vector max = null;
for(Vector v : _points)
{
if(max == null)
{
max = v.clone();
continue;
}
if(v.getX() > max.getX()) max.setX(v.getX());
if(v.getY() > max.getY()) max.setY(v.getY());
if(v.getZ() > max.getZ()) max.setZ(v.getZ());
}
return max;
}
public Vector getMinAABBCorner()
{
Vector min = null;
for(Vector v : _points)
{
if(min == null)
{
min = v.clone();
continue;
}
if(v.getX() < min.getX()) min.setX(v.getX());
if(v.getY() < min.getY()) min.setY(v.getY());
if(v.getZ() < min.getZ()) min.setZ(v.getZ());
}
return min;
}
/**
* Get the closest length which will be a factor of the provided length, but not longer then max
* E.g. You want to split a length of 9 into even peaces, but the peaces should not be longer than the max 5, then this will
* return 4.5, as 4.5 goes 2 times to make up precisely 9.
* @param length The length which the returned factor should fit into
* @param max The max distance of the returned length
* @return The closest to length to be a factor of the provided length which is <= max
*/
public static double getRoundFactor(double length, double max)
{
return length/Math.ceil(length/max);
}
/**
* Get the closest RoundFactor length applied to a vector, using the vector as the max length. The returned vector is a cloned
* parallel vector to the provided length
* @param length The vector used as length and direction
* @param maxLength The max length of the new returned vector
* @return Returns a parallel vector to the given length vector which is also a factor of the provided vector, but not longer
* then maxLength
*
* @see #getRoundFactor(double, double)
*/
public static Vector getVectorFactor(Vector length, double maxLength)
{
return length.clone().multiply(getRoundFactor(length.length(), maxLength));
}
}

View File

@ -0,0 +1,71 @@
package mineplex.core.common.shape;
import org.bukkit.util.Vector;
/**
* An extension of {@link Shape} creating a simple box
*/
public class ShapeBox extends Shape
{
/**
* Define a parallelepiped using three vectors using default density {@link Shape#DefaultDensity} and is not hollow
* @param localx The first vector to use as local x direction, does not have to align to global x direction
* @param localy The second vector to use as local y direction, does not have to align to global y direction
* @param localz The third vector to use as local z direction, does not have to align to global z direction
*/
public ShapeBox(Vector localx, Vector localy, Vector localz)
{
this(localx, localy, localz, false, DEFAULT_DENSITY);
}
/**
* Define a parallelepiped using three vectors using default density {@link Shape#DefaultDensity}
* @param localx The first vector to use as local x direction, does not have to align to global x direction
* @param localy The second vector to use as local y direction, does not have to align to global y direction
* @param localz The third vector to use as local z direction, does not have to align to global z direction
* @param hollow If the parallelepiped box should be hollow or not
*/
public ShapeBox(Vector localx, Vector localy, Vector localz, boolean hollow)
{
this(localx, localy, localz, hollow, DEFAULT_DENSITY);
}
/**
* Define a parallelepiped using three vectors
* @param localx The first vector to use as local x direction, does not have to align to global x direction
* @param localy The second vector to use as local y direction, does not have to align to global y direction
* @param localz The third vector to use as local z direction, does not have to align to global z direction
* @param hollow If the parallelepiped box should be hollow or not
* @param density The density of the vector points
*/
public ShapeBox(Vector localx, Vector localy, Vector localz, boolean hollow, double density)
{
Vector x = Shape.getVectorFactor(localx, density);
Vector y = Shape.getVectorFactor(localx, density);
Vector z = Shape.getVectorFactor(localx, density);
int xm = (int) Math.sqrt(localx.lengthSquared()/x.lengthSquared());
int ym = (int) Math.sqrt(localy.lengthSquared()/y.lengthSquared());
int zm = (int) Math.sqrt(localz.lengthSquared()/z.lengthSquared());
for(int ix = 0; ix < xm; ix++)
{
for(int iy = 0; iy < ym; iy++)
{
for(int iz = 0; iz < zm; iz++)
{
if(hollow)
{
if(!(ix == 0 || ix == xm-1 || iy == 0 || iy == ym-1 || iz == 0 || iz == zm-1)) continue;
}
_points.add(x.clone().multiply(ix).add(y.clone().multiply(iy)).add(z.clone().multiply(iz)));
}
}
}
}
}

View File

@ -0,0 +1,64 @@
package mineplex.core.common.shape;
import org.bukkit.util.Vector;
/**
* A simple grid shape which uses string inputs to define points
*/
public class ShapeGrid extends Shape
{
/**
* Each string in the array represents a layer on the XY-plane, meaning the layers moves towards positive Z.
* Each line in the string represents a line on parallel with the X-axis, where the first line is on the top of the shape.
* Use '#' for each point and anything else for each "non-point".
* The finished shape will then be centered afterwards.
*/
public ShapeGrid(String... input)
{
this(DEFAULT_DENSITY, '#', input);
}
/**
* Each string in the array represents a layer on the XY-plane, meaning the layers moves towards positive Z.
* Each line in the string represents a line on parallel with the X-axis, where the first line is on the top of the shape.
* Use the <code>read</code> char for each point and anything else for each "non-point".
* The finished shape will then be centered afterwards.
*/
public ShapeGrid(char read, String...input)
{
this(DEFAULT_DENSITY, read, input);
}
/**
* Each string in the array represents a layer on the XY-plane, meaning the layers moves towards positive Z.
* Each line in the string represents a line on parallel with the X-axis.
* Use the <code>read</code> char for each point and anything else for each "non-point".
* The finished shape will then be centered afterwards.
*/
public ShapeGrid(double density, char read, String...input)
{
int lx = 0;
int ly = 0;
int lz = 0;
for(int y = 0; y < input.length; y++)
{
String[] lines = input[y].split("\n");
for(int z = 0; z < lines.length; z++)
{
String line = lines[z];
for(int x = 0; x < line.length(); x++)
{
if(line.charAt(x) == read) addPoint(new Vector(-x,-y+input.length,-z).multiply(density));
if(x > lx) lx = x;
if(-y+input.length > ly) ly = -y+input.length;
if(z > lz) lz= z;
}
}
}
add(new Vector(-lx,ly,-lz).multiply(-0.5*density));
}
}

View File

@ -0,0 +1,38 @@
package mineplex.core.common.shape;
import java.util.Collection;
import org.bukkit.util.Vector;
/**
* A bag collection of several shapes. This will add all the points from the given shapes into a new shape
*/
public class ShapeMulti extends Shape
{
/**
* @param shapes Shapes which points will be added to this instance of a shape
*/
public ShapeMulti(Collection<Shape> shapes)
{
for(Shape shape : shapes) addShape(shape);
}
/**
* @param shapes Shapes which points will be added to this instance of a shape
*/
public ShapeMulti(Shape... shapes)
{
for(Shape shape : shapes) addShape(shape);
}
/**
* Add all the points from the given shape to this shape
* @param shape
*/
public void addShape(Shape shape) {
for(Vector v : shape._points) add(v);
}
}

View File

@ -0,0 +1,67 @@
package mineplex.core.common.shape;
import org.bukkit.util.Vector;
/**
* A simple sphere defined using vector points extending {@link Shape}
*/
public class ShapeSphere extends Shape
{
/**
* Define a sphere with radius r that is not hollow and using default density {@link Shape#DefaultDensity}
* @param r Radius for the sphere
*/
public ShapeSphere(double r)
{
this(r,r,r);
}
/**
* A sphere with different radiuses on different planes that is not hollow and using default density {@link Shape#DefaultDensity}
* @param x Radius in x direction
* @param y Radius in y direction
* @param z Radius in z direction
*/
public ShapeSphere(double x, double y, double z)
{
this(x, y, z, false, DEFAULT_DENSITY);
}
/**
* A sphere with different radiuses on different planes using default density {@link Shape#DefaultDensity}
* @param x Radius in x direction
* @param y Radius in y direction
* @param z Radius in z direction
* @param hollow If the sphere should be hollow or not
*/
public ShapeSphere(double x, double y, double z, boolean hollow)
{
this(x, y, z, hollow, DEFAULT_DENSITY);
}
/**
* A sphere with different radiuses on different planes
* @param x Radius in x direction
* @param y Radius in y direction
* @param z Radius in z direction
* @param hollow If the sphere should be hollow or not
* @param density Density between points
*/
public ShapeSphere(double x, double y, double z, boolean hollow, double density)
{
for(double px = -x; px <= x; x += Shape.getRoundFactor(2*x, density))
{
for(double py = -y; py <= y; y += Shape.getRoundFactor(2*y, density))
{
for(double pz = -z; pz <= z; z += Shape.getRoundFactor(2*z, density))
{
if( hollow && px*px/x*x + py*py/y*y + pz*pz/z*z == 1) _points.add(new Vector(px,py,pz));
else if(!hollow && px*px/x*x + py*py/y*y + pz*pz/z*z <= 1) _points.add(new Vector(px,py,pz));
}
}
}
}
}

View File

@ -0,0 +1,173 @@
package mineplex.core.common.shape;
import org.bukkit.Location;
import org.bukkit.util.Vector;
import mineplex.core.common.util.UtilParticle;
import mineplex.core.common.util.UtilParticle.ParticleType;
import mineplex.core.common.util.UtilParticle.ViewDist;
/**
* Some simple wing shapes implementing {@link ICosmeticShape} storing additional particle information
*/
public class ShapeWings extends ShapeGrid implements CosmeticShape
{
public static final String[] ANGEL_WING_PATTERN = new String[]
{
"000$$0000000000$$000",
"00$##$00000000$##$00",
"0$####$000000$####$0",
"$#####$000000$#####$",
"$#####$000000$#####$",
"$######$0000$######$",
"$######$0000$######$",
"$######$0000$######$",
"$######$$$$$$######$",
"$##################$",
"0$################$0",
"00$####$$$$$$####$00",
"00$####$0000$####$00",
"000$##$000000$##$000",
"000$##$000000$##$000",
"000$#$00000000$#$000",
"00$#$0000000000$#$00",
"00$#$0000000000$#$00",
"000$000000000000$000",
};
public static final String[] BUTTERFLY_WING_PATTERN = new String[]
{
"0$$0000000000000000$$0",
"$##$00000000000000$##$",
"0$##$000000000000$##$0",
"00$##$0000000000$##$00",
"00$###$00000000$###$00",
"000$####$0000$####$000",
"000$######$$#####$0000",
"0000$############$0000",
"00000$##########$00000",
"00000$##########$00000",
"00000$####$$$###$00000",
"00000$###$000$###$0000",
"00000$##$00000$##$0000",
"000000$000000000$00000"
};
/**
* Default rotation to give the wings a little tilt when displayed on players for instance
*/
public static double DEFAULT_ROTATION = Math.PI/0.05;
private String _particle;
private Vector _offsetData;
private float _speed;
private int _count;
/**
* A simple non-edge wing shape using the default butterfly pattern {@link ShapeWings#BUTTERFLY_WING_PATTERN}
* and x-rotation {@link #DEFAULT_ROTATION}. It also uses default redstone dust particle with offset of 0, speed of 0 and count 1
*/
public ShapeWings()
{
this(ParticleType.RED_DUST.particleName);
}
/**
* A simple non-edge wing shape using the default butterfly pattern {@link ShapeWings#BUTTERFLY_WING_PATTERN}
* and x-rotation {@link #DEFAULT_ROTATION}
* @param particle The particle to display at each point in the wing shape. Using offset of 0, speed of 0 and count 1
*/
public ShapeWings(String particle)
{
this(particle, null, 0, 1);
}
/**
* A simple non-edge wing shape using the default butterfly pattern {@link ShapeWings#BUTTERFLY_WING_PATTERN}
* and x-rotation {@link #DEFAULT_ROTATION}
* @param particle The particle to display at each point in the wing shape
* @param offsetData Particle data
* @param speed Particle speed
* @param count Particle count
*/
public ShapeWings(String particle, Vector offsetData, float speed, int count)
{
this(particle, offsetData, speed, count, false);
}
/**
* A simple wing shape using the default butterfly pattern {@link ShapeWings#BUTTERFLY_WING_PATTERN}
* and x-rotation {@link #DEFAULT_ROTATION}
* @param particle The particle to display at each point in the wing shape
* @param offsetData Particle data
* @param speed Particle speed
* @param count Particle count
* @param edge If this is the edge of the wings or not
*/
public ShapeWings(String particle, Vector offsetData, float speed, int count, boolean edge)
{
this(particle, offsetData, speed, count, edge, DEFAULT_ROTATION);
}
/**
* A simple wing shape using the default butterfly pattern {@link ShapeWings#BUTTERFLY_WING_PATTERN}
* @param particle The particle to display at each point in the wing shape
* @param offsetData Particle data
* @param speed Particle speed
* @param count Particle count
* @param edge If this is the edge of the wings or not
* @param xRotation Rotation on the x axis
*/
public ShapeWings(String particle, Vector offsetData, float speed, int count, boolean edge, double xRotation)
{
this(particle, offsetData, speed, count, edge, xRotation, BUTTERFLY_WING_PATTERN);
}
/**
* A simple wing shape
* @param particle The particle to display at each point in the wing shape
* @param offsetData Particle data
* @param speed Particle speed
* @param count Particle count
* @param edge If this is the edge of the wings or not
* @param xRotation Rotation on the x axis
* @param pattern Pattern to use as wing shape
*/
public ShapeWings(String particle, Vector offsetData, float speed, int count, boolean edge, double xRotation, String... pattern)
{
super(0.15, edge? '$' : '#',
pattern
);
_particle = particle;
_offsetData = offsetData;
_speed = speed;
_count = count;
rotateOnXAxis(xRotation);
}
@Override
public void display(Location loc)
{
Shape clone = clone();
clone.rotateOnYAxis(Math.toRadians(loc.getYaw()));
for(Vector v : clone._points)
{
Location ploc = loc.clone().add(v);
displayParticle(ploc);
}
}
/**
* Display a single particle of the type provided to this shape at the given location.
*/
public void displayParticle(Location loc)
{
UtilParticle.PlayParticleToAll(_particle, loc, _offsetData, _speed, _count, ViewDist.NORMAL);
}
}

View File

@ -19,21 +19,27 @@ import net.minecraft.server.v1_8_R3.NBTTagString;
public class SkinData
{
private static long _nameCount = -99999999999999L;
public final static SkinData MOOSHROOM = new SkinData("eyJ0aW1lc3RhbXAiOjE0NDk4NzI0OTU0MTcsInByb2ZpbGVJZCI6ImE5ZDBjMDcyYmYxOTQwYTFhMTkzNjhkMDlkNTAwMjZlIiwicHJvZmlsZU5hbWUiOiJTcGlyaXR1c1NhbmN0dXMiLCJzaWduYXR1cmVSZXF1aXJlZCI6dHJ1ZSwidGV4dHVyZXMiOnsiU0tJTiI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzIxOWJlYTU0Y2FkN2Q1OGFiNWRhNDA2YjBhOTJhYjNhODI0MjI1MjY2Nzc3ZTUzNGI3ZGI2YzM3MmRkZmY3ZiJ9fX0=","UoSif81+UyvkcaanU8KAMYBpw9mefAmWehE2liDUFvk+y0X/9NovsxTYVpIDCltTSpLW3sNgamvbj4Ybs+s6DbudPiEkvh0ER7Bv2v29UJw7RzIdr6/1g548X12zcnh5iPGz/P75uNRnSfTFQx0ed8P/GNkPIjWpDuJFxEj6KcPzrCAGMx+BVw1VwryBIYf9cCDHky8z0bxR89rjiIvPTBFI6MRhqI3vgpEBTySHDS+Ki0Hwl5oa3PwS6+jgYx/4RSfFsb+BawcvDk2Xpkt5UimvqZ5BceYLIfCt4KbShYipgLXLfYUZrntjPemd3SxthjxUuA07i44UxRdiC8uqy1twLT/HUS28gpk68lA/id9tKFwu1CUzshgcmvQPt3ghtNViNziR/2t7D/+5D31Vzmhf6n7Pnpdirt/5frMi2BKMMs7pLa0EF8CrrDU7QCwPav+EZVGFvVZbxSkCDq+n3IQ3PUWSCzy6KPxpdOlUjD0pAfLoiNj0P8u4+puQtID76r/St8ExchYl2dodUImu1ZETWeFUClF3ZGat62evx8uRQEI2W4dsVwj40VUfjaAuvyDzuouaKTrCzJXLQZZjR1B8URvuK61fGX0nhW607mEi6DE+nxP2ZoBrROEX4e37Ap6+TQn9Q8tKDPdcxtwSOpPO4Qkncjn/mGtP9lZU/DQ=");
public final static SkinData SNOWMAN = new SkinData("eyJ0aW1lc3RhbXAiOjE0NTAwMTk4Nzk5NDIsInByb2ZpbGVJZCI6ImE5ZDBjMDcyYmYxOTQwYTFhMTkzNjhkMDlkNTAwMjZlIiwicHJvZmlsZU5hbWUiOiJTcGlyaXR1c1NhbmN0dXMiLCJzaWduYXR1cmVSZXF1aXJlZCI6dHJ1ZSwidGV4dHVyZXMiOnsiU0tJTiI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzEzMTgxYWViODQzODk3NzM1ZDQwMmIyNDk2OTQxNmZkYjBjZTM0YTZiOTM3ODE2MjQzNzU2ZTlkYWU1OGUzIn19fQ==","NZvsNu+HQ5uvGWq6O8VNDGq9A145bmk2IkHiz916uRVPMRqqCI/zwhKWNLlFACE/feuLkhYAois29ec6sVVOtHIoNA+S5q1Mb/Vjc3TJQxzqmx2FZOhJiIttFwYuo9WomQKBqrPMSJ9tpQig4wzoqldeeTjWC3dLz7JeX+gkzinryVjG7NNN9L5hXK5/BBxRcrtwmXJfUlSANyrd8RZW7mEUgU8yxlzdqTu0w7bZLjQNd4vciwoF3NelXDorMIIqiHTkuQesG91Njtu25VCUDK3nXbqEnZw2ZtxB5fT5G2Omm/vkNSRXc0P7iqchVowdYQcMlQUsp65xpkBbFS4LwjzDkYIfLmF++hePb8z72Gz77FxhO5sRLGreSH227McyL/0CtWNKm9ZZIfQtZZjEZTj9+eiJMCloCMg3yWa1VBOiLHzz0wY6gGklccIImPyXEg7E0dIK8qYseJMhmmBNZ8pDOkbUDp3mRlrQ2iyClgQkbuR63j79IBUaCxmsa3NnrAtaJklzd9mzkHXfMBh2XT7Gl8AhJS6JK5kCvip1rBBI8yjrsjE/E+lyJFIbC4rXxyMDGZWkcdrd7U4ZFYKiLHbzdFRqX+11qs9xO2BvomGXkATCzYmOf2kQ86R6rNN0+JfE4QpKzj2WWt3C8ky2qpuXZz29p0816E3/qseYtgg=");
public final static SkinData SANTA = new SkinData("eyJ0aW1lc3RhbXAiOjE0NTAwMTk3OTM3NTgsInByb2ZpbGVJZCI6ImE5ZDBjMDcyYmYxOTQwYTFhMTkzNjhkMDlkNTAwMjZlIiwicHJvZmlsZU5hbWUiOiJTcGlyaXR1c1NhbmN0dXMiLCJzaWduYXR1cmVSZXF1aXJlZCI6dHJ1ZSwidGV4dHVyZXMiOnsiU0tJTiI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlL2MyNTM5ZGFkZDUxYmE5ZTg0YzFhOTE1OTY3NWUxZTJiYWM1NmFlNmFlNTMxNTQyZDI1YTlkM2Q1YzQ2ODZmNiJ9fX0=","gvLc0Vo6+1vl17vrFCbK1eNqa4/ix4xiwcWae7WOCvqiVIX4sdIPagOGUrKsDdEhuWCKkTWILGP1K3wYfC9v/0mXZvbu0sRln+APTOsswMkQmbKcA1zTFTMpwEI+nIMzYJSbIx5wjz28K5hDf/umtHH2GADTENdJGGUtU4CyEdeHTzcqIAEV3bcMLkfTKvwKUWqI5gZbbercqmDeGkmXVS9297a9paRX1NfEL9pFT0pjdH3tCjgvvKfAwGC6tYtvTFbfcJocqgI+PI2f5OFf62A4XjWwWFi4wxCHVYNpqs/XTbfF64K7KVE0d9gsLjJoB8DMZPxlNpMFA0R5OIW6Q7Qjyz9IKxUqEYRCQbuUKpHyNDcmVKcTJRwBpCHeqAbTbweZHd5tzrT/terWhLEMsK1+lH2KBfIRIRB9kd3epyShNjSEKoly6uRXVxU+IJtfcq0aFVZlwgG3c1Ds9jbsNJV158e1n6WCmvT00RLdvpcIekwUKODhi3zFeFkrVvV50tGYqXLRZenitLJvDzx4c0IGK4krALrUS0oybinBS7/GmW3Ktz3xbGKZSzzaDw0EKB7Y6XHdb4yqR1xS7lAWgv4cNDEIUSzUDJ7HpmDCIF2A5kPS4XVYFCclyR6qPGD5e+9apVhBMz4lfYlT1IfRAUQlucO4UpAlkXs7ho3pQXU=");
private static long _nameCount = -99999999999999L;
public final static SkinData FREEDOM_CHEST = new SkinData("eyJ0aW1lc3RhbXAiOjE0NjY1NzA5NDAzODcsInByb2ZpbGVJZCI6IjQwZWQ5NzU1OWIzNTQ1M2Q4NjU1ZmMwMDM5OGRiNmI5IiwicHJvZmlsZU5hbWUiOiJTcG9vYm5jb29iciIsInNpZ25hdHVyZVJlcXVpcmVkIjp0cnVlLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjc4N2Q4OGNlYzNmOWI0M2RiNDg1YTU0Mjc2YTQ1MjQzNGFiZDI2ZDMzY2QzZmZhMTM2N2ZiMzVmOWUzODQifX19", "UgsQyW/HJ/jmDzfI1d7RWFbhKi8PeJAKBuAOk7ajS5dzH5od301KfcmiT2X3TU7cBbUswcKtDb2F/m7gNrg/t+pU7Bi9UKzyALEu9HRjd4s1uKbqGkBip1z5Qycp4fhkSyKvtvTnA2fhpP9oHtE5FxGXdMhZXyFkLrli4Hyxp1BI0N4h7pgbcMaISPS0ZYzDRNxkrSnl3y3KyKn5Rl5qH7utmQtAjoyx9aueMZxG3tg/igfYF7uAvvmuYKsSiTZWZOOuSh+U1dkP+ZE/cQANfryXkLJSJHa9YZPCMJHXe4mMoAyu0/quwZCW9NlW3P30XeCfZ87IxfKxISIP0dLgY8hUJyCuI2u5U7TEDrDggPKr6XTcIbX2kFKOsYSeovsAgjC+1UKFH4Ba0jTbRmqzPK49fk/jU8XqRP2Gl9UZDIVbc0dMEXNOeJ0e0wejDtSyX8flBk9sIKYwqeB9ns4cFqSyTI5tKnNin12BNTFRK/bDp8dN7nloyQvhDGlW88UlnJmOFhR6R0naP89VM04VCLaYCr6jyv/ZwV88uPvL2kjhx14qSFfgqJI5ORhFgYkuc+nhyQaD8+y2t3ZMs0HAfoujmq98lp2ECLWyI0ATUcXjUyNYadLj4valS/m0jl7U2fwzcmVMQqOC3ddu6mHbt871hIkG2X4v6kEcVAtKmkg=");
public final static SkinData COMPANION_CUBE = new SkinData("eyJ0aW1lc3RhbXAiOjE0NTUxMDk5NjI0NjEsInByb2ZpbGVJZCI6ImE5ZDBjMDcyYmYxOTQwYTFhMTkzNjhkMDlkNTAwMjZlIiwicHJvZmlsZU5hbWUiOiJTcGlyaXR1c1NhbmN0dXMiLCJzaWduYXR1cmVSZXF1aXJlZCI6dHJ1ZSwidGV4dHVyZXMiOnsiU0tJTiI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlL2MyMTVkYmRhNTY1ZjVjYjhlYjEyZjU1NWY1ZTNkYTBlYTVmNTUxOTg5MWNjNWM1ZDY3NmZkODJjNjIifX19", "vaAQbhnhnTOs64ToFWLg7o4JmqkIl07HWJ6l7xibfISaOcU4BvYBxsfGvmoxlVdsUeCunAJ8/05qVLl5zZYd8Dt+To6JSY0RlqV8piRaaj3FztYWV2ZvG3YZxPxiD3HRJTAQnDobSuxHyPa1e3khjAFp9xJo4q1oqQ28oI2WDuoT+IHqxwkKVbGzO7UD5lzz5chjQC46E8SxddNKp9aqwbbccrkHYT4gteoonOXu4MFxZniJN12LqUCb6+G15rU8MijlBkWx0xE5NMUloeTGuJZItbHun9fysLk/+HE5xJOKYtpZNMuWX+DB/O5ds9dXrOoSAg+Vn0QU4CZbwcxzLii5ILOfEEBtePuEAgzROri+iCKp59CqlEMBrCsd3Um0MCdbuOfvkXGBHBz+bqX7VJY1ujlSdMefmbJtHAkDANnsaaVb+eli9Dk6139041sptsLytD+EfJzaitX6crBwKZ2WDx2P6LHo8B+iSOzOJxjf/08zlXqFw1vsk62IN6lisuZ89QyZw23RvOx3obLAGYs1GxAlMl9qQdpXcmuE1+lPR3g8gZ0BfnTeYwflC2wbR1tuwGG98lyUGCvGLyqNKAQTN87XV4IFQWR81mi1c5CcasoWhKf9D9nAik9aK7A915fEE5IvpeuUdZseDxDVVN5dBIs5q2PIHFAS0rDsDBc=");
public final static SkinData THE_GRINCH = new SkinData("eyJ0aW1lc3RhbXAiOjE0NTAwMTYxNDMwMDQsInByb2ZpbGVJZCI6ImE5ZDBjMDcyYmYxOTQwYTFhMTkzNjhkMDlkNTAwMjZlIiwicHJvZmlsZU5hbWUiOiJTcGlyaXR1c1NhbmN0dXMiLCJzaWduYXR1cmVSZXF1aXJlZCI6dHJ1ZSwidGV4dHVyZXMiOnsiU0tJTiI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzg4ZWRlOTI3ZDQzOWVmMzliMzFhYzFkYzJhODM5NGZlNzlhY2U4NDMyNzBjYmUxMjg2ZGM3NTE3ZjMxYTk2In19fQ==","ELo594vTzPq9ZmPYOtVr4kim/k19gzmoxEIK1ehS87gwgag5HcgM+P1FMnHIyrmSvTVaMh0NxwXmNS+JETFL7OrmgRYNpkxkkO4VBA0pfSn3dA9ujnXpDnDiWEPxKdMgQspIOOI0Z3esNt3pj8qIj6dWPtGwtso48tjHl2o/kazfa82yvGORlFhGkeEJKQMno/Buc12C0foQw39XI8GjvlSkFN2eH4Fp16RLu8/hf7SqJQC3L1KacvzMW1d8BWEIgACCJDni29+YqxflSqSyYrV4Z+D66S0jYvUUL/vM4/q/p/YWX/vs/FtMtHQTj4PCpAmMNTgfkahuhb6rCvKHukbjA+WhUdwyxSqXU5YnpXCu1M2dzZgiXjIi+fnyn4CmXKindWCQtSwu+mCA2ILv/6vEHoYJgdlz+DXyRkFx+DH4Sl74HBCOXTOq5AGjq5h3LYfsre+UjCCUv8VgxbVprOyj35So7K0m+6faCFVSt35T3RgicDQfdiWUrW7kmHQVvJpvaq9Vu+63F/0X93cwqwaR0buMirxRx7qkFrRunSI4T+9fsN02t1fAieeu80lBSv83wr7BFneSsLsdVAND9xttTb6fClg7anr8/XVEVIkylB4B+ZcWQbH61XP1nn7oFP2VBg1h6XuuLp8FGSgYf/LW+54/KZci/MnanqQE6QQ=");
public final static SkinData LOVESTRUCK = new SkinData("eyJ0aW1lc3RhbXAiOjE0NTUxMTAyNDMyNjUsInByb2ZpbGVJZCI6ImE5ZDBjMDcyYmYxOTQwYTFhMTkzNjhkMDlkNTAwMjZlIiwicHJvZmlsZU5hbWUiOiJTcGlyaXR1c1NhbmN0dXMiLCJzaWduYXR1cmVSZXF1aXJlZCI6dHJ1ZSwidGV4dHVyZXMiOnsiU0tJTiI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzczMTY5YWQwZTUyYjM1N2NiZGYxZDU0NGVkNGNmOWJmOTI4YmI0ZWNlMDhlY2YyY2M0YmYyYTlmMjJhODI4MmQifX19", "LL4RiSKQoTZamRQ4QG6izpvhgFu5gAqW4eZxcWAihk7GkhyxifpJpBTOzKrj5hH9fCUfYkkijVWUYTEcVSVRWhocp2HXW59TbKfxOeMvHU5vTMwgpwm6PnUfwuTsRPSLC7WMnEreI3cjOxPVmXbTniOSd+o8j4oOIgwFS+VLPiYLh5Jl16i5I/9ekafl3/x41NISKWl62geqO2jPWehlk+r3soiRJsxaKw20T61GSNLu19iA96Rz2T2tUHB4opm8hbLgoiNL2g1affTjq3cZPLHH4JWF3vPhqLB5uw6xb55vFLM/PP0YiEMIi7YZOfRGeaPp7uXbXgHeew+7PG9UDVMfqbwANQY4ndECijZoei54+xX3MDXkMhQsc5S+FLnGH6e4d008v81eEOyzJUPkKbGxLCBgTUb1s4IHwomCr30twPlo1IuFBOY1qeVvZUfAfPJsREuj5q/oCAoYFgupmb3ClWECnwwaH/T4wdHjfSBHoZQdLzcgDOAl0b5EXxWmYBECqk/WA4TrYIDVGdwkqjI0RkPLUoxTj6135KO+F7P7PwhU9WBGeW8hHq918DBL0fjQVHjrzvolTqwmw6nySSePnPOxFX/iwtHWzpBa9V6kUNNN+V7OGTgRr0H/yUxB+oq1F8UBqyqT4YpqxXCSD36derF/Xt5IdpTbEbGBpm0=");
public final static SkinData PRESENT = new SkinData("eyJ0aW1lc3RhbXAiOjE0NTAwMTk3MDIxNjIsInByb2ZpbGVJZCI6ImE5ZDBjMDcyYmYxOTQwYTFhMTkzNjhkMDlkNTAwMjZlIiwicHJvZmlsZU5hbWUiOiJTcGlyaXR1c1NhbmN0dXMiLCJzaWduYXR1cmVSZXF1aXJlZCI6dHJ1ZSwidGV4dHVyZXMiOnsiU0tJTiI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlL2U2YzRkZWQwNTdjMjhiMTU0NjVkYzQzNmFmODIyYTNkZTY4NzgyZTZjMzgyOGMzMmFhYWE4ZjRiOTIzOWVjIn19fQ==","rJNlxTqHHmOoWwbXdMQLcj0P9w/PIr/hWKXH0nbhm/S2CFo/zfefffZlnQmpKCgn1Y8tXvcRwLGQ4CLpm9m2ZrKprSWRhrnOtZWYabrhExQESEammS3TY81VoNt+4On0pAGBippz/bRfWLuDne2rDbhuljnqvxjROmxpky7gRCU06VMlm2WLFC5XYJkiAaOXBqzpiHMMRPNnCvtcbtpILKi/Luj302eyN8nRKjHHbbiDmttwvlshxZ8UxJHvALtM506IUHba10Q6QX2zCeDAU5/WYRKa6e19r8plROcgGbKYFSq8JW5cWuWT3/rveZM6FnU6ABn9DWsCyfQ5wr2jdBd+xaevGTAScRHA5J493GqL1bBZYKj9yhQFtxJHCAf0++raAVPCZgyPtwTth4TAQisn8gnhM5R+txnW6xK+oflLy0dwEN1YdPLN/h7yuDnyjSMDe9RZT2NKMjok2C6Kux4WBI0KFXKC5Gqwa3Htku4v3WEOWMaVoWOtchQ9BzpQ/etD0ylmzjALQLB+HtndEEm1Jd3tmob42X4hBE8hCce7C3EtGINB33dlx4CK1xBqyGTJEqi69DJRzVL99u98+7kJ1Db9+MaPOfI4B2RY3XbvnSYwecandY//A3bb19FGSdl299ZXbp4zpm8fivzeB1rUAhhmtaA3Iwu/nEQNMkU=");
public final static SkinData RUDOLPH = new SkinData("eyJ0aW1lc3RhbXAiOjE0NTAwMTk1NjgxODIsInByb2ZpbGVJZCI6ImE5ZDBjMDcyYmYxOTQwYTFhMTkzNjhkMDlkNTAwMjZlIiwicHJvZmlsZU5hbWUiOiJTcGlyaXR1c1NhbmN0dXMiLCJzaWduYXR1cmVSZXF1aXJlZCI6dHJ1ZSwidGV4dHVyZXMiOnsiU0tJTiI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlL2IzZjdlMjhiNTJkZjJjZjhlZWM2NDk2ZmM0NWFlMGQ2NTM0Njc5OGIxYWRjNzM3ZDcxYzBmOTRlNDIyMSJ9fX0=","uUBOTe63CL+qRvtsb2g4AjB2YzxE3N6AUqIsTv8n0jYyPsuXpuOmZPSMEdgDVONywEJ1L4XRx05sjnGu56A8vuXmGI/uHQWuMZzbOSjiFfT3DkEm8zEl5AWpH9dz/t8nZ1WYUIwy0pN5VrZqIr1DAkF6AMh/Qy+FGDw1GG9ReRr80eJ0JiRskpkCpCZIGGjrgwNKAM8JOuNZ4gCQOTRC3etrcfls3qmUMFcVlhuB4bydxSR01i2w0A4b5KpufsJjLKw4InWn2+m/druo8hl9sYuusTeItW0MQmZqCAqXCc9YBnRPQ0hDXFgnPxOh3RwGWiZvL4MnWUVmLwZWh/Fk9QmyVbd7zVao0lxS8YNsKtP8j5B+hs4l9qNohhf0A07bt4oPeTtd5fQeOU5N87fUGuUAcpC4gP9U5WpVY5FFPBvLvGbXdV5jpuAQz4lLSoo1grsP9baR2IBvdN/0awjQWoPJfGOttegubkBHwz3LNcVqvZLtX/M13IDHZa6zQZEX0wsnMX60LeWgBWfTON1l2cSgaPTerHFS2EifJ2LvTBife3s9/4XR6Zth3FLFqxI3MSlqT2hVFRPLke6rBqfqPoWOj2MCykQ70IAwb3oTHcJDJ86V2DdNaU2bZ8V4TjaP+nRobsLJOImoPYEPq23MP36X8gbXEIjmuu8S5xRlrrc=");
public final static SkinData THE_GRINCH = new SkinData("eyJ0aW1lc3RhbXAiOjE0NTAwMTYxNDMwMDQsInByb2ZpbGVJZCI6ImE5ZDBjMDcyYmYxOTQwYTFhMTkzNjhkMDlkNTAwMjZlIiwicHJvZmlsZU5hbWUiOiJTcGlyaXR1c1NhbmN0dXMiLCJzaWduYXR1cmVSZXF1aXJlZCI6dHJ1ZSwidGV4dHVyZXMiOnsiU0tJTiI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzg4ZWRlOTI3ZDQzOWVmMzliMzFhYzFkYzJhODM5NGZlNzlhY2U4NDMyNzBjYmUxMjg2ZGM3NTE3ZjMxYTk2In19fQ==","ELo594vTzPq9ZmPYOtVr4kim/k19gzmoxEIK1ehS87gwgag5HcgM+P1FMnHIyrmSvTVaMh0NxwXmNS+JETFL7OrmgRYNpkxkkO4VBA0pfSn3dA9ujnXpDnDiWEPxKdMgQspIOOI0Z3esNt3pj8qIj6dWPtGwtso48tjHl2o/kazfa82yvGORlFhGkeEJKQMno/Buc12C0foQw39XI8GjvlSkFN2eH4Fp16RLu8/hf7SqJQC3L1KacvzMW1d8BWEIgACCJDni29+YqxflSqSyYrV4Z+D66S0jYvUUL/vM4/q/p/YWX/vs/FtMtHQTj4PCpAmMNTgfkahuhb6rCvKHukbjA+WhUdwyxSqXU5YnpXCu1M2dzZgiXjIi+fnyn4CmXKindWCQtSwu+mCA2ILv/6vEHoYJgdlz+DXyRkFx+DH4Sl74HBCOXTOq5AGjq5h3LYfsre+UjCCUv8VgxbVprOyj35So7K0m+6faCFVSt35T3RgicDQfdiWUrW7kmHQVvJpvaq9Vu+63F/0X93cwqwaR0buMirxRx7qkFrRunSI4T+9fsN02t1fAieeu80lBSv83wr7BFneSsLsdVAND9xttTb6fClg7anr8/XVEVIkylB4B+ZcWQbH61XP1nn7oFP2VBg1h6XuuLp8FGSgYf/LW+54/KZci/MnanqQE6QQ=");
public final static SkinData TEDDY_BEAR = new SkinData("eyJ0aW1lc3RhbXAiOjE0NTUxMDkzOTE4MjYsInByb2ZpbGVJZCI6ImE5ZDBjMDcyYmYxOTQwYTFhMTkzNjhkMDlkNTAwMjZlIiwicHJvZmlsZU5hbWUiOiJTcGlyaXR1c1NhbmN0dXMiLCJzaWduYXR1cmVSZXF1aXJlZCI6dHJ1ZSwidGV4dHVyZXMiOnsiU0tJTiI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzQ0OTU4ZDdjNjlhZTQ4NGM2NWYzMTM0N2NkY2M5MmM2OWY1NDA2ODA1YjUzNjUyYTc1YThlZDc5OWRmNyJ9fX0=", "sNTRV9jTjLszUmyaqyEG7N8d5RM1jbwMSXi34S2EkVmIjWsowfSMnHRQqqgZfxcyqBM5I7MljtB84IeQWu4rqhyFrM9blWvtowjijFIOgKCs97q2sswv9iauU6ohvgTpgN5B0Q16MJmMIgZU8d8TATtEaIzq2eg6Ve1AJlNnW4huGNsoNfm8WdVU1tZmsYAwtVP/ryvhyj7mHyVF27m0Sm4fZRf/lHH5gEJYB4JHSAoEhjPIQOdkgRMJRrWGOfhhiGs3kEWmsRGfIPFo2ZJfcu+TFV2rd4Q+A1LmY8kimnzdKX3InXeKbk8qzcgqGNro4XFnSiHo1d6/B+N0JeYOTITYRQ6u24rNSUh5ezbG01iikVFCfrgb7UR6utoLK15F4/fmhpex+BJpmyZoXAqk08tZws/5wsIWQ1okrGcbBKWEHhw2ekUc82US21/W53vd657UBg7FuqM4FhkAqmsYPvYLMpNYxxmDJaI8uJyU7cnGFYyBaFlqUxfJUfcFTwWo10JO3yp5FjqeCQa7rFvfpsqw3w2mBpJmlZ5HRjfS5pmhk0QiY0TRfwZfFemkuZYnNbO82qLUm+6zTm0fbC90Swt8nNr/42ajzEoUjnL6VsERIXS5/fPwjftbQAC60ujy8yo66Sp3sSAALNg5zjM+Uizkq2f9Axc+kind22hp10M=");
public final static SkinData COMPANION_CUBE = new SkinData("eyJ0aW1lc3RhbXAiOjE0NTUxMDk5NjI0NjEsInByb2ZpbGVJZCI6ImE5ZDBjMDcyYmYxOTQwYTFhMTkzNjhkMDlkNTAwMjZlIiwicHJvZmlsZU5hbWUiOiJTcGlyaXR1c1NhbmN0dXMiLCJzaWduYXR1cmVSZXF1aXJlZCI6dHJ1ZSwidGV4dHVyZXMiOnsiU0tJTiI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlL2MyMTVkYmRhNTY1ZjVjYjhlYjEyZjU1NWY1ZTNkYTBlYTVmNTUxOTg5MWNjNWM1ZDY3NmZkODJjNjIifX19", "vaAQbhnhnTOs64ToFWLg7o4JmqkIl07HWJ6l7xibfISaOcU4BvYBxsfGvmoxlVdsUeCunAJ8/05qVLl5zZYd8Dt+To6JSY0RlqV8piRaaj3FztYWV2ZvG3YZxPxiD3HRJTAQnDobSuxHyPa1e3khjAFp9xJo4q1oqQ28oI2WDuoT+IHqxwkKVbGzO7UD5lzz5chjQC46E8SxddNKp9aqwbbccrkHYT4gteoonOXu4MFxZniJN12LqUCb6+G15rU8MijlBkWx0xE5NMUloeTGuJZItbHun9fysLk/+HE5xJOKYtpZNMuWX+DB/O5ds9dXrOoSAg+Vn0QU4CZbwcxzLii5ILOfEEBtePuEAgzROri+iCKp59CqlEMBrCsd3Um0MCdbuOfvkXGBHBz+bqX7VJY1ujlSdMefmbJtHAkDANnsaaVb+eli9Dk6139041sptsLytD+EfJzaitX6crBwKZ2WDx2P6LHo8B+iSOzOJxjf/08zlXqFw1vsk62IN6lisuZ89QyZw23RvOx3obLAGYs1GxAlMl9qQdpXcmuE1+lPR3g8gZ0BfnTeYwflC2wbR1tuwGG98lyUGCvGLyqNKAQTN87XV4IFQWR81mi1c5CcasoWhKf9D9nAik9aK7A915fEE5IvpeuUdZseDxDVVN5dBIs5q2PIHFAS0rDsDBc=");
public final static SkinData LOVESTRUCK = new SkinData("eyJ0aW1lc3RhbXAiOjE0NTUxMTAyNDMyNjUsInByb2ZpbGVJZCI6ImE5ZDBjMDcyYmYxOTQwYTFhMTkzNjhkMDlkNTAwMjZlIiwicHJvZmlsZU5hbWUiOiJTcGlyaXR1c1NhbmN0dXMiLCJzaWduYXR1cmVSZXF1aXJlZCI6dHJ1ZSwidGV4dHVyZXMiOnsiU0tJTiI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzczMTY5YWQwZTUyYjM1N2NiZGYxZDU0NGVkNGNmOWJmOTI4YmI0ZWNlMDhlY2YyY2M0YmYyYTlmMjJhODI4MmQifX19", "LL4RiSKQoTZamRQ4QG6izpvhgFu5gAqW4eZxcWAihk7GkhyxifpJpBTOzKrj5hH9fCUfYkkijVWUYTEcVSVRWhocp2HXW59TbKfxOeMvHU5vTMwgpwm6PnUfwuTsRPSLC7WMnEreI3cjOxPVmXbTniOSd+o8j4oOIgwFS+VLPiYLh5Jl16i5I/9ekafl3/x41NISKWl62geqO2jPWehlk+r3soiRJsxaKw20T61GSNLu19iA96Rz2T2tUHB4opm8hbLgoiNL2g1affTjq3cZPLHH4JWF3vPhqLB5uw6xb55vFLM/PP0YiEMIi7YZOfRGeaPp7uXbXgHeew+7PG9UDVMfqbwANQY4ndECijZoei54+xX3MDXkMhQsc5S+FLnGH6e4d008v81eEOyzJUPkKbGxLCBgTUb1s4IHwomCr30twPlo1IuFBOY1qeVvZUfAfPJsREuj5q/oCAoYFgupmb3ClWECnwwaH/T4wdHjfSBHoZQdLzcgDOAl0b5EXxWmYBECqk/WA4TrYIDVGdwkqjI0RkPLUoxTj6135KO+F7P7PwhU9WBGeW8hHq918DBL0fjQVHjrzvolTqwmw6nySSePnPOxFX/iwtHWzpBa9V6kUNNN+V7OGTgRr0H/yUxB+oq1F8UBqyqT4YpqxXCSD36derF/Xt5IdpTbEbGBpm0=");
public final static SkinData SANTA = new SkinData("eyJ0aW1lc3RhbXAiOjE0NTAwMTk3OTM3NTgsInByb2ZpbGVJZCI6ImE5ZDBjMDcyYmYxOTQwYTFhMTkzNjhkMDlkNTAwMjZlIiwicHJvZmlsZU5hbWUiOiJTcGlyaXR1c1NhbmN0dXMiLCJzaWduYXR1cmVSZXF1aXJlZCI6dHJ1ZSwidGV4dHVyZXMiOnsiU0tJTiI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlL2MyNTM5ZGFkZDUxYmE5ZTg0YzFhOTE1OTY3NWUxZTJiYWM1NmFlNmFlNTMxNTQyZDI1YTlkM2Q1YzQ2ODZmNiJ9fX0=","gvLc0Vo6+1vl17vrFCbK1eNqa4/ix4xiwcWae7WOCvqiVIX4sdIPagOGUrKsDdEhuWCKkTWILGP1K3wYfC9v/0mXZvbu0sRln+APTOsswMkQmbKcA1zTFTMpwEI+nIMzYJSbIx5wjz28K5hDf/umtHH2GADTENdJGGUtU4CyEdeHTzcqIAEV3bcMLkfTKvwKUWqI5gZbbercqmDeGkmXVS9297a9paRX1NfEL9pFT0pjdH3tCjgvvKfAwGC6tYtvTFbfcJocqgI+PI2f5OFf62A4XjWwWFi4wxCHVYNpqs/XTbfF64K7KVE0d9gsLjJoB8DMZPxlNpMFA0R5OIW6Q7Qjyz9IKxUqEYRCQbuUKpHyNDcmVKcTJRwBpCHeqAbTbweZHd5tzrT/terWhLEMsK1+lH2KBfIRIRB9kd3epyShNjSEKoly6uRXVxU+IJtfcq0aFVZlwgG3c1Ds9jbsNJV158e1n6WCmvT00RLdvpcIekwUKODhi3zFeFkrVvV50tGYqXLRZenitLJvDzx4c0IGK4krALrUS0oybinBS7/GmW3Ktz3xbGKZSzzaDw0EKB7Y6XHdb4yqR1xS7lAWgv4cNDEIUSzUDJ7HpmDCIF2A5kPS4XVYFCclyR6qPGD5e+9apVhBMz4lfYlT1IfRAUQlucO4UpAlkXs7ho3pQXU=");
public final static SkinData SECRET_PACKAGE = new SkinData("eyJ0aW1lc3RhbXAiOjE0NTUxMTAzNzE3OTIsInByb2ZpbGVJZCI6ImE5ZDBjMDcyYmYxOTQwYTFhMTkzNjhkMDlkNTAwMjZlIiwicHJvZmlsZU5hbWUiOiJTcGlyaXR1c1NhbmN0dXMiLCJzaWduYXR1cmVSZXF1aXJlZCI6dHJ1ZSwidGV4dHVyZXMiOnsiU0tJTiI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlL2QyNWI5YTRjOWRhOThkZTliZmIwZDNjOWI1M2MzMjJhMjgxN2IyMTMxOTQzY2E1YWM2NTBjZThmMzEzZjdhIn19fQ==", "Wb5T0Zhp1RVt78V/i8dYrwZCNT0xZIRe3LvL0bngH498f8Jrl43KHgTi4f299zE9giVynkTogGhJ8inq/xqFCRctl7Nn9L3LVu78uQwt+fs+o+kw/Qc+lggFSjEIc+fc13AZndpec0Df46Kh/OGD7NXbtbLb6TE/0dU2RwQlvZrZ/QHYJb8OJ6aUcnHvAZim8NUtG/nlZtSClepHVSuKdNnfzoF9rFVFA/x4jTr6mZYPZ33YgQd2oTAPk+qE3iN+0InjZQNs2YLoKFmFrgzn+tGvNApC0siF0HEZGQCFIwJOtnBsasGoxujIrln/ZdOil+5ac4VWInXr8lKgY0Q3Ocy8/0cJl+E/XqB+ztG29zhB8B1zdHBfJr+MgeSIqBCPx4SCtY6r7gnMlQYG+uVx5NP3S5aJW/cEfDyXmpCykIcBPzeErnKC0SiAqXkCVNjWJpX6qRWvWMXqS69w6ht6qHvEY2GxlZUb5AP+JgFlsl3hJDms6EPvM4zNL0Ko4oWIBzwYRQXiemrP9TGgyo0aL1RcQ0JgBFO2hSo37PK0YL3tUPgteJXzm21wu0TiZLkLCWSgMUfYfvVnhTa+xzod0xvfujpN6Y1DUTdcf8WS8TRYw2JigSkWrRW0fXPBCtTtQN5jiwM5/HrTpNLzg03J6SpfZ+rr8Rhq0S/8beQOMas=");
public final static SkinData CHISS = new SkinData("eyJ0aW1lc3RhbXAiOjE0NTk1NDI5NjgyNDEsInByb2ZpbGVJZCI6IjFkMmJmZTYxN2ViZDQ0NWRiYTdkODM1NGEwZmZkMWVhIiwicHJvZmlsZU5hbWUiOiJDaGlzcyIsInNpZ25hdHVyZVJlcXVpcmVkIjp0cnVlLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTg3MmNkMzRjY2IzMTIxYjRjNmEzOGFjM2JmOGVkM2UwMzk3YmQ2YTg4NDI4YjdhZmM2ZTUyNTI4NTVhMzQzIiwibWV0YWRhdGEiOnsibW9kZWwiOiJzbGltIn19fX0=", "hNTLRA2acZYx2dM90lnJN8FMK/ceD3+AxKNdD5FrXzxGtYL4C1Jr/vbTE0UosmwFP3wScNEW/fuDOjeZRjZHMJdvgDZMlMK/5KDhOY6sj/RS9RckztsgummSyjH/hdDn7TWWfhZLMbiia/K0VReI9eq2yD6zGQpvMlz5hB/5SX5YHWXvCah3TL4UzYSlSVDlwY/Q3sVuIZUr8m/LIXJwniJKLGo6tUgtiJd9eseOsbBpVjzCUtLD8A9WBe2/eODgmLfqEvXESIoDRG8vL2nPSXWma/YolYHIl32/i+ZxVD7dRRaXQFYSiLI24EtzX1pPhMjyaTLazP9abH43J6J31w02pKM7N/xTa62020L/YfRRKGT5lygEDb1NMoSpAjszPxah+Ra2/L+yUWEI8cMES6I4mIJ00tclPjWK01xhIn3tqg+y2gqsGHwPhu/7vmF5NirNfKFw0qciKNBfbCAF7ae+mkUKjmAPuvBUBqQb7BOcpNVWsCo/XvzmiZZYsf5P4Uwz8LqUK4uH6V/5dg7lY2Xg3+IUylsrDqLGFDI8iy/NdjIQMbuRadh4IDO6DcmxBri2Ax4JNBPBTnRezge8uq37MZcft/IXQgFWKB9RtidVEACaTOkRj27k+Ojnkki+j44k0wZB47hiXFUHMCHl3a0SVdQe15ZbVsQj/HAvAS0=");
public final static SkinData DEFEK7 = new SkinData("eyJ0aW1lc3RhbXAiOjE0NTk1NDI3ODkwNTksInByb2ZpbGVJZCI6Ijg5ZDQ2M2Y3MjNlYzQ3MGE4MjQ0NDU3ZjBjOGQ4NjFjIiwicHJvZmlsZU5hbWUiOiJkZWZlazciLCJzaWduYXR1cmVSZXF1aXJlZCI6dHJ1ZSwidGV4dHVyZXMiOnsiU0tJTiI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlL2JmYWNjOWM4ZjhlY2E1OWU0NTE4MTUxZmE4OGFiMDZjOTFmNjM3OTE2NzJmMTRlNGYzODY3YTI2OTVlN2NmYmYifSwiQ0FQRSI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzIyYjljNWVhNzYzYzg2ZmM1Y2FlYTMzZDgyYjBmYTY1YTdjMjI4ZmQzMjFiYTU0NzY2ZWE5NWEzZDBiOTc5MyJ9fX0=", "jBoRvkhQXz+nap8yJJIZ+4HClMItWODumeSOYjXytP3WWKHK0UMq0xC/keXsnmvo89lMRdRbknPt2ZX5Flgyjgr4Rt0KtDvpL/hG4BUsTWryUZZMKxdd6DkZXYRtTogLUfHeDYIz+cZQ0aXGMtvX/ZYTXJfMi6FYbIHY/qEEDnWhDX5y+SPpaJaZByPsvzi+qbfcFGnJ6nqi9ccyZYnYpnI2IVBM/yO/VRXWHxfqvJ0VVvv5KsGmVbko2Jxo0SDCxUL2UTH2+eol53FxhkkC+m2geC14k1zsZQLHDF3BgAG9+kFJ4UEoYRKF2Gy1FxeDCJtjYNdrYR8fdaUKRMcpBgEs+ZGe2U9EVVS/ZcBCjB7S+1Ne2bPzPFzTQPuBoMgggo1xbxBmQ5NyhYo4gwgj/xjSLIhb+5h7ioN1URfSRcfYdVv6RRO9l/u9l09jEom8y/jGRviefpEr+/e9iAl5Dd/6nzQgosBQja3NSfqYZmyuet2eI9zu61CObDTpR6yaCbNgBe/lWofRfULdpJpgjb4UNTBom3q82FcCiOe02OekGPw4+YlilhICBhajF5JzN8FKAdqI1osDcX3KuJgikYIW3voNaOP5YN3GXgilJNdou20KFC8ICq68HglgX7/0rLrWKIEoswnINIM6HcJbQuXncVPwQhV6K34Hlt/Na60=");
public final static SkinData SNOWMAN = new SkinData("eyJ0aW1lc3RhbXAiOjE0NTAwMTk4Nzk5NDIsInByb2ZpbGVJZCI6ImE5ZDBjMDcyYmYxOTQwYTFhMTkzNjhkMDlkNTAwMjZlIiwicHJvZmlsZU5hbWUiOiJTcGlyaXR1c1NhbmN0dXMiLCJzaWduYXR1cmVSZXF1aXJlZCI6dHJ1ZSwidGV4dHVyZXMiOnsiU0tJTiI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzEzMTgxYWViODQzODk3NzM1ZDQwMmIyNDk2OTQxNmZkYjBjZTM0YTZiOTM3ODE2MjQzNzU2ZTlkYWU1OGUzIn19fQ==","NZvsNu+HQ5uvGWq6O8VNDGq9A145bmk2IkHiz916uRVPMRqqCI/zwhKWNLlFACE/feuLkhYAois29ec6sVVOtHIoNA+S5q1Mb/Vjc3TJQxzqmx2FZOhJiIttFwYuo9WomQKBqrPMSJ9tpQig4wzoqldeeTjWC3dLz7JeX+gkzinryVjG7NNN9L5hXK5/BBxRcrtwmXJfUlSANyrd8RZW7mEUgU8yxlzdqTu0w7bZLjQNd4vciwoF3NelXDorMIIqiHTkuQesG91Njtu25VCUDK3nXbqEnZw2ZtxB5fT5G2Omm/vkNSRXc0P7iqchVowdYQcMlQUsp65xpkBbFS4LwjzDkYIfLmF++hePb8z72Gz77FxhO5sRLGreSH227McyL/0CtWNKm9ZZIfQtZZjEZTj9+eiJMCloCMg3yWa1VBOiLHzz0wY6gGklccIImPyXEg7E0dIK8qYseJMhmmBNZ8pDOkbUDp3mRlrQ2iyClgQkbuR63j79IBUaCxmsa3NnrAtaJklzd9mzkHXfMBh2XT7Gl8AhJS6JK5kCvip1rBBI8yjrsjE/E+lyJFIbC4rXxyMDGZWkcdrd7U4ZFYKiLHbzdFRqX+11qs9xO2BvomGXkATCzYmOf2kQ86R6rNN0+JfE4QpKzj2WWt3C8ky2qpuXZz29p0816E3/qseYtgg=");
public final static SkinData TEDDY_BEAR = new SkinData("eyJ0aW1lc3RhbXAiOjE0NTUxMDkzOTE4MjYsInByb2ZpbGVJZCI6ImE5ZDBjMDcyYmYxOTQwYTFhMTkzNjhkMDlkNTAwMjZlIiwicHJvZmlsZU5hbWUiOiJTcGlyaXR1c1NhbmN0dXMiLCJzaWduYXR1cmVSZXF1aXJlZCI6dHJ1ZSwidGV4dHVyZXMiOnsiU0tJTiI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzQ0OTU4ZDdjNjlhZTQ4NGM2NWYzMTM0N2NkY2M5MmM2OWY1NDA2ODA1YjUzNjUyYTc1YThlZDc5OWRmNyJ9fX0=", "sNTRV9jTjLszUmyaqyEG7N8d5RM1jbwMSXi34S2EkVmIjWsowfSMnHRQqqgZfxcyqBM5I7MljtB84IeQWu4rqhyFrM9blWvtowjijFIOgKCs97q2sswv9iauU6ohvgTpgN5B0Q16MJmMIgZU8d8TATtEaIzq2eg6Ve1AJlNnW4huGNsoNfm8WdVU1tZmsYAwtVP/ryvhyj7mHyVF27m0Sm4fZRf/lHH5gEJYB4JHSAoEhjPIQOdkgRMJRrWGOfhhiGs3kEWmsRGfIPFo2ZJfcu+TFV2rd4Q+A1LmY8kimnzdKX3InXeKbk8qzcgqGNro4XFnSiHo1d6/B+N0JeYOTITYRQ6u24rNSUh5ezbG01iikVFCfrgb7UR6utoLK15F4/fmhpex+BJpmyZoXAqk08tZws/5wsIWQ1okrGcbBKWEHhw2ekUc82US21/W53vd657UBg7FuqM4FhkAqmsYPvYLMpNYxxmDJaI8uJyU7cnGFYyBaFlqUxfJUfcFTwWo10JO3yp5FjqeCQa7rFvfpsqw3w2mBpJmlZ5HRjfS5pmhk0QiY0TRfwZfFemkuZYnNbO82qLUm+6zTm0fbC90Swt8nNr/42ajzEoUjnL6VsERIXS5/fPwjftbQAC60ujy8yo66Sp3sSAALNg5zjM+Uizkq2f9Axc+kind22hp10M=");
public final static SkinData UNCLE_SAM = new SkinData("eyJ0aW1lc3RhbXAiOjE0NjYxODA0NjY4NTcsInByb2ZpbGVJZCI6IjlmY2FlZDhiMTRiNTRmN2ZhNjRjYjYwNDBlNzA1MjcyIiwicHJvZmlsZU5hbWUiOiJMQ2FzdHIxIiwic2lnbmF0dXJlUmVxdWlyZWQiOnRydWUsInRleHR1cmVzIjp7IlNLSU4iOnsidXJsIjoiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS9jYzM1YWRmZTQ3ODBjNmU2NTk4YTJlYzk2ZjdhZGQ5ZDc4NjljMjBlZjRmYjEyNjk2NmJhOGFlMDRlOWRhIn19fQ==", "NmJ+hXmvwQlYFYY7YVQWRr11yBbAfJP+jk11SQ91gUUtJJjb4v8RFbNu5UXNCKxYj3BPtldqshG1maNB0NWJRud7ZyAdHc0JMmR1vtHEge9Hhet4fLyyaZ9rZn4BvD9Guqgv9H/mZzUzrft9TIho0Qbu/U++lVsbZXC2GrJDDMyLnYr9C7f+FUnr0z4WvkNcg23SHBOYkOYT95NSdykIka3c3v+/HvSvuwOnMsfVxqLyCZLpo20vamBJ1uK1dmx2+TVGnUPlofFHRdOXOpJc+YmicJvrsQR6a9zlvnTbU4MYClMOKvjLe6aX5Af+n8Gw3oKcm0PuR8CPLyf9kjcmUF6XMiEXAWWJtCgvhCiFV5/mQQH3cQ1kqk4BDLUxMVhG5tzjKLoQQy39cFM32ee+QFjXlzy59meC8jgvPmOVU3GpJ32XWOtaXMCyeJrhz2QVKRLEr2KZgz8Pd8VrHARXVZsNYEasj8z0cHjgSJqTU9kD90CC+4YpvdyRBRqbNQig5KuGCqUHKgflsEsM7YrFRKP5As1LgqYQfqRAMmLSo47eW0onOwchC9wCqqisPlYSuDRt4Mun/KFGqYh1Sghn8/gzu49La8BpwlekjVEoPEcDaIIgnFzOvgmmgMANkoJ3PzhHoHMoXtObe3eSTi+eYp4qAQVzkTxfF3WXY2fui1M=");
// Comments this out for now, so it doesn't load the player profile
// A better way to do this would check for the properties when getting the skull or the skin
// Might change on the next version
//public final static SkinData MOOSHROOM = new SkinData("eyJ0aW1lc3RhbXAiOjE0NDk4NzI0OTU0MTcsInByb2ZpbGVJZCI6ImE5ZDBjMDcyYmYxOTQwYTFhMTkzNjhkMDlkNTAwMjZlIiwicHJvZmlsZU5hbWUiOiJTcGlyaXR1c1NhbmN0dXMiLCJzaWduYXR1cmVSZXF1aXJlZCI6dHJ1ZSwidGV4dHVyZXMiOnsiU0tJTiI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzIxOWJlYTU0Y2FkN2Q1OGFiNWRhNDA2YjBhOTJhYjNhODI0MjI1MjY2Nzc3ZTUzNGI3ZGI2YzM3MmRkZmY3ZiJ9fX0=","UoSif81+UyvkcaanU8KAMYBpw9mefAmWehE2liDUFvk+y0X/9NovsxTYVpIDCltTSpLW3sNgamvbj4Ybs+s6DbudPiEkvh0ER7Bv2v29UJw7RzIdr6/1g548X12zcnh5iPGz/P75uNRnSfTFQx0ed8P/GNkPIjWpDuJFxEj6KcPzrCAGMx+BVw1VwryBIYf9cCDHky8z0bxR89rjiIvPTBFI6MRhqI3vgpEBTySHDS+Ki0Hwl5oa3PwS6+jgYx/4RSfFsb+BawcvDk2Xpkt5UimvqZ5BceYLIfCt4KbShYipgLXLfYUZrntjPemd3SxthjxUuA07i44UxRdiC8uqy1twLT/HUS28gpk68lA/id9tKFwu1CUzshgcmvQPt3ghtNViNziR/2t7D/+5D31Vzmhf6n7Pnpdirt/5frMi2BKMMs7pLa0EF8CrrDU7QCwPav+EZVGFvVZbxSkCDq+n3IQ3PUWSCzy6KPxpdOlUjD0pAfLoiNj0P8u4+puQtID76r/St8ExchYl2dodUImu1ZETWeFUClF3ZGat62evx8uRQEI2W4dsVwj40VUfjaAuvyDzuouaKTrCzJXLQZZjR1B8URvuK61fGX0nhW607mEi6DE+nxP2ZoBrROEX4e37Ap6+TQn9Q8tKDPdcxtwSOpPO4Qkncjn/mGtP9lZU/DQ=");
//public final static SkinData CHISS = new SkinData("eyJ0aW1lc3RhbXAiOjE0NTk1NDI5NjgyNDEsInByb2ZpbGVJZCI6IjFkMmJmZTYxN2ViZDQ0NWRiYTdkODM1NGEwZmZkMWVhIiwicHJvZmlsZU5hbWUiOiJDaGlzcyIsInNpZ25hdHVyZVJlcXVpcmVkIjp0cnVlLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTg3MmNkMzRjY2IzMTIxYjRjNmEzOGFjM2JmOGVkM2UwMzk3YmQ2YTg4NDI4YjdhZmM2ZTUyNTI4NTVhMzQzIiwibWV0YWRhdGEiOnsibW9kZWwiOiJzbGltIn19fX0=", "hNTLRA2acZYx2dM90lnJN8FMK/ceD3+AxKNdD5FrXzxGtYL4C1Jr/vbTE0UosmwFP3wScNEW/fuDOjeZRjZHMJdvgDZMlMK/5KDhOY6sj/RS9RckztsgummSyjH/hdDn7TWWfhZLMbiia/K0VReI9eq2yD6zGQpvMlz5hB/5SX5YHWXvCah3TL4UzYSlSVDlwY/Q3sVuIZUr8m/LIXJwniJKLGo6tUgtiJd9eseOsbBpVjzCUtLD8A9WBe2/eODgmLfqEvXESIoDRG8vL2nPSXWma/YolYHIl32/i+ZxVD7dRRaXQFYSiLI24EtzX1pPhMjyaTLazP9abH43J6J31w02pKM7N/xTa62020L/YfRRKGT5lygEDb1NMoSpAjszPxah+Ra2/L+yUWEI8cMES6I4mIJ00tclPjWK01xhIn3tqg+y2gqsGHwPhu/7vmF5NirNfKFw0qciKNBfbCAF7ae+mkUKjmAPuvBUBqQb7BOcpNVWsCo/XvzmiZZYsf5P4Uwz8LqUK4uH6V/5dg7lY2Xg3+IUylsrDqLGFDI8iy/NdjIQMbuRadh4IDO6DcmxBri2Ax4JNBPBTnRezge8uq37MZcft/IXQgFWKB9RtidVEACaTOkRj27k+Ojnkki+j44k0wZB47hiXFUHMCHl3a0SVdQe15ZbVsQj/HAvAS0=");
//public final static SkinData DEFEK7 = new SkinData("eyJ0aW1lc3RhbXAiOjE0NTk1NDI3ODkwNTksInByb2ZpbGVJZCI6Ijg5ZDQ2M2Y3MjNlYzQ3MGE4MjQ0NDU3ZjBjOGQ4NjFjIiwicHJvZmlsZU5hbWUiOiJkZWZlazciLCJzaWduYXR1cmVSZXF1aXJlZCI6dHJ1ZSwidGV4dHVyZXMiOnsiU0tJTiI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlL2JmYWNjOWM4ZjhlY2E1OWU0NTE4MTUxZmE4OGFiMDZjOTFmNjM3OTE2NzJmMTRlNGYzODY3YTI2OTVlN2NmYmYifSwiQ0FQRSI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzIyYjljNWVhNzYzYzg2ZmM1Y2FlYTMzZDgyYjBmYTY1YTdjMjI4ZmQzMjFiYTU0NzY2ZWE5NWEzZDBiOTc5MyJ9fX0=", "jBoRvkhQXz+nap8yJJIZ+4HClMItWODumeSOYjXytP3WWKHK0UMq0xC/keXsnmvo89lMRdRbknPt2ZX5Flgyjgr4Rt0KtDvpL/hG4BUsTWryUZZMKxdd6DkZXYRtTogLUfHeDYIz+cZQ0aXGMtvX/ZYTXJfMi6FYbIHY/qEEDnWhDX5y+SPpaJaZByPsvzi+qbfcFGnJ6nqi9ccyZYnYpnI2IVBM/yO/VRXWHxfqvJ0VVvv5KsGmVbko2Jxo0SDCxUL2UTH2+eol53FxhkkC+m2geC14k1zsZQLHDF3BgAG9+kFJ4UEoYRKF2Gy1FxeDCJtjYNdrYR8fdaUKRMcpBgEs+ZGe2U9EVVS/ZcBCjB7S+1Ne2bPzPFzTQPuBoMgggo1xbxBmQ5NyhYo4gwgj/xjSLIhb+5h7ioN1URfSRcfYdVv6RRO9l/u9l09jEom8y/jGRviefpEr+/e9iAl5Dd/6nzQgosBQja3NSfqYZmyuet2eI9zu61CObDTpR6yaCbNgBe/lWofRfULdpJpgjb4UNTBom3q82FcCiOe02OekGPw4+YlilhICBhajF5JzN8FKAdqI1osDcX3KuJgikYIW3voNaOP5YN3GXgilJNdou20KFC8ICq68HglgX7/0rLrWKIEoswnINIM6HcJbQuXncVPwQhV6K34Hlt/Na60=");
private Property _skinProperty;

View File

@ -0,0 +1,126 @@
package mineplex.core.common.util;
import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.java.JavaPlugin;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
/**
* Utilities for interleaving Bukkit scheduler operations as
* intermediate and terminal operations in a {@link CompletionStage}
* pipeline.
* <p>
* Any {@link Function}s returned by methods are suitable for use
* in {@link CompletionStage#thenCompose(Function)}
*
* @see CompletableFuture#thenCompose(Function)
*/
public class BukkitFuture
{
private static final Plugin LOADING_PLUGIN = JavaPlugin.getProvidingPlugin(BukkitFuture.class);
private static void runBlocking(Runnable action)
{
Bukkit.getScheduler().runTask(LOADING_PLUGIN, action);
}
/**
* Finalize a {@link CompletionStage} by consuming its value
* on the main thread.
*
* @param action the {@link Consumer} to call on the main thread
* @return a {@link Function} to be passed as an argument to
* {@link CompletionStage#thenCompose(Function)}
* @see CompletableFuture#thenCompose(Function)
*/
public static <T> Function<T, CompletionStage<Void>> accept(Consumer<? super T> action)
{
return val ->
{
CompletableFuture<Void> future = new CompletableFuture<>();
runBlocking(() ->
{
action.accept(val);
future.complete(null);
});
return future;
};
}
/**
* Finalize a {@link CompletionStage} by executing code on the
* main thread after its completion.
*
* @param action the {@link Runnable} that will execute
* @return a {@link Function} to be passed as an argument to
* {@link CompletionStage#thenCompose(Function)}
* @see CompletableFuture#thenCompose(Function)
*/
public static <T> Function<T, CompletionStage<Void>> run(Runnable action)
{
return val ->
{
CompletableFuture<Void> future = new CompletableFuture<>();
runBlocking(() ->
{
action.run();
future.complete(null);
});
return future;
};
}
/**
* Transform a value contained within a {@link CompletionStage}
* by executing a mapping {@link Function} on the main thread.
*
* @param fn the {@link Function} used to transform the value
* @return a {@link Function} to be passed as an argument to
* {@link CompletionStage#thenCompose(Function)}
* @see CompletableFuture#thenCompose(Function)
*/
public static <T,U> Function<T, CompletionStage<U>> map(Function<? super T,? extends U> fn)
{
return val ->
{
CompletableFuture<U> future = new CompletableFuture<>();
runBlocking(() -> future.complete(fn.apply(val)));
return future;
};
}
/**
* Finalize a {@link CompletionStage} by executing code on the
* main thread after its normal or exceptional completion.
*
* @param action the {@link BiConsumer} that will execute
* @return a {@link BiConsumer} to be passed as an argument to
* {@link CompletionStage#whenComplete(BiConsumer)}
* @see CompletableFuture#whenComplete(BiConsumer)
*/
public static <T> BiConsumer<? super T,? super Throwable> complete(BiConsumer<? super T,? super Throwable> action)
{
return (val, throwable) -> runBlocking(() -> action.accept(val, throwable));
}
/**
* Create a {@link CompletionStage} from a supplier executed on the
* main thread.
*
* @param supplier the supplier to run on the main thread
* @return a {@link CompletionStage} whose value will be supplied
* during the next Minecraft tick
*/
public static <T> CompletionStage<T> supply(Supplier<T> supplier)
{
CompletableFuture<T> future = new CompletableFuture<>();
runBlocking(() -> future.complete(supplier.get()));
return future;
}
}

View File

@ -1,5 +1,6 @@
package mineplex.core.common.util;
import mineplex.core.common.CurrencyType;
import mineplex.core.common.Rank;
import java.util.LinkedList;
@ -200,6 +201,11 @@ public class F
return out;
}
public static String currency(CurrencyType type, int amount)
{
return type.getString(amount) + ChatColor.RESET + C.mBody;
}
public static String vowelAN(String word)
{
return word.toLowerCase().startsWith("a")

View File

@ -256,33 +256,36 @@ public class MapUtil
@SuppressWarnings({ "rawtypes" })
public static boolean ClearWorldReferences(String worldName)
{
HashMap regionfiles = (HashMap) RegionFileCache.a;
try
synchronized (RegionFileCache.class)
{
for (Iterator<Object> iterator = regionfiles.entrySet().iterator(); iterator.hasNext();)
{
Map.Entry e = (Map.Entry) iterator.next();
RegionFile file = (RegionFile) e.getValue();
HashMap regionfiles = (HashMap) RegionFileCache.a;
try
try
{
for (Iterator<Object> iterator = regionfiles.entrySet().iterator(); iterator.hasNext(); )
{
file.c();
iterator.remove();
}
catch (Exception ex)
{
ex.printStackTrace();
Map.Entry e = (Map.Entry) iterator.next();
RegionFile file = (RegionFile) e.getValue();
try
{
file.c();
iterator.remove();
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
}
}
catch (Exception ex)
{
System.out.println("Exception while removing world reference for '" + worldName + "'!");
ex.printStackTrace();
}
catch (Exception ex)
{
System.out.println("Exception while removing world reference for '" + worldName + "'!");
ex.printStackTrace();
}
return true;
return true;
}
}
public static BlockPosition getBlockPos(int x, int y, int z)

View File

@ -44,9 +44,9 @@ public class ProfileLoader
return profile;
}
private void addProperties(GameProfile profile)
public static boolean addProperties(GameProfile profile)
{
String uuid = getUUID(skinOwner);
String uuid = profile.getId().toString().replaceAll("-", "");
try
{
// Get the name from SwordPVP
@ -85,11 +85,15 @@ public class ProfileLoader
Bukkit.getLogger().log(Level.WARNING, "Failed to apply auth property", e);
}
}
return true;
}
catch (Exception e)
{
e.printStackTrace();
}
return false;
}
@SuppressWarnings("deprecation")

View File

@ -3,7 +3,6 @@ package mineplex.core.common.util;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Queue;
import org.bukkit.Location;
import org.bukkit.Material;
@ -28,9 +27,9 @@ import org.bukkit.inventory.meta.BannerMeta;
import org.bukkit.inventory.meta.SkullMeta;
import org.bukkit.material.Bed;
import mineplex.core.common.block.MultiBlockUpdaterAgent;
import net.minecraft.server.v1_8_R3.BlockPosition;
import net.minecraft.server.v1_8_R3.Blocks;
import net.minecraft.server.v1_8_R3.EnumDirection;
import net.minecraft.server.v1_8_R3.IBlockData;
import net.minecraft.server.v1_8_R3.Item;
import net.minecraft.server.v1_8_R3.MathHelper;
@ -92,6 +91,8 @@ public class UtilBlock
*/
public static HashSet<BlockFace> horizontals = new HashSet<>();
private static MultiBlockUpdaterAgent _quickChangeRecorder;
static
{
@ -604,14 +605,52 @@ public class UtilBlock
return getInBoundingBox(a, b, true);
}
public static ArrayList<Block> getInBoundingBox(Location a, Location b, boolean ignoreAir)
public static ArrayList<Block> getInBoundingBox(Location a, Location b, boolean ignoreAir) {
return getInBoundingBox(a, b, ignoreAir, false, true, true);
}
public static ArrayList<Block> getInBoundingBox(Location a, Location b, boolean ignoreAir, boolean hollow, boolean walls, boolean ceilfloor)
{
ArrayList<Block> blocks = new ArrayList<Block>();
for (int x = Math.min(a.getBlockX(), b.getBlockX()); x <= Math.max(a.getBlockX(), b.getBlockX()); x++)
for (int y = Math.min(a.getBlockY(), b.getBlockY()); y <= Math.max(a.getBlockY(), b.getBlockY()); y++)
for (int z = Math.min(a.getBlockZ(), b.getBlockZ()); z <= Math.max(a.getBlockZ(), b.getBlockZ()); z++)
int xmin = Math.min(a.getBlockX(), b.getBlockX());
int xmax = Math.max(a.getBlockX(), b.getBlockX());
int ymin = Math.min(a.getBlockY(), b.getBlockY());
int ymax = Math.max(a.getBlockY(), b.getBlockY());
int zmin = Math.min(a.getBlockZ(), b.getBlockZ());
int zmax = Math.max(a.getBlockZ(), b.getBlockZ());
for (int x = xmin; x <= xmax; x++)
for (int y = ymin; y <= ymax; y++)
for (int z = zmin; z <= zmax; z++)
{
if(hollow)
{
if(!(x == xmin || x == xmax || y == ymin || y == ymax || z == zmin || z == zmax)) continue;
}
if(!walls)
{
if(
(x == xmin || x == xmax) ||
(z == zmin || z == zmax)
)
{
continue;
}
}
if(!ceilfloor)
{
if(y == ymin || y == ymax)
{
continue;
}
}
Block block = a.getWorld().getBlockAt(x, y, z);
if (ignoreAir)
@ -619,7 +658,9 @@ public class UtilBlock
if (block.getType() != Material.AIR) blocks.add(block);
}
else
{
blocks.add(block);
}
}
return blocks;
@ -1466,6 +1507,39 @@ public class UtilBlock
return state.update(false, false);
}
/**
* See {@link #setQuick(World, int, int, int, int, byte)}
*/
public static void startQuickRecording()
{
if(_quickChangeRecorder != null)
{
_quickChangeRecorder.send();
_quickChangeRecorder.reset();
}
else
{
_quickChangeRecorder = new MultiBlockUpdaterAgent();
}
}
/**
* See {@link #setQuick(World, int, int, int, int, byte)}
*/
public static void stopQuickRecording()
{
if(_quickChangeRecorder == null) return;
_quickChangeRecorder.send();
_quickChangeRecorder.reset();
_quickChangeRecorder = null;
}
/**
* This doesn't send the block changes to the client. If you want to change lots of blocks and then send it to the player
* then do <code>startQuickRecording()</code> first. Change all the blocks you want. Then to send it do
* <code>stopQuickRecording()</code>. This will automatically send all the block changes to all relevant players.
*/
public static void setQuick(World world, int x, int y, int z, int type, byte data)
{
int cx = x >> 4;
@ -1475,10 +1549,18 @@ public class UtilBlock
world.loadChunk(cx, cz, true);
}
net.minecraft.server.v1_8_R3.Chunk chunk = ((CraftWorld) world).getHandle().getChunkAt(x >> 4, z >> 4);
WorldServer nmsWorld = ((CraftWorld) world).getHandle();
net.minecraft.server.v1_8_R3.Chunk chunk = nmsWorld.getChunkAt(x >> 4, z >> 4);
BlockPosition pos = new BlockPosition(x, y, z);
IBlockData ibd = net.minecraft.server.v1_8_R3.Block.getById(type).fromLegacyData(data);
chunk.a(pos, ibd);
nmsWorld.notify(pos);
// if(_quickChangeRecorder != null)
// {
// _quickChangeRecorder.addBlock(world.getBlockAt(x, y, z));
// }
}
/**
@ -1504,4 +1586,35 @@ public class UtilBlock
{
return boundless(origin.getLocation(), radius);
}
/**
* Gets the max distance this blocks bounding box extends in the given block face. E.g. stone have a max:min of 1:0 in all direction.
* Slabs have 0:1 in horizontal directions, but 0:0.5 or 0.5:1 depending on if it is top or bottom.
* @param block The block to test
* @param blockFace The direction to test in
* @return
*/
public static double getSize(Block block, BlockFace blockFace)
{
BlockPosition bpos = new BlockPosition(block.getX(), block.getY(), block.getZ());
net.minecraft.server.v1_8_R3.Block b = ((CraftWorld)block.getWorld()).getHandle().c(bpos);
switch (blockFace)
{
default:
case WEST:
return b.B(); //min-x
case EAST:
return b.C(); //max-x
case DOWN:
return b.D(); //min-y
case UP:
return b.E(); //max-y
case NORTH:
return b.F(); //min-z
case SOUTH:
return b.G(); //max-z
}
}
}

View File

@ -1,6 +1,13 @@
package mineplex.core.common.util;
import org.bukkit.ChatColor;
import org.bukkit.Color;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.LeatherArmorMeta;
import org.bukkit.util.Vector;
import javax.annotation.Nonnull;
/**
* Created by Shaun on 11/12/2014.
@ -13,6 +20,8 @@ public class UtilColor
public static final RGBData RgbLightRed = hexToRgb(0xeb1c1c);
public static final RGBData RgbPurple = hexToRgb(0x9c17a3);
public static final Color DEFAULT_LEATHER_COLOR = Color.fromRGB(160, 101, 64);
public static byte chatColorToClayData(ChatColor chatColor)
{
//TODO
@ -71,6 +80,52 @@ public class UtilColor
return 0;
}
}
public static ChatColor woolDataToChatColor(byte data)
{
switch (data)
{
case 0:
return ChatColor.WHITE;
case 1:
return ChatColor.GOLD;
case 2:
return ChatColor.DARK_PURPLE;
case 3:
return ChatColor.BLUE;
case 4:
return ChatColor.YELLOW;
case 5:
return ChatColor.GREEN;
case 6:
return ChatColor.LIGHT_PURPLE;
case 7:
return ChatColor.DARK_GRAY;
case 8:
return ChatColor.GRAY;
case 9:
return ChatColor.DARK_AQUA;
case 10:
return ChatColor.DARK_PURPLE;
case 11:
return ChatColor.DARK_BLUE;
case 12:
return ChatColor.DARK_RED;
case 13:
return ChatColor.DARK_GREEN;
case 14:
return ChatColor.RED;
case 15:
return ChatColor.BLACK;
default:
return ChatColor.WHITE;
}
}
public static Vector colorToVector(Color color)
{
return new Vector(Math.max(color.getRed()/255.0, 0.00001f), color.getGreen()/255.0, color.getBlue()/255.0);
}
public static RGBData hexToRgb(int hex)
{
@ -91,4 +146,73 @@ public class UtilColor
{
return new RGBData(r, g, b);
}
public static Color getNextColor(Color original, Color finalColor, int increment)
{
int red = original.getRed(), green = original.getGreen(), blue = original.getBlue();
if (red > finalColor.getRed())
red -= increment;
else if (red < finalColor.getRed())
red += increment;
else if (green > finalColor.getGreen())
green -= increment;
else if (green < finalColor.getGreen())
green += increment;
else if (blue > finalColor.getBlue())
blue -= increment;
else if (blue < finalColor.getBlue())
blue += increment;
red = UtilMath.clamp(red, 0, 255);
green = UtilMath.clamp(green, 0, 255);
blue = UtilMath.clamp(blue, 0, 255);
return Color.fromRGB(red, green, blue);
}
/**
* Applies Color to a Leather armor
* @param itemStack
* @param color
* @return ItemStack with color applied
*/
public static ItemStack applyColor(@Nonnull ItemStack itemStack, Color color)
{
switch (itemStack.getType())
{
case LEATHER_HELMET:
case LEATHER_CHESTPLATE:
case LEATHER_LEGGINGS:
case LEATHER_BOOTS:
LeatherArmorMeta leatherArmorMeta = (LeatherArmorMeta) itemStack.getItemMeta();
leatherArmorMeta.setColor(color);
itemStack.setItemMeta(leatherArmorMeta);
return itemStack;
default:
return itemStack;
}
}
/**
* Gets color from Leather armor
* @param itemStack
* @return Color of the item
*/
public static Color getItemColor(@Nonnull ItemStack itemStack)
{
switch (itemStack.getType())
{
case LEATHER_HELMET:
case LEATHER_CHESTPLATE:
case LEATHER_LEGGINGS:
case LEATHER_BOOTS:
LeatherArmorMeta leatherArmorMeta = (LeatherArmorMeta) itemStack.getItemMeta();
return leatherArmorMeta.getColor();
default:
return DEFAULT_LEATHER_COLOR;
}
}
}

View File

@ -258,6 +258,21 @@ public class UtilEnt
}
}
public static void addGoalSelector(Entity entity, int priority, PathfinderGoal goal)
{
try
{
if(((CraftEntity)entity).getHandle() instanceof EntityInsentient)
{
((EntityInsentient)((CraftEntity)entity).getHandle()).goalSelector.a(priority, goal);
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
public static void Rotate(LivingEntity entity, float yaw, float pitch)
{
EntityLiving handle = ((CraftLivingEntity) entity).getHandle();
@ -856,6 +871,11 @@ public class UtilEnt
{
return ent.getLocation().getBlock().getTypeId() == 8 || ent.getLocation().getBlock().getTypeId() == 9;
}
public static void setBoundingBox(Entity ent, double width, double height)
{
((CraftEntity)ent).getHandle().setSize((float) width, (float)height);
}
public static void SetMetadata(Entity entity, String key, Object value)
{
@ -879,4 +899,40 @@ public class UtilEnt
equipment.setItemInHand(item);
}
public static byte getEntityEggData(EntityType type)
{
switch (type)
{
case CREEPER: return (byte) 50;
case SKELETON: return (byte) 51;
case SPIDER: return (byte) 52;
case ZOMBIE: return (byte) 54;
case SLIME: return (byte) 55;
case GHAST: return (byte) 56;
case PIG_ZOMBIE: return (byte) 57;
case ENDERMAN: return (byte) 58;
case CAVE_SPIDER: return (byte) 59;
case SILVERFISH: return (byte) 60;
case BLAZE: return (byte) 61;
case MAGMA_CUBE: return (byte) 62;
case BAT: return (byte) 65;
case WITCH: return (byte) 66;
case ENDERMITE: return (byte) 67;
case GUARDIAN: return (byte) 68;
//case SHULKER: return (byte) 69;
case PIG: return (byte) 90;
case SHEEP: return (byte) 91;
case COW: return (byte) 92;
case CHICKEN: return (byte) 93;
case SQUID: return (byte) 94;
case WOLF: return (byte) 95;
case MUSHROOM_COW: return (byte) 96;
case OCELOT: return (byte) 98;
case HORSE: return (byte) 100;
case RABBIT: return (byte) 101;
case VILLAGER: return (byte) 120;
default: return 0;
}
}
}

View File

@ -108,4 +108,10 @@ public class UtilFirework
UtilMath.random.nextBoolean()
);
}
public static void playFreedomFirework(Location location)
{
playFirework(location, FireworkEffect.builder().withColor(Color.RED).withColor(Color.BLUE)
.withColor(Color.WHITE).withFade(Color.RED).withFade(Color.BLUE).withFade(Color.WHITE).build());
}
}

View File

@ -192,6 +192,13 @@ public class UtilGear
return item.getType() == mat;
}
public static boolean isMatAndData(ItemStack item, Material mat, byte data)
{
if (item == null) return false;
return item.getType() == mat && item.getData().getData() == data;
}
public static boolean isRepairable(ItemStack item)
{

View File

@ -19,7 +19,7 @@ import org.bukkit.inventory.PlayerInventory;
public class UtilInv
{
private static Field _enchantmentNew;
private static DullEnchantment _enchantment;
private static DullEnchantment DULL_ENCHANTMENT;
static
{
@ -29,8 +29,8 @@ public class UtilInv
_enchantmentNew.setAccessible(true);
_enchantmentNew.set(null, true);
_enchantment = new DullEnchantment();
EnchantmentWrapper.registerEnchantment(_enchantment);
DULL_ENCHANTMENT = new DullEnchantment();
EnchantmentWrapper.registerEnchantment(DULL_ENCHANTMENT);
}
catch (Exception e)
{
@ -40,17 +40,17 @@ public class UtilInv
public static void addDullEnchantment(ItemStack itemStack)
{
itemStack.addEnchantment(_enchantment, 1);
itemStack.addEnchantment(DULL_ENCHANTMENT, 1);
}
public static void removeDullEnchantment(ItemStack itemStack)
{
itemStack.removeEnchantment(_enchantment);
itemStack.removeEnchantment(DULL_ENCHANTMENT);
}
public static DullEnchantment getDullEnchantment()
{
return _enchantment;
return DULL_ENCHANTMENT;
}
@SuppressWarnings("deprecation")

View File

@ -9,13 +9,21 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.craftbukkit.v1_8_R3.inventory.CraftItemStack;
import org.bukkit.entity.Item;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.plugin.Plugin;
import org.bukkit.scheduler.BukkitRunnable;
import mineplex.core.common.structs.ItemContainer;
import net.minecraft.server.v1_8_R3.NBTTagCompound;
import net.minecraft.server.v1_8_R3.NBTTagLong;
public class UtilItem
{
@ -1147,6 +1155,66 @@ public class UtilItem
i.setItemMeta(im);
return i;
}
/**
*
* @param item The item stack to use as source for this Item entity
* @param loc Location of where to spawn the Item entity
* @param dropNaturaly If false then no velocity is applied. If true then it drops with random velocity like from when blocks break.
* @param allowPickup If false then it will disable pickup of this item.
* @param ticksToLive Ticks before this item should be removed from the ground. (default 6000 ticks = 5min, -1 to never remove it)
* @param allowMerge If false then the item will not merge with any other items.
* @return
*/
public static Item dropItem(ItemStack item, Location loc, boolean dropNaturaly, boolean allowPickup, int ticksToLive, boolean allowMerge)
{
Item ent;
if(dropNaturaly)
{
ent = loc.getWorld().dropItemNaturally(loc, item);
} else {
ent = loc.getWorld().dropItem(loc, item);
}
if(!allowPickup)
{
ent.setPickupDelay(32767);
}
ent.setTicksLived(32768);
UtilEnt.SetMetadata(ent, "UtilItemSpawning", true);
if(ticksToLive != -1)
{
Plugin plugin = Bukkit.getPluginManager().getPlugin("Hub");
if(plugin == null) plugin = Bukkit.getPluginManager().getPlugin("Arcade");
if(plugin == null) plugin = Bukkit.getPluginManager().getPlugins()[0];
new BukkitRunnable()
{
public void run()
{
ent.remove();
}
}.runTaskLater(plugin, ticksToLive);
}
if(!allowMerge)
{
net.minecraft.server.v1_8_R3.ItemStack stack = CraftItemStack.asNMSCopy(ent.getItemStack());
NBTTagCompound tag = stack.getTag();
if(!stack.hasTag())
{
stack.setTag(new NBTTagCompound());
tag = stack.getTag();
}
tag.set("Pickup_" + UtilMath.r(Integer.MAX_VALUE), new NBTTagLong(UtilMath.random.nextLong()));
ent.setItemStack(CraftItemStack.asBukkitCopy(stack));
}
return ent;
}
public static double getAttackDamage(Material type)
{

View File

@ -1,5 +1,6 @@
package mineplex.core.common.util;
import org.bukkit.Color;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.entity.Player;
@ -12,7 +13,26 @@ public class UtilParticle
{
public enum ViewDist
{
SHORT(8), NORMAL(24), LONG(48), LONGER(96), MAX(256);
/**
* 8 blocks
*/
SHORT(8),
/**
* 24 blocks
*/
NORMAL(24),
/**
* 48 blocks
*/
LONG(48),
/**
* 96 blocks
*/
LONGER(96),
/**
* 256 blocks
*/
MAX(256);
private int _dist;
@ -321,6 +341,21 @@ public class UtilParticle
{
PlayParticle(particle, location, offsetX, offsetY, offsetZ, speed, count, dist, UtilServer.getPlayers());
}
public static void playColoredParticle(Color color, ParticleType particleType, Location location, int count, ViewDist dist, Player... players)
{
if (particleType != ParticleType.RED_DUST
&& particleType != ParticleType.MOB_SPELL_AMBIENT)
return;
PlayParticle(particleType, location, color.getRed() / 255F, color.getGreen() / 255F, color.getBlue() / 255F, 1f, count, dist, players);
}
public static void playColoredParticleToAll(Color color, ParticleType particleType, Location location, int count, ViewDist dist)
{
if (particleType != ParticleType.RED_DUST
&& particleType != ParticleType.MOB_SPELL_AMBIENT)
return;
PlayParticleToAll(particleType, location, color.getRed() / 255F, color.getGreen() / 255F, color.getBlue() / 255F, 1f, count, dist);
}
}

View File

@ -1,15 +1,8 @@
package mineplex.core.common.util;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.UUID;
import java.util.*;
import net.minecraft.server.v1_8_R3.*;
import org.bukkit.ChatColor;
import org.bukkit.GameMode;
import org.bukkit.Location;
@ -29,17 +22,20 @@ import org.bukkit.util.Vector;
import mineplex.core.common.MinecraftVersion;
import mineplex.core.common.events.PlayerMessageEvent;
import net.minecraft.server.v1_8_R3.EntityPlayer;
import net.minecraft.server.v1_8_R3.Packet;
import net.minecraft.server.v1_8_R3.PlayerConnection;
public class UtilPlayer
{
private static Random RANDOM = new Random();
// A mapping of player names (Keys) to the system time when they last changed active Hotbar Slot
private static Map<String, Long> _hotbarUpdates = new HashMap<String, Long>();
private static Map<String, Long> _hotbarUpdates = new HashMap<>();
// A mapping of player UUIDs (Keys) to the world border they are using (if they are using)
private static final Map<UUID, WorldBorder> WORLD_BORDERS = new HashMap<>();
// A mapping of player UUIDs (Keys) to the list of command they're allowed
private static final Map<UUID, List<String>> ALLOWED_COMMANDS = new HashMap<>();
// The amount of time (in milliseconds) after changin hotbars that you can block
public static final long BLOCKING_HOTBAR_DELAY = 100;
@ -68,6 +64,38 @@ public class UtilPlayer
return true;
}
public static void hideFrom(Player player, Collection<Player> players) {
players.stream().forEach(p->p.hidePlayer(player));
}
public static void showFor(Player player, Collection<Player> players) {
players.stream().forEach(p->p.hidePlayer(player));
}
public static void hideFromAll(Player player, Collection<Player> except) {
UtilServer.getPlayersCollection().stream().filter(p->!except.contains(p)).forEach(p->p.hidePlayer(player));
}
public static void showForAll(Player player, Collection<Player> except) {
UtilServer.getPlayersCollection().stream().filter(p->!except.contains(p)).forEach(p->p.showPlayer(player));
}
public static void hideFrom(Player player, Player...players) {
hideFrom(player, Arrays.asList(players));
}
public static void showFor(Player player, Player...players) {
showFor(player, Arrays.asList(players));
}
public static void hideFromAll(Player player, Player...players) {
hideFromAll(player, Arrays.asList(players));
}
public static void showForAll(Player player, Player...players) {
showForAll(player, Arrays.asList(players));
}
public static boolean is1_9(Player player)
{
@ -823,6 +851,45 @@ public class UtilPlayer
((CraftPlayer) player).getHandle().setWingsDeployAt(distance);
}
/**
* Sets the world border red screen for a player
* @param player
* @param warningDistance
*/
public static void sendRedScreen(Player player, int warningDistance)
{
WorldBorder worldBorder = WORLD_BORDERS.computeIfAbsent(player.getUniqueId(), uuid -> new WorldBorder());
worldBorder.setCenter(player.getLocation().getX(), player.getLocation().getZ());
worldBorder.setSize(10000);
worldBorder.setWarningDistance(warningDistance);
PacketPlayOutWorldBorder packet = new PacketPlayOutWorldBorder(worldBorder, PacketPlayOutWorldBorder.EnumWorldBorderAction.INITIALIZE);
sendPacket(player, packet);
WORLD_BORDERS.put(player.getUniqueId(), worldBorder);
}
/**
* Checks if player has a WorldBorder object stored
* @param player
* @return true if WorldBorder object is stored for that player
*/
public static boolean hasWorldBorder(Player player)
{
return WORLD_BORDERS.containsKey(player.getUniqueId());
}
/**
* Removes player from world border map
* @param player
*/
public static void removeWorldBorder(Player player)
{
if (hasWorldBorder(player))
{
sendRedScreen(player, 0);
WORLD_BORDERS.remove(player.getUniqueId());
}
}
public static MinecraftVersion getVersion(Player player)
{
if (is1_9(player))
@ -830,4 +897,50 @@ public class UtilPlayer
return MinecraftVersion.Version1_8;
}
/**
* Allows player to run specific command
* @param player The player to be allowed
* @param command The command that will be allowed
*/
public static void allowCommand(Player player, String command)
{
List<String> commandList = new ArrayList<>();
if (ALLOWED_COMMANDS.containsKey(player.getUniqueId()))
commandList = ALLOWED_COMMANDS.get(player.getUniqueId());
if (!commandList.contains(command))
commandList.add(command);
ALLOWED_COMMANDS.put(player.getUniqueId(), commandList);
}
/**
* Disallows player to run specific command
* @param player The player to be disallowed
* @param command The command that will be disallowed
* @return True if player had command allowed
*/
public static boolean disallowCommand(Player player, String command)
{
if (!isCommandAllowed(player, command))
return false;
List<String> commandList = ALLOWED_COMMANDS.get(player.getUniqueId());
commandList.remove(command);
ALLOWED_COMMANDS.put(player.getUniqueId(), commandList);
return true;
}
public static boolean isCommandAllowed(Player player, String command)
{
if (!ALLOWED_COMMANDS.containsKey(player.getUniqueId()))
return false;
if (!ALLOWED_COMMANDS.get(player.getUniqueId()).contains(command))
return false;
return true;
}
public static void removeAllowedCommands(Player player)
{
if (ALLOWED_COMMANDS.containsKey(player.getUniqueId()))
ALLOWED_COMMANDS.remove(player.getUniqueId());
}
}

View File

@ -11,6 +11,7 @@ import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitRunnable;
import java.lang.reflect.Field;
@ -112,7 +113,7 @@ public class UtilServer
public static Plugin getPlugin()
{
return getPluginManager().getPlugins()[0];
return JavaPlugin.getProvidingPlugin(UtilServer.class);
}
public static PluginManager getPluginManager()
@ -196,4 +197,14 @@ public class UtilServer
{
return Lists.newArrayList(getPlayers());
}
public static boolean isTestServer()
{
return getPlugin().getConfig().getString("serverstatus.group").equalsIgnoreCase("Testing");
}
public static boolean isHubServer()
{
return getPlugin().getConfig().getString("serverstatus.group").equalsIgnoreCase("Lobby");
}
}

View File

@ -40,7 +40,8 @@ public class UtilSkull
if (displayHead)
meta.setOwner(playerName);
meta.setDisplayName(itemName);
meta.setLore(itemLore);
if (itemLore != null)
meta.setLore(itemLore);
skull.setItemMeta(meta);
return skull;
}

View File

@ -6,7 +6,6 @@ import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.UUID;
import javax.imageio.ImageIO;
@ -17,8 +16,10 @@ import mineplex.core.common.CurrencyType;
public class UtilText
{
private static HashMap<Character, Integer> _characters = new HashMap<Character, Integer>();
private static HashMap<Character, BufferedImage> _characterImages = new HashMap<Character, BufferedImage>();
private static HashMap<Character, Integer> _characters = new HashMap<>();
private static HashMap<Character, BufferedImage> _characterImages = new HashMap<>();
private final static char[] VOWELS = new char[]{'a', 'e', 'i', 'o', 'u'};
static
{
@ -286,12 +287,7 @@ public class UtilText
public static String[] splitLineToArray(String string, LineFormat lineFormat)
{
ArrayList<String> lineList = splitLine(string, lineFormat);
String[] lineArray = new String[lineList.size()];
lineArray = lineList.toArray(lineArray);
return lineArray;
return splitLinesToArray(string.split("\n"), lineFormat);
}
public static ArrayList<String> splitLine(String string, LineFormat lineFormat)
@ -308,7 +304,7 @@ public class UtilText
// Empty
if (string.equals("") || string.equals(" "))
{
strings.add(string);
strings.add(" ");
return strings;
}
@ -624,7 +620,20 @@ public class UtilText
public static boolean plural(int x)
{
return x <= 0 ? true : x > 1;
return x != 1;
}
public static String plural(String word, int amount)
{
if(!plural(amount)) return word;
String sufix = "s";
if(word.endsWith("s") || word.endsWith("x") || word.endsWith("z") || word.endsWith("ch")) sufix = "es";
else if(word.endsWith("y"))
{
word.substring(0, word.length()-2);
sufix = "ies";
}
return word + sufix;
}
public static String trim(int maxLength, String s)
@ -661,20 +670,25 @@ public class UtilText
{
return getProgress(prefix, amount, suffix, progressDirectionSwap, 24);
}
public static String getProgress(String prefix, double amount, String suffix, boolean progressDirectionSwap, int bars)
{
return getProgress(prefix, amount, suffix, progressDirectionSwap, bars, C.cRed, C.cGreen);
}
public static String getProgress(String prefix, double amount, String suffix, boolean progressDirectionSwap, int bars, String emptyColor, String fillColor)
{
if (progressDirectionSwap)
amount = 1 - amount;
//Generate Bar
String progressBar = C.cGreen + "";
String progressBar = fillColor + "";
boolean colorChange = false;
for (int i=0 ; i<bars ; i++)
{
if (!colorChange && (float)i/(float)bars >= amount)
{
progressBar += C.cRed;
progressBar += emptyColor;
colorChange = true;
}
@ -698,4 +712,59 @@ public class UtilText
return possesiveNoun.endsWith("s") ? possesiveNoun + "' " + noun : possesiveNoun + "'s " + noun;
}
public static boolean startsWithVowel(String word)
{
if(word == null || word.isEmpty()) return false;
char v = word.toLowerCase().charAt(0);
for(char c : VOWELS)
{
if(c == v) return true;
}
return false;
}
public static String getPronoun(String word)
{
return startsWithVowel(word) ? "an" : "a";
}
public static String prefixPronoun(String word)
{
return getPronoun(word) + " " + word;
}
/**
* Do a replaceAll on all strings in the array. It will replace the strings inside
* the given array. The returned array is the same instance as the one provided.
*/
public static String[] replaceAll(String[] array, String regex, String replacement)
{
if(array == null) return null;
for(int i = 0; i < array.length; i++)
{
if(array[i] == null) continue;
array[i] = array[i].replaceAll(regex, replacement);
}
return array;
}
public static String colorWords(String str, ChatColor... colors)
{
int c = 0, maxC = colors.length - 1;
StringBuilder stringBuilder = new StringBuilder();
for (String word : str.split(" "))
{
stringBuilder.append(colors[c]);
stringBuilder.append(word + " ");
if (c < maxC)
c++;
else
c = 0;
}
return stringBuilder.toString();
}
}

View File

@ -79,6 +79,11 @@ public class UtilTime
{
return _ms;
}
public static TimeUnit[] decreasingOrder()
{
return new TimeUnit[]{ DAYS, HOURS, MINUTES, SECONDS, MILLISECONDS };
}
}
/**
@ -121,6 +126,41 @@ public class UtilTime
{
return convertString(Math.max(0, time), trim, TimeUnit.FIT);
}
public static String convertColonString(long time)
{
return convertColonString(time, TimeUnit.HOURS, TimeUnit.SECONDS);
}
/**
* Converts a time into a colon separated string, displaying max to min units.
*
* @param time Time in milliseconds
* @param max The max {@link TimeUnit} to display, inclusive
* @param min The min {@link TimeUnit} to display, inclusive
* @return A colon separated string to represent the time
*/
public static String convertColonString(long time, TimeUnit max, TimeUnit min)
{
if (time == -1) return "Permanent";
else if (time == 0) return "0";
StringBuilder sb = new StringBuilder();
long curr = time;
for (TimeUnit unit : TimeUnit.decreasingOrder())
{
if (unit.getMilliseconds() >= min.getMilliseconds() && unit.getMilliseconds() <= max.getMilliseconds())
{
long amt = curr / unit.getMilliseconds();
if (amt < 10 && unit.getMilliseconds() != max.getMilliseconds()) sb.append('0'); // prefix single digit numbers with a 0
sb.append(amt);
if (unit.getMilliseconds() > min.getMilliseconds()) sb.append(':');
curr -= amt * unit.getMilliseconds();
}
}
return sb.toString();
}
public static String convertString(long time, int trim, TimeUnit type)
{
@ -140,7 +180,7 @@ public class UtilTime
{
if (type == TimeUnit.DAYS) text = (num = UtilMath.trim(trim, time / 86400000d)) + " Day";
else if (type == TimeUnit.HOURS) text = (num = UtilMath.trim(trim, time / 3600000d)) + " Hour";
else if (type == TimeUnit.MINUTES) text = (num = UtilMath.trim(trim, time / 60000d)) + " Minute";
else if (type == TimeUnit.MINUTES) text = (int) (num = (int) UtilMath.trim(trim, time / 60000d)) + " Minute";
else if (type == TimeUnit.SECONDS) text = (int) (num = (int) UtilMath.trim(trim, time / 1000d)) + " Second";
else text = (int) (num = (int) UtilMath.trim(trim, time)) + " Millisecond";
}

View File

@ -10,6 +10,8 @@ import org.bukkit.World.Environment;
import org.bukkit.WorldBorder;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.craftbukkit.v1_8_R3.entity.CraftEntity;
import org.bukkit.entity.Entity;
import org.bukkit.util.Vector;
import com.google.common.collect.Lists;
@ -28,7 +30,17 @@ public class UtilWorld
if (chunk == null)
return "";
return chunk.getWorld().getName() + "," + chunk.getX() + "," + chunk.getZ();
return chunkToStr(chunk.getWorld().getName(), chunk.getX(), chunk.getZ());
}
public static String chunkToStr(Location location)
{
return chunkToStr(location.getWorld().getName(), location.getBlockX() >> 4, location.getBlockZ() >> 4);
}
public static String chunkToStr(String world, int x, int z)
{
return world + "," + x + "," + z;
}
public static String chunkToStrClean(Chunk chunk)
@ -289,4 +301,15 @@ public class UtilWorld
return startX >= minX && startZ <= maxX && endX >= minZ && endZ <= maxZ;
}
public static double distanceSquared(Entity a, Entity b)
{
if (a.getWorld() != b.getWorld())
throw new IllegalArgumentException("Different worlds: " + a.getWorld().getName() + " and " + b.getWorld().getName());
net.minecraft.server.v1_8_R3.Entity entityA = ((CraftEntity) a).getHandle();
net.minecraft.server.v1_8_R3.Entity entityB = ((CraftEntity) b).getHandle();
double dx = entityA.locX - entityB.locX;
double dy = entityA.locY - entityB.locY;
double dz = entityA.locZ - entityB.locZ;
return (dx * dx) + (dy * dy) + (dz * dz);
}
}

View File

@ -53,6 +53,7 @@ public class WorldUtil
{
generator = server.getGenerator(name);
}
Convertable converter = new WorldLoaderServer(server.getWorldContainer());
if (converter.isConvertable(name))

View File

@ -0,0 +1,70 @@
package mineplex.core.common.util.banner;
import org.bukkit.DyeColor;
import org.bukkit.block.banner.Pattern;
import org.bukkit.block.banner.PatternType;
import org.bukkit.inventory.ItemStack;
public enum CountryFlag
{
Brazil(DyeColor.GREEN, new Pattern(DyeColor.YELLOW, PatternType.RHOMBUS_MIDDLE), new Pattern(DyeColor.BLUE, PatternType.CIRCLE_MIDDLE)),
Usa(DyeColor.RED, new Pattern(DyeColor.WHITE, PatternType.STRIPE_SMALL), new Pattern(DyeColor.BLUE, PatternType.SQUARE_TOP_RIGHT)),
Canada(DyeColor.WHITE, new Pattern(DyeColor.RED, PatternType.STRIPE_TOP), new Pattern(DyeColor.RED, PatternType.STRIPE_BOTTOM),
new Pattern(DyeColor.RED, PatternType.CIRCLE_MIDDLE)),
Uk(DyeColor.BLUE, new Pattern(DyeColor.WHITE, PatternType.STRIPE_DOWNLEFT), new Pattern(DyeColor.WHITE, PatternType.STRIPE_DOWNRIGHT),
new Pattern(DyeColor.RED, PatternType.STRAIGHT_CROSS), new Pattern(DyeColor.RED, PatternType.CROSS)),
Ireland(DyeColor.WHITE, new Pattern(DyeColor.LIME, PatternType.STRIPE_TOP), new Pattern(DyeColor.ORANGE, PatternType.STRIPE_BOTTOM)),
Spain(DyeColor.YELLOW, new Pattern(DyeColor.RED, PatternType.STRIPE_LEFT), new Pattern(DyeColor.RED, PatternType.STRIPE_RIGHT)),
Japan(DyeColor.WHITE, new Pattern(DyeColor.RED, PatternType.CIRCLE_MIDDLE)),
South_Sudan(DyeColor.WHITE, new Pattern(DyeColor.RED, PatternType.STRIPE_LEFT), new Pattern(DyeColor.BLACK, PatternType.STRIPE_RIGHT),
new Pattern(DyeColor.GREEN, PatternType.TRIANGLE_BOTTOM)),
Jamaica(DyeColor.GREEN, new Pattern(DyeColor.BLACK, PatternType.TRIANGLE_TOP), new Pattern(DyeColor.BLACK, PatternType.TRIANGLES_BOTTOM),
new Pattern(DyeColor.YELLOW, PatternType.CROSS)),
Italy(DyeColor.WHITE, new Pattern(DyeColor.RED, PatternType.STRIPE_TOP), new Pattern(DyeColor.GREEN, PatternType.STRIPE_BOTTOM)),
Senegal(DyeColor.YELLOW, new Pattern(DyeColor.RED, PatternType.STRIPE_TOP), new Pattern(DyeColor.GREEN, PatternType.STRIPE_BOTTOM),
new Pattern(DyeColor.GREEN, PatternType.CIRCLE_MIDDLE)),
France(DyeColor.WHITE, new Pattern(DyeColor.RED, PatternType.STRIPE_TOP), new Pattern(DyeColor.BLUE, PatternType.STRIPE_BOTTOM)),
India(DyeColor.WHITE, new Pattern(DyeColor.ORANGE, PatternType.STRIPE_LEFT), new Pattern(DyeColor.GREEN, PatternType.STRIPE_RIGHT),
new Pattern(DyeColor.BLUE, PatternType.CIRCLE_MIDDLE)),
Belgium(DyeColor.YELLOW, new Pattern(DyeColor.BLACK, PatternType.STRIPE_BOTTOM), new Pattern(DyeColor.RED, PatternType.STRIPE_TOP)),
England(DyeColor.WHITE, new Pattern(DyeColor.RED, PatternType.STRAIGHT_CROSS)),
Austria(DyeColor.RED, new Pattern(DyeColor.WHITE, PatternType.STRIPE_CENTER)),
Armenia(DyeColor.RED, new Pattern(DyeColor.BLUE, PatternType.STRIPE_CENTER), new Pattern(DyeColor.ORANGE, PatternType.STRIPE_RIGHT)),
Argentina(DyeColor.LIGHT_BLUE, new Pattern(DyeColor.WHITE, PatternType.STRIPE_CENTER), new Pattern(DyeColor.YELLOW, PatternType.CIRCLE_MIDDLE)),
Greece(DyeColor.LIGHT_BLUE, new Pattern(DyeColor.WHITE, PatternType.STRIPE_SMALL), new Pattern(DyeColor.LIGHT_BLUE, PatternType.SQUARE_BOTTOM_LEFT)),
Czech_Republic(DyeColor.WHITE, new Pattern(DyeColor.RED, PatternType.HALF_VERTICAL_MIRROR), new Pattern(DyeColor.BLUE, PatternType.TRIANGLE_BOTTOM)),
Romania(DyeColor.YELLOW, new Pattern(DyeColor.BLUE, PatternType.STRIPE_BOTTOM), new Pattern(DyeColor.RED, PatternType.STRIPE_TOP)),
Honduras(DyeColor.WHITE, new Pattern(DyeColor.BLUE, PatternType.STRIPE_LEFT), new Pattern(DyeColor.BLUE, PatternType.STRIPE_RIGHT)),
Algeria(DyeColor.WHITE, new Pattern(DyeColor.LIME, PatternType.HALF_HORIZONTAL_MIRROR), new Pattern(DyeColor.RED, PatternType.CIRCLE_MIDDLE)),
Portugal(DyeColor.RED, new Pattern(DyeColor.GREEN, PatternType.STRIPE_TOP), new Pattern(DyeColor.YELLOW, PatternType.CIRCLE_MIDDLE)),
Bahrain(DyeColor.RED, new Pattern(DyeColor.WHITE, PatternType.TRIANGLES_BOTTOM)),
Germany(DyeColor.RED, new Pattern(DyeColor.BLACK, PatternType.STRIPE_LEFT), new Pattern(DyeColor.YELLOW, PatternType.STRIPE_RIGHT)),
Gabon(DyeColor.YELLOW, new Pattern(DyeColor.BLUE, PatternType.STRIPE_RIGHT), new Pattern(DyeColor.LIME, PatternType.STRIPE_LEFT)),
Scotland(DyeColor.BLUE, new Pattern(DyeColor.WHITE, PatternType.CROSS)),
Peru(DyeColor.WHITE, new Pattern(DyeColor.RED, PatternType.STRIPE_TOP), new Pattern(DyeColor.RED, PatternType.STRIPE_BOTTOM)),
Tanzania(DyeColor.LIME, new Pattern(DyeColor.LIGHT_BLUE, PatternType.DIAGONAL_RIGHT), new Pattern(DyeColor.BLACK, PatternType.STRIPE_DOWNLEFT)),
Morocco(DyeColor.RED, new Pattern(DyeColor.GREEN, PatternType.CIRCLE_MIDDLE)),
Solomon_Islands(DyeColor.GREEN, new Pattern(DyeColor.BLUE, PatternType.DIAGONAL_LEFT_MIRROR), new Pattern(DyeColor.YELLOW, PatternType.STRIPE_DOWNRIGHT)),
Switzerland(DyeColor.RED, new Pattern(DyeColor.WHITE, PatternType.STRAIGHT_CROSS), new Pattern(DyeColor.RED, PatternType.STRIPE_BOTTOM),
new Pattern(DyeColor.RED, PatternType.STRIPE_TOP)),
Finland(DyeColor.BLUE, new Pattern(DyeColor.WHITE, PatternType.SQUARE_BOTTOM_LEFT), new Pattern(DyeColor.WHITE, PatternType.SQUARE_BOTTOM_RIGHT),
new Pattern(DyeColor.WHITE, PatternType.HALF_HORIZONTAL), new Pattern(DyeColor.BLUE, PatternType.STRIPE_CENTER)),
South_Africa(DyeColor.WHITE, new Pattern(DyeColor.BLUE, PatternType.HALF_VERTICAL_MIRROR), new Pattern(DyeColor.RED, PatternType.HALF_VERTICAL),
new Pattern(DyeColor.GREEN, PatternType.STRIPE_CENTER), new Pattern(DyeColor.BLACK, PatternType.TRIANGLE_BOTTOM)),
Poland(DyeColor.RED, new Pattern(DyeColor.WHITE, PatternType.HALF_VERTICAL_MIRROR));
private DyeColor _baseColor;
private Pattern[] _patterns;
CountryFlag(DyeColor baseColor, Pattern... patterns){
_baseColor = baseColor;
_patterns = patterns;
}
public ItemStack getBanner()
{
return UtilBanner.createBanner(_baseColor, _patterns);
}
}

View File

@ -0,0 +1,25 @@
package mineplex.core.common.util.banner;
import org.bukkit.DyeColor;
import org.bukkit.Material;
import org.bukkit.block.banner.Pattern;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.BannerMeta;
public class UtilBanner
{
public static ItemStack createBanner(DyeColor baseColor, Pattern... patterns)
{
ItemStack banner = new ItemStack(Material.BANNER);
BannerMeta bannerMeta = (BannerMeta) banner.getItemMeta();
bannerMeta.setBaseColor(baseColor);
for (Pattern pattern : patterns)
{
bannerMeta.addPattern(pattern);
}
banner.setItemMeta(bannerMeta);
return banner;
}
}

View File

@ -0,0 +1,56 @@
package mineplex.core.common.util.particles;
import mineplex.core.common.util.UtilParticle;
import mineplex.core.common.util.UtilServer;
import org.bukkit.Location;
import org.bukkit.entity.Player;
public class ColoredParticle extends ParticleData
{
private ParticleColor _color;
public ColoredParticle(UtilParticle.ParticleType particleType, ParticleColor color, Location location)
{
super(particleType, location);
if ((particleType == UtilParticle.ParticleType.RED_DUST || particleType == UtilParticle.ParticleType.MOB_SPELL_AMBIENT)
&& !(color instanceof DustSpellColor))
throw new IllegalArgumentException("RED_DUST and MOB_SPELL_AMBIENT particle types require a DustSpellColor!");
else if(particleType == UtilParticle.ParticleType.NOTE && !(color instanceof NoteColor))
throw new IllegalArgumentException("NOTE particle type requires a NoteColor!");
else if(particleType != UtilParticle.ParticleType.RED_DUST && particleType != UtilParticle.ParticleType.MOB_SPELL_AMBIENT
&& particleType != UtilParticle.ParticleType.NOTE)
throw new IllegalArgumentException("Particle Type must be RED_DUST, MOB_SPELL_AMBIENT!");
_particleType = particleType;
_color = color;
_location = location;
}
@Override
public void display(UtilParticle.ViewDist viewDist, Player... players)
{
float x = _color.getX();
if (_particleType == UtilParticle.ParticleType.RED_DUST && x == 0)
x = Float.MIN_NORMAL;
UtilParticle.PlayParticle(_particleType, _location, x, _color.getY(), _color.getZ(), 1, 0, viewDist, players);
}
@Override
public void display(UtilParticle.ViewDist viewDist)
{
display(viewDist, UtilServer.getPlayers());
}
@Override
public void display()
{
display(UtilParticle.ViewDist.NORMAL);
}
public void setColor(ParticleColor color)
{
_color = color;
}
}

View File

@ -0,0 +1,39 @@
package mineplex.core.common.util.particles;
import java.awt.*;
public class DustSpellColor extends ParticleColor
{
private int _red, _green, _blue;
public DustSpellColor(Color color)
{
_red = color.getRed();
_green = color.getGreen();
_blue = color.getBlue();
}
public DustSpellColor(int r, int g, int b)
{
_red = r;
_green = g;
_blue = b;
}
public float getX()
{
return (float) _red / 255f;
}
public float getY()
{
return (float) _green / 255f;
}
public float getZ()
{
return (float) _blue / 255f;
}
}

View File

@ -0,0 +1,14 @@
package mineplex.core.common.util.particles;
import mineplex.core.common.util.UtilParticle;
import org.bukkit.Location;
public class NormalParticle extends ParticleData
{
public NormalParticle(UtilParticle.ParticleType particleType, Location location)
{
super(particleType, location);
}
}

View File

@ -0,0 +1,39 @@
package mineplex.core.common.util.particles;
import java.awt.*;
public class NoteColor extends ParticleColor
{
private int _red, _green, _blue;
public NoteColor(Color color)
{
_red = color.getRed();
_green = color.getGreen();
_blue = color.getBlue();
}
public NoteColor(int r, int g, int b)
{
_red = r;
_green = g;
_blue = b;
}
public float getX()
{
return (float) _red / 24f;
}
public float getY()
{
return 0f;
}
public float getZ()
{
return 0f;
}
}

View File

@ -0,0 +1,14 @@
package mineplex.core.common.util.particles;
import java.awt.*;
public abstract class ParticleColor
{
public abstract float getX();
public abstract float getY();
public abstract float getZ();
}

View File

@ -0,0 +1,57 @@
package mineplex.core.common.util.particles;
import mineplex.core.common.util.UtilParticle;
import mineplex.core.common.util.UtilServer;
import org.bukkit.Location;
import org.bukkit.entity.Player;
public class ParticleData
{
protected UtilParticle.ParticleType _particleType;
protected Location _location;
public ParticleData(UtilParticle.ParticleType particleType, Location location)
{
_particleType = particleType;
_location = location;
}
/**
* Displays the particles for selected players
* @param viewDist The distance of the particle view
* @param players The players that will receive the particle
*/
public void display(UtilParticle.ViewDist viewDist, Player... players)
{
UtilParticle.PlayParticle(_particleType, _location, 0f, 0f, 0f, 0f, 1, viewDist);
}
/**
* Displays the particles for all the players
* @param viewDist The distance of the particle view
*/
public void display(UtilParticle.ViewDist viewDist)
{
display(viewDist, UtilServer.getPlayers());
}
/**
* Displays the particles for all the players, with a NORMAL view distance
*/
public void display()
{
display(UtilParticle.ViewDist.NORMAL);
}
public void setLocation(Location location)
{
_location = location;
}
public Location getLocation()
{
return _location;
}
}

View File

@ -0,0 +1,24 @@
package mineplex.core.common.util.worldgen;
import java.util.Random;
import org.bukkit.World;
import org.bukkit.generator.ChunkGenerator;
/**
* A simple clean room void chunk generator
*/
public class WorldGenCleanRoom extends ChunkGenerator
{
/**
* Creates a clean void chunk with no blocks
*/
@Override
public ChunkData generateChunkData(World world, Random random, int x, int z, BiomeGrid biome)
{
return createChunkData(world);
}
}

View File

@ -1,57 +1,59 @@
package mineplex.core.common.weight;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
import java.util.stream.Collectors;
public class WeightSet<T>
{
private static Random random = new Random();
private Set<Weight<T>> _weights;
private Set<Weight<T>> _weights = new HashSet<Weight<T>>();
private volatile transient Set<T> _keyset;
public WeightSet()
{
_weights = new HashSet<Weight<T>>();
}
@SafeVarargs
public WeightSet(Weight<T>... weights)
{
this();
for (Weight<T> weight : weights)
{
_weights.add(weight);
}
computeKeyset();
}
@SafeVarargs
public WeightSet(T... elements)
{
this();
for (T element : elements)
{
_weights.add(new Weight<T>(1, element)); // Constant weight of 1 means all elements are equally likely
}
computeKeyset();
}
public WeightSet(Collection<T> elements)
{
this();
for (T element : elements)
{
_weights.add(new Weight<T>(1, element)); // Constant weight of 1 means all elements are equally likely
}
computeKeyset();
}
public void add(int weight, T element)
{
_weights.add(new Weight<T>(weight, element));
computeKeyset();
}
private int getTotalWeight()
@ -87,13 +89,11 @@ public class WeightSet<T>
public Set<T> elements()
{
Set<T> elements = new HashSet<T>();
for (Weight<T> weight : _weights)
{
elements.add(weight.getValue());
}
return elements;
return this._keyset;
}
private void computeKeyset()
{
_keyset = Collections.unmodifiableSet(_weights.stream().map(Weight::getValue).collect(Collectors.toSet()));
}
}

View File

@ -23,7 +23,6 @@ import net.minecraft.server.v1_8_R3.Entity;
import net.minecraft.server.v1_8_R3.EntityArmorStand;
import net.minecraft.server.v1_8_R3.Packet;
import net.minecraft.server.v1_8_R3.PacketPlayInUseEntity;
import net.minecraft.server.v1_8_R3.PacketPlayInUseEntity.EnumEntityUseAction;
import net.minecraft.server.v1_8_R3.PacketPlayOutAttachEntity;
import net.minecraft.server.v1_8_R3.PacketPlayOutEntityDestroy;
import net.minecraft.server.v1_8_R3.PacketPlayOutEntityMetadata;
@ -59,7 +58,7 @@ public class CustomTagFix extends MiniPlugin implements IPacketHandler, NCPHook
private NautHashMap<String, NautHashMap<Integer, Integer>> _entityRiding = new NautHashMap<String, NautHashMap<Integer, Integer>>();
private HashSet<String> _loggedIn = new HashSet<String>();
private HashSet<Integer> _ignoreSkulls = new HashSet<Integer>();
private HashSet<Integer> _ignoreIds = new HashSet<Integer>();
private NautHashMap<UUID, Long> _exemptTimeMap = new NautHashMap<UUID, Long>();
private NautHashMap<UUID, NautHashMap<CheckType, Long>> _doubleStrike = new NautHashMap<UUID, NautHashMap<CheckType, Long>>();
@ -220,12 +219,11 @@ public class CustomTagFix extends MiniPlugin implements IPacketHandler, NCPHook
PacketPlayOutSpawnEntityLiving spawnPacket = (PacketPlayOutSpawnEntityLiving) packet;
// Ignore Armor stand packets
if (spawnPacket.b == EntityType.ARMOR_STAND.getTypeId() || spawnPacket.l == null || spawnPacket.l.c() == null
|| spawnPacket.a == 777777)
if (spawnPacket.b == EntityType.ARMOR_STAND.getTypeId() || spawnPacket.l == null || spawnPacket.l.c() == null)
{
if (spawnPacket.b == EntityType.ARMOR_STAND.getTypeId())
{
_ignoreSkulls.add(spawnPacket.a);
_ignoreIds.add(spawnPacket.a);
}
return;
@ -322,7 +320,7 @@ public class CustomTagFix extends MiniPlugin implements IPacketHandler, NCPHook
{
PacketPlayOutEntityMetadata metaPacket = (PacketPlayOutEntityMetadata) packet;
if (metaPacket.a != 777777 && !_ignoreSkulls.contains(metaPacket.a) && metaPacket.a != owner.getEntityId())
if (metaPacket.a != 777777 && !_ignoreIds.contains(metaPacket.a) && metaPacket.a != owner.getEntityId())
{
boolean isDisplaying = _entityMap.get(owner.getName()).containsKey(metaPacket.a);
String currentName = _entityNameMap.get(owner.getName()).get(metaPacket.a);
@ -423,9 +421,9 @@ public class CustomTagFix extends MiniPlugin implements IPacketHandler, NCPHook
else if (packet instanceof PacketPlayOutSpawnEntity)
{
PacketPlayOutSpawnEntity spawnPacket = (PacketPlayOutSpawnEntity) packet;
if (spawnPacket.j == 66 && spawnPacket.a != 777777)
if (spawnPacket.j == 78) // Armor Stand Object ID
{
_ignoreSkulls.add(spawnPacket.a);
_ignoreIds.add(spawnPacket.a);
}
}
else if (packet instanceof PacketPlayInUseEntity)

View File

@ -1,8 +1,5 @@
package mineplex.core;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.bukkit.Bukkit;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
@ -99,12 +96,12 @@ public abstract class MiniPlugin implements Listener
public final void addCommand(ICommand command)
{
CommandCenter.Instance.AddCommand(command);
CommandCenter.Instance.addCommand(command);
}
public final void removeCommand(ICommand command)
{
CommandCenter.Instance.RemoveCommand(command);
CommandCenter.Instance.removeCommand(command);
}
public void log(String message)

View File

@ -491,7 +491,7 @@ public class CoreClientManager extends MiniPlugin
}
}
@EventHandler(priority = EventPriority.HIGHEST)
@EventHandler(priority = EventPriority.MONITOR)
public void Quit(PlayerQuitEvent event)
{
// When an account is logged in to this server and the same account name logs in

View File

@ -38,7 +38,7 @@ public class TestRank extends CommandBase<CoreClientManager>
if (args == null)
{
UtilPlayer.message(caller, F.main(Plugin.getName(), "/" + AliasUsed + " MODERATOR"));
UtilPlayer.message(caller, F.main(Plugin.getName(), "/" + _aliasUsed + " MODERATOR"));
}
else
{

View File

@ -30,7 +30,7 @@ public class UpdateRank extends CommandBase<CoreClientManager>
{
if (args == null)
{
UtilPlayer.message(caller, F.main(Plugin.getName(), "/" + AliasUsed + " joeschmo MODERATOR"));
UtilPlayer.message(caller, F.main(Plugin.getName(), "/" + _aliasUsed + " joeschmo MODERATOR"));
}
else
{

View File

@ -1,33 +1,26 @@
package mineplex.core.achievement;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.SkullMeta;
import mineplex.core.MiniPlugin;
import mineplex.core.account.CoreClientManager;
import mineplex.core.achievement.command.StatsCommand;
import mineplex.core.achievement.ui.AchievementShop;
import mineplex.core.common.Rank;
import mineplex.core.common.util.C;
import mineplex.core.common.util.NautHashMap;
import mineplex.core.common.util.UtilGear;
import mineplex.core.common.util.UtilInv;
import mineplex.core.common.util.UtilPlayer;
import mineplex.core.donation.DonationManager;
import mineplex.core.elo.EloManager;
import mineplex.core.itemstack.ItemStackFactory;
import mineplex.core.incognito.IncognitoManager;
import mineplex.core.stats.StatsManager;
import mineplex.core.stats.event.StatChangeEvent;
public class AchievementManager extends MiniPlugin
{
private IncognitoManager _incognitoManager;
private StatsManager _statsManager;
private EloManager _eloManager;
@ -39,10 +32,11 @@ public class AchievementManager extends MiniPlugin
private boolean _shopEnabled = true;
public AchievementManager(StatsManager statsManager, CoreClientManager clientManager, DonationManager donationManager, EloManager eloManager)
public AchievementManager(StatsManager statsManager, CoreClientManager clientManager, DonationManager donationManager, IncognitoManager incognitoManager, EloManager eloManager)
{
super("Achievement Manager", statsManager.getPlugin());
_incognitoManager = incognitoManager;
_statsManager = statsManager;
_eloManager = eloManager;
_shop = new AchievementShop(this, _statsManager, clientManager, donationManager, "Achievement");
@ -221,4 +215,9 @@ public class AchievementManager extends MiniPlugin
{
_shopEnabled = var;
}
public IncognitoManager getIncognito()
{
return _incognitoManager;
}
}

View File

@ -5,6 +5,8 @@ import org.bukkit.entity.Player;
import mineplex.core.achievement.AchievementManager;
import mineplex.core.command.CommandBase;
import mineplex.core.common.Rank;
import mineplex.core.common.util.C;
import mineplex.core.common.util.F;
import mineplex.core.common.util.UtilPlayer;
public class StatsCommand extends CommandBase<AchievementManager>
@ -29,6 +31,14 @@ public class StatsCommand extends CommandBase<AchievementManager>
{
return;
}
if (/* StaffServer special case */Plugin.getIncognito() != null && Plugin.getIncognito().Get(target).Hidden)
{
UtilPlayer.message(caller,
F.main("Online Player Search", "" + C.mCount + "0" + C.mBody + " matches for [" + C.mElem
+ args[0] + C.mBody + "]."));
return;
}
Plugin.openShop(caller, target);
}

View File

@ -54,22 +54,28 @@ public class Blood extends MiniPlugin
@EventHandler(priority = EventPriority.MONITOR)
public void display(BloodEvent event)
{
for (int i = 0 ; i < event.getParticles() ; i++)
if(event.isCancelled()) return;
if(event.getMaterial() != null && event.getMaterial() != Material.AIR)
{
Item item = event.getLocation().getWorld().dropItem(event.getLocation(),
new ItemBuilder(event.getMaterial(), 1, event.getMaterialData()).setTitle("" + System.nanoTime()).build());
item.setVelocity(new Vector((Math.random() - 0.5)*event.getVelocityMult(),Math.random()*event.getVelocityMult(),(Math.random() - 0.5)*event.getVelocityMult()));
item.setPickupDelay(999999);
_blood.put(item, event.getTicks());
for (int i = 0 ; i < event.getParticles() ; i++)
{
Item item = event.getLocation().getWorld().dropItem(event.getLocation(),
new ItemBuilder(event.getMaterial(), 1, event.getMaterialData()).setTitle("" + System.nanoTime()).build());
item.setVelocity(new Vector((Math.random() - 0.5)*event.getVelocityMult(),Math.random()*event.getVelocityMult(),(Math.random() - 0.5)*event.getVelocityMult()));
item.setPickupDelay(999999);
_blood.put(item, event.getTicks());
}
}
if (event.getBloodStep())
event.getLocation().getWorld().playEffect(event.getLocation(), Effect.STEP_SOUND, 55);
event.getLocation().getWorld().playSound(event.getLocation(), event.getSound(), event.getSoundVolume(), event.getSoundPitch());
if(event.getSound() != null)
event.getLocation().getWorld().playSound(event.getLocation(), event.getSound(), event.getSoundVolume(), event.getSoundPitch());
}
@EventHandler

View File

@ -14,6 +14,7 @@ import mineplex.core.bonuses.gui.BonusGui;
import mineplex.core.bonuses.gui.SpinGui;
import mineplex.core.bonuses.redis.VoteHandler;
import mineplex.core.bonuses.redis.VotifierCommand;
import mineplex.core.boosters.BoosterManager;
import mineplex.core.common.Rank;
import mineplex.core.common.util.*;
import mineplex.core.common.util.UtilParticle.ParticleType;
@ -21,6 +22,7 @@ import mineplex.core.common.util.UtilParticle.ViewDist;
import mineplex.core.donation.DonationManager;
import mineplex.core.donation.GiveDonorData;
import mineplex.core.facebook.FacebookManager;
import mineplex.core.gadget.GadgetManager;
import mineplex.core.hologram.Hologram;
import mineplex.core.hologram.HologramManager;
import mineplex.core.inventory.ClientItem;
@ -36,6 +38,7 @@ import mineplex.core.status.ServerStatusManager;
import mineplex.core.treasure.TreasureType;
import mineplex.core.updater.UpdateType;
import mineplex.core.updater.event.UpdateEvent;
import mineplex.core.youtube.YoutubeManager;
import mineplex.database.Tables;
import mineplex.database.tables.records.BonusRecord;
import mineplex.serverdata.commands.ServerCommandManager;
@ -119,6 +122,8 @@ public class BonusManager extends MiniClientPlugin<BonusClientData> implements I
private RewardManager _rewardManager;
private StatsManager _statsManager;
private FacebookManager _facebookManager;
private YoutubeManager _youtubeManager;
private BoosterManager _boosterManager;
public boolean _enabled;
private Npc _carlNpc;
private AnimationCarl _animation;
@ -157,7 +162,7 @@ public class BonusManager extends MiniClientPlugin<BonusClientData> implements I
updateOffSet();
}
public BonusManager(JavaPlugin plugin, CoreClientManager clientManager, ServerStatusManager statusManager, DonationManager donationManager, PollManager pollManager, NpcManager npcManager, HologramManager hologramManager, StatsManager statsManager, InventoryManager inventoryManager, PetManager petManager, FacebookManager facebookManager)
public BonusManager(JavaPlugin plugin, CoreClientManager clientManager, ServerStatusManager statusManager, DonationManager donationManager, PollManager pollManager, NpcManager npcManager, HologramManager hologramManager, StatsManager statsManager, InventoryManager inventoryManager, PetManager petManager, FacebookManager facebookManager, YoutubeManager youtubeManager, GadgetManager gadgetManager, BoosterManager boosterManager)
{
super("Bonus", plugin);
_repository = new BonusRepository(plugin, this, donationManager);
@ -166,17 +171,14 @@ public class BonusManager extends MiniClientPlugin<BonusClientData> implements I
_npcManager = npcManager;
_hologramManager = hologramManager;
_inventoryManager = inventoryManager;
_boosterManager = boosterManager;
_rewardManager = new RewardManager(clientManager, statusManager, donationManager, inventoryManager, petManager, statsManager,
100, 250,
500, 1000,
4000, 6000,
12000, 32000,
true, true);
_rewardManager = new RewardManager(_clientManager, _donationManager, _inventoryManager, petManager, statsManager, gadgetManager);
_pollManager = pollManager;
_statsManager = statsManager;
_facebookManager = facebookManager;
_youtubeManager = youtubeManager;
_voteList = new ArrayList<String>();
_voteList.add("http://vote1.mineplex.com");
@ -415,6 +417,7 @@ public class BonusManager extends MiniClientPlugin<BonusClientData> implements I
public static final long DAILY_STREAK_RESET_TIME = 1000 * 60 * 60 * 12;
public static final long VOTE_STREAK_RESET_TIME = 1000 * 60 * 60 * 24;
public void attemptDailyBonus(final Player player, final BonusAmount amount, final Callback<Boolean> result)
{
if (timeTillDailyBonus(player) > 0)
@ -824,7 +827,7 @@ public class BonusManager extends MiniClientPlugin<BonusClientData> implements I
if (entity.equals(_carlNpc.getEntity()))
{
updateDailyStreak(event.getPlayer());
new BonusGui(_plugin, event.getPlayer(), this, _rewardManager, _facebookManager).openInventory();
new BonusGui(_plugin, event.getPlayer(), this, _rewardManager, _facebookManager, _youtubeManager, _boosterManager).openInventory();
}
}
@ -840,7 +843,7 @@ public class BonusManager extends MiniClientPlugin<BonusClientData> implements I
if (event.getEntity().equals(_carlNpc.getEntity()))
{
updateDailyStreak(player);
new BonusGui(_plugin, player, this, _rewardManager, _facebookManager).openInventory();
new BonusGui(_plugin, player, this, _rewardManager, _facebookManager, _youtubeManager, _boosterManager).openInventory();
}
}
}
@ -902,17 +905,23 @@ public class BonusManager extends MiniClientPlugin<BonusClientData> implements I
int availableRewards = 0;
if (canVote(player)) availableRewards++;
if (_youtubeManager.canYoutube(player)) availableRewards++;
if (canRank(player) && _clientManager.hasRank(player, Rank.ULTRA) && isPastAugust()) availableRewards++;
if (canDaily(player)) availableRewards++;
if (getPollManager().getNextPoll(_pollManager.Get(player), _clientManager.Get(player).GetRank()) != null) availableRewards++;
if (!_facebookManager.hasRedeemed(player)) availableRewards++;
if (_boosterManager.getTipManager().Get(player).getTips() > 0) availableRewards++;
Hologram hologram;
if (client.getHologram() == null)
{
double yAdd = 2.45;
double yAdd = 2.3;
if(!UtilPlayer.is1_9(player))
{
yAdd = 2.45;
}
hologram = new Hologram(_hologramManager, _carlNpc.getLocation().clone().add(0, yAdd, 0), "");
hologram.setHologramTarget(Hologram.HologramTarget.WHITELIST);
hologram.addPlayer(player);
@ -1048,6 +1057,11 @@ public class BonusManager extends MiniClientPlugin<BonusClientData> implements I
return _facebookManager;
}
public YoutubeManager getYoutubeManager()
{
return _youtubeManager;
}
@EventHandler
public void Join(final PlayerJoinEvent event)
{
@ -1065,6 +1079,8 @@ public class BonusManager extends MiniClientPlugin<BonusClientData> implements I
public void Quit(PlayerQuitEvent event)
{
_showCarl.remove(event.getPlayer().getName());
// Removes from allow command map
UtilPlayer.removeAllowedCommands(event.getPlayer());
}
@EventHandler
@ -1179,4 +1195,9 @@ public class BonusManager extends MiniClientPlugin<BonusClientData> implements I
{
return "SELECT * FROM bonus WHERE accountId = '" + accountId + "';";
}
public BoosterManager getBoosterManager()
{
return _boosterManager;
}
}

View File

@ -0,0 +1,83 @@
package mineplex.core.bonuses.commands;
import java.util.Arrays;
import mineplex.core.bonuses.BonusManager;
import mineplex.core.command.CommandBase;
import mineplex.core.command.CommandCenter;
import mineplex.core.command.ICommand;
import mineplex.core.common.Rank;
import mineplex.core.common.util.F;
import mineplex.core.common.util.NautHashMap;
import mineplex.core.common.util.UtilPlayer;
import org.bukkit.entity.Player;
/**
* Allows players to run rank-specific commands
* Found no better place to create it
*/
public class AllowCommand extends CommandBase<BonusManager>
{
private BonusManager _plugin;
public AllowCommand(BonusManager plugin)
{
super(plugin, Rank.MODERATOR, "allowCommand", "allowCmd");
_plugin = plugin;
}
@Override
public void Execute(Player caller, String[] args)
{
if (args.length < 2 || args.length > 3)
{
UtilPlayer.message(caller, F.main("Allow Command", "Usage: /allowCmd <player> <command> [disallow]"));
return;
}
NautHashMap<String, ICommand> commands = CommandCenter.getCommands();
if (!commands.containsKey(args[1].toLowerCase()))
{
UtilPlayer.message(caller, F.main("Allow Command", "Command not found!"));
return;
}
ICommand iCommand = commands.get(args[1]);
Rank playerRank = _plugin.getClientManager().Get(caller).GetRank();
if (playerRank.compareTo(iCommand.GetRequiredRank()) > 0
&& Arrays.asList(iCommand.GetSpecificRanks()).contains(playerRank))
{
UtilPlayer.message(caller, F.main("Allow Command", "You're not allowed to use that command!"));
return;
}
boolean disallow = false;
if (args.length == 3)
disallow = Boolean.parseBoolean(args[2]);
Player receiver = UtilPlayer.searchExact(args[0]);
if (receiver == null)
{
UtilPlayer.message(caller, F.main("Allow Command", "Could not find player " + F.name(args[0]) + "!"));
return;
}
if (receiver.getUniqueId().equals(caller.getUniqueId()))
{
UtilPlayer.message(caller, F.main("Allow Command", "You can't use that for yourself!"));
return;
}
if (disallow)
{
boolean canDisallow = UtilPlayer.disallowCommand(receiver, args[1].toLowerCase());
if (!canDisallow)
{
UtilPlayer.message(caller, F.main("Allow Command", "That command was not allowed for the player " + F.name(receiver.getName()) + "!"));
return;
}
UtilPlayer.message(caller, F.main("Allow Command", "You disallowed the player " + F.name(receiver.getName()) + " to use the command " + F.elem(args[1]) + "!"));
UtilPlayer.message(receiver, F.main("Allow Command", "The player " + F.name(caller.getName()) + " disallowed you to use the command " + F.elem(args[1]) + "!"));
return;
}
UtilPlayer.allowCommand(receiver, args[1].toLowerCase());
UtilPlayer.message(caller, F.main("Allow Command", "You allowed the player " + F.name(receiver.getName()) + " to use the command " + F.elem(args[1]) + "!"));
UtilPlayer.message(receiver, F.main("Allow Command", "The player " + F.name(caller.getName()) + " allowed you to use the command " + F.elem(args[1]) + "!"));
}
}

View File

@ -1,5 +1,6 @@
package mineplex.core.bonuses.commands;
import mineplex.core.boosters.BoosterManager;
import org.bukkit.entity.Player;
import mineplex.core.command.CommandBase;
@ -7,8 +8,8 @@ import mineplex.core.common.Rank;
import mineplex.core.bonuses.BonusManager;
import mineplex.core.bonuses.gui.BonusGui;
public class GuiCommand extends CommandBase<BonusManager>{
public class GuiCommand extends CommandBase<BonusManager>
{
public GuiCommand(BonusManager plugin)
{
super(plugin, Rank.DEVELOPER, "bonus");
@ -17,7 +18,7 @@ public class GuiCommand extends CommandBase<BonusManager>{
@Override
public void Execute(Player caller, String[] args)
{
new BonusGui(Plugin.getPlugin(), caller, Plugin, Plugin.getRewardManager(), Plugin.getFacebookManager()).openInventory();
new BonusGui(Plugin.getPlugin(), caller, Plugin, Plugin.getRewardManager(), Plugin.getFacebookManager(), Plugin.getYoutubeManager(), Plugin.getBoosterManager()).openInventory();
}
}

View File

@ -1,16 +1,12 @@
package mineplex.core.bonuses.gui;
import mineplex.core.bonuses.gui.buttons.FacebookButton;
import mineplex.core.bonuses.BonusManager;
import mineplex.core.bonuses.gui.buttons.*;
import mineplex.core.boosters.BoosterManager;
import mineplex.core.facebook.FacebookManager;
import mineplex.core.gui.SimpleGui;
import mineplex.core.reward.RewardManager;
import mineplex.core.bonuses.BonusManager;
import mineplex.core.bonuses.gui.buttons.CarlSpinButton;
import mineplex.core.bonuses.gui.buttons.DailyBonusButton;
import mineplex.core.bonuses.gui.buttons.PollButton;
import mineplex.core.bonuses.gui.buttons.RankBonusButton;
import mineplex.core.bonuses.gui.buttons.VoteButton;
import mineplex.core.youtube.YoutubeManager;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
@ -19,22 +15,28 @@ public class BonusGui extends SimpleGui
private BonusManager manager;
public BonusGui(Plugin plugin, Player player, BonusManager manager, RewardManager rewardManager, FacebookManager facebookManager)
public BonusGui(Plugin plugin, Player player, BonusManager manager, RewardManager rewardManager, FacebookManager facebookManager, YoutubeManager youtubeManager, BoosterManager boosterManager)
{
super(plugin, player, player.getName() + "'s Bonuses", 5 * 9);
this.manager = manager;
setItem(9, new VoteButton(plugin, player, this, manager));
setItem(10, new VoteButton(plugin, player, this, manager));
setItem(11, new RankBonusButton(getPlugin(), player, this, manager));
setItem(12, new RankBonusButton(getPlugin(), player, this, manager));
setItem(13, new DailyBonusButton(getPlugin(), player, this, manager));
setItem(14, new DailyBonusButton(getPlugin(), player, this, manager));
setItem(15, new PollButton(getPlugin(), player, manager.getPollManager(), manager.getClientManager(), this, manager));
setItem(16, new PollButton(getPlugin(), player, manager.getPollManager(), manager.getClientManager(), this, manager));
setItem(19, new FacebookButton(player, facebookManager));
setItem(21, new YoutubeButton(player, youtubeManager));
setItem(23, new TwitterButton(player));
setItem(25, new ClaimTipsButton(getPlugin(), player, this, manager, boosterManager));
setItem(17, new FacebookButton(player, facebookManager));
setItem(31, new CarlSpinButton(getPlugin(), player, manager, rewardManager));
}

View File

@ -12,6 +12,7 @@ import mineplex.core.itemstack.ItemStackFactory;
import mineplex.core.reward.Reward;
import mineplex.core.reward.RewardData;
import mineplex.core.reward.RewardManager;
import mineplex.core.reward.RewardPool.Type;
import mineplex.core.reward.RewardRarity;
import mineplex.core.reward.RewardType;
import mineplex.core.shop.item.ShopItem;
@ -101,11 +102,11 @@ public class SpinGui extends SimpleGui
{
if (i != _stopSpinnerAt + 4)
{
_rewards[i] = rewardManager.nextReward(player, null, false, RewardType.SpinnerFiller, true);
_rewards[i] = rewardManager.nextReward(player, Type.CARL_SPINNER, null, false, RewardType.SpinnerFiller, true);
}
else
{
_rewards[i] = rewardManager.nextReward(player, null, false, RewardType.SpinnerReal, true);
_rewards[i] = rewardManager.nextReward(player, Type.CARL_SPINNER, null, false, RewardType.SpinnerReal, true);
_reward = _rewards[i];
}
}

View File

@ -0,0 +1,51 @@
package mineplex.core.bonuses.gui;
import mineplex.core.common.jsonchat.ClickEvent;
import mineplex.core.common.jsonchat.JsonMessage;
import mineplex.core.common.util.C;
import mineplex.core.gui.GuiItem;
import mineplex.core.itemstack.ItemBuilder;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
import org.bukkit.inventory.ItemStack;
public class TwitterButton implements GuiItem
{
private static final ItemStack ICON = new ItemBuilder(Material.EGG)
.setTitle(C.cGreen + C.Bold + "Visit us on Twitter")
.addLore(
C.cWhite + "Check out and follow Mineplex on",
C.cWhite + "Twitter for Giveaways, Announcements,",
C.cWhite + "Teasers, and Tips!",
" ",
C.cGreen + "Click to visit us on Twitter!"
)
.build();
private final Player _player;
public TwitterButton(Player player)
{
this._player = player;
}
@Override
public void setup() {}
@Override
public void close() {}
@Override
public void click(ClickType clickType)
{
_player.closeInventory();
new JsonMessage(C.cAquaB + "Click here to visit our Twitter page!").click(ClickEvent.OPEN_URL, "https://www.twitter.com/Mineplex").sendToPlayer(_player);
}
@Override
public ItemStack getObject()
{
return ICON;
}
}

View File

@ -0,0 +1,192 @@
package mineplex.core.bonuses.gui.buttons;
import java.util.ArrayList;
import mineplex.core.boosters.BoosterManager;
import mineplex.core.common.CurrencyType;
import mineplex.core.common.util.C;
import mineplex.core.common.util.Callback;
import mineplex.core.common.util.F;
import mineplex.core.common.util.UtilPlayer;
import mineplex.core.common.util.UtilTime;
import mineplex.core.common.util.UtilTime.TimeUnit;
import mineplex.core.gui.GuiItem;
import mineplex.core.gui.ItemRefresher;
import mineplex.core.gui.pages.LoadingWindow;
import mineplex.core.gui.pages.TimedMessageWindow;
import mineplex.core.itemstack.ItemStackFactory;
import mineplex.core.shop.item.ShopItem;
import mineplex.core.updater.UpdateType;
import mineplex.core.updater.event.UpdateEvent;
import mineplex.core.bonuses.BonusAmount;
import mineplex.core.bonuses.BonusClientData;
import mineplex.core.bonuses.BonusManager;
import mineplex.core.bonuses.StreakRecord;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.DyeColor;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.ClickType;
import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.Plugin;
public class ClaimTipsButton implements GuiItem, Listener
{
private ItemStack _item;
private Player _player;
private Plugin _plugin;
private ItemRefresher _gui;
private BonusManager _bonusManager;
private BoosterManager _boosterManager;
public ClaimTipsButton(Plugin plugin, Player player, ItemRefresher gui, BonusManager bonusManager, BoosterManager boosterManager)
{
_bonusManager = bonusManager;
_boosterManager = boosterManager;
_player = player;
_plugin = plugin;
_gui = gui;
}
@Override
public void setup()
{
Bukkit.getPluginManager().registerEvents(this, getPlugin());
setItem();
}
@Override
public void close()
{
HandlerList.unregisterAll(this);
}
@Override
public void click(ClickType clickType)
{
if (isAvailable()) {
_item = ItemStackFactory.Instance.CreateStack(Material.LAPIS_BLOCK, (byte)0, 1, ChatColor.BLUE + "Processing...");
refreshItem();
new LoadingWindow(getPlugin(), getPlayer(), 6*9);
_boosterManager.getTipManager().claimTips(getPlayer(), claimed -> {
if (claimed > 0)
{
// Woo, success!
setItem();
if (getPlayer().getOpenInventory() != null)
{
new TimedMessageWindow(getPlugin(), getPlayer(), ItemStackFactory.Instance.CreateStack(Material.STAINED_GLASS_PANE, DyeColor.LIME.getData(), 1, ChatColor.GREEN + "Amplifier Thanks Collected"), "Thanks Collected", 6*9, 20*3, getGui()).openInventory();
}
UtilPlayer.message(getPlayer(), F.main("Carl", "You collected " + F.currency(CurrencyType.TREASURE_SHARD, claimed) + " from Amplifiers!"));
// Pending explosions are strange.. Not sure why we are using strings. Either way, lets display a rank reward effect
_bonusManager.addPendingExplosion(getPlayer(), "RANK");
getPlayer().playSound(getPlayer().getLocation(), Sound.NOTE_PLING, 1, 1.6f);
}
else if (claimed == 0)
{
// No tips to claim
if (getPlayer().getOpenInventory() != null)
{
new TimedMessageWindow(getPlugin(), getPlayer(), ItemStackFactory.Instance.CreateStack(Material.STAINED_GLASS_PANE, DyeColor.RED.getData(), 1, ChatColor.RED + "No Thanks to Claim!"), "You have no thanks to claim!", 6*9, 20*3, getGui()).openInventory();
}
UtilPlayer.message(getPlayer(), F.main("Carl", "You have no rewards to claim!"));
getPlayer().playSound(getPlayer().getLocation(), Sound.ENDERDRAGON_GROWL, 1, 10);
}
else
{
// Failed to claim
if (getPlayer().getOpenInventory() != null)
{
new TimedMessageWindow(getPlugin(), getPlayer(), ItemStackFactory.Instance.CreateStack(Material.STAINED_GLASS_PANE, DyeColor.RED.getData(), 1, ChatColor.RED + "Error collecting rewards. Try again later."), "Error", 6*9, 20*3, getGui()).openInventory();
}
UtilPlayer.message(getPlayer(), F.main("Carl", "Error collecting rewards. Try again later."));
getPlayer().playSound(getPlayer().getLocation(), Sound.ENDERDRAGON_GROWL, 1, 10);
}
getPlayer().closeInventory();
});
}
else
{
getPlayer().playSound(getPlayer().getLocation(), Sound.ITEM_BREAK, 1, 10);
}
}
private void setItem()
{
ArrayList<String> lore = new ArrayList<String>();
Material material;
String itemName;
if (isAvailable())
{
material = Material.EMERALD;
itemName = C.cGreen + C.Bold + "Game Amplifiers";
lore.add(" ");
lore.add(C.cYellow + "Your Rewards");
lore.add(" " + C.cWhite + getTips() + " Treasure Shards");
lore.add(" ");
lore.add(ChatColor.RESET + "Click to Claim!");
}
else
{
material = Material.REDSTONE_BLOCK;
itemName = C.cRed + C.Bold + "Game Amplifiers";
lore.add(" ");
lore.add(C.cGray + "Use Amplifiers to earn rewards");
lore.add(" ");
lore.add(C.cWhite + "Get Amplifiers at " + C.cGreen + "mineplex.com/shop");
}
_item = new ShopItem(material, itemName, lore.toArray(new String[0]), 1, false, false);
}
@Override
public ItemStack getObject()
{
return _item;
}
public void refreshItem()
{
getGui().refreshItem(this);
}
private int getTips()
{
return _boosterManager.getTipManager().Get(getPlayer()).getTips();
}
private boolean isAvailable()
{
return getTips() > 0;
}
public Plugin getPlugin()
{
return _plugin;
}
public Player getPlayer()
{
return _player;
}
public ItemRefresher getGui()
{
return _gui;
}
}

View File

@ -0,0 +1,82 @@
package mineplex.core.bonuses.gui.buttons;
import mineplex.core.common.jsonchat.ClickEvent;
import mineplex.core.common.jsonchat.JsonMessage;
import mineplex.core.common.util.C;
import mineplex.core.gui.GuiItem;
import mineplex.core.itemstack.ItemBuilder;
import mineplex.core.youtube.YoutubeManager;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
import org.bukkit.inventory.ItemStack;
public class YoutubeButton implements GuiItem
{
private static final ItemStack DISABLED_ICON = new ItemBuilder(Material.APPLE)
.setTitle(C.cGreen + C.Bold + "Visit us on YouTube")
.addLore(
C.cWhite + "Come back tomorrow for your",
C.cWhite + "Daily 250 Shard Reward!",
" ",
C.cWhite + "Check out the latest Video",
C.cWhite + "on the MineplexGames Channel!",
" ",
C.cWhite + "Be sure and Subscribe so you",
C.cWhite + "don't miss a video!",
" ",
C.cGreen + "Click to visit us on YouTube!"
)
.build();
private static final ItemStack ENABLED_ICON = new ItemBuilder(Material.APPLE)
.setTitle(C.cGreen + C.Bold + "Visit us on YouTube")
.addLore(
C.cYellow + "Claim your Daily 250 Shard Reward",
C.cWhite + "by checking out the latest Video",
C.cWhite + "on the MineplexGames Channel!",
C.cWhite + " ",
C.cWhite + "Be sure and Subscribe so you",
C.cWhite + "don't miss a video!",
" ",
C.cGreen + "Click to visit us on YouTube!"
)
.build();
private final Player _player;
private final YoutubeManager _youtubeManager;
public YoutubeButton(Player player, YoutubeManager youtubeManager)
{
this._player = player;
this._youtubeManager = youtubeManager;
}
@Override
public void setup() {}
@Override
public void close() {}
@Override
public void click(ClickType clickType)
{
_player.closeInventory();
final String message;
if (_youtubeManager.canYoutube(_player))
{
message = "Click here to claim YouTube Prize!";
_youtubeManager.attemptYoutube(_player);
} else
{
message = "Click here to visit our YouTube page!";
}
new JsonMessage(C.cAquaB + message).click(ClickEvent.OPEN_URL, "https://www.youtube.com/mineplexgamesofficial").sendToPlayer(_player);
}
@Override
public ItemStack getObject()
{
return _youtubeManager.canYoutube(_player) ? ENABLED_ICON : DISABLED_ICON;
}
}

View File

@ -0,0 +1,146 @@
package mineplex.core.boosters;
import com.mojang.authlib.properties.PropertyMap;
import mineplex.core.common.util.UtilTime;
import java.util.Date;
import java.util.UUID;
/**
* @author Shaun Bennett
*/
public class Booster
{
private int _id;
private String _playerName;
private UUID _uuid;
private int _accountId;
private int _duration;
private double _multiplier;
private Date _startTime;
private Date _endTime;
private Date _activationTime;
// private PropertyMap _propertyMap;
public Booster()
{
}
public int getId()
{
return _id;
}
public String getPlayerName()
{
return _playerName;
}
public UUID getUuid()
{
return _uuid;
}
public int getAccountId()
{
return _accountId;
}
public int getDuration()
{
return _duration;
}
public Date getStartTime()
{
return _startTime;
}
public Date getEndTime()
{
return _endTime;
}
public Date getActivationTime()
{
return _activationTime;
}
public boolean isActive()
{
Date now = new Date();
return getStartTime().before(now) && getEndTime().after(now);
}
public long getTimeRemaining()
{
if (isActive())
{
return Math.max(0, getEndTime().getTime() - System.currentTimeMillis());
}
else if (getEndTime().after(new Date()))
{
return _duration * 1000L;
}
else
{
return 0;
}
}
public String getTimeRemainingString()
{
return UtilTime.convertColonString(getTimeRemaining(), UtilTime.TimeUnit.MINUTES, UtilTime.TimeUnit.SECONDS);
}
public double getMultiplier()
{
return _multiplier;
}
// public PropertyMap getPropertyMap()
// {
// return _propertyMap;
// }
@Override
public boolean equals(Object o)
{
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Booster booster = (Booster) o;
if (_id != booster._id) return false;
return _accountId == booster._accountId;
}
@Override
public int hashCode()
{
int result = _id;
result = 31 * result + _accountId;
return result;
}
public int getIncreasePercent()
{
return (int) (getMultiplier() - 1) * 100;
}
@Override
public String toString()
{
return "Booster{" +
"_id=" + _id +
", _playerName='" + _playerName + '\'' +
", _uuid=" + _uuid +
", _accountId=" + _accountId +
", _duration=" + _duration +
", _multiplier=" + _multiplier +
", _startTime=" + _startTime +
", _endTime=" + _endTime +
", _activationTime=" + _activationTime +
'}';
}
}

View File

@ -0,0 +1,26 @@
package mineplex.core.boosters;
import mineplex.core.common.api.ApiResponse;
import java.util.Date;
/**
* @author Shaun Bennett
*/
public class BoosterApiResponse extends ApiResponse
{
private Date startTime;
public Date getStartTime()
{
return startTime;
}
@Override
public String toString()
{
return "BoosterApiResponse{" +
"startTime='" + startTime + '\'' +
"} " + super.toString();
}
}

View File

@ -0,0 +1,394 @@
package mineplex.core.boosters;
import com.mojang.authlib.properties.PropertyMap;
import mineplex.core.MiniPlugin;
import mineplex.core.account.CoreClientManager;
import mineplex.core.boosters.command.BoosterCommand;
import mineplex.core.boosters.event.BoosterActivateEvent;
import mineplex.core.boosters.event.BoosterExpireEvent;
import mineplex.core.boosters.event.BoosterUpdateEvent;
import mineplex.core.boosters.gui.BoosterShop;
import mineplex.core.boosters.redis.BoosterUpdateRepository;
import mineplex.core.boosters.tips.BoosterTipManager;
import mineplex.core.common.util.C;
import mineplex.core.common.util.Callback;
import mineplex.core.common.util.UtilGear;
import mineplex.core.common.util.UtilInv;
import mineplex.core.donation.DonationManager;
import mineplex.core.inventory.InventoryManager;
import mineplex.core.itemstack.ItemStackFactory;
import mineplex.core.updater.UpdateType;
import mineplex.core.updater.event.UpdateEvent;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.EventHandler;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.java.JavaPlugin;
import java.util.*;
/**
* BoosterManager handles the majority of logic for creating and getting Boosters. Every BoosterManager stores a cache
* for all boosters across all servers. We pull all boosters from the API when the server boots up. To keep them in sync,
* instead of consistently polling the API I have decided to go with a redis pub/sub solution to ensuring all boosters
* across all servers are up to date. Whenever the Booster API receives a call to add or modify boosters, it will publish
* an updated version of all boosters over redis.
*
* Boosters are enabled on live servers using "Booster Groups". A {@link mineplex.serverdata.data.ServerGroup} can specify
* which BoosterGroup applies to it. If there is no BoosterGroup, then it means the server does not use boosters. To add
* a BoosterGroup, you must add to the "boostergroups" set on redis (the same way the servergroups set works), otherwise
* the API will return an error saying that BoosterGroup does not exist. Currently BoosterGroups are no more than a String
* key for Boosters. In the future we may want to look into implementing BoosterGroup specific data such as default
* booster length and multiplier.
*
* @author Shaun Bennett
*/
public class BoosterManager extends MiniPlugin
{
// The InventoryManager item name for boosters. This is required to activate a booster on servers
public static final String BOOSTER_ITEM = "Game Booster";
// Item in arcade lobbies that opens the booster gui
public static final ItemStack INTERFACE_ITEM = ItemStackFactory.Instance.CreateStack(Material.EMERALD, (byte)0, 1, ChatColor.RESET + C.cGreen + "Game Amplifiers");
// Slot for the booster gui item
public static final int INTERFACE_SLOT = 7;
private BoosterRepository _repository;
private CoreClientManager _clientManager;
private DonationManager _donationManager;
private InventoryManager _inventoryManager;
private BoosterTipManager _tipManager;
private BoosterShop _shop;
private String _boosterGroup;
private boolean _giveInterfaceItem;
private long _cacheLastUpdated;
private Map<String, List<Booster>> _boosterCache = new HashMap<>();
public BoosterManager(JavaPlugin plugin, String boosterGroup, CoreClientManager clientManager, DonationManager donationManager, InventoryManager inventoryManager)
{
super("Booster Manager", plugin);
_repository = new BoosterRepository();
_boosterGroup = boosterGroup;
_clientManager = clientManager;
_donationManager = donationManager;
_inventoryManager = inventoryManager;
_tipManager = new BoosterTipManager(plugin, clientManager, donationManager);
_shop = new BoosterShop(this, clientManager, donationManager);
try
{
Map<String, List<Booster>> boosters = _repository.getBoosters();
if (boosters != null) _boosterCache = boosters;
}
catch (Exception e)
{
System.out.println("Failed to load boosters on server start.");
e.printStackTrace();
}
_giveInterfaceItem = canActivateBoosters();
new BoosterUpdateRepository(plugin);
}
@Override
public void addCommands()
{
addCommand(new BoosterCommand(this));
}
/**
* Make an API call to grab all Boosters
*/
@Deprecated
public void getBoostersAsync(Callback<Map<String, List<Booster>>> callback)
{
runAsync(() -> {
try
{
long time = System.currentTimeMillis();
Map<String, List<Booster>> boosters = _repository.getBoosters();
long timeTaken = System.currentTimeMillis() - time;
runSync(() -> {
handleBoosterUpdate(boosters);
if (callback != null) callback.run(boosters);
});
}
catch (Exception e)
{
System.err.println("Failed to grab boosters;");
e.printStackTrace();
}
});
}
/**
* Make an API call to grab all boosters for a specific booster group
* @param boosterGroup
* @param callback
*/
@Deprecated
public void getBoostersAsync(String boosterGroup, Callback<List<Booster>> callback)
{
runAsync(() -> {
try
{
List<Booster> boosters = _repository.getBoosters(boosterGroup);
if (callback != null) runSync(() -> callback.run(boosters));
}
catch (Exception e)
{
System.err.println("Failed to grab boosters for boostergroup: " + boosterGroup);
e.printStackTrace();
}
});
}
/**
* Process the new boosterMap whenever a BoosterUpdateEvent is sent. This will compare itself to the current
* cached BoosterMap and call events when it finds a booster was activated or deactivated
* @param boosterMap The new booster map
*/
private void handleBoosterUpdate(Map<String, List<Booster>> boosterMap)
{
_boosterCache.entrySet().stream()
.filter(entry -> entry.getValue().size() > 0)
.filter(entry -> boosterMap.get(entry.getKey()) == null)
.forEach(entry -> callNextTick(new BoosterExpireEvent(entry.getKey(), entry.getValue().get(0))));
for (Map.Entry<String, List<Booster>> entry : boosterMap.entrySet())
{
List<Booster> current = _boosterCache.get(entry.getKey());
if (entry.getValue() != null && !entry.getValue().isEmpty())
{
if (current == null || current.isEmpty())
{
// New booster was added
callNextTick(new BoosterActivateEvent(entry.getKey(), entry.getValue().get(0)));
} else if (!current.get(0).equals(entry.getValue().get(0)))
{
// First booster was deactivated, new booster replaced it
callNextTick(new BoosterExpireEvent(entry.getKey(), current.get(0)));
callNextTick(new BoosterActivateEvent(entry.getKey(), entry.getValue().get(0)));
}
}
}
_cacheLastUpdated = System.currentTimeMillis();
_boosterCache = boosterMap;
}
private void tickBoosterCache()
{
List<Event> events = new ArrayList<>(3);
for (Map.Entry<String, List<Booster>> entry : _boosterCache.entrySet())
{
Iterator<Booster> iterator = entry.getValue().iterator();
boolean removedOne = false;
while (iterator.hasNext())
{
Booster booster = iterator.next();
if (!booster.isActive())
{
iterator.remove();
removedOne = true;
events.add(new BoosterExpireEvent(entry.getKey(), booster));
}
else
{
if (removedOne) events.add(new BoosterActivateEvent(entry.getKey(), booster));
break;
}
}
}
events.forEach(Bukkit.getPluginManager()::callEvent);
}
@EventHandler
public void tickBoosters(UpdateEvent event)
{
if (event.getType() == UpdateType.MIN_10)
{
// sync with API every 10 minutes, incase pubsub fails
getBoostersAsync(null);
}
else if (event.getType() == UpdateType.SEC)
{
tickBoosterCache();
}
}
/**
* Return all boosters for the active booster group
* @return list of boosters, or null if there is no active booster group
*/
public List<Booster> getBoosters()
{
if (_boosterGroup == null || _boosterGroup.length() == 0)
{
return null;
}
else
{
List<Booster> boosters = _boosterCache.get(_boosterGroup);
return boosters == null ? Collections.emptyList() : boosters;
}
}
public String getBoosterGroup()
{
return _boosterGroup;
}
public long getBoostTime()
{
return getBoostTime(_boosterGroup);
}
public long getBoostTime(String boosterGroup)
{
long time = 0;
List<Booster> boosters = _boosterCache.get(boosterGroup);
if (boosters != null && boosters.size() > 0)
{
for (Booster booster : boosters)
{
time += booster.getTimeRemaining();
}
}
return time;
}
public Booster getActiveBooster()
{
return getActiveBooster(_boosterGroup);
}
public Booster getActiveBooster(String boosterGroup)
{
List<Booster> boosters = _boosterCache.get(boosterGroup);
if (boosters != null)
{
for (Booster booster : boosters)
{
if (booster.getEndTime().after(new Date()))
return booster;
}
}
return null;
}
public void activateBooster(Player player, Callback<BoosterApiResponse> callback)
{
activateBooster(_boosterGroup, player, callback);
}
public void activateBooster(String serverGroup, Player player, Callback<BoosterApiResponse> callback)
{
String playerName = player.getName();
UUID uuid = player.getUniqueId();
int accountId = _clientManager.getAccountId(player);
// PropertyMap propertyMap = ((CraftPlayer) player).getHandle().getProfile().getProperties();
runAsync(() -> {
BoosterApiResponse response = _repository.addBooster(serverGroup, playerName, uuid, accountId, 3600);
callback.run(response);
});
}
public void chargeBooster(Player player, Callback<Boolean> callback)
{
_inventoryManager.addItemToInventory(callback, player, BOOSTER_ITEM, -1);
}
public void refundBooster(Player player, Callback<Boolean> callback)
{
_inventoryManager.addItemToInventory(callback, player, BOOSTER_ITEM, 1);
}
public void openShop(Player player)
{
_shop.attemptShopOpen(player);
}
/**
* Booster updates are sent from {@link mineplex.core.boosters.redis.BoosterUpdateListener}
*/
@EventHandler
public void onBoosterUpdate(BoosterUpdateEvent event)
{
handleBoosterUpdate(event.getBoosterMap());
}
public BoosterTipManager getTipManager()
{
return _tipManager;
}
/**
* Returns the number of unactivated game boosters a player owns
* @param player
* @return The amount of unactivated game boosters the player owns
*/
public int getAvailableBoosterCount(Player player)
{
return _inventoryManager.Get(player).getItemCount(BOOSTER_ITEM);
}
/**
* Can players activate boosters on this server?
* @return true if players are able to activate a booster on this server
*/
public boolean canActivateBoosters()
{
return _boosterGroup != null && _boosterGroup.length() > 0;
}
public void giveInterfaceItem(Player player)
{
if (_giveInterfaceItem && !UtilGear.isMat(player.getInventory().getItem(INTERFACE_SLOT), Material.EMERALD))
{
player.getInventory().setItem(INTERFACE_SLOT, INTERFACE_ITEM);
UtilInv.Update(player);
}
}
@EventHandler
public void onJoin(PlayerJoinEvent event)
{
giveInterfaceItem(event.getPlayer());
}
@EventHandler
public void onInteract(PlayerInteractEvent event)
{
if (INTERFACE_ITEM.equals(event.getPlayer().getItemInHand()))
{
openShop(event.getPlayer());
}
}
public Map<String, List<Booster>> getBoosterCache()
{
return _boosterCache;
}
private void callNextTick(Event event)
{
runSync(() -> getPluginManager().callEvent(event));
}
}

View File

@ -0,0 +1,59 @@
package mineplex.core.boosters;
import mineplex.core.common.util.C;
import mineplex.core.common.util.F;
import mineplex.core.common.util.UtilTime;
import mineplex.core.shop.confirmation.ConfirmationCallback;
import mineplex.core.shop.confirmation.ConfirmationProcessor;
import org.bukkit.entity.Player;
/**
* @author Shaun Bennett
*/
public class BoosterProcessor implements ConfirmationProcessor
{
private BoosterManager _boosterManager;
private Player _player;
public BoosterProcessor(BoosterManager boosterManager, Player player)
{
_boosterManager = boosterManager;
_player = player;
}
@Override
public void process(ConfirmationCallback callback)
{
_boosterManager.chargeBooster(_player, data -> {
if (data)
{
_boosterManager.activateBooster(_player, response -> {
if (response.isSuccess())
{
long timeToStart = response.getStartTime().getTime() - System.currentTimeMillis();
if (timeToStart <= 0) _player.sendMessage(F.main("Amplifier", "Game Amplifier Activated!"));
else _player.sendMessage(F.main("Amplifier", "Game Amplifier Added. It will start in " + F.elem(UtilTime.convertString(timeToStart, 2, UtilTime.TimeUnit.FIT))));
callback.resolve("Success!");
}
else
{
_player.sendMessage(C.cRed + "There was an error trying to enable your Game Amplifier");
if (response.getStatusCode() == 503 && response.getError() != null && response.getError().length() > 0)
{
// Service Unavailable HTTP Code
_player.sendMessage(C.cRed + "Error: " + response.getError());
}
_boosterManager.refundBooster(_player, null);
callback.reject("Failed. Try again later.");
}
});
}
else
{
callback.reject("Failed charging account.");
_player.sendMessage(F.main("Amplifier", "There was an error charging your account. Try again later!"));
}
});
}
}

View File

@ -0,0 +1,52 @@
package mineplex.core.boosters;
import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import com.mojang.authlib.properties.PropertyMap;
import mineplex.core.common.api.ApiEndpoint;
import mineplex.core.common.api.ApiFieldNamingStrategy;
import mineplex.core.common.api.ApiResponse;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.UUID;
/**
* Boosters interaction is handled through a web API. All data is represented as JSON and then parsed using gson.
*
* @author Shaun Bennett
*/
public class BoosterRepository extends ApiEndpoint
{
public BoosterRepository()
{
super("/booster", new GsonBuilder().setFieldNamingStrategy(new ApiFieldNamingStrategy())
// .registerTypeAdapter(PropertyMap.class, new PropertyMap.Serializer())
.setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX").create());
}
public Map<String, List<Booster>> getBoosters()
{
return getWebCall().get("/", new TypeToken<Map<String, List<Booster>>>(){}.getType());
}
public List<Booster> getBoosters(String serverGroup)
{
return Arrays.asList(getWebCall().get("/" + serverGroup, Booster[].class));
}
public BoosterApiResponse addBooster(String serverGroup, String playerName, UUID uuid, int accountId, int duration)
{
JsonObject body = new JsonObject();
body.addProperty("playerName", playerName);
body.addProperty("uuid", uuid.toString());
body.addProperty("accountId", accountId);
body.addProperty("duration", duration);
// body.add("propertyMap", getGson().toJsonTree(propertyMap));
return getWebCall().post("/" + serverGroup, BoosterApiResponse.class, body);
}
}

View File

@ -0,0 +1,54 @@
package mineplex.core.boosters.command;
import mineplex.core.boosters.BoosterApiResponse;
import mineplex.core.boosters.BoosterManager;
import mineplex.core.command.CommandBase;
import mineplex.core.common.Rank;
import mineplex.core.common.util.Callback;
import mineplex.core.common.util.F;
import mineplex.core.common.util.UtilPlayer;
import org.bukkit.entity.Player;
/**
* @author Shaun Bennett
*/
public class AddCommand extends CommandBase<BoosterManager>
{
public AddCommand(BoosterManager plugin)
{
super(plugin, Rank.DEVELOPER, "add");
}
@Override
public void Execute(Player caller, String[] args)
{
if (args != null && args.length > 0)
{
String serverGroup = args[0];
Plugin.activateBooster(serverGroup, caller, new Callback<BoosterApiResponse>()
{
@Override
public void run(BoosterApiResponse response)
{
if (response.isSuccess())
{
UtilPlayer.message(caller, F.main("Amplifier", "Successfully added amplifier to " + F.elem(serverGroup)));
}
else
{
UtilPlayer.message(caller, F.main("Amplifier", "Failed to add amplifier. Error: " + F.elem(response.getError())));
}
}
});
}
else
{
help(caller);
}
}
private void help(Player caller)
{
UtilPlayer.message(caller, F.help("amplifier add <servergroup>", "Add an amplifier to that server group", Rank.DEVELOPER));
}
}

View File

@ -0,0 +1,31 @@
package mineplex.core.boosters.command;
import mineplex.core.boosters.BoosterManager;
import mineplex.core.command.CommandBase;
import mineplex.core.command.MultiCommandBase;
import mineplex.core.common.Rank;
import mineplex.core.common.util.F;
import mineplex.core.common.util.UtilPlayer;
import org.bukkit.entity.Player;
/**
* @author Shaun Bennett
*/
public class BoosterCommand extends MultiCommandBase<BoosterManager>
{
public BoosterCommand(BoosterManager plugin)
{
super(plugin, Rank.DEVELOPER, "amplifier", "booster");
AddCommand(new AddCommand(plugin));
AddCommand(new GuiCommand(plugin));
AddCommand(new ReloadCommand(plugin));
}
@Override
protected void Help(Player caller, String[] args)
{
UtilPlayer.message(caller, F.help("amplifier add <group>", "Add an amplifier to that group", Rank.DEVELOPER));
UtilPlayer.message(caller, F.help("amplifier gui", "Open Amplifier GUI", Rank.DEVELOPER));
}
}

View File

@ -0,0 +1,23 @@
package mineplex.core.boosters.command;
import mineplex.core.boosters.BoosterManager;
import mineplex.core.command.CommandBase;
import mineplex.core.common.Rank;
import org.bukkit.entity.Player;
/**
* @author Shaun Bennett
*/
public class GuiCommand extends CommandBase<BoosterManager>
{
public GuiCommand(BoosterManager plugin)
{
super(plugin, Rank.DEVELOPER, "gui");
}
@Override
public void Execute(Player caller, String[] args)
{
Plugin.openShop(caller);
}
}

View File

@ -0,0 +1,35 @@
package mineplex.core.boosters.command;
import mineplex.core.boosters.Booster;
import mineplex.core.boosters.BoosterManager;
import mineplex.core.command.CommandBase;
import mineplex.core.common.Rank;
import mineplex.core.common.util.Callback;
import mineplex.core.common.util.F;
import mineplex.core.common.util.UtilPlayer;
import org.bukkit.entity.Player;
import java.util.List;
import java.util.Map;
/**
* @author Shaun Bennett
*/
public class ReloadCommand extends CommandBase<BoosterManager>
{
public ReloadCommand(BoosterManager plugin)
{
super(plugin, Rank.DEVELOPER, "reload");
}
@Override
public void Execute(Player caller, String[] args)
{
Plugin.getBoostersAsync(data -> {
if (data != null)
{
UtilPlayer.message(caller, F.main("Amplifier", "Amplifiers reloaded!"));
}
});
}
}

View File

@ -0,0 +1,46 @@
package mineplex.core.boosters.event;
import mineplex.core.boosters.Booster;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
/**
* Called when a Booster is activated. This will be called regardless of which "BoosterGroup" the current server is set
* to, so if you only want Boosters on the current BoosterGroup, you will need to verify it.
*
* @author Shaun Bennett
*/
public class BoosterActivateEvent extends Event
{
private String _boosterGroup;
private Booster _booster;
public BoosterActivateEvent(String boosterGroup, Booster booster)
{
_boosterGroup = boosterGroup;
_booster = booster;
}
public String getBoosterGroup()
{
return _boosterGroup;
}
public Booster getBooster()
{
return _booster;
}
private static final HandlerList _handlers = new HandlerList();
private static HandlerList getHandlerList()
{
return _handlers;
}
@Override
public HandlerList getHandlers()
{
return getHandlerList();
}
}

View File

@ -0,0 +1,45 @@
package mineplex.core.boosters.event;
import mineplex.core.boosters.Booster;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
/**
* Called when a Booster is finished.
*
* @author Shaun Bennett
*/
public class BoosterExpireEvent extends Event
{
private String _boosterGroup;
private Booster _booster;
public BoosterExpireEvent(String boosterGroup, Booster booster)
{
_boosterGroup = boosterGroup;
_booster = booster;
}
public String getBoosterGroup()
{
return _boosterGroup;
}
public Booster getBooster()
{
return _booster;
}
private static final HandlerList _handlers = new HandlerList();
private static HandlerList getHandlerList()
{
return _handlers;
}
@Override
public HandlerList getHandlers()
{
return getHandlerList();
}
}

View File

@ -0,0 +1,41 @@
package mineplex.core.boosters.event;
import mineplex.core.boosters.Booster;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import java.util.List;
import java.util.Map;
/**
* Called when {@link mineplex.core.boosters.redis.BoosterUpdateListener} receives updated Boosters over redis pubsub.
*
* @author Shaun Bennett
*/
public class BoosterUpdateEvent extends Event
{
private Map<String, List<Booster>> _boosterMap;
public BoosterUpdateEvent(Map<String, List<Booster>> boosterMap)
{
_boosterMap = boosterMap;
}
public Map<String, List<Booster>> getBoosterMap()
{
return _boosterMap;
}
private static final HandlerList _handlers = new HandlerList();
private static HandlerList getHandlerList()
{
return _handlers;
}
@Override
public HandlerList getHandlers()
{
return getHandlerList();
}
}

View File

@ -0,0 +1,55 @@
package mineplex.core.boosters.gui;
import mineplex.core.boosters.BoosterApiResponse;
import mineplex.core.boosters.BoosterManager;
import mineplex.core.common.util.C;
import mineplex.core.common.util.Callback;
import mineplex.core.common.util.F;
import mineplex.core.common.util.UtilTime;
import mineplex.core.shop.item.IButton;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
/**
* @author Shaun Bennett
*/
@Deprecated
public class ActivateBoosterButton implements IButton
{
private BoosterShop _boosterShop;
private BoosterManager _boosterManager;
public ActivateBoosterButton(BoosterShop boosterShop, BoosterManager boosterManager)
{
_boosterShop = boosterShop;
_boosterManager = boosterManager;
}
@Override
public void onClick(Player player, ClickType clickType)
{
player.closeInventory();
_boosterManager.chargeBooster(player, data -> {
if (data)
{
_boosterManager.activateBooster(player, response -> {
if (response.isSuccess())
{
long timeToStart = response.getStartTime().getTime() - System.currentTimeMillis();
if (timeToStart <= 0) player.sendMessage(F.main("Amplifier", "Amplifier Activated!"));
else player.sendMessage(F.main("Amplifier", "Game Amplifier Added. It will start in " + F.elem(UtilTime.convertString(timeToStart, 2, UtilTime.TimeUnit.FIT))));
}
else
{
player.sendMessage(C.cRed + "There was an error trying to enable your Amplifier :(");
}
});
}
else
{
player.sendMessage(F.main("Amplifier", "There was an error charging your account. Try again later!"));
}
});
}
}

View File

@ -0,0 +1,230 @@
package mineplex.core.boosters.gui;
import mineplex.core.account.CoreClientManager;
import mineplex.core.boosters.Booster;
import mineplex.core.boosters.BoosterManager;
import mineplex.core.boosters.BoosterProcessor;
import mineplex.core.common.Pair;
import mineplex.core.common.util.C;
import mineplex.core.common.util.UtilTime;
import mineplex.core.donation.DonationManager;
import mineplex.core.shop.confirmation.ConfirmationPage;
import mineplex.core.shop.item.ShopItem;
import mineplex.core.shop.page.ShopPageBase;
import org.apache.commons.lang3.tuple.Triple;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* @author Shaun Bennett
*/
public class BoosterPage extends ShopPageBase<BoosterManager, BoosterShop>
{
public BoosterPage(BoosterManager plugin, BoosterShop shop, CoreClientManager clientManager, DonationManager donationManager, Player player)
{
super(plugin, shop, clientManager, donationManager, "Game Amplifiers", player, 45);
buildPage();
}
@Override
protected void buildPage()
{
ArrayList<String> lore = new ArrayList<>();
int amplifierCount = getPlugin().getAvailableBoosterCount(getPlayer());
lore.add(" ");
lore.add(C.cWhite + "You own " + C.cGreen + amplifierCount + C.cWhite + " Game Amplifiers");
if (getPlugin().canActivateBoosters() && amplifierCount > 0)
{
List<Booster> boosters = getPlugin().getBoosters();
long waitTime = getPlugin().getBoostTime();
if (waitTime == 0)
{
lore.add(C.cWhite + "Amplifier would activate " + C.cGreen + "now");
lore.add(" ");
lore.add(C.cGray + "Once this Amplifier is activated");
lore.add(C.cGray + "or queued you are not able to");
lore.add(C.cGray + "cancel or refund it. You will still");
lore.add(C.cGray + "earn rewards if you are offline.");
lore.add(" ");
lore.add(C.cWhite + "Click to Activate Amplifier");
}
else
{
lore.add(" ");
lore.add(C.cWhite + "Amplifier would activate in " + C.cGreen + UtilTime.convertColonString(waitTime, UtilTime.TimeUnit.HOURS, UtilTime.TimeUnit.SECONDS));
if (boosters.size() - 1 == 1)
{
lore.add(C.cWhite + "There is " + C.cGreen + 1 + C.cWhite + " Amplifier queued");
}
else if (boosters.size() - 1 > 0)
{
lore.add(C.cWhite + "There are " + C.cGreen + (boosters.size() - 1) + C.cWhite + " Amplifiers queued");
}
lore.add(" ");
lore.add(C.cGray + "Once this Amplifier is activated");
lore.add(C.cGray + "or queued you are not able to");
lore.add(C.cGray + "cancel or refund it. You will still");
lore.add(C.cGray + "earn rewards if you are offline.");
lore.add(" ");
lore.add(C.cWhite + "Click to Queue Amplifier");
}
}
else
{
lore.add(" ");
lore.add(C.cGray + "Game Amplifiers allow you to");
lore.add(C.cGray + "increase the gems and shards");
lore.add(C.cGray + "earned in that game for 1 hour.");
lore.add(C.cGray + "You will also earn bonus rewards");
lore.add(C.cGray + "from players thanking you while");
lore.add(C.cGray + "your amplifier is active.");
lore.add(" ");
lore.add(C.cWhite + "Get Amplifiers at " + C.cGreen + "mineplex.com/shop");
}
ShopItem booster = new ShopItem(Material.SUGAR, "Game Amplifier", lore.toArray(new String[0]), 0, false, false);
if (getPlugin().canActivateBoosters() && amplifierCount > 0)
{
addButton(13, booster, this::openConfirmation);
}
else
{
setItem(13, booster);
}
addBoosterQueue();
// addOtherBoosters();
}
private void openConfirmation(Player player, ClickType type)
{
ArrayList<String> lore = new ArrayList<>();
lore.add(" ");
lore.add(C.cGray + "Once this Amplifier is activated");
lore.add(C.cGray + "or queued you are not able to");
lore.add(C.cGray + "cancel or refund it. You will still");
lore.add(C.cGray + "earn rewards if you are offline.");
ShopItem booster = new ShopItem(Material.SUGAR, "Game Amplifier", lore.toArray(new String[0]), 0, false, false);
BoosterProcessor processor = new BoosterProcessor(getPlugin(), getPlayer());
ConfirmationPage<BoosterManager, BoosterShop> page = new ConfirmationPage<>(getPlugin(), getShop(),
getClientManager(), getDonationManager(), getPlayer(), this, processor, booster);
getShop().openPageForPlayer(getPlayer(), page);
}
private void addBoosterQueue()
{
if (getPlugin().getBoosters() == null)
return;
List<Booster> boosters = getPlugin().getBoosters();
int startIndex = Math.max(0, (9 - boosters.size()) / 2);
for (int i = 0; i < boosters.size() && i < 18; i++)
{
int slot = startIndex + 27 + i;
Booster booster = boosters.get(i);
boolean active = booster.isActive();
int queueIndex = Math.max(1, i);
boolean owns = getPlayer().getUniqueId().equals(booster.getUuid());
long timeActivatedDif = System.currentTimeMillis() - booster.getActivationTime().getTime();
String activationTime = UtilTime.convertString(timeActivatedDif, 0, UtilTime.TimeUnit.FIT);
List<String> lore = new ArrayList<>();
if (active)
{
lore.add(C.cWhite + "Active");
lore.add(" ");
String expireTime = UtilTime.convertColonString(booster.getTimeRemaining(), UtilTime.TimeUnit.MINUTES, UtilTime.TimeUnit.SECONDS);
lore.add(C.cWhite + "Added by " + C.cGreen + booster.getPlayerName());
lore.add(C.cWhite + "Expires in " + C.cGreen + expireTime);
}
else
{
long timeToActive = booster.getStartTime().getTime() - System.currentTimeMillis();
String activeString = UtilTime.convertColonString(timeToActive, UtilTime.TimeUnit.HOURS, UtilTime.TimeUnit.SECONDS);
lore.add(" ");
lore.add(C.cWhite + "Added by " + C.cGreen + booster.getPlayerName());
lore.add(C.cWhite + "Starts in " + C.cGreen + activeString);
// lore.add(C.cWhite + "Position " + C.cGreen + queueIndex + C.cWhite + " in queue");
}
lore.add(" ");
lore.add(C.cGray + "Added " + activationTime + " ago");
ShopItem shopItem = new ShopItem(booster.isActive() ? Material.EMERALD_BLOCK : Material.REDSTONE_BLOCK,
"Game Amplifier", lore.toArray(new String[0]), queueIndex, !active, false);
setItem(slot, shopItem);
// Add glow if the booster belongs to you
if (owns)
{
addGlow(slot);
}
}
}
private void addOtherBoosters()
{
Map<String, List<Booster>> boosterMap = getPlugin().getBoosterCache();
List<Triple<Integer, String, Booster>> tripleList = new ArrayList<>();
for (Map.Entry<String, List<Booster>> entry : boosterMap.entrySet())
{
String boosterGroup = entry.getKey();
// dont display boosters for the current booster group
if (boosterGroup.equals(getPlugin().getBoosterGroup()))
continue;
List<Booster> boosters = entry.getValue();
for (int i = 0; i < boosters.size(); i++)
{
Booster booster = boosters.get(i);
if (booster.getUuid().equals(getPlayer().getUniqueId()))
{
tripleList.add(Triple.of(i, boosterGroup, booster));
}
}
}
int startIndex = Math.max(0, (9 - tripleList.size()) / 2);
for (int i = 0; i < 9 && i < tripleList.size(); i++)
{
Triple<Integer, String, Booster> triple = tripleList.get(i);
int deliveryAmount = Math.max(1, triple.getLeft());
String boosterGroup = triple.getMiddle();
Booster booster = triple.getRight();
long timeActivatedDif = System.currentTimeMillis() - booster.getActivationTime().getTime();
String activationTime = UtilTime.convertString(timeActivatedDif, 2, UtilTime.TimeUnit.FIT);
List<String> lore = new ArrayList<String>();
lore.add(" ");
lore.add(C.cWhite + "Server: " + C.cGreen + boosterGroup);
if (booster.isActive())
{
lore.add(C.cWhite + "Expires in " + C.cGreen + UtilTime.convertColonString(booster.getTimeRemaining(), UtilTime.TimeUnit.MINUTES, UtilTime.TimeUnit.SECONDS));
}
else
{
long timeToActive = booster.getStartTime().getTime() - System.currentTimeMillis();
lore.add(C.cWhite + "Starts in " + C.cGreen + UtilTime.convertColonString(timeToActive, UtilTime.TimeUnit.HOURS, UtilTime.TimeUnit.SECONDS));
}
lore.add(" ");
lore.add(C.cGray + "Added " + activationTime + " ago");
ShopItem shopItem = new ShopItem(Material.GOLD_BLOCK,
"Game Amplifier", lore.toArray(new String[0]), 1, false, false);
setItem(startIndex + i + 27, shopItem);
}
}
}

View File

@ -0,0 +1,37 @@
package mineplex.core.boosters.gui;
import mineplex.core.account.CoreClientManager;
import mineplex.core.boosters.BoosterManager;
import mineplex.core.donation.DonationManager;
import mineplex.core.shop.ShopBase;
import mineplex.core.shop.page.ShopPageBase;
import mineplex.core.updater.UpdateType;
import mineplex.core.updater.event.UpdateEvent;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
/**
* @author Shaun Bennett
*/
public class BoosterShop extends ShopBase<BoosterManager>
{
public BoosterShop(BoosterManager plugin, CoreClientManager clientManager, DonationManager donationManager)
{
super(plugin, clientManager, donationManager, "Game Amplifiers");
}
@Override
protected ShopPageBase<BoosterManager, ? extends ShopBase<BoosterManager>> buildPagesFor(Player player)
{
return new BoosterPage(getPlugin(), this, getClientManager(), getDonationManager(), player);
}
@EventHandler
public void update(UpdateEvent event)
{
if (event.getType() != UpdateType.SEC)
return;
getPlayerPageMap().values().stream().filter(value -> value instanceof BoosterPage).forEach(ShopPageBase::refresh);
}
}

View File

@ -0,0 +1,44 @@
package mineplex.core.boosters.redis;
import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import mineplex.core.boosters.Booster;
import mineplex.core.boosters.event.BoosterUpdateEvent;
import mineplex.core.common.api.ApiFieldNamingStrategy;
import org.bukkit.Bukkit;
import org.bukkit.plugin.java.JavaPlugin;
import redis.clients.jedis.JedisPubSub;
import java.util.List;
import java.util.Map;
/**
* @author Shaun Bennett
*/
public class BoosterUpdateListener extends JedisPubSub
{
private Gson _gson = new GsonBuilder().setFieldNamingStrategy(new ApiFieldNamingStrategy())
.setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX").create();
private JavaPlugin _plugin;
public BoosterUpdateListener(JavaPlugin plugin)
{
_plugin = plugin;
}
@Override
public void onMessage(String channel, String message)
{
try
{
Map<String, List<Booster>> boosterMap = _gson.fromJson(message, new TypeToken<Map<String, List<Booster>>>() {}.getType());
_plugin.getServer().getScheduler().runTask(_plugin, () -> Bukkit.getPluginManager().callEvent(new BoosterUpdateEvent(boosterMap)));
}
catch (Exception e)
{
System.out.println("Failed to load booster update");
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,39 @@
package mineplex.core.boosters.redis;
import mineplex.serverdata.Region;
import mineplex.serverdata.redis.RedisRepository;
import org.bukkit.plugin.java.JavaPlugin;
import redis.clients.jedis.Jedis;
/**
* @author Shaun Bennett
*/
public class BoosterUpdateRepository extends RedisRepository
{
private JavaPlugin _plugin;
public BoosterUpdateRepository(JavaPlugin plugin)
{
super(Region.ALL);
_plugin = plugin;
init();
}
private void init()
{
Thread thread = new Thread("Booster Subscriber")
{
@Override
public void run()
{
try (Jedis jedis = getResource(false))
{
jedis.subscribe(new BoosterUpdateListener(_plugin), "minecraft.boosters");
}
}
};
thread.start();
}
}

View File

@ -0,0 +1,130 @@
package mineplex.core.boosters.tips;
import mineplex.core.MiniDbClientPlugin;
import mineplex.core.account.CoreClientManager;
import mineplex.core.boosters.Booster;
import mineplex.core.common.util.Callback;
import mineplex.core.donation.DonationManager;
import mineplex.core.recharge.Recharge;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* @author Shaun Bennett
*/
public class BoosterTipManager extends MiniDbClientPlugin<PlayerTipData>
{
public static final int TIP_FOR_SPONSOR = 5;
public static final int TIP_FOR_TIPPER = 5;
private BoosterTipRepository _repository;
private DonationManager _donationManager;
public BoosterTipManager(JavaPlugin plugin, CoreClientManager clientManager, DonationManager donationManager)
{
super("Amplifier Thanks", plugin, clientManager);
_donationManager = donationManager;
_repository = new BoosterTipRepository(plugin);
}
public void addTip(Player player, Booster booster, Callback<TipAddResult> callback)
{
if (!Recharge.Instance.use(player, "Amplifier Thanks", 1000 * 60 * 10, true, false))
{
callback.run(TipAddResult.ON_COOLDOWN);
return;
}
int accountId = ClientManager.getAccountId(player);
// Break out if client manager has a bad account id
if (accountId == -1)
{
callback.run(TipAddResult.INVALID_ACCOUNT_ID);
return;
}
// You can't tip yourself, silly!
if (accountId == booster.getAccountId())
{
callback.run(TipAddResult.CANNOT_TIP_SELF);
return;
}
runAsync(() -> {
TipAddResult result;
if (_repository.addTip(accountId, booster.getAccountId(), booster.getId(), TIP_FOR_SPONSOR))
{
_donationManager.rewardCoinsUntilSuccess(null, "Tips", player.getName(), accountId, TIP_FOR_TIPPER);
result = TipAddResult.SUCCESS;
}
else
result = TipAddResult.ALREADY_TIPPED_BOOSTER;
runSync(() -> callback.run(result));
});
}
/**
* Claim all tips for a player and add those tips to their account (Treasure Shards)
* This will call a database routine that handles the tip process.
*
* The callback will return -1 on a failed attempt or 0 if there was no tips to claim
* @param player The player with tips to claim
* @param callback Callback returning the amount of tips claimed
*/
public void claimTips(Player player, Callback<Integer> callback)
{
String playerName = player.getName();
int accountId = ClientManager.getAccountId(player);
if (accountId == -1)
{
// uh oh, invalid account id!
if (callback != null) callback.run(-1);
}
runAsync(() -> {
int tips = _repository.claimTips(accountId);
runSync(() -> {
if (tips > 0)
{
_donationManager.rewardCoinsUntilSuccess(null, "Tips", playerName, accountId, tips);
}
// Reset tips back to 0
if (Get(player) != null) Get(player).setTips(0);
if (callback != null) callback.run(tips);
});
});
}
@Override
public String getQuery(int accountId, String uuid, String name)
{
return "SELECT tips FROM Account.accountTip WHERE accountTip.accountId = " + accountId + ";";
}
@Override
protected PlayerTipData AddPlayer(String player)
{
return new PlayerTipData();
}
@Override
public void processLoginResultSet(String playerName, int accountId, ResultSet resultSet) throws SQLException
{
PlayerTipData data = new PlayerTipData();
while (resultSet.next())
{
data.setTips(resultSet.getInt(1));
}
Set(playerName, data);
}
}

View File

@ -0,0 +1,55 @@
package mineplex.core.boosters.tips;
import mineplex.core.database.MinecraftRepository;
import mineplex.database.routines.AddTip;
import mineplex.database.routines.ClaimTips;
import mineplex.serverdata.database.DBPool;
import mineplex.serverdata.database.RepositoryBase;
import mineplex.serverdata.database.column.ColumnInt;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
/**
* @author Shaun Bennett
*/
public class BoosterTipRepository extends MinecraftRepository
{
public static String LOG_TIP = "INSERT INTO Account.accountTipLogs (accountId, boosterId) VALUES (?, ?)";
public static String ADD_TIP = "INSERT INTO Account.accountTip (accountId, tips) VALUES (?, ?) ON DUPLICATE KEY UPDATE tips = tips + ?";
public BoosterTipRepository(JavaPlugin plugin)
{
super(plugin, DBPool.getAccount());
}
public boolean addTip(int tipperId, int receiverId, int boosterId, int tipAmount)
{
AddTip addTip = new AddTip();
addTip.setTipperAccountId(tipperId);
addTip.setBoosterAccountId(receiverId);
addTip.setBoosterId(boosterId);
addTip.setTipAmount(tipAmount);
addTip.execute(jooq().configuration());
return addTip.getSuccess() == 1;
}
public int claimTips(int accountId)
{
ClaimTips claimTips = new ClaimTips();
claimTips.setAccountId_in(accountId);
claimTips.execute(jooq().configuration());
return claimTips.getTipsClaimed();
}
@Override
protected void initialize()
{
}
@Override
protected void update()
{
}
}

View File

@ -0,0 +1,24 @@
package mineplex.core.boosters.tips;
/**
* @author Shaun Bennett
*/
public class PlayerTipData
{
private int _tips;
public PlayerTipData()
{
_tips = 0;
}
public int getTips()
{
return _tips;
}
public void setTips(int tips)
{
_tips = tips;
}
}

View File

@ -0,0 +1,25 @@
package mineplex.core.boosters.tips;
/**
* @author Shaun Bennett
*/
public enum TipAddResult
{
ALREADY_TIPPED_BOOSTER("You have already thanked this Amplifier!"),
INVALID_ACCOUNT_ID("Uh oh, something went wrong. Try relogging"),
CANNOT_TIP_SELF("You can't thank yourself, silly!"),
ON_COOLDOWN(null),
SUCCESS(null);
private String _friendlyMessage;
TipAddResult(String friendlyMessage)
{
_friendlyMessage = friendlyMessage;
}
public String getFriendlyMessage()
{
return _friendlyMessage;
}
}

View File

@ -0,0 +1,57 @@
package mineplex.core.brawl.fountain;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
/**
* This class handled filling a vertical area with a specific block based off a percent
*
* @author Shaun Bennett
*/
public class BlockProgressBar
{
// Starting block for the block fill
private final Block _startBlock;
// Direction the blockfill takes place in
private final BlockFace _direction;
// Blocks in order from lowest to highes
private final Block[] _blocks;
// Material used to fill the blocks
private final Material _material;
public BlockProgressBar(Block startBlock, Material material, BlockFace direction)
{
_startBlock = startBlock;
_material = material;
_direction = direction;
// Add blocks to array
int i;
Block curr;
Block[] blocks = new Block[100]; // max of 100 to prevent blocking
for (i = 0, curr = startBlock; (curr.getType() == Material.AIR || curr.getType() == material) && i < blocks.length; i++)
{
blocks[i] = curr;
curr = curr.getRelative(direction);
}
_blocks = new Block[i];
System.arraycopy(blocks, 0, _blocks, 0, i);
}
// Update the blockfill based on fill percent
public void update(double percent)
{
double percentPerBlock = 1D / _blocks.length;
double check = 0;
for (int i = 0; i < _blocks.length; i++)
{
_blocks[i].setType(percent > check ? _material : Material.AIR);
check += percentPerBlock;
}
}
}

View File

@ -0,0 +1,11 @@
package mineplex.core.brawl.fountain;
import mineplex.core.shop.ShopBase;
/**
* @author Shaun Bennett
*/
public interface BrawlShopProvider
{
public ShopBase getBrawlShop();
}

View File

@ -0,0 +1,250 @@
package mineplex.core.brawl.fountain;
import mineplex.core.account.CoreClientManager;
import mineplex.core.brawl.fountain.gui.FountainShop;
import mineplex.core.common.SortedSchematicLoader;
import mineplex.core.common.block.schematic.UtilSchematic;
import mineplex.core.common.util.C;
import mineplex.core.common.util.F;
import mineplex.core.common.util.UtilText;
import mineplex.core.donation.DonationManager;
import mineplex.core.hologram.Hologram;
import mineplex.core.hologram.HologramManager;
import mineplex.core.stats.StatsManager;
import mineplex.core.updater.UpdateType;
import mineplex.core.updater.event.UpdateEvent;
import mineplex.serverdata.redis.counter.GoalCounter;
import mineplex.serverdata.redis.counter.GoalCounterListener;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.TimeZone;
/**
* Represents a fountain that players can add gems to, with a reward for reaching specific goals
* @author Shaun Bennett
*/
public class Fountain implements GoalCounterListener
{
// Manager Injections
private final HologramManager _hologramManager;
private final StatsManager _statsManager;
private boolean _brawlActive;
private final String _name;
private final String _dataKey;
private final Location _location;
private final Hologram _hologram;
private final GoalCounter _counter;
// private final BlockProgressBar _blockProgressBar;
private final SortedSchematicLoader<Double> _schematicLoader;
private final FountainShop _shop;
public Fountain(Location location, Location pasteLocation, String name, String dataKey, long goal, FountainManager fountainManager,
CoreClientManager clientManager, DonationManager donationManager, HologramManager hologramManager,
StatsManager statsManager)
{
_hologramManager = hologramManager;
_statsManager = statsManager;
_name = name;
_dataKey = dataKey;
_location = location;
_hologram = new Hologram(hologramManager, location.clone().add(4, 3, -3), name).start();
_counter = new GoalCounter(dataKey, 5000, goal);
_counter.addListener(this);
_brawlActive = false;
// _blockProgressBar = new BlockProgressBar(_lavaLocation.getBlock(), Material.LAVA, BlockFace.UP);
_schematicLoader = new SortedSchematicLoader<>(pasteLocation);
loadSchematics();
_shop = new FountainShop(this, fountainManager, clientManager, donationManager);
updateVisuals();
}
private void loadSchematics()
{
try
{
_schematicLoader.addSchematic(0.0, UtilSchematic.loadSchematic(new File("../../update/schematic/fountain0.schematic")));
_schematicLoader.addSchematic(0.2, UtilSchematic.loadSchematic(new File("../../update/schematic/fountain20.schematic")));
_schematicLoader.addSchematic(0.4, UtilSchematic.loadSchematic(new File("../../update/schematic/fountain40.schematic")));
_schematicLoader.addSchematic(0.6, UtilSchematic.loadSchematic(new File("../../update/schematic/fountain60.schematic")));
_schematicLoader.addSchematic(0.8, UtilSchematic.loadSchematic(new File("../../update/schematic/fountain80.schematic")));
_schematicLoader.addSchematic(1.0, UtilSchematic.loadSchematic(new File("../../update/schematic/fountain100.schematic")));
_schematicLoader.addSchematic(2.0, UtilSchematic.loadSchematic(new File("../../update/schematic/fountain200.schematic")));
_schematicLoader.addSchematic(3.0, UtilSchematic.loadSchematic(new File("../../update/schematic/fountain300.schematic")));
}
catch (IOException e)
{
System.err.println("Failed to load Gem Fountain Schematics");
e.printStackTrace();
}
}
protected void updateVisuals()
{
double fillPercent = getFillPercent();
if (isBrawlActive())
{
ArrayList<String> text = new ArrayList<>();
if (fillPercent >= 1)
{
text.add(C.cRed + C.Bold + "Weekend Brawl is Active!");
if (fillPercent >= 2)
{
text.add("Bonus Reward Unlocked:");
if (fillPercent >= 3)
{
text.add(C.cGreen + "3X Experience in Brawl");
}
else
{
text.add(C.cGreen + "2X Experience in Brawl");
}
}
text.add(" ");
text.add("Speak to the Fountain Keeper to Join!");
}
else
{
text.add(C.cRed + "Brawl goal was not met");
text.add("Come back next week");
}
_hologram.setText(text.toArray(new String[text.size()]));
_schematicLoader.update(fillPercent);
}
else
{
double flatPercent = fillPercent - (int) fillPercent;
String fillColor;
String emptyColor;
String goalMessage;
if (fillPercent < 1)
{
fillColor = C.cGreen;
emptyColor = C.cRed;
goalMessage = "100% to Unlock Weekend Brawl";
} else if (fillPercent < 2)
{
fillColor = C.cYellow;
emptyColor = C.cGreen;
goalMessage = "200% to Unlock 2x XP for Weekend Brawl";
} else if (fillPercent < 3)
{
fillColor = C.cAqua;
emptyColor = C.cYellow;
goalMessage = "300% to Unlock 3x XP for Weekend Brawl";
} else
{
fillColor = C.cAqua;
emptyColor = C.cYellow;
goalMessage = "All Rewards Unlocked!";
flatPercent = 1;
}
int intPercent = (int) (fillPercent * 100);
String progressBar = UtilText.getProgress(null, flatPercent, null, false, 30, emptyColor, fillColor);
_hologram.setText(_name + C.Reset + " " + intPercent + "%", goalMessage, progressBar);
_schematicLoader.update(fillPercent);
}
}
public void increment(Player player, long amount)
{
_statsManager.incrementStat(player, getStatName(), amount);
_counter.addAndGet(amount);
updateVisuals();
}
public long getAmountAdded(Player player)
{
return _statsManager.Get(player).getStat(getStatName());
}
private final String getStatName()
{
return "Global.Fountain." + getDataKey();
}
public String getName()
{
return _name;
}
public String getDataKey()
{
return _dataKey;
}
public void openShop(Player player)
{
_shop.attemptShopOpen(player);
}
public double getFillPercent()
{
return Math.min(3, _counter.getFillPercent());
}
public long getCount()
{
return _counter.getCount();
}
public void reset()
{
_counter.reset();
updateVisuals();
}
@Override
public void onMilestone(GoalCounter counter, int milestone)
{
switch (milestone)
{
case 1:
Bukkit.broadcastMessage(F.main("Fountain", "The Gem Fountain has reached 100%! Brawl Game unlocked this week"));
break;
case 2:
Bukkit.broadcastMessage(F.main("Fountain", "The Gem Fountain has reached 200%! 2x XP enabled for Brawl!"));
break;
case 3:
Bukkit.broadcastMessage(F.main("Fountain", "The Gem Fountain has reached 300%! 3x XP enabled for Brawl!"));
break;
}
}
public void updateBrawlActive()
{
Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("PST"));
int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
if (dayOfWeek == Calendar.FRIDAY || dayOfWeek == Calendar.SATURDAY || dayOfWeek == Calendar.SUNDAY)
{
_brawlActive = true;
}
else
{
_brawlActive = false;
}
}
public boolean isBrawlActive()
{
return _brawlActive;
}
}

View File

@ -0,0 +1,118 @@
package mineplex.core.brawl.fountain;
import mineplex.core.MiniPlugin;
import mineplex.core.account.CoreClientManager;
import mineplex.core.brawl.fountain.command.FountainCommand;
import mineplex.core.brawl.fountain.gui.FountainShop;
import mineplex.core.common.util.C;
import mineplex.core.common.util.UtilServer;
import mineplex.core.common.util.UtilWorld;
import mineplex.core.donation.DonationManager;
import mineplex.core.hologram.HologramManager;
import mineplex.core.stats.StatsManager;
import mineplex.core.updater.UpdateType;
import mineplex.core.updater.event.UpdateEvent;
import mineplex.serverdata.Region;
import mineplex.serverdata.redis.counter.Counter;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
import org.bukkit.event.player.PlayerInteractAtEntityEvent;
import org.bukkit.plugin.java.JavaPlugin;
import java.io.File;
/**
* @author Shaun Bennett
*/
public class FountainManager extends MiniPlugin
{
private HologramManager _hologramManager;
private StatsManager _statsManager;
private DonationManager _donationManager;
// used so we can inject the brawl shop (only on hub) into fountain code
private BrawlShopProvider _brawlShopProvider;
private Fountain _gemFountain;
public FountainManager(JavaPlugin plugin, CoreClientManager clientManager, DonationManager donationManager, HologramManager hologramManager, StatsManager statsManager, BrawlShopProvider shopProvider)
{
super("Counter", plugin);
_hologramManager = hologramManager;
_statsManager = statsManager;
_donationManager = donationManager;
_brawlShopProvider = shopProvider;
World world = Bukkit.getWorlds().get(0);//-43.5, 66, -38.5
int goal = !new File("eu.dat").exists() ? 300000000 : 5000000;
_gemFountain = new Fountain(new Location(world, -32.5, 72, -23.5), new Location(world, -43.5, 67, -38.5),
C.cGreen + "Gem Fountain", "GemFountain_01", goal, this, clientManager, donationManager, _hologramManager, _statsManager);
}
@Override
public void addCommands()
{
addCommand(new FountainCommand(this));
}
@EventHandler
public void updateFountainCount(UpdateEvent event)
{
if (event.getType() != UpdateType.SEC)
return;
_gemFountain.updateBrawlActive();
_gemFountain.updateVisuals();
}
@EventHandler
public void onInteractAtEntity(PlayerInteractAtEntityEvent event)
{
Entity entity = event.getRightClicked();
if (entity.getCustomName() != null && entity.isCustomNameVisible())
{
if (entity.getCustomName().contains("Weekend Brawl") && getBrawlShopProvider() != null)
{
getBrawlShopProvider().getBrawlShop().attemptShopOpen(event.getPlayer());
}
}
}
@EventHandler
public void onDamage(EntityDamageByEntityEvent event)
{
if (!(event.getDamager() instanceof Player))
return;
Entity entity = event.getEntity();
if (entity.getCustomName() != null && entity.isCustomNameVisible())
{
if (entity.getCustomName().contains("Weekend Brawl") && getBrawlShopProvider() != null)
{
getBrawlShopProvider().getBrawlShop().attemptShopOpen(((Player) event.getDamager()));
}
}
}
public Fountain getGemFountain()
{
return _gemFountain;
}
public DonationManager getDonationManager()
{
return _donationManager;
}
public BrawlShopProvider getBrawlShopProvider()
{
return _brawlShopProvider;
}
}

View File

@ -0,0 +1,27 @@
package mineplex.core.brawl.fountain;
import mineplex.core.common.CurrencyType;
import mineplex.core.shop.item.SalesPackageBase;
import org.bukkit.Material;
import org.bukkit.entity.Player;
/**
* @author Shaun Bennett
*/
public class GemFountainSalesPackage extends SalesPackageBase
{
public GemFountainSalesPackage(int gems)
{
super("Add " + gems + " Gems", Material.EMERALD, (byte) 0, new String[] {}, gems, 1);
CurrencyCostMap.put(CurrencyType.GEM, gems);
KnownPackage = false;
OneTimePurchaseOnly = false;
}
@Override
public void sold(Player player, CurrencyType currencyType)
{
}
}

View File

@ -0,0 +1,68 @@
package mineplex.core.brawl.fountain.command;
import mineplex.core.brawl.fountain.FountainManager;
import mineplex.core.command.CommandBase;
import mineplex.core.common.CurrencyType;
import mineplex.core.common.Rank;
import mineplex.core.common.util.Callback;
import mineplex.core.common.util.F;
import mineplex.core.common.util.UtilPlayer;
import mineplex.core.server.util.TransactionResponse;
import org.bukkit.entity.Player;
/**
* Command to add gems to the fountain
* @author Shaun Bennett
*/
public class AddCommand extends CommandBase<FountainManager>
{
public AddCommand(FountainManager plugin)
{
super(plugin, Rank.DEVELOPER, "add");
}
@Override
public void Execute(Player caller, String[] args)
{
if (args == null || args.length != 1)
{
help(caller);
return;
}
try
{
int amount = Integer.parseInt(args[0]);
Plugin.getDonationManager().purchaseUnknownSalesPackage(new Callback<TransactionResponse>()
{
@Override
public void run(TransactionResponse result)
{
if (result == TransactionResponse.Success)
{
Plugin.getGemFountain().increment(caller, amount);
UtilPlayer.message(caller, F.main("Fountain", "Added " + F.elem(amount) + " to the fountain!"));
}
else if (result == TransactionResponse.InsufficientFunds)
{
UtilPlayer.message(caller, F.main("Fountain", "You do not have enough gems!"));
}
else
{
UtilPlayer.message(caller, F.main("Fountain", "There was an error processing your request!"));
}
}
}, caller, "GemFountain.Add", CurrencyType.GEM, amount, false);
}
catch (NumberFormatException ex)
{
help(caller);
}
}
private void help(Player player)
{
UtilPlayer.message(player, F.help("/fountain add", "<amount>", Rank.DEVELOPER));
}
}

View File

@ -0,0 +1,27 @@
package mineplex.core.brawl.fountain.command;
import mineplex.core.brawl.fountain.FountainManager;
import mineplex.core.command.MultiCommandBase;
import mineplex.core.common.Rank;
import org.bukkit.entity.Player;
/**
* @author Shaun Bennett
*/
public class FountainCommand extends MultiCommandBase<FountainManager>
{
public FountainCommand(FountainManager plugin)
{
super(plugin, Rank.DEVELOPER, "fountain");
AddCommand(new AddCommand(plugin));
AddCommand(new GuiCommand(plugin));
AddCommand(new ResetCommand(plugin));
}
@Override
protected void Help(Player caller, String[] args)
{
}
}

View File

@ -0,0 +1,26 @@
package mineplex.core.brawl.fountain.command;
import mineplex.core.brawl.fountain.FountainManager;
import mineplex.core.command.CommandBase;
import mineplex.core.common.Rank;
import mineplex.core.common.util.F;
import mineplex.core.common.util.UtilPlayer;
import org.bukkit.entity.Player;
/**
* Command to open the fountain gui without speaking to the fountain keeper
* @author Shaun Bennett
*/
public class GuiCommand extends CommandBase<FountainManager>
{
public GuiCommand(FountainManager plugin)
{
super(plugin, Rank.DEVELOPER, "gui");
}
@Override
public void Execute(Player caller, String[] args)
{
Plugin.getGemFountain().openShop(caller);
}
}

View File

@ -0,0 +1,26 @@
package mineplex.core.brawl.fountain.command;
import mineplex.core.brawl.fountain.FountainManager;
import mineplex.core.command.CommandBase;
import mineplex.core.common.Rank;
import mineplex.core.common.util.F;
import mineplex.core.common.util.UtilPlayer;
import org.bukkit.entity.Player;
/**
* Command to reset the fountain
* @author Shaun Bennett
*/
public class ResetCommand extends CommandBase<FountainManager>
{
public ResetCommand(FountainManager plugin)
{
super(plugin, Rank.DEVELOPER, "reset");
}
@Override
public void Execute(Player caller, String[] args)
{
Plugin.getGemFountain().reset();
}
}

View File

@ -0,0 +1,92 @@
package mineplex.core.brawl.fountain.gui;
import mineplex.core.account.CoreClientManager;
import mineplex.core.brawl.fountain.Fountain;
import mineplex.core.brawl.fountain.FountainManager;
import mineplex.core.brawl.fountain.gui.button.FountainAddButton;
import mineplex.core.common.CurrencyType;
import mineplex.core.common.MaterialData;
import mineplex.core.common.util.C;
import mineplex.core.donation.DonationManager;
import mineplex.core.shop.item.ShopItem;
import mineplex.core.shop.page.ShopPageBase;
import org.bukkit.Material;
import org.bukkit.entity.Player;
/**
* @author Shaun Bennett
*/
public class FountainPage extends ShopPageBase<FountainManager, FountainShop>
{
private final MaterialData EMPTY_XP = MaterialData.of(Material.STAINED_GLASS_PANE, (byte) 7);
private final MaterialData XP = MaterialData.of(Material.STAINED_GLASS_PANE, (byte) 5);
private final MaterialData EMPTY_XP100 = MaterialData.of(Material.STAINED_GLASS_PANE, (byte) 5);
private final MaterialData XP100 = MaterialData.of(Material.STAINED_GLASS_PANE, (byte) 4);
private final MaterialData EMPTY_XP200 = MaterialData.of(Material.STAINED_GLASS_PANE, (byte) 4);
private final MaterialData XP200 = MaterialData.of(Material.STAINED_GLASS_PANE, (byte) 3);
private final int[] XP_SLOTS = { 2, 3, 4, 5, 6 };
private Fountain _fountain;
public FountainPage(FountainManager plugin, FountainShop shop, CoreClientManager clientManager, DonationManager donationManager, Fountain fountain, Player player)
{
super(plugin, shop, clientManager, donationManager, "Fountain Keeper", player, 27);
_fountain = fountain;
buildPage();
}
@Override
protected void buildPage()
{
// Experience Bar
long added = _fountain.getAmountAdded(getPlayer());
final double fillPercent = _fountain.getFillPercent();
String title = ((int)(fillPercent * 100)) + "% Complete";
boolean canAdd = fillPercent < 3;
String unlockMessage;
if (fillPercent < 1) unlockMessage = "Reach 100% to unlock Weekend Brawl Game";
else if (fillPercent < 2) unlockMessage = "Reach 200% to unlock 2x XP in Brawl";
else if (fillPercent < 3) unlockMessage = "Reach 300% to unlock 3x XP in Brawl";
else unlockMessage = "All rewards unlocked!";
String[] lore = new String[] {
" ",
C.cWhite + unlockMessage,
" ",
C.cWhite + "You have added " + C.cGreen + added + " Gems"};
final double percentForEach = 1D / XP_SLOTS.length;
double check = percentForEach;
double flatPercent = fillPercent == 3 ? 1 : fillPercent - ((int) fillPercent);
for (int i = 0; i < XP_SLOTS.length; i++)
{
MaterialData data;
if (fillPercent < 1) data = flatPercent >= check ? XP : EMPTY_XP;
else if (fillPercent < 2) data = flatPercent >= check ? XP100 : EMPTY_XP100;
else data = flatPercent >= check ? XP200 : EMPTY_XP200;
ShopItem shopItem = new ShopItem(data.getMaterial(), data.getData(), title,
lore, 1, false, false);
setItem(XP_SLOTS[i], shopItem);
check += percentForEach;
}
if (canAdd)
{
int playerGems = getDonationManager().Get(getPlayer()).GetGems();
ShopItem add1 = new ShopItem(Material.EMERALD, "Add 100 Gems", new String[]{}, 1, playerGems < 100, false);
ShopItem add2 = new ShopItem(Material.EMERALD, "Add 1,000 Gems", new String[]{}, 64, playerGems < 1000, false);
ShopItem add3 = new ShopItem(Material.EMERALD_BLOCK, "Add 10,000 Gems", new String[]{}, 1, playerGems < 10000, false);
ShopItem add4 = new ShopItem(Material.EMERALD_BLOCK, "Add 100,000 Gems", new String[]{}, 64, playerGems < 100000, false);
// Buttons
addButton(19, add1, new FountainAddButton(this, 100));
addButton(21, add2, new FountainAddButton(this, 1000));
addButton(23, add3, new FountainAddButton(this, 10000));
addButton(25, add4, new FountainAddButton(this, 100000));
}
}
}

Some files were not shown because too many files have changed in this diff Show More