Skip to content

Instantly share code, notes, and snippets.

@cadenkriese
Last active July 10, 2019 02:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cadenkriese/8d1af303c36166d368c48b90457dca10 to your computer and use it in GitHub Desktop.
Save cadenkriese/8d1af303c36166d368c48b90457dca10 to your computer and use it in GitHub Desktop.
Excerpt of MineSwine Vehicles Code.
//© 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