1
0
Fork 0
mirror of https://github.com/Sollace/Unicopia.git synced 2025-04-03 09:45:29 +02:00

Merge branch 'Sollace:1.20.1' into 1.20.1

This commit is contained in:
LingVarr 2024-03-26 11:58:52 +11:00 committed by GitHub
commit 7f97e15a3b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
50 changed files with 764 additions and 327 deletions

View file

@ -80,7 +80,7 @@ public record Race (Supplier<Composite> compositeSupplier, Availability availabi
}
public boolean hasIronGut() {
return !isHuman() && this != CHANGELING;
return !isHuman();
}
public boolean isUnset() {

View file

@ -28,6 +28,7 @@ public interface UCriteria {
CustomEventCriterion.Trigger POWER_UP_HEART = CUSTOM_EVENT.createTrigger("power_up_heart");
CustomEventCriterion.Trigger SPLIT_SEA = CUSTOM_EVENT.createTrigger("split_sea");
CustomEventCriterion.Trigger RIDE_BALLOON = CUSTOM_EVENT.createTrigger("ride_balloon");
CustomEventCriterion.Trigger CONSTRUCT_BALLOON = CUSTOM_EVENT.createTrigger("construct_balloon");
CustomEventCriterion.Trigger TELEPORT_ABOVE_WORLD = CUSTOM_EVENT.createTrigger("teleport_above_world");
static void bootstrap() { }

View file

@ -31,7 +31,6 @@ import net.minecraft.util.shape.VoxelShape;
import net.minecraft.util.shape.VoxelShapes;
import net.minecraft.world.BlockView;
import net.minecraft.world.World;
import net.minecraft.world.WorldAccess;
import net.minecraft.world.event.GameEvent;
public class FancyBedBlock extends BedBlock {

View file

@ -36,6 +36,7 @@ import com.minelittlepony.unicopia.item.cloud.CloudBlockItem;
import com.minelittlepony.unicopia.item.group.ItemGroupRegistry;
import com.minelittlepony.unicopia.server.world.UTreeGen;
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
import net.fabricmc.fabric.api.registry.CompostingChanceRegistry;
import net.fabricmc.fabric.api.registry.FlammableBlockRegistry;
import net.fabricmc.fabric.api.registry.OxidizableBlocksRegistry;
import net.fabricmc.fabric.api.registry.StrippableBlockRegistry;
@ -253,6 +254,7 @@ public interface UBlocks {
Block SPECTRAL_FIRE = register("spectral_fire", new SpectralFireBlock(Settings.copy(Blocks.SOUL_FIRE)));
Block WORM_BLOCK = register("worm_block", new FallingBlock(Settings.create().hardness(0.1F).resistance(0).requiresTool().sounds(BlockSoundGroup.MUD)), ItemGroups.NATURAL);
EdibleBlock HAY_BLOCK = register("hay_block", new EdibleBlock(new Identifier("hay_block"), new Identifier("wheat"), true));
private static <T extends Block> T register(String name, T item) {
@ -328,6 +330,8 @@ public interface UBlocks {
FlammableBlockRegistry.getDefaultInstance().add(BANANAS, 5, 20);
FlammableBlockRegistry.getDefaultInstance().add(CURING_JOKE, 60, 100);
CompostingChanceRegistry.INSTANCE.add(WORM_BLOCK, 8F);
UBlockEntities.bootstrap();
EdibleBlock.bootstrap();
}

View file

@ -1,79 +1,115 @@
package com.minelittlepony.unicopia.block.cloud;
import java.util.Map;
import java.util.function.Function;
import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.EquineContext;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.PillarBlock;
import net.minecraft.block.ShapeContext;
import net.minecraft.item.ItemPlacementContext;
import net.minecraft.state.StateManager;
import net.minecraft.state.property.BooleanProperty;
import net.minecraft.state.property.EnumProperty;
import net.minecraft.state.property.Properties;
import net.minecraft.util.BlockRotation;
import net.minecraft.util.Util;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.Direction.AxisDirection;
import net.minecraft.util.shape.VoxelShape;
import net.minecraft.util.shape.VoxelShapes;
import net.minecraft.world.BlockView;
import net.minecraft.world.WorldAccess;
public class CloudPillarBlock extends CloudBlock {
private static final BooleanProperty NORTH = Properties.NORTH;
private static final BooleanProperty SOUTH = Properties.SOUTH;
public static final EnumProperty<Direction.Axis> AXIS = Properties.AXIS;
private static final BooleanProperty TOP = Properties.NORTH;
private static final BooleanProperty BOTTOM = Properties.SOUTH;
private static final Map<Direction, BooleanProperty> DIRECTION_PROPERTIES = Map.of(
Direction.UP, NORTH,
Direction.DOWN, SOUTH
Direction.UP, TOP, Direction.DOWN, BOTTOM,
Direction.SOUTH, TOP, Direction.NORTH, BOTTOM,
Direction.EAST, TOP, Direction.WEST, BOTTOM
);
private static final VoxelShape CORE_SHAPE = Block.createCuboidShape(1, 0, 1, 15, 16, 15);
private static final VoxelShape FOOT_SHAPE = Block.createCuboidShape(0, 0, 0, 16, 5, 16);
private static final VoxelShape CAP_SHAPE = FOOT_SHAPE.offset(0, 11F / 16F, 0);
private static final VoxelShape[] SHAPES = new VoxelShape[] {
CORE_SHAPE,
VoxelShapes.union(CORE_SHAPE, FOOT_SHAPE),
VoxelShapes.union(CORE_SHAPE, CAP_SHAPE),
VoxelShapes.union(CORE_SHAPE, FOOT_SHAPE, CAP_SHAPE)
};
// [0,0] [0,1]
// [1,0] [1,1]
private static final Function<Direction.Axis, VoxelShape[]> SHAPES = Util.memoize(axis -> {
int[] offsets = { axis.choose(1, 0, 0), axis.choose(0, 1, 0), axis.choose(0, 0, 1) };
float capOffset = 11F / 16F;
VoxelShape core = Block.createCuboidShape(
axis.choose(0, 1, 1), axis.choose(1, 0, 1), axis.choose(1, 1, 0),
16 - axis.choose(0, 1, 1), 16 - axis.choose(1, 0, 1), 16 - axis.choose(1, 1, 0)
);
VoxelShape foot = Block.createCuboidShape(0, 0, 0, 16 - (11 * offsets[0]), 16 - (11 * offsets[1]), 16 - (11 * offsets[2]));
VoxelShape cap = foot.offset(capOffset * offsets[0], capOffset * offsets[1], capOffset * offsets[2]);
return new VoxelShape[] {
core,
VoxelShapes.union(core, foot),
VoxelShapes.union(core, cap),
VoxelShapes.union(core, cap, foot)
};
});
public CloudPillarBlock(Settings settings) {
super(settings, false);
setDefaultState(getDefaultState().with(NORTH, true).with(SOUTH, true));
setDefaultState(getDefaultState().with(TOP, true).with(BOTTOM, true).with(AXIS, Direction.Axis.Y));
}
@Override
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
builder.add(NORTH, SOUTH);
builder.add(AXIS, TOP, BOTTOM);
}
@Override
protected VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context, EquineContext equineContext) {
return SHAPES[(state.get(NORTH) ? 0 : 2) + (state.get(SOUTH) ? 0 : 1)];
var axis = state.get(AXIS);
int[] offsets = { axis.choose(1, 0, 0), axis.choose(0, 1, 0), axis.choose(0, 0, 1) };
float capOffset = 11F / 16F;
VoxelShape core = Block.createCuboidShape(
axis.choose(0, 1, 1), axis.choose(1, 0, 1), axis.choose(1, 1, 0),
16 - axis.choose(0, 1, 1), 16 - axis.choose(1, 0, 1), 16 - axis.choose(1, 1, 0)
);
VoxelShape foot = Block.createCuboidShape(0, 0, 0, 16 - (11 * offsets[0]), 16 - (11 * offsets[1]), 16 - (11 * offsets[2]));
VoxelShape cap = foot.offset(capOffset * offsets[0], capOffset * offsets[1], capOffset * offsets[2]);
var temp = new VoxelShape[] {
core,
VoxelShapes.union(core, foot),
VoxelShapes.union(core, cap),
VoxelShapes.union(core, cap, foot)
};
return temp[(state.get(TOP) ? 0 : 2) + (state.get(BOTTOM) ? 0 : 1)];
//return SHAPES.apply(state.get(AXIS))[(state.get(TOP) ? 0 : 2) + (state.get(BOTTOM) ? 0 : 1)];
}
@Override
@Nullable
protected BlockState getPlacementState(ItemPlacementContext placementContext, EquineContext equineContext) {
BlockPos pos = placementContext.getBlockPos();
BlockState state = super.getPlacementState(placementContext, equineContext);
for (var property : DIRECTION_PROPERTIES.entrySet()) {
state = state.with(property.getValue(), placementContext.getWorld().getBlockState(pos.offset(property.getKey())).isOf(this));
}
return state;
Direction.Axis axis = placementContext.getSide().getAxis();
Direction upDirection = Direction.get(AxisDirection.POSITIVE, axis);
Direction downDirection = Direction.get(AxisDirection.NEGATIVE, axis);
BlockState above = placementContext.getWorld().getBlockState(pos.offset(upDirection));
BlockState below = placementContext.getWorld().getBlockState(pos.offset(downDirection));
return super.getPlacementState(placementContext, equineContext)
.with(DIRECTION_PROPERTIES.get(upDirection), above.isOf(this) && above.get(AXIS) == axis)
.with(DIRECTION_PROPERTIES.get(downDirection), below.isOf(this) && below.get(AXIS) == axis)
.with(AXIS, axis);
}
@Deprecated
@Override
public BlockState getStateForNeighborUpdate(BlockState state, Direction direction, BlockState neighborState, WorldAccess world, BlockPos pos, BlockPos neighborPos) {
if (direction.getAxis() == Direction.Axis.Y) {
return state.with(DIRECTION_PROPERTIES.get(direction), neighborState.isOf(this));
if (direction.getAxis() == state.get(AXIS)) {
return state.with(DIRECTION_PROPERTIES.get(direction), neighborState.isOf(this) && neighborState.get(AXIS) == state.get(AXIS));
}
return state;
}
@Override
public BlockState rotate(BlockState state, BlockRotation rotation) {
return PillarBlock.changeRotation(state, rotation);
}
}

View file

@ -12,6 +12,7 @@ import com.minelittlepony.unicopia.client.particle.CloudsEscapingParticle;
import com.minelittlepony.unicopia.client.particle.DiskParticle;
import com.minelittlepony.unicopia.client.particle.DustCloudParticle;
import com.minelittlepony.unicopia.client.particle.FloatingBubbleParticle;
import com.minelittlepony.unicopia.client.particle.FootprintParticle;
import com.minelittlepony.unicopia.client.particle.GroundPoundParticle;
import com.minelittlepony.unicopia.client.particle.HealthDrainParticle;
import com.minelittlepony.unicopia.client.particle.LightningBoltParticle;
@ -19,7 +20,6 @@ import com.minelittlepony.unicopia.client.particle.MagicParticle;
import com.minelittlepony.unicopia.client.particle.RainboomParticle;
import com.minelittlepony.unicopia.client.particle.RainbowTrailParticle;
import com.minelittlepony.unicopia.client.particle.RaindropsParticle;
import com.minelittlepony.unicopia.client.particle.RunesParticle;
import com.minelittlepony.unicopia.client.particle.ShockwaveParticle;
import com.minelittlepony.unicopia.client.particle.SphereParticle;
import com.minelittlepony.unicopia.client.render.*;
@ -54,6 +54,7 @@ import net.minecraft.client.particle.SpriteProvider;
import net.minecraft.client.render.*;
import net.minecraft.client.render.VertexConsumerProvider.Immediate;
import net.minecraft.client.render.block.entity.BlockEntityRendererFactories;
import net.minecraft.client.render.entity.EmptyEntityRenderer;
import net.minecraft.client.render.entity.FlyingItemEntityRenderer;
import net.minecraft.client.render.item.ItemRenderer;
import net.minecraft.client.render.model.json.ModelTransformationMode;
@ -68,7 +69,6 @@ import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.BlockRenderView;
@SuppressWarnings("deprecation")
public interface URenderers {
BlockEntity CHEST_RENDER_ENTITY = new CloudChestBlock.TileData(BlockPos.ORIGIN, UBlocks.CLOUD_CHEST.getDefaultState());
@ -78,10 +78,10 @@ public interface URenderers {
ParticleFactoryRegistry.getInstance().register(UParticles.BUBBLE, createFactory(FloatingBubbleParticle::new));
ParticleFactoryRegistry.getInstance().register(UParticles.RAIN_DROPS, createFactory(RaindropsParticle::new));
ParticleFactoryRegistry.getInstance().register(UParticles.HEALTH_DRAIN, createFactory(HealthDrainParticle::create));
ParticleFactoryRegistry.getInstance().register(UParticles.FOOTPRINT, createFactory(FootprintParticle::new));
ParticleFactoryRegistry.getInstance().register(UParticles.RAINBOOM_RING, RainboomParticle::new);
ParticleFactoryRegistry.getInstance().register(UParticles.RAINBOOM_TRAIL, RainbowTrailParticle::new);
ParticleFactoryRegistry.getInstance().register(UParticles.SHOCKWAVE, ShockwaveParticle::new);
ParticleFactoryRegistry.getInstance().register(UParticles.MAGIC_RUNES, RunesParticle::new);
ParticleFactoryRegistry.getInstance().register(UParticles.SPHERE, SphereParticle::new);
ParticleFactoryRegistry.getInstance().register(UParticles.DISK, DiskParticle::new);
ParticleFactoryRegistry.getInstance().register(UParticles.GROUND_POUND, GroundPoundParticle::new);
@ -111,6 +111,7 @@ public interface URenderers {
EntityRendererRegistry.register(UEntities.LOOT_BUG, LootBugEntityRenderer::new);
EntityRendererRegistry.register(UEntities.TENTACLE, TentacleEntityRenderer::new);
EntityRendererRegistry.register(UEntities.IGNOMINIOUS_BULB, IgnominiousBulbEntityRenderer::new);
EntityRendererRegistry.register(UEntities.SPECTER, EmptyEntityRenderer::new);
BlockEntityRendererFactories.register(UBlockEntities.WEATHER_VANE, WeatherVaneBlockEntityRenderer::new);
BlockEntityRendererFactories.register(UBlockEntities.FANCY_BED, CloudBedBlockEntityRenderer::new);

View file

@ -3,6 +3,7 @@ package com.minelittlepony.unicopia.client;
import java.util.Optional;
import org.jetbrains.annotations.Nullable;
import org.joml.Vector3f;
import com.minelittlepony.common.client.gui.element.Button;
import com.minelittlepony.common.event.ScreenInitCallback;
@ -33,11 +34,14 @@ import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.OpenToLanScreen;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.ingame.HandledScreens;
import net.minecraft.client.render.Camera;
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;
public class UnicopiaClient implements ClientModInitializer {
@ -66,6 +70,20 @@ public class UnicopiaClient implements ClientModInitializer {
return Optional.empty();
}
public static Vec3d getAdjustedSoundPosition(Vec3d pos) {
PlayerCamera cam = getCamera().orElse(null);
if (cam == null) {
return pos;
}
Camera camera = MinecraftClient.getInstance().gameRenderer.getCamera();
Vector3f rotated = pos.subtract(camera.getPos()).toVector3f();
rotated = rotated.rotateAxis(cam.calculateRoll() * MathHelper.RADIANS_PER_DEGREE, 0, 1, 0);
return new Vec3d(rotated).add(camera.getPos());
}
public static Race getPreferredRace() {
if (!Unicopia.getConfig().ignoreMineLP.get()
&& MinecraftClient.getInstance().player != null) {

View file

@ -0,0 +1,74 @@
package com.minelittlepony.unicopia.client.particle;
import org.joml.Vector3f;
import com.minelittlepony.unicopia.particle.FootprintParticleEffect;
import net.minecraft.client.particle.ParticleTextureSheet;
import net.minecraft.client.particle.SpriteBillboardParticle;
import net.minecraft.client.particle.SpriteProvider;
import net.minecraft.client.render.Camera;
import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
public class FootprintParticle extends SpriteBillboardParticle {
// specter
public FootprintParticle(FootprintParticleEffect effect, SpriteProvider provider, ClientWorld world, double x, double y, double z, double dx, double dy, double dz) {
super(world, x, y, z, 0, 0, 0);
setVelocity(0, 0, 0);
setSprite(provider.getSprite(world.random));
this.angle = effect.yaw() * MathHelper.RADIANS_PER_DEGREE;
this.maxAge = 1000;
this.gravityStrength = 1;
}
@Override
public ParticleTextureSheet getType() {
return ParticleTextureSheet.PARTICLE_SHEET_TRANSLUCENT;
}
@Override
public void tick() {
super.tick();
}
@Override
public void buildGeometry(VertexConsumer drawer, Camera camera, float tickDelta) {
Vec3d cam = camera.getPos();
float renderX = (float)(MathHelper.lerp(tickDelta, prevPosX, x) - cam.getX());
float renderY = (float)(MathHelper.lerp(tickDelta, prevPosY, y) - cam.getY());
float renderZ = (float)(MathHelper.lerp(tickDelta, prevPosZ, z) - cam.getZ());
Vector3f[] corners = new Vector3f[]{
new Vector3f(-1, 0, -1),
new Vector3f(-1, 0, 1),
new Vector3f( 1, 0, 1),
new Vector3f( 1, 0, -1)
};
for (int k = 0; k < 4; ++k) {
Vector3f corner = corners[k];
corner.mul(0.2F);
corner.rotateAxis(angle, 0, 1, 0);
corner.add(renderX, renderY + 0.0001F, renderZ);
}
float alpha = this.alpha * (1 - ((float)age / maxAge));
int light = getBrightness(tickDelta);
float minU = this.sprite.getMinU();
float maxU = this.sprite.getMaxU();
float minV = this.sprite.getMinV();
float maxV = this.sprite.getMaxV();
drawer.vertex(corners[0].x, corners[0].y, corners[0].z).texture(minU, minV).color(red, green, blue, alpha).light(light).next();
drawer.vertex(corners[1].x, corners[1].y, corners[1].z).texture(maxU, minV).color(red, green, blue, alpha).light(light).next();
drawer.vertex(corners[2].x, corners[2].y, corners[2].z).texture(maxU, maxV).color(red, green, blue, alpha).light(light).next();
drawer.vertex(corners[3].x, corners[3].y, corners[3].z).texture(minU, maxV).color(red, green, blue, alpha).light(light).next();
}
}

View file

@ -1,123 +0,0 @@
package com.minelittlepony.unicopia.client.particle;
import org.joml.Quaternionf;
import org.joml.Vector3f;
import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.particle.OrientedBillboardParticleEffect;
import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.render.BufferBuilder;
import net.minecraft.client.render.Tessellator;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.*;
@Deprecated
public class RunesParticle extends OrientedBillboardParticle {
private static final Identifier[] TEXTURES = new Identifier[] {
Unicopia.id("textures/particles/runes_0.png"),
Unicopia.id("textures/particles/runes_1.png"),
Unicopia.id("textures/particles/runes_2.png"),
Unicopia.id("textures/particles/runes_3.png"),
Unicopia.id("textures/particles/runes_4.png"),
Unicopia.id("textures/particles/runes_5.png")
};
protected float targetSize = 3;
protected float prevBaseSize = 0;
protected float baseSize = 0;
private float prevRotationAngle;
private float rotationAngle;
public RunesParticle(OrientedBillboardParticleEffect effect, ClientWorld world, double x, double y, double z, double velocityX, double velocityY, double velocityZ) {
super(effect, world, x, y, z, velocityX, velocityY, velocityZ);
setMaxAge(70);
red = world.random.nextFloat();
green = world.random.nextFloat();
blue = world.random.nextFloat();
}
@Override
public float getScale(float tickDelta) {
return MathHelper.lerp(tickDelta, prevBaseSize, baseSize) * super.getScale(tickDelta);
}
@Override
protected Identifier getTexture() {
return TEXTURES[0];
}
private float getAlphaScale() {
float transitionScale = age < maxAge / 2 ? 5 : 3;
return (float)Math.min(1, Math.sin(Math.PI * age / maxAge) * transitionScale);
}
@Override
protected int getBrightness(float tint) {
return 0xF000F0;
}
@Override
protected void renderQuads(Tessellator te, BufferBuilder buffer, float x, float y, float z, float tickDelta) {
float alpha = this.alpha * getAlphaScale();
float angle = MathHelper.lerp(tickDelta, prevRotationAngle, rotationAngle);
for (int i = 0; i < TEXTURES.length; i++) {
for (int dim = 0; dim < 3; dim++) {
RenderSystem.setShaderTexture(0, TEXTURES[i]);
RenderSystem.setShaderColor(red, green, blue, alpha / ((float)(dim * 3) + 1));
Vector3f[] corners = new Vector3f[]{
new Vector3f(-1, -1, 0),
new Vector3f(-1, 1, 0),
new Vector3f( 1, 1, 0),
new Vector3f( 1, -1, 0)
};
float scale = getScale(tickDelta);
float ringSpeed = (i % 2 == 0 ? i : -1) * i;
Quaternionf ringAngle = RotationAxis.POSITIVE_Z.rotationDegrees(angle * ringSpeed);
Quaternionf ringFlip = RotationAxis.POSITIVE_Y.rotationDegrees(angle * ringSpeed * dim);
Quaternionf ringRoll = RotationAxis.POSITIVE_X.rotationDegrees(angle * ringSpeed * dim);
for(int k = 0; k < 4; ++k) {
Vector3f corner = corners[k];
corner.rotate(ringAngle);
corner.rotate(ringFlip);
corner.rotate(ringRoll);
corner.rotate(rotation);
corner.mul(scale);
corner.add(x, y + 0.001F, z);
}
renderQuad(te, buffer, corners, alpha, tickDelta);
}
}
RenderSystem.setShaderColor(1, 1, 1, 1);
}
@Override
public void tick() {
super.tick();
prevBaseSize = baseSize;
if (baseSize < targetSize) {
baseSize += 0.1F;
}
if (baseSize > targetSize) {
baseSize -= 0.1F;
}
rotationAngle = (rotationAngle + 0.3F) % 360;
prevRotationAngle = rotationAngle - 0.3F;
}
}

View file

@ -3,7 +3,6 @@ package com.minelittlepony.unicopia.datagen.providers;
import java.util.Optional;
import java.util.Set;
import java.util.function.Consumer;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.UTags;
import com.minelittlepony.unicopia.advancement.CustomEventCriterion;
@ -54,31 +53,37 @@ public class UAdvancementsProvider extends FabricAdvancementProvider {
createTribeRootAdvancement(consumer, root, Race.PEGASUS).children(consumer, this::generatePegasusTribeAdvancementsTree);
createTribeRootAdvancement(consumer, root, Race.UNICORN).children(consumer, this::generateUnicornTribeAdvancementsTree);
root.child(UItems.DRAGON_BREATH_SCROLL).criterion("has_scroll", hasItems(UItems.DRAGON_BREATH_SCROLL)).build(consumer, "take_a_note").children(p -> {
p.child(UItems.DRAGON_BREATH_SCROLL).criterion("send_scroll", dragonScroll(false, Items.WRITTEN_BOOK)).build(consumer, "dear_princess");
root.child(UItems.DRAGON_BREATH_SCROLL).showToast().announce().criterion("has_scroll", hasItems(UItems.DRAGON_BREATH_SCROLL)).build(consumer, "take_a_note").children(p -> {
p.child(UItems.DRAGON_BREATH_SCROLL).criterion("send_book", dragonScroll(false, Items.WRITTEN_BOOK)).build(consumer, "dear_princess")
.child(UItems.DRAGON_BREATH_SCROLL).criterion("send_scroll", dragonScroll(false, UItems.DRAGON_BREATH_SCROLL)).build(consumer, "i_await_your_reply");
p.child(UItems.IMPORTED_OATS).hidden().frame(AdvancementFrame.CHALLENGE)
.criterion("send_oats", dragonScroll(false, UItems.OATS, UItems.IMPORTED_OATS))
.criterion("receieve_oats", dragonScroll(true, UItems.OATS, UItems.IMPORTED_OATS))
.criteriaMerger(CriterionMerger.OR)
.build(consumer, "imported_oats");
.criterion("receieve_oats", dragonScroll(true, UItems.IMPORTED_OATS))
.criteriaMerger(CriterionMerger.OR).build(consumer, "imported_oats");
p.child(Items.CHIPPED_ANVIL).hidden().frame(AdvancementFrame.CHALLENGE).criterion("ding_sun", dingCelestia(Set.of(), Set.of(Race.BAT))).build(consumer, "blasphemy");
p.child(Items.CHIPPED_ANVIL).hidden().frame(AdvancementFrame.CHALLENGE).criterion("ding_sun", dingCelestia(Set.of(Race.BAT), Set.of())).build(consumer, "sweet_sweet_revenge");
});
root.child(UItems.OATS).criterion("has_oats", hasItems(UItems.OATS)).build(consumer, "what_the_hay");
root.child(UItems.IRON_HORSE_SHOE).criterion("killed_entity_with_horseshoe", killWithItems(UTags.FROM_HORSESHOES)).build(consumer, "dead_ringer");
root.child(UItems.PINECONE).frame(AdvancementFrame.CHALLENGE).criterion("eat_pinecone", ConsumeItemCriterion.Conditions.item(UItems.PINECONE)).build(consumer, "eat_pinecone");
root.child(UItems.GIANT_BALLOON).criterion("ride_balloon", CustomEventCriterion.create("ride_balloon")).build(consumer, "travelling_in_style");
root.child(UItems.MUFFIN).hidden().criterion("has_muffin", hasItems(UItems.MUFFIN)).build(consumer, "baked_bads");
root.child(UItems.HORSE_SHOE_FRIES).criterion("has_horse_shoe_fries", hasItems(UItems.HORSE_SHOE_FRIES)).build(consumer, "lucky");
root.child(UItems.TOAST).criterion("has_toast", hasItems(UItems.TOAST)).build(consumer, "toast")
root.child(UItems.OATS).showToast().announce().criterion("has_oats", hasItems(UItems.OATS)).build(consumer, "oats_so_easy");
root.child(Items.HAY_BLOCK).showToast().announce().criterion("eat_hay", ConsumeItemCriterion.Conditions.item(Items.HAY_BLOCK)).build(consumer, "what_the_hay");
root.child(UItems.COPPER_HORSE_SHOE).showToast().announce().criterion("has_horseshoe", hasItems(UTags.HORSE_SHOES)).build(consumer, "blacksmith").children(p -> {
p.child(UItems.IRON_HORSE_SHOE).criterion("has_iron_horseshoe", hasItems(UItems.IRON_HORSE_SHOE)).build(consumer, "change_of_shoes")
.child(UItems.GOLDEN_HORSE_SHOE).criterion("has_gold_horseshoe", hasItems(UItems.GOLDEN_HORSE_SHOE)).build(consumer, "fashionably_expensive")
.child(UItems.NETHERITE_HORSE_SHOE).criterion("has_netherite_horseshoe", hasItems(UItems.NETHERITE_HORSE_SHOE)).build(consumer, "overkill");
p.child(UItems.IRON_HORSE_SHOE).hidden().frame(AdvancementFrame.CHALLENGE).criterion("killed_entity_with_horseshoe", killWithItems(UTags.FROM_HORSESHOES)).build(consumer, "dead_ringer");
});
root.child(UItems.PINECONE).showToast().announce().frame(AdvancementFrame.CHALLENGE).criterion("eat_pinecone", ConsumeItemCriterion.Conditions.item(UItems.PINECONE)).build(consumer, "eat_pinecone");
root.child(UItems.OAK_BASKET).showToast().criterion("has_basket", hasItems(UTags.BASKETS)).build(consumer, "basket_case")
.child(Items.LANTERN).showToast().criterion("construct_balloon", CustomEventCriterion.create("construct_balloon")).build(consumer, "aeronaut")
.child(UItems.GIANT_BALLOON).showToast().announce().frame(AdvancementFrame.CHALLENGE).criterion("ride_balloon", CustomEventCriterion.create("ride_balloon")).build(consumer, "travelling_in_style");
root.child(UItems.MUFFIN).showToast().announce().hidden().criterion("has_muffin", hasItems(UItems.MUFFIN)).build(consumer, "baked_bads");
root.child(UItems.HORSE_SHOE_FRIES).showToast().announce().criterion("has_horse_shoe_fries", hasItems(UItems.HORSE_SHOE_FRIES)).build(consumer, "lucky");
root.child(UItems.TOAST).showToast().announce().criterion("has_toast", hasItems(UItems.TOAST)).build(consumer, "toast")
.child(UItems.BURNED_TOAST).hidden().criterion("has_burned_toast", hasItems(UItems.BURNED_TOAST)).build(consumer, "burn_toast");
root.child(UItems.GREEN_APPLE).criterion("has_apple", hasItems(UTags.FRESH_APPLES)).build(consumer, "apple_route").children(p -> {
p.child(UItems.SWEET_APPLE)
.criterion("has_all_apples", hasItems(Items.APPLE, UItems.GREEN_APPLE, UItems.SWEET_APPLE, UItems.SOUR_APPLE, UItems.ROTTEN_APPLE, UItems.ZAP_APPLE, UItems.COOKED_ZAP_APPLE, Items.GOLDEN_APPLE))
.build(consumer, "sweet_apple_acres");
root.child(UItems.GREEN_APPLE).showToast().announce().criterion("has_apple", hasItems(UTags.FRESH_APPLES)).build(consumer, "apple_route").children(p -> {
p.child(UItems.SWEET_APPLE).criterion("has_all_apples", hasItems(Items.APPLE, UItems.GREEN_APPLE, UItems.SWEET_APPLE, UItems.SOUR_APPLE, UItems.ROTTEN_APPLE, UItems.ZAP_APPLE, UItems.COOKED_ZAP_APPLE, Items.GOLDEN_APPLE)).build(consumer, "sweet_apple_acres");
p.child(UItems.ZAP_BULB).criterion("has_zap_apple", hasItems(UItems.ZAP_APPLE)).build(consumer, "trick_apple").children(pp -> {
pp.child(UItems.ZAP_APPLE).hidden().criterion("eat_trick_apple", CustomEventCriterion.createFlying("eat_trick_apple")).build(consumer, "eat_trick_apple");
pp.child(UItems.ZAP_APPLE).hidden().criterion("feed_trick_apple", CustomEventCriterion.createFlying("feed_trick_apple")).build(consumer, "feed_trick_apple");
pp.child(UItems.ZAP_APPLE).hidden().criterion("eat_trick_apple", CustomEventCriterion.createFlying("eat_trick_apple")).build(consumer, "eat_trick_apple");
pp.child(UItems.ZAP_APPLE).hidden().criterion("feed_trick_apple", CustomEventCriterion.createFlying("feed_trick_apple")).build(consumer, "feed_trick_apple");
});
p.child(UItems.JUICE).criterion("has_juice", hasItems(UItems.JUICE)).build(consumer, "juice")
.child(UItems.BURNED_JUICE).hidden().criterion("has_burned_juice", hasItems(UItems.BURNED_JUICE)).build(consumer, "burn_juice")
@ -149,13 +154,14 @@ public class UAdvancementsProvider extends FabricAdvancementProvider {
private void generateUnicornTribeAdvancementsTree(Consumer<Advancement> consumer, AdvancementDisplayBuilder.Parent parent) {
parent.child(UItems.SPELLBOOK).criterion("has_spellbook", hasItems(UItems.SPELLBOOK)).build(consumer, "books").children(p -> {
//ItemPredicate bookPredicate = ItemPredicate.Builder.create().tag(ItemTags.BOOKSHELF_BOOKS).build();
//p.child(Items.BOOK).hidden().frame(AdvancementFrame.CHALLENGE).criterion("has_books", InventoryChangedCriterion.Conditions.items(IntStream.range(0, 9 * 4).mapToObj(i -> bookPredicate).toArray(ItemPredicate[]::new))).build(consumer, "books_books_books");
p.child(UItems.CRYSTAL_SHARD).criterion("has_shard", hasItems(UItems.CRYSTAL_SHARD)).build(consumer, "crystaline").children(pp -> {
pp.child(UItems.CRYSTAL_HEART).criterion("power_up_heart", CustomEventCriterion.create("power_up_heart")).rewards(AdvancementRewards.Builder.experience(105)).build(consumer, "power_up_heart");
pp.child(UItems.CRYSTAL_HEART).criterion("power_up_heart", CustomEventCriterion.create("power_up_heart")).rewards(AdvancementRewards.Builder.experience(105)).build(consumer, "power_up_heart");
});
p.child(UItems.ALICORN_AMULET).criterion("has_alicorn_amulet", hasItems(UItems.ALICORN_AMULET)).build(consumer, "tempting")
p.child(UItems.ALICORN_AMULET).criterion("has_alicorn_amulet", hasItems(UItems.ALICORN_AMULET)).build(consumer, "tempted")
.child(Items.CRYING_OBSIDIAN).criterion("light_altar", CustomEventCriterion.create("light_altar")).build(consumer, "hello_darkness_my_old_friend")
.child(UItems.BROKEN_ALICORN_AMULET).frame(AdvancementFrame.GOAL).criterion("defeat_sombra", CustomEventCriterion.create("defeat_sombra")).rewards(AdvancementRewards.Builder.experience(2000)).build(consumer, "save_the_day")
.children(pp -> {
.child(UItems.BROKEN_ALICORN_AMULET).frame(AdvancementFrame.GOAL).criterion("defeat_sombra", CustomEventCriterion.create("defeat_sombra")).rewards(AdvancementRewards.Builder.experience(2000)).build(consumer, "save_the_day").children(pp -> {
pp.child(UItems.UNICORN_AMULET).frame(AdvancementFrame.GOAL).criterion("obtain_the_thing", hasItems(UItems.UNICORN_AMULET)).rewards(AdvancementRewards.Builder.experience(1100)).build(consumer, "ascension");
pp.child(UItems.BROKEN_ALICORN_AMULET).hidden().frame(AdvancementFrame.CHALLENGE).criterion("defeat_sombra_again", CustomEventCriterion.create("defeat_sombra", 2)).rewards(AdvancementRewards.Builder.experience(2000)).build(consumer, "doctor_sombrero");
});
@ -169,15 +175,14 @@ public class UAdvancementsProvider extends FabricAdvancementProvider {
private void generateBatTribeAdvancementsTree(Consumer<Advancement> consumer, AdvancementDisplayBuilder.Parent parent) {
parent.child(Items.LIGHT).criterion("look_into_sun", CustomEventCriterion.create("look_into_sun")).build(consumer, "praise_the_sun").children(p -> {
p.child(UItems.SUNGLASSES).criterion("wear_shades", CustomEventCriterion.create("wear_shades")).build(consumer, "cool_potato");
p.child(Items.BLACK_CANDLE).frame(AdvancementFrame.CHALLENGE).criterion("screech_twenty_mobs", CustomEventCriterion.createFlying("screech_twenty_mobs")).build(consumer, "screech_twenty_mobs").children(pp -> {
pp.child(Items.BRICK).frame(AdvancementFrame.CHALLENGE).criterion("super_scare_entity", CustomEventCriterion.createFlying("super_scare_entity")).build(consumer, "extra_spooky");
});
p.child(Items.BLACK_CANDLE).frame(AdvancementFrame.CHALLENGE).criterion("screech_twenty_mobs", CustomEventCriterion.createFlying("screech_twenty_mobs")).build(consumer, "screech_twenty_mobs")
.child(Items.BRICK).frame(AdvancementFrame.CHALLENGE).criterion("super_scare_entity", CustomEventCriterion.createFlying("super_scare_entity")).build(consumer, "extra_spooky");
p.child(Items.BLACK_CANDLE).frame(AdvancementFrame.CHALLENGE).criterion("screech_self", CustomEventCriterion.createFlying("screech_self")).build(consumer, "screech_self");
});
}
private void generateEnchantmentsAdvancementsTree(Consumer<Advancement> consumer) {
AdvancementDisplayBuilder.create(Items.NETHERITE_SCRAP)
AdvancementDisplayBuilder.create(Items.NETHERITE_SCRAP).showToast().announce()
.criterion("enchant_with_consumption", enchant(UEnchantments.CONSUMPTION))
.rewards(AdvancementRewards.Builder.experience(120))
.parent(new Identifier("story/enchant_item"))
@ -189,9 +194,10 @@ public class UAdvancementsProvider extends FabricAdvancementProvider {
.group("enchanting")
.hidden()
.build(consumer, "xp_miner");
AdvancementDisplayBuilder.create(Items.GOLDEN_APPLE)
AdvancementDisplayBuilder.create(Items.GOLDEN_APPLE).showToast().announce()
.criterion("enchant_with_heart_bound", enchant(UEnchantments.HEART_BOUND))
.rewards(AdvancementRewards.Builder.experience(120))
.parent(new Identifier("story/enchant_item"))
.group("enchanting")
.build(consumer, "hearts_stronger_than_horses")
.child(Items.GOLDEN_PICKAXE)
@ -215,7 +221,7 @@ public class UAdvancementsProvider extends FabricAdvancementProvider {
public static CriterionConditions dragonScroll(boolean receiving, ItemPredicate items) {
return new SendViaDragonBreathScrollCriterion.Conditions(
LootContextPredicate.EMPTY,
ItemPredicate.ANY,
items,
receiving,
Optional.empty(),
TriState.DEFAULT,

View file

@ -123,7 +123,7 @@ public class UBlockStateModelGenerator extends BlockStateModelGenerator {
registerLog(UBlocks.STRIPPED_PALM_LOG).log(UBlocks.STRIPPED_PALM_LOG).wood(UBlocks.STRIPPED_PALM_WOOD);
registerCubeAllModelTexturePool(UBlocks.PALM_PLANKS).family(UBlockFamilies.PALM);
registerHangingSign(UBlocks.STRIPPED_PALM_LOG, UBlocks.PALM_HANGING_SIGN, UBlocks.PALM_WALL_HANGING_SIGN);
registerSimpleCubeAll(UBlocks.PALM_LEAVES);
registerSingleton(UBlocks.PALM_LEAVES, TexturedModel.LEAVES);
// zap wood
registerLog(UBlocks.ZAP_LOG)
@ -170,6 +170,7 @@ public class UBlockStateModelGenerator extends BlockStateModelGenerator {
// shells
registerAll(UBlockStateModelGenerator::registerShell, UBlocks.CLAM_SHELL, UBlocks.TURRET_SHELL, UBlocks.SCALLOP_SHELL);
// other
registerSimpleCubeAll(UBlocks.WORM_BLOCK);
registerBuiltinWithParticle(UBlocks.WEATHER_VANE, UBlocks.WEATHER_VANE.asItem());
registerWithStages(UBlocks.FROSTED_OBSIDIAN, Properties.AGE_3, BlockModels.CUBE_ALL, 0, 1, 2, 3);
registerWithStagesBuiltinModels(UBlocks.ROCKS, Properties.AGE_7, 0, 1, 2, 3, 4, 5, 6, 7);
@ -381,9 +382,17 @@ public class UBlockStateModelGenerator extends BlockStateModelGenerator {
Identifier middle = BlockModels.TEMPLATE_PILLAR.upload(pillar, textures, modelCollector);
Identifier end = BlockModels.TEMPLATE_PILLAR_END.upload(pillar, textures, modelCollector);
blockStateCollector.accept(MultipartBlockStateSupplier.create(pillar)
.with(BlockStateVariant.create().put(MODEL, middle))
.with(When.create().set(Properties.NORTH, false), BlockStateVariant.create().put(MODEL, end).put(UVLOCK, true).put(X, R180))
.with(When.create().set(Properties.SOUTH, false), BlockStateVariant.create().put(MODEL, end))
.with(When.create().set(Properties.AXIS, Direction.Axis.X), BlockStateVariant.create().put(MODEL, middle).put(X, R90).put(Y, R90))
.with(When.create().set(Properties.AXIS, Direction.Axis.X).set(Properties.NORTH, false), BlockStateVariant.create().put(MODEL, end).put(X, R270).put(Y, R90))
.with(When.create().set(Properties.AXIS, Direction.Axis.X).set(Properties.SOUTH, false), BlockStateVariant.create().put(MODEL, end).put(X, R90).put(Y, R90))
.with(When.create().set(Properties.AXIS, Direction.Axis.Y), BlockStateVariant.create().put(MODEL, middle))
.with(When.create().set(Properties.AXIS, Direction.Axis.Y).set(Properties.NORTH, false), BlockStateVariant.create().put(MODEL, end).put(X, R180))
.with(When.create().set(Properties.AXIS, Direction.Axis.Y).set(Properties.SOUTH, false), BlockStateVariant.create().put(MODEL, end))
.with(When.create().set(Properties.AXIS, Direction.Axis.Z), BlockStateVariant.create().put(MODEL, middle).put(X, R90))
.with(When.create().set(Properties.AXIS, Direction.Axis.Z).set(Properties.NORTH, false), BlockStateVariant.create().put(MODEL, end).put(X, R90))
.with(When.create().set(Properties.AXIS, Direction.Axis.Z).set(Properties.SOUTH, false), BlockStateVariant.create().put(MODEL, end).put(X, R270))
);
ItemModels.TEMPLATE_PILLAR.upload(ModelIds.getItemModelId(pillar.asItem()), textures, modelCollector);
}

View file

@ -48,6 +48,7 @@ public class UBlockTagProvider extends FabricTagProvider.BlockTagProvider {
getOrCreateTagBuilder(BlockTags.DRAGON_IMMUNE).add(UBlocks.FROSTED_OBSIDIAN, UBlocks.GOLDEN_OAK_LOG, UBlocks.GOLDEN_OAK_LEAVES);
getOrCreateTagBuilder(BlockTags.FIRE).add(UBlocks.SPECTRAL_FIRE);
getOrCreateTagBuilder(BlockTags.HOE_MINEABLE).add(UBlocks.HAY_BLOCK).addOptional(Unicopia.id("rice_block")).addOptional(Unicopia.id("straw_block"));
getOrCreateTagBuilder(BlockTags.SHOVEL_MINEABLE).add(UBlocks.WORM_BLOCK);
addZapWoodset();
addPalmWoodset();

View file

@ -54,7 +54,8 @@ public class UBlockLootTableProvider extends FabricBlockLootTableProvider {
UBlocks.WEATHER_VANE,
UBlocks.ZAP_FENCE_GATE, UBlocks.ZAP_FENCE,
UBlocks.ZAP_LOG, UBlocks.ZAP_PLANKS, UBlocks.ZAP_STAIRS, UBlocks.ZAP_WOOD
UBlocks.ZAP_LOG, UBlocks.ZAP_PLANKS, UBlocks.ZAP_STAIRS, UBlocks.ZAP_WOOD,
UBlocks.WORM_BLOCK
).forEach(this::addDrop);
// slabs

View file

@ -449,6 +449,9 @@ public class URecipeProvider extends FabricRecipeProvider {
.pattern("---")
.offerTo(exporter);
// worms
offerReversibleCompactingRecipes(exporter, RecipeCategory.BUILDING_BLOCKS, UItems.WHEAT_WORMS, RecipeCategory.BUILDING_BLOCKS, UBlocks.WORM_BLOCK);
// utility
ShapedRecipeJsonBuilder.create(RecipeCategory.MISC, Items.DIRT)
.input('*', UItems.WHEAT_WORMS).criterion("has_wheat_worms", conditionsFromItem(UItems.WHEAT_WORMS))
@ -457,6 +460,8 @@ public class URecipeProvider extends FabricRecipeProvider {
.pattern("#*")
.offerTo(exporter, convertBetween(Items.DIRT, UItems.WHEAT_WORMS));
offerShapelessRecipe(exporter, Items.BONE_MEAL, UTags.SHELLS, "bonemeal", 3);
offer2x2CompactingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, Items.COBBLESTONE, UItems.ROCK);
offerReversibleCompactingRecipesWithReverseRecipeGroup(exporter, RecipeCategory.MISC, UItems.PEBBLES, RecipeCategory.BUILDING_BLOCKS, Blocks.GRAVEL, convertBetween(UItems.PEBBLES, Blocks.GRAVEL), "pebbles");
offerShapelessRecipe(exporter, UItems.PEBBLES, Blocks.SUSPICIOUS_GRAVEL, "pebbles", 9);

View file

@ -77,21 +77,15 @@ public class PonyDiets implements DietView {
@Override
public void appendTooltip(ItemStack stack, @Nullable PlayerEntity user, List<Text> tooltip, TooltipContext context) {
if (initEdibility(stack, user)) {
Pony pony = Pony.of(user);
if (!((ItemDuck)stack.getItem()).getOriginalFoodComponent().isEmpty() || stack.getItem().getFoodComponent() != null) {
Pony pony = Pony.of(user);
tooltip.add(Text.translatable("unicopia.diet.information").formatted(Formatting.DARK_PURPLE));
getEffects(stack, pony).appendTooltip(stack, tooltip, context);
/*for (Race race : Race.REGISTRY) {
var diet = diets.get(race);
if (diet != null) {
tooltip.add(race.getDisplayName());
diet.appendTooltip(stack, user, tooltip, context);
}
}*/
getDiet(pony).appendTooltip(stack, user, tooltip, context);
tooltip.add(Text.translatable("unicopia.diet.information").formatted(Formatting.DARK_PURPLE));
getEffects(stack, pony).appendTooltip(stack, tooltip, context);
getDiet(pony).appendTooltip(stack, user, tooltip, context);
}
}
}

View file

@ -8,7 +8,9 @@ import net.minecraft.block.BlockRenderType;
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.MovementType;
import net.minecraft.entity.data.TrackedData;
import net.minecraft.entity.mob.MobEntity;
import net.minecraft.nbt.NbtCompound;
@ -35,6 +37,14 @@ public class EntityPhysics<T extends Entity> implements Physics, Copyable<Entity
@Override
public void tick() {
if (isGravityNegative()) {
if (isGravityNegative() && !entity.isSneaking() && entity.isInSneakingPose()) {
float currentHeight = entity.getDimensions(entity.getPose()).height;
float sneakingHeight = entity.getDimensions(EntityPose.STANDING).height;
entity.move(MovementType.SELF, new Vec3d(0, -(currentHeight - sneakingHeight), 0));
entity.setPose(EntityPose.STANDING);
}
if (entity.getY() > entity.getWorld().getHeight() + 64) {
entity.damage(entity.getDamageSources().outOfWorld(), 4.0F);
}

View file

@ -39,7 +39,8 @@ public interface RotatedView {
if (!hasTransform() || rotations.isEmpty()) {
return y;
}
return y - ((y - rotations.peek()) * 2);
return (rotations.peek() * 2) - y;
}
}

View file

@ -380,6 +380,9 @@ public class AirBalloonEntity extends MobEntity implements EntityCollisions.Comp
getWorld().emitGameEvent(player, GameEvent.EQUIP, getBlockPos());
}
setDesign(HotAirBalloonItem.getDesign(getWorld(), stack));
if (hasBurner() && hasBalloon()) {
UCriteria.CONSTRUCT_BALLOON.trigger(player);
}
return ActionResult.SUCCESS;
}
@ -405,6 +408,9 @@ public class AirBalloonEntity extends MobEntity implements EntityCollisions.Comp
if (!player.isSneaky()) {
getWorld().emitGameEvent(player, GameEvent.EQUIP, getBlockPos());
}
if (hasBurner() && hasBalloon()) {
UCriteria.CONSTRUCT_BALLOON.trigger(player);
}
return ActionResult.SUCCESS;
}

View file

@ -72,6 +72,10 @@ public class ButterflyEntity extends AmbientEntity {
return createMobAttributes().add(EntityAttributes.GENERIC_MAX_HEALTH, 2);
}
public static boolean canSpawn(EntityType<? extends ButterflyEntity> type, WorldAccess world, SpawnReason spawnReason, BlockPos pos, Random random) {
return world.getBlockState(pos.down()).isIn(BlockTags.ANIMALS_SPAWNABLE_ON);
}
@Override
public float getSoundPitch() {
return super.getSoundPitch() * 0.95F;

View file

@ -0,0 +1,118 @@
package com.minelittlepony.unicopia.entity.mob;
import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.particle.FootprintParticleEffect;
import com.minelittlepony.unicopia.particle.ParticleUtils;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.ai.goal.ActiveTargetGoal;
import net.minecraft.entity.ai.goal.LookAroundGoal;
import net.minecraft.entity.ai.goal.LookAtEntityGoal;
import net.minecraft.entity.ai.goal.MeleeAttackGoal;
import net.minecraft.entity.ai.goal.RevengeGoal;
import net.minecraft.entity.ai.goal.SwimGoal;
import net.minecraft.entity.ai.goal.WanderAroundFarGoal;
import net.minecraft.entity.attribute.DefaultAttributeContainer;
import net.minecraft.entity.attribute.EntityAttributes;
import net.minecraft.entity.damage.DamageSource;
import net.minecraft.entity.mob.HostileEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.particle.BlockStateParticleEffect;
import net.minecraft.particle.ParticleTypes;
import net.minecraft.registry.tag.BlockTags;
import net.minecraft.sound.SoundEvent;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.GameRules;
import net.minecraft.world.World;
public class SpecterEntity extends HostileEntity {
public static DefaultAttributeContainer.Builder createAttributes() {
return HostileEntity.createHostileAttributes()
.add(EntityAttributes.GENERIC_MAX_HEALTH, 16F)
.add(EntityAttributes.GENERIC_MOVEMENT_SPEED, 0.5F);
}
private double stepDistance;
private double nextStepDistance;
private boolean wasLeft;
public SpecterEntity(EntityType<? extends HostileEntity> entityType, World world) {
super(entityType, world);
}
@Override
protected void initGoals() {
this.goalSelector.add(1, new SwimGoal(this));
this.goalSelector.add(4, new MeleeAttackGoal(this, 1.0, true));
this.goalSelector.add(5, new WanderAroundFarGoal(this, 0.8));
this.goalSelector.add(6, new LookAtEntityGoal(this, PlayerEntity.class, 8.0f));
this.goalSelector.add(6, new LookAroundGoal(this));
this.targetSelector.add(1, new RevengeGoal(this));
this.targetSelector.add(2, new TargetGoal<>(this, PlayerEntity.class));
}
@SuppressWarnings("deprecation")
@Override
public void tick() {
Vec3d prevPosition = getPos();
super.tick();
if (getBrightnessAtEyes() < 0.5F || getTarget() != null) {
ParticleUtils.spawnParticles(ParticleTypes.AMBIENT_ENTITY_EFFECT, this, 6);
if (getWorld().getGameRules().getBoolean(GameRules.DO_MOB_GRIEFING)) {
if (getWorld().getBlockState(getBlockPos()).isIn(BlockTags.REPLACEABLE_BY_TREES)) {
getWorld().breakBlock(getBlockPos(), true);
}
}
}
if (!hasVehicle() && isOnGround()) {
stepDistance += getPos().subtract(prevPosition).horizontalLength() * 0.6F;
if (stepDistance >= nextStepDistance) {
nextStepDistance = stepDistance + 1;
wasLeft = !wasLeft;
float offset = 0.4F;
float yaw = getHeadYaw();
Vec3d offsetVec = new Vec3d((wasLeft ? offset : -offset), 0, 0).rotateY(yaw);
getWorld().addParticle(new FootprintParticleEffect(yaw), true, getX() + offsetVec.getX(), getY(), getZ() + offsetVec.getZ(), 0, 0, 0);
ParticleUtils.spawnParticles(new BlockStateParticleEffect(ParticleTypes.BLOCK, getSteppingBlockState()), getWorld(), getPos(), 6);
playSound(getSteppingBlockState().getSoundGroup().getStepSound(), 0.5F, 1);
}
}
}
@Override
public float getSoundPitch() {
return super.getSoundPitch() * 0.3F;
}
@Override
@Nullable
protected SoundEvent getHurtSound(DamageSource source) {
return null;
}
@Override
protected void playSwimSound(float volume) {
}
@Override
protected void onSwimmingStart() {
}
static class TargetGoal<T extends LivingEntity> extends ActiveTargetGoal<T> {
public TargetGoal(SpecterEntity specter, Class<T> targetEntityClass) {
super(specter, targetEntityClass, true);
}
@SuppressWarnings("deprecation")
@Override
public boolean canStart() {
return mob.getBrightnessAtEyes() < 0.5F && super.canStart();
}
}
}

View file

@ -7,7 +7,6 @@ import com.minelittlepony.unicopia.entity.behaviour.EntityBehaviour;
import com.minelittlepony.unicopia.projectile.MagicBeamEntity;
import com.minelittlepony.unicopia.projectile.MagicProjectileEntity;
import com.minelittlepony.unicopia.projectile.PhysicsBodyProjectileEntity;
import net.fabricmc.fabric.api.biome.v1.BiomeModifications;
import net.fabricmc.fabric.api.biome.v1.BiomeSelectionContext;
import net.fabricmc.fabric.api.biome.v1.BiomeSelectors;
@ -17,13 +16,17 @@ import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityDimensions;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.SpawnGroup;
import net.minecraft.entity.SpawnRestriction.Location;
import net.minecraft.entity.decoration.painting.PaintingVariant;
import net.minecraft.entity.mob.FlyingEntity;
import net.minecraft.entity.mob.HostileEntity;
import net.minecraft.registry.*;
import net.minecraft.registry.tag.BiomeTags;
import net.minecraft.world.Heightmap.Type;
public interface UEntities {
EntityType<ButterflyEntity> BUTTERFLY = register("butterfly", FabricEntityTypeBuilder.create(SpawnGroup.AMBIENT, ButterflyEntity::new)
EntityType<ButterflyEntity> BUTTERFLY = register("butterfly", FabricEntityTypeBuilder.createMob().spawnGroup(SpawnGroup.AMBIENT).entityFactory(ButterflyEntity::new)
.spawnRestriction(Location.NO_RESTRICTIONS, Type.WORLD_SURFACE_WG, ButterflyEntity::canSpawn)
.dimensions(EntityDimensions.fixed(0.25F, 0.25F)));
EntityType<MagicProjectileEntity> THROWN_ITEM = register("thrown_item", FabricEntityTypeBuilder.<MagicProjectileEntity>create(SpawnGroup.MISC, MagicProjectileEntity::new)
.trackRangeBlocks(100)
@ -74,6 +77,11 @@ public interface UEntities {
EntityType<IgnominiousBulbEntity> IGNOMINIOUS_BULB = register("ignominious_bulb", FabricEntityTypeBuilder.<IgnominiousBulbEntity>create(SpawnGroup.MISC, IgnominiousBulbEntity::new)
.trackRangeChunks(8)
.dimensions(EntityDimensions.fixed(3, 2)));
EntityType<SpecterEntity> SPECTER = register("specter", FabricEntityTypeBuilder.createMob().spawnGroup(SpawnGroup.MONSTER).entityFactory(SpecterEntity::new)
.spawnRestriction(Location.ON_GROUND, Type.WORLD_SURFACE, HostileEntity::canSpawnInDark)
.fireImmune()
.spawnableFarFromPlayer()
.dimensions(EntityDimensions.fixed(1, 2)));
static <T extends Entity> EntityType<T> register(String name, FabricEntityTypeBuilder<T> builder) {
EntityType<T> type = builder.build();
@ -89,6 +97,7 @@ public interface UEntities {
FabricDefaultAttributeRegistry.register(FRIENDLY_CREEPER, FriendlyCreeperEntity.createCreeperAttributes());
FabricDefaultAttributeRegistry.register(LOOT_BUG, LootBugEntity.createSilverfishAttributes());
FabricDefaultAttributeRegistry.register(IGNOMINIOUS_BULB, IgnominiousBulbEntity.createMobAttributes());
FabricDefaultAttributeRegistry.register(SPECTER, SpecterEntity.createAttributes());
if (!Unicopia.getConfig().disableButterflySpawning.get()) {
final Predicate<BiomeSelectionContext> butterflySpawnable = BiomeSelectors.foundInOverworld()
@ -105,6 +114,8 @@ public interface UEntities {
), SpawnGroup.AMBIENT, BUTTERFLY, 7, 5, 19);
}
BiomeModifications.addSpawn(BiomeSelectors.spawnsOneOf(EntityType.ZOMBIE), SpawnGroup.MONSTER, SPECTER, 2, 1, 2);
UTradeOffers.bootstrap();
EntityBehaviour.bootstrap();
UEntityAttributes.bootstrap();

View file

@ -7,6 +7,7 @@ import com.minelittlepony.unicopia.ability.magic.SpellPredicate;
import com.minelittlepony.unicopia.ability.magic.spell.AbstractDisguiseSpell;
import com.minelittlepony.unicopia.client.render.spell.DarkVortexSpellRenderer;
import net.minecraft.client.MinecraftClient;
import net.minecraft.util.math.Vec3d;
public class PlayerCamera extends MotionCompositor {
@ -18,30 +19,28 @@ public class PlayerCamera extends MotionCompositor {
}
public float calculateRoll() {
return player.getInterpolator().interpolate("roll", (float)applyModifiers(-getMotionRoll()), 15);
}
double roll = 0;
public float calculateFirstPersonRoll() {
return player.getInterpolator().interpolate("roll_fp", (float)applyModifiers(-getMotionRoll() * getFovScale() * 0.25F), 25);
}
if (player.getMotion().isFlying()) {
Vec3d vel = player.asEntity().getVelocity();
roll -= calculateRoll(player.asEntity(), vel.x, vel.y, vel.z);
}
if (player.getPhysics().isGravityNegative()) {
roll *= -1;
roll += 180;
}
if (player.asEntity().age > 10) {
roll = player.getInterpolator().interpolate("roll", (float)roll, 15);
private double getMotionRoll() {
if (!player.getMotion().isFlying() || player.asEntity().hasVehicle() || player.asEntity().isOnGround()) {
return 0;
}
Vec3d vel = player.asEntity().getVelocity();
return calculateRoll(player.asEntity(), vel.x, vel.y, vel.z);
}
private double applyModifiers(double motionRoll) {
if (player.getAcrobatics().isFloppy()) {
roll += 90;
motionRoll += 90;
}
return (float)roll;
return player.getPhysics().isGravityNegative() ? 180 - motionRoll : motionRoll;
}
public float calculatePitch(float pitch) {
@ -61,13 +60,16 @@ public class PlayerCamera extends MotionCompositor {
}
public double calculateFieldOfView(double fov) {
fov += player.getMagicalReserves().getExertion().get() / 5F;
fov += getEnergyAddition();
fov += (player.getMagicalReserves().getExertion().get() / 5F) * getFovScale();
fov += getEnergyAddition() * getFovScale();
fov += DarkVortexSpellRenderer.getCameraDistortion() * 2.5F;
return fov;
}
private float getFovScale() {
return MinecraftClient.getInstance().options.getFovEffectScale().getValue().floatValue();
}
protected float getEnergyAddition() {
int maxE = (int)Math.floor(player.getMagicalReserves().getEnergy().get() * 100);

View file

@ -32,7 +32,6 @@ import com.minelittlepony.unicopia.util.*;
import net.fabricmc.fabric.api.tag.convention.v1.ConventionalBlockTags;
import net.minecraft.block.*;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.EntityPose;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.LightningEntity;
@ -253,18 +252,6 @@ public class PlayerPhysics extends EntityPhysics<PlayerEntity> implements Tickab
final MutableVector velocity = new MutableVector(entity.getVelocity());
if (isGravityNegative()) {
velocity.y *= -1;
}
if (isGravityNegative() && !entity.isSneaking() && entity.isInSneakingPose()) {
float currentHeight = entity.getDimensions(entity.getPose()).height;
float sneakingHeight = entity.getDimensions(EntityPose.STANDING).height;
entity.setPos(entity.getX(), entity.getY() + currentHeight - sneakingHeight, entity.getZ());
entity.setPose(EntityPose.STANDING);
}
FlightType type = recalculateFlightType();
boolean typeChanged = type != lastFlightType;
@ -396,10 +383,6 @@ public class PlayerPhysics extends EntityPhysics<PlayerEntity> implements Tickab
velocity.z /= heavyness;
}
if (isGravityNegative()) {
velocity.y *= -1;
}
entity.setVelocity(velocity.toImmutable());
if (isFlying() && !entity.isFallFlying() && !pony.getAcrobatics().isHanging() && pony.isClient()) {

View file

@ -5,9 +5,7 @@ import java.util.Optional;
import org.spongepowered.asm.mixin.*;
import org.spongepowered.asm.mixin.gen.Accessor;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Constant;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.ModifyConstant;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@ -178,14 +176,6 @@ abstract class MixinLivingEntity extends Entity implements LivingEntityDuck, Equ
}
}
@ModifyConstant(method = "travel(Lnet/minecraft/util/math/Vec3d;)V", constant = {
@Constant(doubleValue = 0.08D),
@Constant(doubleValue = 0.01D)
})
private double modifyGravity(double initial) {
return get().getPhysics().calcGravity(initial);
}
@Override
public void updateItemUsage(Hand hand, ItemStack stack, int time) {
activeItemStack = stack;

View file

@ -9,7 +9,6 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import com.minelittlepony.unicopia.entity.*;
import com.minelittlepony.unicopia.entity.duck.RotatedView;
import com.minelittlepony.unicopia.item.enchantment.WantItNeedItEnchantment;
import net.minecraft.entity.EntityType;
@ -33,18 +32,6 @@ abstract class MixinMobEntity extends LivingEntity implements Equine.Container<C
get().initAi(goalSelector, targetSelector);
}
@Inject(method = "tickNewAi", at = @At("HEAD"))
public void beforeTickAi(CallbackInfo into) {
if (get().getPhysics().isGravityNegative()) {
((RotatedView)getWorld()).pushRotation((int)getY());
}
}
@Inject(method = "tickNewAi", at = @At("RETURN"))
public void afterTickAi(CallbackInfo into) {
((RotatedView)getWorld()).popRotation();
}
@Inject(method = "prefersNewEquipment(Lnet/minecraft/item/ItemStack;Lnet/minecraft/item/ItemStack;)Z",
at = @At("HEAD"), cancellable = true)
private void onPrefersNewEquipment(ItemStack newStack, ItemStack oldStack, CallbackInfoReturnable<Boolean> info) {

View file

@ -97,14 +97,6 @@ abstract class MixinPlayerEntity extends LivingEntity implements Equine.Containe
get().getMotion().getDimensions().calculateActiveEyeHeight(dimensions).ifPresent(info::setReturnValue);
}
/*
@Inject(method = "getDimensions(Lnet/minecraft/entity/EntityPose;)Lnet/minecraft/entity/EntityDimensions;",
at = @At("RETURN"),
cancellable = true)
private void onGetDimensions(EntityPose pose, CallbackInfoReturnable<EntityDimensions> info) {
get().getMotion().getDimensions().calculateDimensions().ifPresent(info::setReturnValue);
}*/
@Redirect(method = "getDimensions(Lnet/minecraft/entity/EntityPose;)Lnet/minecraft/entity/EntityDimensions;",
at = @At(
value = "INVOKE",

View file

@ -1,19 +1,13 @@
package com.minelittlepony.unicopia.mixin;
import java.util.Stack;
import java.util.function.Supplier;
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.ModifyVariable;
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 net.minecraft.block.BlockState;
import net.minecraft.entity.Entity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraft.world.WorldAccess;
@ -22,20 +16,8 @@ abstract class MixinWorld implements WorldAccess, BlockDestructionManager.Source
private final Supplier<BlockDestructionManager> destructions = BlockDestructionManager.create((World)(Object)this);
private int recurseCount = 0;
private final Stack<Integer> rotations = new Stack<>();
private boolean mirrorEntityStatuses;
@Override
public Stack<Integer> getRotations() {
return rotations;
}
@Override
public boolean hasTransform() {
return recurseCount <= 0;
}
@Override
public void setMirrorEntityStatuses(boolean enable) {
mirrorEntityStatuses = enable;
@ -52,17 +34,5 @@ abstract class MixinWorld implements WorldAccess, BlockDestructionManager.Source
entity.handleStatus(status);
}
}
@ModifyVariable(method = "setBlockState(Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/BlockState;II)Z", at = @At("HEAD"))
private BlockPos modifyBlockPos(BlockPos pos) {
pos = applyRotation(pos);
recurseCount = Math.max(0, recurseCount) + 1;
return pos;
}
@Inject(method = "setBlockState(Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/BlockState;II)Z", at = @At("RETURN"))
public void onSetBlockState(BlockPos pos, BlockState state, int flags, int maxUpdateDepth, CallbackInfoReturnable<Boolean> info) {
recurseCount = Math.max(0, recurseCount - 1);
}
}

View file

@ -36,7 +36,7 @@ abstract class MixinGameRenderer implements AutoCloseable, SynchronousResourceRe
@Inject(method = "renderWorld(FJLnet/minecraft/client/util/math/MatrixStack;)V",
at = @At("HEAD"))
private void beforeRenderWorld(float tickDelta, long limitTime, MatrixStack matrices, CallbackInfo info) {
UnicopiaClient.getCamera().ifPresent(c -> matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(c.calculateRoll())));
UnicopiaClient.getCamera().ifPresent(c -> matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(c.calculateFirstPersonRoll())));
BatEyesApplicator.INSTANCE.enable();
}

View file

@ -28,11 +28,11 @@ abstract class MixinKeyboardInput extends Input {
movementSideways = -movementSideways;
if (player.asEntity().getAbilities().flying && !player.getPhysics().isFlying()) {
/*if (player.asEntity().getAbilities().flying && !player.getPhysics().isFlying()) {
tmp = jumping;
jumping = sneaking;
sneaking = tmp;
}
}*/
}
if (EffectUtils.getAmplifier(MinecraftClient.getInstance().player, UEffects.PARALYSIS) > 1) {

View file

@ -1,4 +1,4 @@
package com.minelittlepony.unicopia.mixin;
package com.minelittlepony.unicopia.mixin.gravity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
@ -21,7 +21,7 @@ abstract class MixinBrain<E extends LivingEntity> {
Equine<?> eq = Equine.of(entity).orElse(null);
if (eq instanceof Living<?> && eq.getPhysics().isGravityNegative()) {
((RotatedView)world).pushRotation((int)entity.getY());
((RotatedView)world).pushRotation((int)(entity.getY() + entity.getHeight() * 0.5F));
}
}

View file

@ -0,0 +1,30 @@
package com.minelittlepony.unicopia.mixin.gravity;
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.entity.Equine;
import com.minelittlepony.unicopia.entity.duck.RotatedView;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.entity.Entity;
@Mixin(ClientWorld.class)
abstract class MixinClientWorld implements RotatedView {
@Inject(method = "tickEntity", at = @At("HEAD"))
private void beforeTickEntity(Entity entity, CallbackInfo info) {
if (entity instanceof Equine.Container eq && eq.get().getPhysics().isGravityNegative()) {
// pushRotation((int)(entity.getY() + entity.getHeight() * 0.5F));
}
}
@Inject(method = "tickEntity", at = @At("RETURN"))
private void afterTickEntity(Entity entity, CallbackInfo info) {
if (entity instanceof Equine.Container eq && eq.get().getPhysics().isGravityNegative()) {
// popRotation();
}
}
}

View file

@ -0,0 +1,76 @@
package com.minelittlepony.unicopia.mixin.gravity;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.At.Shift;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.ModifyVariable;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import com.minelittlepony.unicopia.entity.Equine;
import net.minecraft.entity.Entity;
import net.minecraft.entity.MovementType;
import net.minecraft.util.math.Vec3d;
@Mixin(value = Entity.class, priority = 29000)
abstract class MixinEntity {
// we invert y when moving
@ModifyVariable(method = "move", at = @At("HEAD"), argsOnly = true)
private Vec3d modifyMovement(Vec3d movement) {
if (this instanceof Equine.Container eq && eq.get().getPhysics().isGravityNegative()) {
return movement.multiply(1, -1, 1);
}
return movement;
}
// fix on ground check
@Inject(method = "move", at = @At(value = "FIELD", target = "net/minecraft/entity/Entity.groundCollision:Z", shift = Shift.AFTER, ordinal = 0))
private void onUpdateOnGroundFlag(MovementType movementType, Vec3d movement, CallbackInfo info) {
if (this instanceof Equine.Container eq && eq.get().getPhysics().isGravityNegative()) {
eq.get().asEntity().groundCollision = eq.get().asEntity().verticalCollision && movement.y > 0.0;
}
}
// invert jumping velocity so we can jump
@Inject(method = "getJumpVelocityMultiplier", at = @At("RETURN"), cancellable = true)
private void onGetJumpVelocityMultiplier(CallbackInfoReturnable<Float> info) {
if (this instanceof Equine.Container eq && eq.get().getPhysics().isGravityNegative()) {
info.setReturnValue(-info.getReturnValue());
}
}
// invert offsets so it can properly find the block we're walking on
@ModifyVariable(method = "getPosWithYOffset", at = @At("HEAD"), argsOnly = true)
private float onGetPosWithYOffset(float offset) {
if (this instanceof Equine.Container eq && eq.get().getPhysics().isGravityNegative()) {
return -(eq.get().asEntity().getHeight() + offset);
}
return offset;
}
// fix sprinting particles
@Inject(method = "spawnSprintingParticles", at = @At("HEAD"), cancellable = true)
protected void spawnSprintingParticles(CallbackInfo info) {
if (this instanceof Equine.Container eq && eq.get().getPhysics().isGravityNegative()) {
eq.get().getPhysics().spawnSprintingParticles();
info.cancel();
}
}
// invert check for walking up a step
@ModifyVariable(
method = "adjustMovementForCollisions(Lnet/minecraft/entity/Entity;Lnet/minecraft/util/math/Vec3d;Lnet/minecraft/util/math/Box;Lnet/minecraft/world/World;Ljava/util/List;)Lnet/minecraft/util/math/Vec3d;",
at = @At("HEAD"),
argsOnly = true)
private static Vec3d modifyMovementForStepheight(Vec3d movement, @Nullable Entity entity) {
if (entity != null && movement.getY() == entity.getStepHeight()) {
return movement.multiply(1, -1, 1);
}
return movement;
}
}

View file

@ -0,0 +1,22 @@
package com.minelittlepony.unicopia.mixin.gravity;
import org.spongepowered.asm.mixin.*;
import org.spongepowered.asm.mixin.injection.Constant;
import org.spongepowered.asm.mixin.injection.ModifyConstant;
import com.minelittlepony.unicopia.entity.*;
import net.minecraft.entity.Entity;
import net.minecraft.entity.LivingEntity;
@Mixin(LivingEntity.class)
abstract class MixinLivingEntity extends Entity implements Equine.Container<Living<?>> {
private MixinLivingEntity() { super(null, null); }
@ModifyConstant(method = "travel(Lnet/minecraft/util/math/Vec3d;)V", constant = {
@Constant(doubleValue = 0.08D),
@Constant(doubleValue = 0.01D)
})
private double modifyGravity(double initial) {
return Math.abs(get().getPhysics().calcGravity(initial));
}
}

View file

@ -0,0 +1,28 @@
package com.minelittlepony.unicopia.mixin.gravity;
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.entity.*;
import com.minelittlepony.unicopia.entity.duck.RotatedView;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.mob.MobEntity;
@Mixin(MobEntity.class)
abstract class MixinMobEntity extends LivingEntity implements Equine.Container<Creature> {
private MixinMobEntity() { super(null, null); }
@Inject(method = "tickNewAi", at = @At("HEAD"))
public void beforeTickAi(CallbackInfo into) {
if (get().getPhysics().isGravityNegative()) {
((RotatedView)getWorld()).pushRotation((int)(getY() + getHeight() * 0.5F));
}
}
@Inject(method = "tickNewAi", at = @At("RETURN"))
public void afterTickAi(CallbackInfo into) {
((RotatedView)getWorld()).popRotation();
}
}

View file

@ -0,0 +1,29 @@
package com.minelittlepony.unicopia.mixin.gravity;
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.entity.Equine;
import com.minelittlepony.unicopia.entity.duck.RotatedView;
import net.minecraft.entity.Entity;
import net.minecraft.server.world.ServerWorld;
@Mixin(ServerWorld.class)
abstract class MixinServerWorld implements RotatedView {
@Inject(method = "tickEntity", at = @At("HEAD"))
private void beforeTickEntity(Entity entity, CallbackInfo info) {
if (entity instanceof Equine.Container eq && eq.get().getPhysics().isGravityNegative()) {
// pushRotation((int)(entity.getY() + entity.getHeight() * 0.5F));
}
}
@Inject(method = "tickEntity", at = @At("RETURN"))
private void afterTickEntity(Entity entity, CallbackInfo info) {
if (entity instanceof Equine.Container eq && eq.get().getPhysics().isGravityNegative()) {
// popRotation();
}
}
}

View file

@ -0,0 +1,17 @@
package com.minelittlepony.unicopia.mixin.gravity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.ModifyVariable;
import com.minelittlepony.unicopia.client.UnicopiaClient;
import net.minecraft.client.sound.Source;
import net.minecraft.util.math.Vec3d;
@Mixin(Source.class)
abstract class MixinSoundSource {
@ModifyVariable(method = "setPosition", at = @At("HEAD"), argsOnly = true)
private Vec3d modifyPosition(Vec3d pos) {
return UnicopiaClient.getAdjustedSoundPosition(pos);
}
}

View file

@ -0,0 +1,43 @@
package com.minelittlepony.unicopia.mixin.gravity;
import java.util.Stack;
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.ModifyVariable;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import com.minelittlepony.unicopia.entity.duck.RotatedView;
import net.minecraft.block.BlockState;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraft.world.WorldAccess;
@Mixin(World.class)
abstract class MixinWorld implements WorldAccess, RotatedView {
private int recurseCount = 0;
private final Stack<Integer> rotations = new Stack<>();
@Override
public Stack<Integer> getRotations() {
return rotations;
}
@Override
public boolean hasTransform() {
return recurseCount <= 0;
}
@ModifyVariable(method = "setBlockState(Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/BlockState;II)Z", at = @At("HEAD"))
private BlockPos modifyBlockPos(BlockPos pos) {
pos = applyRotation(pos);
recurseCount = Math.max(0, recurseCount) + 1;
return pos;
}
@Inject(method = "setBlockState(Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/BlockState;II)Z", at = @At("RETURN"))
public void onSetBlockState(BlockPos pos, BlockState state, int flags, int maxUpdateDepth, CallbackInfoReturnable<Boolean> info) {
recurseCount = Math.max(0, recurseCount - 1);
}
}

View file

@ -1,4 +1,4 @@
package com.minelittlepony.unicopia.mixin;
package com.minelittlepony.unicopia.mixin.gravity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;

View file

@ -0,0 +1,42 @@
package com.minelittlepony.unicopia.particle;
import java.util.Locale;
import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import net.minecraft.particle.ParticleEffect;
import net.minecraft.particle.ParticleType;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.registry.Registries;
public record FootprintParticleEffect (
float yaw
) implements ParticleEffect {
@SuppressWarnings("deprecation")
public static final ParticleEffect.Factory<FootprintParticleEffect> FACTORY = ParticleFactoryHelper.of(FootprintParticleEffect::new, FootprintParticleEffect::new);
protected FootprintParticleEffect(ParticleType<FootprintParticleEffect> type, StringReader reader) throws CommandSyntaxException {
this(ParticleFactoryHelper.readFloat(reader));
}
protected FootprintParticleEffect(ParticleType<FootprintParticleEffect> particleType, PacketByteBuf buf) {
this(buf.readFloat());
}
@Override
public ParticleType<?> getType() {
return UParticles.FOOTPRINT;
}
@Override
public void write(PacketByteBuf buf) {
buf.writeFloat(yaw);
}
@Override
public String asString() {
return String.format(Locale.ROOT, "%s %.2f", Registries.PARTICLE_TYPE.getId(getType()), yaw);
}
}

View file

@ -14,14 +14,12 @@ public interface UParticles {
ParticleType<MagicParticleEffect> UNICORN_MAGIC = register("unicorn_magic", FabricParticleTypes.complex(MagicParticleEffect.FACTORY));
DefaultParticleType CHANGELING_MAGIC = register("changeling_magic", FabricParticleTypes.simple());
DefaultParticleType BUBBLE = register("bubble", FabricParticleTypes.simple());
ParticleType<FootprintParticleEffect> FOOTPRINT = register("footprint", FabricParticleTypes.complex(FootprintParticleEffect.FACTORY));
ParticleType<BlockStateParticleEffect> DUST_CLOUD = register("dust_cloud", FabricParticleTypes.complex(BlockStateParticleEffect.PARAMETERS_FACTORY));
ParticleType<OrientedBillboardParticleEffect> RAINBOOM_RING = register("rainboom_ring", FabricParticleTypes.complex(OrientedBillboardParticleEffect.FACTORY));
ParticleType<TargetBoundParticleEffect> RAINBOOM_TRAIL = register("rainboom_trail", FabricParticleTypes.complex(TargetBoundParticleEffect.FACTORY));
@Deprecated
ParticleType<OrientedBillboardParticleEffect> MAGIC_RUNES = register("magic_runes", FabricParticleTypes.complex(OrientedBillboardParticleEffect.FACTORY));
DefaultParticleType RAIN_DROPS = register("rain_drops", FabricParticleTypes.simple());
ParticleType<SphereParticleEffect> SPHERE = register("sphere", FabricParticleTypes.complex(true, SphereParticleEffect.FACTORY));

View file

@ -1,5 +1,6 @@
package com.minelittlepony.unicopia.util;
import net.minecraft.util.Util;
import net.minecraft.util.math.Box;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.MathHelper;
@ -14,7 +15,7 @@ public interface VoxelShapeUtil {
Vec3d CENTER = new Vec3d(0.5, 0, 0.5);
static Function<Direction, VoxelShape> rotator(VoxelShape base) {
return d -> rotate(base, d);
return Util.memoize(d -> rotate(base, d));
}
static VoxelShape rotate(VoxelShape shape, Direction direction) {
@ -27,7 +28,7 @@ public interface VoxelShapeUtil {
float angle = direction.asRotation() * MathHelper.RADIANS_PER_DEGREE;
return VoxelShapes.union(VoxelShapes.empty(), shape.getBoundingBoxes().stream()
.map(box -> {
//These first two are enough for orthogonal rotations
//These first two are enough for orthogonal rotations
Vec3d a = rotate(box.minX, box.minZ, angle);
Vec3d b = rotate(box.maxX, box.maxZ, angle);
//These cover odd angles

View file

@ -280,6 +280,7 @@
"block.unicopia.golden_oak_leaves": "Golden Oak Leaves",
"block.unicopia.golden_oak_log": "Golden Oak Log",
"block.unicopia.mango": "Mango",
"block.unicopia.worm_block": "Block of Worms",
"block.unicopia.mango_leaves": "Mango Leaves",
"block.unicopia.mango_sapling": "Mango Sapling",
"block.unicopia.potted_mango_sapling": "Potted Mango Sapling",
@ -355,6 +356,7 @@
"entity.unicopia.butterfly": "Butterfly",
"entity.unicopia.twittermite": "Twittermite",
"entity.unicopia.specter": "Specter",
"entity.unicopia.cast_spell": "Cast Spell",
"entity.unicopia.cast_spell.by": "a spell cast by %s",
"entity.unicopia.spellbook": "Spellbook",
@ -1598,6 +1600,8 @@
"advancements.unicopia.take_a_note.description": "Obtain a dragon breath scroll",
"advancements.unicopia.dear_princess.title": "Dear princess...",
"advancements.unicopia.dear_princess.description": "Send a letter with a dragon's breath scroll",
"advancements.unicopia.i_await_your_reply.title": "I Await Your Reply",
"advancements.unicopia.i_await_your_reply.description": "Use the dragon's breath scroll to send someone a dragon's breath scroll",
"advancements.unicopia.baked_bads.title": "Baked Bads",
"advancements.unicopia.baked_bads.description": "Bake a delicious muffin",
"advancements.unicopia.mid_flight_interruption.title": "Mid-Flight Interruption",
@ -1618,6 +1622,10 @@
"advancements.unicopia.eat_trick_apple.description": "Bite into a zap apple",
"advancements.unicopia.eat_pinecone.title": "Desperation",
"advancements.unicopia.eat_pinecone.description": "Eat a pinecone",
"advancements.unicopia.what_the_hay.title": "What The Hay",
"advancements.unicopia.what_the_hay.description": "Eat an entire block of hay",
"advancements.unicopia.oats_so_easy.title": "Oats So Easy",
"advancements.unicopia.oats_so_easy.description": "Farm some oats",
"advancements.unicopia.imported_oats.title": "Delicious As They Are Expensive",
"advancements.unicopia.imported_oats.description": "Send or receive fancy imported oats",
@ -1647,11 +1655,15 @@
"advancements.unicopia.sweet_apple_acres.description": "Obtain one of every apple",
"advancements.unicopia.brew_cider.title": "Applejack's Finest",
"advancements.unicopia.brew_cider.description": "Brew some cider",
"advancements.unicopia.basket_case.title": "Basket Case",
"advancements.unicopia.basket_case.description": "Weave a basket",
"advancements.unicopia.aeronaut.title": "Aeronaut",
"advancements.unicopia.aeronaut.description": "Equip your basket with a lantern and hot air balloon",
"advancements.unicopia.travelling_in_style.title": "Travelling in Style",
"advancements.unicopia.travelling_in_style.description": "Ride a hot air balloon",
"advancements.unicopia.night_route.title": "Children of The Night",
"advancements.unicopia.night_route.description": "Walk the path of the night",
"advancements.unicopia.bat_route.title": "Children of The Night",
"advancements.unicopia.bat_route.description": "Walk the path of the night",
"advancements.unicopia.screech_twenty_mobs.title": "Terror From The Skies",
"advancements.unicopia.screech_twenty_mobs.description": "Rain down terror on at least 20 mobs at once",
"advancements.unicopia.screech_self.title": "Jeepers!",
@ -1668,6 +1680,14 @@
"advancements.unicopia.earth_route.description": "Join the Apple Clan",
"advancements.unicopia.sticks_and_stones.title": "Sticks and Stones",
"advancements.unicopia.sticks_and_stones.description": "Kill a mob by throwing rocks at it",
"advancements.unicopia.blacksmith.title": "Blacksmith",
"advancements.unicopia.blacksmith.description": "Craft a horseshoe",
"advancements.unicopia.change_of_shoes.title": "A Change of Shoes",
"advancements.unicopia.change_of_shoes.description": "Craft an iron horse shoe",
"advancements.unicopia.fashionably_expensive.title": "Fashionably Expensive",
"advancements.unicopia.fashionably_expensive.description": "Upgrade to a set of golden horse shoes",
"advancements.unicopia.overkill.title": "Overkill",
"advancements.unicopia.overkill.description": "Craft a netherite horse shoe",
"advancements.unicopia.dead_ringer.title": "Dead Ringer",
"advancements.unicopia.dead_ringer.description": "Kill a mob with a horseshoe",
"advancements.unicopia.born_on_a_rock_farm.title": "Born on a Rock Farm",
@ -1675,8 +1695,8 @@
"advancements.unicopia.thats_unusual.title": "That's Unusual",
"advancements.unicopia.thats_unusual.description": "But what does it do?",
"advancements.unicopia.sky_route.title": "Path of the Pegasus",
"advancements.unicopia.sky_route.description": "Join the Clousdale Pegasi",
"advancements.unicopia.pegasus_route.title": "Path of the Pegasus",
"advancements.unicopia.pegasus_route.description": "Join the Clousdale Pegasi",
"advancements.unicopia.molting_season_1.title": "Molting Season",
"advancements.unicopia.molting_season_1.description": "Drop your first feather whilst flying",
"advancements.unicopia.molting_season_2.title": "Molting Season 2",
@ -1708,11 +1728,13 @@
"advancements.unicopia.deter_phantom.title": "What Flies Around",
"advancements.unicopia.deter_phantom.description": "Get up there and give those phantoms a taste of their own medicine",
"advancements.unicopia.magical_route.title": "Horn of the Unicorn",
"advancements.unicopia.magical_route.description": "Delve into the world of glitter and rainbows",
"advancements.unicopia.unicorn_route.title": "Horn of the Unicorn",
"advancements.unicopia.unicorn_route.description": "Delve into the world of glitter and rainbows",
"advancements.unicopia.books.title": "Books!",
"advancements.unicopia.books.description": "This is MY spellbook and I'm going to READ it!",
"advancements.unicopia.books_books_books.title": "Books! Books! Books!",
"advancements.unicopia.books_books_books.description": "Have an inventory full of books",
"advancements.unicopia.tempted.title": "Tempting...",
"advancements.unicopia.tempted.description": "Put on the alicorn amulet",
"advancements.unicopia.hello_darkness_my_old_friend.title": "Hello Darkness...",

View file

@ -0,0 +1,5 @@
{
"textures": [
"unicopia:footprint"
]
}

Binary file not shown.

After

(image error) Size: 6.9 KiB

Binary file not shown.

After

(image error) Size: 6.8 KiB

View file

@ -2,7 +2,8 @@
"replace": false,
"values": [
"minecraft:spider_eye",
"unicopia:butterfly",
"unicopia:wheat_worms",
"unicopia:butterfly"
"unicopia:worm_block"
]
}

View file

@ -1,8 +1,8 @@
{
"tags": [ "unicopia:food_types/raw_insect" ],
"food_component": {
"hunger": 1,
"saturation": 0.1
"hunger": 6,
"saturation": 0.3
},
"ailment": {
"effects": [

View file

@ -74,6 +74,18 @@
]
}
},
{
"tags": [
"unicopia:food_types/raw_insect"
],
"food_component": {
"hunger": 3,
"saturation": 2
},
"ailment": {
"effects": [ ]
}
},
{
"tags": [
"unicopia:food_types/cooked_fish",
@ -98,11 +110,14 @@
"tags": [
"unicopia:food_types/rotten_fish",
"unicopia:food_types/cooked_insect",
"unicopia:food_types/raw_insect",
"unicopia:food_types/cooked_meat",
"unicopia:food_types/raw_meat",
"unicopia:food_types/rotten_meat"
],
"food_component": {
"hunger": 6,
"saturation": 9
},
"ailment": {
"effects": [
{

View file

@ -57,6 +57,7 @@
"unicopia:crispy_hay_fries",
"unicopia:horse_shoe_fries",
"unicopia:wheat_worms",
"unicopia:worm_block",
"unicopia:muffin",
"unicopia:acorn",
"unicopia:pinecone",

View file

@ -13,7 +13,6 @@
"MixinBlockEntityType",
"MixinBlockItem",
"MixinBoatEntity",
"MixinBrain",
"MixinChunkBlockLightProvider",
"MutableBlockLightStorage",
"MixinDamageSource",
@ -53,8 +52,14 @@
"MixinVanillaBiomeParameters",
"MixinWardenEntity",
"MixinWorld",
"MixinWorldChunk",
"PointOfInterestTypesAccessor",
"gravity.MixinBrain",
"gravity.MixinEntity",
"gravity.MixinLivingEntity",
"gravity.MixinMobEntity",
"gravity.MixinWorld",
"gravity.MixinServerWorld",
"gravity.MixinWorldChunk",
"trinkets.MixinTrinketSurvivalSlot",
"trinkets.MixinTrinketItem",
"trinkets.MixinTrinketInventory",
@ -88,7 +93,9 @@
"client.MixinWorldRenderer",
"client.sodium.MixinSodiumWorldRenderer",
"client.minelp.MixinPonyPosture",
"trinkets.MixinTrinketCreativeSlot"
"trinkets.MixinTrinketCreativeSlot",
"gravity.MixinClientWorld",
"gravity.MixinSoundSource"
],
"injectors": {
"defaultRequire": 1