This commit is contained in:
okx-code
2026-06-02 01:35:57 +01:00
parent 304ae8ab5b
commit c68d4ef3db
19 changed files with 745 additions and 192 deletions

View File

@@ -0,0 +1,22 @@
package net.civmc.zorweth;
import org.bukkit.attribute.Attribute;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
public class GravityListener implements Listener {
private final double gravity;
public GravityListener(double gravity) {
this.gravity = gravity;
}
@EventHandler
public void on(PlayerJoinEvent event) {
Player player = event.getPlayer();
player.getAttribute(Attribute.GRAVITY).setBaseValue(gravity);
}
}

View File

@@ -16,6 +16,7 @@ import java.util.logging.Level;
import net.civmc.zorweth.database.RocketTransferDao;
import net.civmc.zorweth.database.ZorwethDatabase;
import net.civmc.zorweth.flight.FlightComputerGui;
import net.civmc.zorweth.mechanics.Fuel;
import net.civmc.zorweth.mechanics.OilMechanics;
import net.civmc.zorweth.oxygen.ActivityManager;
import net.civmc.zorweth.oxygen.OxygenCommand;
@@ -59,6 +60,7 @@ public final class ZorwethPlugin extends JavaPlugin {
getServer().getPluginManager().disablePlugin(this);
return;
}
Fuel.registerCustomItems();
getServer().getMessenger().registerOutgoingPluginChannel(this, "BungeeCord");
this.rocketClipboard = loadRocketClipboard();
this.stasisHandler = new StasisHandler();
@@ -76,11 +78,16 @@ public final class ZorwethPlugin extends JavaPlugin {
}
loadOxygen();
double gravity = getConfig().getDouble("gravity");
if (gravity != 0) {
getServer().getPluginManager().registerEvents(new GravityListener(gravity), this);
}
}
private void loadOxygen() {
ConfigurationSection oxygenSection = getConfig().getConfigurationSection("oxygen");
if (!oxygenSection.getBoolean("enabled")) {
if (oxygenSection == null || !oxygenSection.getBoolean("enabled")) {
return;
}

View File

@@ -32,6 +32,7 @@ import org.bukkit.block.Block;
import org.bukkit.block.Chest;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataType;
import org.bukkit.plugin.java.JavaPlugin;
import vg.civcraft.mc.citadel.ReinforcementLogic;
@@ -44,10 +45,11 @@ public class LaunchHandler {
public static final double EXHAUST_VELOCITY_METERS_PER_SECOND = 5_000.0;
public static final double ROCKET_DRY_MASS_KG = 100.0;
public static final double SITTING_PLAYER_MASS_KG = 50.0;
private static final String COMPACTED_LORE = "Compacted Item";
public static FuelStatus calculateFuelStatus(final Block computer, final List<RocketManifestPassenger> passengers,
final List<RocketManifestChest> chests) {
final double cargoMass = calculateCargoMass(chests);
final double cargoMass = calculateCargoMass(chests, passengers);
final int sittingPlayers = Math.max(1, passengers.size());
final double nonFuelMass = ROCKET_DRY_MASS_KG + cargoMass + sittingPlayers * SITTING_PLAYER_MASS_KG;
final double requiredFuelKg = nonFuelMass * (Math.exp(getDeltaVMetersPerSecond() / EXHAUST_VELOCITY_METERS_PER_SECOND) - 1.0);
@@ -117,23 +119,62 @@ public class LaunchHandler {
return new RocketWeightPayload(passengers, chests, getRemainingFuel(chests, passengers, computer));
}
private static double calculateCargoMass(final List<RocketManifestChest> chests) {
private static double calculateCargoMass(final List<RocketManifestChest> chests,
final List<RocketManifestPassenger> passengers) {
double mass = 0.0;
for (final RocketManifestChest chest : chests) {
for (final ItemStack item : chest.contents()) {
if (item == null || item.getType().isAir()) {
continue;
}
double itemMass = item.getAmount() / (double) item.getMaxStackSize();
if (FlightComputer.isFuel(item)) {
itemMass *= FUEL_ITEM_MASS_KG * item.getMaxStackSize();
}
mass += itemMass;
}
mass += calculateItemMass(chest.contents());
}
for (final RocketManifestPassenger passenger : passengers) {
mass += calculateItemMass(passenger.inventoryContents());
}
return mass;
}
private static double calculateItemMass(final ItemStack[] items) {
double mass = 0.0;
for (final ItemStack item : items) {
if (item == null || item.getType().isAir()) {
continue;
}
int itemAmount = item.getAmount();
if (isCompacted(item)) {
itemAmount *= getCompactStackSize(item.getType());
}
double itemMass = itemAmount / (double) item.getMaxStackSize();
if (FlightComputer.isFuel(item)) {
itemMass = itemAmount * FUEL_ITEM_MASS_KG;
}
mass += itemMass;
}
return mass;
}
private static int getCompactStackSize(final Material material) {
return switch (material.getMaxStackSize()) {
case 64 -> 64;
case 16 -> 16;
case 1 -> 8;
default -> 1;
};
}
private static boolean isCompacted(final ItemStack item) {
if (!item.hasItemMeta()) {
return false;
}
final ItemMeta meta = item.getItemMeta();
if (!meta.hasLore()) {
return false;
}
for (final String lore : meta.getLore()) {
if (COMPACTED_LORE.equals(lore)) {
return true;
}
}
return false;
}
public static RocketManifestResult collectLaunchManifest(final ZorwethPlugin plugin, final Block computer, final Player player, Clipboard rocket) {
final Region region = rocket.getRegion();
final BlockVector3 schematicNorthWestCorner = region.getMinimumPoint();
@@ -196,7 +237,7 @@ public class LaunchHandler {
private static double getRemainingFuel(final List<RocketManifestChest> chests,
final List<RocketManifestPassenger> passengers,
final Block computer) {
final double cargoMass = calculateCargoMass(chests);
final double cargoMass = calculateCargoMass(chests, passengers);
final double dryMass = ROCKET_DRY_MASS_KG + cargoMass + passengers.size() * SITTING_PLAYER_MASS_KG;
final double wetMass = FlightComputer.getFuelKg(computer) + dryMass;
return wetMass / (Math.exp(getDeltaVMetersPerSecond() / EXHAUST_VELOCITY_METERS_PER_SECOND)) - dryMass;

View File

@@ -13,6 +13,12 @@ import vg.civcraft.mc.civmodcore.inventory.CustomItem;
public class Fuel {
public static void registerCustomItems() {
createCrudeOil();
createRocketFuel();
createAluminiumIngot();
}
public static ItemStack createCrudeOil() {
ItemStack item = new ItemStack(Material.RECOVERY_COMPASS);
item.setData(DataComponentTypes.ITEM_MODEL, new NamespacedKey("minecraft", "charcoal"));
@@ -41,6 +47,17 @@ public class Fuel {
return item;
}
public static ItemStack createAluminiumIngot() {
ItemStack item = new ItemStack(Material.IRON_INGOT);
ItemMeta meta = item.getItemMeta();
meta.itemName(Component.text("Aluminium Ingot", TextColor.color(211, 131, 59)));
meta.setEnchantmentGlintOverride(true);
item.setItemMeta(meta);
CustomItem.registerCustomItem("aluminium_ingot", item);
return item;
}
public static boolean isRocketFuel(final ItemStack item) {
return CustomItem.isCustomItem(item, "rocket_fuel");
}

View File

@@ -1,9 +1,9 @@
package net.civmc.zorweth.oxygen;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.TreeMap;
import java.util.Set;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
@@ -11,7 +11,6 @@ import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityRegainHealthEvent;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerQuitEvent;
@@ -23,14 +22,19 @@ public class ActivityManager implements Listener {
// last time activity was detected
private final Map<Player, Map<Activity, Long>> activities = new HashMap<>();
public Activity getActivity(Player player) {
public Set<Activity> getActivities(Player player) {
Set<Activity> playerActivities = new HashSet<>();
for (Map.Entry<Activity, Long> entry : activities.get(player).entrySet()) {
if (entry.getValue() + ACTIVITY_DURATION_MS > System.currentTimeMillis()) {
return entry.getKey();
playerActivities.add(entry.getKey());
}
}
return Activity.IDLE;
if (playerActivities.isEmpty()) {
playerActivities.add(Activity.IDLE);
}
return playerActivities;
}
@EventHandler
@@ -69,10 +73,6 @@ public class ActivityManager implements Listener {
if (event.getDamager() instanceof Player player) {
recordActivity(player, Activity.COMBAT);
}
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void on(EntityDamageEvent event) {
if (event.getEntity() instanceof Player player) {
recordActivity(player, Activity.COMBAT);
}
@@ -95,7 +95,7 @@ public class ActivityManager implements Listener {
}
private void recordActivity(Player player, Activity activity) {
activities.computeIfAbsent(player, k -> new TreeMap<>(Comparator.reverseOrder()))
activities.computeIfAbsent(player, k -> new HashMap<>())
.put(activity, System.currentTimeMillis());
}

View File

@@ -1,12 +1,15 @@
package net.civmc.zorweth.oxygen;
import io.papermc.paper.datacomponent.DataComponentTypes;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextColor;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.entity.Player;
import org.bukkit.inventory.CraftingRecipe;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.ShapelessRecipe;
@@ -18,7 +21,8 @@ import vg.civcraft.mc.civmodcore.inventory.CustomItem;
public final class OxygenBladder {
private static final String CUSTOM_ITEM_KEY = "small_oxygen_bladder";
private static final String SMALL_OXYGEN_BLADDER = "small_oxygen_bladder";
private static final String OXYGEN_REBREATHER = "oxygen_rebreather";
private static final NamespacedKey RESERVE_KEY = new NamespacedKey("zorweth", "oxygen_bladder_reserve");
private OxygenBladder() {
@@ -37,36 +41,75 @@ public final class OxygenBladder {
));
meta.setEnchantmentGlintOverride(true);
item.setItemMeta(meta);
CustomItem.registerCustomItem(CUSTOM_ITEM_KEY, item);
CustomItem.registerCustomItem(SMALL_OXYGEN_BLADDER, item);
return item;
}
public static boolean isSmallOxygenBladder(final ItemStack item) {
if (item == null || item.isEmpty()) {
return false;
public static ItemStack createOxygenRebreather() {
final ItemStack item = new ItemStack(Material.RECOVERY_COMPASS);
item.setData(DataComponentTypes.ITEM_MODEL, NamespacedKey.minecraft("conduit"));
item.setData(DataComponentTypes.MAX_STACK_SIZE, 1);
final ItemMeta meta = item.getItemMeta();
meta.itemName(Component.text("Oxygen Rebreather", TextColor.color(140, 163, 177)));
meta.lore(List.of(
Component.text("An efficient apparatus for recycling oxygen.", NamedTextColor.WHITE),
Component.text("Increases max oxygen to 16000", NamedTextColor.WHITE),
Component.text("Automatically consumes oxygen items below 1000 oxygen", NamedTextColor.WHITE)
));
meta.setEnchantmentGlintOverride(true);
item.setItemMeta(meta);
CustomItem.registerCustomItem(OXYGEN_REBREATHER, item);
return item;
}
private static final Map<String, Double> BLADDER_MAX = new HashMap<>();
static {
BLADDER_MAX.put(SMALL_OXYGEN_BLADDER, 3D);
BLADDER_MAX.put(OXYGEN_REBREATHER, 16D);
}
public static ItemStack getOxygenBladder(Player player) {
ItemStack bladder = null;
double max = 0;
for (final ItemStack item : player.getInventory().getContents()) {
String key = CustomItem.getCustomItemKey(item);
if (BLADDER_MAX.containsKey(key) && BLADDER_MAX.get(key) > max) {
max = BLADDER_MAX.get(key);
bladder = item;
}
}
return CustomItem.isCustomItem(item, CUSTOM_ITEM_KEY);
return bladder;
}
public static double getMaxOxygen(Player player) {
double max = OxygenManager.DEFAULT_MAX_OXYGEN;
for (final ItemStack item : player.getInventory().getContents()) {
String key = CustomItem.getCustomItemKey(item);
if (BLADDER_MAX.containsKey(key) && BLADDER_MAX.get(key) > max) {
max = BLADDER_MAX.get(key);
}
}
return max;
}
public static double getReserve(final ItemStack item) {
if (!isSmallOxygenBladder(item)) {
return 0;
}
final ItemMeta meta = item.getItemMeta();
return Math.max(0, meta.getPersistentDataContainer().getOrDefault(RESERVE_KEY, PersistentDataType.DOUBLE, 0D));
}
public static void setReserve(final ItemStack item, final double reserve) {
if (!isSmallOxygenBladder(item)) {
return;
}
final ItemMeta meta = item.getItemMeta();
meta.getPersistentDataContainer().set(RESERVE_KEY, PersistentDataType.DOUBLE, Math.max(0, reserve));
item.setItemMeta(meta);
}
public static CraftingRecipe getRecipe(final Plugin plugin) {
final ShapelessRecipe recipe = new ShapelessRecipe(new NamespacedKey(plugin, CUSTOM_ITEM_KEY),
final ShapelessRecipe recipe = new ShapelessRecipe(new NamespacedKey(plugin, SMALL_OXYGEN_BLADDER),
createSmallOxygenBladder())
.addIngredient(Material.STICK)
.addIngredient(Material.STRING)

View File

@@ -8,7 +8,6 @@ import org.bukkit.inventory.ItemStack;
public final class OxygenBladderMechanics {
public static final double MAX_OXYGEN = 3;
public static final double CONSUME_ITEM_PLAYER_OXYGEN_THRESHOLD = 1;
public double drainOxygen(final Player player, final double amount, final double oxygenPerItem,
@@ -28,7 +27,7 @@ public final class OxygenBladderMechanics {
private double drawOxygen(final Player player, final double amount, final double oxygenPerItem,
final boolean canConsumeItem) {
double remaining = amount;
final ItemStack bladder = getSmallOxygenBladder(player);
final ItemStack bladder = OxygenBladder.getOxygenBladder(player);
if (bladder == null) {
return 0;
}
@@ -54,10 +53,6 @@ public final class OxygenBladderMechanics {
return amount - remaining;
}
public double getMaxOxygen(final Player player, final double defaultMaxOxygen) {
return getSmallOxygenBladder(player) == null ? defaultMaxOxygen : MAX_OXYGEN;
}
private double consumeOneOxygenItem(final Player player, final double oxygenPerItem) {
for (final ItemStack item : player.getInventory().getContents()) {
if (!OxygenBottle.isCrudeOxygen(item)) {
@@ -73,13 +68,4 @@ public final class OxygenBladderMechanics {
}
return 0;
}
private ItemStack getSmallOxygenBladder(final Player player) {
for (final ItemStack item : player.getInventory().getContents()) {
if (OxygenBladder.isSmallOxygenBladder(item)) {
return item;
}
}
return null;
}
}

View File

@@ -45,7 +45,7 @@ public class OxygenBottle {
.addIngredient(Material.GLASS_BOTTLE)
.addIngredient(Material.COAL)
.addIngredient(Material.PITCHER_PLANT);
recipe.setCategory(CraftingBookCategory.EQUIPMENT);
recipe.setCategory(CraftingBookCategory.MISC);
return recipe;
}
}

View File

@@ -67,7 +67,7 @@ public class OxygenDisplay implements Listener {
public void updateScoreboardHUD(Player p) {
double oxygen = oxygenManager.getOxygen(p);
if (!showOxygen.hasValue(p.getUniqueId()) || oxygen >= oxygenManager.getMaxOxygen(p)) {
if (!showOxygen.hasValue(p.getUniqueId()) || oxygen >= OxygenBladder.getMaxOxygen(p)) {
oxygenScoreboard.hide(p);
oxygenBottomLine.removePlayer(p);
return;

View File

@@ -10,6 +10,7 @@ import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.WeakHashMap;
import net.civmc.zorweth.ZorwethPlugin;
import net.kyori.adventure.text.Component;
@@ -36,8 +37,8 @@ public class OxygenManager implements Listener {
private static final String OXYGEN_BREW_RECIPE_NAME = "Oxygen";
private static final double CRUDE_OXYGEN_AMOUNT = 0.09;
private static final double OXYGEN_BREW_AMOUNT = 1.8;
private static final double DEFAULT_MAX_OXYGEN = 1;
private static final double OXYGEN_BREW_AMOUNT = 1.6;
public static final double DEFAULT_MAX_OXYGEN = 1;
private static final double REGENERATION_PREVENTION_OXYGEN = -0.15;
public static final NamespacedKey NO_HEALTH_REGEN = new NamespacedKey("finale", "no_health_regen");
@@ -59,15 +60,18 @@ public class OxygenManager implements Listener {
double oxygen = getOxygen(player);
ActivityManager.Activity activity = activityManager.getActivity(player);
player.sendMessage("activity -> " + activity);
double playerActivityMultiplier = activityMultiplier.getOrDefault(activity, 0D);
Set<ActivityManager.Activity> activities = activityManager.getActivities(player);
double playerActivityMultiplier = activities
.stream()
.mapToDouble(activityMultiplier::get)
.max()
.orElse(0D);
double biomeMultiplier = biomeMultipliers.getOrDefault(player.getLocation().getBlock().getBiome(), 0D);
double loss = playerActivityMultiplier * biomeMultiplier;
if (loss == 0) {
if (activity == ActivityManager.Activity.IDLE) {
if (activities.contains(ActivityManager.Activity.IDLE)) {
oxygen += baseOxygenConsumptionPerSecond;
} else {
oxygen += baseOxygenConsumptionPerSecond / 2;
@@ -97,12 +101,10 @@ public class OxygenManager implements Listener {
@EventHandler
public void on(PlayerItemConsumeEvent event) {
if (!OxygenBottle.isCrudeOxygen(event.getItem())) {
return;
}
Player player = event.getPlayer();
addOxygen(player, CRUDE_OXYGEN_AMOUNT);
if (OxygenBottle.isCrudeOxygen(event.getItem())) {
addOxygen(player, CRUDE_OXYGEN_AMOUNT);
}
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
@@ -209,16 +211,12 @@ public class OxygenManager implements Listener {
public void setOxygen(final Player player, final double oxygen) {
player.getPersistentDataContainer().set(oxygenKey, PersistentDataType.DOUBLE,
Math.clamp(oxygen, -1, this.oxygenBladderMechanics.getMaxOxygen(player, DEFAULT_MAX_OXYGEN)));
}
public double getMaxOxygen(final Player player) {
return this.oxygenBladderMechanics.getMaxOxygen(player, DEFAULT_MAX_OXYGEN);
Math.clamp(oxygen, -1, OxygenBladder.getMaxOxygen(player)));
}
private void sendDebouncedMessage(Player player, Component message) {
Long lastMessageTime = lastMessage.get(player);
if (lastMessageTime != null && lastMessageTime + 30_000 > System.currentTimeMillis()) {
if (lastMessageTime != null && lastMessageTime + 15_000 > System.currentTimeMillis()) {
return;
}