Last active
July 10, 2019 02:59
-
-
Save cadenkriese/8d1af303c36166d368c48b90457dca10 to your computer and use it in GitHub Desktop.
Excerpt of MineSwine Vehicles Code.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//© MineSwine 2019. | |
//Written by Caden Kriese (flogic) | |
public class Vehicle { | |
private World world; | |
private ItemStack[] inventoryContents; | |
private ItemStack[] inventoryArmorContents; | |
private ItemStack weapon; | |
private ArmorStand stand; | |
private VehicleType type; | |
private BossBar speedBar; | |
private BossBar healthBar; | |
private Player lastDamager; | |
private Player rider; | |
private double speed; | |
private double acceleration; | |
private int health; | |
private long lastDamageTime; | |
private boolean flyable = true; | |
private boolean modelVisible = true; | |
public Vehicle(VehicleType type) { | |
this.type = type; | |
lastDamageTime = 0; | |
health = type.getMaxHealth(); | |
acceleration = (double) type.getAcceleration() / 50; | |
speed = type.getMaxSpeed(); | |
speedBar = | |
Bukkit.createBossBar( | |
ChatColor.translateAlternateColorCodes( | |
'&', type.getColor() + "&o&l" + type.getName() + " &8&l- &eSPEED"), | |
BarColor.YELLOW, | |
BarStyle.SOLID); | |
healthBar = | |
Bukkit.createBossBar( | |
ChatColor.translateAlternateColorCodes( | |
'&', type.getColor() + "&o&l" + type.getName() + " &8&l- &4HEALTH"), | |
BarColor.RED, | |
BarStyle.SOLID); | |
GameDefinition gameDefinition = JediCraft.getInstance().getJediConfig().getGameDefinition(); | |
world = gameDefinition.getGameWorld(); | |
} | |
private static void killRider(Player rider, Player lastDamager) { | |
if (rider != null) { | |
if (lastDamager != null) { | |
rider.eject(); | |
rider.setLastDamageCause( | |
new EntityDamageByEntityEvent( | |
lastDamager, rider, EntityDamageEvent.DamageCause.ENTITY_ATTACK, 300)); | |
rider.setHealth(0); | |
} else { | |
rider.eject(); | |
rider.setHealth(0); | |
} | |
} | |
} | |
public void spawn(Location loc) { | |
loc.setYaw(0); | |
stand = world.spawn(loc, ArmorStand.class); | |
speed = 0; | |
stand.setGravity(true); | |
stand.setItemInHand(type.getItem()); | |
stand.setVisible(false); | |
stand.setArms(true); | |
stand.setBasePlate(false); | |
stand.setInvulnerable(true); | |
stand.setMaxHealth(type.getMaxHealth()); | |
stand.setHealth(type.getMaxHealth()); | |
health = type.getMaxHealth(); | |
flyable = true; | |
stand.setCustomName( | |
ChatColor.translateAlternateColorCodes( | |
'&', type.getColor() + "&o&l" + type.getName() + " &8[" + getHealthBarText() + "&8]")); | |
stand.setCustomNameVisible(true); | |
weapon = WeaponUtils.spawnItemStack(type.getWeapon()); | |
stand.setRightArmPose(EulerAngleUtils.getInstance().getDefaultAngle()); | |
Entity standEntity = stand; | |
// HITBOXES | |
// Equivalent of doing CraftEntity.getHandle().setSize(float, float); | |
try { | |
Class<?> craftEntityClazz = NMSUtils.getOBCClass("entity.CraftEntity"); | |
Class<?> nmsEntityClazz = NMSUtils.getNMSClass("Entity"); | |
if (craftEntityClazz == null || nmsEntityClazz == null) | |
return; | |
Method getHandle = NMSUtils.getMethod(craftEntityClazz, "getHandle"); | |
Object nmsEntity = getHandle.invoke(standEntity); | |
Method setSize = NMSUtils.getMethod(nmsEntityClazz, "setSize", Float.class, Float.class); | |
setSize.invoke(nmsEntity, type.getXzSize(), type.getySize()); | |
} catch (Exception e) { | |
StringUtils.printException(e); | |
} | |
VehicleManager.getInstance().addVehicle(this); | |
} | |
public void setRider(Player rider) { | |
if (this.getRider() != null) { | |
playerExit(); | |
} | |
if (PlayerManager.getInstance().getGamePlayer(rider).getVehicle() != null) { | |
PlayerManager.getInstance().getGamePlayer(rider).getVehicle().playerExit(); | |
} | |
inventoryContents = rider.getInventory().getContents(); | |
inventoryArmorContents = rider.getInventory().getArmorContents(); | |
rider.getInventory().clear(); | |
rider.getInventory().setArmorContents(new ItemStack[0]); | |
this.rider = rider; | |
rider | |
.getInventory() | |
.setItem( | |
8, | |
new ItemStackBuilder(Material.STAINED_CLAY) | |
.setDurability((short) 5) | |
.setName(ChatColor.GREEN + "MODEL ENABLED") | |
.build()); | |
rider.setCanPickupItems(false); | |
rider.addPotionEffect(new PotionEffect(PotionEffectType.INVISIBILITY, 99999, 2, false, false)); | |
GamePlayer gp = PlayerManager.getInstance().getGamePlayer(rider); | |
gp.setVehicle(this); | |
gp.setAntiCheatLenient(true); | |
short durability = type.getItem().getDurability(); | |
if (type.hasSkins()) { | |
durability += PlayerManager.getInstance().getGamePlayer(rider).getVehicleSkin(); | |
} | |
stand.setItemInHand( | |
new ItemStackBuilder(Material.FLINT_AND_STEEL) | |
.setDurability(durability) | |
.build()); | |
stand.setGravity(true); | |
stand.setRightArmPose( | |
stand | |
.getRightArmPose() | |
.setX(Math.toRadians(rider.getLocation().getPitch())) | |
.setY(Math.toRadians(rider.getLocation().getYaw()))); | |
stand.setPassenger(rider); | |
speedBar.addPlayer(rider); | |
healthBar.addPlayer(rider); | |
updateUI(); | |
LocaleManager.ENTER_VEHICLE.prefixedMessage().send(rider); | |
flyable = true; | |
} | |
private String getHealthBarText() { | |
//10 | |
String bar = "::::::::::"; | |
int healthSub = (health / (type.getMaxHealth() / bar.length())); | |
bar = "&a" + bar.substring(0, healthSub) + "&c" + bar.substring(healthSub); | |
return ChatColor.translateAlternateColorCodes('&', bar); | |
} | |
private Vector getDirection() { | |
return ArmorStandUtils.getUtil() | |
.getVector( | |
stand.getRightArmPose().getY() - Math.toRadians(180), | |
(stand.getRightArmPose().getX() - Math.toRadians(90)) * -1) | |
.normalize(); | |
} | |
public void update(KeyType currentKey) { | |
if (speed > 10 | |
&& (rider.getInventory().getItem(4) == null | |
|| rider.getInventory().getItem(4).getType() != Material.BOWL)) { | |
if (weapon.getAmount() > 1) { | |
weapon.setAmount(1); | |
} | |
rider.getInventory().setItem(4, weapon); | |
} else if (speed < 10) { | |
stand.setFallDistance(0); | |
} | |
// Model Visibility | |
if (rider.getInventory().getHeldItemSlot() == 8) { | |
ProtocolManager manager = JediCraft.getInstance().getProtocol(); | |
PacketContainer container = new PacketContainer(PacketType.Play.Server.ENTITY_EQUIPMENT); | |
modelVisible = !modelVisible; | |
String message = | |
ChatColor.DARK_GRAY | |
+ "Model Visibility: " | |
+ (modelVisible ? ChatColor.GREEN + "TRUE" : ChatColor.RED + "FALSE"); | |
new Message(message).sendAsActionBarMessage(rider); | |
container.getItemSlots().write(0, EnumWrappers.ItemSlot.MAINHAND); | |
container.getIntegers().write(0, stand.getEntityId()); | |
if (modelVisible) { | |
container.getItemModifier().write(0, new ItemStack(stand.getItemInHand())); | |
rider | |
.getInventory() | |
.setItem( | |
8, | |
new ItemStackBuilder(Material.STAINED_CLAY) | |
.setDurability((short) 5) | |
.setName(ChatColor.GREEN + "MODEL ENABLED") | |
.build()); | |
} else { | |
container.getItemModifier().write(0, new ItemStack(Material.AIR)); | |
rider | |
.getInventory() | |
.setItem( | |
8, | |
new ItemStackBuilder(Material.STAINED_CLAY) | |
.setDurability((short) 14) | |
.setName(ChatColor.RED + "MODEL DISABLED") | |
.build()); | |
} | |
try { | |
manager.sendServerPacket(rider, container); | |
} catch (InvocationTargetException exception) { | |
StringUtils.printException(exception); | |
} | |
} | |
if (rider.getInventory().getHeldItemSlot() != 4) { | |
rider.getInventory().setHeldItemSlot(4); | |
} | |
if (rider.getVehicle() == null || rider.getVehicle() != stand) { | |
playerExit(); | |
} | |
if (!flyable) { | |
updateUI(); | |
return; | |
} | |
if (currentKey == KeyType.FORWARDS) { | |
if (speed < type.getMaxSpeed()) { | |
if (speed + acceleration > type.getMaxSpeed()) { | |
speed = type.getMaxSpeed(); | |
} else { | |
speed += acceleration; | |
} | |
updateUI(); | |
} | |
} else if (currentKey == KeyType.BACKWARDS) { | |
if (speed > 0) { | |
if (speed - acceleration < 0) { | |
speed = 0; | |
} else { | |
speed -= acceleration; | |
} | |
updateUI(); | |
} | |
} else if (currentKey == KeyType.SNEAK) { | |
playerExit(); | |
} | |
updateVelocity(); | |
} | |
private void updateVelocity() { | |
if (rider != null) { | |
//CALCULATE YAW | |
double standYaw = Math.toDegrees(stand.getRightArmPose().getY()); | |
double playerYaw = rider.getLocation().getYaw(); | |
double difference = ArmorStandUtils.getUtil().angleDifference(standYaw, playerYaw); | |
double roll = 0; | |
if (Math.round(standYaw) != Math.round(playerYaw)) { | |
if (difference > -3 && difference < 3) { | |
// Not much difference to spline left just set it to players yaw | |
standYaw = playerYaw; | |
} else { | |
//Calculate movement spline based on handling. | |
double degrees = (difference / (13 - type.getHandling())) + standYaw; | |
//reduce difference to a reasonable degree for roll. | |
roll = difference * 0.015; | |
double maxRoll = Math.toRadians(25); | |
if (type.isLandVehicle()) | |
maxRoll = Math.toRadians(15); | |
// dont roll more than 25 degrees or 15 for land vehicles | |
if (roll < -maxRoll) { | |
roll = -maxRoll; | |
} else if (roll > maxRoll) { | |
roll = maxRoll; | |
} | |
standYaw = degrees; | |
} | |
} | |
//Calculate pitch based on incline | |
double playerPitch = rider.getLocation().getPitch() - 90; | |
double standPitch = Math.toDegrees(stand.getRightArmPose().getX()); | |
if (type.isLandVehicle()) { | |
standPitch = -90; | |
Vector direction = getDirection(); | |
direction.setY(0); | |
BlockIterator blockIterator = new BlockIterator(stand.getLocation().getWorld(), stand.getLocation().toVector(), direction, 0, 7); | |
if (!blockIterator.hasNext()) | |
return; | |
Block block = null; | |
while (blockIterator.hasNext()) { | |
block = blockIterator.next(); | |
if (block.getType() != null && block.getType() != Material.AIR) { | |
break; | |
} | |
} | |
Location loc = new Location(block.getWorld(), block.getX(), block.getY(), block.getZ()); | |
boolean decline = loc.getBlock().getType() == Material.AIR; | |
boolean tooHigh = false; | |
if (loc.getBlock().getType() == Material.AIR) { | |
while (loc.getBlock().getType() == Material.AIR) { | |
loc.setY(loc.getBlockY() - 1); | |
} | |
//make it relative to the vehicle which is 1 block above the ground. | |
loc.add(0, 1, 0); | |
} else { | |
while (loc.getBlock().getType() != Material.AIR) { | |
loc.setY(loc.getBlockY() + 1); | |
if (loc.getBlockY() - block.getY() >= 3) { | |
tooHigh = true; | |
break; | |
} | |
} | |
if (loc != block.getLocation()) | |
loc.add(0, type.getHoverDistance(), 0); | |
} | |
double opposite = loc.distance(block.getLocation()); | |
double adjacent = block.getLocation().distance(stand.getLocation()); | |
//tan^-1(opp/adj)=𝛳 | |
double inclineAngle = Math.toDegrees(Math.atan2(opposite, adjacent)); | |
if (inclineAngle > 30) | |
inclineAngle = 30; | |
if (!decline) | |
inclineAngle *= -1; | |
if (tooHigh) | |
inclineAngle = 0; | |
standPitch += inclineAngle; | |
} else { | |
if (Math.round(standPitch) != Math.round(playerPitch)) { | |
// Not much difference to spline left just set it to players pitch | |
if (standPitch - playerPitch > -3 && standPitch - rider.getLocation().getPitch() < 3) { | |
standPitch = playerPitch; | |
} else { | |
standPitch = ((playerPitch - standPitch) / 12) + standPitch; | |
} | |
} | |
} | |
//TODO implement this method of rotating instead of the arm yaw. | |
// net.minecraft.server.v1_12_R1.Entity nmsEntity = ((CraftEntity) stand).getHandle(); | |
// | |
// NBTTagCompound tag = new NBTTagCompound(); | |
// | |
// nmsEntity.c(tag); | |
// | |
// tag.setFloat("Rotation", (float) standYaw); | |
// | |
// EntityLiving el = (EntityLiving) nmsEntity; | |
// el.a(tag); | |
// try { | |
// Class<?> craftEntityClazz = NMSUtils.getOBCClass("entity.CraftEntity"); | |
// Class<?> nmsEntityClazz = NMSUtils.getNMSClass("Entity"); | |
// Class<?> nmsEntityLivingClazz = NMSUtils.getNMSClass("EntityLiving"); | |
// Class<?> nmsNBTTagClazz = NMSUtils.getNMSClass("NBTTagCompound"); | |
// | |
// if (craftEntityClazz == null || nmsEntityClazz == null || nmsNBTTagClazz == null) { | |
// System.out.println("CLAZZ NULL"); | |
// return; | |
// } | |
// | |
// Method getHandle = NMSUtils.getMethod(craftEntityClazz, "getHandle"); | |
// Object nmsEntity = getHandle.invoke((stand)); | |
// Object entityLiving = nmsEntityLivingClazz.cast(nmsEntity); | |
// Object nbtTagCompound = nmsNBTTagClazz.newInstance(); | |
// | |
// Method c = NMSUtils.getMethod(nmsEntityClazz, "c", nmsNBTTagClazz); | |
// c.invoke(nbtTagCompound); | |
// | |
// Method setDouble = NMSUtils.getMethod(nmsNBTTagClazz, "setDouble", String.class, Double.class); | |
// setDouble.invoke(nbtTagCompound, "Rotation", standYaw); | |
// | |
// Method saveTagData = NMSUtils.getMethod(nmsEntityClazz, "a", nmsNBTTagClazz); | |
// saveTagData.invoke(entityLiving, nbtTagCompound); | |
// } catch (Exception e) { | |
// StringUtils.printException(e); | |
// } | |
stand.setRightArmPose(new EulerAngle(Math.toRadians(standPitch), Math.toRadians(standYaw), roll)); | |
// Equation to convert Blocks Per Second to vector. | |
Vector speedVec = getDirection().multiply(speed / 20); | |
if (type.isLandVehicle()) | |
speedVec = ArmorStandUtils.getUtil().getVector(Math.toRadians(standYaw - 180), -1 * Math.toRadians(standPitch - 90)).multiply(speed / 20); | |
stand.setVelocity(speedVec); | |
} | |
} | |
private void updateUI() { | |
speedBar.setProgress(speed / type.getMaxSpeed()); | |
if (health > 0) | |
healthBar.setProgress((double) health / type.getMaxHealth()); | |
else | |
healthBar.setProgress(0.0d); | |
if (speed > 10 | |
&& (rider.getInventory().getItem(4) == null || rider.getInventory().getItem(4).getType() == Material.AIR)) { | |
rider.getInventory().setItem(4, weapon); | |
} else if (speed < 10 | |
&& rider.getInventory().getItem(4) != null | |
&& rider.getInventory().getItem(4).getType() != Material.AIR) { | |
weapon = rider.getInventory().getItem(4); | |
rider.getInventory().setItem(4, new ItemStack(Material.AIR)); | |
} | |
String nameSuffix = rider.getName().endsWith("s") ? "'" : "'s"; | |
stand.setCustomName( | |
ChatColor.translateAlternateColorCodes( | |
'&', | |
type.getColor() | |
+ "&l" | |
+ rider.getName() | |
+ nameSuffix | |
+ " &o" | |
+ type.getName() | |
+ "&8[" | |
+ getHealthBarText() | |
+ "&8]")); | |
} | |
public void damage(double amount, EntityDamageEvent.DamageCause cause) { | |
if (health <= 0 && stand.isOnGround()) { | |
killRider(rider, lastDamager); | |
world.createExplosion( | |
stand.getLocation().getX(), | |
stand.getLocation().getY(), | |
stand.getLocation().getZ(), | |
1.6f, | |
false, | |
false); | |
destroy(true); | |
return; | |
} | |
if (cause == EntityDamageEvent.DamageCause.FALL && type.isLandVehicle()) | |
return; | |
// DEATH MECHANICS | |
if (cause == EntityDamageEvent.DamageCause.FALL && health <= 0) { | |
killRider(rider, lastDamager); | |
world.createExplosion( | |
stand.getLocation().getX(), | |
stand.getLocation().getY(), | |
stand.getLocation().getZ(), | |
1.6f, | |
false, | |
false); | |
destroy(true); | |
return; | |
} else if (health == -1) { | |
return; | |
} | |
amount *= type.getArmorDamageReduction(); | |
if (amount >= health) { | |
vehicleDeath(); | |
return; | |
} | |
if (amount > health) { | |
amount = health; | |
} | |
health -= amount; | |
// Don't let the armor stand die. | |
stand.setHealth(stand.getMaxHealth()); | |
if (rider != null) { | |
rider.playSound(rider.getLocation(), "vehicle.damage", 1, 1); | |
VignetteUtils.getInstance() | |
.fadeBorder(rider, (int) (100 - Math.round((double) ((health * 100) / type.getMaxHealth()))), 5); | |
new Message(ChatColor.DARK_RED + "- " + Math.round(amount)).sendAsActionBarMessage(rider); | |
updateUI(); | |
} else { | |
stand.setCustomName( | |
ChatColor.translateAlternateColorCodes( | |
'&', | |
type.getColor() + "&l&o" + type.getName() + " &8[" + getHealthBarText() + "&8]")); | |
} | |
} | |
private void vehicleDeath() { | |
health = -1; | |
if (rider != null && !stand.isOnGround() && !type.isLandVehicle()) { | |
LocaleManager.VEHICLE_KILLED.prefixedMessage().send(rider); | |
updateUI(); | |
} | |
Vector speedVec = stand.getVelocity().multiply(2); | |
stand.setVelocity(speedVec); | |
world.createExplosion( | |
stand.getLocation().getX(), | |
stand.getLocation().getY(), | |
stand.getLocation().getZ(), | |
1f, | |
false, | |
false); | |
flyable = false; | |
if (stand.isOnGround() || type.isLandVehicle()) { | |
if (rider != null) { | |
rider.eject(); | |
rider.setHealth(0); | |
} | |
world.createExplosion( | |
stand.getLocation().getX(), | |
stand.getLocation().getY(), | |
stand.getLocation().getZ(), | |
1.6f, | |
false, | |
false); | |
destroy(true); | |
health = 0; | |
return; | |
} | |
//Create a 'Falling out of the sky' effect, | |
//giving the player some time to escape their vehicle. | |
new BukkitRunnable() { | |
@Override | |
public void run() { | |
if (stand.getPassenger() != null) { | |
killRider(rider, lastDamager); | |
world.createExplosion( | |
stand.getLocation().getX(), | |
stand.getLocation().getY(), | |
stand.getLocation().getZ(), | |
1.6f, | |
false, | |
false); | |
destroy(true); | |
} | |
} | |
}.runTaskLater(JediCraft.getInstance(), 5 * 20L); | |
} | |
public void destroy(boolean remove) { | |
speedBar.removeAll(); | |
healthBar.removeAll(); | |
if (rider != null) | |
playerExit(); | |
rider = null; | |
stand.remove(); | |
if (remove) | |
VehicleManager.getInstance().removeVehicle(this); | |
} | |
public void playerExit() { | |
if (rider != null) { | |
ProtocolManager manager = JediCraft.getInstance().getProtocol(); | |
PacketContainer container = new PacketContainer(PacketType.Play.Server.ENTITY_EQUIPMENT); | |
container.getItemSlots().write(0, EnumWrappers.ItemSlot.MAINHAND); | |
container.getIntegers().write(0, stand.getEntityId()); | |
container.getItemModifier().write(0, new ItemStack(stand.getItemInHand())); | |
try { | |
manager.sendServerPacket(rider, container); | |
} catch (InvocationTargetException exception) { | |
StringUtils.printException(exception); | |
} | |
short durability = type.getItem().getDurability(); | |
if (type.hasSkins()) | |
durability += PlayerManager.getInstance().getGamePlayer(rider).getVehicleSkin(); | |
stand.setItemInHand( | |
new ItemStackBuilder(Material.FLINT_AND_STEEL) | |
.setDurability(durability) | |
.build()); | |
healthBar.removePlayer(rider); | |
speedBar.removePlayer(rider); | |
speed = 0; | |
rider.removePotionEffect(PotionEffectType.INVISIBILITY); | |
rider.setCanPickupItems(true); | |
rider.getInventory().setContents(inventoryContents); | |
rider.getInventory().setArmorContents(inventoryArmorContents); | |
stand.setRightArmPose( | |
new EulerAngle( | |
EulerAngleUtils.getInstance().getDefaultAngle().getX(), | |
stand.getRightArmPose().getY(), | |
EulerAngleUtils.getInstance().getDefaultAngle().getZ())); | |
stand.setCustomName( | |
ChatColor.translateAlternateColorCodes( | |
'&', | |
type.getColor() + "&l&o" + type.getName() + " &8[" + getHealthBarText() + "&8]")); | |
GamePlayer gp = PlayerManager.getInstance().getGamePlayer(rider); | |
gp.setVehicle(null); | |
JediCraft.getInstance() | |
.getServer() | |
.getScheduler() | |
.runTaskLater( | |
JediCraft.getInstance(), | |
() -> { | |
if (rider == null) { | |
gp.setAntiCheatLenient(false); | |
} | |
}, | |
20L * 5L); | |
rider = null; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment