Update some patches from Leaves
This commit is contained in:
+4
-53
@@ -48,40 +48,10 @@ index 11e6197dec541b28733715f0d7eaa4c7b834d632..6b7c92fdf562dfa46eee8e8acbc82b02
|
|||||||
AABB aabb = new AABB(this.blockPosition()).inflate(32.0, 10.0, 32.0);
|
AABB aabb = new AABB(this.blockPosition()).inflate(32.0, 10.0, 32.0);
|
||||||
this.level()
|
this.level()
|
||||||
diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java
|
diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java
|
||||||
index 567d63ae589705e13403814b36e35d00c241a69e..919628d93add71d9b30cae29587a0049cce6973d 100644
|
index 567d63ae589705e13403814b36e35d00c241a69e..3f4b1c54f9207ba1854a8c8da965cbaca5ea517d 100644
|
||||||
--- a/net/minecraft/world/entity/LivingEntity.java
|
--- a/net/minecraft/world/entity/LivingEntity.java
|
||||||
+++ b/net/minecraft/world/entity/LivingEntity.java
|
+++ b/net/minecraft/world/entity/LivingEntity.java
|
||||||
@@ -1216,6 +1216,29 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
|
@@ -1948,6 +1948,13 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
+ // Luminol Start - raid revert adapt Cross Region Damage trace
|
|
||||||
+ public boolean addEffect(MobEffectInstance effectInstance, @Nullable Entity entity, EntityPotionEffectEvent.Cause cause, boolean fireEvent, boolean async) {
|
|
||||||
+ if (ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(entity)) {
|
|
||||||
+ return addEffect(effectInstance, entity, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.PATROL_CAPTAIN, true);
|
|
||||||
+ } else if (fun.bm.lophine.config.modules.experiment.EntityDamageSourceTraceConfig.enabled) {
|
|
||||||
+ postToEntityThreadAddEffect(effectInstance, entity, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.PATROL_CAPTAIN, true);
|
|
||||||
+ return true;
|
|
||||||
+ }
|
|
||||||
+ return false;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ private void postToEntityThreadAddEffect(MobEffectInstance effectInstance, @Nullable Entity entity, EntityPotionEffectEvent.Cause cause, boolean fireEvent) {
|
|
||||||
+ if (entity != null)
|
|
||||||
+ entity.getBukkitEntity().taskScheduler.schedule((Entity nmsEntity) -> {
|
|
||||||
+ try {
|
|
||||||
+ addEffect(effectInstance, nmsEntity, cause, fireEvent);
|
|
||||||
+ } catch (Throwable ex) {
|
|
||||||
+ LOGGER.error(ex.getMessage(), ex);
|
|
||||||
+ }
|
|
||||||
+ }, null, 1L );
|
|
||||||
+ }
|
|
||||||
+ // Luminol End - raid revert adapt Cross Region Damage trace
|
|
||||||
+
|
|
||||||
public boolean canBeAffected(MobEffectInstance effectInstance) {
|
|
||||||
if (this.getType().is(EntityTypeTags.IMMUNE_TO_INFESTED)) {
|
|
||||||
return !effectInstance.is(MobEffects.INFESTED);
|
|
||||||
@@ -1948,6 +1971,13 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
|
|
||||||
final LivingEntity killer = this.getKillCredit();
|
final LivingEntity killer = this.getKillCredit();
|
||||||
if (killer != null) {
|
if (killer != null) {
|
||||||
killer.awardKillScore(this, damageSource);
|
killer.awardKillScore(this, damageSource);
|
||||||
@@ -95,7 +65,7 @@ index 567d63ae589705e13403814b36e35d00c241a69e..919628d93add71d9b30cae29587a0049
|
|||||||
}
|
}
|
||||||
}); // Paper end
|
}); // Paper end
|
||||||
this.postDeathDropItems(deathEvent); // Paper
|
this.postDeathDropItems(deathEvent); // Paper
|
||||||
@@ -1958,6 +1988,18 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
|
@@ -1958,6 +1965,18 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
|
||||||
return deathEvent; // Paper
|
return deathEvent; // Paper
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,7 +84,7 @@ index 567d63ae589705e13403814b36e35d00c241a69e..919628d93add71d9b30cae29587a0049
|
|||||||
protected void dropEquipment(ServerLevel level) {
|
protected void dropEquipment(ServerLevel level) {
|
||||||
}
|
}
|
||||||
protected void postDeathDropItems(org.bukkit.event.entity.EntityDeathEvent event) {} // Paper - method for post death logic that cannot be ran before the event is potentially cancelled
|
protected void postDeathDropItems(org.bukkit.event.entity.EntityDeathEvent event) {} // Paper - method for post death logic that cannot be ran before the event is potentially cancelled
|
||||||
@@ -2556,6 +2598,18 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
|
@@ -2556,6 +2575,18 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,22 +103,3 @@ index 567d63ae589705e13403814b36e35d00c241a69e..919628d93add71d9b30cae29587a0049
|
|||||||
public final float getMaxHealth() {
|
public final float getMaxHealth() {
|
||||||
return (float)this.getAttributeValue(Attributes.MAX_HEALTH);
|
return (float)this.getAttributeValue(Attributes.MAX_HEALTH);
|
||||||
}
|
}
|
||||||
diff --git a/net/minecraft/world/entity/raid/Raider.java b/net/minecraft/world/entity/raid/Raider.java
|
|
||||||
index 510514e363f4816a6e286fb9b5488153e03c9e55..ce5602283757c564b45ec0765b5f1868ffcd180b 100644
|
|
||||||
--- a/net/minecraft/world/entity/raid/Raider.java
|
|
||||||
+++ b/net/minecraft/world/entity/raid/Raider.java
|
|
||||||
@@ -157,7 +157,13 @@ public abstract class Raider extends PatrollingMonster {
|
|
||||||
net.minecraft.world.effect.MobEffectInstance mobeffect1 = new net.minecraft.world.effect.MobEffectInstance(net.minecraft.world.effect.MobEffects.BAD_OMEN, fun.bm.lophine.config.modules.misc.RaidChangesConfig.infinite ? net.minecraft.world.effect.MobEffectInstance.INFINITE_DURATION : 120000, i, false, false, true);
|
|
||||||
|
|
||||||
if (!serverLevel.getGameRules().getBoolean(net.minecraft.world.level.GameRules.RULE_DISABLE_RAIDS)) {
|
|
||||||
- entityhuman.addEffect(mobeffect1, entityhuman, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.PATROL_CAPTAIN, true); // CraftBukkit
|
|
||||||
+ // Luminol start - raid revert adapt Cross Region Damage trace
|
|
||||||
+ if (fun.bm.lophine.config.modules.experiment.EntityDamageSourceTraceConfig.enabled) {
|
|
||||||
+ entityhuman.addEffect(mobeffect1, entityhuman, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.PATROL_CAPTAIN, true, true);
|
|
||||||
+ } else {
|
|
||||||
+ entityhuman.addEffect(mobeffect1, entityhuman, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.PATROL_CAPTAIN, true); // CraftBukkit
|
|
||||||
+ }
|
|
||||||
+ // Luminol end - raid revert adapt Cross Region Damage trace
|
|
||||||
}
|
|
||||||
this.setPatrolLeader(false);
|
|
||||||
}
|
|
||||||
-207
@@ -1,207 +0,0 @@
|
|||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
|
|
||||||
Date: Fri, 11 Apr 2025 16:53:57 +0800
|
|
||||||
Subject: [PATCH] Add config to revert raid changes
|
|
||||||
|
|
||||||
Co-authored by: huanli233 <392352840@qq.com>
|
|
||||||
Some of changes is a part of : Leaves (https://github.com/LeavesMC/Leaves/blob/b5793e809b6346e16b7ea218496806a312562e27/leaves-server/minecraft-patches/features/0106-Revert-raid-changes.patch)
|
|
||||||
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
|
|
||||||
|
|
||||||
diff --git a/net/minecraft/world/effect/BadOmenMobEffect.java b/net/minecraft/world/effect/BadOmenMobEffect.java
|
|
||||||
index 80f17f33f670018240c854df589cf90cdeab6e70..985f27d249810bf133a520d937b7006e57f553ec 100644
|
|
||||||
--- a/net/minecraft/world/effect/BadOmenMobEffect.java
|
|
||||||
+++ b/net/minecraft/world/effect/BadOmenMobEffect.java
|
|
||||||
@@ -22,6 +22,11 @@ class BadOmenMobEffect extends MobEffect {
|
|
||||||
&& !serverPlayer.isSpectator()
|
|
||||||
&& level.getDifficulty() != Difficulty.PEACEFUL
|
|
||||||
&& level.isVillage(serverPlayer.blockPosition())) {
|
|
||||||
+ // Leaves start - Revert raid changes
|
|
||||||
+ if (fun.bm.lophine.config.modules.misc.RaidChangesConfig.trigger) {
|
|
||||||
+ return level.getRaids().createOrExtendRaid(serverPlayer, serverPlayer.blockPosition()) == null;
|
|
||||||
+ }
|
|
||||||
+ // Leaves end - Revert raid changes
|
|
||||||
Raid raidAt = level.getRaidAt(serverPlayer.blockPosition());
|
|
||||||
if (raidAt == null || raidAt.getRaidOmenLevel() < raidAt.getMaxRaidOmenLevel()) {
|
|
||||||
serverPlayer.addEffect(new MobEffectInstance(MobEffects.RAID_OMEN, 600, amplifier));
|
|
||||||
diff --git a/net/minecraft/world/entity/raid/Raid.java b/net/minecraft/world/entity/raid/Raid.java
|
|
||||||
index 1910bff3f08147bfd63703097e30b9f88c84e337..26f4d7359f638a11ea2d768d18091e261d6b1791 100644
|
|
||||||
--- a/net/minecraft/world/entity/raid/Raid.java
|
|
||||||
+++ b/net/minecraft/world/entity/raid/Raid.java
|
|
||||||
@@ -340,7 +340,20 @@ public class Raid {
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flag1) {
|
|
||||||
- this.waveSpawnPos = this.getValidSpawnPos(level);
|
|
||||||
+ // Luminol Start - Raid revert
|
|
||||||
+ if (!fun.bm.lophine.config.modules.misc.RaidChangesConfig.posRevert) {
|
|
||||||
+ this.waveSpawnPos = this.getValidSpawnPos(level);
|
|
||||||
+ } else {
|
|
||||||
+ int n4 = 0;
|
|
||||||
+ if (this.raidCooldownTicks < 100) {
|
|
||||||
+ n4 = 1;
|
|
||||||
+ }
|
|
||||||
+ if (this.raidCooldownTicks < 40) {
|
|
||||||
+ n4 = 2;
|
|
||||||
+ }
|
|
||||||
+ this.waveSpawnPos = this.getValidSpawnPos(level, n4);
|
|
||||||
+ }
|
|
||||||
+ // Luminol End - Raid revert
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.raidCooldownTicks == 300 || this.raidCooldownTicks % 20 == 0) {
|
|
||||||
@@ -375,7 +388,14 @@ public class Raid {
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
while (this.shouldSpawnGroup()) {
|
|
||||||
- BlockPos blockPos = this.waveSpawnPos.orElseGet(() -> this.findRandomSpawnPos(level, 20));
|
|
||||||
+ // Luminol Start - Raid revert
|
|
||||||
+ BlockPos blockPos;
|
|
||||||
+ if (!fun.bm.lophine.config.modules.misc.RaidChangesConfig.posRevert) {
|
|
||||||
+ blockPos = this.waveSpawnPos.orElseGet(() -> this.findRandomSpawnPos(level, 20));
|
|
||||||
+ } else {
|
|
||||||
+ blockPos = this.waveSpawnPos.isPresent() ? this.waveSpawnPos.get() : this.findRandomSpawnPos(level, i, 20);
|
|
||||||
+ }
|
|
||||||
+ // Luminol End - Raid revert
|
|
||||||
if (blockPos != null) {
|
|
||||||
this.started = true;
|
|
||||||
this.spawnGroup(level, blockPos);
|
|
||||||
@@ -387,7 +407,7 @@ public class Raid {
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
- if (i > 5) {
|
|
||||||
+ if (i > (fun.bm.lophine.config.modules.misc.RaidChangesConfig.posRevert ? 3 : 5)) { // Luminol - Raid revert
|
|
||||||
org.bukkit.craftbukkit.event.CraftEventFactory.callRaidStopEvent(level, this, org.bukkit.event.raid.RaidStopEvent.Reason.UNSPAWNABLE); // CraftBukkit
|
|
||||||
this.stop();
|
|
||||||
break;
|
|
||||||
@@ -458,6 +478,17 @@ public class Raid {
|
|
||||||
return blockPos != null ? Optional.of(blockPos) : Optional.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
+ // Luminol Start - Raid revert
|
|
||||||
+ private Optional<BlockPos> getValidSpawnPos(ServerLevel level, int n) {
|
|
||||||
+ for (int i = 0; i < 3; ++i) {
|
|
||||||
+ BlockPos blockPos = this.findRandomSpawnPos(level, n, 1);
|
|
||||||
+ if (blockPos == null) continue;
|
|
||||||
+ return Optional.of(blockPos);
|
|
||||||
+ }
|
|
||||||
+ return Optional.empty();
|
|
||||||
+ }
|
|
||||||
+ // Luminol End - Raid revert
|
|
||||||
+
|
|
||||||
private boolean hasMoreWaves() {
|
|
||||||
return this.hasBonusWave() ? !this.hasSpawnedBonusWave() : !this.isFinalWave();
|
|
||||||
}
|
|
||||||
@@ -683,7 +714,7 @@ public class Raid {
|
|
||||||
int i2 = this.center.getX() + Mth.floor(Mth.cos(f2) * 32.0F * f) + level.random.nextInt(3) * Mth.floor(f);
|
|
||||||
int i3 = this.center.getZ() + Mth.floor(Mth.sin(f2) * 32.0F * f) + level.random.nextInt(3) * Mth.floor(f);
|
|
||||||
int height = level.getHeight(Heightmap.Types.WORLD_SURFACE, i2, i3);
|
|
||||||
- if (Mth.abs(height - this.center.getY()) <= 96) {
|
|
||||||
+ if (fun.bm.lophine.config.modules.misc.RaidChangesConfig.heightCheck || Mth.abs(height - this.center.getY()) <= 96) { // Leaves - Disable height check
|
|
||||||
mutableBlockPos.set(i2, height, i3);
|
|
||||||
if (!level.isVillage(mutableBlockPos) || i <= 7) {
|
|
||||||
int i4 = 10;
|
|
||||||
@@ -702,6 +733,26 @@ public class Raid {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ // Luminol Start - Raid revert
|
|
||||||
+ @Nullable
|
|
||||||
+ private BlockPos findRandomSpawnPos(ServerLevel level, int n, int n2) {
|
|
||||||
+ int n3 = 2 - n;
|
|
||||||
+ BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos();
|
|
||||||
+ SpawnPlacementType spawnPlacementType = SpawnPlacements.getPlacementType(EntityType.RAVAGER);
|
|
||||||
+ for (int i = 0; i < n2; ++i) {
|
|
||||||
+ float f = level.random.nextFloat() * ((float)Math.PI * 2);
|
|
||||||
+ int n4 = this.center.getX() + Mth.floor(Mth.cos(f) * 32.0f * (float)n3) + level.random.nextInt(5);
|
|
||||||
+ int n5 = this.center.getZ() + Mth.floor(Mth.sin(f) * 32.0f * (float)n3) + level.random.nextInt(5);
|
|
||||||
+ int n6 = level.getHeight(Heightmap.Types.WORLD_SURFACE, n4, n5);
|
|
||||||
+ mutableBlockPos.set(n4, n6, n5);
|
|
||||||
+ if (level.isVillage(mutableBlockPos) && n < 2) continue;
|
|
||||||
+ if (!level.hasChunksAt(mutableBlockPos.getX() - 10, mutableBlockPos.getZ() - 10, mutableBlockPos.getX() + 10, mutableBlockPos.getZ() + 10) || !level.isPositionEntityTicking(mutableBlockPos) || !spawnPlacementType.isSpawnPositionOk(level, mutableBlockPos, EntityType.RAVAGER) && (!level.getBlockState(mutableBlockPos.below()).is(Blocks.SNOW) || !level.getBlockState(mutableBlockPos).isAir())) continue;
|
|
||||||
+ return mutableBlockPos;
|
|
||||||
+ }
|
|
||||||
+ return null;
|
|
||||||
+ }
|
|
||||||
+ // Luminol End - Raid revert
|
|
||||||
+
|
|
||||||
private boolean addWaveMob(ServerLevel level, int wave, Raider raider) {
|
|
||||||
// Folia start - make raids thread-safe
|
|
||||||
if (!this.ownsRaid(level)) {
|
|
||||||
diff --git a/net/minecraft/world/entity/raid/Raider.java b/net/minecraft/world/entity/raid/Raider.java
|
|
||||||
index 3e30989c99cd11c8c94d6fd194d2969e3a7efda6..510514e363f4816a6e286fb9b5488153e03c9e55 100644
|
|
||||||
--- a/net/minecraft/world/entity/raid/Raider.java
|
|
||||||
+++ b/net/minecraft/world/entity/raid/Raider.java
|
|
||||||
@@ -128,6 +128,41 @@ public abstract class Raider extends PatrollingMonster {
|
|
||||||
|
|
||||||
currentRaid.removeFromRaid(serverLevel, this, false);
|
|
||||||
}
|
|
||||||
+
|
|
||||||
+ // Leaves start - Revert raid changes
|
|
||||||
+ if (fun.bm.lophine.config.modules.misc.RaidChangesConfig.effect && !this.hasRaid()) {
|
|
||||||
+ ItemStack itemstack = this.getItemBySlot(EquipmentSlot.HEAD);
|
|
||||||
+ net.minecraft.world.entity.player.Player entityhuman = null;
|
|
||||||
+ if (entity instanceof net.minecraft.world.entity.player.Player player) {
|
|
||||||
+ entityhuman = player;
|
|
||||||
+ } else if (entity instanceof net.minecraft.world.entity.animal.wolf.Wolf wolf) {
|
|
||||||
+ LivingEntity entityliving = wolf.getOwner();
|
|
||||||
+ if (wolf.isTame() && entityliving instanceof net.minecraft.world.entity.player.Player player) {
|
|
||||||
+ entityhuman = player;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (entityhuman != null && !itemstack.isEmpty() && this.isCaptain()) {
|
|
||||||
+ net.minecraft.world.effect.MobEffectInstance mobeffect = entityhuman.getEffect(net.minecraft.world.effect.MobEffects.BAD_OMEN);
|
|
||||||
+ int i = 1;
|
|
||||||
+
|
|
||||||
+ if (mobeffect != null) {
|
|
||||||
+ i += mobeffect.getAmplifier();
|
|
||||||
+ entityhuman.removeEffectNoUpdate(net.minecraft.world.effect.MobEffects.BAD_OMEN);
|
|
||||||
+ } else {
|
|
||||||
+ --i;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ i = net.minecraft.util.Mth.clamp(i, 0, 4);
|
|
||||||
+ net.minecraft.world.effect.MobEffectInstance mobeffect1 = new net.minecraft.world.effect.MobEffectInstance(net.minecraft.world.effect.MobEffects.BAD_OMEN, fun.bm.lophine.config.modules.misc.RaidChangesConfig.infinite ? net.minecraft.world.effect.MobEffectInstance.INFINITE_DURATION : 120000, i, false, false, true);
|
|
||||||
+
|
|
||||||
+ if (!serverLevel.getGameRules().getBoolean(net.minecraft.world.level.GameRules.RULE_DISABLE_RAIDS)) {
|
|
||||||
+ entityhuman.addEffect(mobeffect1, entityhuman, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.PATROL_CAPTAIN, true); // CraftBukkit
|
|
||||||
+ }
|
|
||||||
+ this.setPatrolLeader(false);
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ // Leaves end - Revert raid changes
|
|
||||||
}
|
|
||||||
|
|
||||||
super.die(cause);
|
|
||||||
@@ -156,7 +191,7 @@ public abstract class Raider extends PatrollingMonster {
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasRaid() {
|
|
||||||
- return this.level() instanceof ServerLevel serverLevel && (this.getCurrentRaid() != null || serverLevel.getRaidAt(this.blockPosition()) != null);
|
|
||||||
+ return !fun.bm.lophine.config.modules.misc.RaidChangesConfig.selfCheck && (this.level() instanceof ServerLevel serverLevel && (this.getCurrentRaid() != null || serverLevel.getRaidAt(this.blockPosition()) != null)); // Leaves - Disable raid self check
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasActiveRaid() {
|
|
||||||
diff --git a/net/minecraft/world/item/component/OminousBottleAmplifier.java b/net/minecraft/world/item/component/OminousBottleAmplifier.java
|
|
||||||
index 33907bb190ffa22ccf9ea424b1e536297878711a..2fca459f2c888079322f6b957bbee3ac0e33c4bc 100644
|
|
||||||
--- a/net/minecraft/world/item/component/OminousBottleAmplifier.java
|
|
||||||
+++ b/net/minecraft/world/item/component/OminousBottleAmplifier.java
|
|
||||||
@@ -29,7 +29,7 @@ public record OminousBottleAmplifier(int value) implements ConsumableListener, T
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onConsume(Level level, LivingEntity entity, ItemStack stack, Consumable consumable) {
|
|
||||||
- entity.addEffect(new MobEffectInstance(MobEffects.BAD_OMEN, 120000, this.value, false, false, true)); // Paper - properly resend entities - diff on change for below
|
|
||||||
+ entity.addEffect(new MobEffectInstance(MobEffects.BAD_OMEN, fun.bm.lophine.config.modules.misc.RaidChangesConfig.infinite ? net.minecraft.world.effect.MobEffectInstance.INFINITE_DURATION : 120000, this.value, false, false, true)); // Paper - properly resend entities - diff on change for below // Luminol - Raid effect infinite
|
|
||||||
}
|
|
||||||
|
|
||||||
// Paper start - properly resend entities - collect packets for bundle
|
|
||||||
@@ -41,7 +41,7 @@ public record OminousBottleAmplifier(int value) implements ConsumableListener, T
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addToTooltip(Item.TooltipContext context, Consumer<Component> tooltipAdder, TooltipFlag flag, DataComponentGetter componentGetter) {
|
|
||||||
- List<MobEffectInstance> list = List.of(new MobEffectInstance(MobEffects.BAD_OMEN, 120000, this.value, false, false, true));
|
|
||||||
+ List<MobEffectInstance> list = List.of(new MobEffectInstance(MobEffects.BAD_OMEN, fun.bm.lophine.config.modules.misc.RaidChangesConfig.infinite ? net.minecraft.world.effect.MobEffectInstance.INFINITE_DURATION : 120000, this.value, false, false, true)); // Luminol - Raid effect infinite
|
|
||||||
PotionContents.addPotionTooltip(list, tooltipAdder, 1.0F, context.tickRate());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
|
||||||
|
Date: Wed, 23 Jul 2025 20:28:40 +0800
|
||||||
|
Subject: [PATCH] Leaves: Redstone Shears Wrench
|
||||||
|
|
||||||
|
Co-authored by: violetc <58360096+s-yh-china@users.noreply.github.com>
|
||||||
|
As a part of : Leaves (https://github.com/LeavesMC/Leaves/blob/79d9ef74c2684eb49060f07e1ab31c827326c9a5/leaves-server/minecraft-patches/features/0009-Redstone-Shears-Wrench.patch)
|
||||||
|
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
|
||||||
|
|
||||||
|
diff --git a/net/minecraft/world/item/BlockItem.java b/net/minecraft/world/item/BlockItem.java
|
||||||
|
index 6db566adf2d0df1d26221eda04aa01738df6d3d2..24ebfdf98e343a7892af621d032c35819156deec 100644
|
||||||
|
--- a/net/minecraft/world/item/BlockItem.java
|
||||||
|
+++ b/net/minecraft/world/item/BlockItem.java
|
||||||
|
@@ -56,6 +56,14 @@ public class BlockItem extends Item {
|
||||||
|
if (blockPlaceContext == null) {
|
||||||
|
return InteractionResult.FAIL;
|
||||||
|
} else {
|
||||||
|
+ // Leaves start - shears wrench
|
||||||
|
+ if (org.leavesmc.leaves.util.ShearsWrenchUtil.shouldSkipPlace(context)) {
|
||||||
|
+ if (context.getPlayer() != null) {
|
||||||
|
+ context.getPlayer().containerMenu.forceHeldSlot(blockPlaceContext.getHand());
|
||||||
|
+ }
|
||||||
|
+ return InteractionResult.FAIL;
|
||||||
|
+ }
|
||||||
|
+ // Leaves end - shears wrench
|
||||||
|
BlockState placementState = this.getPlacementState(blockPlaceContext);
|
||||||
|
// CraftBukkit start - special case for handling block placement with water lilies and snow buckets
|
||||||
|
org.bukkit.block.BlockState bukkitState = null;
|
||||||
|
diff --git a/net/minecraft/world/item/ShearsItem.java b/net/minecraft/world/item/ShearsItem.java
|
||||||
|
index 8cf3e51e12f9cf98836657e722edb23943f9e866..5fd5e9fd4e1a79dd1a9d62a5cf0c308805979420 100644
|
||||||
|
--- a/net/minecraft/world/item/ShearsItem.java
|
||||||
|
+++ b/net/minecraft/world/item/ShearsItem.java
|
||||||
|
@@ -80,7 +80,10 @@ public class ShearsItem extends Item {
|
||||||
|
|
||||||
|
return InteractionResult.SUCCESS;
|
||||||
|
} else {
|
||||||
|
- return super.useOn(context);
|
||||||
|
+ // Leaves start - shears wrench
|
||||||
|
+ InteractionResult result = org.leavesmc.leaves.util.ShearsWrenchUtil.tryApplyRotate(context, blockState);
|
||||||
|
+ return result == null ? super.useOn(context) : result;
|
||||||
|
+ // Leaves end - shears wrench
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,153 +0,0 @@
|
|||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
|
|
||||||
Date: Wed, 23 Jul 2025 20:28:40 +0800
|
|
||||||
Subject: [PATCH] Leaves: Redstone Shears Wrench
|
|
||||||
|
|
||||||
Co-authored by: violetc <58360096+s-yh-china@users.noreply.github.com>
|
|
||||||
As a part of : Leaves (https://github.com/LeavesMC/Leaves/blob/bfde470a867b74d177fe1b9a2a3ed5c49cd126c7/leaves-server/minecraft-patches/features/0009-Redstone-Shears-Wrench.patch)
|
|
||||||
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
|
|
||||||
|
|
||||||
diff --git a/net/minecraft/world/item/ShearsItem.java b/net/minecraft/world/item/ShearsItem.java
|
|
||||||
index 8cf3e51e12f9cf98836657e722edb23943f9e866..155693a18bb641a930a000bc9b1ccfc853e1bae5 100644
|
|
||||||
--- a/net/minecraft/world/item/ShearsItem.java
|
|
||||||
+++ b/net/minecraft/world/item/ShearsItem.java
|
|
||||||
@@ -24,6 +24,30 @@ import net.minecraft.world.level.block.GrowingPlantHeadBlock;
|
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
|
||||||
import net.minecraft.world.level.gameevent.GameEvent;
|
|
||||||
|
|
||||||
+// Leaves start - shears wrench
|
|
||||||
+import net.minecraft.Util;
|
|
||||||
+import net.minecraft.network.chat.Component;
|
|
||||||
+import net.minecraft.world.level.block.ComparatorBlock;
|
|
||||||
+import net.minecraft.world.level.block.DispenserBlock;
|
|
||||||
+import net.minecraft.world.level.block.HopperBlock;
|
|
||||||
+import net.minecraft.world.level.block.ObserverBlock;
|
|
||||||
+import net.minecraft.world.level.block.RepeaterBlock;
|
|
||||||
+import net.minecraft.world.level.block.CrafterBlock;
|
|
||||||
+import net.minecraft.world.level.block.LeverBlock;
|
|
||||||
+import net.minecraft.world.level.block.CocoaBlock;
|
|
||||||
+import net.minecraft.world.level.block.TrapDoorBlock;
|
|
||||||
+import net.minecraft.world.level.block.FenceGateBlock;
|
|
||||||
+import net.minecraft.world.level.block.LightningRodBlock;
|
|
||||||
+import net.minecraft.world.level.block.RailBlock;
|
|
||||||
+import net.minecraft.world.level.block.BaseRailBlock;
|
|
||||||
+import net.minecraft.world.level.block.PoweredRailBlock;
|
|
||||||
+import net.minecraft.world.level.block.CalibratedSculkSensorBlock;
|
|
||||||
+import net.minecraft.world.level.block.piston.PistonBaseBlock;
|
|
||||||
+import net.minecraft.world.level.block.state.StateDefinition;
|
|
||||||
+import net.minecraft.world.level.block.state.properties.RailShape;
|
|
||||||
+import net.minecraft.world.level.block.state.properties.Property;
|
|
||||||
+// Leaves end - shears wrench
|
|
||||||
+
|
|
||||||
public class ShearsItem extends Item {
|
|
||||||
public ShearsItem(Item.Properties properties) {
|
|
||||||
super(properties);
|
|
||||||
@@ -80,7 +104,108 @@ public class ShearsItem extends Item {
|
|
||||||
|
|
||||||
return InteractionResult.SUCCESS;
|
|
||||||
} else {
|
|
||||||
+ // Leaves start - shears wrench
|
|
||||||
+ Block block = blockState.getBlock();
|
|
||||||
+ if (fun.bm.lophine.config.modules.misc.RedStoneConfig.shears && (
|
|
||||||
+ block instanceof ObserverBlock ||
|
|
||||||
+ block instanceof DispenserBlock ||
|
|
||||||
+ block instanceof PistonBaseBlock ||
|
|
||||||
+ block instanceof HopperBlock ||
|
|
||||||
+ block instanceof RepeaterBlock ||
|
|
||||||
+ block instanceof ComparatorBlock ||
|
|
||||||
+ block instanceof CrafterBlock ||
|
|
||||||
+ block instanceof LeverBlock ||
|
|
||||||
+ block instanceof CocoaBlock ||
|
|
||||||
+ block instanceof TrapDoorBlock ||
|
|
||||||
+ block instanceof FenceGateBlock ||
|
|
||||||
+ block instanceof LightningRodBlock ||
|
|
||||||
+ block instanceof CalibratedSculkSensorBlock ||
|
|
||||||
+ block instanceof BaseRailBlock
|
|
||||||
+ )) {
|
|
||||||
+ StateDefinition<Block, BlockState> blockstatelist = block.getStateDefinition();
|
|
||||||
+ Property<?> iblockstate;
|
|
||||||
+ if (block instanceof CrafterBlock) iblockstate = blockstatelist.getProperty("orientation");
|
|
||||||
+ else if (block instanceof BaseRailBlock) iblockstate = blockstatelist.getProperty("shape");
|
|
||||||
+ else iblockstate = blockstatelist.getProperty("facing");
|
|
||||||
+ Player player = context.getPlayer();
|
|
||||||
+
|
|
||||||
+ if (iblockstate == null || player == null) {
|
|
||||||
+ return InteractionResult.FAIL;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (block instanceof BaseRailBlock) {
|
|
||||||
+ if (block instanceof RailBlock) {
|
|
||||||
+ if (blockState.getValue(RailBlock.SHAPE).isSlope()) {
|
|
||||||
+ return InteractionResult.FAIL;
|
|
||||||
+ }
|
|
||||||
+ } else {
|
|
||||||
+ if (getNameHelper(blockState, PoweredRailBlock.POWERED).equals("true")) {
|
|
||||||
+ return InteractionResult.FAIL;
|
|
||||||
+ }
|
|
||||||
+ if (blockState.getValue(PoweredRailBlock.SHAPE).isSlope()) {
|
|
||||||
+ return InteractionResult.FAIL;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (block instanceof PistonBaseBlock) {
|
|
||||||
+ if (getNameHelper(blockState, PistonBaseBlock.EXTENDED).equals("true")) {
|
|
||||||
+ return InteractionResult.FAIL;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (block instanceof RepeaterBlock || block instanceof ComparatorBlock) {
|
|
||||||
+ if (getNameHelper(blockState, ComparatorBlock.POWERED).equals("true")) {
|
|
||||||
+ return InteractionResult.FAIL;
|
|
||||||
+ }
|
|
||||||
+ if (block instanceof RepeaterBlock) {
|
|
||||||
+ if (getNameHelper(blockState, RepeaterBlock.LOCKED).equals("true")) {
|
|
||||||
+ return InteractionResult.FAIL;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (block instanceof CrafterBlock) {
|
|
||||||
+ if (getNameHelper(blockState, CrafterBlock.CRAFTING).equals("true")) {
|
|
||||||
+ return InteractionResult.FAIL;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ BlockState iblockdata1 = ShearsItem.cycleState(blockState, iblockstate, player.isSecondaryUseActive());
|
|
||||||
+ level.setBlock(clickedPos, iblockdata1, 18);
|
|
||||||
+ ShearsItem.message(player, Component.translatable("item.minecraft.debug_stick.update", iblockstate.getName(), ShearsItem.getNameHelper(iblockdata1, iblockstate)));
|
|
||||||
+ return InteractionResult.CONSUME;
|
|
||||||
+ }
|
|
||||||
+ // Leaves end - shears wrench
|
|
||||||
+
|
|
||||||
return super.useOn(context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+
|
|
||||||
+ // Leaves start - shears wrench
|
|
||||||
+ private static <T extends Comparable<T>> BlockState cycleState(BlockState state, Property<T> property, boolean inverse) {
|
|
||||||
+ List<T> possibleValues = property.getPossibleValues();
|
|
||||||
+ if (possibleValues.getFirst() instanceof RailShape) {
|
|
||||||
+ boolean isRailBlock = state.getBlock() instanceof RailBlock;
|
|
||||||
+ possibleValues = possibleValues.stream().filter(possibleValue -> {
|
|
||||||
+ RailShape shape = (RailShape) possibleValue;
|
|
||||||
+ if (isRailBlock) return !shape.isSlope();
|
|
||||||
+ return !shape.isSlope() && shape != RailShape.NORTH_EAST && shape != RailShape.NORTH_WEST && shape != RailShape.SOUTH_EAST && shape != RailShape.SOUTH_WEST;
|
|
||||||
+ }).toList();
|
|
||||||
+ }
|
|
||||||
+ return state.setValue(property, ShearsItem.getRelative(possibleValues, state.getValue(property), inverse)); // CraftBukkit - decompile error
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ private static <T> T getRelative(Iterable<T> elements, T current, boolean inverse) {
|
|
||||||
+ return inverse ? Util.findPreviousInIterable(elements, current) : Util.findNextInIterable(elements, current);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ private static void message(Player player, Component message) {
|
|
||||||
+ ((ServerPlayer) player).sendSystemMessage(message, true);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ private static <T extends Comparable<T>> String getNameHelper(BlockState state, Property<T> property) {
|
|
||||||
+ return property.getName(state.getValue(property));
|
|
||||||
+ }
|
|
||||||
+ // Leaves end - shears wrench
|
|
||||||
}
|
|
||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
|
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
|
||||||
Date: Mon, 7 Jul 2025 15:33:57 +0800
|
Date: Mon, 7 Jul 2025 15:33:57 +0800
|
||||||
Subject: [PATCH] Old Explosion Damage Calculator
|
Subject: [PATCH] Leaves: Old Explosion Damage Calculator
|
||||||
|
|
||||||
Co-authored by: MC_XiaoHei <xor7xiaohei@gmail.com>
|
Co-authored by: MC_XiaoHei <xor7xiaohei@gmail.com>
|
||||||
As a part of : Leaves (https://github.com/LeavesMC/Leaves/blob/3e96b237749a960f297f211d439ffc9ea7fd2381/leaves-server/minecraft-patches/features/0134-Old-wet-tnt-explode-behavior.patch)
|
As a part of : Leaves (https://github.com/LeavesMC/Leaves/blob/3e96b237749a960f297f211d439ffc9ea7fd2381/leaves-server/minecraft-patches/features/0134-Old-wet-tnt-explode-behavior.patch)
|
||||||
@@ -0,0 +1,216 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
|
||||||
|
Date: Fri, 11 Apr 2025 16:53:57 +0800
|
||||||
|
Subject: [PATCH] Leaves: Old raid behavior
|
||||||
|
|
||||||
|
Co-authored by: huanli233 <392352840@qq.com>
|
||||||
|
As a part of : Leaves (https://github.com/LeavesMC/Leaves/blob/79d9ef74c2684eb49060f07e1ab31c827326c9a5/leaves-server/minecraft-patches/features/0106-Old-raid-behavior.patch)
|
||||||
|
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
|
||||||
|
|
||||||
|
diff --git a/net/minecraft/world/effect/BadOmenMobEffect.java b/net/minecraft/world/effect/BadOmenMobEffect.java
|
||||||
|
index 80f17f33f670018240c854df589cf90cdeab6e70..cbfb4ae2dc30c2ee98ef37f44a95434a7968e320 100644
|
||||||
|
--- a/net/minecraft/world/effect/BadOmenMobEffect.java
|
||||||
|
+++ b/net/minecraft/world/effect/BadOmenMobEffect.java
|
||||||
|
@@ -22,6 +22,11 @@ class BadOmenMobEffect extends MobEffect {
|
||||||
|
&& !serverPlayer.isSpectator()
|
||||||
|
&& level.getDifficulty() != Difficulty.PEACEFUL
|
||||||
|
&& level.isVillage(serverPlayer.blockPosition())) {
|
||||||
|
+ // Leaves start - Revert raid changes
|
||||||
|
+ if (fun.bm.lophine.config.modules.misc.OldFeatureConfig.oldRaidBehavior) {
|
||||||
|
+ return level.getRaids().createOrExtendRaid(serverPlayer, serverPlayer.blockPosition()) == null;
|
||||||
|
+ }
|
||||||
|
+ // Leaves end - Revert raid changes
|
||||||
|
Raid raidAt = level.getRaidAt(serverPlayer.blockPosition());
|
||||||
|
if (raidAt == null || raidAt.getRaidOmenLevel() < raidAt.getMaxRaidOmenLevel()) {
|
||||||
|
serverPlayer.addEffect(new MobEffectInstance(MobEffects.RAID_OMEN, 600, amplifier));
|
||||||
|
diff --git a/net/minecraft/world/entity/raid/Raid.java b/net/minecraft/world/entity/raid/Raid.java
|
||||||
|
index 1910bff3f08147bfd63703097e30b9f88c84e337..5188ae86aff3051d45fe5e7d2fcc51233b7074d4 100644
|
||||||
|
--- a/net/minecraft/world/entity/raid/Raid.java
|
||||||
|
+++ b/net/minecraft/world/entity/raid/Raid.java
|
||||||
|
@@ -263,7 +263,7 @@ public class Raid {
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean absorbRaidOmen(ServerPlayer player) {
|
||||||
|
- MobEffectInstance effect = player.getEffect(MobEffects.RAID_OMEN);
|
||||||
|
+ MobEffectInstance effect = player.getEffect(fun.bm.lophine.config.modules.misc.OldFeatureConfig.oldRaidBehavior ? MobEffects.BAD_OMEN : MobEffects.RAID_OMEN); // Leaves - old Raid Behavior
|
||||||
|
if (effect == null) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
@@ -340,7 +340,13 @@ public class Raid {
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flag1) {
|
||||||
|
- this.waveSpawnPos = this.getValidSpawnPos(level);
|
||||||
|
+ // Leaves Start - old FindSpawnPosition
|
||||||
|
+ if (fun.bm.lophine.config.modules.misc.OldFeatureConfig.oldRaidBehavior) {
|
||||||
|
+ this.waveSpawnPos = this.preCalcRavagerSpawnLocation(level, this.raidCooldownTicks < 100 ? 1 : 0);
|
||||||
|
+ } else {
|
||||||
|
+ this.waveSpawnPos = this.getValidSpawnPos(level);
|
||||||
|
+ }
|
||||||
|
+ // Leaves End - old FindSpawnPosition
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.raidCooldownTicks == 300 || this.raidCooldownTicks % 20 == 0) {
|
||||||
|
@@ -375,7 +381,14 @@ public class Raid {
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
while (this.shouldSpawnGroup()) {
|
||||||
|
- BlockPos blockPos = this.waveSpawnPos.orElseGet(() -> this.findRandomSpawnPos(level, 20));
|
||||||
|
+ // Leaves Start - old FindSpawnPosition
|
||||||
|
+ BlockPos blockPos;
|
||||||
|
+ if (fun.bm.lophine.config.modules.misc.OldFeatureConfig.oldRaidBehavior) {
|
||||||
|
+ blockPos = this.getRavagerSpawnLocation(level, i, 20);
|
||||||
|
+ } else {
|
||||||
|
+ blockPos = this.waveSpawnPos.orElseGet(() -> this.findRandomSpawnPos(level, 20));
|
||||||
|
+ }
|
||||||
|
+ // Leaves End - old FindSpawnPosition
|
||||||
|
if (blockPos != null) {
|
||||||
|
this.started = true;
|
||||||
|
this.spawnGroup(level, blockPos);
|
||||||
|
@@ -387,7 +400,7 @@ public class Raid {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
- if (i > 5) {
|
||||||
|
+ if (i > (fun.bm.lophine.config.modules.misc.OldFeatureConfig.oldRaidBehavior ? 3 : 5)) { // Leaves - old FindSpawnPosition
|
||||||
|
org.bukkit.craftbukkit.event.CraftEventFactory.callRaidStopEvent(level, this, org.bukkit.event.raid.RaidStopEvent.Reason.UNSPAWNABLE); // CraftBukkit
|
||||||
|
this.stop();
|
||||||
|
break;
|
||||||
|
@@ -683,7 +696,7 @@ public class Raid {
|
||||||
|
int i2 = this.center.getX() + Mth.floor(Mth.cos(f2) * 32.0F * f) + level.random.nextInt(3) * Mth.floor(f);
|
||||||
|
int i3 = this.center.getZ() + Mth.floor(Mth.sin(f2) * 32.0F * f) + level.random.nextInt(3) * Mth.floor(f);
|
||||||
|
int height = level.getHeight(Heightmap.Types.WORLD_SURFACE, i2, i3);
|
||||||
|
- if (Mth.abs(height - this.center.getY()) <= 96) {
|
||||||
|
+ if (fun.bm.lophine.config.modules.misc.OldFeatureConfig.oldRaidBehavior || Mth.abs(height - this.center.getY()) <= 96) { // Leaves - skippable
|
||||||
|
mutableBlockPos.set(i2, height, i3);
|
||||||
|
if (!level.isVillage(mutableBlockPos) || i <= 7) {
|
||||||
|
int i4 = 10;
|
||||||
|
@@ -702,6 +715,36 @@ public class Raid {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ // Leaves Start - old FindSpawnPosition
|
||||||
|
+ @Nullable
|
||||||
|
+ private BlockPos findRandomSpawnPos(ServerLevel level, int n, int n2) {
|
||||||
|
+ int n3 = 2 - n;
|
||||||
|
+ BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos();
|
||||||
|
+ SpawnPlacementType spawnPlacementType = SpawnPlacements.getPlacementType(EntityType.RAVAGER);
|
||||||
|
+ for (int i = 0; i < n2; ++i) {
|
||||||
|
+ float f = level.random.nextFloat() * ((float)Math.PI * 2);
|
||||||
|
+ int n4 = this.center.getX() + Mth.floor(Mth.cos(f) * 32.0f * (float)n3) + level.random.nextInt(5);
|
||||||
|
+ int n5 = this.center.getZ() + Mth.floor(Mth.sin(f) * 32.0f * (float)n3) + level.random.nextInt(5);
|
||||||
|
+ int n6 = level.getHeight(Heightmap.Types.WORLD_SURFACE, n4, n5);
|
||||||
|
+ mutableBlockPos.set(n4, n6, n5);
|
||||||
|
+ if (level.isVillage(mutableBlockPos) && n < 2) continue;
|
||||||
|
+ if (!level.hasChunksAt(mutableBlockPos.getX() - 10, mutableBlockPos.getZ() - 10, mutableBlockPos.getX() + 10, mutableBlockPos.getZ() + 10) || !level.isPositionEntityTicking(mutableBlockPos) || !spawnPlacementType.isSpawnPositionOk(level, mutableBlockPos, EntityType.RAVAGER) && (!level.getBlockState((BlockPos)mutableBlockPos.below()).is(Blocks.SNOW) || !level.getBlockState(mutableBlockPos).isAir())) continue;
|
||||||
|
+ return mutableBlockPos;
|
||||||
|
+ }
|
||||||
|
+ return null;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private Optional<BlockPos> getValidSpawnPos(ServerLevel level, int n) {
|
||||||
|
+ for (int i = 0; i < 3; ++i) {
|
||||||
|
+ BlockPos blockPos = this.findRandomSpawnPos(level, n, 1);
|
||||||
|
+ if (blockPos == null) continue;
|
||||||
|
+ return Optional.of(blockPos);
|
||||||
|
+ }
|
||||||
|
+ return Optional.empty();
|
||||||
|
+ }
|
||||||
|
+ // Leaves End - old FindSpawnPosition
|
||||||
|
+
|
||||||
|
+
|
||||||
|
private boolean addWaveMob(ServerLevel level, int wave, Raider raider) {
|
||||||
|
// Folia start - make raids thread-safe
|
||||||
|
if (!this.ownsRaid(level)) {
|
||||||
|
@@ -864,4 +907,43 @@ public class Raid {
|
||||||
|
this.spawnsPerWaveBeforeBonus = spawnsPerWaveBeforeBonus;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ // Leaves start - old FindSpawnPosition
|
||||||
|
+ private BlockPos getRavagerSpawnLocation(ServerLevel serverWorld, int proximity, int tries) {
|
||||||
|
+ int i = proximity == 0 ? 2 : 2 - proximity;
|
||||||
|
+ BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos();
|
||||||
|
+ SpawnPlacementType spawnLocation = SpawnPlacements.getPlacementType(EntityType.RAVAGER);
|
||||||
|
+
|
||||||
|
+ for (int j = 0; j < tries; j++) {
|
||||||
|
+ float f = serverWorld.random.nextFloat() * (float) (Math.PI * 2);
|
||||||
|
+ int k = this.center.getX() + Mth.floor(Mth.cos(f) * 32.0F * (float) i + serverWorld.random.nextInt(5));
|
||||||
|
+ int l = this.center.getZ() + Mth.floor(Mth.sin(f) * 32.0F * (float) i + serverWorld.random.nextInt(5));
|
||||||
|
+ int m = serverWorld.getHeight(Heightmap.Types.WORLD_SURFACE, k, l);
|
||||||
|
+ mutable.set(k, m, l);
|
||||||
|
+
|
||||||
|
+ if (serverWorld.isVillage(mutable) && proximity < 2) {
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
+ if (serverWorld.hasChunksAt(mutable.getX() - 10, mutable.getZ() - 10, mutable.getX() + 10, mutable.getZ() + 10)
|
||||||
|
+ && serverWorld.isPositionEntityTicking(mutable)
|
||||||
|
+ && (spawnLocation.isSpawnPositionOk(serverWorld, mutable, EntityType.RAVAGER)
|
||||||
|
+ || serverWorld.getBlockState(mutable.below()).is(Blocks.SNOW)
|
||||||
|
+ && serverWorld.getBlockState(mutable).isAir())
|
||||||
|
+ ) {
|
||||||
|
+ return mutable;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ return null;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private Optional<BlockPos> preCalcRavagerSpawnLocation(ServerLevel serverWorld, int proximity) {
|
||||||
|
+ for (int i = 0; i < 3; i++) {
|
||||||
|
+ BlockPos blockPos = this.getRavagerSpawnLocation(serverWorld, proximity, 1);
|
||||||
|
+ if (blockPos != null) {
|
||||||
|
+ return Optional.of(blockPos);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ return Optional.empty();
|
||||||
|
+ }
|
||||||
|
+ // Leaves end - old FindSpawnPosition
|
||||||
|
}
|
||||||
|
diff --git a/net/minecraft/world/entity/raid/Raider.java b/net/minecraft/world/entity/raid/Raider.java
|
||||||
|
index 3e30989c99cd11c8c94d6fd194d2969e3a7efda6..b1f1bcf7f5ac002550077d5e1d4efd5c67d18063 100644
|
||||||
|
--- a/net/minecraft/world/entity/raid/Raider.java
|
||||||
|
+++ b/net/minecraft/world/entity/raid/Raider.java
|
||||||
|
@@ -128,6 +128,43 @@ public abstract class Raider extends PatrollingMonster {
|
||||||
|
|
||||||
|
currentRaid.removeFromRaid(serverLevel, this, false);
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ // Leaves start - Revert raid changes
|
||||||
|
+ if (this.level() instanceof ServerLevel) {
|
||||||
|
+ if (fun.bm.lophine.config.modules.misc.OldFeatureConfig.oldRaidBehavior && !this.hasRaid()) {
|
||||||
|
+ ItemStack itemstack = this.getItemBySlot(EquipmentSlot.HEAD);
|
||||||
|
+ net.minecraft.world.entity.player.Player entityhuman = null;
|
||||||
|
+ if (entity instanceof net.minecraft.world.entity.player.Player player) {
|
||||||
|
+ entityhuman = player;
|
||||||
|
+ } else if (entity instanceof net.minecraft.world.entity.animal.wolf.Wolf wolf) {
|
||||||
|
+ LivingEntity entityliving = wolf.getOwner();
|
||||||
|
+ if (wolf.isTame() && entityliving instanceof net.minecraft.world.entity.player.Player player) {
|
||||||
|
+ entityhuman = player;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (entityhuman != null && !itemstack.isEmpty() && this.isCaptain()) {
|
||||||
|
+ net.minecraft.world.effect.MobEffectInstance mobeffect = entityhuman.getEffect(net.minecraft.world.effect.MobEffects.BAD_OMEN);
|
||||||
|
+ int i = 1;
|
||||||
|
+
|
||||||
|
+ if (mobeffect != null) {
|
||||||
|
+ i += mobeffect.getAmplifier();
|
||||||
|
+ entityhuman.removeEffectNoUpdate(net.minecraft.world.effect.MobEffects.BAD_OMEN);
|
||||||
|
+ } else {
|
||||||
|
+ --i;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ i = net.minecraft.util.Mth.clamp(i, 0, 4);
|
||||||
|
+ net.minecraft.world.effect.MobEffectInstance mobeffect1 = new net.minecraft.world.effect.MobEffectInstance(net.minecraft.world.effect.MobEffects.BAD_OMEN, 120000, i, false, false, true);
|
||||||
|
+
|
||||||
|
+ if (!serverLevel.getGameRules().getBoolean(net.minecraft.world.level.GameRules.RULE_DISABLE_RAIDS)) {
|
||||||
|
+ entityhuman.addEffect(mobeffect1, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.PATROL_CAPTAIN); // CraftBukkit
|
||||||
|
+ }
|
||||||
|
+ this.setPatrolLeader(false);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ // Leaves end - Revert raid changes
|
||||||
|
}
|
||||||
|
|
||||||
|
super.die(cause);
|
||||||
@@ -4,6 +4,32 @@ Date: Thu, 12 Jun 2025 04:44:24 +0800
|
|||||||
Subject: [PATCH] I18n support
|
Subject: [PATCH] I18n support
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/net/minecraft/locale/Language.java b/net/minecraft/locale/Language.java
|
||||||
|
index 7b9e2a1a208b46a69c16e6afd8b502259893574f..db46a31ea8a36562e548eb07f0c4cf9b9e8c3360 100644
|
||||||
|
--- a/net/minecraft/locale/Language.java
|
||||||
|
+++ b/net/minecraft/locale/Language.java
|
||||||
|
@@ -65,7 +65,7 @@ public abstract class Language {
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
- private static void parseTranslations(BiConsumer<String, String> output, String languagePath) {
|
||||||
|
+ public static void parseTranslations(BiConsumer<String, String> output, String languagePath) { // Lophine - private -> public
|
||||||
|
try (InputStream resourceAsStream = Language.class.getResourceAsStream(languagePath)) {
|
||||||
|
loadFromJson(resourceAsStream, output);
|
||||||
|
} catch (JsonParseException | IOException var7) {
|
||||||
|
diff --git a/net/minecraft/server/Main.java b/net/minecraft/server/Main.java
|
||||||
|
index cf72cb8b418239b56c755486b03a321672e16bc3..b69c06607ca900beeebf4892a978442dad2db19b 100644
|
||||||
|
--- a/net/minecraft/server/Main.java
|
||||||
|
+++ b/net/minecraft/server/Main.java
|
||||||
|
@@ -155,6 +155,8 @@ public class Main {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ fun.bm.lophine.utils.ServerI18nUtil.preInit(); // Lophine - I18n support
|
||||||
|
+
|
||||||
|
// Paper start - Detect headless JRE
|
||||||
|
String awtException = io.papermc.paper.util.ServerEnvironment.awtDependencyCheck();
|
||||||
|
if (awtException != null) {
|
||||||
diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java
|
diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java
|
||||||
index c6c6432c2efeb7b95c2894b188cd966321ae3186..1cd9af71ee66df5f277748c0a5a59a30bd57accc 100644
|
index c6c6432c2efeb7b95c2894b188cd966321ae3186..1cd9af71ee66df5f277748c0a5a59a30bd57accc 100644
|
||||||
--- a/net/minecraft/server/dedicated/DedicatedServer.java
|
--- a/net/minecraft/server/dedicated/DedicatedServer.java
|
||||||
|
|||||||
+54
@@ -0,0 +1,54 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
|
||||||
|
Date: Fri, 15 Aug 2025 02:29:30 +0800
|
||||||
|
Subject: [PATCH] Compatibility fix for Raid Revert and Cross Region Damage
|
||||||
|
Trace
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java
|
||||||
|
index 3f4b1c54f9207ba1854a8c8da965cbaca5ea517d..a8348a073682eec31990e9ab963b11ad32cf8bf8 100644
|
||||||
|
--- a/net/minecraft/world/entity/LivingEntity.java
|
||||||
|
+++ b/net/minecraft/world/entity/LivingEntity.java
|
||||||
|
@@ -1216,6 +1216,29 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ // Lophine Start - raid revert adapt Cross Region Damage trace
|
||||||
|
+ public boolean addEffect(MobEffectInstance effectInstance, EntityPotionEffectEvent.Cause cause, boolean fireEvent, boolean async) {
|
||||||
|
+ if (!async || ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(this)) {
|
||||||
|
+ return addEffect(effectInstance, this, cause, fireEvent);
|
||||||
|
+ } else if (fun.bm.lophine.config.modules.experiment.EntityDamageSourceTraceConfig.enabled) {
|
||||||
|
+ postToAddEffect(effectInstance, this, cause, fireEvent);
|
||||||
|
+ return true;
|
||||||
|
+ }
|
||||||
|
+ return false;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private void postToAddEffect(MobEffectInstance effectInstance, @Nullable Entity entity, EntityPotionEffectEvent.Cause cause, boolean fireEvent) {
|
||||||
|
+ if (entity != null)
|
||||||
|
+ entity.getBukkitEntity().taskScheduler.schedule((Entity nmsEntity) -> {
|
||||||
|
+ try {
|
||||||
|
+ addEffect(effectInstance, nmsEntity, cause, fireEvent);
|
||||||
|
+ } catch (Throwable ex) {
|
||||||
|
+ LOGGER.error(ex.getMessage(), ex);
|
||||||
|
+ }
|
||||||
|
+ }, null, 1L );
|
||||||
|
+ }
|
||||||
|
+ // Lophine End - raid revert adapt Cross Region Damage trace
|
||||||
|
+
|
||||||
|
public boolean canBeAffected(MobEffectInstance effectInstance) {
|
||||||
|
if (this.getType().is(EntityTypeTags.IMMUNE_TO_INFESTED)) {
|
||||||
|
return !effectInstance.is(MobEffects.INFESTED);
|
||||||
|
diff --git a/net/minecraft/world/entity/raid/Raider.java b/net/minecraft/world/entity/raid/Raider.java
|
||||||
|
index b1f1bcf7f5ac002550077d5e1d4efd5c67d18063..6120f7b970ff05867524ee9f1433d46843d57483 100644
|
||||||
|
--- a/net/minecraft/world/entity/raid/Raider.java
|
||||||
|
+++ b/net/minecraft/world/entity/raid/Raider.java
|
||||||
|
@@ -158,7 +158,7 @@ public abstract class Raider extends PatrollingMonster {
|
||||||
|
net.minecraft.world.effect.MobEffectInstance mobeffect1 = new net.minecraft.world.effect.MobEffectInstance(net.minecraft.world.effect.MobEffects.BAD_OMEN, 120000, i, false, false, true);
|
||||||
|
|
||||||
|
if (!serverLevel.getGameRules().getBoolean(net.minecraft.world.level.GameRules.RULE_DISABLE_RAIDS)) {
|
||||||
|
- entityhuman.addEffect(mobeffect1, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.PATROL_CAPTAIN); // CraftBukkit
|
||||||
|
+ entityhuman.addEffect(mobeffect1, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.PATROL_CAPTAIN, true, fun.bm.lophine.config.modules.experiment.EntityDamageSourceTraceConfig.enabled); // Lophine - raid revert adapt Cross Region Damage trace
|
||||||
|
}
|
||||||
|
this.setPatrolLeader(false);
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ package fun.bm.lophine.config.modules.misc;
|
|||||||
import me.earthme.luminol.config.EnumConfigCategory;
|
import me.earthme.luminol.config.EnumConfigCategory;
|
||||||
import me.earthme.luminol.config.IConfigModule;
|
import me.earthme.luminol.config.IConfigModule;
|
||||||
import me.earthme.luminol.config.flags.ConfigInfo;
|
import me.earthme.luminol.config.flags.ConfigInfo;
|
||||||
|
import me.earthme.luminol.config.flags.TransformedConfig;
|
||||||
|
|
||||||
public class OldFeatureConfig implements IConfigModule {
|
public class OldFeatureConfig implements IConfigModule {
|
||||||
@ConfigInfo(baseName = "spawn_invulnerable_time")
|
@ConfigInfo(baseName = "spawn_invulnerable_time")
|
||||||
@@ -14,6 +15,10 @@ public class OldFeatureConfig implements IConfigModule {
|
|||||||
@ConfigInfo(baseName = "old_explosion_damage_calculator")
|
@ConfigInfo(baseName = "old_explosion_damage_calculator")
|
||||||
public static boolean oldExplosionDamageCalculator = false;
|
public static boolean oldExplosionDamageCalculator = false;
|
||||||
|
|
||||||
|
@TransformedConfig(name = "give_bad_omen_when_kill_raid_captain", category = {"misc", "revert_raid_changes"}, transformComments = false)
|
||||||
|
@ConfigInfo(baseName = "old_raid_behavior")
|
||||||
|
public static boolean oldRaidBehavior = false;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EnumConfigCategory getCategory() {
|
public EnumConfigCategory getCategory() {
|
||||||
return EnumConfigCategory.MISC;
|
return EnumConfigCategory.MISC;
|
||||||
|
|||||||
-54
@@ -1,54 +0,0 @@
|
|||||||
package fun.bm.lophine.config.modules.misc;
|
|
||||||
|
|
||||||
import me.earthme.luminol.config.EnumConfigCategory;
|
|
||||||
import me.earthme.luminol.config.IConfigModule;
|
|
||||||
import me.earthme.luminol.config.flags.ConfigInfo;
|
|
||||||
|
|
||||||
public class RaidChangesConfig implements IConfigModule {
|
|
||||||
@ConfigInfo(baseName = "allow_skip_cooldown", comments =
|
|
||||||
"""
|
|
||||||
Allow players with bad omen to skip a
|
|
||||||
30-second cooldown and trigger attacks directly""")
|
|
||||||
public static boolean trigger = false;
|
|
||||||
|
|
||||||
@ConfigInfo(baseName = "give_bad_omen_when_kill_raid_captain", comments =
|
|
||||||
"""
|
|
||||||
Enable players to obtain a bad omen
|
|
||||||
effect when killing the raid captain""")
|
|
||||||
public static boolean effect = false;
|
|
||||||
|
|
||||||
@ConfigInfo(baseName = "bad_omen_infinite", comments =
|
|
||||||
"""
|
|
||||||
Enable bad omen effect infinite time
|
|
||||||
--- this config is not old version's function""")
|
|
||||||
public static boolean infinite = false;
|
|
||||||
|
|
||||||
@ConfigInfo(baseName = "skip_height_check", comments =
|
|
||||||
"""
|
|
||||||
Disable y <= 96 check.
|
|
||||||
If you enabled use_old_position_find, this config
|
|
||||||
will useless and always behavior of enabled""")
|
|
||||||
public static boolean heightCheck = false;
|
|
||||||
|
|
||||||
@ConfigInfo(baseName = "skip_self_raid_check", comments =
|
|
||||||
"""
|
|
||||||
Disable raid self check
|
|
||||||
--- this config is not old version's function""")
|
|
||||||
public static boolean selfCheck = false;
|
|
||||||
|
|
||||||
@ConfigInfo(baseName = "use_old_position_find", comments =
|
|
||||||
"""
|
|
||||||
Revert Old raid's find spawn position logic
|
|
||||||
--- This revert MC-274911""")
|
|
||||||
public static boolean posRevert = false;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public EnumConfigCategory getCategory() {
|
|
||||||
return EnumConfigCategory.MISC;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getBaseName() {
|
|
||||||
return "revert_raid_changes";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -12,9 +12,6 @@ public class RedStoneConfig implements IConfigModule {
|
|||||||
Allows you to use the Shears to right-click to rotate the block.""")
|
Allows you to use the Shears to right-click to rotate the block.""")
|
||||||
public static boolean shears = false;
|
public static boolean shears = false;
|
||||||
|
|
||||||
@ConfigInfo(baseName = "vanilla_hopper")
|
|
||||||
public static boolean vanillaHopper = false;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EnumConfigCategory getCategory() {
|
public EnumConfigCategory getCategory() {
|
||||||
return EnumConfigCategory.MISC;
|
return EnumConfigCategory.MISC;
|
||||||
|
|||||||
@@ -6,6 +6,12 @@ import me.earthme.luminol.config.flags.ConfigInfo;
|
|||||||
import me.earthme.luminol.config.flags.TransformedConfig;
|
import me.earthme.luminol.config.flags.TransformedConfig;
|
||||||
|
|
||||||
public class RemovedConfig implements IConfigModule {
|
public class RemovedConfig implements IConfigModule {
|
||||||
|
@TransformedConfig(name = "allow_skip_cooldown", category = {"misc", "revert_raid_changes"}, transform = false)
|
||||||
|
@TransformedConfig(name = "bad_omen_infinite", category = {"misc", "revert_raid_changes"}, transform = false)
|
||||||
|
@TransformedConfig(name = "skip_height_check", category = {"misc", "revert_raid_changes"}, transform = false)
|
||||||
|
@TransformedConfig(name = "skip_self_raid_check", category = {"misc", "revert_raid_changes"}, transform = false)
|
||||||
|
@TransformedConfig(name = "use_old_position_find", category = {"misc", "revert_raid_changes"}, transform = false)
|
||||||
|
@TransformedConfig(name = "vanilla_hopper", category = {"misc", "redstone"}, transform = false)
|
||||||
@TransformedConfig(name = "old_replaceable_by_mushrooms", category = {"misc", "old-feature"}, transform = false)
|
@TransformedConfig(name = "old_replaceable_by_mushrooms", category = {"misc", "old-feature"}, transform = false)
|
||||||
@TransformedConfig(name = "old_nether_portal_collision", category = {"misc", "old-feature"}, transform = false)
|
@TransformedConfig(name = "old_nether_portal_collision", category = {"misc", "old-feature"}, transform = false)
|
||||||
@TransformedConfig(name = "better_shulker_box", category = {"misc", "container_expansion"}, transform = false)
|
@TransformedConfig(name = "better_shulker_box", category = {"misc", "container_expansion"}, transform = false)
|
||||||
|
|||||||
@@ -4,7 +4,10 @@ import com.google.gson.JsonElement;
|
|||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import com.google.gson.JsonParser;
|
import com.google.gson.JsonParser;
|
||||||
import com.google.gson.JsonSyntaxException;
|
import com.google.gson.JsonSyntaxException;
|
||||||
|
import com.mojang.logging.LogUtils;
|
||||||
import fun.bm.lophine.config.modules.optimizations.LanguageConfig;
|
import fun.bm.lophine.config.modules.optimizations.LanguageConfig;
|
||||||
|
import me.earthme.luminol.config.ConfigManager;
|
||||||
|
import me.earthme.luminol.config.ConfigsInstance;
|
||||||
import net.minecraft.DetectedVersion;
|
import net.minecraft.DetectedVersion;
|
||||||
import net.minecraft.locale.DeprecatedTranslationsInfo;
|
import net.minecraft.locale.DeprecatedTranslationsInfo;
|
||||||
import net.minecraft.locale.Language;
|
import net.minecraft.locale.Language;
|
||||||
@@ -12,8 +15,8 @@ import net.minecraft.network.chat.FormattedText;
|
|||||||
import net.minecraft.network.chat.Style;
|
import net.minecraft.network.chat.Style;
|
||||||
import net.minecraft.util.FormattedCharSequence;
|
import net.minecraft.util.FormattedCharSequence;
|
||||||
import net.minecraft.util.StringDecomposer;
|
import net.minecraft.util.StringDecomposer;
|
||||||
import org.apache.commons.io.FileUtils;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
@@ -23,13 +26,13 @@ import java.net.http.HttpClient;
|
|||||||
import java.net.http.HttpRequest;
|
import java.net.http.HttpRequest;
|
||||||
import java.net.http.HttpResponse;
|
import java.net.http.HttpResponse;
|
||||||
import java.nio.file.*;
|
import java.nio.file.*;
|
||||||
|
import java.time.Duration;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* authored by: Helvetica Volubi <suisuroru@blue-millennium.fun>
|
* authored by: Helvetica Volubi <suisuroru@blue-millennium.fun>
|
||||||
@@ -37,30 +40,62 @@ import java.util.logging.Logger;
|
|||||||
* Some of diff form Leaves
|
* Some of diff form Leaves
|
||||||
*/
|
*/
|
||||||
public class ServerI18nUtil {
|
public class ServerI18nUtil {
|
||||||
|
private static final Logger logger = LogUtils.getClassLogger();
|
||||||
private static final Logger logger = Logger.getLogger("LangLoader");
|
|
||||||
private static final String VERSION = DetectedVersion.BUILT_IN.name();
|
private static final String VERSION = DetectedVersion.BUILT_IN.name();
|
||||||
private static final String BASE_PATH = "cache/lophine/" + VERSION + "/";
|
private static final String BASE_PATH = "cache/lophine/" + VERSION + "/";
|
||||||
|
private static final String defaultLophineLangPath = "/assets/lophine/lang/en_us.json";
|
||||||
private static final String manifestUrl = "https://launchermeta.mojang.com/mc/game/version_manifest.json";
|
private static final String manifestUrl = "https://launchermeta.mojang.com/mc/game/version_manifest.json";
|
||||||
private static final String resourceBaseUrl = "https://resources.download.minecraft.net/";
|
private static final String resourceBaseUrl = "https://resources.download.minecraft.net/";
|
||||||
|
// pre-load
|
||||||
|
private static CompletableFuture<Void> preloadTask;
|
||||||
|
// paths
|
||||||
private static String langPath;
|
private static String langPath;
|
||||||
private static String assetsPath;
|
private static String assetsPath;
|
||||||
private static String versionPath;
|
private static String versionPath;
|
||||||
private static String manifestPath;
|
private static String manifestPath;
|
||||||
private static String langJsonPath;
|
private static String langJsonPath;
|
||||||
|
private static String lophineLangPath;
|
||||||
|
|
||||||
public static void init() {
|
public static void init() {
|
||||||
if (Objects.equals(LanguageConfig.lang, "en_us")) {
|
if (Objects.equals(LanguageConfig.lang, "en_us")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
langPath = BASE_PATH + "lang/" + LanguageConfig.lang + ".json";
|
langPath = BASE_PATH + "lang/" + LanguageConfig.lang + ".json";
|
||||||
|
langJsonPath = "minecraft/lang/" + LanguageConfig.lang + ".json";
|
||||||
|
lophineLangPath = "/assets/Lophine/lang/" + LanguageConfig.lang + ".json";
|
||||||
|
logger.info("Starting load language: {}", LanguageConfig.lang);
|
||||||
|
preloadTask.thenAcceptAsync(v -> loadI18n(LanguageConfig.lang, 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void preInit() {
|
||||||
assetsPath = BASE_PATH + "assets.json";
|
assetsPath = BASE_PATH + "assets.json";
|
||||||
versionPath = BASE_PATH + VERSION + ".json";
|
versionPath = BASE_PATH + VERSION + ".json";
|
||||||
manifestPath = BASE_PATH + "manifest.json";
|
manifestPath = BASE_PATH + "manifest.json";
|
||||||
langJsonPath = "minecraft/lang/" + LanguageConfig.lang + ".json";
|
preloadTask = CompletableFuture.runAsync(() -> preLoadI18n(2));
|
||||||
logger.info("Starting load language: " + LanguageConfig.lang);
|
}
|
||||||
CompletableFuture.runAsync(() -> loadI18n(LanguageConfig.lang, 2));
|
|
||||||
|
private static void preLoadI18n(int retryTime) {
|
||||||
|
try {
|
||||||
|
if (!Files.exists(Path.of(assetsPath))) {
|
||||||
|
downloadAssets(true);
|
||||||
|
}
|
||||||
|
} catch (UnsupportedLanguageException e) {
|
||||||
|
logger.warn("Unsupported language: {}", LanguageConfig.lang);
|
||||||
|
// Fallback to English
|
||||||
|
final ConfigsInstance configsInstance = ConfigManager.configfiles.get("lophine");
|
||||||
|
configsInstance.setConfig(new String[]{"optimizations", "lang"}, "en_us");
|
||||||
|
configsInstance.reloadAsync();
|
||||||
|
} catch (Exception e) {
|
||||||
|
if (e instanceof MalformedJsonException malformedJson) {
|
||||||
|
malformedJson.clean();
|
||||||
|
}
|
||||||
|
logger.warn("Failed to download language list file: ", e);
|
||||||
|
if (retryTime > 0) {
|
||||||
|
preLoadI18n(retryTime - 1);
|
||||||
|
} else {
|
||||||
|
logger.error("Failed to download language list file for many times, skip pre-load language.");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void loadI18n(String lang, int retryTime) {
|
private static void loadI18n(String lang, int retryTime) {
|
||||||
@@ -69,15 +104,16 @@ public class ServerI18nUtil {
|
|||||||
downloadLang(true);
|
downloadLang(true);
|
||||||
}
|
}
|
||||||
Language.inject(createLangInstance());
|
Language.inject(createLangInstance());
|
||||||
logger.info("Successfully loaded language: " + lang);
|
logger.info("Successfully loaded language: {}", lang);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.warning("Failed to load language file for " + lang + "\n" + e);
|
if (e instanceof MalformedJsonException malformedJson) {
|
||||||
|
malformedJson.clean();
|
||||||
|
}
|
||||||
|
logger.warn("Failed to load language file for {}", lang, e);
|
||||||
if (retryTime > 0) {
|
if (retryTime > 0) {
|
||||||
cleanCache();
|
|
||||||
loadI18n(lang, retryTime - 1);
|
loadI18n(lang, retryTime - 1);
|
||||||
} else {
|
} else {
|
||||||
logger.severe("Failed to load for many times, use default lang \"en_us\" instead");
|
logger.error("Failed to load for many times, use default lang \"en_us\" instead");
|
||||||
cleanCache();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -94,6 +130,10 @@ public class ServerI18nUtil {
|
|||||||
|
|
||||||
JsonObject langEntry = json.getAsJsonObject("objects").getAsJsonObject(langJsonPath);
|
JsonObject langEntry = json.getAsJsonObject("objects").getAsJsonObject(langJsonPath);
|
||||||
|
|
||||||
|
if (langEntry == null) {
|
||||||
|
throw new UnsupportedLanguageException();
|
||||||
|
}
|
||||||
|
|
||||||
String hash = langEntry.get("hash").getAsString();
|
String hash = langEntry.get("hash").getAsString();
|
||||||
if (hash == null || hash.length() < 2) {
|
if (hash == null || hash.length() < 2) {
|
||||||
throw new IllegalArgumentException("Invalid hash value");
|
throw new IllegalArgumentException("Invalid hash value");
|
||||||
@@ -145,37 +185,31 @@ public class ServerI18nUtil {
|
|||||||
fetchAndSave(versionUrl, versionPath);
|
fetchAndSave(versionUrl, versionPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String createHttpResponse(String path) throws IOException, InterruptedException {
|
private static byte[] fetch(String urlString) throws IOException, InterruptedException {
|
||||||
try {
|
try {
|
||||||
HttpResponse<String> response;
|
HttpResponse<String> response;
|
||||||
try (HttpClient httpClient = HttpClient.newHttpClient()) {
|
try (HttpClient httpClient = HttpClient.newHttpClient()) {
|
||||||
|
|
||||||
HttpRequest request = HttpRequest.newBuilder()
|
HttpRequest request = HttpRequest.newBuilder()
|
||||||
.uri(URI.create(path))
|
.uri(URI.create(urlString))
|
||||||
|
.timeout(Duration.ofSeconds(10))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
|
response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
|
||||||
}
|
}
|
||||||
|
|
||||||
int responseCode = response.statusCode();
|
int responseCode = response.statusCode();
|
||||||
if (responseCode != 200) {
|
if (responseCode != 200) {
|
||||||
logger.info("Unexpected response code: " + responseCode);
|
logger.info("Unexpected response code: {}", responseCode);
|
||||||
logger.info("Response body: " + response.body());
|
logger.info("Response body: {}", response.body());
|
||||||
throw new UnsupportedEncodingException("Unexpected response code");
|
throw new UnsupportedEncodingException("Unexpected response code");
|
||||||
} else {
|
} else {
|
||||||
return response.body();
|
return response.body().getBytes();
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.warning("Error in getting info: " + e.getMessage());
|
logger.warn("Error in getting info!");
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte[] fetch(String urlString) throws IOException, InterruptedException {
|
|
||||||
String ret = createHttpResponse(urlString);
|
|
||||||
return ret.getBytes();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void fetchAndSave(String url, String savePath) throws IOException, InterruptedException {
|
private static void fetchAndSave(String url, String savePath) throws IOException, InterruptedException {
|
||||||
byte[] data = fetch(url);
|
byte[] data = fetch(url);
|
||||||
Path outputPath = Path.of(savePath);
|
Path outputPath = Path.of(savePath);
|
||||||
@@ -183,23 +217,15 @@ public class ServerI18nUtil {
|
|||||||
Files.write(outputPath, data, StandardOpenOption.CREATE, StandardOpenOption.WRITE);
|
Files.write(outputPath, data, StandardOpenOption.CREATE, StandardOpenOption.WRITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void cleanCache() {
|
|
||||||
try {
|
|
||||||
FileUtils.deleteDirectory(Path.of(BASE_PATH).toFile());
|
|
||||||
} catch (IOException e) {
|
|
||||||
logger.severe("Cache cleanup failed: " + e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static JsonObject loadJson(String path) {
|
private static JsonObject loadJson(String path) {
|
||||||
try {
|
try {
|
||||||
byte[] data = Files.readAllBytes(Paths.get(path));
|
byte[] data = Files.readAllBytes(Paths.get(path));
|
||||||
return JsonParser.parseString(new String(data)).getAsJsonObject();
|
return JsonParser.parseString(new String(data)).getAsJsonObject();
|
||||||
} catch (JsonSyntaxException e) {
|
} catch (JsonSyntaxException e) {
|
||||||
logger.warning("Corrupt json file: " + e);
|
logger.warn("Corrupt json file!");
|
||||||
throw e;
|
throw new MalformedJsonException(e, path);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.warning("Failed to load local JSON: " + e);
|
logger.warn("Failed to load local JSON!");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -208,6 +234,7 @@ public class ServerI18nUtil {
|
|||||||
DeprecatedTranslationsInfo deprecatedTranslationsInfo = DeprecatedTranslationsInfo.loadFromDefaultResource();
|
DeprecatedTranslationsInfo deprecatedTranslationsInfo = DeprecatedTranslationsInfo.loadFromDefaultResource();
|
||||||
Map<String, String> map = new HashMap<>();
|
Map<String, String> map = new HashMap<>();
|
||||||
parseTranslations(map::put);
|
parseTranslations(map::put);
|
||||||
|
loadLophineI18n(map::put);
|
||||||
deprecatedTranslationsInfo.applyToMap(map);
|
deprecatedTranslationsInfo.applyToMap(map);
|
||||||
final Map<String, String> map1 = Map.copyOf(map);
|
final Map<String, String> map1 = Map.copyOf(map);
|
||||||
return new Language() {
|
return new Language() {
|
||||||
@@ -237,16 +264,52 @@ public class ServerI18nUtil {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void loadLophineI18n(BiConsumer<String, String> bi) {
|
||||||
|
if (Language.class.getResource(lophineLangPath) != null) {
|
||||||
|
Language.parseTranslations(bi, lophineLangPath);
|
||||||
|
} else {
|
||||||
|
loadLophineI18nDefault(bi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void loadLophineI18nDefault(BiConsumer<String, String> bi) {
|
||||||
|
if (Language.class.getResource(defaultLophineLangPath) != null) {
|
||||||
|
Language.parseTranslations(bi, defaultLophineLangPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static void parseTranslations(BiConsumer<String, String> output) throws IOException {
|
private static void parseTranslations(BiConsumer<String, String> output) throws IOException {
|
||||||
Path filePath = Path.of(langPath);
|
Path filePath = Path.of(langPath);
|
||||||
try (InputStream fileStream = Files.newInputStream(filePath)) {
|
try (InputStream fileStream = Files.newInputStream(filePath)) {
|
||||||
Language.loadFromJson(fileStream, output);
|
Language.loadFromJson(fileStream, output);
|
||||||
} catch (NoSuchFileException noSuchFileException) {
|
} catch (NoSuchFileException e) {
|
||||||
logger.warning("Couldn't find language file: " + langPath);
|
logger.warn("Couldn't find language file: {}", langPath);
|
||||||
throw noSuchFileException;
|
throw e;
|
||||||
|
} catch (JsonSyntaxException e) {
|
||||||
|
throw new MalformedJsonException(e, langPath);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.warning("Failed to load language from filesystem " + filePath + "\n" + e);
|
logger.warn("Failed to load language from filesystem {}", filePath);
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class UnsupportedLanguageException extends Exception {
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class MalformedJsonException extends RuntimeException {
|
||||||
|
private final Path path;
|
||||||
|
|
||||||
|
protected MalformedJsonException(Throwable root, String path) {
|
||||||
|
super(root);
|
||||||
|
this.path = Path.of(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clean() {
|
||||||
|
try {
|
||||||
|
Files.delete(path);
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.info("Failed to delete malformed JSON file: {}", path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,141 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Leaves (https://github.com/LeavesMC/Leaves)
|
||||||
|
*
|
||||||
|
* Leaves is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Leaves is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with Leaves. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.leavesmc.leaves.util;
|
||||||
|
|
||||||
|
import fun.bm.lophine.config.modules.misc.RedStoneConfig;
|
||||||
|
import net.minecraft.Util;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.world.InteractionHand;
|
||||||
|
import net.minecraft.world.InteractionResult;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.item.Items;
|
||||||
|
import net.minecraft.world.item.context.BlockPlaceContext;
|
||||||
|
import net.minecraft.world.item.context.UseOnContext;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.level.block.*;
|
||||||
|
import net.minecraft.world.level.block.piston.PistonBaseBlock;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.block.state.StateDefinition;
|
||||||
|
import net.minecraft.world.level.block.state.properties.Property;
|
||||||
|
import net.minecraft.world.level.block.state.properties.RailShape;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class ShearsWrenchUtil {
|
||||||
|
|
||||||
|
public static InteractionResult tryApplyRotate(UseOnContext context, BlockState blockState) {
|
||||||
|
Level level = context.getLevel();
|
||||||
|
BlockPos clickedPos = context.getClickedPos();
|
||||||
|
Block block = blockState.getBlock();
|
||||||
|
if (!RedStoneConfig.shears || !(block instanceof ObserverBlock || block instanceof DispenserBlock || block instanceof PistonBaseBlock || block instanceof HopperBlock || block instanceof RepeaterBlock || block instanceof ComparatorBlock || block instanceof CrafterBlock || block instanceof LeverBlock || block instanceof CocoaBlock || block instanceof TrapDoorBlock || block instanceof FenceGateBlock || block instanceof LightningRodBlock || block instanceof CalibratedSculkSensorBlock || block instanceof BaseRailBlock)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
StateDefinition<Block, BlockState> blockstatelist = block.getStateDefinition();
|
||||||
|
Property<?> iblockstate;
|
||||||
|
if (block instanceof CrafterBlock) {
|
||||||
|
iblockstate = blockstatelist.getProperty("orientation");
|
||||||
|
} else if (block instanceof BaseRailBlock) {
|
||||||
|
iblockstate = blockstatelist.getProperty("shape");
|
||||||
|
} else {
|
||||||
|
iblockstate = blockstatelist.getProperty("facing");
|
||||||
|
}
|
||||||
|
Player player = context.getPlayer();
|
||||||
|
|
||||||
|
if (iblockstate == null || player == null) {
|
||||||
|
return InteractionResult.FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (block instanceof BaseRailBlock) {
|
||||||
|
if (block instanceof RailBlock) {
|
||||||
|
if (blockState.getValue(RailBlock.SHAPE).isSlope()) {
|
||||||
|
return InteractionResult.FAIL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (getNameHelper(blockState, PoweredRailBlock.POWERED).equals("true")) {
|
||||||
|
return InteractionResult.FAIL;
|
||||||
|
}
|
||||||
|
if (blockState.getValue(PoweredRailBlock.SHAPE).isSlope()) {
|
||||||
|
return InteractionResult.FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (block instanceof PistonBaseBlock) {
|
||||||
|
if (getNameHelper(blockState, PistonBaseBlock.EXTENDED).equals("true")) {
|
||||||
|
return InteractionResult.FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (block instanceof RepeaterBlock || block instanceof ComparatorBlock) {
|
||||||
|
if (getNameHelper(blockState, ComparatorBlock.POWERED).equals("true")) {
|
||||||
|
return InteractionResult.FAIL;
|
||||||
|
}
|
||||||
|
if (block instanceof RepeaterBlock) {
|
||||||
|
if (getNameHelper(blockState, RepeaterBlock.LOCKED).equals("true")) {
|
||||||
|
return InteractionResult.FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (block instanceof CrafterBlock) {
|
||||||
|
if (getNameHelper(blockState, CrafterBlock.CRAFTING).equals("true")) {
|
||||||
|
return InteractionResult.FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockState iblockdata1 = cycleState(blockState, iblockstate, player.isSecondaryUseActive());
|
||||||
|
level.setBlock(clickedPos, iblockdata1, 18);
|
||||||
|
message(player, Component.translatable("item.minecraft.debug_stick.update", iblockstate.getName(), getNameHelper(iblockdata1, iblockstate)));
|
||||||
|
return InteractionResult.CONSUME;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean shouldSkipPlace(BlockPlaceContext context) {
|
||||||
|
return RedStoneConfig.shears &&
|
||||||
|
context.getPlayer() != null &&
|
||||||
|
context.getPlayer().getItemInHand(InteractionHand.MAIN_HAND).is(Items.SHEARS);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T extends Comparable<T>> BlockState cycleState(BlockState state, Property<T> property, boolean inverse) {
|
||||||
|
List<T> possibleValues = property.getPossibleValues();
|
||||||
|
if (possibleValues.getFirst() instanceof RailShape) {
|
||||||
|
boolean isRailBlock = state.getBlock() instanceof RailBlock;
|
||||||
|
possibleValues = possibleValues.stream().filter(possibleValue -> {
|
||||||
|
RailShape shape = (RailShape) possibleValue;
|
||||||
|
if (isRailBlock) {
|
||||||
|
return !shape.isSlope();
|
||||||
|
}
|
||||||
|
return !shape.isSlope() && shape != RailShape.NORTH_EAST && shape != RailShape.NORTH_WEST && shape != RailShape.SOUTH_EAST && shape != RailShape.SOUTH_WEST;
|
||||||
|
}).toList();
|
||||||
|
}
|
||||||
|
return state.setValue(property, getRelative(possibleValues, state.getValue(property), inverse)); // CraftBukkit - decompile error
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T> T getRelative(Iterable<T> elements, T current, boolean inverse) {
|
||||||
|
return inverse ? Util.findPreviousInIterable(elements, current) : Util.findNextInIterable(elements, current);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void message(Player player, Component message) {
|
||||||
|
((ServerPlayer) player).sendSystemMessage(message, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T extends Comparable<T>> String getNameHelper(BlockState state, Property<T> property) {
|
||||||
|
return property.getName(state.getValue(property));
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user