diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000..50c1f090 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,38 @@ +--- +name: Bug report +about: Create a report to help us improve +title: "[BUG]" +labels: bug +assignees: Sollace + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Steps to reproduce** +Help us figure out what you did to get this issue + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Version Information:** + - Minecraft Version: [e.g. 1.20.5] + - Mine Little Pony Version: + +**Mod Loader:** + - [ ] Fabric + - [ ] Quilt + - [ ] Neoforge (with connector) + +**Client/Server Logs** +If applicable, add log files by uploading them as attachments or put them below. + +
+``` +**Paste logs here** +``` +
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 00000000..7b2634da --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,26 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: enhancement +assignees: Sollace + +--- + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Additional context** +Add any other context or screenshots about the feature request here. + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Version Information:** + - Minecraft Version: [e.g. 1.20.5] + - Mine Little Pony Version: + +**Mod Loader:** + - [ ] Fabric + - [ ] Quilt + - [ ] Neoforge (with connector) diff --git a/build.gradle b/build.gradle index cd55edfe..c49f6fde 100644 --- a/build.gradle +++ b/build.gradle @@ -77,9 +77,14 @@ dependencies { include "com.sollace:Romanizer:Romanizer:1.0.2" modCompileOnly "com.terraformersmc:modmenu:${project.modmenu_version}" - modCompileOnly "dev.emi:trinkets:${project.trinkets_version}" + + if (project.use_trinkets == '1') { + modCompileOnly "dev.emi:trinkets:${project.trinkets_version}" modCompileOnly "dev.onyxstudios.cardinal-components-api:cardinal-components-base:5.3.0" modCompileOnly "dev.onyxstudios.cardinal-components-api:cardinal-components-entity:5.3.0" + } else { + modCompileOnly "dev.emi:trinkets-dummy:${project.trinkets_version}" + } modImplementation "com.terraformersmc.terraform-api:terraform-wood-api-v1:${project.terraformer_api_version}" include "com.terraformersmc.terraform-api:terraform-wood-api-v1:${project.terraformer_api_version}" @@ -98,7 +103,12 @@ dependencies { if (project.use_sodium == '1') { modCompileOnly "maven.modrinth:indium:${project.indium_version}", { exclude group: "net.fabricmc.fabric-api" } modCompileOnly "maven.modrinth:sodium:${project.sodium_version}", { exclude group: "net.fabricmc.fabric-api" } - // modCompileOnly "maven.modrinth:iris:${project.iris_version}", { exclude group: "net.fabricmc.fabric-api" } + if (project.use_iris == '1') { + modCompileOnly "maven.modrinth:iris:${project.iris_version}", { exclude group: "net.fabricmc.fabric-api" } + modImplementation "org.anarres:jcpp:1.4.14" + modImplementation "org.antlr:antlr4-runtime:4.13.1" + modImplementation "io.github.douira:glsl-transformer:2.0.1" + } } if (project.tmi_type == 'emi') { diff --git a/gradle.properties b/gradle.properties index 3ca5c348..040b73ac 100644 --- a/gradle.properties +++ b/gradle.properties @@ -30,8 +30,10 @@ org.gradle.daemon=false nodium_version=1.1.0+1.20 # Testing + use_trinkets=1 use_pehkui=0 use_sodium=0 + use_iris=1 farmers_delight_version=1.20.1-2.0.9 pehkui_version=3.7.8+1.14.4-1.20.2 diff --git a/lib/trinkets-dummy-3.8.0.jar b/lib/trinkets-dummy-3.8.0.jar new file mode 100644 index 00000000..1e65318d Binary files /dev/null and b/lib/trinkets-dummy-3.8.0.jar differ diff --git a/src/main/java/com/minelittlepony/unicopia/EquineContext.java b/src/main/java/com/minelittlepony/unicopia/EquineContext.java index 596c2cbb..824940de 100644 --- a/src/main/java/com/minelittlepony/unicopia/EquineContext.java +++ b/src/main/java/com/minelittlepony/unicopia/EquineContext.java @@ -22,7 +22,7 @@ public interface EquineContext { } default boolean collidesWithClouds() { - return getCompositeRace().canInteractWithClouds(); + return getCompositeRace().canInteractWithClouds() || getCloudWalkingStrength() >= 1; } default boolean hasFeatherTouch() { diff --git a/src/main/java/com/minelittlepony/unicopia/InteractionManager.java b/src/main/java/com/minelittlepony/unicopia/InteractionManager.java index 5326ce75..b3fb38b8 100644 --- a/src/main/java/com/minelittlepony/unicopia/InteractionManager.java +++ b/src/main/java/com/minelittlepony/unicopia/InteractionManager.java @@ -2,6 +2,7 @@ package com.minelittlepony.unicopia; import java.util.Map; import java.util.Optional; +import java.util.Stack; import java.util.UUID; import org.jetbrains.annotations.NotNull; @@ -37,7 +38,7 @@ public class InteractionManager { @Nullable private SyncedConfig config; - private EquineContext equineContext = EquineContext.ABSENT; + private final Stack equineContext = new Stack<>(); public static InteractionManager getInstance() { return INSTANCE; @@ -109,11 +110,21 @@ public class InteractionManager { } public void setEquineContext(EquineContext context) { - equineContext = context; + equineContext.push(context); + } + + public void clearEquineContext() { + if (!equineContext.isEmpty()) { + equineContext.pop(); + } } public EquineContext getEquineContext() { - return getClientPony().map(EquineContext.class::cast).orElse(equineContext); + return getClientPony().map(EquineContext.class::cast).orElseGet(this::getPathingEquineContext); + } + + public EquineContext getPathingEquineContext() { + return equineContext.isEmpty() ? EquineContext.ABSENT : equineContext.peek(); } public Optional getClientPony() { diff --git a/src/main/java/com/minelittlepony/unicopia/Race.java b/src/main/java/com/minelittlepony/unicopia/Race.java index 84994481..8607c091 100644 --- a/src/main/java/com/minelittlepony/unicopia/Race.java +++ b/src/main/java/com/minelittlepony/unicopia/Race.java @@ -70,7 +70,7 @@ public record Race ( * This is used if there are no other races. */ public static final Race UNSET = register("unset", new Builder().availability(Availability.COMMANDS)); - public static final Race HUMAN = register("human", new Builder().availability(Availability.COMMANDS)); + public static final Race HUMAN = register("human", new Builder()); public static final Race EARTH = register("earth", new Builder().foraging().earth() .abilities(Abilities.HUG, Abilities.STOMP, Abilities.KICK, Abilities.GROW) ); diff --git a/src/main/java/com/minelittlepony/unicopia/UConventionalTags.java b/src/main/java/com/minelittlepony/unicopia/UConventionalTags.java index 6b54e607..31b02f7f 100644 --- a/src/main/java/com/minelittlepony/unicopia/UConventionalTags.java +++ b/src/main/java/com/minelittlepony/unicopia/UConventionalTags.java @@ -46,6 +46,7 @@ public interface UConventionalTags { TagKey FRUITS = item("fruits"); TagKey WORMS = item("worms"); TagKey ROCKS = item("rocks"); + TagKey GEMS = item("gems"); TagKey RAW_INSECT = item("raw_insect"); TagKey COOKED_INSECT = item("cooked_insect"); diff --git a/src/main/java/com/minelittlepony/unicopia/Unicopia.java b/src/main/java/com/minelittlepony/unicopia/Unicopia.java index 8142560d..a6057f85 100644 --- a/src/main/java/com/minelittlepony/unicopia/Unicopia.java +++ b/src/main/java/com/minelittlepony/unicopia/Unicopia.java @@ -31,6 +31,7 @@ import com.minelittlepony.unicopia.item.enchantment.UEnchantments; import com.minelittlepony.unicopia.network.Channel; import com.minelittlepony.unicopia.particle.UParticles; import com.minelittlepony.unicopia.server.world.BlockDestructionManager; +import com.minelittlepony.unicopia.server.world.Ether; import com.minelittlepony.unicopia.server.world.NocturnalSleepManager; import com.minelittlepony.unicopia.server.world.UGameRules; import com.minelittlepony.unicopia.server.world.UWorldGen; @@ -71,6 +72,7 @@ public class Unicopia implements ModInitializer { ((BlockDestructionManager.Source)w).getDestructionManager().tick(); ZapAppleStageStore.get(w).tick(); WeatherConditions.get(w).tick(); + Ether.get(w).tick(); if (Debug.SPELLBOOK_CHAPTERS) { SpellbookChapterLoader.INSTANCE.sendUpdate(w.getServer()); } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/BatPonyHangAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/BatPonyHangAbility.java index 723cc0f5..95566b44 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/BatPonyHangAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/BatPonyHangAbility.java @@ -37,7 +37,7 @@ public class BatPonyHangAbility implements Ability { } return TraceHelper.findBlock(player.asEntity(), 5, 1) - .map(BlockPos::down) + .map(pos -> pos.down(player.getPhysics().getGravitySignum())) .filter(player.getAcrobatics()::canHangAt) .map(pos -> new Multi(pos, 1)); } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyGrowAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyGrowAbility.java index bb9b49e4..af04192f 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyGrowAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyGrowAbility.java @@ -14,6 +14,7 @@ import com.minelittlepony.unicopia.particle.ParticleUtils; import com.minelittlepony.unicopia.recipe.TransformCropsRecipe; import com.minelittlepony.unicopia.recipe.URecipes; import com.minelittlepony.unicopia.server.world.BlockDestructionManager; +import com.minelittlepony.unicopia.server.world.ModificationType; import com.minelittlepony.unicopia.util.TraceHelper; import com.minelittlepony.unicopia.util.VecHelper; @@ -70,7 +71,9 @@ public class EarthPonyGrowAbility implements Ability { for (BlockPos pos : BlockPos.iterate( data.pos().add(-2, -2, -2), data.pos().add( 2, 2, 2))) { - count += applySingle(player, player.asWorld(), player.asWorld().getBlockState(pos), pos); + if (player.canModifyAt(pos, ModificationType.PHYSICAL)) { + count += applySingle(player, player.asWorld(), player.asWorld().getBlockState(pos), pos); + } } } else { count = 1; diff --git a/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyKickAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyKickAbility.java index ca76579f..f8e4e861 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyKickAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyKickAbility.java @@ -17,6 +17,7 @@ import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.particle.ParticleUtils; import com.minelittlepony.unicopia.particle.UParticles; import com.minelittlepony.unicopia.server.world.BlockDestructionManager; +import com.minelittlepony.unicopia.server.world.ModificationType; import com.minelittlepony.unicopia.util.*; import net.minecraft.block.BeehiveBlock; @@ -98,7 +99,7 @@ public class EarthPonyKickAbility implements Ability { } BlockPos pos = kickLocation.pos(); - EarthPonyStompAbility.stompBlock(w, pos, 10 * (1 + player.getLevel().getScaled(5)) * w.getBlockState(pos).calcBlockBreakingDelta(player.asEntity(), w, pos)); + EarthPonyStompAbility.stompBlock(player, w, pos, 10 * (1 + player.getLevel().getScaled(5)) * w.getBlockState(pos).calcBlockBreakingDelta(player.asEntity(), w, pos)); player.setAnimation(Animation.KICK, Animation.Recipient.ANYONE); }); } @@ -165,10 +166,16 @@ public class EarthPonyKickAbility implements Ability { if (BlockDestructionManager.of(player.getWorld()).getBlockDestruction(pos) + 4 >= BlockDestructionManager.MAX_DAMAGE) { if (player.getWorld().random.nextInt(30) == 0) { - tree.logs().forEach(player.getWorld(), (w, state, p) -> w.breakBlock(p, true)); + tree.logs().forEach(player.getWorld(), (w, state, p) -> { + if (iplayer.canModifyAt(p, ModificationType.PHYSICAL)) { + w.breakBlock(p, true); + } + }); tree.leaves().forEach(player.getWorld(), (w, state, p) -> { - Block.dropStacks(w.getBlockState(p), w, p); - w.setBlockState(p, Blocks.AIR.getDefaultState(), Block.NOTIFY_ALL); + if (iplayer.canModifyAt(p, ModificationType.PHYSICAL)) { + Block.dropStacks(w.getBlockState(p), w, p); + w.setBlockState(p, Blocks.AIR.getDefaultState(), Block.NOTIFY_ALL); + } }); } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyStompAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyStompAbility.java index de4c8be8..e1761d25 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyStompAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyStompAbility.java @@ -19,6 +19,7 @@ import com.minelittlepony.unicopia.item.enchantment.UEnchantments; import com.minelittlepony.unicopia.particle.ParticleUtils; import com.minelittlepony.unicopia.particle.UParticles; import com.minelittlepony.unicopia.server.world.BlockDestructionManager; +import com.minelittlepony.unicopia.server.world.ModificationType; import com.minelittlepony.unicopia.util.PosHelper; import com.minelittlepony.unicopia.util.VecHelper; @@ -166,7 +167,7 @@ public class EarthPonyStompAbility implements Ability { double radius = rad + heavyness * 0.3; - spawnEffectAround(player, center, radius, rad); + spawnEffectAround(iplayer, player, center, radius, rad); ParticleUtils.spawnParticle(player.getWorld(), UParticles.GROUND_POUND, player.getX(), player.getY() - 1, player.getZ(), 0, 0, 0); BlockState steppingState = player.getSteppingBlockState(); @@ -198,17 +199,17 @@ public class EarthPonyStompAbility implements Ability { return true; } - public static void spawnEffectAround(Entity source, BlockPos center, double radius, double range) { + public static void spawnEffectAround(Pony pony, Entity source, BlockPos center, double radius, double range) { BlockPos.stream(new BlockBox(center).expand(MathHelper.ceil(radius))).forEach(i -> { double dist = Math.sqrt(i.getSquaredDistance(source.getX(), source.getY(), source.getZ())); if (dist <= radius) { - spawnEffect(source.getWorld(), i, dist, range); + spawnEffect(pony, source.getWorld(), i, dist, range); } }); } - public static void spawnEffect(World w, BlockPos pos, double dist, double rad) { + public static void spawnEffect(Pony pony, World w, BlockPos pos, double dist, double rad) { if (w.getBlockState(pos.up()).isAir()) { BlockState state = w.getBlockState(pos); @@ -216,18 +217,18 @@ public class EarthPonyStompAbility implements Ability { float scaledHardness = (1 - hardness / 70); float damage = hardness < 0 ? 0 : MathHelper.clamp((int)((1 - dist / rad) * 9 * scaledHardness), 0, BlockDestructionManager.MAX_DAMAGE - 1); - stompBlock(w, pos, damage); + stompBlock(pony, w, pos, damage); } } - public static void stompBlock(World w, BlockPos pos, float damage) { + public static void stompBlock(Pony pony, World w, BlockPos pos, float damage) { BlockState state = w.getBlockState(pos); if (state.isAir() || damage <= 0) { return; } - if (BlockDestructionManager.of(w).damageBlock(pos, damage) >= BlockDestructionManager.MAX_DAMAGE) { + if (BlockDestructionManager.of(w).damageBlock(pos, damage) >= BlockDestructionManager.MAX_DAMAGE && pony.canModifyAt(pos, ModificationType.PHYSICAL)) { w.breakBlock(pos, true); if (w instanceof ServerWorld) { diff --git a/src/main/java/com/minelittlepony/unicopia/ability/ScreechAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/ScreechAbility.java index 53c8b702..100905b9 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/ScreechAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/ScreechAbility.java @@ -8,6 +8,7 @@ import com.minelittlepony.unicopia.UTags; import com.minelittlepony.unicopia.ability.data.Numeric; import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; import com.minelittlepony.unicopia.advancement.UCriteria; +import com.minelittlepony.unicopia.client.minelittlepony.MineLPDelegate; import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation; import com.minelittlepony.unicopia.entity.Living; import com.minelittlepony.unicopia.entity.damage.UDamageTypes; @@ -126,8 +127,10 @@ public class ScreechAbility implements Ability { @Override public void coolDown(Pony player, AbilitySlot slot) { + Vec3d eyePos = player.asEntity().getPos().add(0, MineLPDelegate.getInstance().getPonyHeight(player.asEntity()) * 0.8, 0); + for (int i = 0; i < 20; i++) { - player.addParticle(ParticleTypes.BUBBLE_POP, player.asEntity().getEyePos(), + player.addParticle(ParticleTypes.BUBBLE_POP, eyePos, VecHelper.supply(() -> (player.asWorld().getRandom().nextGaussian() - 0.5) * 0.3) ); } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/ToggleFlightAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/ToggleFlightAbility.java index d1a45aa2..a3c3e6fa 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/ToggleFlightAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/ToggleFlightAbility.java @@ -11,6 +11,7 @@ import com.minelittlepony.unicopia.entity.Living; import com.minelittlepony.unicopia.entity.player.Pony; import net.minecraft.util.Identifier; +import net.minecraft.util.math.Vec3d; public class ToggleFlightAbility implements Ability { @@ -27,7 +28,7 @@ public class ToggleFlightAbility implements Ability { @Nullable @Override public Optional prepare(Pony player) { - return Hit.of(!player.asEntity().hasVehicle() && !player.asEntity().isCreative() && !player.getPhysics().getFlightType().isGrounded()); + return Hit.of(!player.asEntity().isCreative() && !player.getPhysics().getFlightType().isGrounded()); } @Override @@ -59,6 +60,11 @@ public class ToggleFlightAbility implements Ability { player.subtractEnergyCost(1); if (!player.getPhysics().isFlying()) { + if (player.asEntity().hasVehicle()) { + Vec3d pos = player.asEntity().getPos(); + player.asEntity().stopRiding(); + player.asEntity().setPosition(pos.getX(), pos.getY() + 0.25, pos.getZ()); + } player.asEntity().addVelocity(0, player.getPhysics().getGravitySignum() * 0.7F, 0); Living.updateVelocity(player.asEntity()); player.getPhysics().startFlying(true); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/MultiSpellSlot.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/MultiSpellSlot.java index e38184b7..50cb5902 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/MultiSpellSlot.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/MultiSpellSlot.java @@ -116,6 +116,9 @@ class MultiSpellSlot implements SpellSlots, NbtSerialisable { if (s != null) { s.setDead(); s.tickDying(owner); + if (s.isDead()) { + s.destroy(owner); + } } } } @@ -128,7 +131,7 @@ class MultiSpellSlot implements SpellSlots, NbtSerialisable { return hasValue ? Status.NEW : Status.REMOVED; } - return spell.hasDirtySpell() ? Status.UPDATED : Status.DEFAULT; + return Status.DEFAULT; } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractAreaEffectSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractAreaEffectSpell.java index 1425a6ae..464b517a 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractAreaEffectSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractAreaEffectSpell.java @@ -8,8 +8,10 @@ import com.minelittlepony.unicopia.ability.magic.spell.attribute.TooltipFactory; import com.minelittlepony.unicopia.ability.magic.spell.effect.*; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; +import net.minecraft.util.math.MathHelper; + public abstract class AbstractAreaEffectSpell extends AbstractSpell { - protected static final SpellAttribute RANGE = SpellAttribute.create(SpellAttributeType.RANGE, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.POWER, power -> Math.max(0, 4 + power)); + protected static final SpellAttribute RANGE = SpellAttribute.create(SpellAttributeType.RANGE, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.POWER, power -> MathHelper.clamp(4 + power, 0, 32)); public static final TooltipFactory TOOLTIP = RANGE; protected AbstractAreaEffectSpell(CustomisedSpellType type) { diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractDelegatingSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractDelegatingSpell.java index 78373b5a..9ff86367 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractDelegatingSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractDelegatingSpell.java @@ -80,18 +80,6 @@ public abstract class AbstractDelegatingSpell implements Spell { return getOrEmpty().isDying(); } - @Deprecated - @Override - public boolean isDirty() { - return delegate.hasDirtySpell(); - } - - @Deprecated - @Override - public void setDirty() { - getOrEmpty().setDirty(); - } - @Override public boolean isHidden() { return getOrEmpty().isHidden(); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractDisguiseSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractDisguiseSpell.java index 41e7c996..b4e6ad08 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractDisguiseSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractDisguiseSpell.java @@ -20,7 +20,7 @@ import net.minecraft.nbt.NbtCompound; */ public abstract class AbstractDisguiseSpell extends AbstractSpell implements Disguise, ProjectileImpactListener { - private final EntityAppearance disguise = new EntityAppearance(); + private final EntityAppearance disguise = dataTracker.startTracking(new EntityAppearance()); public AbstractDisguiseSpell(CustomisedSpellType type) { super(type); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/DispersableDisguiseSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/DispersableDisguiseSpell.java index 7f614bc6..2b7f7cb8 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/DispersableDisguiseSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/DispersableDisguiseSpell.java @@ -26,11 +26,18 @@ public class DispersableDisguiseSpell extends AbstractDisguiseSpell implements I private final DataTracker.Entry suppressed = dataTracker.startTracking(TrackableDataType.BOOLEAN, false); private int suppressionCounter; + private boolean forced; + public DispersableDisguiseSpell(CustomisedSpellType type) { super(type); setHidden(true); } + public void setForced() { + forced = true; + setHidden(false); + } + @Override public boolean isVulnerable(Caster otherSource, Spell other) { return suppressionCounter <= otherSource.getLevel().get(); @@ -59,7 +66,7 @@ public class DispersableDisguiseSpell extends AbstractDisguiseSpell implements I } } - if (!source.canUse(Abilities.DISGUISE)) { + if (!forced && !source.canUse(Abilities.DISGUISE)) { setDead(); } @@ -91,12 +98,14 @@ public class DispersableDisguiseSpell extends AbstractDisguiseSpell implements I public void toNBT(NbtCompound compound) { super.toNBT(compound); compound.putInt("suppressionCounter", suppressionCounter); + compound.putBoolean("forced", forced); } @Override public void fromNBT(NbtCompound compound) { super.fromNBT(compound); suppressionCounter = compound.getInt("suppressionCounter"); + forced = compound.getBoolean("forced"); if (suppressionCounter > 0) { suppressed.set(true); } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/EmptySpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/EmptySpell.java index 89b3f986..f4dca074 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/EmptySpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/EmptySpell.java @@ -44,11 +44,6 @@ public final class EmptySpell implements Spell { return false; } - @Override - public boolean isDirty() { - return false; - } - @Override public boolean tick(Caster caster, Situation situation) { return false; @@ -57,9 +52,6 @@ public final class EmptySpell implements Spell { @Override public void tickDying(Caster caster) { } - @Override - public void setDirty() { } - @Override public boolean isHidden() { return true; diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlacementControlSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlacementControlSpell.java index 9eee830f..e3f31a03 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlacementControlSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlacementControlSpell.java @@ -9,6 +9,8 @@ import com.minelittlepony.unicopia.ability.magic.spell.effect.AbstractSpell; import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType; import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; import com.minelittlepony.unicopia.entity.mob.CastSpellEntity; +import com.minelittlepony.unicopia.network.track.DataTracker; +import com.minelittlepony.unicopia.network.track.TrackableDataType; import com.minelittlepony.unicopia.server.world.Ether; import com.minelittlepony.unicopia.util.NbtSerialisable; @@ -21,12 +23,10 @@ import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; public class PlacementControlSpell extends AbstractSpell implements OrientedSpell { - @Nullable - private UUID placedEntityId; - - private Optional> dimension = Optional.empty(); - private Optional position = Optional.empty(); - private Optional orientation = Optional.empty(); + private final DataTracker.Entry placedEntityId = dataTracker.startTracking(TrackableDataType.UUID, null); + private final DataTracker.Entry>> dimension = dataTracker.startTracking(TrackableDataType.ofRegistryKey(), Optional.empty()); + private final DataTracker.Entry> position = dataTracker.startTracking(TrackableDataType.OPTIONAL_VECTOR, Optional.empty()); + private final DataTracker.Entry> orientation = dataTracker.startTracking(TrackableDataType.OPTIONAL_VECTOR, Optional.empty()); @Nullable private Spell delegate; @@ -46,26 +46,23 @@ public class PlacementControlSpell extends AbstractSpell implements OrientedSpel } public Optional getPosition() { - return position; + return position.get(); } public void setDimension(RegistryKey dimension) { - this.dimension = Optional.of(dimension); - setDirty(); + this.dimension.set(Optional.of(dimension)); } public void setPosition(Vec3d position) { - this.position = Optional.of(position); - setDirty(); + this.position.set(Optional.of(position)); } @Override public void setOrientation(Caster caster, float pitch, float yaw) { - this.orientation = Optional.of(new Vec3d(pitch, yaw, 0)); + this.orientation.set(Optional.of(new Vec3d(pitch, yaw, 0))); if (delegate instanceof OrientedSpell o) { o.setOrientation(caster, pitch, yaw); } - setDirty(); if (!caster.isClient()) { var entry = getConnection(caster); if (entry != null) { @@ -77,62 +74,60 @@ public class PlacementControlSpell extends AbstractSpell implements OrientedSpel @Override public boolean apply(Caster caster) { - if (delegate == null) { - return false; - } - boolean result = super.apply(caster); - if (result) { - if (dimension.isEmpty()) { - setDimension(caster.asWorld().getRegistryKey()); - } - if (position.isEmpty()) { - setPosition(caster.asEntity().getPos()); - } - if (delegate instanceof PlacementDelegate) { - ((PlacementDelegate)delegate).onPlaced(caster, this); - } - - CastSpellEntity entity = new CastSpellEntity(caster.asWorld(), caster, this); - - Vec3d pos = position.get(); - Vec3d rot = orientation.orElse(Vec3d.ZERO); - - entity.updatePositionAndAngles(pos.x, pos.y, pos.z, (float)rot.y, (float)rot.x); - entity.getWorld().spawnEntity(entity); - - placedEntityId = entity.getUuid(); - } - return result; + return delegate != null && super.apply(caster); } @Override public boolean tick(Caster source, Situation situation) { - if (!source.isClient() && getConnection(source) == null) { - setDead(); + if (!source.isClient()) { + + if (placedEntityId.get() == null) { + if (dimension.get().isEmpty()) { + setDimension(source.asWorld().getRegistryKey()); + } + if (getPosition().isEmpty()) { + setPosition(source.asEntity().getPos()); + } + + CastSpellEntity entity = new CastSpellEntity(source.asWorld(), source, this); + + Vec3d pos = getPosition().get(); + Vec3d rot = orientation.get().orElse(Vec3d.ZERO); + + entity.updatePositionAndAngles(pos.x, pos.y, pos.z, (float)rot.y, (float)rot.x); + entity.getWorld().spawnEntity(entity); + + placedEntityId.set(entity.getUuid()); + } else { + if (getConnection(source) == null) { + setDead(); + } + } } + return !isDead(); } @Nullable private Ether.Entry getConnection(Caster source) { - return delegate == null || placedEntityId == null ? null : getWorld(source) - .map(world -> Ether.get(world).get(getDelegate().getTypeAndTraits().type(), placedEntityId, delegate.getUuid())) + return delegate == null || placedEntityId.get() == null ? null : getWorld(source) + .map(world -> Ether.get(world).get(getDelegate().getTypeAndTraits().type(), placedEntityId.get(), delegate.getUuid())) .orElse(null); } private Optional getWorld(Caster source) { - return dimension.map(source.asWorld().getServer()::getWorld); + return dimension.get().map(source.asWorld().getServer()::getWorld); } @Override public void toNBT(NbtCompound compound) { super.toNBT(compound); compound.put("spell", Spell.writeNbt(delegate)); - position.ifPresent(pos -> compound.put("position", NbtSerialisable.writeVector(pos))); - orientation.ifPresent(o -> compound.put("orientation", NbtSerialisable.writeVector(o))); - dimension.ifPresent(d -> compound.putString("dimension", d.getValue().toString())); - if (placedEntityId != null) { - compound.putUuid("placedEntityId", placedEntityId); + position.get().ifPresent(pos -> compound.put("position", NbtSerialisable.writeVector(pos))); + orientation.get().ifPresent(o -> compound.put("orientation", NbtSerialisable.writeVector(o))); + dimension.get().ifPresent(d -> compound.putString("dimension", d.getValue().toString())); + if (placedEntityId.get() != null) { + compound.putUuid("placedEntityId", placedEntityId.get()); } } @@ -140,12 +135,10 @@ public class PlacementControlSpell extends AbstractSpell implements OrientedSpel public void fromNBT(NbtCompound compound) { super.fromNBT(compound); delegate = Spell.readNbt(compound.getCompound("spell")); - placedEntityId = compound.containsUuid("placedEntityId") ? compound.getUuid("placedEntityId") : null; - position = compound.contains("position") ? Optional.of(NbtSerialisable.readVector(compound.getList("position", NbtElement.DOUBLE_TYPE))) : Optional.empty(); - orientation = compound.contains("orientation") ? Optional.of(NbtSerialisable.readVector(compound.getList("orientation", NbtElement.DOUBLE_TYPE))) : Optional.empty(); - if (compound.contains("dimension", NbtElement.STRING_TYPE)) { - dimension = Optional.ofNullable(Identifier.tryParse(compound.getString("dimension"))).map(id -> RegistryKey.of(RegistryKeys.WORLD, id)); - } + placedEntityId.set(compound.containsUuid("placedEntityId") ? compound.getUuid("placedEntityId") : null); + position.set(compound.contains("position") ? Optional.of(NbtSerialisable.readVector(compound.getList("position", NbtElement.DOUBLE_TYPE))) : Optional.empty()); + orientation.set(compound.contains("orientation") ? Optional.of(NbtSerialisable.readVector(compound.getList("orientation", NbtElement.DOUBLE_TYPE))) : Optional.empty()); + dimension.set(compound.contains("dimension", NbtElement.STRING_TYPE) ? Optional.ofNullable(Identifier.tryParse(compound.getString("dimension"))).map(id -> RegistryKey.of(RegistryKeys.WORLD, id)) : Optional.empty()); } public interface PlacementDelegate { diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/Spell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/Spell.java index aab10703..6add4b0f 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/Spell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/Spell.java @@ -74,18 +74,6 @@ public interface Spell extends NbtSerialisable, Affine { boolean isDying(); - /** - * Returns true if this effect has changes that need to be sent to the client. - */ - @Deprecated - boolean isDirty(); - - /** - * Marks this effect as dirty. - */ - @Deprecated - void setDirty(); - /** * Applies this spell to the supplied caster. * @param caster The caster to apply the spell to diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/SpellReference.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/SpellReference.java index 4bab564c..66cd3acc 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/SpellReference.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/SpellReference.java @@ -25,11 +25,6 @@ public final class SpellReference implements NbtSerialisable { set(spell, null); } - @Deprecated - public boolean hasDirtySpell() { - return spell != null && spell.isDirty(); - } - public boolean set(T spell, @Nullable Caster owner) { spell = spell == null || spell.isDead() ? null : spell; if (spell == this.spell) { diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AbstractSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AbstractSpell.java index 6d08d6a9..16839123 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AbstractSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AbstractSpell.java @@ -20,7 +20,6 @@ public abstract class AbstractSpell implements Spell { private final DataTracker.Entry dead = dataTracker.startTracking(TrackableDataType.BOOLEAN, false); private final DataTracker.Entry dying = dataTracker.startTracking(TrackableDataType.BOOLEAN, false); - private boolean dirty; private final DataTracker.Entry hidden = dataTracker.startTracking(TrackableDataType.BOOLEAN, false); private boolean destroyed; @@ -66,18 +65,6 @@ public abstract class AbstractSpell implements Spell { return dying.get(); } - @Deprecated - @Override - public final boolean isDirty() { - return dirty; - } - - @Deprecated - @Override - public final void setDirty() { - dirty = true; - } - @Override public final boolean isHidden() { return hidden.get(); @@ -120,7 +107,6 @@ public abstract class AbstractSpell implements Spell { @Override public void fromNBT(NbtCompound compound) { - dirty = false; if (compound.containsUuid("uuid")) { uuid = compound.getUuid("uuid"); } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AttractiveSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AttractiveSpell.java index 7bf39425..08b6e1a2 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AttractiveSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AttractiveSpell.java @@ -28,14 +28,12 @@ public class AttractiveSpell extends ShieldSpell implements HomingSpell, TimedSp static final TooltipFactory TARGET = (type, tooltip) -> (TARGET_FOCUSED_ENTITY.get(type.traits()) ? TARGET_FOCUSED_ENTITY : ShieldSpell.TARGET).appendTooltip(type, tooltip); static final TooltipFactory TOOLTIP = TooltipFactory.of(TIME, RANGE, TARGET, STICK_TO_TARGET, CAST_ON); - private final EntityReference target = new EntityReference<>(); + private final EntityReference target = dataTracker.startTracking(new EntityReference<>()); - private final Timer timer; + private final Timer timer = new Timer(TIME.get(getTraits())); protected AttractiveSpell(CustomisedSpellType type) { super(type); - timer = new Timer(TIME.get(getTraits())); - dataTracker.startTracking(target); } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AwkwardSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AwkwardSpell.java index dab51b1b..7a9402c5 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AwkwardSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AwkwardSpell.java @@ -19,11 +19,10 @@ import net.minecraft.registry.Registries; public class AwkwardSpell extends AbstractSpell implements TimedSpell { - private final Timer timer; + private final Timer timer = new Timer(20); protected AwkwardSpell(CustomisedSpellType type) { super(type); - timer = new Timer(20); } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/BubbleSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/BubbleSpell.java index df1e9c92..dfd6d601 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/BubbleSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/BubbleSpell.java @@ -56,17 +56,14 @@ public class BubbleSpell extends AbstractSpell implements TimedSpell, static final TooltipFactory TOOLTIP = TooltipFactory.of(TimedSpell.TIME, SOAPINESS); - private final Timer timer; + private final Timer timer = new Timer(TIME.get(getTraits())); private float prevRadius; - private DataTracker.Entry radius; - private DataTracker.Entry struggles; + private DataTracker.Entry radius = dataTracker.startTracking(TrackableDataType.FLOAT, 0F); + private DataTracker.Entry struggles = dataTracker.startTracking(TrackableDataType.INT, SOAPINESS.get(getTraits())); protected BubbleSpell(CustomisedSpellType type) { super(type); - timer = new Timer(TIME.get(getTraits())); - radius = dataTracker.startTracking(TrackableDataType.FLOAT, 0F); - struggles = dataTracker.startTracking(TrackableDataType.INT, SOAPINESS.get(getTraits())); } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DisplacementSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DisplacementSpell.java index 1afef18f..d9659de6 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DisplacementSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DisplacementSpell.java @@ -18,13 +18,13 @@ import net.minecraft.nbt.NbtCompound; import net.minecraft.util.hit.EntityHitResult; import net.minecraft.util.math.Vec3d; -public class DisplacementSpell extends AbstractSpell implements HomingSpell, ProjectileDelegate.EntityHitListener { +public class DisplacementSpell extends AbstractSpell implements HomingSpell, ProjectileDelegate.HitListener { private static final SpellAttribute DAMAGE_TO_TARGET = SpellAttribute.create(SpellAttributeType.DAMAGE_TO_TARGET, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.BLOOD, blood -> blood); static final TooltipFactory TOOLTIP = DAMAGE_TO_TARGET; - private final EntityReference target = new EntityReference<>(); + private final EntityReference target = dataTracker.startTracking(new EntityReference<>()); private int ticks = 10; @@ -34,7 +34,7 @@ public class DisplacementSpell extends AbstractSpell implements HomingSpell, Pro @Override public Spell prepareForCast(Caster caster, CastingMethod method) { - return toPlaceable(); + return method.isIndirectCause() ? this : toPlaceable(); } @Override @@ -43,14 +43,23 @@ public class DisplacementSpell extends AbstractSpell implements HomingSpell, Pro originator.asEntity().setGlowing(true); + if (situation == Situation.PROJECTILE) { + return !isDead(); + } + ticks--; if (originator.isClient()) { return !isDead() || ticks >= -10; } - if (ticks == 0) { - target.ifPresent(originator.asWorld(), target -> apply(originator, target)); + if (!originator.isClient()) { + target.ifPresent(originator.asWorld(), target -> { + target.setGlowing(true); + if (ticks == 0) { + apply(originator, target); + } + }); } return ticks >= -10; @@ -58,7 +67,18 @@ public class DisplacementSpell extends AbstractSpell implements HomingSpell, Pro @Override public void onImpact(MagicProjectileEntity projectile, EntityHitResult hit) { - Caster.of(projectile.getMaster()).ifPresent(originator -> apply(originator, hit.getEntity())); + HitListener.super.onImpact(projectile, hit); + Caster.of(projectile.getMaster()).ifPresent(originator -> { + apply(originator, hit.getEntity()); + }); + } + + @Override + public void onImpact(MagicProjectileEntity projectile) { + if (projectile.getMaster() != null) { + projectile.getMaster().setGlowing(false); + } + target.ifPresent(projectile.asWorld(), e -> e.setGlowing(false)); } private void apply(Caster originator, Entity target) { @@ -107,11 +127,13 @@ public class DisplacementSpell extends AbstractSpell implements HomingSpell, Pro public void toNBT(NbtCompound compound) { super.toNBT(compound); compound.putInt("ticks", ticks); + compound.put("target", target.toNBT()); } @Override public void fromNBT(NbtCompound compound) { super.fromNBT(compound); ticks = compound.getInt("ticks"); + target.fromNBT(compound.getCompound("target")); } } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/FeatherFallSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/FeatherFallSpell.java index e90558d0..8f7ffabf 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/FeatherFallSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/FeatherFallSpell.java @@ -59,11 +59,10 @@ public class FeatherFallSpell extends AbstractSpell implements TimedSpell { .with(Trait.ORDER, 15) .build(); - private final Timer timer; + private final Timer timer = new Timer(DURATION.get(getTraits())); protected FeatherFallSpell(CustomisedSpellType type) { super(type); - timer = new Timer(DURATION.get(getTraits())); } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/FireBoltSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/FireBoltSpell.java index 9075457a..04cf61fd 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/FireBoltSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/FireBoltSpell.java @@ -47,7 +47,7 @@ public class FireBoltSpell extends AbstractSpell implements HomingSpell, static final TooltipFactory TOOLTIP = TooltipFactory.of(EXPLOSION_STRENGTH, VELOCITY, PROJECTILE_COUNT, FOLLOWS_TARGET, FOLLOW_RANGE.conditionally(FOLLOWS_TARGET::get)); - private final EntityReference target = new EntityReference<>(); + private final EntityReference target = dataTracker.startTracking(new EntityReference<>()); protected FireBoltSpell(CustomisedSpellType type) { super(type); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/LightSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/LightSpell.java index 2c14e4f8..d1bf985f 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/LightSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/LightSpell.java @@ -38,13 +38,12 @@ public class LightSpell extends AbstractSpell implements TimedSpell, ProjectileD static final TooltipFactory TOOLTIP = TooltipFactory.of(TIME, ORB_COUNT); - private final Timer timer; + private final Timer timer = new Timer(TIME.get(getTraits())); private final List> lights = new ArrayList<>(); protected LightSpell(CustomisedSpellType type) { super(type); - timer = new Timer(TIME.get(getTraits())); } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/MimicSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/MimicSpell.java index 57b984c1..1108bd43 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/MimicSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/MimicSpell.java @@ -11,11 +11,10 @@ public class MimicSpell extends AbstractDisguiseSpell implements HomingSpell, Ti static final TooltipFactory TOOLTIP = TimedSpell.TIME; - private final Timer timer; + private final Timer timer = new Timer(TIME.get(getTraits())); protected MimicSpell(CustomisedSpellType type) { super(type); - timer = new Timer(TIME.get(getTraits())); } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/PortalSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/PortalSpell.java index 4277ff0c..bb007fe5 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/PortalSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/PortalSpell.java @@ -46,7 +46,7 @@ public class PortalSpell extends AbstractSpell implements PlacementControlSpell. private final DataTracker.Entry targetPortalId = dataTracker.startTracking(TrackableDataType.UUID, Util.NIL_UUID); private final DataTracker.Entry targetPortalPitch = dataTracker.startTracking(TrackableDataType.FLOAT, 0F); private final DataTracker.Entry targetPortalYaw = dataTracker.startTracking(TrackableDataType.FLOAT, 0F); - private final EntityReference teleportationTarget = new EntityReference<>(); + private final EntityReference teleportationTarget = dataTracker.startTracking(new EntityReference<>()); private final DataTracker.Entry pitch = dataTracker.startTracking(TrackableDataType.FLOAT, 0F); private final DataTracker.Entry yaw = dataTracker.startTracking(TrackableDataType.FLOAT, 0F); diff --git a/src/main/java/com/minelittlepony/unicopia/block/EdibleBlock.java b/src/main/java/com/minelittlepony/unicopia/block/EdibleBlock.java index e6bf0482..707853b1 100644 --- a/src/main/java/com/minelittlepony/unicopia/block/EdibleBlock.java +++ b/src/main/java/com/minelittlepony/unicopia/block/EdibleBlock.java @@ -205,7 +205,7 @@ public class EdibleBlock extends HayBlock { if (world.random.nextInt(10) == 0) { player.playSound(USounds.Vanilla.ENTITY_PLAYER_BURP, 1, player.getSoundPitch()); } - player.getHungerManager().add(4, 2.3F); + player.getHungerManager().add(2, 1.3F); } return ActionResult.SUCCESS; } diff --git a/src/main/java/com/minelittlepony/unicopia/block/cloud/CloudBedBlock.java b/src/main/java/com/minelittlepony/unicopia/block/cloud/CloudBedBlock.java index e6eb8ddf..e4d562c3 100644 --- a/src/main/java/com/minelittlepony/unicopia/block/cloud/CloudBedBlock.java +++ b/src/main/java/com/minelittlepony/unicopia/block/cloud/CloudBedBlock.java @@ -24,7 +24,7 @@ public class CloudBedBlock extends FancyBedBlock implements CloudLike { private final CloudBlock baseBlock; public CloudBedBlock(String base, BlockState baseState, Settings settings) { - super(base, settings.dynamicBounds()); + super(base, CloudLike.applyCloudProperties(settings)); this.baseState = baseState; this.baseBlock = (CloudBlock)baseState.getBlock(); } @@ -75,6 +75,6 @@ public class CloudBedBlock extends FancyBedBlock implements CloudLike { @Override @Deprecated public boolean canPathfindThrough(BlockState state, BlockView world, BlockPos pos, NavigationType type) { - return true; + return baseState.canPathfindThrough(world, pos, type); } } diff --git a/src/main/java/com/minelittlepony/unicopia/block/cloud/CloudBlock.java b/src/main/java/com/minelittlepony/unicopia/block/cloud/CloudBlock.java index fd526300..6381eda2 100644 --- a/src/main/java/com/minelittlepony/unicopia/block/cloud/CloudBlock.java +++ b/src/main/java/com/minelittlepony/unicopia/block/cloud/CloudBlock.java @@ -3,6 +3,7 @@ package com.minelittlepony.unicopia.block.cloud; import org.jetbrains.annotations.Nullable; import com.minelittlepony.unicopia.EquineContext; +import com.minelittlepony.unicopia.InteractionManager; import com.minelittlepony.unicopia.entity.player.Pony; import net.minecraft.block.Block; @@ -30,10 +31,21 @@ public class CloudBlock extends Block implements CloudLike { protected final boolean meltable; public CloudBlock(Settings settings, boolean meltable) { - super((meltable ? settings.ticksRandomly() : settings).nonOpaque().dynamicBounds()); + super(CloudLike.applyCloudProperties(meltable ? settings.ticksRandomly() : settings)); this.meltable = meltable; } + @Override + @Deprecated + public float getAmbientOcclusionLightLevel(BlockState state, BlockView world, BlockPos pos) { + return 0.9F; + } + + @Override + public boolean isTransparent(BlockState state, BlockView world, BlockPos pos) { + return true; + } + @Override public void onEntityLand(BlockView world, Entity entity) { boolean bounce = Math.abs(entity.getVelocity().y) > 0.3; @@ -105,10 +117,9 @@ public class CloudBlock extends Block implements CloudLike { entity.addVelocity(0, 0.07, 0); entity.setOnGround(true); } - entity.setVelocity(entity.getVelocity().multiply(0.9F, 1, 0.9F)); - } else { - entity.setVelocity(entity.getVelocity().multiply(0.9F)); } + + entity.setVelocity(entity.getVelocity().multiply(0.9F, 1, 0.9F)); } @Override @@ -163,7 +174,8 @@ public class CloudBlock extends Block implements CloudLike { @Override @Deprecated public boolean canPathfindThrough(BlockState state, BlockView world, BlockPos pos, NavigationType type) { - return true; + System.out.println(InteractionManager.getInstance().getPathingEquineContext().collidesWithClouds()); + return type != NavigationType.LAND || !InteractionManager.getInstance().getPathingEquineContext().collidesWithClouds(); } protected VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context, EquineContext equineContext) { diff --git a/src/main/java/com/minelittlepony/unicopia/block/cloud/CloudChestBlock.java b/src/main/java/com/minelittlepony/unicopia/block/cloud/CloudChestBlock.java index f4f5ba0b..7d53232c 100644 --- a/src/main/java/com/minelittlepony/unicopia/block/cloud/CloudChestBlock.java +++ b/src/main/java/com/minelittlepony/unicopia/block/cloud/CloudChestBlock.java @@ -5,6 +5,7 @@ import java.util.Optional; import org.jetbrains.annotations.Nullable; import com.minelittlepony.unicopia.EquineContext; +import com.minelittlepony.unicopia.InteractionManager; import com.minelittlepony.unicopia.block.UBlockEntities; import net.minecraft.block.BlockState; import net.minecraft.block.ChestBlock; @@ -77,7 +78,7 @@ public class CloudChestBlock extends ChestBlock implements CloudLike { }; public CloudChestBlock(Settings settings, BlockState baseState) { - super(settings.dynamicBounds(), () -> UBlockEntities.CLOUD_CHEST); + super(CloudLike.applyCloudProperties(settings), () -> UBlockEntities.CLOUD_CHEST); this.baseState = baseState; this.baseBlock = (CloudBlock)baseState.getBlock(); } @@ -139,7 +140,7 @@ public class CloudChestBlock extends ChestBlock implements CloudLike { @Override @Deprecated public boolean canPathfindThrough(BlockState state, BlockView world, BlockPos pos, NavigationType type) { - return true; + return type != NavigationType.LAND || !InteractionManager.getInstance().getPathingEquineContext().collidesWithClouds(); } public static class TileData extends ChestBlockEntity { diff --git a/src/main/java/com/minelittlepony/unicopia/block/cloud/CloudDoorBlock.java b/src/main/java/com/minelittlepony/unicopia/block/cloud/CloudDoorBlock.java index e0b495d1..b243a67f 100644 --- a/src/main/java/com/minelittlepony/unicopia/block/cloud/CloudDoorBlock.java +++ b/src/main/java/com/minelittlepony/unicopia/block/cloud/CloudDoorBlock.java @@ -3,6 +3,7 @@ package com.minelittlepony.unicopia.block.cloud; import org.jetbrains.annotations.Nullable; import com.minelittlepony.unicopia.EquineContext; +import com.minelittlepony.unicopia.InteractionManager; import com.minelittlepony.unicopia.Race; import net.minecraft.block.BlockSetType; @@ -10,6 +11,7 @@ import net.minecraft.block.BlockState; import net.minecraft.block.DoorBlock; import net.minecraft.block.ShapeContext; import net.minecraft.entity.Entity; +import net.minecraft.entity.ai.pathing.NavigationType; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemPlacementContext; import net.minecraft.util.ActionResult; @@ -26,7 +28,7 @@ public class CloudDoorBlock extends DoorBlock implements CloudLike { private final CloudBlock baseBlock; public CloudDoorBlock(Settings settings, BlockState baseState, BlockSetType blockSet) { - super(settings.dynamicBounds(), blockSet); + super(CloudLike.applyCloudProperties(settings), blockSet); this.baseState = baseState; this.baseBlock = (CloudBlock)baseState.getBlock(); } @@ -84,4 +86,10 @@ public class CloudDoorBlock extends DoorBlock implements CloudLike { entity.setVelocity(entity.getVelocity().multiply(0.5F, 1, 0.5F)); } } + + @Override + @Deprecated + public boolean canPathfindThrough(BlockState state, BlockView world, BlockPos pos, NavigationType type) { + return !InteractionManager.getInstance().getPathingEquineContext().collidesWithClouds() || super.canPathfindThrough(state, world, pos, type); + } } diff --git a/src/main/java/com/minelittlepony/unicopia/block/cloud/CloudLike.java b/src/main/java/com/minelittlepony/unicopia/block/cloud/CloudLike.java index ec9ef4fd..3684c890 100644 --- a/src/main/java/com/minelittlepony/unicopia/block/cloud/CloudLike.java +++ b/src/main/java/com/minelittlepony/unicopia/block/cloud/CloudLike.java @@ -1,5 +1,13 @@ package com.minelittlepony.unicopia.block.cloud; -public interface CloudLike { +import net.minecraft.block.Block; +import net.minecraft.entity.EntityType; +import net.minecraft.entity.SpawnGroup; +public interface CloudLike { + static Block.Settings applyCloudProperties(Block.Settings settings) { + return settings.nonOpaque().dynamicBounds().allowsSpawning((state, world, pos, type) -> { + return type == EntityType.PHANTOM || type == EntityType.PARROT || type.getSpawnGroup() == SpawnGroup.AMBIENT; + }); + } } diff --git a/src/main/java/com/minelittlepony/unicopia/block/cloud/CloudStairsBlock.java b/src/main/java/com/minelittlepony/unicopia/block/cloud/CloudStairsBlock.java index a2b1e4ba..dcff5ff1 100644 --- a/src/main/java/com/minelittlepony/unicopia/block/cloud/CloudStairsBlock.java +++ b/src/main/java/com/minelittlepony/unicopia/block/cloud/CloudStairsBlock.java @@ -21,10 +21,21 @@ public class CloudStairsBlock extends StairsBlock implements CloudLike { private final CloudBlock baseBlock; public CloudStairsBlock(BlockState baseState, Settings settings) { - super(baseState, settings.dynamicBounds()); + super(baseState, CloudLike.applyCloudProperties(settings)); this.baseBlock = (CloudBlock)baseState.getBlock(); } + @Override + @Deprecated + public float getAmbientOcclusionLightLevel(BlockState state, BlockView world, BlockPos pos) { + return baseBlock.getAmbientOcclusionLightLevel(state, world, pos); + } + + @Override + public boolean isTransparent(BlockState state, BlockView world, BlockPos pos) { + return baseBlock.isTransparent(state, world, pos); + } + @Override public void onEntityLand(BlockView world, Entity entity) { baseBlock.onEntityLand(world, entity); @@ -86,6 +97,6 @@ public class CloudStairsBlock extends StairsBlock implements CloudLike { @Override @Deprecated public boolean canPathfindThrough(BlockState state, BlockView world, BlockPos pos, NavigationType type) { - return true; + return baseBlock.canPathfindThrough(state, world, pos, type); } } diff --git a/src/main/java/com/minelittlepony/unicopia/block/cloud/NaturalCloudBlock.java b/src/main/java/com/minelittlepony/unicopia/block/cloud/NaturalCloudBlock.java index 2d7325dc..e950ba4b 100644 --- a/src/main/java/com/minelittlepony/unicopia/block/cloud/NaturalCloudBlock.java +++ b/src/main/java/com/minelittlepony/unicopia/block/cloud/NaturalCloudBlock.java @@ -25,10 +25,11 @@ public class NaturalCloudBlock extends PoreousCloudBlock { public NaturalCloudBlock(Settings settings, boolean meltable, @Nullable Supplier soggyBlock, Supplier compactedBlock) { - super(settings.nonOpaque(), meltable, soggyBlock); + super(settings, meltable, soggyBlock); this.compactedBlock = compactedBlock; } + @Deprecated @Override public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) { ItemStack stack = player.getStackInHand(hand); @@ -41,6 +42,6 @@ public class NaturalCloudBlock extends PoreousCloudBlock { return ActionResult.SUCCESS; } - return ActionResult.PASS; + return super.onUse(state, world, pos, player, hand, hit); } } diff --git a/src/main/java/com/minelittlepony/unicopia/block/cloud/PoreousCloudBlock.java b/src/main/java/com/minelittlepony/unicopia/block/cloud/PoreousCloudBlock.java index 15303184..171b8a9e 100644 --- a/src/main/java/com/minelittlepony/unicopia/block/cloud/PoreousCloudBlock.java +++ b/src/main/java/com/minelittlepony/unicopia/block/cloud/PoreousCloudBlock.java @@ -7,9 +7,14 @@ import org.jetbrains.annotations.Nullable; import com.minelittlepony.unicopia.block.state.StateUtil; import net.minecraft.block.BlockState; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Hand; +import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.random.Random; +import net.minecraft.world.World; public class PoreousCloudBlock extends CloudBlock implements Soakable { @Nullable @@ -20,6 +25,12 @@ public class PoreousCloudBlock extends CloudBlock implements Soakable { this.soggyBlock = soggyBlock; } + @Deprecated + @Override + public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) { + return Soakable.tryDepositMoisture(state, world, pos, player, hand, hit); + } + @Nullable @Override public BlockState getStateWithMoisture(BlockState state, int moisture) { diff --git a/src/main/java/com/minelittlepony/unicopia/block/cloud/PoreousCloudStairsBlock.java b/src/main/java/com/minelittlepony/unicopia/block/cloud/PoreousCloudStairsBlock.java index 3ee498a1..2a8e4f81 100644 --- a/src/main/java/com/minelittlepony/unicopia/block/cloud/PoreousCloudStairsBlock.java +++ b/src/main/java/com/minelittlepony/unicopia/block/cloud/PoreousCloudStairsBlock.java @@ -7,6 +7,12 @@ import org.jetbrains.annotations.Nullable; import com.minelittlepony.unicopia.block.state.StateUtil; import net.minecraft.block.BlockState; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Hand; +import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; public class PoreousCloudStairsBlock extends CloudStairsBlock implements Soakable { @@ -17,6 +23,12 @@ public class PoreousCloudStairsBlock extends CloudStairsBlock implements Soakabl this.soggyBlock = soggyBlock; } + @Deprecated + @Override + public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) { + return Soakable.tryDepositMoisture(state, world, pos, player, hand, hit); + } + @Nullable @Override public BlockState getStateWithMoisture(BlockState state, int moisture) { diff --git a/src/main/java/com/minelittlepony/unicopia/block/cloud/Soakable.java b/src/main/java/com/minelittlepony/unicopia/block/cloud/Soakable.java index 94ce19e8..44d6a95e 100644 --- a/src/main/java/com/minelittlepony/unicopia/block/cloud/Soakable.java +++ b/src/main/java/com/minelittlepony/unicopia/block/cloud/Soakable.java @@ -9,8 +9,11 @@ import com.minelittlepony.unicopia.USounds; import net.minecraft.block.BlockState; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; +import net.minecraft.item.ItemUsage; import net.minecraft.item.Items; import net.minecraft.particle.ParticleTypes; +import net.minecraft.potion.PotionUtil; +import net.minecraft.potion.Potions; import net.minecraft.server.world.ServerWorld; import net.minecraft.sound.SoundCategory; import net.minecraft.sound.SoundEvents; @@ -50,15 +53,8 @@ public interface Soakable { static ActionResult tryCollectMoisture(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) { if (state.getBlock() instanceof Soakable soakable) { ItemStack stack = player.getStackInHand(hand); - if (stack.getItem() == Items.GLASS_BOTTLE) { - if (!player.isCreative()) { - stack.split(1); - } - if (stack.isEmpty()) { - player.setStackInHand(hand, Items.POTION.getDefaultStack()); - } else { - player.giveItemStack(Items.POTION.getDefaultStack()); - } + if (stack.isOf(Items.GLASS_BOTTLE)) { + player.setStackInHand(hand, ItemUsage.exchangeStack(stack, player, Items.POTION.getDefaultStack(), false)); world.playSound(player, player.getX(), player.getY(), player.getZ(), USounds.Vanilla.ITEM_BOTTLE_FILL, SoundCategory.NEUTRAL, 1, 1); world.emitGameEvent(player, GameEvent.FLUID_PICKUP, pos); updateMoisture(soakable, state, world, pos, soakable.getMoisture(state) - 1); @@ -67,6 +63,24 @@ public interface Soakable { } } + return tryDepositMoisture(state, world, pos, player, hand, hit); + } + + static ActionResult tryDepositMoisture(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) { + if (state.getBlock() instanceof Soakable soakable) { + ItemStack stack = player.getStackInHand(hand); + if (soakable.getMoisture(state) < 7 + && stack.isOf(Items.POTION) + && PotionUtil.getPotion(stack) == Potions.WATER) { + player.setStackInHand(hand, ItemUsage.exchangeStack(stack, player, Items.GLASS_BOTTLE.getDefaultStack(), false)); + world.playSound(player, player.getX(), player.getY(), player.getZ(), USounds.Vanilla.ITEM_BUCKET_EMPTY, SoundCategory.NEUTRAL, 1, 1); + world.emitGameEvent(player, GameEvent.FLUID_PLACE, pos); + updateMoisture(soakable, state, world, pos, soakable.getMoisture(state) + 1); + + return ActionResult.SUCCESS; + } + } + return ActionResult.PASS; } @@ -78,7 +92,7 @@ public interface Soakable { if (moisture < 7) { world.setBlockState(pos, soakable.getStateWithMoisture(state, moisture + 1)); } - } else { + } else if (!world.isAir(pos.up())) { if (moisture > 1) { BlockPos neighborPos = pos.offset(Util.getRandom(Soakable.DIRECTIONS, random)); BlockState neighborState = world.getBlockState(neighborPos); diff --git a/src/main/java/com/minelittlepony/unicopia/block/cloud/SoggyCloudStairsBlock.java b/src/main/java/com/minelittlepony/unicopia/block/cloud/SoggyCloudStairsBlock.java index 9e51e398..2efff68b 100644 --- a/src/main/java/com/minelittlepony/unicopia/block/cloud/SoggyCloudStairsBlock.java +++ b/src/main/java/com/minelittlepony/unicopia/block/cloud/SoggyCloudStairsBlock.java @@ -8,10 +8,15 @@ import com.minelittlepony.unicopia.block.state.StateUtil; import net.minecraft.block.Block; import net.minecraft.block.BlockState; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; import net.minecraft.state.StateManager; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Hand; +import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.math.BlockPos; import net.minecraft.world.BlockView; +import net.minecraft.world.World; public class SoggyCloudStairsBlock extends CloudStairsBlock implements Soakable { @@ -34,6 +39,12 @@ public class SoggyCloudStairsBlock extends CloudStairsBlock implements Soakable return dryBlock.get().getPickStack(world, pos, state); } + @Deprecated + @Override + public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) { + return Soakable.tryCollectMoisture(state, world, pos, player, hand, hit); + } + @Nullable @Override public BlockState getStateWithMoisture(BlockState state, int moisture) { diff --git a/src/main/java/com/minelittlepony/unicopia/block/jar/FluidOnlyJarContents.java b/src/main/java/com/minelittlepony/unicopia/block/jar/FluidOnlyJarContents.java index 0cdcab4b..b3ac0222 100644 --- a/src/main/java/com/minelittlepony/unicopia/block/jar/FluidOnlyJarContents.java +++ b/src/main/java/com/minelittlepony/unicopia/block/jar/FluidOnlyJarContents.java @@ -5,11 +5,11 @@ import com.minelittlepony.unicopia.block.ItemJarBlock.JarContents; import com.minelittlepony.unicopia.block.ItemJarBlock.TileData; import com.minelittlepony.unicopia.util.FluidHelper; +import net.fabricmc.fabric.api.tag.convention.v1.ConventionalItemTags; import net.fabricmc.fabric.api.transfer.v1.fluid.FluidConstants; import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariant; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; -import net.minecraft.item.Items; import net.minecraft.nbt.NbtCompound; import net.minecraft.util.Hand; import net.minecraft.util.TypedActionResult; @@ -27,7 +27,7 @@ public record FluidOnlyJarContents ( @Override public TypedActionResult interact(PlayerEntity player, Hand hand) { ItemStack stack = player.getStackInHand(hand); - if (stack.isOf(Items.BUCKET)) { + if (stack.isIn(ConventionalItemTags.EMPTY_BUCKETS)) { long remainder = FluidHelper.deposit(stack, player, hand, fluid, amount); tile.markDirty(); fluid.getFluid().getBucketFillSound().ifPresent(sound -> player.playSound(sound, 1, 1)); diff --git a/src/main/java/com/minelittlepony/unicopia/block/jar/ItemsJarContents.java b/src/main/java/com/minelittlepony/unicopia/block/jar/ItemsJarContents.java index a406c3dd..62f39881 100644 --- a/src/main/java/com/minelittlepony/unicopia/block/jar/ItemsJarContents.java +++ b/src/main/java/com/minelittlepony/unicopia/block/jar/ItemsJarContents.java @@ -30,15 +30,16 @@ public record ItemsJarContents ( TileData tile, List stacks ) implements JarContents, SidedInventory { - private static final int[] SLOTS = IntStream.range(0, 16).toArray(); + private static final int MAX_SIZE = 16; + private static final int[] SLOTS = IntStream.range(0, MAX_SIZE).toArray(); public ItemsJarContents(TileData tile) { - this(tile, new ArrayList<>()); + this(tile, new ArrayList<>(MAX_SIZE)); } public ItemsJarContents(TileData tile, NbtCompound compound) { this(tile, NbtSerialisable.ITEM_STACK.readAll(compound.getList("items", NbtElement.COMPOUND_TYPE)) - .limit(15) + .limit(MAX_SIZE) .collect(Collectors.toList())); } @@ -115,7 +116,7 @@ public record ItemsJarContents ( @Override public int size() { - return 15; + return MAX_SIZE; } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/client/BatEyesApplicator.java b/src/main/java/com/minelittlepony/unicopia/client/BatEyesApplicator.java index a3191d17..f9f26c79 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/BatEyesApplicator.java +++ b/src/main/java/com/minelittlepony/unicopia/client/BatEyesApplicator.java @@ -3,9 +3,9 @@ package com.minelittlepony.unicopia.client; import com.minelittlepony.unicopia.EquinePredicates; import net.minecraft.client.MinecraftClient; +import net.minecraft.entity.LivingEntity; import net.minecraft.entity.effect.StatusEffectInstance; import net.minecraft.entity.effect.StatusEffects; -import net.minecraft.entity.player.PlayerEntity; public class BatEyesApplicator { @@ -15,11 +15,17 @@ public class BatEyesApplicator { private final MinecraftClient client = MinecraftClient.getInstance(); + public float getWorldBrightness(float initial, LivingEntity entity, float tickDelta) { + if (!EquinePredicates.PLAYER_BAT.test(entity)) { + return initial; + } + return 0.6F; + } + public void enable() { - if (client.world != null) { - PlayerEntity player = client.player; - if (!player.hasStatusEffect(StatusEffects.NIGHT_VISION) && EquinePredicates.PLAYER_BAT.test(player)) { - player.addStatusEffect(new StatusEffectInstance(StatusEffects.NIGHT_VISION, 1, 1, false, false)); + if (client.world != null && client.player != null) { + if (!client.player.hasStatusEffect(StatusEffects.NIGHT_VISION) && EquinePredicates.PLAYER_BAT.test(client.player)) { + client.player.addStatusEffect(new StatusEffectInstance(StatusEffects.NIGHT_VISION, -1, 1, false, false)); batEyesApplied = true; } } diff --git a/src/main/java/com/minelittlepony/unicopia/client/UnicopiaClient.java b/src/main/java/com/minelittlepony/unicopia/client/UnicopiaClient.java index 1ad3f0a1..8fb1e403 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/UnicopiaClient.java +++ b/src/main/java/com/minelittlepony/unicopia/client/UnicopiaClient.java @@ -21,7 +21,6 @@ import com.minelittlepony.unicopia.container.*; import com.minelittlepony.unicopia.entity.player.PlayerCamera; import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.network.handler.ClientNetworkHandlerImpl; -import com.minelittlepony.unicopia.server.world.WeatherConditions; import com.minelittlepony.unicopia.server.world.ZapAppleStageStore; import com.minelittlepony.unicopia.util.Lerp; @@ -38,7 +37,6 @@ import net.minecraft.client.world.ClientWorld; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.resource.ResourceType; import net.minecraft.text.Text; -import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; @@ -55,10 +53,6 @@ public class UnicopiaClient implements ClientModInitializer { return Pony.of(MinecraftClient.getInstance().player); } - @Nullable - private Float originalRainGradient; - private final Lerp rainGradient = new Lerp(0); - public final Lerp tangentalSkyAngle = new Lerp(0, true); public final Lerp skyAngle = new Lerp(0, true); @@ -106,10 +100,6 @@ public class UnicopiaClient implements ClientModInitializer { return Unicopia.getConfig().preferredRace.get(); } - public static float getWorldBrightness(float initial) { - return 0.6F; - } - public UnicopiaClient() { instance = this; } @@ -157,38 +147,22 @@ public class UnicopiaClient implements ClientModInitializer { } private void onWorldTick(ClientWorld world) { - BlockPos pos = MinecraftClient.getInstance().getCameraEntity().getBlockPos(); + /*BlockPos pos = MinecraftClient.getInstance().getCameraEntity().getBlockPos(); float tickDelta = MinecraftClient.getInstance().getTickDelta(); - Float targetRainGradient = getTargetRainGradient(world, pos, tickDelta); + Float targetRainGradient = ((WeatherAccess)world).isInRangeOfStorm(pos) ? (Float)1F : ((WeatherAccess)world).isBelowCloudLayer(pos) ? null : (Float)0F; + Float targetThunderGradient = ((WeatherAccess)world).isInRangeOfStorm(pos) ? (Float)1F : null; - if (targetRainGradient != null) { - rainGradient.update(targetRainGradient, 2000); - } + ((WeatherAccess)world).setWeatherOverride(null, null); + rainGradient.update(targetRainGradient == null ? world.getRainGradient(tickDelta) : targetRainGradient, 2000); - float gradient = rainGradient.getValue(); - if (!rainGradient.isFinished()) { - world.setRainGradient(gradient); - world.setThunderGradient(gradient); - } - } + ((WeatherAccess)world).setWeatherOverride(1F, null); + thunderGradient.update(targetThunderGradient == null ? world.getThunderGradient(tickDelta) : targetThunderGradient, 2000); - private Float getTargetRainGradient(ClientWorld world, BlockPos pos, float tickDelta) { - if (WeatherConditions.get(world).isInRangeOfStorm(pos)) { - if (originalRainGradient == null) { - originalRainGradient = world.getRainGradient(tickDelta); - } - - return 1F; - } - - if (originalRainGradient != null) { - Float f = originalRainGradient; - originalRainGradient = null; - return f; - } - - return null; + ((WeatherAccess)world).setWeatherOverride( + rainGradient.isFinished() ? targetRainGradient : (Float)rainGradient.getValue(), + thunderGradient.isFinished() ? targetThunderGradient : (Float)thunderGradient.getValue() + );*/ } private void onScreenInit(Screen screen, ButtonList buttons) { diff --git a/src/main/java/com/minelittlepony/unicopia/client/gui/Slot.java b/src/main/java/com/minelittlepony/unicopia/client/gui/Slot.java index 80b7ef78..ced749de 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/gui/Slot.java +++ b/src/main/java/com/minelittlepony/unicopia/client/gui/Slot.java @@ -14,6 +14,7 @@ import com.mojang.blaze3d.systems.RenderSystem; import net.minecraft.client.gui.DrawContext; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.text.MutableText; +import net.minecraft.util.Colors; import net.minecraft.util.Formatting; import net.minecraft.util.math.MathHelper; @@ -145,10 +146,7 @@ class Slot { return; } - MutableText label = KeyBindingsHandler.INSTANCE.getBinding(aSlot).getLabel().copy().formatted(Formatting.BOLD); - - MatrixStack matrices = context.getMatrices(); - matrices.push(); + MutableText label = KeyBindingsHandler.INSTANCE.getBinding(aSlot).getLabel().copy(); int x = getX(); if (uHud.xDirection > 0) { @@ -158,9 +156,6 @@ class Slot { x -= uHud.client.textRenderer.getWidth(label)/2; } - matrices.translate(x, getY() + labelY, 0); - matrices.scale(0.5F, 0.5F, 0.5F); - ActivationType activation = KeyBindingsHandler.INSTANCE.getForcedActivationType(); if (activation.isResult()) { label = label.append("+T" + activation.getTapCount()); @@ -169,8 +164,6 @@ class Slot { } } - context.drawText(uHud.font, label, 0, 0, 0xFFFFFF, true); - - matrices.pop(); + DrawableUtil.drawScaledText(context, label, x, getY() + labelY, 0.5F, Colors.WHITE); } } \ No newline at end of file diff --git a/src/main/java/com/minelittlepony/unicopia/client/gui/TribeConfirmationScreen.java b/src/main/java/com/minelittlepony/unicopia/client/gui/TribeConfirmationScreen.java index 50967105..d329b50b 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/gui/TribeConfirmationScreen.java +++ b/src/main/java/com/minelittlepony/unicopia/client/gui/TribeConfirmationScreen.java @@ -104,10 +104,12 @@ public class TribeConfirmationScreen extends GameGui implements HidesHud { @Override public void render(DrawContext context, int mouseX, int mouseY, float delta) { + context.getMatrices().push(); + context.getMatrices().translate(0, 0, -2); if (parent != null) { context.getMatrices().push(); context.getMatrices().translate(0, 0, -100); - parent.render(context, 0, 0, delta); + parent.render(context, -1, -1, delta); context.getMatrices().pop(); } @@ -119,30 +121,20 @@ public class TribeConfirmationScreen extends GameGui implements HidesHud { int left = (width - columnWidth) / 2; top += 40; - final int zOffset = 0; context.drawTexture(TribeSelectionScreen.TEXTURE, left + zOffset, top, 0, 70, 123, columnHeight); - context.drawTexture(TribeSelectionScreen.TEXTURE, left + segmentWidth + zOffset, top, 20, 70, 123, columnHeight); - - context.drawTexture(TribeSelectionScreen.TEXTURE, width - left - segmentWidth + zOffset, top, 10, 70, 123, columnHeight); - + context.drawTexture(TribeSelectionScreen.TEXTURE, width - left - segmentWidth + zOffset + 1, top, 10, 70, 123, columnHeight); top -= 31; - left = width / 2; - context.drawTexture(TribeSelectionScreen.TEXTURE, left - 55, top, 140, 70, 21, 50); context.drawTexture(TribeSelectionScreen.TEXTURE, left + 35, top, 148, 70, 21, 50); - textBody.render(context, mouseX, mouseY, delta); - - context.getMatrices().push(); - context.getMatrices().translate(0, 0, 2); + context.getMatrices().pop(); context.drawTexture(TribeSelectionScreen.TEXTURE, left - 35, top - 5, 10, 70, 69, 50); context.drawTexture(TribeSelectionScreen.TEXTURE, left - 35, top - 15, 10, 70, 69, 50); super.render(context, mouseX, mouseY, delta); - context.getMatrices().pop(); } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/client/gui/UHud.java b/src/main/java/com/minelittlepony/unicopia/client/gui/UHud.java index 1dd0ae28..687bcffb 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/gui/UHud.java +++ b/src/main/java/com/minelittlepony/unicopia/client/gui/UHud.java @@ -51,8 +51,8 @@ public class UHud { private final List slots = List.of( new ManaRingSlot(this, AbilitySlot.PRIMARY, AbilitySlot.PASSIVE, 0, 0), - new Slot(this, AbilitySlot.SECONDARY, AbilitySlot.SECONDARY, 30, -8), - new Slot(this, AbilitySlot.TERTIARY, AbilitySlot.TERTIARY, 40, 18) + new Slot(this, AbilitySlot.SECONDARY, AbilitySlot.SECONDARY, 30, -10), + new Slot(this, AbilitySlot.TERTIARY, AbilitySlot.TERTIARY, 43, 10) ); @Nullable @@ -84,7 +84,7 @@ public class UHud { Pony pony = Pony.of(client.player); matrices.push(); - matrices.translate(0, 0, hotbarZ); + matrices.translate(0, 0, hotbarZ - 9800); renderViewEffects(pony, context, scaledWidth, scaledHeight, tickDelta); matrices.pop(); @@ -137,9 +137,11 @@ public class UHud { slots.forEach(slot -> slot.renderBackground(context, abilities, swap, tickDelta)); + int currentPage = Unicopia.getConfig().hudPage.get(); + int maxPages = pony.getAbilities().getMaxPage(); Ability ability = pony.getAbilities().getStat(AbilitySlot.PRIMARY) - .getAbility(Unicopia.getConfig().hudPage.get()) + .getAbility(currentPage) .orElse(null); boolean canCast = ability == Abilities.CAST || ability == Abilities.KIRIN_CAST || ability == Abilities.SHOOT; @@ -168,6 +170,14 @@ public class UHud { slots.forEach(slot -> slot.renderLabel(context, abilities, tickDelta)); + //if (maxPages > 0) { + DrawableUtil.drawScaledText(context, Text.literal((currentPage + 1) + "/" + (maxPages + 1)), 44, 38, 0.5F, Colors.WHITE); + //down + context.drawTexture(HUD_TEXTURE, 42, 43, 52, currentPage == 0 ? 6 : 0, 6, 6, 128, 128); + //up + context.drawTexture(HUD_TEXTURE, 48, 43, 57, currentPage < maxPages ? 0 : 6, 8, 6, 128, 128); + //} + matrices.pop(); if (canCast) { @@ -188,7 +198,7 @@ public class UHud { int progress = Math.min(255, (int)(time * 255F / 20F)); if (progress > 8) { - int color = 0xFFFFFF; + int color = Colors.WHITE; int alpha = progress << 24 & -16777216; color |= alpha; diff --git a/src/main/java/com/minelittlepony/unicopia/client/minelittlepony/Main.java b/src/main/java/com/minelittlepony/unicopia/client/minelittlepony/Main.java index 399a8cea..9259e775 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/minelittlepony/Main.java +++ b/src/main/java/com/minelittlepony/unicopia/client/minelittlepony/Main.java @@ -116,7 +116,9 @@ public class Main extends MineLPDelegate implements ClientModInitializer { @Override public float getPonyHeight(Entity entity) { - return super.getPonyHeight(entity) * com.minelittlepony.api.pony.Pony.getManager().getPony(entity).map(pony -> pony.metadata().size().scaleFactor() + 0.1F).orElse(1F); + return super.getPonyHeight(entity) * com.minelittlepony.api.pony.Pony.getManager().getPony(entity) + .map(pony -> pony.race().isHuman() ? 1 : pony.metadata().size().scaleFactor() + 0.1F) + .orElse(1F); } private static Race toUnicopiaRace(com.minelittlepony.api.pony.meta.Race race) { diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/AmuletFeatureRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/AmuletFeatureRenderer.java index 99bce334..d5a2ffbf 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/AmuletFeatureRenderer.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/AmuletFeatureRenderer.java @@ -49,7 +49,9 @@ public class AmuletFeatureRenderer implements AccessoryF VertexConsumer consumer = ItemRenderer.getArmorGlintConsumer(renderContext, RenderLayer.getArmorCutoutNoCull(texture), false, false); - model.setAngles(entity, context.getModel()); + if (context.getModel() instanceof BipedEntityModel) { + model.setAngles(entity, context.getModel()); + } model.render(matrices, consumer, lightUv, OverlayTexture.DEFAULT_UV, 1, 1, 1, 1); } } diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/EntityReplacementManager.java b/src/main/java/com/minelittlepony/unicopia/client/render/EntityReplacementManager.java index 8b759a18..0e1dcd76 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/EntityReplacementManager.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/EntityReplacementManager.java @@ -67,10 +67,6 @@ class EntityReplacementManager implements Disguise { return disguise; } - @Override - public void setDirty() { - } - @Override public boolean isDead() { return false; diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/shader/ViewportShader.java b/src/main/java/com/minelittlepony/unicopia/client/render/shader/ViewportShader.java index 21df38bc..0bda2eb9 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/shader/ViewportShader.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/shader/ViewportShader.java @@ -9,7 +9,6 @@ import com.google.common.collect.*; import com.google.gson.JsonSyntaxException; import com.minelittlepony.unicopia.Unicopia; import com.minelittlepony.unicopia.entity.player.Pony; -import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.logging.LogUtils; import it.unimi.dsi.fastutil.objects.Object2FloatMap; @@ -52,11 +51,7 @@ public class ViewportShader implements SynchronousResourceReloader, Identifiable } } - if (shaderId == null) { - return; - } - - if (Unicopia.getConfig().disableShaders.get()) { + if (shaderId == null || Unicopia.getConfig().disableShaders.get()) { return; } @@ -81,29 +76,23 @@ public class ViewportShader implements SynchronousResourceReloader, Identifiable } if (shader != null && client.player != null) { - RenderSystem.disableBlend(); - RenderSystem.disableDepthTest(); - RenderSystem.resetTextureMatrix(); - Pony pony = Pony.of(client.player); float corruption = pony.getCorruption().getScaled(0.9F); - corruption = pony.getInterpolator().interpolate("corruption", corruption, 10); + if (!MathHelper.approximatelyEquals(corruption, 0)) { + corruption = pony.getInterpolator().interpolate("corruption", corruption, 10); - corruption = 1 - corruption + 0.05F; + corruption = 1 - corruption + 0.05F; - shader.setUniformValue("color_convolve", "Saturation", corruption); - shader.render(tickDelta); + shader.setUniformValue("color_convolve", "Saturation", corruption); + shader.render(tickDelta); + } } } @Override public void reload(ResourceManager var1) { - if (shader != null) { - loadShader(shader.id); - } else { - loadShader(DESATURATION_SHADER); - } + loadShader(shader != null ? shader.id : DESATURATION_SHADER); } static class LoadedShader extends PostEffectProcessor { diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/spell/BubbleSpellRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/spell/BubbleSpellRenderer.java index 48f0dbb9..f7fe2241 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/spell/BubbleSpellRenderer.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/spell/BubbleSpellRenderer.java @@ -19,19 +19,22 @@ public class BubbleSpellRenderer extends SpellRenderer { super.render(matrices, vertices, spell, caster, light, limbAngle, limbDistance, tickDelta, animationProgress, headYaw, headPitch); matrices.push(); - double height = caster.asEntity().getEyeY() - caster.getOriginVector().y; - matrices.translate(0, height * 0.5F, 0); + double height = caster.asEntity().getEyeY() - caster.getOriginVector().getY(); - float radius = spell.getRadius(tickDelta) * 0.7F; - VertexConsumer buffer = vertices.getBuffer(RenderLayers.getMagicNoColor()); + float radius = spell.getRadius(tickDelta) * 1.5F; + + matrices.translate(0, radius * 0.5F + height, 0); + + VertexConsumer buffer = vertices.getBuffer(RenderLayers.getMagicShield()); Entity cameraEntity = MinecraftClient.getInstance().getCameraEntity(); matrices.push(); - matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(-45)); - matrices.multiply(RotationAxis.NEGATIVE_X.rotationDegrees(45 + cameraEntity.getYaw(tickDelta))); - matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(-cameraEntity.getPitch(tickDelta))); + matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(90)); + matrices.multiply(RotationAxis.NEGATIVE_Z.rotationDegrees(cameraEntity.getYaw(tickDelta) - 25)); + matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(-cameraEntity.getPitch(tickDelta))); + new SphereModel(40, 40, DrawableUtil.PI * 0.25F).render(matrices, buffer, light, 0, radius - 0.1F, 0.9F, 0.9F, 1, 0.3F); matrices.pop(); diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/spell/SpellRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/spell/SpellRenderer.java index a1171b7c..be29e501 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/spell/SpellRenderer.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/spell/SpellRenderer.java @@ -1,5 +1,7 @@ package com.minelittlepony.unicopia.client.render.spell; +import org.joml.Quaternionf; + import com.minelittlepony.unicopia.EquinePredicates; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.Spell; @@ -13,6 +15,8 @@ import net.minecraft.client.MinecraftClient; import net.minecraft.client.render.VertexConsumerProvider; import net.minecraft.client.render.model.json.ModelTransformationMode; import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.entity.EntityPose; +import net.minecraft.entity.LivingEntity; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.RotationAxis; @@ -37,6 +41,8 @@ public class SpellRenderer { private void renderGemstone(MatrixStack matrices, VertexConsumerProvider vertices, T spell, Caster caster, int light, float tickDelta, float animationProgress) { matrices.push(); + float scale = 1/8F; + matrices.scale(scale, scale, scale); transformGemstone(matrices, vertices, spell, caster, animationProgress); matrices.push(); @@ -46,6 +52,22 @@ public class SpellRenderer { matrices.pop(); if (spell instanceof TimedSpell timed) { + if (caster.asEntity() instanceof LivingEntity l && !l.isInPose(EntityPose.SLEEPING)) { + float bodyYaw = MathHelper.lerpAngleDegrees(tickDelta, l.prevBodyYaw, l.bodyYaw); + float headYaw = MathHelper.lerpAngleDegrees(tickDelta, l.prevHeadYaw, l.headYaw); + float yawDifference = headYaw - bodyYaw; + if (l.hasVehicle() && l.getVehicle() instanceof LivingEntity vehicle) { + bodyYaw = MathHelper.lerpAngleDegrees(tickDelta, vehicle.prevBodyYaw, vehicle.bodyYaw); + yawDifference = headYaw - bodyYaw; + float clampedYawDifference = MathHelper.clamp(MathHelper.wrapDegrees(yawDifference), -85, 85); + bodyYaw = headYaw - clampedYawDifference; + if (clampedYawDifference * clampedYawDifference > 2500) { + bodyYaw += clampedYawDifference * 0.2F; + } + yawDifference = headYaw - bodyYaw; + } + matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(180 - bodyYaw)); + } renderCountdown(matrices, timed, tickDelta); } @@ -53,7 +75,7 @@ public class SpellRenderer { } protected void renderCountdown(MatrixStack matrices, TimedSpell spell, float tickDelta) { - matrices.multiply(client.getEntityRenderDispatcher().getRotation().invert()); + matrices.multiply(client.getEntityRenderDispatcher().getRotation().invert(new Quaternionf())); float radius = 0.6F; float timeRemaining = spell.getTimer().getPercentTimeRemaining(tickDelta); @@ -67,6 +89,6 @@ public class SpellRenderer { if (caster.asEntity() instanceof CastSpellEntity) { y = 1F; } - matrices.translate(0, y + MathHelper.sin(animationProgress / 3F) * 0.2F, 0); + matrices.translate(0, y * 8 + MathHelper.sin(animationProgress / 3F) * 0.2F, 0); } } diff --git a/src/main/java/com/minelittlepony/unicopia/command/ConfigCommand.java b/src/main/java/com/minelittlepony/unicopia/command/ConfigCommand.java index 81b0abab..fb9b5ab2 100644 --- a/src/main/java/com/minelittlepony/unicopia/command/ConfigCommand.java +++ b/src/main/java/com/minelittlepony/unicopia/command/ConfigCommand.java @@ -23,7 +23,6 @@ import net.minecraft.registry.RegistryKeys; import net.minecraft.registry.RegistryWrapper; import net.minecraft.server.command.CommandManager; import net.minecraft.server.command.ServerCommandSource; -import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.text.Text; import net.minecraft.util.Identifier; @@ -63,10 +62,8 @@ public class ConfigCommand { }))) ) .then(CommandManager.literal("list").executes(source -> ConfigCommand.>getProperty(configName, values -> { - ServerPlayerEntity player = source.getSource().getPlayerOrThrow(); - - player.sendMessage(Text.translatable("command.unicopia.config.list", configName, values.size()), false); - values.forEach(line -> player.sendMessage(Text.literal(line))); + source.getSource().sendFeedback(() -> Text.translatable("command.unicopia.config.list", configName, values.size()), false); + values.forEach(line -> source.getSource().sendFeedback(() -> Text.literal(line), false)); })) ); } diff --git a/src/main/java/com/minelittlepony/unicopia/command/DisguiseCommand.java b/src/main/java/com/minelittlepony/unicopia/command/DisguiseCommand.java index d735c89a..5dba2c32 100644 --- a/src/main/java/com/minelittlepony/unicopia/command/DisguiseCommand.java +++ b/src/main/java/com/minelittlepony/unicopia/command/DisguiseCommand.java @@ -4,8 +4,10 @@ import java.util.function.Function; import com.minelittlepony.unicopia.EquinePredicates; import com.minelittlepony.unicopia.InteractionManager; +import com.minelittlepony.unicopia.ability.Abilities; import com.minelittlepony.unicopia.ability.magic.SpellPredicate; import com.minelittlepony.unicopia.ability.magic.spell.CastingMethod; +import com.minelittlepony.unicopia.ability.magic.spell.DispersableDisguiseSpell; import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; import com.minelittlepony.unicopia.entity.player.Pony; import com.mojang.authlib.GameProfile; @@ -81,7 +83,13 @@ public class DisguiseCommand { Pony iplayer = Pony.of(player); iplayer.getSpellSlot().get(SpellType.CHANGELING_DISGUISE) - .orElseGet(() -> SpellType.CHANGELING_DISGUISE.withTraits().apply(iplayer, CastingMethod.INNATE)) + .orElseGet(() -> { + DispersableDisguiseSpell spell = SpellType.CHANGELING_DISGUISE.withTraits().apply(iplayer, CastingMethod.INNATE); + if (!iplayer.canUse(Abilities.DISGUISE)) { + spell.setForced(); + } + return spell; + }) .setDisguise(entity); if (source.getEntity() == player) { diff --git a/src/main/java/com/minelittlepony/unicopia/command/GravityCommand.java b/src/main/java/com/minelittlepony/unicopia/command/GravityCommand.java index a97272e9..d071b6bf 100644 --- a/src/main/java/com/minelittlepony/unicopia/command/GravityCommand.java +++ b/src/main/java/com/minelittlepony/unicopia/command/GravityCommand.java @@ -50,17 +50,19 @@ class GravityCommand { l.getPhysics().setBaseGravityModifier(gravity); if (l.asEntity() instanceof PlayerEntity player) { if (source.getEntity() == player) { - player.sendMessage(Text.translatable("commands.gravity.set.self", gravity)); - } else if (source.getWorld().getGameRules().getBoolean(GameRules.SEND_COMMAND_FEEDBACK)) { - player.sendMessage(Text.translatable("commands.gravity.set.other", l.asEntity().getDisplayName(), gravity)); + source.sendFeedback(() -> Text.translatable("commands.gravity.set.self", gravity), true); + } else { + if (source.getWorld().getGameRules().getBoolean(GameRules.SEND_COMMAND_FEEDBACK)) { + player.sendMessage(Text.translatable("commands.gravity.set", gravity)); + } + + source.sendFeedback(() -> Text.translatable("commands.gravity.set.other", l.asEntity().getDisplayName(), gravity), true); } } return (Entity)l.asEntity(); }).toList(); - if (affected.size() == 1) { - source.sendFeedback(() -> Text.translatable("commands.gravity.set.other", affected.get(0).getDisplayName()), true); - } else { + if (affected.size() > 1) { source.sendFeedback(() -> Text.translatable("commands.gravity.set.multiple", affected.size()), true); } return 0; diff --git a/src/main/java/com/minelittlepony/unicopia/command/ManaCommand.java b/src/main/java/com/minelittlepony/unicopia/command/ManaCommand.java index b75fd8e8..31e41416 100644 --- a/src/main/java/com/minelittlepony/unicopia/command/ManaCommand.java +++ b/src/main/java/com/minelittlepony/unicopia/command/ManaCommand.java @@ -24,7 +24,7 @@ public class ManaCommand { var pony = Pony.of(source.getSource().getPlayer()); var bar = type.getBar(pony.getMagicalReserves()); - source.getSource().getPlayer().sendMessage(Text.literal(type.name() + " is " + bar.get() + "/" + bar.getMax())); + source.getSource().sendFeedback(() -> Text.literal(type.name() + " is " + bar.get() + "/" + bar.getMax()), true); return 0; }) .then(CommandManager.argument("value", FloatArgumentType.floatArg()).executes(source -> { @@ -48,7 +48,8 @@ public class ManaCommand { pony.asWorld().playSound(null, pony.getOrigin(), USounds.Vanilla.ENTITY_PLAYER_LEVELUP, SoundCategory.PLAYERS, 1, 2); } bar.set(value); - source.getSource().getPlayer().sendMessage(Text.literal("Set " + type.name() + " to " + bar.get() + "/" + bar.getMax())); + var t = type; + source.getSource().sendFeedback(() -> Text.literal("Set " + t.name() + " to " + bar.get() + "/" + bar.getMax()), true); return 0; }))); } diff --git a/src/main/java/com/minelittlepony/unicopia/command/SpeciesCommand.java b/src/main/java/com/minelittlepony/unicopia/command/SpeciesCommand.java index e1e9e999..5fecdbe6 100644 --- a/src/main/java/com/minelittlepony/unicopia/command/SpeciesCommand.java +++ b/src/main/java/com/minelittlepony/unicopia/command/SpeciesCommand.java @@ -44,10 +44,10 @@ class SpeciesCommand { )) .then(CommandManager.literal("describe") .then(CommandManager.argument("race", Race.argument()).suggests(UCommandSuggestion.ALL_RACE_SUGGESTIONS) - .executes(context -> describe(context.getSource().getPlayer(), Race.fromArgument(context, "race"))) + .executes(context -> describe(context.getSource(), Race.fromArgument(context, "race"))) )) .then(CommandManager.literal("list") - .executes(context -> list(context.getSource().getPlayer()) + .executes(context -> list(context.getSource()) )); } @@ -70,57 +70,59 @@ class SpeciesCommand { } source.sendFeedback(() -> Text.translatable("commands.race.success.other", player.getName(), race.getDisplayName()), true); } - } else if (player.getEntityWorld().getGameRules().getBoolean(GameRules.SEND_COMMAND_FEEDBACK)) { - player.sendMessage(Text.translatable("commands.race.permission"), false); + } else { + source.sendFeedback(() -> Text.translatable("commands.race.permission"), false); } return 0; } static int get(ServerCommandSource source, PlayerEntity player, boolean isSelf) { - Race spec = Pony.of(player).getSpecies(); + source.sendFeedback(() -> { + Race spec = Pony.of(player).getSpecies(); - String name = "commands.race.tell."; - name += isSelf ? "self" : "other"; + String name = "commands.race.tell."; + name += isSelf ? "self" : "other"; - player.sendMessage(Text.translatable(name, player.getName()) + return Text.translatable(name, player.getName()) .append(Text.translatable(spec.getTranslationKey()) - .styled(s -> s.withColor(Formatting.GOLD))), false); - + .styled(s -> s.withColor(Formatting.GOLD))); + }, false); return 0; } - static int list(PlayerEntity player) { - player.sendMessage(Text.translatable("commands.race.list"), false); + static int list(ServerCommandSource source) { + source.sendFeedback(() -> Text.translatable("commands.race.list"), false); + source.sendFeedback(() -> { + MutableText message = Text.literal(""); - MutableText message = Text.literal(""); - - boolean first = true; - for (Race i : Race.REGISTRY) { - if (i.availability().isGrantable() && !i.isUnset() && i.isPermitted(player)) { - message.append(Text.literal((!first ? "\n" : "") + " - ")); - message.append(i.getDisplayName()); - first = false; + boolean first = true; + for (Race i : Race.REGISTRY) { + if (i.availability().isGrantable() && !i.isUnset() && i.isPermitted(source.getPlayer())) { + message.append(Text.literal((!first ? "\n" : "") + " - ")); + message.append(i.getDisplayName()); + first = false; + } } - } - player.sendMessage(message.styled(s -> s.withColor(Formatting.GOLD)), false); + return message.styled(s -> s.withColor(Formatting.GOLD)); + }, false); return 0; } - static int describe(PlayerEntity player, Race species) { + static int describe(ServerCommandSource source, Race species) { Identifier id = Race.REGISTRY.getId(species); for (String category : new String[] { "goods", "bads" }) { - player.sendMessage(Text.translatable( + source.sendFeedback(() -> Text.translatable( String.format("gui.unicopia.tribe_selection.confirm.%s.%d.%s.%s", category), species.getAltDisplayName() ), false); for (int i = 1; i < 5; i++) { String line = String.format("gui.unicopia.tribe_selection.confirm.%s.%d.%s.%s", category, i, id.getNamespace(), id.getPath()); - player.sendMessage(Text.translatable(line).styled(s -> s.withColor(category.equals("goods") ? Formatting.YELLOW : Formatting.RED)), false); + source.sendFeedback(() -> Text.translatable(line).styled(s -> s.withColor(category.equals("goods") ? Formatting.YELLOW : Formatting.RED)), false); } } diff --git a/src/main/java/com/minelittlepony/unicopia/command/TraitCommand.java b/src/main/java/com/minelittlepony/unicopia/command/TraitCommand.java index 04bcf078..560eaecc 100644 --- a/src/main/java/com/minelittlepony/unicopia/command/TraitCommand.java +++ b/src/main/java/com/minelittlepony/unicopia/command/TraitCommand.java @@ -13,6 +13,7 @@ import net.minecraft.server.command.CommandManager; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.text.*; import net.minecraft.util.Hand; +import net.minecraft.world.GameRules; class TraitCommand { static LiteralArgumentBuilder create() { @@ -78,7 +79,9 @@ class TraitCommand { float gravity = iplayer.getPhysics().getGravityModifier(); if (source.getPlayer() == player) { - player.sendMessage(Text.translatable(translationKey, gravity), false); + if (player.getEntityWorld().getGameRules().getBoolean(GameRules.SEND_COMMAND_FEEDBACK)) { + player.sendMessage(Text.translatable(translationKey, gravity), false); + } } else { source.sendFeedback(() -> Text.translatable(translationKey + ".other", player.getName(), gravity), true); } diff --git a/src/main/java/com/minelittlepony/unicopia/compat/trinkets/TrinketsDelegate.java b/src/main/java/com/minelittlepony/unicopia/compat/trinkets/TrinketsDelegate.java index f19d592a..c73f5d46 100644 --- a/src/main/java/com/minelittlepony/unicopia/compat/trinkets/TrinketsDelegate.java +++ b/src/main/java/com/minelittlepony/unicopia/compat/trinkets/TrinketsDelegate.java @@ -127,7 +127,7 @@ public interface TrinketsDelegate { } record EquippedStack(ItemStack stack, Runnable sendUpdate, Consumer breakStatusSender) { - public static EquippedStack EMPTY = new EquippedStack(ItemStack.EMPTY, () -> {}, l -> {}); + public static final EquippedStack EMPTY = new EquippedStack(ItemStack.EMPTY, () -> {}, l -> {}); EquippedStack(LivingEntity entity, EquipmentSlot slot) { this(entity.getEquippedStack(slot), () -> {}, l -> l.sendEquipmentBreakStatus(slot)); diff --git a/src/main/java/com/minelittlepony/unicopia/datagen/providers/DietProfileGenerator.java b/src/main/java/com/minelittlepony/unicopia/datagen/providers/DietProfileGenerator.java index 4034021f..cfa28601 100644 --- a/src/main/java/com/minelittlepony/unicopia/datagen/providers/DietProfileGenerator.java +++ b/src/main/java/com/minelittlepony/unicopia/datagen/providers/DietProfileGenerator.java @@ -148,12 +148,14 @@ public class DietProfileGenerator { bakedGoodExtremePreference, pineconeMultiplier, properMeatStandards, seaFoodExclusions, // They have a sweet tooth new Multiplier.Builder().tag(Unicopia.id("candy")).tag(Unicopia.id("desserts")).tag(Unicopia.id("rocks")).hunger(2.5F).saturation(1.7F).build(), + new Multiplier.Builder().tag(Unicopia.id("gems")).hunger(0.5F).saturation(0.7F).build(), new Multiplier.Builder().tag(Unicopia.id("fish/cooked")).hunger(0.2F).saturation(0.3F).build(), new Multiplier.Builder().tag(Unicopia.id("insect/cooked")).hunger(0.1F).saturation(0.1F).build(), new Multiplier.Builder().tag(Unicopia.id("meat/cooked")).hunger(0.1F).saturation(0.1F).build() ), List.of( // Candy and rocks gives them a massive saturation boost. Maybe too much? new FoodGroupEffects.Builder().tag(Unicopia.id("candy")).tag(Unicopia.id("rocks")).food(UFoodComponents.builder(5, 12).alwaysEdible()).build(), + new FoodGroupEffects.Builder().tag(Unicopia.id("gems")).food(UFoodComponents.builder(2, 1.5F).snack().alwaysEdible()).build(), new FoodGroupEffects.Builder().tag(Unicopia.id("desserts")).food(UFoodComponents.builder(12, 32).snack().alwaysEdible()).build() ), Optional.empty())); // Pegasi prefer fish over other food sources diff --git a/src/main/java/com/minelittlepony/unicopia/datagen/providers/FoodGroupsGenerator.java b/src/main/java/com/minelittlepony/unicopia/datagen/providers/FoodGroupsGenerator.java index a30de498..47864d46 100644 --- a/src/main/java/com/minelittlepony/unicopia/datagen/providers/FoodGroupsGenerator.java +++ b/src/main/java/com/minelittlepony/unicopia/datagen/providers/FoodGroupsGenerator.java @@ -31,6 +31,7 @@ public class FoodGroupsGenerator { exporter.accept(Unicopia.id("desserts"), new FoodGroupEffects.Builder().tag(UConventionalTags.Items.DESSERTS).food(FoodComponents.COOKIE)); exporter.accept(Unicopia.id("fruit"), new FoodGroupEffects.Builder().tag(UConventionalTags.Items.FRUITS).food(UFoodComponents.BANANA)); exporter.accept(Unicopia.id("rocks"), new FoodGroupEffects.Builder().tag(UConventionalTags.Items.ROCKS).tag(UTags.Items.ROCK_STEWS).food(FoodComponents.MUSHROOM_STEW)); + exporter.accept(Unicopia.id("gems"), new FoodGroupEffects.Builder().tag(UConventionalTags.Items.GEMS)); exporter.accept(Unicopia.id("shells"), new FoodGroupEffects.Builder().tag(UTags.Items.SHELLS).food(UFoodComponents.SHELL)); exporter.accept(Unicopia.id("special_shells"), new FoodGroupEffects.Builder().tag(UTags.Items.SPECIAL_SHELLS).food(UFoodComponents.SHELLY)); exporter.accept(Unicopia.id("love"), new FoodGroupEffects.Builder().tag(UTags.Items.CONTAINER_WITH_LOVE).food(UFoodComponents.LOVE_MUG).ailment(new CompoundAffliction(List.of( diff --git a/src/main/java/com/minelittlepony/unicopia/datagen/providers/tag/SereneSeasonsTags.java b/src/main/java/com/minelittlepony/unicopia/datagen/providers/tag/SereneSeasonsTags.java new file mode 100644 index 00000000..100dcc99 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/datagen/providers/tag/SereneSeasonsTags.java @@ -0,0 +1,32 @@ +package com.minelittlepony.unicopia.datagen.providers.tag; + +import net.minecraft.block.Block; +import net.minecraft.item.Item; +import net.minecraft.registry.RegistryKeys; +import net.minecraft.registry.tag.TagKey; +import net.minecraft.util.Identifier; + +public interface SereneSeasonsTags { + interface Items { + TagKey AUTUMN_CROPS = item("autumn_crops"); + TagKey WINTER_CROPS = item("winter_crops"); + TagKey SPRING_CROPS = item("spring_crops"); + TagKey SUMMER_CROPS = item("summer_crops"); + + private static TagKey item(String name) { + return TagKey.of(RegistryKeys.ITEM, new Identifier("sereneseasons", name)); + } + } + + interface Blocks { + TagKey AUTUMN_CROPS = block("autumn_crops"); + TagKey WINTER_CROPS = block("winter_crops"); + TagKey SPRING_CROPS = block("spring_crops"); + TagKey SUMMER_CROPS = block("summer_crops"); + + private static TagKey block(String name) { + return TagKey.of(RegistryKeys.BLOCK, new Identifier("sereneseasons", name)); + } + } + +} diff --git a/src/main/java/com/minelittlepony/unicopia/datagen/providers/tag/UBlockTagProvider.java b/src/main/java/com/minelittlepony/unicopia/datagen/providers/tag/UBlockTagProvider.java index 66ea54f0..b741612e 100644 --- a/src/main/java/com/minelittlepony/unicopia/datagen/providers/tag/UBlockTagProvider.java +++ b/src/main/java/com/minelittlepony/unicopia/datagen/providers/tag/UBlockTagProvider.java @@ -8,6 +8,7 @@ import com.minelittlepony.unicopia.UTags; import com.minelittlepony.unicopia.Unicopia; import com.minelittlepony.unicopia.block.UBlocks; import com.minelittlepony.unicopia.server.world.Tree; +import com.minelittlepony.unicopia.server.world.UTreeGen; import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput; import net.fabricmc.fabric.api.datagen.v1.provider.FabricTagProvider; @@ -103,6 +104,30 @@ public class UBlockTagProvider extends FabricTagProvider.BlockTagProvider { ).forceAddTag(TagKey.of(RegistryKeys.BLOCK, new Identifier("c", "concrete_powders"))); getOrCreateTagBuilder(UTags.Blocks.UNAFFECTED_BY_GROW_ABILITY).add(Blocks.GRASS_BLOCK); + addSeasonalCrops(); + } + + private void addSeasonalCrops() { + getOrCreateTagBuilder(SereneSeasonsTags.Blocks.AUTUMN_CROPS).add( + UBlocks.GREEN_APPLE_LEAVES, UBlocks.GREEN_APPLE_SPROUT, UTreeGen.GREEN_APPLE_TREE.sapling().get(), + UBlocks.SOUR_APPLE_LEAVES, UBlocks.SOUR_APPLE_SPROUT, UTreeGen.SOUR_APPLE_TREE.sapling().get(), + UBlocks.OATS_CROWN, UBlocks.OATS_STEM, UBlocks.OATS, + UBlocks.ROCKS + ); + getOrCreateTagBuilder(SereneSeasonsTags.Blocks.WINTER_CROPS).add(UBlocks.ROCKS); + getOrCreateTagBuilder(SereneSeasonsTags.Blocks.SPRING_CROPS).add( + UBlocks.SWEET_APPLE_LEAVES, UBlocks.SWEET_APPLE_SPROUT, UTreeGen.SWEET_APPLE_TREE.sapling().get(), + UBlocks.GOLDEN_OAK_LEAVES, UBlocks.GOLDEN_OAK_SPROUT, UTreeGen.GOLDEN_APPLE_TREE.sapling().get(), + UBlocks.PALM_LEAVES, UBlocks.BANANAS, UTreeGen.BANANA_TREE.sapling().get(), + UBlocks.PINEAPPLE, + UBlocks.ROCKS + ); + getOrCreateTagBuilder(SereneSeasonsTags.Blocks.SUMMER_CROPS).add( + UBlocks.SWEET_APPLE_LEAVES, UBlocks.SWEET_APPLE_SPROUT, UTreeGen.SWEET_APPLE_TREE.sapling().get(), + UBlocks.MANGO_LEAVES, UTreeGen.MANGO_TREE.sapling().get(), + UBlocks.OATS_CROWN, UBlocks.OATS_STEM, UBlocks.OATS, + UBlocks.ROCKS + ); } private void addFruitTrees() { diff --git a/src/main/java/com/minelittlepony/unicopia/datagen/providers/tag/UDamageTypeProvider.java b/src/main/java/com/minelittlepony/unicopia/datagen/providers/tag/UDamageTypeProvider.java index a257ccb4..1506283c 100644 --- a/src/main/java/com/minelittlepony/unicopia/datagen/providers/tag/UDamageTypeProvider.java +++ b/src/main/java/com/minelittlepony/unicopia/datagen/providers/tag/UDamageTypeProvider.java @@ -8,6 +8,7 @@ import com.minelittlepony.unicopia.entity.damage.UDamageTypes; import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput; import net.fabricmc.fabric.api.datagen.v1.provider.FabricTagProvider; import net.minecraft.entity.damage.DamageType; +import net.minecraft.entity.damage.DamageTypes; import net.minecraft.registry.RegistryKeys; import net.minecraft.registry.RegistryWrapper.WrapperLookup; import net.minecraft.registry.tag.DamageTypeTags; @@ -25,7 +26,11 @@ public class UDamageTypeProvider extends FabricTagProvider { ).forceAddTag(DamageTypeTags.IS_FALL).forceAddTag(DamageTypeTags.IS_FREEZING).forceAddTag(DamageTypeTags.IS_LIGHTNING).forceAddTag(DamageTypeTags.IS_PROJECTILE); getOrCreateTagBuilder(UTags.DamageTypes.FROM_ROCKS).add(UDamageTypes.ROCK); getOrCreateTagBuilder(UTags.DamageTypes.FROM_HORSESHOES).add(UDamageTypes.HORSESHOE); - getOrCreateTagBuilder(UTags.DamageTypes.BREAKS_SUNGLASSES).add(UDamageTypes.BAT_SCREECH, UDamageTypes.RAINBOOM); + getOrCreateTagBuilder(UTags.DamageTypes.BREAKS_SUNGLASSES).add( + UDamageTypes.BAT_SCREECH, UDamageTypes.RAINBOOM, + DamageTypes.FLY_INTO_WALL, DamageTypes.FALLING_ANVIL, DamageTypes.FALLING_BLOCK, + DamageTypes.SONIC_BOOM + ).forceAddTag(DamageTypeTags.IS_EXPLOSION); getOrCreateTagBuilder(DamageTypeTags.AVOIDS_GUARDIAN_THORNS).add( UDamageTypes.EXHAUSTION, UDamageTypes.ALICORN_AMULET, UDamageTypes.ZAP_APPLE, UDamageTypes.KICK, UDamageTypes.SMASH, @@ -35,9 +40,13 @@ public class UDamageTypeProvider extends FabricTagProvider { UDamageTypes.EXHAUSTION, UDamageTypes.GAVITY_WELL_RECOIL, UDamageTypes.ALICORN_AMULET, UDamageTypes.ZAP_APPLE, UDamageTypes.KICK, UDamageTypes.SMASH, UDamageTypes.BAT_SCREECH, UDamageTypes.LOVE_DRAINING, UDamageTypes.LIFE_DRAINING, UDamageTypes.STEAMROLLER, UDamageTypes.RAINBOOM, - UDamageTypes.SUN, UDamageTypes.SUNLIGHT, UDamageTypes.PETRIFIED + UDamageTypes.SUN, UDamageTypes.SUNLIGHT, UDamageTypes.PETRIFIED, UDamageTypes.TRIBE_SWAP ); getOrCreateTagBuilder(DamageTypeTags.BYPASSES_INVULNERABILITY).add(UDamageTypes.TRIBE_SWAP); + getOrCreateTagBuilder(DamageTypeTags.BYPASSES_COOLDOWN).add(UDamageTypes.TRIBE_SWAP); + getOrCreateTagBuilder(DamageTypeTags.BYPASSES_EFFECTS).add(UDamageTypes.TRIBE_SWAP); + getOrCreateTagBuilder(DamageTypeTags.BYPASSES_RESISTANCE).add(UDamageTypes.TRIBE_SWAP); + getOrCreateTagBuilder(DamageTypeTags.BYPASSES_ENCHANTMENTS).add(UDamageTypes.TRIBE_SWAP); getOrCreateTagBuilder(DamageTypeTags.BYPASSES_SHIELD).add( UDamageTypes.EXHAUSTION, UDamageTypes.BAT_SCREECH, UDamageTypes.ALICORN_AMULET, UDamageTypes.LOVE_DRAINING, UDamageTypes.LIFE_DRAINING, diff --git a/src/main/java/com/minelittlepony/unicopia/datagen/providers/tag/UItemTagProvider.java b/src/main/java/com/minelittlepony/unicopia/datagen/providers/tag/UItemTagProvider.java index 44d1db03..ec4dd783 100644 --- a/src/main/java/com/minelittlepony/unicopia/datagen/providers/tag/UItemTagProvider.java +++ b/src/main/java/com/minelittlepony/unicopia/datagen/providers/tag/UItemTagProvider.java @@ -175,6 +175,11 @@ public class UItemTagProvider extends FabricTagProvider.ItemTagProvider { copy(UTags.Blocks.CLOUD_STAIRS, UTags.Items.CLOUD_STAIRS); copy(UTags.Blocks.CLOUD_BLOCKS, UTags.Items.CLOUD_BLOCKS); copy(UTags.Blocks.CHITIN_BLOCKS, UTags.Items.CHITIN_BLOCKS); + + copy(SereneSeasonsTags.Blocks.AUTUMN_CROPS, SereneSeasonsTags.Items.AUTUMN_CROPS); + copy(SereneSeasonsTags.Blocks.WINTER_CROPS, SereneSeasonsTags.Items.WINTER_CROPS); + copy(SereneSeasonsTags.Blocks.SPRING_CROPS, SereneSeasonsTags.Items.SPRING_CROPS); + copy(SereneSeasonsTags.Blocks.SUMMER_CROPS, SereneSeasonsTags.Items.SUMMER_CROPS); } private void exportForagingTags() { @@ -348,6 +353,7 @@ public class UItemTagProvider extends FabricTagProvider.ItemTagProvider { getOrCreateTagBuilder(UConventionalTags.Items.WORMS).add(UItems.WHEAT_WORMS); getOrCreateTagBuilder(UConventionalTags.Items.STICKS).add(Items.STICK); getOrCreateTagBuilder(UConventionalTags.Items.ROCKS).add(UItems.ROCK); + getOrCreateTagBuilder(UConventionalTags.Items.GEMS).add(UItems.GEMSTONE, UItems.BOTCHED_GEM); getOrCreateTagBuilder(UConventionalTags.Items.PINECONES).add(UItems.PINECONE); getOrCreateTagBuilder(UConventionalTags.Items.PINEAPPLES).add(UItems.PINEAPPLE); getOrCreateTagBuilder(UConventionalTags.Items.MANGOES).add(UItems.MANGO); diff --git a/src/main/java/com/minelittlepony/unicopia/entity/AttributeContainer.java b/src/main/java/com/minelittlepony/unicopia/entity/AttributeContainer.java index 8c2ba874..11000da1 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/AttributeContainer.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/AttributeContainer.java @@ -26,7 +26,7 @@ public interface AttributeContainer { EntityAttributeModifier modifier = instance.getModifier(id); if (!MathHelper.approximatelyEquals(desiredValue, modifier == null ? 0 : modifier.getValue())) { - instance.tryRemoveModifier(id); + instance.removeModifier(id); if (desiredValue != 0) { if (permanent) { diff --git a/src/main/java/com/minelittlepony/unicopia/entity/Creature.java b/src/main/java/com/minelittlepony/unicopia/entity/Creature.java index c319f104..4be62edd 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/Creature.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/Creature.java @@ -11,7 +11,6 @@ import com.minelittlepony.unicopia.InteractionManager; import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.WeaklyOwned; import com.minelittlepony.unicopia.ability.magic.*; -import com.minelittlepony.unicopia.ability.magic.spell.Spell; import com.minelittlepony.unicopia.ability.magic.spell.effect.TargetSelecter; import com.minelittlepony.unicopia.entity.ai.BreakHeartGoal; import com.minelittlepony.unicopia.entity.ai.DynamicTargetGoal; @@ -302,9 +301,6 @@ public class Creature extends Living implements WeaklyOwned.Mutabl @Override public void toNBT(NbtCompound compound) { super.toNBT(compound); - getSpellSlot().get().ifPresent(effect -> { - compound.put("effect", Spell.writeNbt(effect)); - }); compound.put("master", getMasterReference().toNBT()); physics.toNBT(compound); compound.putBoolean("discorded", isDiscorded()); @@ -313,9 +309,6 @@ public class Creature extends Living implements WeaklyOwned.Mutabl @Override public void fromNBT(NbtCompound compound) { super.fromNBT(compound); - if (compound.contains("effect")) { - getSpellSlot().put(Spell.readNbt(compound.getCompound("effect"))); - } if (compound.contains("master", NbtElement.COMPOUND_TYPE)) { owner.fromNBT(compound.getCompound("master")); if (owner.isSet()) { diff --git a/src/main/java/com/minelittlepony/unicopia/entity/EntityPhysics.java b/src/main/java/com/minelittlepony/unicopia/entity/EntityPhysics.java index c50d740f..bd51d7ba 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/EntityPhysics.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/EntityPhysics.java @@ -10,12 +10,12 @@ import com.minelittlepony.unicopia.util.Tickable; import net.minecraft.block.BlockState; import net.minecraft.block.FenceGateBlock; import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityPose; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.mob.MobEntity; import net.minecraft.nbt.NbtCompound; import net.minecraft.registry.tag.BlockTags; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; public class EntityPhysics implements Physics, Copyable>, Tickable { @@ -75,18 +75,17 @@ public class EntityPhysics implements Physics, Copyable implements Equine, Caste } } - if (entity instanceof HostileEntity mob && mob.hasStatusEffect(UEffects.CORRUPT_INFLUENCE) && mob.getRandom().nextInt(4) == 0) { + if (entity instanceof HostileEntity mob && mob.hasStatusEffect(UEffects.CORRUPT_INFLUENCE) && mob.getRandom().nextInt(4000) == 0) { CorruptInfluenceStatusEffect.reproduce(mob); } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/ai/BreakHeartGoal.java b/src/main/java/com/minelittlepony/unicopia/entity/ai/BreakHeartGoal.java index 38328a96..a37eff54 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/ai/BreakHeartGoal.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/ai/BreakHeartGoal.java @@ -49,6 +49,7 @@ public class BreakHeartGoal extends Goal { public void stop() { targetter.stop(); mob.getNavigation().stop(); + mob.setTarget(null); } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/Disguise.java b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/Disguise.java index b34606f7..9604dfc1 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/Disguise.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/Disguise.java @@ -24,8 +24,6 @@ public interface Disguise extends FlightType.Provider, PlayerDimensions.Provider EntityAppearance getDisguise(); - void setDirty(); - boolean isDead(); default Optional getAppearance() { @@ -57,7 +55,6 @@ public interface Disguise extends FlightType.Provider, PlayerDimensions.Provider } getDisguise().setAppearance(entity); - setDirty(); return this; } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/EntityAppearance.java b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/EntityAppearance.java index 6c272cca..7f9a1011 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/EntityAppearance.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/EntityAppearance.java @@ -21,6 +21,7 @@ import com.minelittlepony.unicopia.entity.mob.SombraEntity; import com.minelittlepony.unicopia.entity.mob.UEntityAttributes; import com.minelittlepony.unicopia.entity.player.PlayerDimensions; import com.minelittlepony.unicopia.entity.player.Pony; +import com.minelittlepony.unicopia.network.track.TrackableObject; import com.minelittlepony.unicopia.projectile.ProjectileUtil; import com.minelittlepony.unicopia.util.NbtSerialisable; import com.mojang.authlib.GameProfile; @@ -51,7 +52,7 @@ import net.minecraft.nbt.NbtElement; import net.minecraft.util.math.Vec3d; import net.minecraft.util.shape.VoxelShape; -public class EntityAppearance implements NbtSerialisable, PlayerDimensions.Provider, FlightType.Provider, EntityCollisions.ComplexCollidable { +public class EntityAppearance implements NbtSerialisable, PlayerDimensions.Provider, FlightType.Provider, EntityCollisions.ComplexCollidable, TrackableObject { private static final Optional BLOCK_HEIGHT = Optional.of(0.5F); @NotNull @@ -77,6 +78,8 @@ public class EntityAppearance implements NbtSerialisable, PlayerDimensions.Provi @Nullable private NbtCompound entityNbt; + private boolean dirty; + @Nullable public Entity getAppearance() { return entity; @@ -109,6 +112,7 @@ public class EntityAppearance implements NbtSerialisable, PlayerDimensions.Provi entityNbt = entity == null ? null : encodeEntityToNBT(entity); entityId = entityNbt == null ? "" : entityNbt.getString("id"); + markDirty(); } public boolean isPresent() { @@ -392,4 +396,44 @@ public class EntityAppearance implements NbtSerialisable, PlayerDimensions.Provi getAttachments().forEach(e -> EntityCollisions.getCollissionShapes(e.entity(), context, output)); } + public void markDirty() { + dirty = true; + } + + @Override + public Status getStatus() { + if (dirty) { + dirty = false; + return Status.UPDATED; + } + return Status.DEFAULT; + } + + @Override + public void readTrackedNbt(NbtCompound nbt) { + fromNBT(nbt); + } + + @Override + public NbtCompound writeTrackedNbt() { + return toNBT(); + } + + @Override + public void discard(boolean immediate) { + setAppearance(null); + dirty = false; + } + + @Override + public void copyTo(EntityAppearance destination) { + destination.entityId = entityId; + destination.entity = entity; + destination.blockEntity = blockEntity; + destination.attachments.addAll(attachments); + destination.dimensions = dimensions; + destination.tag = tag == null ? null : tag.copy(); + destination.entityNbt = entityNbt == null ? null : entityNbt.copy(); + } + } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/SheepBehaviour.java b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/SheepBehaviour.java index c4074e27..1a7ac949 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/SheepBehaviour.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/SheepBehaviour.java @@ -65,7 +65,7 @@ public class SheepBehaviour extends EntityBehaviour { } } while (dropAmount-- > 0); } - spell.setDirty(); + spell.getAppearance().ifPresent(EntityAppearance::markDirty); } } } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/effect/CorruptInfluenceStatusEffect.java b/src/main/java/com/minelittlepony/unicopia/entity/effect/CorruptInfluenceStatusEffect.java index bf98ef9d..a30d7656 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/effect/CorruptInfluenceStatusEffect.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/effect/CorruptInfluenceStatusEffect.java @@ -89,6 +89,9 @@ public class CorruptInfluenceStatusEffect extends StatusEffect { } } + if (mob.getRandom().nextInt(4) != 0) { + clone.clearStatusEffects(); + } mob.getWorld().spawnEntity(clone); if (!mob.isSilent()) { diff --git a/src/main/java/com/minelittlepony/unicopia/entity/effect/UPotions.java b/src/main/java/com/minelittlepony/unicopia/entity/effect/UPotions.java index 2fb07320..ed9c57c4 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/effect/UPotions.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/effect/UPotions.java @@ -20,11 +20,11 @@ import net.minecraft.util.Identifier; import net.minecraft.registry.Registries; public interface UPotions { - MorphingPotion MORPH_EARTH_PONY = new MorphingPotion(Race.EARTH).registerBaseRecipes(Potions.STRENGTH, UItems.CURING_JOKE); - MorphingPotion MORPH_UNICORN = new MorphingPotion(Race.UNICORN).registerBaseRecipes(Potions.REGENERATION, UItems.BOTCHED_GEM); - MorphingPotion MORPH_PEGASUS = new MorphingPotion(Race.PEGASUS).registerBaseRecipes(Potions.SWIFTNESS, UItems.PEGASUS_FEATHER, UItems.HIPPOGRIFF_BADGE, Items.FEATHER); + MorphingPotion MORPH_EARTH_PONY = new MorphingPotion(Race.EARTH).registerBaseRecipes(Potions.STRENGTH, UItems.CURING_JOKE, UItems.PEBBLES); + MorphingPotion MORPH_UNICORN = new MorphingPotion(Race.UNICORN).registerBaseRecipes(Potions.REGENERATION, UItems.BOTCHED_GEM, UItems.GEMSTONE); + MorphingPotion MORPH_PEGASUS = new MorphingPotion(Race.PEGASUS).registerBaseRecipes(Potions.SWIFTNESS, UItems.PEGASUS_FEATHER, UItems.GRYPHON_FEATHER, Items.FEATHER); MorphingPotion MORPH_BAT = new MorphingPotion(Race.BAT).registerBaseRecipes(Potions.NIGHT_VISION, UItems.BUTTERFLY); - MorphingPotion MORPH_CHANGELING = new MorphingPotion(Race.CHANGELING).registerBaseRecipes(Potions.HARMING, UItems.CARAPACE); + MorphingPotion MORPH_CHANGELING = new MorphingPotion(Race.CHANGELING).registerBaseRecipes(Potions.HARMING, UItems.CARAPACE, UItems.ROTTEN_APPLE); MorphingPotion MORPH_KIRIN = new MorphingPotion(Race.KIRIN).registerBaseRecipes(Potions.FIRE_RESISTANCE, Items.MAGMA_CREAM); MorphingPotion MORPH_HIPPOGRIFF = new MorphingPotion(Race.HIPPOGRIFF).registerBaseRecipes(Potions.WATER_BREATHING, UItems.CLAM_SHELL, UItems.TURRET_SHELL, UItems.SCALLOP_SHELL); diff --git a/src/main/java/com/minelittlepony/unicopia/entity/mob/CastSpellEntity.java b/src/main/java/com/minelittlepony/unicopia/entity/mob/CastSpellEntity.java index fbca955c..34216ea4 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/mob/CastSpellEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/mob/CastSpellEntity.java @@ -11,6 +11,7 @@ import com.minelittlepony.unicopia.ability.magic.SpellSlots; import com.minelittlepony.unicopia.ability.magic.spell.PlacementControlSpell; import com.minelittlepony.unicopia.ability.magic.spell.Situation; import com.minelittlepony.unicopia.ability.magic.spell.Spell; +import com.minelittlepony.unicopia.ability.magic.spell.PlacementControlSpell.PlacementDelegate; import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; import com.minelittlepony.unicopia.entity.EntityPhysics; import com.minelittlepony.unicopia.entity.EntityReference; @@ -70,8 +71,12 @@ public class CastSpellEntity extends LightEmittingEntity implements Caster type, World world) { diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/Acrobatics.java b/src/main/java/com/minelittlepony/unicopia/entity/player/Acrobatics.java index e86b61c8..8e529828 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/Acrobatics.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/Acrobatics.java @@ -58,6 +58,8 @@ public class Acrobatics implements Tickable, NbtSerialisable { public void tick() { BlockPos climbingPos = entity.getClimbingPos().orElse(null); + BlockPos hangingPos = pony.getPhysics().getHeadPosition(); + if (!pony.getPhysics().isFlying() && !entity.getAbilities().flying && climbingPos != null && pony.getObservedSpecies() == Race.CHANGELING @@ -68,7 +70,8 @@ public class Acrobatics implements Tickable, NbtSerialisable { } distanceClimbed += Math.abs(pony.getMotion().getClientVelocity().y); - BlockPos hangingPos = entity.getBlockPos().up(); + + boolean canhangHere = canHangAt(hangingPos); if (distanceClimbed > 1.5) { @@ -156,8 +159,9 @@ public class Acrobatics implements Tickable, NbtSerialisable { } public void startHanging(BlockPos pos) { + boolean inverted = pony.getPhysics().isGravityNegative(); hangingPos.set(Optional.of(pos)); - entity.teleport(pos.getX() + 0.5, pos.getY() - 1, pos.getZ() + 0.5); + entity.teleport(pos.getX() + 0.5, pos.getY() - (inverted ? 0 : 1), pos.getZ() + 0.5); entity.setVelocity(Vec3d.ZERO); entity.setSneaking(false); entity.stopFallFlying(); @@ -165,14 +169,17 @@ public class Acrobatics implements Tickable, NbtSerialisable { } public boolean canHangAt(BlockPos pos) { - if (!pony.asWorld().isAir(pos) || !pony.asWorld().isAir(pos.down())) { + int gravity = pony.getPhysics().getGravitySignum() * (isHanging() && pony.getObservedSpecies() == Race.BAT ? -1 : 1); + BlockState state = pony.asWorld().getBlockState(pos); + + if (!pony.asWorld().isAir(pos) || !pony.asWorld().isAir(pos.down(gravity))) { return false; } - pos = pos.up(); - BlockState state = pony.asWorld().getBlockState(pos); + pos = pos.up(gravity); + state = pony.asWorld().getBlockState(pos); - return state.isSolidSurface(pony.asWorld(), pos, entity, Direction.DOWN) && entity.getWorld().isAir(entity.getBlockPos().down()); + return state.isSolidSurface(pony.asWorld(), pos, entity, gravity > 0 ? Direction.UP : Direction.DOWN); } private boolean canKeepHanging() { @@ -184,7 +191,7 @@ public class Acrobatics implements Tickable, NbtSerialisable { return true; } return getHangingPosition().filter(hangingPos -> { - return (race != Race.BAT || hangingPos.equals(pony.getOrigin().down())) && canHangAt(hangingPos); + return (race != Race.BAT || hangingPos.equals(pony.asEntity().getBlockPos().up(pony.getPhysics().isGravityNegative() ? 1 : 0))) && canHangAt(hangingPos); }).isPresent(); } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java index c2789be6..568e1331 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java @@ -242,7 +242,7 @@ public class PlayerPhysics extends EntityPhysics implements Tickab public void tick() { super.tick(); - if (pony.isClientPlayer() && isFlying() && (pony.getJumpingHeuristic().hasChanged(Heuristic.ONCE) || pony.sneakingChanged())) { + if (pony.isClientPlayer() && (pony.getJumpingHeuristic().hasChanged(Heuristic.ONCE) || pony.sneakingChanged())) { Channel.FLIGHT_CONTROLS_INPUT.sendToServer(new MsgPlayerFlightControlsInput(pony)); } @@ -369,7 +369,7 @@ public class PlayerPhysics extends EntityPhysics implements Tickab pony.getMagicalReserves().getCharge().set(0); } - if (!creative) { + if (!creative && !pony.isClient()) { checkAvianTakeoffConditions(velocity); } } @@ -377,16 +377,17 @@ public class PlayerPhysics extends EntityPhysics implements Tickab tickGrounded(); } - if (!entity.isOnGround()) { - float heavyness = 1 - EnchantmentHelper.getEquipmentLevel(UEnchantments.HEAVY, entity) * 0.015F; - velocity.x /= heavyness; - velocity.z /= heavyness; - } - float maximum = 1.5F; velocity.x = MathHelper.clamp(velocity.x, -maximum, maximum); velocity.y = MathHelper.clamp(velocity.y, -maximum, maximum); velocity.z = MathHelper.clamp(velocity.z, -maximum, maximum); + + if (!entity.isOnGround()) { + float heavyness = 1 + EnchantmentHelper.getEquipmentLevel(UEnchantments.HEAVY, entity) * 0.009F; + velocity.x /= heavyness; + velocity.z /= heavyness; + } + entity.setVelocity(velocity.toImmutable()); if (isFlying() && !entity.isFallFlying() && !pony.getAcrobatics().isHanging() && pony.isClient()) { @@ -463,7 +464,7 @@ public class PlayerPhysics extends EntityPhysics implements Tickab entity.damage(entity.getDamageSources().generic(), 0.5F); } - if (type.isAvian()) { + if (type.isAvian() && !entity.getWorld().isClient) { if (pony.getObservedSpecies() != Race.BAT && entity.getWorld().random.nextInt(9000) == 0) { entity.dropItem(pony.getObservedSpecies() == Race.HIPPOGRIFF ? UItems.GRYPHON_FEATHER : UItems.PEGASUS_FEATHER); playSound(USounds.ENTITY_PLAYER_PEGASUS_MOLT, 0.3F, 1); @@ -530,7 +531,7 @@ public class PlayerPhysics extends EntityPhysics implements Tickab } private void playSound(SoundEvent sound, float volume, float pitch) { - entity.getWorld().playSoundFromEntity(entity, entity, sound, SoundCategory.PLAYERS, volume, pitch); + entity.getWorld().playSoundFromEntity(entity.getWorld().isClient ? entity : null, entity, sound, SoundCategory.PLAYERS, volume, pitch); } private void tickNaturalFlight(MutableVector velocity) { @@ -689,7 +690,7 @@ public class PlayerPhysics extends EntityPhysics implements Tickab if (entity.getWorld().hasRain(entity.getBlockPos())) { applyTurbulance(velocity); } else { - float targetUpdraft = (float)WeatherConditions.getUpdraft(new BlockPos.Mutable().set(entity.getBlockPos()), entity.getWorld()) / 3F; + float targetUpdraft = WeatherConditions.THERMAL_FIELD.getValue(entity.getWorld(), new BlockPos.Mutable().set(entity.getBlockPos())) / 3F; targetUpdraft *= 1 + motion; if (isGravityNegative()) { targetUpdraft *= -1; @@ -829,8 +830,8 @@ public class PlayerPhysics extends EntityPhysics implements Tickab .reduce(0, (u, pos) -> { if (pony.canModifyAt(pos, ModificationType.PHYSICAL)) { if (isEarthPonySmash) { - BlockDestructionManager.of(entity.getWorld()).damageBlock(pos, (int)entity.getWorld().getRandom().nextTriangular(5, 3)); - if (BlockDestructionManager.of(entity.getWorld()).getBlockDestruction(pos) >= 9) { + float destruction = BlockDestructionManager.of(entity.getWorld()).damageBlock(pos, (int)entity.getWorld().getRandom().nextTriangular(5, 3)); + if (destruction >= BlockDestructionManager.MAX_DAMAGE - 1 && pony.canModifyAt(pos, ModificationType.PHYSICAL)) { entity.getWorld().breakBlock(pos, true); } } else { @@ -862,7 +863,7 @@ public class PlayerPhysics extends EntityPhysics implements Tickab if (isFlying()) { playSound(USounds.ENTITY_PLAYER_PEGASUS_DASH, 1, 1); } else { - playSound(USounds.ENTITY_PLAYER_EARTHPONY_DASH, 2, 0.3F); + playSound(USounds.ENTITY_PLAYER_EARTHPONY_DASH, 2, 1.3F); } } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java index cfe236a9..ca4aa870 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java @@ -224,6 +224,11 @@ public class Pony extends Living implements Copyable, Update return compositeRace; } + @Override + public boolean collidesWithClouds() { + return getCompositeRace().canInteractWithClouds() || entity.isCreative(); + } + @Override public void setSpecies(Race race) { race = race.validate(entity); @@ -597,7 +602,7 @@ public class Pony extends Living implements Copyable, Update float lightScale = light / 15F; float approachFactor = ((velocityScale + lightScale) / 2F); - if (approachFactor < (entity.isSneaking() ? 0.8F : 0.6F)) { + if (approachFactor < (entity.isSneaking() ? 0.8F : 0.3F)) { return false; } } @@ -703,7 +708,7 @@ public class Pony extends Living implements Copyable, Update if (EffectUtils.hasExtraDefenses(entity)) { double radius = distance / 10; if (radius > 0) { - EarthPonyStompAbility.spawnEffectAround(entity, entity.getSteppingPos(), radius, radius); + EarthPonyStompAbility.spawnEffectAround(this, entity, entity.getSteppingPos(), radius, radius); } } @@ -807,7 +812,7 @@ public class Pony extends Living implements Copyable, Update public ActionResult canSleepNow() { if (asWorld().getGameRules().getBoolean(UGameRules.DO_NOCTURNAL_BAT_PONIES) && getSpecies().isNocturnal()) { - return asWorld().isDay() ? ActionResult.SUCCESS : ActionResult.FAIL; + return asWorld().isDay() || asWorld().getAmbientDarkness() >= 4 ? ActionResult.SUCCESS : ActionResult.FAIL; } return ActionResult.PASS; diff --git a/src/main/java/com/minelittlepony/unicopia/item/AmuletItem.java b/src/main/java/com/minelittlepony/unicopia/item/AmuletItem.java index 8e0673f7..a434863f 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/AmuletItem.java +++ b/src/main/java/com/minelittlepony/unicopia/item/AmuletItem.java @@ -101,7 +101,7 @@ public class AmuletItem extends WearableItem implements ChargeableItem { } public static TrinketsDelegate.EquippedStack get(LivingEntity entity) { - return TrinketsDelegate.getInstance(entity).getEquipped(entity, TrinketsDelegate.NECKLACE) + return TrinketsDelegate.getInstance(entity).getEquipped(entity, TrinketsDelegate.NECKLACE, stack -> stack.getItem() instanceof AmuletItem) .findFirst() .orElse(TrinketsDelegate.EquippedStack.EMPTY); } diff --git a/src/main/java/com/minelittlepony/unicopia/item/HeavyProjectileItem.java b/src/main/java/com/minelittlepony/unicopia/item/HeavyProjectileItem.java index 16797e43..e76a2920 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/HeavyProjectileItem.java +++ b/src/main/java/com/minelittlepony/unicopia/item/HeavyProjectileItem.java @@ -18,12 +18,13 @@ public class HeavyProjectileItem extends ProjectileItem { @Override public PhysicsBodyProjectileEntity createProjectile(ItemStack stack, World world, @Nullable PlayerEntity player) { - PhysicsBodyProjectileEntity projectile = player == null ? new PhysicsBodyProjectileEntity(world) : new PhysicsBodyProjectileEntity(world, player); + PhysicsBodyProjectileEntity projectile = player == null + ? new PhysicsBodyProjectileEntity(world, stack.copyWithCount(1)) + : new PhysicsBodyProjectileEntity(world, player, stack.copyWithCount(1)); if (player != null) { projectile.setVelocity(player, player.getPitch(), player.getYaw(), 0, 1.5F, 1); } projectile.pickupType = PersistentProjectileEntity.PickupPermission.ALLOWED; - projectile.setStack(stack.copy().split(1)); return projectile; } diff --git a/src/main/java/com/minelittlepony/unicopia/item/PolearmItem.java b/src/main/java/com/minelittlepony/unicopia/item/PolearmItem.java index 5dc90908..85517dc5 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/PolearmItem.java +++ b/src/main/java/com/minelittlepony/unicopia/item/PolearmItem.java @@ -7,14 +7,17 @@ import com.google.common.collect.Multimap; import com.minelittlepony.unicopia.UTags; import com.minelittlepony.unicopia.entity.Living; import com.minelittlepony.unicopia.entity.mob.UEntityAttributes; +import com.minelittlepony.unicopia.item.enchantment.CustomEnchantableItem; import net.minecraft.block.*; +import net.minecraft.enchantment.Enchantment; +import net.minecraft.enchantment.Enchantments; import net.minecraft.entity.EquipmentSlot; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.attribute.*; import net.minecraft.item.*; -public class PolearmItem extends SwordItem { +public class PolearmItem extends SwordItem implements CustomEnchantableItem { static final UUID ATTACK_RANGE_MODIFIER_ID = UUID.fromString("A7B3659C-AA74-469C-963A-09A391DCAA0F"); private final Multimap attributeModifiers; @@ -65,4 +68,9 @@ public class PolearmItem extends SwordItem { return true; } + + @Override + public boolean isAcceptableEnchant(ItemStack stack, Enchantment enchantment) { + return enchantment != Enchantments.SWEEPING; + } } diff --git a/src/main/java/com/minelittlepony/unicopia/item/SpellbookItem.java b/src/main/java/com/minelittlepony/unicopia/item/SpellbookItem.java index 1fefc4e8..a853ffa3 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/SpellbookItem.java +++ b/src/main/java/com/minelittlepony/unicopia/item/SpellbookItem.java @@ -20,6 +20,8 @@ import net.minecraft.util.TypedActionResult; import net.minecraft.util.math.BlockPointer; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; +import net.minecraft.util.math.Position; +import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; public class SpellbookItem extends BookItem implements Dispensable { @@ -29,15 +31,18 @@ public class SpellbookItem extends BookItem implements Dispensable { } @Override - public TypedActionResult dispenseStack(BlockPointer source, ItemStack stack) { - Direction facing = source.state().get(DispenserBlock.FACING); - BlockPos pos = source.pos().offset(facing); + public TypedActionResult dispenseStack(BlockPointer pointer, ItemStack stack) { + Direction facing = pointer.state().get(DispenserBlock.FACING); + Position pos = DispenserBlock.getOutputLocation(pointer); float yaw = facing.getOpposite().asRotation(); - placeBook(stack, source.world(), pos.getX(), pos.getY(), pos.getZ(), yaw, null); - stack.decrement(1); + if (placeBook(stack, pointer.world(), pos, yaw, null)) { + stack.decrement(1); - return new TypedActionResult<>(ActionResult.SUCCESS, stack); + return new TypedActionResult<>(ActionResult.SUCCESS, stack); + } + + return new TypedActionResult<>(ActionResult.FAIL, stack); } @Override @@ -49,24 +54,28 @@ public class SpellbookItem extends BookItem implements Dispensable { if (!context.getWorld().isClient) { BlockPos pos = context.getBlockPos().offset(context.getSide()); - placeBook(context.getStack(), context.getWorld(), pos.getX(), pos.getY(), pos.getZ(), context.getPlayerYaw() + 180, player); + if (placeBook(context.getStack(), context.getWorld(), Vec3d.ofBottomCenter(pos), context.getPlayerYaw() + 180, player)) { + if (!player.getAbilities().creativeMode) { + player.getStackInHand(context.getHand()).decrement(1); + } - if (!player.getAbilities().creativeMode) { - player.getStackInHand(context.getHand()).decrement(1); + return ActionResult.SUCCESS; } - - return ActionResult.SUCCESS; } return ActionResult.PASS; } - private static void placeBook(ItemStack stack, World world, int x, int y, int z, float yaw, @Nullable Entity placer) { + private static boolean placeBook(ItemStack stack, World world, Position pos, float yaw, @Nullable Entity placer) { SpellbookEntity book = UEntities.SPELLBOOK.create(world); - book.refreshPositionAndAngles(x + 0.5, y, z + 0.5, 0, 0); + book.refreshPositionAndAngles(pos.getX(), pos.getY(), pos.getZ(), 0, 0); book.setHeadYaw(yaw); book.setYaw(yaw); + if (!book.canSpawn(world)) { + return false; + } + @Nullable NbtCompound tag = stack.getSubNbt("spellbookState"); if (tag != null) { @@ -80,6 +89,8 @@ public class SpellbookItem extends BookItem implements Dispensable { altar.generateDecorations(world); UCriteria.LIGHT_ALTAR.trigger(placer); }); + + return true; } } diff --git a/src/main/java/com/minelittlepony/unicopia/item/UItems.java b/src/main/java/com/minelittlepony/unicopia/item/UItems.java index c1f8081e..083e4ef8 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/UItems.java +++ b/src/main/java/com/minelittlepony/unicopia/item/UItems.java @@ -146,12 +146,12 @@ public interface UItems { Item COPPER_HORSE_SHOE = register("copper_horse_shoe", new HorseShoeItem(new Item.Settings().maxDamage(250), 6, 0.5F, 0.8F), ItemGroups.COMBAT); Item NETHERITE_HORSE_SHOE = register("netherite_horse_shoe", new HorseShoeItem(new Item.Settings().maxDamage(800), 3, 0.7F, 1.2F), ItemGroups.COMBAT); - Item WOODEN_POLEARM = register("wooden_polearm", new PolearmItem(ToolMaterials.WOOD, 2, -3.6F, 2, new Item.Settings()), ItemGroups.COMBAT); - Item STONE_POLEARM = register("stone_polearm", new PolearmItem(ToolMaterials.STONE, 2, -3.6F, 2, new Item.Settings()), ItemGroups.COMBAT); - Item IRON_POLEARM = register("iron_polearm", new PolearmItem(ToolMaterials.IRON, 2, -3.6F, 3, new Item.Settings()), ItemGroups.COMBAT); - Item GOLDEN_POLEARM = register("golden_polearm", new PolearmItem(ToolMaterials.GOLD, 2, -3.6F, 4, new Item.Settings()), ItemGroups.COMBAT); - Item DIAMOND_POLEARM = register("diamond_polearm", new PolearmItem(ToolMaterials.DIAMOND, 2, -3.6F, 5, new Item.Settings()), ItemGroups.COMBAT); - Item NETHERITE_POLEARM = register("netherite_polearm", new PolearmItem(ToolMaterials.NETHERITE, 2, -3.6F, 5, new Item.Settings().fireproof()), ItemGroups.COMBAT); + Item WOODEN_POLEARM = register("wooden_polearm", new PolearmItem(ToolMaterials.WOOD, 2, -3.2F, 2, new Item.Settings()), ItemGroups.COMBAT); + Item STONE_POLEARM = register("stone_polearm", new PolearmItem(ToolMaterials.STONE, 2, -3.2F, 2, new Item.Settings()), ItemGroups.COMBAT); + Item IRON_POLEARM = register("iron_polearm", new PolearmItem(ToolMaterials.IRON, 2, -3.1F, 3, new Item.Settings()), ItemGroups.COMBAT); + Item GOLDEN_POLEARM = register("golden_polearm", new PolearmItem(ToolMaterials.GOLD, 3, -3F, 4, new Item.Settings()), ItemGroups.COMBAT); + Item DIAMOND_POLEARM = register("diamond_polearm", new PolearmItem(ToolMaterials.DIAMOND, 3, -3F, 5, new Item.Settings()), ItemGroups.COMBAT); + Item NETHERITE_POLEARM = register("netherite_polearm", new PolearmItem(ToolMaterials.NETHERITE, 3, -3F, 6, new Item.Settings().fireproof()), ItemGroups.COMBAT); Item LOOT_BUG_SPAWN_EGG = register("loot_bug_spawn_egg", new SpawnEggItem(UEntities.LOOT_BUG, 0x3C9D14, 0xE66F16, new Item.Settings()), ItemGroups.SPAWN_EGGS); Item BUTTERFLY_SPAWN_EGG = register("butterfly_spawn_egg", new SpawnEggItem(UEntities.BUTTERFLY, 0x222200, 0xAAEEFF, new Item.Settings()), ItemGroups.SPAWN_EGGS); diff --git a/src/main/java/com/minelittlepony/unicopia/item/enchantment/CustomEnchantableItem.java b/src/main/java/com/minelittlepony/unicopia/item/enchantment/CustomEnchantableItem.java new file mode 100644 index 00000000..5fbec700 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/item/enchantment/CustomEnchantableItem.java @@ -0,0 +1,8 @@ +package com.minelittlepony.unicopia.item.enchantment; + +import net.minecraft.enchantment.Enchantment; +import net.minecraft.item.ItemStack; + +public interface CustomEnchantableItem { + boolean isAcceptableEnchant(ItemStack stack, Enchantment enchantment); +} diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/MixinEnchantment.java b/src/main/java/com/minelittlepony/unicopia/mixin/MixinEnchantment.java new file mode 100644 index 00000000..5143711c --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/mixin/MixinEnchantment.java @@ -0,0 +1,21 @@ +package com.minelittlepony.unicopia.mixin; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import com.minelittlepony.unicopia.item.enchantment.CustomEnchantableItem; + +import net.minecraft.enchantment.Enchantment; +import net.minecraft.item.ItemStack; + +@Mixin(Enchantment.class) +abstract class MixinEnchantment { + @Inject(method = "isAcceptableItem", at = @At("HEAD"), cancellable = true) + private void onIsAcceptableItem(ItemStack stack, CallbackInfoReturnable info) { + if (stack.getItem() instanceof CustomEnchantableItem item && !item.isAcceptableEnchant(stack, (Enchantment)(Object)this)) { + info.setReturnValue(false); + } + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/MixinEnchantmentHelper.java b/src/main/java/com/minelittlepony/unicopia/mixin/MixinEnchantmentHelper.java index 4458399c..0dd1aacf 100644 --- a/src/main/java/com/minelittlepony/unicopia/mixin/MixinEnchantmentHelper.java +++ b/src/main/java/com/minelittlepony/unicopia/mixin/MixinEnchantmentHelper.java @@ -1,5 +1,7 @@ package com.minelittlepony.unicopia.mixin; +import java.util.List; + import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -9,7 +11,9 @@ import com.minelittlepony.unicopia.entity.player.Pony; import net.minecraft.enchantment.Enchantment; import net.minecraft.enchantment.EnchantmentHelper; +import net.minecraft.enchantment.EnchantmentLevelEntry; import net.minecraft.entity.LivingEntity; +import net.minecraft.item.ItemStack; @Mixin(EnchantmentHelper.class) abstract class MixinEnchantmentHelper { @@ -23,4 +27,9 @@ abstract class MixinEnchantmentHelper { } }); } + + @Inject(method = "getPossibleEntries", at = @At("RETURN")) + private static void onGetPossibleEntries(int power, ItemStack stack, boolean treasureAllowed, CallbackInfoReturnable> info) { + info.getReturnValue().removeIf(entry -> !entry.enchantment.isAcceptableItem(stack)); + } } diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/MixinHeightmap.java b/src/main/java/com/minelittlepony/unicopia/mixin/MixinHeightmap.java new file mode 100644 index 00000000..99da4dde --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/mixin/MixinHeightmap.java @@ -0,0 +1,21 @@ +package com.minelittlepony.unicopia.mixin; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import com.minelittlepony.unicopia.block.cloud.CloudLike; + +import net.minecraft.block.BlockState; +import net.minecraft.world.Heightmap; + +@Mixin(Heightmap.class) +abstract class MixinHeightmap { + @Inject(method = "method_16682", at = @At("HEAD"), cancellable = true) + private static void excludeCloudsFromWorldSurfaceHeightMap(BlockState state, CallbackInfoReturnable info) { + if (state.getBlock() instanceof CloudLike) { + info.setReturnValue(false); + } + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/MixinWorld.java b/src/main/java/com/minelittlepony/unicopia/mixin/MixinWorld.java index 99ca9150..f0377bb4 100644 --- a/src/main/java/com/minelittlepony/unicopia/mixin/MixinWorld.java +++ b/src/main/java/com/minelittlepony/unicopia/mixin/MixinWorld.java @@ -1,21 +1,32 @@ package com.minelittlepony.unicopia.mixin; import java.util.function.Supplier; + +import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + import com.minelittlepony.unicopia.entity.duck.RotatedView; import com.minelittlepony.unicopia.server.world.BlockDestructionManager; +import com.minelittlepony.unicopia.server.world.WeatherAccess; + import net.minecraft.entity.Entity; +import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraft.world.WorldAccess; @Mixin(World.class) -abstract class MixinWorld implements WorldAccess, BlockDestructionManager.Source, RotatedView { - +abstract class MixinWorld implements WorldAccess, BlockDestructionManager.Source, RotatedView, WeatherAccess { private final Supplier destructions = BlockDestructionManager.create((World)(Object)this); + @Nullable + private Float rainGradientOverride; + @Nullable + private Float thunderGradientOverride; + private boolean mirrorEntityStatuses; @Override @@ -28,11 +39,36 @@ abstract class MixinWorld implements WorldAccess, BlockDestructionManager.Source return destructions.get(); } + @Override + public void setWeatherOverride(Float rain, Float thunder) { + rainGradientOverride = rain; + thunderGradientOverride = thunder; + } + @Inject(method = "sendEntityStatus(Lnet/minecraft/entity/Entity;B)V", at = @At("HEAD")) private void onSendEntityStatus(Entity entity, byte status, CallbackInfo info) { if (mirrorEntityStatuses) { entity.handleStatus(status); } } + + @Inject(method = "getThunderGradient", at = @At("HEAD"), cancellable = true) + private void onGetThunderGradient(float delta, CallbackInfoReturnable info) { + if (thunderGradientOverride != null) { + info.setReturnValue(thunderGradientOverride * ((World)(Object)this).getRainGradient(delta)); + } + } + + @Inject(method = "getRainGradient", at = @At("HEAD"), cancellable = true) + private void onGetRainGradient(float delta, CallbackInfoReturnable info) { + if (rainGradientOverride != null) { + info.setReturnValue(rainGradientOverride); + } + } + + @Inject(method = "hasRain", at = @At("RETURN"), cancellable = true) + private void onHasRain(BlockPos pos, CallbackInfoReturnable info) { + info.setReturnValue((info.getReturnValue() && isBelowCloudLayer(pos)) || isInRangeOfStorm(pos)); + } } diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinGameRenderer.java b/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinGameRenderer.java index 2fe4abe2..d9effcf6 100644 --- a/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinGameRenderer.java +++ b/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinGameRenderer.java @@ -6,7 +6,6 @@ import org.spongepowered.asm.mixin.injection.At.Shift; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import com.minelittlepony.unicopia.EquinePredicates; import com.minelittlepony.unicopia.client.BatEyesApplicator; import com.minelittlepony.unicopia.client.UnicopiaClient; import com.minelittlepony.unicopia.client.render.shader.ViewportShader; @@ -17,7 +16,6 @@ import net.minecraft.client.render.GameRenderer; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.util.math.RotationAxis; import net.minecraft.entity.LivingEntity; -import net.minecraft.entity.effect.StatusEffects; import net.minecraft.resource.SynchronousResourceReloader; @Mixin(value = GameRenderer.class, priority = Integer.MAX_VALUE) @@ -46,21 +44,11 @@ abstract class MixinGameRenderer implements AutoCloseable, SynchronousResourceRe BatEyesApplicator.INSTANCE.disable(); } - @Inject(method = "getNightVisionStrength(Lnet/minecraft/entity/LivingEntity;F)F", - at = @At("HEAD"), - cancellable = true) - private static void onGetNightVisionStrengthHead(LivingEntity entity, float tickDelta, CallbackInfoReturnable info) { - if (!entity.hasStatusEffect(StatusEffects.NIGHT_VISION)) { - info.setReturnValue(UnicopiaClient.getWorldBrightness(0)); - } - } @Inject(method = "getNightVisionStrength(Lnet/minecraft/entity/LivingEntity;F)F", at = @At("RETURN"), cancellable = true) private static void onGetNightVisionStrengthReturn(LivingEntity entity, float tickDelta, CallbackInfoReturnable info) { - if (entity.hasStatusEffect(StatusEffects.NIGHT_VISION) && EquinePredicates.PLAYER_BAT.test(entity)) { - info.setReturnValue(UnicopiaClient.getWorldBrightness(info.getReturnValueF())); - } + info.setReturnValue(BatEyesApplicator.INSTANCE.getWorldBrightness(info.getReturnValueF(), entity, tickDelta)); } @Inject(method = "render", diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinWorldRenderer.java b/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinWorldRenderer.java index edcc852d..4dcaf112 100644 --- a/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinWorldRenderer.java +++ b/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinWorldRenderer.java @@ -15,6 +15,8 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import com.minelittlepony.unicopia.client.ClientBlockDestructionManager; import com.minelittlepony.unicopia.client.UnicopiaClient; +import com.minelittlepony.unicopia.server.world.WeatherAccess; + import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import net.minecraft.client.render.BlockBreakingInfo; import net.minecraft.client.render.Camera; @@ -22,7 +24,10 @@ import net.minecraft.client.render.WorldRenderer; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.world.ClientWorld; import net.minecraft.resource.SynchronousResourceReloader; +import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.RotationAxis; +import net.minecraft.world.biome.Biome; +import net.minecraft.world.biome.Biome.Precipitation; @Mixin(value = WorldRenderer.class, priority = 1001) abstract class MixinWorldRenderer implements SynchronousResourceReloader, AutoCloseable, ClientBlockDestructionManager.Source { @@ -80,4 +85,13 @@ abstract class MixinWorldRenderer implements SynchronousResourceReloader, AutoCl matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(UnicopiaClient.getInstance().getSkyAngleDelta(tickDelta))); matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(UnicopiaClient.getInstance().tangentalSkyAngle.getValue())); } + + @Redirect(method = "renderWeather", at = @At(value = "INVOKE", target = "net/minecraft/world/biome/Biome.getPrecipitation(Lnet/minecraft/util/math/BlockPos;)Lnet/minecraft/world/biome/Biome$Precipitation;")) + private Biome.Precipitation modifyPrecipitation(Biome biome, BlockPos pos) { + Biome.Precipitation precipitation = biome.getPrecipitation(pos); + if (!((WeatherAccess)world).isBelowClientCloudLayer(pos)) { + return Precipitation.NONE; + } + return precipitation; + } } diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/server/MixinPathNodeMaker.java b/src/main/java/com/minelittlepony/unicopia/mixin/server/MixinPathNodeMaker.java new file mode 100644 index 00000000..9e18310c --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/mixin/server/MixinPathNodeMaker.java @@ -0,0 +1,26 @@ +package com.minelittlepony.unicopia.mixin.server; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import com.minelittlepony.unicopia.EquineContext; +import com.minelittlepony.unicopia.InteractionManager; + +import net.minecraft.entity.ai.pathing.PathNodeMaker; +import net.minecraft.entity.mob.MobEntity; +import net.minecraft.world.chunk.ChunkCache; + +@Mixin(PathNodeMaker.class) +abstract class MixinPathNodeMaker { + @Inject(method = "init", at = @At("HEAD")) + private void onInit(ChunkCache cachedWorld, MobEntity entity, CallbackInfo info) { + InteractionManager.getInstance().setEquineContext(EquineContext.of(entity)); + } + + @Inject(method = "clear", at = @At("HEAD")) + private void onClear(CallbackInfo info) { + InteractionManager.getInstance().clearEquineContext(); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/server/MixinPlayerManager.java b/src/main/java/com/minelittlepony/unicopia/mixin/server/MixinPlayerManager.java index 0c845c1c..271bf40a 100644 --- a/src/main/java/com/minelittlepony/unicopia/mixin/server/MixinPlayerManager.java +++ b/src/main/java/com/minelittlepony/unicopia/mixin/server/MixinPlayerManager.java @@ -44,6 +44,6 @@ abstract class MixinPlayerManager { @Inject(method = "respawnPlayer", at = @At("RETURN")) private void afterRespawnPlayer(ServerPlayerEntity player, boolean alive, CallbackInfoReturnable info) { - InteractionManager.getInstance().setEquineContext(EquineContext.ABSENT); + InteractionManager.getInstance().clearEquineContext(); } } diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/server/MixinServerPlayerEntity.java b/src/main/java/com/minelittlepony/unicopia/mixin/server/MixinServerPlayerEntity.java index 2ae21fe5..30a69af2 100644 --- a/src/main/java/com/minelittlepony/unicopia/mixin/server/MixinServerPlayerEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/mixin/server/MixinServerPlayerEntity.java @@ -52,4 +52,9 @@ abstract class MixinServerPlayerEntity extends PlayerEntity implements ScreenHan private void onUpdateKilledAdvancementCriterion(Entity entityKilled, int score, DamageSource damageSource, CallbackInfo info) { get().onKill(entityKilled, damageSource); } + + @Inject(method = "startRiding(Lnet/minecraft/entity/Entity;Z)Z", at = @At("HEAD")) + private void onStartRiding(Entity entity, boolean force, CallbackInfoReturnable info) { + get().getPhysics().cancelFlight(true); + } } diff --git a/src/main/java/com/minelittlepony/unicopia/network/track/TrackableDataType.java b/src/main/java/com/minelittlepony/unicopia/network/track/TrackableDataType.java index 9c5c6b74..e918e3e7 100644 --- a/src/main/java/com/minelittlepony/unicopia/network/track/TrackableDataType.java +++ b/src/main/java/com/minelittlepony/unicopia/network/track/TrackableDataType.java @@ -11,8 +11,10 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import net.minecraft.nbt.NbtCompound; import net.minecraft.network.PacketByteBuf; +import net.minecraft.registry.RegistryKey; import net.minecraft.util.Identifier; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; public record TrackableDataType(int id, PacketCodec codec) { private static final Int2ObjectMap> REGISTRY = new Int2ObjectOpenHashMap<>(); @@ -26,8 +28,16 @@ public record TrackableDataType(int id, PacketCodec codec) { public static final TrackableDataType> RAW_BYTES = of(new Identifier("raw_bytes"), PacketCodec.RAW_BYTES.asOptional()); public static final TrackableDataType> OPTIONAL_POS = of(new Identifier("optional_pos"), PacketCodec.OPTIONAL_POS); + public static final TrackableDataType> OPTIONAL_VECTOR = of(new Identifier("optional_vector"), PacketCodec.OPTIONAL_VECTOR); + private static final TrackableDataType>> OPTIONAL_REGISTRY_KEY = of(new Identifier("optional_registry_key"), PacketCodec.OPTIONAL_REGISTRY_KEY); + public static final TrackableDataType RACE = TrackableDataType.of(Unicopia.id("race"), PacketCodec.ofRegistry(Race.REGISTRY)); + @SuppressWarnings({ "rawtypes", "unchecked" }) + public static TrackableDataType>> ofRegistryKey() { + return (TrackableDataType)OPTIONAL_REGISTRY_KEY; + } + @SuppressWarnings("unchecked") public static TrackableDataType of(PacketByteBuf buffer) { int id = buffer.readInt(); diff --git a/src/main/java/com/minelittlepony/unicopia/projectile/PhysicsBodyProjectileEntity.java b/src/main/java/com/minelittlepony/unicopia/projectile/PhysicsBodyProjectileEntity.java index 19b3c2bc..a831c804 100644 --- a/src/main/java/com/minelittlepony/unicopia/projectile/PhysicsBodyProjectileEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/projectile/PhysicsBodyProjectileEntity.java @@ -55,16 +55,18 @@ public class PhysicsBodyProjectileEntity extends PersistentProjectileEntity impl private RegistryKey damageType = UDamageTypes.ROCK; + public PhysicsBodyProjectileEntity(World world, ItemStack stack) { + super(UEntities.MUFFIN, world); + setStack(stack); + } + public PhysicsBodyProjectileEntity(EntityType type, World world) { super(type, world); } - public PhysicsBodyProjectileEntity(World world) { - this(UEntities.MUFFIN, world); - } - - public PhysicsBodyProjectileEntity(World world, @Nullable LivingEntity thrower) { + public PhysicsBodyProjectileEntity(World world, @Nullable LivingEntity thrower, ItemStack stack) { super(UEntities.MUFFIN, thrower, world); + setStack(stack); } @Override @@ -75,7 +77,7 @@ public class PhysicsBodyProjectileEntity extends PersistentProjectileEntity impl } public void setStack(ItemStack stack) { - getDataTracker().set(ITEM, stack); + getDataTracker().set(ITEM, stack.copy()); } @Override @@ -89,7 +91,7 @@ public class PhysicsBodyProjectileEntity extends PersistentProjectileEntity impl @Override protected ItemStack asItemStack() { - return getStack(); + return getStack().copy(); } public void setBouncy() { @@ -273,7 +275,7 @@ public class PhysicsBodyProjectileEntity extends PersistentProjectileEntity impl super.writeCustomDataToNbt(nbt); ItemStack stack = getStack(); if (!stack.isEmpty()) { - nbt.put("Item", stack.writeNbt(new NbtCompound())); + nbt.put("item", stack.writeNbt(new NbtCompound())); } nbt.putString("damageType", damageType.getValue().toString()); } @@ -281,7 +283,7 @@ public class PhysicsBodyProjectileEntity extends PersistentProjectileEntity impl @Override public void readCustomDataFromNbt(NbtCompound nbt) { super.readCustomDataFromNbt(nbt); - setStack(ItemStack.fromNbt(nbt.getCompound("Item"))); + setStack(ItemStack.fromNbt(nbt.getCompound("item"))); if (nbt.contains("damageType", NbtElement.STRING_TYPE)) { Optional.ofNullable(Identifier.tryParse(nbt.getString("damageType"))).ifPresent(id -> { setDamageType(RegistryKey.of(RegistryKeys.DAMAGE_TYPE, id)); diff --git a/src/main/java/com/minelittlepony/unicopia/projectile/Projectile.java b/src/main/java/com/minelittlepony/unicopia/projectile/Projectile.java index c8b0c2a2..34f831ea 100644 --- a/src/main/java/com/minelittlepony/unicopia/projectile/Projectile.java +++ b/src/main/java/com/minelittlepony/unicopia/projectile/Projectile.java @@ -38,12 +38,12 @@ public interface Projectile extends ItemConvertible { default TypedActionResult triggerThrow(World world, PlayerEntity player, Hand hand) { ItemStack stack = player.getStackInHand(hand); - SoundEmitter.playSoundAt(player, - getThrowSound(stack), SoundCategory.NEUTRAL, - 0.5F, - 0.4F / (world.random.nextFloat() * 0.4F + 0.8F)); - if (!world.isClient) { + SoundEmitter.playSoundAt(player, + getThrowSound(stack), SoundCategory.NEUTRAL, + 0.5F, + 0.4F / (world.random.nextFloat() * 0.4F + 0.8F)); + world.spawnEntity(createProjectile(stack.copyWithCount(1), world, player)); } diff --git a/src/main/java/com/minelittlepony/unicopia/server/world/BlockDestructionManager.java b/src/main/java/com/minelittlepony/unicopia/server/world/BlockDestructionManager.java index 974abaef..25464839 100644 --- a/src/main/java/com/minelittlepony/unicopia/server/world/BlockDestructionManager.java +++ b/src/main/java/com/minelittlepony/unicopia/server/world/BlockDestructionManager.java @@ -17,6 +17,7 @@ import net.minecraft.nbt.NbtCompound; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.util.Identifier; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; import net.minecraft.world.World; public class BlockDestructionManager implements Tickable { @@ -54,7 +55,7 @@ public class BlockDestructionManager implements Tickable { if (amount == 0) { return getBlockDestruction(pos); } - amount = Math.max(getBlockDestruction(pos), 0) + amount; + amount = MathHelper.clamp(Math.max(getBlockDestruction(pos), 0) + amount, 0, MAX_DAMAGE); setBlockDestruction(pos, amount); return amount; } diff --git a/src/main/java/com/minelittlepony/unicopia/server/world/Ether.java b/src/main/java/com/minelittlepony/unicopia/server/world/Ether.java index 840e66fa..08c6a9a2 100644 --- a/src/main/java/com/minelittlepony/unicopia/server/world/Ether.java +++ b/src/main/java/com/minelittlepony/unicopia/server/world/Ether.java @@ -13,14 +13,18 @@ import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.Spell; import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; import com.minelittlepony.unicopia.entity.EntityReference; +import com.minelittlepony.unicopia.server.world.chunk.PositionalDataMap; import com.minelittlepony.unicopia.util.NbtSerialisable; +import com.minelittlepony.unicopia.util.Tickable; + import net.minecraft.nbt.*; import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; import net.minecraft.world.PersistentState; import net.minecraft.world.World; -public class Ether extends PersistentState { +public class Ether extends PersistentState implements Tickable { private static final Identifier ID = Unicopia.id("ether"); public static Ether get(World world) { @@ -28,6 +32,7 @@ public class Ether extends PersistentState { } private final Map>>> endpoints; + private final PositionalDataMap> positionData = new PositionalDataMap<>(); private final Object locker = new Object(); @@ -70,23 +75,36 @@ public class Ether extends PersistentState { markDirty(); return new Entry<>(spell, caster); }); - if (entry.removed) { - entry.removed = false; - markDirty(); - } + if (entry.spell.get() != spell) { entry.spell = new WeakReference<>(spell); markDirty(); } + if (entry.removed) { + entry.removed = false; + positionData.update(entry); + markDirty(); + } return entry; } } + @Override + public void tick() { + endpoints.values().forEach(byType -> { + byType.values().forEach(entries -> { + entries.values().forEach(Entry::update); + }); + }); + } + public void remove(SpellType spellType, UUID entityId) { synchronized (locker) { endpoints.computeIfPresent(spellType.getId(), (typeId, entries) -> { - if (entries.remove(entityId) != null) { + Map> data = entries.remove(entityId); + if (data != null) { markDirty(); + data.values().forEach(positionData::remove); } return entries.isEmpty() ? null : entries; }); @@ -150,6 +168,10 @@ public class Ether extends PersistentState { return false; } + public Set> getAtPosition(BlockPos pos) { + return world.isClient() ? Set.of() : positionData.getState(pos); + } + private void pruneNodes() { this.endpoints.values().removeIf(entities -> { entities.values().removeIf(spells -> { @@ -160,7 +182,7 @@ public class Ether extends PersistentState { }); } - public class Entry implements NbtSerialisable { + public class Entry implements PositionalDataMap.Hotspot, NbtSerialisable { public final EntityReference entity; @Nullable @@ -176,6 +198,9 @@ public class Ether extends PersistentState { private final Set claimants = new HashSet<>(); + private BlockPos currentPos = BlockPos.ORIGIN; + private BlockPos previousPos = BlockPos.ORIGIN; + private Entry(NbtElement nbt) { this.entity = new EntityReference<>(); this.spell = new WeakReference<>(null); @@ -186,6 +211,15 @@ public class Ether extends PersistentState { this.entity = new EntityReference<>(caster.asEntity()); this.spell = new WeakReference<>(spell); spellId = spell.getUuid(); + update(); + } + + void update() { + previousPos = currentPos; + currentPos = entity.getTarget().map(t -> BlockPos.ofFloored(t.pos())).orElse(BlockPos.ORIGIN); + if (!currentPos.equals(previousPos)) { + positionData.update(this); + } } public boolean hasChanged() { @@ -216,6 +250,13 @@ public class Ether extends PersistentState { markDirty(); } + + @Override + public BlockPos getCenter() { + return currentPos; + } + + @Override public float getRadius() { return radius; } @@ -223,6 +264,9 @@ public class Ether extends PersistentState { public void setRadius(float radius) { if (!MathHelper.approximatelyEquals(this.radius, radius)) { this.radius = radius; + if ((int)radius != (int)this.radius) { + positionData.update(this); + } changed.set(true); } markDirty(); @@ -247,6 +291,7 @@ public class Ether extends PersistentState { public void markDead() { Unicopia.LOGGER.debug("Marking " + entity.getTarget().orElse(null) + " as dead"); removed = true; + positionData.remove(this); claimants.clear(); markDirty(); } diff --git a/src/main/java/com/minelittlepony/unicopia/server/world/UWorldGen.java b/src/main/java/com/minelittlepony/unicopia/server/world/UWorldGen.java index c7c781a6..2c8d1903 100644 --- a/src/main/java/com/minelittlepony/unicopia/server/world/UWorldGen.java +++ b/src/main/java/com/minelittlepony/unicopia/server/world/UWorldGen.java @@ -6,7 +6,10 @@ import java.util.function.Consumer; import com.minelittlepony.unicopia.Unicopia; import com.minelittlepony.unicopia.block.ShellsBlock; import com.minelittlepony.unicopia.block.UBlocks; +import com.minelittlepony.unicopia.server.world.gen.CaveCarvingStructureProcessor; +import com.minelittlepony.unicopia.server.world.gen.CloudCarver; import com.minelittlepony.unicopia.server.world.gen.OverworldBiomeSelectionCallback; +import com.minelittlepony.unicopia.server.world.gen.SurfaceGrowthStructureProcessor; import com.minelittlepony.unicopia.util.registry.DynamicRegistry; import net.fabricmc.fabric.api.biome.v1.BiomeModifications; @@ -23,6 +26,7 @@ import net.minecraft.registry.RegistryKeys; import net.minecraft.registry.tag.BiomeTags; import net.minecraft.sound.BiomeMoodSound; import net.minecraft.sound.SoundEvents; +import net.minecraft.structure.processor.StructureProcessorType; import net.minecraft.util.collection.DataPool; import net.minecraft.util.math.Direction; import net.minecraft.util.math.Vec3i; @@ -35,6 +39,9 @@ import net.minecraft.world.biome.OverworldBiomeCreator; import net.minecraft.world.biome.SpawnSettings; import net.minecraft.world.gen.GenerationStep; import net.minecraft.world.gen.blockpredicate.BlockPredicate; +import net.minecraft.world.gen.carver.Carver; +import net.minecraft.world.gen.carver.CaveCarverConfig; +import net.minecraft.world.gen.carver.ConfiguredCarver; import net.minecraft.world.gen.feature.ConfiguredFeatures; import net.minecraft.world.gen.feature.DefaultBiomeFeatures; import net.minecraft.world.gen.feature.Feature; @@ -120,6 +127,12 @@ public interface UWorldGen { .build(); }); + StructureProcessorType SURFACE_GROWTH_STRUCTURE_PROCESSOR = Registry.register(Registries.STRUCTURE_PROCESSOR, Unicopia.id("surface_growth"), () -> SurfaceGrowthStructureProcessor.CODEC); + StructureProcessorType CAVE_CARVING_STRUCTURE_PROCESSOR = Registry.register(Registries.STRUCTURE_PROCESSOR, Unicopia.id("cave_carving"), () -> CaveCarvingStructureProcessor.CODEC); + + RegistryKey> OVERWORLD_CLOUD_CARVER_CONFIG = RegistryKey.of(RegistryKeys.CONFIGURED_CARVER, Unicopia.id("overworld_cloud_carver")); + Carver CLOUR_CARVER = Registry.register(Registries.CARVER, Unicopia.id("cloud"), new CloudCarver(CaveCarverConfig.CAVE_CODEC)); + @SafeVarargs static T applyAll(T t, Consumer ...consumers) { for (Consumer consumer : consumers) { @@ -136,6 +149,7 @@ public interface UWorldGen { .or(BiomeSelectors.tag(BiomeTags.IS_RIVER)) .or(BiomeSelectors.includeByKey(BiomeKeys.STONY_SHORE)) ), GenerationStep.Feature.VEGETAL_DECORATION, SHELLS_PLACED_FEATURE); + BiomeModifications.addCarver(BiomeSelectors.foundInOverworld(), GenerationStep.Carver.AIR, OVERWORLD_CLOUD_CARVER_CONFIG); UTreeGen.bootstrap(); OverworldBiomeSelectionCallback.EVENT.register(context -> { diff --git a/src/main/java/com/minelittlepony/unicopia/server/world/WeatherAccess.java b/src/main/java/com/minelittlepony/unicopia/server/world/WeatherAccess.java new file mode 100644 index 00000000..59f62cd5 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/server/world/WeatherAccess.java @@ -0,0 +1,89 @@ +package com.minelittlepony.unicopia.server.world; + +import com.minelittlepony.unicopia.block.cloud.CloudLike; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.client.MinecraftClient; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.util.math.ChunkSectionPos; +import net.minecraft.world.World; +import net.minecraft.world.chunk.Chunk; + +public interface WeatherAccess { + void setWeatherOverride(Float rain, Float thunder); + + default boolean isInRangeOfStorm(BlockPos pos) { + return WeatherConditions.get((World)this).isInRangeOfStorm(pos); + } + + @Environment(EnvType.CLIENT) + default boolean isBelowClientCloudLayer(BlockPos pos) { + + int range = MinecraftClient.isFancyGraphicsOrBetter() ? 10 : 5; + + if (pos.getY() < 230 - range) { + return true; + } + + Chunk chunk = ((World)this).getChunk(pos); + int topSection = chunk.getHighestNonEmptySection(); + + if (topSection > -1) { + int sectionBottomY = ChunkSectionPos.getBlockCoord(topSection); + if (sectionBottomY >= pos.getY() - 16) { + BlockPos.Mutable mutable = pos.mutableCopy(); + BlockPos.Mutable probeMutable = pos.mutableCopy(); + int maxDistance = 16; + + while (((World)this).isInBuildLimit(mutable)) { + if (--maxDistance <= 0) break; + if (!((World)this).isAir(probeMutable.setY(mutable.getY() + range))) { + + mutable.set(pos); + maxDistance = 16; + + while (((World)this).isInBuildLimit(mutable)) { + if (--maxDistance <= 0) break; + if (((World)this).getBlockState(probeMutable.setY(mutable.getY())).getBlock() instanceof CloudLike) { + return false; + } + mutable.move(Direction.DOWN); + } + + return true; + } + mutable.move(Direction.UP); + } + } + } + return false; + } + + default boolean isBelowCloudLayer(BlockPos pos) { + if (pos.getY() < 230) { + return true; + } + + Chunk chunk = ((World)this).getChunk(pos); + int topSection = chunk.getHighestNonEmptySection(); + + if (topSection > -1) { + int sectionBottomY = ChunkSectionPos.getBlockCoord(topSection); + if (sectionBottomY >= pos.getY() - 16) { + BlockPos.Mutable mutable = pos.mutableCopy(); + int maxDistance = 32; + + while (((World)this).isInBuildLimit(mutable)) { + if (--maxDistance <= 0) break; + if (!((World)this).isAir(mutable)) { + return true; + } + mutable.move(Direction.UP); + } + } + } + return false; + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/server/world/WeatherConditions.java b/src/main/java/com/minelittlepony/unicopia/server/world/WeatherConditions.java index ac2d4e84..cc77d9ea 100644 --- a/src/main/java/com/minelittlepony/unicopia/server/world/WeatherConditions.java +++ b/src/main/java/com/minelittlepony/unicopia/server/world/WeatherConditions.java @@ -23,8 +23,21 @@ import net.minecraft.world.PersistentState; import net.minecraft.world.World; public class WeatherConditions extends PersistentState implements Tickable { + public static final double FIRE_UPDRAFT = 0.13; + public static final double SAND_UPDRAFT = 0.03; + public static final double SOUL_SAND_UPDRAFT = -0.03; + public static final double ICE_UPDRAFT = 0; + public static final double VOID_UPDRAFT = -0.23; + + public static final float MAX_UPDRAFT_HEIGHT = 20; + public static final float MAX_TERRAIN_HEIGHT = 50; + public static final float MAX_WIND_HEIGHT = 70; + public static final Plane HEIGHT_MAP_FIELD = (world, pos) -> world.getTopY(Heightmap.Type.WORLD_SURFACE_WG, pos.getX(), pos.getZ()); - public static final Plane THERMAL_FIELD = (world, pos) -> (float)getUpdraft(pos, world); + public static final Plane THERMAL_FIELD = (world, pos) -> { + double factor = 1 - getScaledDistanceFromTerrain(pos, world, MAX_UPDRAFT_HEIGHT); + return (float)(factor * getMaterialSurfaceTemperature(pos, world)); + }; public static final Plane LOCAL_ALTITUDE_FIELD = (world, pos) -> { if (!world.isAir(pos)) { return 0; @@ -36,16 +49,6 @@ public class WeatherConditions extends PersistentState implements Tickable { return y - pos.getY(); }; - public static final double FIRE_UPDRAFT = 0.13; - public static final double SAND_UPDRAFT = 0.03; - public static final double SOUL_SAND_UPDRAFT = -0.03; - public static final double ICE_UPDRAFT = 0; - public static final double VOID_UPDRAFT = -0.23; - - public static final float MAX_UPDRAFT_HEIGHT = 20; - public static final float MAX_TERRAIN_HEIGHT = 50; - public static final float MAX_WIND_HEIGHT = 70; - private static final Identifier ID = Unicopia.id("weather_conditions"); public static WeatherConditions get(World world) { @@ -176,11 +179,6 @@ public class WeatherConditions extends PersistentState implements Tickable { .multiply(windFactor); } - public static double getUpdraft(BlockPos.Mutable pos, World world) { - double factor = 1 - getScaledDistanceFromTerrain(pos, world, MAX_UPDRAFT_HEIGHT); - return factor * getMaterialSurfaceTemperature(pos, world); - } - private static float getScaledDistanceFromTerrain(BlockPos.Mutable pos, World world, float maxDistance) { return Math.min(maxDistance, LOCAL_ALTITUDE_FIELD.getValue(world, pos)) / maxDistance; } diff --git a/src/main/java/com/minelittlepony/unicopia/server/world/WorldOverlay.java b/src/main/java/com/minelittlepony/unicopia/server/world/WorldOverlay.java index 6ab36008..a094a5aa 100644 --- a/src/main/java/com/minelittlepony/unicopia/server/world/WorldOverlay.java +++ b/src/main/java/com/minelittlepony/unicopia/server/world/WorldOverlay.java @@ -98,7 +98,7 @@ public class WorldOverlay extends PersistentState } private Chunk getChunk(BlockPos pos) { - return chunks.computeIfAbsent(new ChunkPos(pos).toLong(), Chunk::new); + return chunks.computeIfAbsent(ChunkPos.toLong(pos), Chunk::new); } public void setState(BlockPos pos, @Nullable T state) { diff --git a/src/main/java/com/minelittlepony/unicopia/server/world/chunk/Chunk.java b/src/main/java/com/minelittlepony/unicopia/server/world/chunk/Chunk.java new file mode 100644 index 00000000..d59919db --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/server/world/chunk/Chunk.java @@ -0,0 +1,64 @@ +package com.minelittlepony.unicopia.server.world.chunk; + +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.WeakHashMap; + +import it.unimi.dsi.fastutil.longs.Long2ObjectMap; +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Box; +import net.minecraft.util.math.ChunkSectionPos; + +public class Chunk { + private final Long2ObjectMap> sections = new Long2ObjectOpenHashMap<>(); + private final Map>> entryToSections = new WeakHashMap<>(); + + Chunk(long pos) { } + + public synchronized Set getState(BlockPos pos) { + Section section = sections.get(ChunkSectionPos.getSectionCoord(pos.getY())); + return section == null ? Set.of() : section.getState(pos); + } + + public synchronized boolean remove(T entry) { + Set> sections = entryToSections.remove(entry); + if (sections != null) { + sections.forEach(section -> { + if (section.remove(entry) && section.isEmpty()) { + this.sections.remove(section.pos); + } + }); + return true; + } + return false; + } + + public synchronized boolean update(T entry, Box entryBox) { + Set> oldSections = entryToSections.get(entry); + Set> newSections = getIntersectingSections(entryBox); + if (oldSections != null) { + oldSections.forEach(section -> { + if (!newSections.contains(section) && section.remove(entry) && section.isEmpty()) { + this.sections.remove(section.pos); + } + }); + } + newSections.forEach(chunk -> chunk.update(entry, entryBox)); + entryToSections.put(entry, newSections); + return true; + } + + private Set> getIntersectingSections(Box entryBox) { + Set> sections = new HashSet<>(); + + int minY = ChunkSectionPos.getSectionCoord(entryBox.minY); + int maxY = ChunkSectionPos.getSectionCoord(entryBox.maxY); + for (int y = minY; y <= maxY; y++) { + sections.add(this.sections.computeIfAbsent(y, Section::new)); + } + + return sections; + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/server/world/chunk/PositionalDataMap.java b/src/main/java/com/minelittlepony/unicopia/server/world/chunk/PositionalDataMap.java new file mode 100644 index 00000000..eb2ee335 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/server/world/chunk/PositionalDataMap.java @@ -0,0 +1,63 @@ +package com.minelittlepony.unicopia.server.world.chunk; + +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.WeakHashMap; + +import it.unimi.dsi.fastutil.longs.Long2ObjectMap; +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Box; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.util.math.ChunkSectionPos; +import net.minecraft.util.math.MathHelper; + +public class PositionalDataMap { + private final Long2ObjectMap> chunks = new Long2ObjectOpenHashMap<>(); + private final Map>> entryToChunks = new WeakHashMap<>(); + + public Set getState(BlockPos pos) { + Chunk chunk = chunks.get(ChunkPos.toLong(pos)); + return chunk == null ? Set.of() : chunk.getState(pos); + } + + public void remove(T entry) { + Set> chunks = entryToChunks.remove(entry); + if (chunks != null) { + chunks.forEach(chunk -> chunk.remove(entry)); + } + } + + public void update(T entry) { + Box entryBox = new Box(entry.getCenter()).expand(MathHelper.ceil(entry.getRadius())); + Set> oldChunks = entryToChunks.get(entry); + Set> newChunks = getIntersectingChunks(entryBox); + if (oldChunks != null) { + oldChunks.forEach(chunk -> chunk.remove(entry)); + } + newChunks.forEach(chunk -> chunk.update(entry, entryBox)); + entryToChunks.put(entry, newChunks); + } + + private Set> getIntersectingChunks(Box entryBox) { + int minX = ChunkSectionPos.getSectionCoord(entryBox.minX); + int maxX = ChunkSectionPos.getSectionCoord(entryBox.maxX); + int minZ = ChunkSectionPos.getSectionCoord(entryBox.minZ); + int maxZ = ChunkSectionPos.getSectionCoord(entryBox.maxZ); + + Set> chunks = new HashSet<>(); + for (int x = minX; x <= maxX; x++) { + for (int z = minZ; z <= maxZ; z++) { + chunks.add(this.chunks.computeIfAbsent(ChunkPos.toLong(x, z), Chunk::new)); + } + } + return chunks; + } + + public interface Hotspot { + float getRadius(); + + BlockPos getCenter(); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/server/world/chunk/Section.java b/src/main/java/com/minelittlepony/unicopia/server/world/chunk/Section.java new file mode 100644 index 00000000..7024acdc --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/server/world/chunk/Section.java @@ -0,0 +1,82 @@ +package com.minelittlepony.unicopia.server.world.chunk; + +import java.util.Collections; +import java.util.Set; +import java.util.WeakHashMap; + +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Box; +import net.minecraft.util.math.MathHelper; + +public class Section { + private final Set entries = weakSet(); + private Set[] states; + + final long pos; + + public Section(long pos) { + this.pos = pos; + } + + public boolean isEmpty() { + return entries.isEmpty(); + } + + public boolean remove(T entry) { + if (entries.remove(entry)) { + states = null; + return true; + } + return false; + } + + public boolean update(T entry, Box box) { + entries.add(entry); + states = null; + return true; + } + + @SuppressWarnings("unchecked") + public Set getState(BlockPos pos) { + int localPos = toLocalIndex(pos); + if (states == null) { + states = new Set[16 * 16 * 16]; + } + Set state = states[localPos]; + return state == null ? (states[localPos] = calculateState(pos)) : state; + } + + private Set calculateState(BlockPos pos) { + Set state = weakSet(); + + for (T entry : entries) { + BlockPos center = entry.getCenter(); + int radius = MathHelper.ceil(entry.getRadius()); + + if (pos.equals(center) + || (isInRange(pos.getX(), center.getX(), radius) + && isInRange(pos.getZ(), center.getZ(), radius) + && isInRange(pos.getY(), center.getY(), radius) + && center.isWithinDistance(pos, radius))) { + state.add(entry); + } + } + + return state; + } + + static boolean isInRange(int value, int center, int radius) { + return value >= center - radius && value <= center + radius; + } + + static int toLocalIndex(BlockPos pos) { + int x = pos.getX() % 16; + int y = pos.getY() % 16; + int z = pos.getZ() % 16; + return x + (y * 16) + (z * 16 * 16); + } + + static Set weakSet() { + return Collections.newSetFromMap(new WeakHashMap<>()); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/server/world/gen/CaveCarvingStructureProcessor.java b/src/main/java/com/minelittlepony/unicopia/server/world/gen/CaveCarvingStructureProcessor.java new file mode 100644 index 00000000..cfb2db26 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/server/world/gen/CaveCarvingStructureProcessor.java @@ -0,0 +1,36 @@ +package com.minelittlepony.unicopia.server.world.gen; + +import org.jetbrains.annotations.Nullable; + +import com.minelittlepony.unicopia.server.world.UWorldGen; +import com.mojang.serialization.Codec; +import net.minecraft.structure.StructurePlacementData; +import net.minecraft.structure.StructureTemplate; +import net.minecraft.structure.processor.StructureProcessor; +import net.minecraft.structure.processor.StructureProcessorType; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.Heightmap; +import net.minecraft.world.WorldView; + +public class CaveCarvingStructureProcessor extends StructureProcessor { + public static final Codec CODEC = Codec.unit(new CaveCarvingStructureProcessor()); + + @Override + protected StructureProcessorType getType() { + return UWorldGen.SURFACE_GROWTH_STRUCTURE_PROCESSOR; + } + + @Nullable + @Override + public StructureTemplate.StructureBlockInfo process( + WorldView world, + BlockPos pos, + BlockPos pivot, + StructureTemplate.StructureBlockInfo originalBlockInfo, + StructureTemplate.StructureBlockInfo currentBlockInfo, + StructurePlacementData data + ) { + int topY = world.getTopY(Heightmap.Type.WORLD_SURFACE_WG, currentBlockInfo.pos().getX(), currentBlockInfo.pos().getZ()); + return currentBlockInfo.pos().getY() > topY && world.isAir(currentBlockInfo.pos()) ? null : currentBlockInfo; + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/server/world/gen/CloudCarver.java b/src/main/java/com/minelittlepony/unicopia/server/world/gen/CloudCarver.java new file mode 100644 index 00000000..41736d0d --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/server/world/gen/CloudCarver.java @@ -0,0 +1,185 @@ +package com.minelittlepony.unicopia.server.world.gen; + +import java.util.function.Function; + +import org.apache.commons.lang3.mutable.MutableBoolean; + +import com.minelittlepony.unicopia.block.UBlocks; +import com.mojang.serialization.Codec; + +import it.unimi.dsi.fastutil.longs.LongOpenHashSet; +import it.unimi.dsi.fastutil.longs.LongSet; +import net.minecraft.block.BlockState; +import net.minecraft.registry.entry.RegistryEntry; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.util.math.Direction; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.random.Random; +import net.minecraft.world.biome.Biome; +import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.gen.carver.Carver; +import net.minecraft.world.gen.carver.CarverContext; +import net.minecraft.world.gen.carver.CarvingMask; +import net.minecraft.world.gen.carver.CaveCarver; +import net.minecraft.world.gen.carver.CaveCarverConfig; +import net.minecraft.world.gen.chunk.AquiferSampler; +import net.minecraft.world.gen.densityfunction.DensityFunction.NoisePos; + +public class CloudCarver extends CaveCarver { + + private Random random; + + private final LongSet topWrittenPositions = new LongOpenHashSet(); + + public CloudCarver(Codec codec) { + super(codec); + } + + @Override + protected int getMaxCaveCount() { + return 15; + } + + @Override + protected float getTunnelSystemWidth(Random random) { + return (random.nextFloat() * 2.0F + random.nextFloat()) * 2.0F; + } + + @Override + protected double getTunnelSystemHeightWidthRatio() { + return 0.5; + } + + @Override + public boolean carve( + CarverContext context, + CaveCarverConfig config, + Chunk chunk, + Function> function, + Random random, + AquiferSampler sampler, + ChunkPos chunkPos, + CarvingMask carvingMask + ) { + this.random = random; + boolean result = super.carve(context, config, chunk, function, random, new AquiferSampler() { + @Override + public BlockState apply(NoisePos pos, double density) { + BlockState state = sampler.apply(pos, density); + return state != null && state.isAir() ? UBlocks.CLOUD.getDefaultState() : state; + } + + @Override + public boolean needsFluidTick() { + return sampler.needsFluidTick(); + } + + }, chunkPos, carvingMask); + BlockPos.Mutable mutable = new BlockPos.Mutable(); + topWrittenPositions.forEach(l -> { + processSurfaceBlocks(mutable.set(l), context, config, chunk, random); + }); + topWrittenPositions.clear(); + return result; + } + + @Override + protected void carveCave( + CarverContext context, + CaveCarverConfig config, + Chunk chunk, + Function> posToBiome, + AquiferSampler aquiferSampler, + double x, + double y, + double z, + float xScale, + double yScale, + CarvingMask mask, + Carver.SkipPredicate skipPredicate + ) { + if (random == null) { + return; + } + int maxY = context.getMinY() + context.getHeight(); + + int bubbleCount = 10 + random.nextInt(12); + for (int i = 0; i < bubbleCount; i++) { + double width = 1.5 * xScale + random.nextTriangular(3, 2); + double height = Math.min(width * yScale * (1 + random.nextFloat() * 2) + MathHelper.sin((float) (Math.PI / 2)) * xScale, maxY - y); + double bubbleX = x + (random.nextFloat() * 2 - 1) * width; + double bubbleZ = z + (random.nextFloat() * 2 - 1) * width; + carveRegion(context, config, chunk, posToBiome, aquiferSampler, bubbleX + 1.0, y, bubbleZ, width, height, mask, skipPredicate); + } + } + + @Override + protected void carveTunnels( + CarverContext context, + CaveCarverConfig config, + Chunk chunk, + Function> posToBiome, + long seed, + AquiferSampler aquiferSampler, + double x, + double y, + double z, + double horizontalScale, + double verticalScale, + float w, + float yaw, + float pitch, + int branchStartIndex, + int branchCount, + double yawPitchRatio, + CarvingMask mask, + Carver.SkipPredicate skipPredicate + ) { + if (random == null) { + return; + } + int maxY = context.getMinY() + context.getHeight(); + int bubbleCount = 10 + random.nextInt(12); + for (int i = 0; i < bubbleCount; i++) { + double width = /*1.5 + MathHelper.sin((float) (Math.PI / 2)) * xScale +*/ 1.5 * horizontalScale + random.nextInt(3) + w; + double height = width * (1 + random.nextFloat() * 2) * verticalScale * 0.2; + double bubbleX = x + (random.nextFloat() * 2 - 1) * width * 1.5; + double bubbleZ = z + (random.nextFloat() * 2 - 1) * width * 1.5; + double bubbleY = y + random.nextFloat() * height * 0.5; + if (bubbleY + height < maxY) { + carveRegion(context, config, chunk, posToBiome, aquiferSampler, bubbleX, bubbleY, bubbleZ, width, height, mask, skipPredicate); + } + } + //super.carveTunnels(context, config, chunk, posToBiome, seed, aquiferSampler, x, y, z, horizontalScale, verticalScale, w, yaw, pitch, branchStartIndex, branchCount, yawPitchRatio, mask, skipPredicate); + } + + @Override + protected boolean carveAtPoint( + CarverContext context, + CaveCarverConfig config, + Chunk chunk, + Function> posToBiome, + CarvingMask mask, + BlockPos.Mutable pos, + BlockPos.Mutable tmp, + AquiferSampler aquiferSampler, + MutableBoolean replacedGrassy + ) { + if (super.carveAtPoint(context, config, chunk, posToBiome, mask, pos, tmp, aquiferSampler, replacedGrassy)) { + topWrittenPositions.remove(tmp.set(pos).move(Direction.DOWN).asLong()); + topWrittenPositions.add(pos.asLong()); + if (chunk.getBlockState(tmp).isOf(UBlocks.SOGGY_CLOUD)) { + chunk.setBlockState(tmp, UBlocks.CLOUD.getDefaultState(), false); + } + return true; + } + return false; + } + + protected void processSurfaceBlocks(BlockPos.Mutable pos, CarverContext context, CaveCarverConfig config, Chunk chunk, Random random) { + if (chunk.getBlockState(pos.move(Direction.UP)).isAir()) { + chunk.setBlockState(pos.move(Direction.DOWN), UBlocks.SOGGY_CLOUD.getDefaultState(), false); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/minelittlepony/unicopia/server/world/gen/SurfaceGrowthStructureProcessor.java b/src/main/java/com/minelittlepony/unicopia/server/world/gen/SurfaceGrowthStructureProcessor.java new file mode 100644 index 00000000..33ef60c7 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/server/world/gen/SurfaceGrowthStructureProcessor.java @@ -0,0 +1,67 @@ +package com.minelittlepony.unicopia.server.world.gen; + +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +import com.minelittlepony.unicopia.server.world.UWorldGen; +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; + +import net.minecraft.block.BlockState; +import net.minecraft.structure.StructurePlacementData; +import net.minecraft.structure.StructureTemplate; +import net.minecraft.structure.processor.StructureProcessor; +import net.minecraft.structure.processor.StructureProcessorType; +import net.minecraft.structure.rule.RuleTest; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.random.Random; +import net.minecraft.world.ServerWorldAccess; + +public class SurfaceGrowthStructureProcessor extends StructureProcessor { + public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( + RuleTest.TYPE_CODEC.fieldOf("input_predicate").forGetter(rule -> rule.inputPredicate), + BlockState.CODEC.fieldOf("output_state").forGetter(rule -> rule.outputState) + ).apply(instance, SurfaceGrowthStructureProcessor::new)); + + private final RuleTest inputPredicate; + private final BlockState outputState; + + public SurfaceGrowthStructureProcessor(RuleTest inputPredicate, BlockState outputState) { + this.inputPredicate = inputPredicate; + this.outputState = outputState; + } + + @Override + protected StructureProcessorType getType() { + return UWorldGen.SURFACE_GROWTH_STRUCTURE_PROCESSOR; + } + + @SuppressWarnings("deprecation") + @Override + public List reprocess( + ServerWorldAccess world, + BlockPos pos, + BlockPos pivot, + List originalBlockInfos, + List currentBlockInfos, + StructurePlacementData data + ) { + Map positionalInfos = currentBlockInfos.stream().collect(Collectors.toMap( + StructureTemplate.StructureBlockInfo::pos, + Function.identity() + )); + + return currentBlockInfos.stream().map(currentBlockInfo -> { + StructureTemplate.StructureBlockInfo aboveBlockInfo = positionalInfos.get(currentBlockInfo.pos().up()); + BlockState currentState = aboveBlockInfo == null ? world.getBlockState(currentBlockInfo.pos().up()) : aboveBlockInfo.state(); + if ((currentState.isAir() || currentState.isReplaceable()) + && inputPredicate.test(currentBlockInfo.state(), Random.create(MathHelper.hashCode(currentBlockInfo.pos())))) { + return new StructureTemplate.StructureBlockInfo(currentBlockInfo.pos(), outputState, currentBlockInfo.nbt()); + } + return currentBlockInfo; + }).collect(Collectors.toList()); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/util/serialization/PacketCodec.java b/src/main/java/com/minelittlepony/unicopia/util/serialization/PacketCodec.java index 03336ec2..cd964b76 100644 --- a/src/main/java/com/minelittlepony/unicopia/util/serialization/PacketCodec.java +++ b/src/main/java/com/minelittlepony/unicopia/util/serialization/PacketCodec.java @@ -16,9 +16,11 @@ import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtIo; import net.minecraft.network.PacketByteBuf; import net.minecraft.registry.Registry; +import net.minecraft.registry.RegistryKey; import net.minecraft.util.Identifier; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; public record PacketCodec(PacketByteBuf.PacketReader reader, PacketByteBuf.PacketWriter writer) { public static final PacketCodec BOOLEAN = new PacketCodec<>(PacketByteBuf::readBoolean, PacketByteBuf::writeBoolean); @@ -30,7 +32,7 @@ public record PacketCodec(PacketByteBuf.PacketReader reader, PacketByteBuf public static final PacketCodec UUID = new PacketCodec<>(PacketByteBuf::readUuid, PacketByteBuf::writeUuid); public static final PacketCodec> OPTIONAL_UUID = UUID.asOptional(); - public static final PacketCodec IDENTIFIER = STRING.xMap(Identifier::new, Identifier::toString); + public static final PacketCodec IDENTIFIER = new PacketCodec<>(PacketByteBuf::readIdentifier, PacketByteBuf::writeIdentifier); public static final PacketCodec NBT = new PacketCodec<>(PacketByteBuf::readNbt, PacketByteBuf::writeNbt); @@ -58,6 +60,19 @@ public record PacketCodec(PacketByteBuf.PacketReader reader, PacketByteBuf public static final PacketCodec POS = new PacketCodec<>(PacketByteBuf::readBlockPos, PacketByteBuf::writeBlockPos); public static final PacketCodec> OPTIONAL_POS = POS.asOptional(); + public static final PacketCodec VECTOR = new PacketCodec<>(buffer -> new Vec3d(buffer.readDouble(), buffer.readDouble(), buffer.readDouble()), (buffer, vector) -> { + buffer.writeDouble(vector.x); + buffer.writeDouble(vector.y); + buffer.writeDouble(vector.z); + }); + public static final PacketCodec> OPTIONAL_VECTOR = VECTOR.asOptional(); + public static final PacketCodec> REGISTRY_KEY = new PacketCodec<>(buffer -> { + return RegistryKey.of(RegistryKey.ofRegistry(IDENTIFIER.read(buffer)), IDENTIFIER.read(buffer)); + }, (buffer, key) -> { + IDENTIFIER.write(buffer, key.getRegistry()); + IDENTIFIER.write(buffer, key.getValue()); + }); + public static final PacketCodec>> OPTIONAL_REGISTRY_KEY = REGISTRY_KEY.asOptional(); public static final PacketCodec ofRegistry(Registry registry) { return INT.xMap(registry::get, registry::getRawId); diff --git a/src/main/resources/assets/unicopia/lang/en_us.json b/src/main/resources/assets/unicopia/lang/en_us.json index 3d8903f2..df90e36b 100644 --- a/src/main/resources/assets/unicopia/lang/en_us.json +++ b/src/main/resources/assets/unicopia/lang/en_us.json @@ -799,6 +799,7 @@ "gui.unicopia.tribe_selection.options": "Available Tribes:", "gui.unicopia.tribe_selection.options.disabled": "Option Unavailable", + "gui.unicopia.tribe_selection.describe.unicopia.human": "Go it alone", "gui.unicopia.tribe_selection.describe.unicopia.earth": "Join the Earth Tribe", "gui.unicopia.tribe_selection.describe.unicopia.unicorn": "Join the Unicorn Tribe, master the arcane arts", "gui.unicopia.tribe_selection.describe.unicopia.pegasus": "Join the Pegasus Tribe, soar with the Wonderbolts", diff --git a/src/main/resources/assets/unicopia/textures/block/soggy_cloud_side.png b/src/main/resources/assets/unicopia/textures/block/soggy_cloud_side.png index b030c4a7..bfe6574f 100644 Binary files a/src/main/resources/assets/unicopia/textures/block/soggy_cloud_side.png and b/src/main/resources/assets/unicopia/textures/block/soggy_cloud_side.png differ diff --git a/src/main/resources/assets/unicopia/textures/block/soggy_cloud_slab_side.png b/src/main/resources/assets/unicopia/textures/block/soggy_cloud_slab_side.png index d0c064b0..8817ab38 100644 Binary files a/src/main/resources/assets/unicopia/textures/block/soggy_cloud_slab_side.png and b/src/main/resources/assets/unicopia/textures/block/soggy_cloud_slab_side.png differ diff --git a/src/main/resources/assets/unicopia/textures/block/soggy_cloud_top.png b/src/main/resources/assets/unicopia/textures/block/soggy_cloud_top.png index bbc1fdd9..ed6d470c 100644 Binary files a/src/main/resources/assets/unicopia/textures/block/soggy_cloud_top.png and b/src/main/resources/assets/unicopia/textures/block/soggy_cloud_top.png differ diff --git a/src/main/resources/assets/unicopia/textures/gui/hud.png b/src/main/resources/assets/unicopia/textures/gui/hud.png index 7070f5ad..6fcab1f6 100644 Binary files a/src/main/resources/assets/unicopia/textures/gui/hud.png and b/src/main/resources/assets/unicopia/textures/gui/hud.png differ diff --git a/src/main/resources/data/unicopia/structures/changeling_hive/entrance_large_lower.nbt b/src/main/resources/data/unicopia/structures/changeling_hive/entrance_large_lower.nbt new file mode 100644 index 00000000..2a6cd5e5 Binary files /dev/null and b/src/main/resources/data/unicopia/structures/changeling_hive/entrance_large_lower.nbt differ diff --git a/src/main/resources/data/unicopia/structures/changeling_hive/entrance_large_upper.nbt b/src/main/resources/data/unicopia/structures/changeling_hive/entrance_large_upper.nbt new file mode 100644 index 00000000..c2eb01d0 Binary files /dev/null and b/src/main/resources/data/unicopia/structures/changeling_hive/entrance_large_upper.nbt differ diff --git a/src/main/resources/data/unicopia/structures/changeling_hive/floor_decoration/empty.nbt b/src/main/resources/data/unicopia/structures/changeling_hive/floor_decoration/empty.nbt new file mode 100644 index 00000000..106da760 Binary files /dev/null and b/src/main/resources/data/unicopia/structures/changeling_hive/floor_decoration/empty.nbt differ diff --git a/src/main/resources/data/unicopia/structures/changeling_hive/floor_decoration/slime_1.nbt b/src/main/resources/data/unicopia/structures/changeling_hive/floor_decoration/slime_1.nbt new file mode 100644 index 00000000..86e553a7 Binary files /dev/null and b/src/main/resources/data/unicopia/structures/changeling_hive/floor_decoration/slime_1.nbt differ diff --git a/src/main/resources/data/unicopia/structures/changeling_hive/floor_decoration/slime_2.nbt b/src/main/resources/data/unicopia/structures/changeling_hive/floor_decoration/slime_2.nbt new file mode 100644 index 00000000..185d053b Binary files /dev/null and b/src/main/resources/data/unicopia/structures/changeling_hive/floor_decoration/slime_2.nbt differ diff --git a/src/main/resources/data/unicopia/structures/changeling_hive/floor_decoration/slime_3.nbt b/src/main/resources/data/unicopia/structures/changeling_hive/floor_decoration/slime_3.nbt new file mode 100644 index 00000000..53574e14 Binary files /dev/null and b/src/main/resources/data/unicopia/structures/changeling_hive/floor_decoration/slime_3.nbt differ diff --git a/src/main/resources/data/unicopia/structures/changeling_hive/floor_decoration/spikes.nbt b/src/main/resources/data/unicopia/structures/changeling_hive/floor_decoration/spikes.nbt new file mode 100644 index 00000000..c3932214 Binary files /dev/null and b/src/main/resources/data/unicopia/structures/changeling_hive/floor_decoration/spikes.nbt differ diff --git a/src/main/resources/data/unicopia/structures/changeling_hive/roof_decoration/empty.nbt b/src/main/resources/data/unicopia/structures/changeling_hive/roof_decoration/empty.nbt new file mode 100644 index 00000000..bd44b266 Binary files /dev/null and b/src/main/resources/data/unicopia/structures/changeling_hive/roof_decoration/empty.nbt differ diff --git a/src/main/resources/data/unicopia/structures/changeling_hive/roof_decoration/slime.nbt b/src/main/resources/data/unicopia/structures/changeling_hive/roof_decoration/slime.nbt new file mode 100644 index 00000000..521802b8 Binary files /dev/null and b/src/main/resources/data/unicopia/structures/changeling_hive/roof_decoration/slime.nbt differ diff --git a/src/main/resources/data/unicopia/structures/changeling_hive/roof_decoration/spikes.nbt b/src/main/resources/data/unicopia/structures/changeling_hive/roof_decoration/spikes.nbt new file mode 100644 index 00000000..7a388fab Binary files /dev/null and b/src/main/resources/data/unicopia/structures/changeling_hive/roof_decoration/spikes.nbt differ diff --git a/src/main/resources/data/unicopia/worldgen/configured_carver/overworld_cloud_carver.json b/src/main/resources/data/unicopia/worldgen/configured_carver/overworld_cloud_carver.json new file mode 100644 index 00000000..b7543372 --- /dev/null +++ b/src/main/resources/data/unicopia/worldgen/configured_carver/overworld_cloud_carver.json @@ -0,0 +1,26 @@ +{ + "type": "unicopia:cloud", + "config": { + "probability": 0.05, + "y": { + "type": "minecraft:uniform", + "min_inclusive": { + "absolute": 240 + }, + "max_inclusive": { + "absolute": 600 + } + }, + "yScale": 0.15, + "lava_level": { + "above_bottom": 8 + }, + "replaceable": "minecraft:air", + "horizontal_radius_multiplier": 3.7, + "vertical_radius_multiplier": 2.8, + "floor_level": { + "type": "minecraft:constant", + "value": 0 + } + } +} diff --git a/src/main/resources/data/unicopia/worldgen/processor_list/changeling_hive_decay.json b/src/main/resources/data/unicopia/worldgen/processor_list/changeling_hive_decay.json index 63441ea5..4e9c23c6 100644 --- a/src/main/resources/data/unicopia/worldgen/processor_list/changeling_hive_decay.json +++ b/src/main/resources/data/unicopia/worldgen/processor_list/changeling_hive_decay.json @@ -13,10 +13,23 @@ }, "output_state": { "name": "unicopia:hive", - "Name": "unicopia:hive", - "properties": [] + "Name": "unicopia:hive" } } ] + }, + { + "processor_type": "unicopia:cave_carving" + }, + { + "processor_type": "unicopia:surface_growth", + "input_predicate": { + "predicate_type": "block_match", + "block": "unicopia:chitin" + }, + "output_state": { + "name": "unicopia:surface_chitin", + "Name": "unicopia:surface_chitin" + } } ] \ No newline at end of file diff --git a/src/main/resources/data/unicopia/worldgen/processor_list/changeling_hive_entrance_decay.json b/src/main/resources/data/unicopia/worldgen/processor_list/changeling_hive_entrance_decay.json new file mode 100644 index 00000000..0ab08c0b --- /dev/null +++ b/src/main/resources/data/unicopia/worldgen/processor_list/changeling_hive_entrance_decay.json @@ -0,0 +1,32 @@ +[ + { + "processor_type": "minecraft:rule", + "rules": [ + { + "location_predicate": { + "predicate_type": "always_true" + }, + "input_predicate": { + "predicate_type": "random_block_match", + "block": "unicopia:chitin", + "probability": 0.2 + }, + "output_state": { + "name": "unicopia:hive", + "Name": "unicopia:hive" + } + } + ] + }, + { + "processor_type": "unicopia:surface_growth", + "input_predicate": { + "predicate_type": "block_match", + "block": "unicopia:chitin" + }, + "output_state": { + "name": "unicopia:surface_chitin", + "Name": "unicopia:surface_chitin" + } + } +] \ No newline at end of file diff --git a/src/main/resources/data/unicopia/worldgen/processor_list/changeling_hive_surfacing.json b/src/main/resources/data/unicopia/worldgen/processor_list/changeling_hive_surfacing.json new file mode 100644 index 00000000..91d90a09 --- /dev/null +++ b/src/main/resources/data/unicopia/worldgen/processor_list/changeling_hive_surfacing.json @@ -0,0 +1,13 @@ +[ + { + "processor_type": "unicopia:surface_growth", + "input_predicate": { + "predicate_type": "block_match", + "block": "unicopia:chitin" + }, + "output_state": { + "name": "unicopia:surface_chitin", + "Name": "unicopia:surface_chitin" + } + } +] \ No newline at end of file diff --git a/src/main/resources/data/unicopia/worldgen/structure/abandoned_changeling_hive.json b/src/main/resources/data/unicopia/worldgen/structure/abandoned_changeling_hive.json index 70b16c5a..d88b505b 100644 --- a/src/main/resources/data/unicopia/worldgen/structure/abandoned_changeling_hive.json +++ b/src/main/resources/data/unicopia/worldgen/structure/abandoned_changeling_hive.json @@ -18,10 +18,10 @@ } }, "start_height": { - "absolute": -7 + "absolute": -6 }, "start_pool": "unicopia:changeling_hive/start", - "step": "underground_decoration", + "step": "underground_structures", "terrain_adaptation": "none", "use_expansion_hack": false } \ No newline at end of file diff --git a/src/main/resources/data/unicopia/worldgen/template_pool/changeling_hive/chamber_decors.json b/src/main/resources/data/unicopia/worldgen/template_pool/changeling_hive/chamber_decors.json index beb46991..68d93295 100644 --- a/src/main/resources/data/unicopia/worldgen/template_pool/changeling_hive/chamber_decors.json +++ b/src/main/resources/data/unicopia/worldgen/template_pool/changeling_hive/chamber_decors.json @@ -4,9 +4,7 @@ "element": { "element_type": "minecraft:single_pool_element", "location": "unicopia:changeling_hive/chamber_decoration/nothing", - "processors": { - "processors": [] - }, + "processors": "unicopia:changeling_hive_surfacing", "projection": "rigid" }, "weight": 7 @@ -24,9 +22,7 @@ "element": { "element_type": "minecraft:single_pool_element", "location": "unicopia:changeling_hive/chamber_decoration/spiders", - "processors": { - "processors": [] - }, + "processors": "unicopia:changeling_hive_surfacing", "projection": "rigid" }, "weight": 4 @@ -35,9 +31,7 @@ "element": { "element_type": "minecraft:single_pool_element", "location": "unicopia:changeling_hive/chamber_decoration/spiked", - "processors": { - "processors": [] - }, + "processors": "unicopia:changeling_hive_surfacing", "projection": "rigid" }, "weight": 2 @@ -46,9 +40,7 @@ "element": { "element_type": "minecraft:single_pool_element", "location": "unicopia:changeling_hive/chamber_decoration/slime", - "processors": { - "processors": [] - }, + "processors": "unicopia:changeling_hive_surfacing", "projection": "rigid" }, "weight": 2 diff --git a/src/main/resources/data/unicopia/worldgen/template_pool/changeling_hive/floor_additions.json b/src/main/resources/data/unicopia/worldgen/template_pool/changeling_hive/floor_additions.json new file mode 100644 index 00000000..b4619725 --- /dev/null +++ b/src/main/resources/data/unicopia/worldgen/template_pool/changeling_hive/floor_additions.json @@ -0,0 +1,50 @@ +{ + "elements": [ + { + "element": { + "element_type": "minecraft:single_pool_element", + "location": "unicopia:changeling_hive/floor_decoration/empty", + "processors": [], + "projection": "rigid" + }, + "weight": 6 + }, + { + "element": { + "element_type": "minecraft:single_pool_element", + "location": "unicopia:changeling_hive/floor_decoration/slime_1", + "processors": [], + "projection": "rigid" + }, + "weight": 1 + }, + { + "element": { + "element_type": "minecraft:single_pool_element", + "location": "unicopia:changeling_hive/floor_decoration/slime_2", + "processors": [], + "projection": "rigid" + }, + "weight": 1 + }, + { + "element": { + "element_type": "minecraft:single_pool_element", + "location": "unicopia:changeling_hive/floor_decoration/slime_3", + "processors": [], + "projection": "rigid" + }, + "weight": 1 + }, + { + "element": { + "element_type": "minecraft:single_pool_element", + "location": "unicopia:changeling_hive/floor_decoration/spikes", + "processors": [], + "projection": "rigid" + }, + "weight": 3 + } + ], + "fallback": "unicopia:changeling_hive/floor_additions_termination" +} \ No newline at end of file diff --git a/src/main/resources/data/unicopia/worldgen/template_pool/changeling_hive/floor_additions_termination.json b/src/main/resources/data/unicopia/worldgen/template_pool/changeling_hive/floor_additions_termination.json new file mode 100644 index 00000000..a75d7346 --- /dev/null +++ b/src/main/resources/data/unicopia/worldgen/template_pool/changeling_hive/floor_additions_termination.json @@ -0,0 +1,14 @@ +{ + "elements": [ + { + "element": { + "element_type": "minecraft:single_pool_element", + "location": "unicopia:changeling_hive/floor_decoration/empty", + "processors": [], + "projection": "rigid" + }, + "weight": 1 + } + ], + "fallback": "minecraft:empty" +} \ No newline at end of file diff --git a/src/main/resources/data/unicopia/worldgen/template_pool/changeling_hive/main_entrance_shafts.json b/src/main/resources/data/unicopia/worldgen/template_pool/changeling_hive/main_entrance_shafts.json new file mode 100644 index 00000000..872201a0 --- /dev/null +++ b/src/main/resources/data/unicopia/worldgen/template_pool/changeling_hive/main_entrance_shafts.json @@ -0,0 +1,14 @@ +{ + "elements": [ + { + "element": { + "element_type": "minecraft:single_pool_element", + "location": "unicopia:changeling_hive/entrance_large_lower", + "processors": [], + "projection": "rigid" + }, + "weight": 6 + } + ], + "fallback": "minecraft:empty" +} \ No newline at end of file diff --git a/src/main/resources/data/unicopia/worldgen/template_pool/changeling_hive/pit_decors.json b/src/main/resources/data/unicopia/worldgen/template_pool/changeling_hive/pit_decors.json index f5380f91..660a7749 100644 --- a/src/main/resources/data/unicopia/worldgen/template_pool/changeling_hive/pit_decors.json +++ b/src/main/resources/data/unicopia/worldgen/template_pool/changeling_hive/pit_decors.json @@ -4,9 +4,7 @@ "element": { "element_type": "minecraft:single_pool_element", "location": "unicopia:changeling_hive/pit_decoration/eggs", - "processors": { - "processors": [] - }, + "processors": "unicopia:changeling_hive_surfacing", "projection": "rigid" }, "weight": 1 @@ -15,9 +13,7 @@ "element": { "element_type": "minecraft:single_pool_element", "location": "unicopia:changeling_hive/pit_decoration/lava", - "processors": { - "processors": [] - }, + "processors": "unicopia:changeling_hive_surfacing", "projection": "rigid" }, "weight": 1 @@ -35,9 +31,7 @@ "element": { "element_type": "minecraft:single_pool_element", "location": "unicopia:changeling_hive/pit_decoration/spiders", - "processors": { - "processors": [] - }, + "processors": "unicopia:changeling_hive_surfacing", "projection": "rigid" }, "weight": 1 @@ -46,9 +40,7 @@ "element": { "element_type": "minecraft:single_pool_element", "location": "unicopia:changeling_hive/pit_decoration/spikes", - "processors": { - "processors": [] - }, + "processors": "unicopia:changeling_hive_surfacing", "projection": "rigid" }, "weight": 1 @@ -57,9 +49,7 @@ "element": { "element_type": "minecraft:single_pool_element", "location": "unicopia:changeling_hive/pit_decoration/bulb", - "processors": { - "processors": [] - }, + "processors": "unicopia:changeling_hive_surfacing", "projection": "rigid" }, "weight": 1 diff --git a/src/main/resources/data/unicopia/worldgen/template_pool/changeling_hive/roof_additions.json b/src/main/resources/data/unicopia/worldgen/template_pool/changeling_hive/roof_additions.json new file mode 100644 index 00000000..0dff505a --- /dev/null +++ b/src/main/resources/data/unicopia/worldgen/template_pool/changeling_hive/roof_additions.json @@ -0,0 +1,32 @@ +{ + "elements": [ + { + "element": { + "element_type": "minecraft:single_pool_element", + "location": "unicopia:changeling_hive/roof_decoration/empty", + "processors": [], + "projection": "rigid" + }, + "weight": 6 + }, + { + "element": { + "element_type": "minecraft:single_pool_element", + "location": "unicopia:changeling_hive/roof_decoration/slime", + "processors": [], + "projection": "rigid" + }, + "weight": 1 + }, + { + "element": { + "element_type": "minecraft:single_pool_element", + "location": "unicopia:changeling_hive/roof_decoration/spikes", + "processors": [], + "projection": "rigid" + }, + "weight": 3 + } + ], + "fallback": "unicopia:changeling_hive/roof_additions_termination" +} \ No newline at end of file diff --git a/src/main/resources/data/unicopia/worldgen/template_pool/changeling_hive/roof_additions_termination.json b/src/main/resources/data/unicopia/worldgen/template_pool/changeling_hive/roof_additions_termination.json new file mode 100644 index 00000000..307bb99b --- /dev/null +++ b/src/main/resources/data/unicopia/worldgen/template_pool/changeling_hive/roof_additions_termination.json @@ -0,0 +1,14 @@ +{ + "elements": [ + { + "element": { + "element_type": "minecraft:single_pool_element", + "location": "unicopia:changeling_hive/roof_decoration/empty", + "processors": [], + "projection": "rigid" + }, + "weight": 1 + } + ], + "fallback": "minecraft:empty" +} \ No newline at end of file diff --git a/src/main/resources/data/unicopia/worldgen/template_pool/changeling_hive/start.json b/src/main/resources/data/unicopia/worldgen/template_pool/changeling_hive/start.json index 2b17e07a..5bfb0c50 100644 --- a/src/main/resources/data/unicopia/worldgen/template_pool/changeling_hive/start.json +++ b/src/main/resources/data/unicopia/worldgen/template_pool/changeling_hive/start.json @@ -3,26 +3,8 @@ { "element": { "element_type": "minecraft:single_pool_element", - "location": "unicopia:changeling_hive/entrance", - "processors": "unicopia:changeling_hive_decay", - "projection": "rigid" - }, - "weight": 3 - }, - { - "element": { - "element_type": "minecraft:single_pool_element", - "location": "unicopia:changeling_hive/spiked/entrance", - "processors": "unicopia:changeling_hive_decay", - "projection": "rigid" - }, - "weight": 3 - }, - { - "element": { - "element_type": "minecraft:single_pool_element", - "location": "unicopia:changeling_hive/slimey/entrance", - "processors": "unicopia:changeling_hive_decay", + "location": "unicopia:changeling_hive/entrance_large_upper", + "processors": "unicopia:changeling_hive_entrance_decay", "projection": "rigid" }, "weight": 1 diff --git a/src/main/resources/unicopia.mixin.json b/src/main/resources/unicopia.mixin.json index 17bd2121..533483c0 100644 --- a/src/main/resources/unicopia.mixin.json +++ b/src/main/resources/unicopia.mixin.json @@ -17,6 +17,7 @@ "MixinChunkBlockLightProvider", "MutableBlockLightStorage", "MixinDamageSource", + "MixinEnchantment", "MixinEnchantmentHelper", "MixinFallLocation", "MixinEntity", @@ -27,6 +28,7 @@ "MixinFallingBlockEntity", "MixinFlowableFluid", "MixinGuardianTargetPredicate", + "MixinHeightmap", "MixinItem", "MixinItemEntity", "MixinItemStack", @@ -52,6 +54,7 @@ "MixinWorld", "PointOfInterestTypesAccessor", "server.MixinEntityTrackerEntry", + "server.MixinPathNodeMaker", "server.MixinPlayerManager", "server.MixinServerPlayerEntity", "server.MixinServerPlayNetworkHandler",