diff --git a/paper/src/main/java/com/programmerdan/minecraft/simpleadminhacks/configs/BetterRailsConfig.java b/paper/src/main/java/com/programmerdan/minecraft/simpleadminhacks/configs/BetterRailsConfig.java new file mode 100644 index 00000000..77097ea6 --- /dev/null +++ b/paper/src/main/java/com/programmerdan/minecraft/simpleadminhacks/configs/BetterRailsConfig.java @@ -0,0 +1,64 @@ +package com.programmerdan.minecraft.simpleadminhacks.configs; + +import com.google.common.collect.Maps; +import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks; +import com.programmerdan.minecraft.simpleadminhacks.framework.SimpleHackConfig; +import org.bukkit.Material; +import org.bukkit.configuration.ConfigurationSection; +import vg.civcraft.mc.civmodcore.utilities.CivLogger; + +import java.util.*; + +public final class BetterRailsConfig extends SimpleHackConfig { + + private final CivLogger logger; + + private Map speeds; + private double baseSpeed = 8; + + private Map skySpeeds; + private double skySpeed = 0; + + public BetterRailsConfig(SimpleAdminHacks plugin, ConfigurationSection base) { + super(plugin, base, false); + this.logger = CivLogger.getLogger(getClass()); + wireup(base); + } + + @Override + protected void wireup(ConfigurationSection config) { + this.baseSpeed = config.getDouble("base"); + + ConfigurationSection materials = config.getConfigurationSection("materials"); + Set keys = materials.getKeys(false); + this.speeds = Maps.newHashMapWithExpectedSize(keys.size()); + for (String key : keys) { + this.speeds.put(Material.valueOf(key), materials.getDouble(key)); + } + + this.skySpeed = config.getDouble("skyBase"); + + ConfigurationSection skyMaterials = config.getConfigurationSection("skyMaterials"); + Set skyKeys = skyMaterials.getKeys(false); + this.skySpeeds = Maps.newHashMapWithExpectedSize(skyKeys.size()); + for (String key : skyKeys) { + this.skySpeeds.put(Material.valueOf(key), skyMaterials.getDouble(key)); + } + } + + public Double getMaxSpeedMetresPerSecond(Material material) { + return speeds.get(material); + } + + public Double getSkySpeedMetresPerSecond(Material material) { + return skySpeeds.get(material); + } + + public double getBaseSpeed() { + return baseSpeed; + } + + public double getSkySpeed() { + return skySpeed; + } +} diff --git a/paper/src/main/java/com/programmerdan/minecraft/simpleadminhacks/framework/HackManager.java b/paper/src/main/java/com/programmerdan/minecraft/simpleadminhacks/framework/HackManager.java index 4f1a9a8c..00da9c46 100644 --- a/paper/src/main/java/com/programmerdan/minecraft/simpleadminhacks/framework/HackManager.java +++ b/paper/src/main/java/com/programmerdan/minecraft/simpleadminhacks/framework/HackManager.java @@ -130,7 +130,9 @@ public SimpleHack loadHack(final Class> hackClass, final Config public void enableAllHacks() { for (final SimpleHack hack : hacks) { - enableHack(hack); + if (hack.shouldEnable()) { + enableHack(hack); + } } } diff --git a/paper/src/main/java/com/programmerdan/minecraft/simpleadminhacks/framework/commands/CommandRegistrar.java b/paper/src/main/java/com/programmerdan/minecraft/simpleadminhacks/framework/commands/CommandRegistrar.java index b60afafb..7b00ad75 100644 --- a/paper/src/main/java/com/programmerdan/minecraft/simpleadminhacks/framework/commands/CommandRegistrar.java +++ b/paper/src/main/java/com/programmerdan/minecraft/simpleadminhacks/framework/commands/CommandRegistrar.java @@ -5,8 +5,9 @@ import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks; import com.programmerdan.minecraft.simpleadminhacks.framework.SimpleHack; import com.programmerdan.minecraft.simpleadminhacks.framework.SimpleHackConfig; -import java.util.ArrayList; -import java.util.List; +import java.util.Set; +import java.util.TreeSet; + import vg.civcraft.mc.civmodcore.commands.CommandManager; public class CommandRegistrar extends CommandManager { @@ -31,7 +32,7 @@ public void registerCommands() { public void registerCompletions(final CommandCompletions completions) { super.registerCompletions(completions); completions.registerAsyncCompletion("hacks", (context) -> { - final List names = new ArrayList<>(); + final Set names = new TreeSet<>(); for (final SimpleHack hack : this.plugin.getHackManager().getHacks()) { names.add(hack.getName()); } diff --git a/paper/src/main/java/com/programmerdan/minecraft/simpleadminhacks/framework/commands/HacksCommand.java b/paper/src/main/java/com/programmerdan/minecraft/simpleadminhacks/framework/commands/HacksCommand.java index 14c160a1..de415ffd 100644 --- a/paper/src/main/java/com/programmerdan/minecraft/simpleadminhacks/framework/commands/HacksCommand.java +++ b/paper/src/main/java/com/programmerdan/minecraft/simpleadminhacks/framework/commands/HacksCommand.java @@ -13,7 +13,9 @@ import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks; import com.programmerdan.minecraft.simpleadminhacks.framework.SimpleHack; import com.programmerdan.minecraft.simpleadminhacks.framework.SimpleHackConfig; -import java.util.List; + +import java.util.*; + import net.md_5.bungee.api.ChatColor; import org.bukkit.command.CommandSender; @@ -34,11 +36,13 @@ public void viewHacksCommand(final CommandSender sender) { if (hacks.isEmpty()) { sender.sendMessage(" No hacks registered."); } - else { - for (final SimpleHack hack : hacks) { - sender.sendMessage(" • " + ChatColor.YELLOW + hack.getName() + ": " + ChatColor.AQUA + - (hack.isEnabled() ? "enabled" : "disabled")); - } + final Map> names = new TreeMap<>(); + for (SimpleHack hack : hacks) { + names.put(hack.getName(), hack); + } + for (final SimpleHack hack : names.values()) { + sender.sendMessage(" • " + ChatColor.YELLOW + hack.getName() + ": " + ChatColor.AQUA + + (hack.isEnabled() ? "enabled" : "disabled")); } } diff --git a/paper/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/BetterRails.java b/paper/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/BetterRails.java new file mode 100644 index 00000000..7ba157e9 --- /dev/null +++ b/paper/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/BetterRails.java @@ -0,0 +1,112 @@ +package com.programmerdan.minecraft.simpleadminhacks.hacks; + + +import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks; +import com.programmerdan.minecraft.simpleadminhacks.configs.BetterRailsConfig; +import com.programmerdan.minecraft.simpleadminhacks.framework.SimpleHack; +import org.bukkit.HeightMap; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Minecart; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.HandlerList; +import org.bukkit.event.Listener; +import org.bukkit.event.vehicle.VehicleEnterEvent; +import org.bukkit.event.vehicle.VehicleExitEvent; +import org.bukkit.event.vehicle.VehicleMoveEvent; + +public final class BetterRails extends SimpleHack implements Listener { + + // A minecart goes at 8m/s but its internal speed is 0.4, this adjusts for that + private static final double METRES_PER_SECOND_TO_SPEED = 0.05; + private static final double VANILLA_SPEED = 0.4; + + public BetterRails(SimpleAdminHacks plugin, final BetterRailsConfig config) { + super(plugin, config); + } + + public static BetterRailsConfig generate(SimpleAdminHacks plugin, ConfigurationSection config) { + return new BetterRailsConfig(plugin, config); + } + + @Override + public void onEnable() { + plugin().registerListener(this); + } + + @Override + public void onDisable() { + HandlerList.unregisterAll(this); + } + + @EventHandler + public void on(VehicleMoveEvent event) { + if (!(event.getVehicle() instanceof Minecart minecart)) { + return; + } + + Location to = event.getTo(); + Location from = event.getFrom(); + if (to.getBlockX() == from.getBlockX() && to.getBlockY() == from.getBlockY() && to.getBlockZ() == from.getBlockZ()) { + return; + } + + for (Entity entity : minecart.getPassengers()) { + if (entity instanceof Player) { + adjustSpeed(minecart); + return; + } + } + } + + @EventHandler + public void on(VehicleEnterEvent event) { + if (!(event.getVehicle() instanceof Minecart minecart)) { + return; + } + + if (event.getEntered() instanceof Player) { + adjustSpeed(minecart); + } + } + + @EventHandler + public void on(VehicleExitEvent event) { + if (!(event.getVehicle() instanceof Minecart minecart)) { + return; + } + + // Empty minecarts should return to their vanilla speed + minecart.setMaxSpeed(VANILLA_SPEED); + } + + + private void adjustSpeed(Minecart minecart) { + Material belowRail = minecart.getLocation().subtract(0, 1, 0).getBlock().getType(); + Material belowRail2 = minecart.getLocation().subtract(0, 2, 0).getBlock().getType(); + + double speedMetresPerSecond = maxOrGet(config.getMaxSpeedMetresPerSecond(belowRail), config.getMaxSpeedMetresPerSecond(belowRail2), config.getBaseSpeed()); + + if (minecart.getLocation().getBlockY() == minecart.getWorld().getHighestBlockYAt(minecart.getLocation(), HeightMap.WORLD_SURFACE)) { + speedMetresPerSecond += maxOrGet(config.getSkySpeedMetresPerSecond(belowRail), config.getSkySpeedMetresPerSecond(belowRail2), config.getSkySpeed()); + } + + + minecart.setMaxSpeed(speedMetresPerSecond * METRES_PER_SECOND_TO_SPEED); + } + + private double maxOrGet(Double left, Double right, double defaultAmount) { + if (left != null && right != null) { + return Math.max(left, right); + } else if (left != null) { + return left; + } else if (right != null) { + return right; + } else { + return defaultAmount; + } + } +} diff --git a/paper/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/HorseStats.java b/paper/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/HorseStats.java index 9302f8ef..0ea10f83 100644 --- a/paper/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/HorseStats.java +++ b/paper/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/HorseStats.java @@ -17,6 +17,7 @@ import org.bukkit.inventory.ItemStack; public class HorseStats extends SimpleHack implements Listener { + private static final double INTERNAL_TO_METRES_PER_SECOND = 42.15778758471; public HorseStats(SimpleAdminHacks plugin, HorseStatsConfig config) { super(plugin, config); @@ -36,24 +37,31 @@ public void onHorseStatCheck(PlayerInteractEntityEvent event) { AbstractHorse horse = (AbstractHorse)entity; AttributeInstance attrHealth = horse.getAttribute(Attribute.GENERIC_MAX_HEALTH); AttributeInstance attrSpeed = horse.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED); - event.getPlayer().sendMessage(String.format("%sHealth = %f, Speed = %f, Jump height = %f", + event.getPlayer().sendMessage(String.format("%sHealth = %f, Speed = %fm/s, Jump height = %f blocks", ChatColor.YELLOW, attrHealth.getBaseValue(), - attrSpeed.getBaseValue(), - horse.getJumpStrength())); + attrSpeed.getBaseValue() * INTERNAL_TO_METRES_PER_SECOND, + jumpHeightInBlocks(horse.getJumpStrength()))); + event.setCancelled(true); } else if (entity instanceof Strider) { Strider strider = (Strider) entity; AttributeInstance attrHealth = strider.getAttribute(Attribute.GENERIC_MAX_HEALTH); AttributeInstance attrSpeed = strider.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED); - event.getPlayer().sendMessage(String.format("%sHealth = %f, Speed = %f", + event.getPlayer().sendMessage(String.format("%sHealth = %f, Speed = %fm/s", ChatColor.YELLOW, attrHealth.getBaseValue(), - attrSpeed.getBaseValue())); + attrSpeed.getBaseValue() * INTERNAL_TO_METRES_PER_SECOND)); + event.setCancelled(true); } else { return; } } + private double jumpHeightInBlocks(double x) { + // This is a curve-fitted formula, so not 100% accurate + return -0.1817584952 * x * x * x + 3.689713992 * x * x + 2.128599134 * x - 0.343930367; + } + @Override public void registerListeners() { if (config.isEnabled()) { diff --git a/paper/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/basic/CopperRail.java b/paper/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/basic/CopperRail.java new file mode 100644 index 00000000..1195f533 --- /dev/null +++ b/paper/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/basic/CopperRail.java @@ -0,0 +1,191 @@ +package com.programmerdan.minecraft.simpleadminhacks.hacks.basic; + +import com.destroystokyo.paper.MaterialTags; +import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks; +import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHack; +import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHackConfig; +import com.programmerdan.minecraft.simpleadminhacks.framework.autoload.AutoLoad; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.level.block.WeatheringCopper; +import net.minecraft.world.level.block.state.BlockState; +import org.bukkit.Effect; +import org.bukkit.Location; +import org.bukkit.Sound; +import org.bukkit.SoundCategory; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.craftbukkit.v1_18_R2.CraftWorld; +import org.bukkit.craftbukkit.v1_18_R2.block.CraftBlock; +import org.bukkit.craftbukkit.v1_18_R2.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_18_R2.event.CraftEventFactory; +import org.bukkit.craftbukkit.v1_18_R2.inventory.CraftItemStack; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Minecart; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.block.BlockFormEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.vehicle.VehicleMoveEvent; +import org.bukkit.inventory.EquipmentSlot; +import org.bukkit.inventory.ItemStack; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +public class CopperRail extends BasicHack { + + // ServerLevel has a private version of this so we will make one ourselves + private final io.papermc.paper.util.math.ThreadUnsafeRandom randomTickRandom = new io.papermc.paper.util.math.ThreadUnsafeRandom(); + + @AutoLoad + private boolean deoxidise; + + @AutoLoad + private double damage; + + private boolean formingBlock = false; + + public CopperRail(SimpleAdminHacks plugin, BasicHackConfig config) { + super(plugin, config); + } + + @EventHandler + public void on(VehicleMoveEvent event) { + if (this.damage <= 0 || !(event.getVehicle() instanceof Minecart minecart)) { + return; + } + + boolean hasPlayer = false; + for (Entity entity : minecart.getPassengers()) { + if (entity instanceof Player) { + hasPlayer = true; + break; + } + } + + if (!hasPlayer) { + return; + } + + Location to = event.getTo(); + Location from = event.getFrom(); + if (to.getBlockX() == from.getBlockX() && to.getBlockY() == from.getBlockY() && to.getBlockZ() == from.getBlockZ()) { + return; + } + + int signX = from.getBlockX() > to.getBlockX() ? 1 : -1; + int signZ = from.getBlockZ() > to.getBlockZ() ? 1 : -1; + boolean firstBlock = true; + + List copperBlocks = new ArrayList<>(4); + for (int x = to.getBlockX(); x != to.getBlockX() + (from.getBlockX() - to.getBlockX()) + signX; x += signX) { + for (int z = to.getBlockZ(); z != to.getBlockZ() + (from.getBlockZ() - to.getBlockZ()) + signZ; z += signZ) { + if (firstBlock) { + firstBlock = false; + continue; + } + Location location = new Location(minecart.getWorld(), x, from.getY(), z); + Block topCopperBlock = location.getBlock().getRelative(BlockFace.DOWN); + Optional next = WeatheringCopper.getNext(((CraftBlock) topCopperBlock).getNMS().getBlock()); + if (next.isPresent()) { + copperBlocks.add(topCopperBlock); + } + Block belowCopperBlock = topCopperBlock.getRelative(BlockFace.DOWN); + next = WeatheringCopper.getNext(((CraftBlock) belowCopperBlock).getNMS().getBlock()); + if (next.isPresent()) { + copperBlocks.add(belowCopperBlock); + } + } + } + + for (Block copperBlock : copperBlocks) { + CraftBlock craftBlock = (CraftBlock) copperBlock; + BlockState state = craftBlock.getNMS(); + ServerLevel level = ((CraftWorld) copperBlock.getWorld()).getHandle(); + // We damage the copper directly instead of using random ticking, as random ticking is easy to cheese + // by placing waxed copper next to the rail, entirely preventing the rest of the rail from oxidising. + WeatheringCopper copper = (WeatheringCopper) state.getBlock(); + float chanceModifier = copper.getChanceModifier(); + if (this.damage * chanceModifier > this.randomTickRandom.nextFloat()) { + copper.getNext(state).ifPresent((iblockdata2) -> { + try { + formingBlock = true; + CraftEventFactory.handleBlockFormEvent(level, craftBlock.getPosition(), iblockdata2); + } finally { + formingBlock = false; + } + }); + } + } + } + + @EventHandler(ignoreCancelled = true) + public void on(PlayerInteractEvent event) { + if (!this.deoxidise) { + return; + } + + ItemStack item = event.getItem(); + if (item == null || !MaterialTags.AXES.isTagged(item)) { + return; + } + + Block block = event.getClickedBlock(); + if (block == null || !MaterialTags.RAILS.isTagged(block)) { + return; + } + + Block copperBlock = block.getRelative(BlockFace.DOWN); + Optional previous = WeatheringCopper.getPrevious(((CraftBlock) copperBlock).getNMS()); + if (previous.isEmpty()) { + copperBlock = copperBlock.getRelative(BlockFace.DOWN); + } + + previous = WeatheringCopper.getPrevious(((CraftBlock) copperBlock).getNMS()); + if (previous.isEmpty()) { + return; + } + + copperBlock.setType(previous.get().getBukkitMaterial()); + + block.getWorld().playSound(block.getLocation(), Sound.ITEM_AXE_SCRAPE, SoundCategory.BLOCKS, 1, 1); + block.getWorld().playEffect(block.getLocation(), Effect.OXIDISED_COPPER_SCRAPE, 0); + + CraftPlayer player = (CraftPlayer) event.getPlayer(); + // TODO: In 1.19 or above, this can be replaced with ItemStack#damage thanks to Paper + ((CraftItemStack) item).handle.hurtAndBreak(1, player.getHandle(), p -> { + p.broadcastBreakEvent(event.getHand() == EquipmentSlot.HAND ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND); + }); + + event.setCancelled(true); + } + + // It's not really fair for copper blocks that are below rails to naturally oxidise, + // as it is easy to cheese by placing a waxed copper block every 9 blocks + @EventHandler + public void on(BlockFormEvent event) { + if (formingBlock) { + return; + } + + Block block = event.getBlock(); + + Optional next = WeatheringCopper.getNext(((CraftBlock) block).getNMS().getBlock()); + if (next.isEmpty()) { + return; + } + + Block railAbove = block.getRelative(BlockFace.UP); + if (!MaterialTags.RAILS.isTagged(railAbove)) { + railAbove = railAbove.getRelative(BlockFace.UP); + } + + if (!MaterialTags.RAILS.isTagged(railAbove)) { + return; + } + + event.setCancelled(true); + } +} diff --git a/paper/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/basic/FasterHorses.java b/paper/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/basic/FasterHorses.java new file mode 100644 index 00000000..281f5fa2 --- /dev/null +++ b/paper/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/basic/FasterHorses.java @@ -0,0 +1,63 @@ +package com.programmerdan.minecraft.simpleadminhacks.hacks.basic; + +import com.programmerdan.minecraft.simpleadminhacks.SimpleAdminHacks; +import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHack; +import com.programmerdan.minecraft.simpleadminhacks.framework.BasicHackConfig; +import com.programmerdan.minecraft.simpleadminhacks.framework.autoload.AutoLoad; +import org.bukkit.attribute.Attribute; +import org.bukkit.attribute.AttributeInstance; +import org.bukkit.entity.EntityType; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.event.entity.EntityBreedEvent; + +import java.util.logging.Level; + +public class FasterHorses extends BasicHack { + @AutoLoad + private double minSpeed; + @AutoLoad + private double maxSpeed; + + public FasterHorses(SimpleAdminHacks plugin, BasicHackConfig config) { + super(plugin, config); + } + + @EventHandler(priority = EventPriority.HIGH) + public void on(EntityBreedEvent event) { + if (event.getEntity().getType() != EntityType.HORSE) { + return; + } + double dadSpeed = event.getFather().getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).getBaseValue(); + double mumSpeed = event.getMother().getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).getBaseValue(); + double irwinHallDist = (Math.random() * 0.3 + Math.random() * 0.3 + Math.random() * 0.3) * ((this.maxSpeed - this.minSpeed) / 0.9) + this.minSpeed; + double newSpeed = (dadSpeed + mumSpeed + irwinHallDist) / 3; + if (newSpeed < minSpeed) { + newSpeed = minSpeed; + } else if (newSpeed > maxSpeed) { + newSpeed = maxSpeed; + } + event.getEntity().getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).setBaseValue(newSpeed); + + plugin.getLogger().log(Level.INFO, "Horse breed to have speed: " + newSpeed); + } + + @EventHandler(priority = EventPriority.HIGHEST) + public void on(CreatureSpawnEvent event) { + if (event.getEntity().getType() != EntityType.HORSE) { + return; + } + if (event.getSpawnReason() == CreatureSpawnEvent.SpawnReason.BREEDING) { + return; + } + + AttributeInstance moveSpeed = event.getEntity().getAttribute(Attribute.GENERIC_MOVEMENT_SPEED); + if (moveSpeed == null) { + return; + } + double irwinHallDist = (Math.random() * 0.3 + Math.random() * 0.3 + Math.random() * 0.3) * ((this.maxSpeed - this.minSpeed) / 0.9) + this.minSpeed; + moveSpeed.setBaseValue(irwinHallDist); + plugin.getLogger().log(Level.INFO, "Setting Horse Speed to: " + irwinHallDist); + } +} diff --git a/paper/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/basic/StriderBreeding.java b/paper/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/basic/StriderBreeding.java index 102c5b26..8e1dde29 100644 --- a/paper/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/basic/StriderBreeding.java +++ b/paper/src/main/java/com/programmerdan/minecraft/simpleadminhacks/hacks/basic/StriderBreeding.java @@ -36,11 +36,8 @@ public void onStriderBreed(EntityBreedEvent event) { } double dadSpeed = event.getFather().getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).getBaseValue(); double mumSpeed = event.getMother().getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).getBaseValue(); - double randomSpeed = Math.random() * (this.maxSpeed - this.minSpeed) + this.minSpeed; - //the 0.44.... number, I was given this number by Okx#5481, apparently it is the horse speed generation number - //Also worth noting he told me it is not exactly a bell curve even if I did name it bellCurve - double bellCurve = (0.44999998807907104 + randomSpeed * 0.3 + randomSpeed * 0.3 + randomSpeed * 0.3) * 0.25; - double newStriderSpeed = (dadSpeed + mumSpeed + bellCurve) / 3; + double irwinHallDist = (0.45 + Math.random() * 0.3 + Math.random() * 0.3 + Math.random() * 0.3) * 0.25; + double newStriderSpeed = (dadSpeed + mumSpeed + irwinHallDist) / 3; if (newStriderSpeed < minSpeed) { newStriderSpeed = minSpeed; } else if (newStriderSpeed > maxSpeed) { @@ -80,15 +77,14 @@ public void rollSpeedStat(LivingEntity strider, double minSpeed, double maxSpeed if (moveSpeed == null) { return; } - double random = Math.random() * (maxSpeed - minSpeed) + minSpeed; - double bellCurve = (0.44999998807907104 + random * 0.3 + random * 0.3 + random * 0.3) * 0.25; - if (bellCurve < minSpeed) { - bellCurve = minSpeed; - } else if (bellCurve > maxSpeed) { - bellCurve = maxSpeed; + double irwinHallDist = (0.45 + Math.random() * 0.3 + Math.random() * 0.3 + Math.random() * 0.3) * 0.25; + if (irwinHallDist < minSpeed) { + irwinHallDist = minSpeed; + } else if (irwinHallDist > maxSpeed) { + irwinHallDist = maxSpeed; } - moveSpeed.setBaseValue(bellCurve); - plugin.getLogger().log(Level.INFO, "Setting Strider Speed to: " + bellCurve); + moveSpeed.setBaseValue(irwinHallDist); + plugin.getLogger().log(Level.INFO, "Setting Strider Speed to: " + irwinHallDist); } public void rollHealthStat(LivingEntity strider, int minHealth, int maxHealth) { diff --git a/paper/src/main/resources/config.yml b/paper/src/main/resources/config.yml index 55a65dec..eef5f514 100644 --- a/paper/src/main/resources/config.yml +++ b/paper/src/main/resources/config.yml @@ -513,3 +513,31 @@ hacks: ToggleLamp: enabled: false cooldownTime: 100 + BetterRails: + enabled: true + # All in metres per second + # Minecraft will prevent you going faster than 30m/s + base: 11 + materials: + COBBLESTONE: 8 + COPPER_BLOCK: 29 + EXPOSED_COPPER: 23 + WEATHERED_COPPER: 18 + OXIDIZED_COPPER: 14 + skyBase: 1 + skyMaterials: + COBBLESTONE: 0 + COPPER_BLOCK: 1 + EXPOSED_COPPER: 1 + WEATHERED_COPPER: 1 + OXIDIZED_COPPER: 1 + CopperRail: + enabled: true + deoxidise: true + # Chance to oxidise copper one level. + # Unoxidised copper will oxidise at 75% of this level. + damage: 0.03 + FasterHorses: + enabled: true + minSpeed: 0.1125 + maxSpeed: 0.438827582278 # 18.5m/s