Add backend system for saving/loading clans mounts with varied stats and skins

This commit is contained in:
AlexTheCoder 2017-04-09 04:52:23 -04:00
parent b7a566744c
commit 03d9032f82
10 changed files with 614 additions and 1 deletions

View File

@ -0,0 +1,54 @@
package mineplex.core.common;
import java.util.Objects;
/**
* Represents an operation that accepts two input arguments and returns no
* result. This is the three-arity specialization of {@link Consumer}.
* Unlike most other functional interfaces, {@code TriConsumer} is expected
* to operate via side-effects.
*
* <p>This is a <a href="package-summary.html">functional interface</a>
* whose functional method is {@link #accept(Object, Object, Object)}.
*
* @param <T> the type of the first argument to the operation
* @param <U> the type of the second argument to the operation
* @param <V> the type of the third argument to the operation
*
* @see Consumer
*/
@FunctionalInterface
public interface TriConsumer<T, U, V>
{
/**
* Performs this operation on the given arguments.
*
* @param t the first input argument
* @param u the second input argument
* @param v the third input argument
*/
void accept(T t, U u, V v);
/**
* Returns a composed {@code TriConsumer} that performs, in sequence, this
* operation followed by the {@code after} operation. If performing either
* operation throws an exception, it is relayed to the caller of the
* composed operation. If performing this operation throws an exception,
* the {@code after} operation will not be performed.
*
* @param after the operation to perform after this operation
* @return a composed {@code TriConsumer} that performs in sequence this
* operation followed by the {@code after} operation
* @throws NullPointerException if {@code after} is null
*/
default TriConsumer<T, U, V> andThen(TriConsumer<? super T, ? super U, ? super V> after)
{
Objects.requireNonNull(after);
return (f, s, t) -> {
accept(f, s, t);
after.accept(f, s, t);
};
}
}

View File

@ -175,7 +175,7 @@ public class CoreClientManager extends MiniPlugin
}
/**
* Get the databse account id for a player. Requires the player is online
* Get the database account id for a player. Requires the player is online
*
* @param player
* @return

View File

@ -0,0 +1,181 @@
package mineplex.game.clans.clans.mounts;
import org.bukkit.Material;
import org.bukkit.craftbukkit.v1_8_R3.entity.CraftHorse;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Horse.Color;
import org.bukkit.entity.Horse.Style;
import org.bukkit.entity.Horse.Variant;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import mineplex.core.common.TriConsumer;
import mineplex.core.common.util.C;
import mineplex.core.common.util.UtilServer;
import net.minecraft.server.v1_8_R3.GenericAttributes;
public class Mount
{
private Player _owner;
private CraftHorse _entity;
public Mount(Player owner, CraftHorse entity)
{
_owner = owner;
_entity = entity;
}
public void despawn()
{
UtilServer.CallEvent(new MountDespawnEvent(this));
_entity.remove();
}
public static enum SkinType
{
;
private final int _id;
private final String _packageName;
private final String _displayName;
private final Color _color;
private final Variant _variant;
private final Style _style;
private SkinType(int id, String packageName, String displayName, Color color, Variant variant, Style style)
{
_id = id;
_packageName = packageName;
_displayName = displayName;
_color = color;
_variant = variant;
_style = style;
}
public int getId()
{
return _id;
}
public String getPackageName()
{
return _packageName;
}
public String getDisplayName()
{
return _displayName;
}
public Color getColor()
{
return _color;
}
public Variant getVariant()
{
return _variant;
}
public Style getStyle()
{
return _style;
}
public static SkinType getFromId(int id)
{
for (SkinType type : SkinType.values())
{
if (type.getId() == id)
{
return type;
}
}
return null;
}
}
public static enum MountType
{
HORSE(1, C.cGold + "Horse", (owner, skin, stats) ->
{
CraftHorse horse = (CraftHorse) owner.getWorld().spawnEntity(owner.getLocation(), EntityType.HORSE);
horse.setAdult();
horse.setAgeLock(true);
horse.setBreed(false);
horse.setVariant(skin.getVariant());
horse.setColor(skin.getColor());
horse.setStyle(skin.getStyle());
horse.setTamed(true);
horse.getInventory().setSaddle(new ItemStack(Material.SADDLE));
horse.setOwner(owner);
horse.setJumpStrength(stats.JumpStrength);
horse.getHandle().getAttributeInstance(GenericAttributes.MOVEMENT_SPEED).setValue(stats.Speed);
horse.setCustomNameVisible(true);
horse.setCustomName(owner.getName() + "'s " + skin.getDisplayName());
horse.setPassenger(owner);
Mount mount = new Mount(owner, horse);
UtilServer.CallEvent(new MountSpawnEvent(mount));
}),
STORAGE(2, C.cGold + "Storage", (owner, skin, stats) ->
{
CraftHorse horse = (CraftHorse) owner.getWorld().spawnEntity(owner.getLocation(), EntityType.HORSE);
horse.setAdult();
horse.setAgeLock(true);
horse.setBreed(false);
horse.setVariant(skin.getVariant());
horse.setTamed(true);
horse.getInventory().setSaddle(new ItemStack(Material.SADDLE));
horse.setOwner(owner);
horse.setJumpStrength(stats.JumpStrength);
horse.getHandle().getAttributeInstance(GenericAttributes.MOVEMENT_SPEED).setValue(stats.Speed);
horse.setCustomNameVisible(true);
horse.setCustomName(owner.getName() + "'s " + skin.getDisplayName());
horse.setCarryingChest(true);
horse.setPassenger(owner);
Mount mount = new Mount(owner, horse);
UtilServer.CallEvent(new MountSpawnEvent(mount));
})
;
private final int _id;
private final String _displayName;
private final TriConsumer<Player, SkinType, MountStatToken> _spawnHandler;
private MountType(int id, String displayName, TriConsumer<Player, SkinType, MountStatToken> spawnHandler)
{
_id = id;
_displayName = displayName;
_spawnHandler = spawnHandler;
}
public int getId()
{
return _id;
}
public String getDisplayName()
{
return _displayName;
}
public void spawn(Player owner, SkinType skinType, MountStatToken statToken)
{
_spawnHandler.accept(owner, skinType, statToken);
}
public static MountType getFromId(int id)
{
for (MountType type : MountType.values())
{
if (type.getId() == id)
{
return type;
}
}
return null;
}
}
}

View File

@ -0,0 +1,34 @@
package mineplex.game.clans.clans.mounts;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
/**
* Event called before a mount despawns
*/
public class MountDespawnEvent extends Event
{
private static final HandlerList handlers = new HandlerList();
private final Mount _mount;
public MountDespawnEvent(Mount mount)
{
_mount = mount;
}
public Mount getMount()
{
return _mount;
}
public HandlerList getHandlers()
{
return handlers;
}
public static HandlerList getHandlerList()
{
return handlers;
}
}

View File

@ -0,0 +1,63 @@
package mineplex.game.clans.clans.mounts;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.UUID;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
import mineplex.core.MiniDbClientPlugin;
import mineplex.core.account.CoreClientManager;
import mineplex.core.common.Pair;
import mineplex.game.clans.clans.mounts.Mount.MountType;
import mineplex.game.clans.clans.mounts.Mount.SkinType;
import mineplex.serverdata.Utility;
public class MountManager extends MiniDbClientPlugin<MountOwnerData>
{
private static final double[] JUMP_BOUNDS = {0.5, 2};
private static final double[] SPEED_BOUNDS = {0.1125, 0.3375};
private static final int[] STRENGTH_BOUNDS = {1, 3};
private MountRepository _repository;
public MountManager(JavaPlugin plugin, CoreClientManager clientManager)
{
super("Clans Mount Manager", plugin, clientManager);
}
public void giveMount(Player player, MountType type)
{
Pair<MountToken, MountStatToken> tokens = Get(player).grantMount(type, SPEED_BOUNDS, JUMP_BOUNDS, STRENGTH_BOUNDS);
_repository.saveMount(ClientManager.getAccountId(player), tokens.getLeft(), tokens.getRight());
}
@Override
public String getQuery(int accountId, String uuid, String name)
{
return "SELECT am.id, am.mountTypeId, am.mountSkinId, ms.statToken FROM accountClansMounts AS am INNER JOIN clansMountStats AS ms ON ms.mountId = am.id WHERE am.accountId=" + accountId + ";";
}
@Override
public void processLoginResultSet(String playerName, UUID uuid, int accountId, ResultSet resultSet) throws SQLException
{
MountOwnerData data = new MountOwnerData();
while (resultSet.next())
{
MountToken token = new MountToken();
token.Id = resultSet.getInt("id");
token.Type = MountType.getFromId(resultSet.getInt("mountTypeId"));
token.Skin = SkinType.getFromId(resultSet.getInt("mountSkinId"));
MountStatToken statToken = Utility.deserialize(resultSet.getString("statToken"), MountStatToken.class);
data.acceptLoad(token, statToken);
}
Set(uuid, data);
}
@Override
protected MountOwnerData addPlayer(UUID uuid)
{
return new MountOwnerData();
}
}

View File

@ -0,0 +1,60 @@
package mineplex.game.clans.clans.mounts;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import mineplex.core.common.Pair;
import mineplex.core.common.util.UtilMath;
import mineplex.game.clans.clans.mounts.Mount.MountType;
public class MountOwnerData
{
private Map<MountToken, MountStatToken> _mounts = new HashMap<>();
public List<Pair<MountToken, MountStatToken>> getOwnedMounts(boolean onlyInitialized)
{
return _mounts.entrySet().stream().filter(entry -> onlyInitialized ? entry.getKey().Id != -1 : true).map(entry -> Pair.create(entry.getKey(), entry.getValue())).collect(Collectors.toList());
}
public boolean ownsMount(MountType type)
{
return _mounts.keySet().stream().anyMatch(token->token.Type == type);
}
public void acceptLoad(MountToken token, MountStatToken statToken)
{
_mounts.put(token, statToken);
}
public Pair<MountToken, MountStatToken> grantMount(MountType type, double[] speedRange, double[] jumpRange, int[] strengthRange)
{
double speed = UtilMath.random(speedRange[0], speedRange[1]);
double jump = UtilMath.random(jumpRange[0], jumpRange[1]);
int strength = UtilMath.rRange(strengthRange[0], strengthRange[1]);
MountToken token = new MountToken();
token.Type = type;
MountStatToken statToken = new MountStatToken();
statToken.JumpStrength = jump;
statToken.Speed = speed;
statToken.Strength = strength;
_mounts.put(token, statToken);
return Pair.create(token, statToken);
}
public int[] revokeMount(MountType type)
{
Integer[] array = _mounts.keySet().stream().filter(token->token.Type == type).map(token->token.Id).toArray(size->new Integer[size]);
_mounts.keySet().removeIf(token->token.Type == type);
int[] returnArray = new int[array.length];
for (int i = 0; i < returnArray.length; i++)
{
returnArray[i] = array[i];
}
return returnArray;
}
}

View File

@ -0,0 +1,168 @@
package mineplex.game.clans.clans.mounts;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import org.bukkit.plugin.java.JavaPlugin;
import mineplex.core.common.Pair;
import mineplex.serverdata.Utility;
import mineplex.serverdata.database.DBPool;
import mineplex.serverdata.database.RepositoryBase;
import mineplex.serverdata.database.column.ColumnInt;
import mineplex.serverdata.database.column.ColumnVarChar;
/**
* Database repository class for mounts
*/
public class MountRepository extends RepositoryBase
{
private static final String CREATE_MOUNTS_TABLE = "CREATE TABLE IF NOT EXISTS accountClansMounts (id INT NOT NULL AUTO_INCREMENT,"
+ "accountId INT NOT NULL,"
+ "mountTypeId INT NOT NULL,"
+ "mountSkinId INT NOT NULL,"
+ "UNIQUE INDEX typeIndex (accountId, mountTypeId),"
+ "INDEX skinIndex (mountSkinId),"
+ "PRIMARY KEY (id));";
private static final String CREATE_MOUNT_STATS_TABLE = "CREATE TABLE IF NOT EXISTS clansMountStats (mountId INT NOT NULL,"
+ "accountId INT NOT NULL,"
+ "statToken VARCHAR(20) NOT NULL,"
+ "PRIMARY KEY (mountId));";
private static final String SAVE_MOUNT = "INSERT INTO accountClansMounts (accountId, mountTypeId, mountSkinId) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE mountSkinId=VALUES(mountSkinId);";
private static final String SAVE_MOUNT_STATS = "INSERT INTO clansMountStats (mountId, statToken) VALUES (?, ?) ON DUPLICATE KEY UPDATE statToken=VALUES(statToken);";
private static final String DELETE_MOUNT = "DELETE FROM accountClansMounts WHERE id=?;";
private static final String DELETE_MOUNT_STATS = "DELETE FROM clansMountStats WHERE mountId=?;";
private MountManager _mountManager;
public MountRepository(JavaPlugin plugin, MountManager mountManager)
{
super(DBPool.getAccount());
_mountManager = mountManager;
}
/**
* Saves a mount into the database
* @param accountId The owner's account id
* @param token The mount token to save
* @param statToken The stat token to save
*/
public void saveMount(final int accountId, final MountToken token, final MountStatToken statToken)
{
_mountManager.runAsync(() ->
{
try (Connection connection = getConnection();)
{
if (token.Id == -1)
{
executeInsert(connection, SAVE_MOUNT, idResult ->
{
if (idResult.next())
{
token.Id = idResult.getInt(1);
}
}, null, new ColumnInt("accountId", accountId), new ColumnInt("mountTypeId", token.Type.getId()), new ColumnInt("mountSkinId", token.Skin.getId()));
}
else
{
executeUpdate(connection, SAVE_MOUNT, null, new ColumnInt("accountId", accountId), new ColumnInt("mountTypeId", token.Type.getId()), new ColumnInt("mountSkinId", token.Skin.getId()));
}
if (token.Id == -1)
{
return;
}
executeUpdate(connection, SAVE_MOUNT_STATS, null, new ColumnInt("mountId", token.Id), new ColumnVarChar("statToken", 20, Utility.serialize(statToken)));
}
catch (SQLException e)
{
e.printStackTrace();
}
});
}
/**
* Saves a list of mounts into the database
* @param accountId The owner's account id
* @param tokens The list of token pairs to save
*/
public void saveMounts(final int accountId, final List<Pair<MountToken, MountStatToken>> tokens)
{
_mountManager.runAsync(() ->
{
try (Connection connection = getConnection())
{
for (Pair<MountToken, MountStatToken> tokenPair : tokens)
{
MountToken token = tokenPair.getLeft();
MountStatToken statToken = tokenPair.getRight();
if (token.Id == -1)
{
executeInsert(connection, SAVE_MOUNT, idResult ->
{
if (idResult.next())
{
token.Id = idResult.getInt(1);
}
}, null, new ColumnInt("accountId", accountId), new ColumnInt("mountTypeId", token.Type.getId()), new ColumnInt("mountSkinId", token.Skin.getId()));
}
else
{
executeUpdate(connection, SAVE_MOUNT, null, new ColumnInt("accountId", accountId), new ColumnInt("mountTypeId", token.Type.getId()), new ColumnInt("mountSkinId", token.Skin.getId()));
}
if (token.Id == -1)
{
continue;
}
executeUpdate(connection, SAVE_MOUNT_STATS, null, new ColumnInt("mountId", token.Id), new ColumnVarChar("statToken", 20, Utility.serialize(statToken)));
}
}
catch (SQLException e)
{
e.printStackTrace();
}
});
}
/**
* Deletes a mount from the database
* @param token The mount to delete
*/
public void deleteMount(final MountToken token)
{
if (token.Id == -1)
{
return;
}
_mountManager.runAsync(() ->
{
executeUpdate(DELETE_MOUNT, new ColumnInt("id", token.Id));
executeUpdate(DELETE_MOUNT_STATS, new ColumnInt("mountId", token.Id));
});
}
/**
* Deletes an array from the database
* @param ids The mount ids to delete
*/
public void deleteMounts(final int[] ids)
{
if (ids.length <= 0)
{
return;
}
_mountManager.runAsync(() ->
{
String idList = ids[0] + "";
for (int i = 1; i < ids.length; i++)
{
idList += ("," + ids[i]);
}
executeUpdate(DELETE_MOUNT.replace("id=?;", "id IN (" + idList + ");"));
executeUpdate(DELETE_MOUNT_STATS.replace("mountId=?;", "mountId IN (" + idList + ");"));
});
}
}

View File

@ -0,0 +1,34 @@
package mineplex.game.clans.clans.mounts;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
/**
* Event called after a mount spawns
*/
public class MountSpawnEvent extends Event
{
private static final HandlerList handlers = new HandlerList();
private final Mount _mount;
public MountSpawnEvent(Mount mount)
{
_mount = mount;
}
public Mount getMount()
{
return _mount;
}
public HandlerList getHandlers()
{
return handlers;
}
public static HandlerList getHandlerList()
{
return handlers;
}
}

View File

@ -0,0 +1,8 @@
package mineplex.game.clans.clans.mounts;
public class MountStatToken
{
public double JumpStrength = 0.7;
public double Speed = .2250;
public int Strength = 1;
}

View File

@ -0,0 +1,11 @@
package mineplex.game.clans.clans.mounts;
import mineplex.game.clans.clans.mounts.Mount.MountType;
import mineplex.game.clans.clans.mounts.Mount.SkinType;
public class MountToken
{
public int Id = -1;
public MountType Type = null;
public SkinType Skin = null;
}