Added zap apple trees

This commit is contained in:
Sollace 2022-09-23 23:25:00 +02:00
parent 94d81ff5f5
commit def7e37712
40 changed files with 755 additions and 8 deletions

View file

@ -18,12 +18,16 @@ public interface UTags {
TagKey<Item> SHADES = item("shades");
TagKey<Item> POLEARMS = item("polearms");
TagKey<Block> FRAGILE = block("fragile");
TagKey<Block> INTERESTING = block("interesting");
TagKey<Block> CRYSTAL_HEART_BASE = block("crystal_heart_base");
TagKey<Block> CRYSTAL_HEART_ORNAMENT = block("crystal_heart_ornament");
TagKey<Block> POLEARM_MINEABLE = block("mineable/polearm");
TagKey<EntityType<?>> TRANSFORMABLE_ENTITIES = entity("transformable");
static TagKey<Item> item(String name) {

View file

@ -17,7 +17,9 @@ import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
import com.minelittlepony.unicopia.ability.magic.spell.trait.TraitLoader;
import com.minelittlepony.unicopia.advancement.UCriteria;
import com.minelittlepony.unicopia.block.UBlocks;
import com.minelittlepony.unicopia.block.UTreeGen;
import com.minelittlepony.unicopia.block.data.BlockDestructionManager;
import com.minelittlepony.unicopia.block.data.ZapAppleStageStore;
import com.minelittlepony.unicopia.block.state.StateMapLoader;
import com.minelittlepony.unicopia.command.Commands;
import com.minelittlepony.unicopia.container.SpellbookChapterLoader;
@ -59,6 +61,7 @@ public class Unicopia implements ModInitializer {
ServerTickEvents.END_WORLD_TICK.register(w -> {
((BlockDestructionManager.Source)w).getDestructionManager().tick();
ZapAppleStageStore.get(w).tick();
if (SpellbookChapterLoader.DEBUG) {
SpellbookChapterLoader.INSTANCE.sendUpdate(w.getServer());
}
@ -78,6 +81,7 @@ public class Unicopia implements ModInitializer {
SpellType.bootstrap();
Abilities.bootstrap();
UScreenHandlers.bootstrap();
UTreeGen.bootstrap();
}
public interface SidedAccess {

View file

@ -0,0 +1,57 @@
package com.minelittlepony.unicopia.block;
import net.minecraft.block.*;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.random.Random;
import net.minecraft.util.shape.VoxelShape;
import net.minecraft.util.shape.VoxelShapes;
import net.minecraft.world.BlockView;
import net.minecraft.world.WorldView;
public class FruitBlock extends Block {
public static final int DEFAULT_FRUIT_SIZE = 8;
public static final VoxelShape DEFAULT_SHAPE = createFruitShape(DEFAULT_FRUIT_SIZE);
private final Direction attachmentFace;
private final Block stem;
private final VoxelShape shape;
public static VoxelShape createFruitShape(int fruitSize) {
int min = (16 - fruitSize) / 2;
int max = 16 - min;
return VoxelShapes.cuboid(min / 16D, (max - fruitSize) / 16D, min / 16D, max / 16D, 1, max / 16D);
}
public FruitBlock(Settings settings, Direction attachmentFace, Block stem, VoxelShape shape) {
super(settings.nonOpaque().suffocates(UBlocks::never).blockVision(UBlocks::never));
this.attachmentFace = attachmentFace;
this.stem = stem;
this.shape = shape;
}
@Override
public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
return shape;
}
@Override
public boolean canPlaceAt(BlockState state, WorldView world, BlockPos pos) {
BlockPos attachedPos = pos.offset(attachmentFace.getOpposite());
BlockState attachedState = world.getBlockState(attachedPos);
return canAttachTo(attachedState) && attachedState.isSideSolidFullSquare(world, attachedPos, attachmentFace);
}
@Override
public void scheduledTick(BlockState state, ServerWorld world, BlockPos pos, Random random) {
if (!state.canPlaceAt(world, pos)) {
world.breakBlock(pos, true);
}
}
protected boolean canAttachTo(BlockState state) {
return state.isOf(stem);
}
}

View file

@ -4,11 +4,17 @@ import com.minelittlepony.unicopia.Unicopia;
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
import net.fabricmc.fabric.api.object.builder.v1.block.FabricMaterialBuilder;
import net.minecraft.block.Block;
import net.minecraft.block.Blocks;
import net.minecraft.block.MapColor;
import net.minecraft.block.*;
import net.minecraft.block.sapling.SaplingGenerator;
import net.minecraft.entity.EntityType;
import net.minecraft.sound.BlockSoundGroup;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.random.Random;
import net.minecraft.util.registry.Registry;
import net.minecraft.util.registry.RegistryEntry;
import net.minecraft.world.BlockView;
import net.minecraft.world.gen.feature.ConfiguredFeature;
public interface UBlocks {
Block ROCKS = register("rocks", new RockCropBlock(FabricBlockSettings.of(
@ -21,9 +27,30 @@ public interface UBlocks {
Block FROSTED_OBSIDIAN = register("frosted_obsidian", new FrostedObsidianBlock(FabricBlockSettings.copy(Blocks.OBSIDIAN).ticksRandomly()));
Block ZAPLING = register("zapling", new SaplingBlock(new SaplingGenerator() {
@Override
protected RegistryEntry<? extends ConfiguredFeature<?, ?>> getTreeFeature(Random rng, boolean flowersNearby) {
return UTreeGen.ZAP_APPLE_TREE;
}
}, FabricBlockSettings.copy(Blocks.OAK_SAPLING)));
Block ZAP_LOG = register("zap_log", new ZapAppleLogBlock(MapColor.GRAY, MapColor.DEEPSLATE_GRAY));
Block ZAP_LEAVES = register("zap_leaves", new ZapAppleLeavesBlock());
Block ZAP_BULB = register("zap_bulb", new FruitBlock(FabricBlockSettings.of(Material.GOURD, MapColor.GRAY).strength(500, 1200).sounds(BlockSoundGroup.AZALEA_LEAVES), Direction.DOWN, ZAP_LEAVES, FruitBlock.DEFAULT_SHAPE));
Block ZAP_APPLE = register("zap_apple", new FruitBlock(FabricBlockSettings.of(Material.GOURD, MapColor.GRAY).sounds(BlockSoundGroup.AZALEA_LEAVES), Direction.DOWN, ZAP_LEAVES, FruitBlock.DEFAULT_SHAPE));
private static <T extends Block> T register(String name, T item) {
return Registry.register(Registry.BLOCK, Unicopia.id(name), item);
}
static void bootstrap() {}
static boolean never(BlockState state, BlockView world, BlockPos pos) {
return false;
}
static Boolean canSpawnOnLeaves(BlockState state, BlockView world, BlockPos pos, EntityType<?> type) {
return type == EntityType.OCELOT || type == EntityType.PARROT;
}
}

View file

@ -0,0 +1,41 @@
package com.minelittlepony.unicopia.block;
import net.fabricmc.fabric.api.biome.v1.*;
import net.minecraft.tag.BiomeTags;
import net.minecraft.tag.BlockTags;
import net.minecraft.util.math.intprovider.ConstantIntProvider;
import net.minecraft.util.math.intprovider.UniformIntProvider;
import net.minecraft.util.registry.*;
import net.minecraft.world.gen.GenerationStep;
import net.minecraft.world.gen.feature.*;
import net.minecraft.world.gen.feature.size.TwoLayersFeatureSize;
import net.minecraft.world.gen.foliage.JungleFoliagePlacer;
import net.minecraft.world.gen.stateprovider.BlockStateProvider;
import net.minecraft.world.gen.trunk.UpwardsBranchingTrunkPlacer;
public interface UTreeGen {
RegistryEntry<ConfiguredFeature<TreeFeatureConfig, ?>> ZAP_APPLE_TREE = ConfiguredFeatures.register("unicopia:zap_apple_tree", Feature.TREE, new TreeFeatureConfig.Builder(
BlockStateProvider.of(UBlocks.ZAP_LOG),
new UpwardsBranchingTrunkPlacer(7, 2, 3,
UniformIntProvider.create(3, 6), 0.3f,
UniformIntProvider.create(1, 3),
Registry.BLOCK.getOrCreateEntryList(BlockTags.MANGROVE_LOGS_CAN_GROW_THROUGH)
),
BlockStateProvider.of(UBlocks.ZAP_LEAVES),
new JungleFoliagePlacer(
ConstantIntProvider.create(3),
ConstantIntProvider.create(2),
3
),
new TwoLayersFeatureSize(6, 0, 16)
).forceDirt()
.build()
);
RegistryEntry<PlacedFeature> TREES_ZAP = PlacedFeatures.register("unicopia:trees_zap", ZAP_APPLE_TREE,
VegetationPlacedFeatures.modifiersWithWouldSurvive(PlacedFeatures.createCountExtraModifier(0, 0.01F, 1), UBlocks.ZAPLING)
);
static void bootstrap() {
BiomeModifications.addFeature(BiomeSelectors.foundInOverworld().and(BiomeSelectors.tag(BiomeTags.IS_FOREST)), GenerationStep.Feature.VEGETAL_DECORATION, TREES_ZAP.getKey().get());
}
}

View file

@ -0,0 +1,188 @@
package com.minelittlepony.unicopia.block;
import com.minelittlepony.unicopia.block.data.ZapAppleStageStore;
import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.particle.ParticleUtils;
import com.minelittlepony.unicopia.particle.UParticles;
import net.minecraft.block.*;
import net.minecraft.entity.*;
import net.minecraft.entity.damage.DamageSource;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.fluid.Fluid;
import net.minecraft.item.ItemPlacementContext;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.sound.BlockSoundGroup;
import net.minecraft.state.StateManager;
import net.minecraft.state.property.EnumProperty;
import net.minecraft.util.math.*;
import net.minecraft.util.math.random.Random;
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.event.GameEvent;
public class ZapAppleLeavesBlock extends LeavesBlock {
public static final EnumProperty<ZapAppleStageStore.Stage> STAGE = EnumProperty.of("stage", ZapAppleStageStore.Stage.class);
ZapAppleLeavesBlock() {
super(Settings.of(Material.LEAVES)
.strength(500, 1200)
.ticksRandomly()
.sounds(BlockSoundGroup.AZALEA_LEAVES)
.nonOpaque()
.allowsSpawning(UBlocks::canSpawnOnLeaves)
.suffocates(UBlocks::never)
.blockVision(UBlocks::never)
);
setDefaultState(getDefaultState().with(STAGE, ZapAppleStageStore.Stage.HIBERNATING));
}
@Override
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
super.appendProperties(builder);
builder.add(STAGE);
}
@Override
public void randomTick(BlockState state, ServerWorld world, BlockPos pos, Random random) {
super.randomTick(state, world, pos, random);
ZapAppleStageStore store = ZapAppleStageStore.get(world);
ZapAppleStageStore.Stage newStage = store.getStage();
if (!world.isDay() && state.get(STAGE).mustChangeInto(newStage)) {
world.setBlockState(pos, state.with(STAGE, newStage));
onStageChanged(store, newStage, world, state, pos, random);
}
}
@Override
public void scheduledTick(BlockState state, ServerWorld world, BlockPos pos, Random random) {
super.scheduledTick(state, world, pos, random);
ZapAppleStageStore store = ZapAppleStageStore.get(world);
ZapAppleStageStore.Stage newStage = store.getStage();
if (!world.isDay() && state.get(STAGE).mustChangeIntoInstantly(newStage)) {
world.setBlockState(pos, state.with(STAGE, newStage));
onStageChanged(store, newStage, world, state, pos, random);
}
world.createAndScheduleBlockTick(pos, this, 1);
}
@Override
protected boolean shouldDecay(BlockState state) {
return false;
}
@Override
public BlockState getPlacementState(ItemPlacementContext ctx) {
if (!ctx.getWorld().isClient) {
ctx.getWorld().createAndScheduleBlockTick(ctx.getBlockPos(), this, 1);
return super.getPlacementState(ctx).with(STAGE, ZapAppleStageStore.get(ctx.getWorld()).getStage());
}
return super.getPlacementState(ctx);
}
private void onStageChanged(ZapAppleStageStore store, ZapAppleStageStore.Stage stage, ServerWorld world, BlockState state, BlockPos pos, Random random) {
boolean mustFruit = Random.create(state.getRenderingSeed(pos)).nextInt(5) < 2;
BlockState below = world.getBlockState(pos.down());
if (world.isAir(pos.down())) {
if (stage == ZapAppleStageStore.Stage.FRUITING && mustFruit) {
world.setBlockState(pos.down(), UBlocks.ZAP_BULB.getDefaultState(), Block.NOTIFY_ALL);
store.triggerLightningStrike(pos);
}
}
if (stage != ZapAppleStageStore.Stage.HIBERNATING && world.getRandom().nextInt(10) == 0) {
store.triggerLightningStrike(pos);
}
if (stage == ZapAppleStageStore.Stage.RIPE) {
store.playMoonEffect(pos);
if (below.isOf(UBlocks.ZAP_BULB)) {
world.setBlockState(pos.down(), UBlocks.ZAP_APPLE.getDefaultState(), Block.NOTIFY_ALL);
store.triggerLightningStrike(pos);
}
}
if (mustFruit && stage == ZapAppleStageStore.Stage.HIBERNATING) {
if (below.isOf(UBlocks.ZAP_APPLE) || below.isOf(UBlocks.ZAP_BULB)) {
world.setBlockState(pos.down(), Blocks.AIR.getDefaultState());
}
}
}
@Override
public void onBlockBreakStart(BlockState state, World world, BlockPos pos, PlayerEntity player) {
triggerLightning(state, world, pos, player);
}
@Deprecated
@Override
public BlockRenderType getRenderType(BlockState state) {
return isAir(state) ? BlockRenderType.INVISIBLE : super.getRenderType(state);
}
@Deprecated
@Override
public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
return isAir(state) ? VoxelShapes.empty() : super.getOutlineShape(state, world, pos, context);
}
@Deprecated
@Override
public boolean canReplace(BlockState state, ItemPlacementContext context) {
return isAir(state) || super.canReplace(state, context);
}
@Deprecated
@Override
public boolean canBucketPlace(BlockState state, Fluid fluid) {
return isAir(state) || super.canBucketPlace(state, fluid);
}
protected boolean isAir(BlockState state) {
return state.get(STAGE) == ZapAppleStageStore.Stage.HIBERNATING;
}
@Deprecated
@Override
public float calcBlockBreakingDelta(BlockState state, PlayerEntity player, BlockView world, BlockPos pos) {
float delta = super.calcBlockBreakingDelta(state, player, world, pos);
if (Pony.of(player).getSpecies().canUseEarth()) {
delta *= 50;
}
if (state.get(STAGE) == ZapAppleStageStore.Stage.RIPE) {
delta *= 5;
}
return MathHelper.clamp(delta, 0, 0.9F);
}
public static void triggerLightning(BlockState state, World world, BlockPos pos, PlayerEntity player) {
if (world instanceof ServerWorld serverWorld) {
Vec3d center = Vec3d.ofCenter(pos);
LightningEntity lightning = EntityType.LIGHTNING_BOLT.create(world);
world.getOtherEntities(null, Box.from(center).expand(7)).forEach(other -> {
float dist = (float)other.getPos().distanceTo(center);
if (dist < 4) {
other.onStruckByLightning(serverWorld, lightning);
} else {
float damage = 3 / dist;
if (damage > 1) {
other.damage(DamageSource.LIGHTNING_BOLT, damage);
}
}
});
}
world.emitGameEvent(GameEvent.LIGHTNING_STRIKE, pos, GameEvent.Emitter.of(state));
ParticleUtils.spawnParticle(world, UParticles.LIGHTNING_BOLT, Vec3d.ofCenter(pos), Vec3d.ZERO);
}
}

View file

@ -0,0 +1,34 @@
package com.minelittlepony.unicopia.block;
import com.minelittlepony.unicopia.entity.player.Pony;
import net.minecraft.block.*;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.sound.BlockSoundGroup;
import net.minecraft.util.math.*;
import net.minecraft.world.BlockView;
import net.minecraft.world.World;
public class ZapAppleLogBlock extends PillarBlock {
ZapAppleLogBlock(MapColor topMapColor, MapColor sideMapColor) {
super(AbstractBlock.Settings.of(Material.WOOD, state -> state.get(PillarBlock.AXIS) == Direction.Axis.Y ? topMapColor : sideMapColor).strength(2.0f).sounds(BlockSoundGroup.WOOD).strength(500, 1200));
}
@Deprecated
@Override
public void onBlockBreakStart(BlockState state, World world, BlockPos pos, PlayerEntity player) {
ZapAppleLeavesBlock.triggerLightning(state, world, pos, player);
}
@Deprecated
@Override
public float calcBlockBreakingDelta(BlockState state, PlayerEntity player, BlockView world, BlockPos pos) {
float delta = super.calcBlockBreakingDelta(state, player, world, pos);
if (Pony.of(player).getSpecies().canUseEarth()) {
delta *= 50;
}
return MathHelper.clamp(delta, 0, 0.9F);
}
}

View file

@ -8,6 +8,8 @@ import com.google.common.base.Suppliers;
import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.network.Channel;
import com.minelittlepony.unicopia.network.MsgBlockDestruction;
import com.minelittlepony.unicopia.util.Tickable;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import net.minecraft.block.BlockState;
@ -17,7 +19,7 @@ import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
public class BlockDestructionManager {
public class BlockDestructionManager implements Tickable {
private static final Identifier ID = Unicopia.id("destruction_manager");
public static final int DESTRUCTION_COOLDOWN = 50;
@ -63,6 +65,7 @@ public class BlockDestructionManager {
}
}
@Override
public void tick() {
chunks.tick();
}

View file

@ -6,6 +6,7 @@ import java.util.function.*;
import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.util.NbtSerialisable;
import com.minelittlepony.unicopia.util.Tickable;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
@ -19,7 +20,7 @@ import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.PersistentState;
import net.minecraft.world.World;
public class WorldOverlay<T extends WorldOverlay.State> extends PersistentState {
public class WorldOverlay<T extends WorldOverlay.State> extends PersistentState implements Tickable {
private final World world;
private final Long2ObjectMap<Chunk> chunks = new Long2ObjectOpenHashMap<>();
@ -98,6 +99,7 @@ public class WorldOverlay<T extends WorldOverlay.State> extends PersistentState
}
}
@Override
public void tick() {
synchronized (locker) {
chunks.long2ObjectEntrySet().removeIf(entry -> entry.getValue().tick());

View file

@ -0,0 +1,164 @@
package com.minelittlepony.unicopia.block.data;
import java.util.Locale;
import java.util.stream.StreamSupport;
import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.particle.ParticleUtils;
import com.minelittlepony.unicopia.particle.UParticles;
import com.minelittlepony.unicopia.util.Tickable;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.LightningEntity;
import net.minecraft.nbt.*;
import net.minecraft.sound.SoundCategory;
import net.minecraft.sound.SoundEvents;
import net.minecraft.util.Identifier;
import net.minecraft.util.StringIdentifiable;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.PersistentState;
import net.minecraft.world.World;
import net.minecraft.world.event.GameEvent;
public class ZapAppleStageStore extends PersistentState implements Tickable {
private static final Identifier ID = Unicopia.id("zap_apple_stage");
public static ZapAppleStageStore get(World world) {
return WorldOverlay.getPersistableStorage(world, ID, ZapAppleStageStore::new, ZapAppleStageStore::new);
}
private final World world;
private Stage lastStage = Stage.HIBERNATING;
private int countdown;
private boolean stageChanged;
private boolean playedMoonEffect;
private int nextLightningEvent = 1200;
ZapAppleStageStore(World world, NbtCompound compound) {
this(world);
lastStage = Stage.VALUES[Math.max(0, compound.getInt("stage")) % Stage.VALUES.length];
stageChanged = compound.getBoolean("stageChanged");
countdown = compound.getInt("countdown");
playedMoonEffect = compound.getBoolean("playedMoonEffect");
nextLightningEvent = compound.getInt("nextLightningEvent");
}
ZapAppleStageStore(World world) {
this.world = world;
}
@Override
public void tick() {
if (!world.isDay()) {
if (nextLightningEvent > 0) {
nextLightningEvent--;
markDirty();
}
if (!stageChanged && (lastStage != Stage.HIBERNATING || (world.getMoonPhase() == 0))) {
stageChanged = true;
if (countDay()) {
lastStage = lastStage.getNext();
countdown = 1;
playedMoonEffect = false;
markDirty();
onStageChanged();
}
}
} else if (stageChanged) {
stageChanged = false;
markDirty();
}
}
private boolean countDay() {
markDirty();
return countdown-- <= 0;
}
protected void onStageChanged() {
world.setRainGradient(0.5F);
}
public void playMoonEffect(BlockPos pos) {
if (!playedMoonEffect) {
playedMoonEffect = true;
markDirty();
world.playSound(pos.getX(), pos.getY(), pos.getZ(), SoundEvents.ENTITY_WOLF_HOWL, SoundCategory.BLOCKS, 1.5F, 0.9F, true);
}
}
public void triggerLightningStrike(BlockPos pos) {
world.emitGameEvent(GameEvent.LIGHTNING_STRIKE, pos, GameEvent.Emitter.of(world.getBlockState(pos)));
ParticleUtils.spawnParticle(world, UParticles.LIGHTNING_BOLT, Vec3d.ofCenter(pos), Vec3d.ZERO);
if (nextLightningEvent <= 0) {
StreamSupport.stream(BlockPos.iterateRandomly(world.random, 20, pos, 10).spliterator(), false)
.filter(p -> world.isAir(p) && !world.isAir(p.down()) && world.isSkyVisible(p))
.findFirst().ifPresent(p -> {
LightningEntity bolt = EntityType.LIGHTNING_BOLT.create(world);
bolt.refreshPositionAfterTeleport(Vec3d.ofBottomCenter(pos));
bolt.setCosmetic(true);
world.spawnEntity(bolt);
nextLightningEvent = world.getRandom().nextBetween(1200, 8000);
markDirty();
});
}
}
/**
* Returns true during nights that the zap apples must change their states.
* @return
*/
public boolean hasStageChanged() {
return stageChanged;
}
/**
* Returns the current zap apple ripening stage.
*/
public Stage getStage() {
return lastStage;
}
@Override
public NbtCompound writeNbt(NbtCompound compound) {
compound.putInt("stage", lastStage.ordinal());
compound.putBoolean("stageChanged", stageChanged);
compound.putInt("countdown", countdown);
compound.putBoolean("playedMoonEffect", playedMoonEffect);
compound.putInt("nextLightningEvent", nextLightningEvent);
return compound;
}
public enum Stage implements StringIdentifiable {
HIBERNATING,
GREENING,
FLOWERING,
FRUITING,
RIPE;
static final long DAY_LENGTH = 24000;
static final Stage[] VALUES = values();
public Stage getNext() {
return VALUES[(ordinal() + 1) % VALUES.length];
}
public boolean mustChangeInto(Stage to) {
return this != to && (getNext() == to || this == HIBERNATING || to == HIBERNATING);
}
public boolean mustChangeIntoInstantly(Stage to) {
return this != to && (this == HIBERNATING || to == HIBERNATING);
}
@Override
public String asString() {
return name().toLowerCase(Locale.ROOT);
}
}
}

View file

@ -1,5 +1,6 @@
package com.minelittlepony.unicopia.client;
import com.minelittlepony.unicopia.block.UBlocks;
import com.minelittlepony.unicopia.client.particle.ChangelingMagicParticle;
import com.minelittlepony.unicopia.client.particle.CloudsEscapingParticle;
import com.minelittlepony.unicopia.client.particle.DiskParticle;
@ -27,6 +28,8 @@ import net.fabricmc.fabric.api.client.rendering.v1.EntityRendererRegistry;
import net.fabricmc.fabric.api.client.rendering.v1.BuiltinItemRendererRegistry;
import net.fabricmc.fabric.api.client.rendering.v1.ColorProviderRegistry;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.color.world.BiomeColors;
import net.minecraft.client.color.world.FoliageColors;
import net.minecraft.client.item.ModelPredicateProviderRegistry;
import net.minecraft.client.particle.Particle;
import net.minecraft.client.particle.SpriteProvider;
@ -117,9 +120,20 @@ public interface URenderers {
ColorProviderRegistry.ITEM.register((stack, i) -> {
return i > 0 || !GemstoneItem.isEnchanted(stack) ? -1 : GemstoneItem.getSpellKey(stack).getColor();
}, UItems.GEMSTONE);
ColorProviderRegistry.BLOCK.register((state, view, pos, color) -> {
if (view == null || pos == null) {
color = FoliageColors.getDefaultColor();
} else {
color = BiomeColors.getFoliageColor(view, pos);
}
return (color << 2) | ((color >> 4) & 0xFF);
}, UBlocks.ZAP_LEAVES);
// for lava boats
BlockRenderLayerMap.INSTANCE.putFluids(RenderLayers.getTranslucent(), Fluids.LAVA, Fluids.FLOWING_LAVA);
BlockRenderLayerMap.INSTANCE.putBlocks(RenderLayers.getTranslucent(), UBlocks.ZAP_BULB, UBlocks.ZAP_APPLE, UBlocks.ZAPLING);
}
static <T extends ParticleEffect> PendingParticleFactory<T> createFactory(ParticleSupplier<T> supplier) {

View file

@ -198,10 +198,10 @@ public class FairyEntity extends PathAwareEntity implements DynamicLightSource,
@Override
public boolean handleAttack(Entity attacker) {
if (world instanceof ServerWorld) {
if (world instanceof ServerWorld serverWorld) {
LightningEntity lightning = EntityType.LIGHTNING_BOLT.create(world);
lightning.refreshPositionAfterTeleport(getX(), getY(), getZ());
attacker.onStruckByLightning((ServerWorld)world, lightning);
attacker.onStruckByLightning(serverWorld, lightning);
}
emitGameEvent(GameEvent.LIGHTNING_STRIKE);
ParticleUtils.spawnParticle(world, UParticles.LIGHTNING_BOLT, getPos(), Vec3d.ZERO);

View file

@ -4,6 +4,7 @@ import java.util.UUID;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Multimap;
import com.minelittlepony.unicopia.UTags;
import com.minelittlepony.unicopia.entity.UEntityAttributes;
import net.minecraft.block.*;
@ -40,7 +41,7 @@ public class PolearmItem extends SwordItem {
@Override
public boolean isSuitableFor(BlockState state) {
return false;
return state.isIn(UTags.POLEARM_MINEABLE);
}
@Override

View file

@ -9,6 +9,8 @@ import com.minelittlepony.unicopia.entity.UEntities;
import com.minelittlepony.unicopia.item.enchantment.UEnchantments;
import com.minelittlepony.unicopia.item.toxin.UFoodComponents;
import net.minecraft.entity.effect.StatusEffectInstance;
import net.minecraft.entity.effect.StatusEffects;
import net.minecraft.item.*;
import net.minecraft.item.Item.Settings;
import net.fabricmc.fabric.api.item.v1.FabricItemSettings;
@ -26,6 +28,14 @@ public interface UItems {
Item SOUR_APPLE = register("sour_apple", AppleItem.registerTickCallback(new Item(new Item.Settings().group(ItemGroup.FOOD).food(FoodComponents.APPLE))));
ZapAppleItem ZAP_APPLE = register("zap_apple", AppleItem.registerTickCallback(new ZapAppleItem(new Item.Settings().group(ItemGroup.FOOD).food(UFoodComponents.ZAP_APPLE))));
Item ZAP_BULB = register("zap_bulb", new Item(new Item.Settings().group(ItemGroup.FOOD).food(new FoodComponent.Builder()
.hunger(-2)
.saturationModifier(-0.8f)
.alwaysEdible()
.statusEffect(new StatusEffectInstance(StatusEffects.POISON, 100, 0), 0.6F)
.statusEffect(new StatusEffectInstance(StatusEffects.BLINDNESS, 100, 0), 0.6F)
.statusEffect(new StatusEffectInstance(StatusEffects.BAD_OMEN, 100, 0), 0.6F)
.build())));
Item ROTTEN_APPLE = register("rotten_apple", new RottenAppleItem(new Item.Settings().group(ItemGroup.FOOD).food(FoodComponents.APPLE)));
Item COOKED_ZAP_APPLE = register("cooked_zap_apple", new Item(new Item.Settings().group(ItemGroup.FOOD).food(FoodComponents.APPLE)));
@ -90,6 +100,8 @@ public interface UItems {
Item SPELLBOOK = register("spellbook", new SpellbookItem(new Item.Settings().maxCount(1).rarity(Rarity.UNCOMMON).group(ItemGroup.TOOLS)));
Item ZAPLING = register("zapling", new BlockItem(UBlocks.ZAPLING, new Item.Settings().group(ItemGroup.DECORATIONS)));
AmuletItem PEGASUS_AMULET = register("pegasus_amulet", new AmuletItem(new FabricItemSettings()
.maxCount(1)
.maxDamage(890)

View file

@ -0,0 +1,7 @@
{
"variants": {
"": {
"model": "unicopia:block/zap_apple"
}
}
}

View file

@ -0,0 +1,7 @@
{
"variants": {
"": {
"model": "unicopia:block/zap_bulb"
}
}
}

View file

@ -0,0 +1,19 @@
{
"variants": {
"stage=hibernating": {
"model": "unicopia:block/zap_leaves"
},
"stage=greening": {
"model": "unicopia:block/zap_leaves"
},
"stage=flowering": {
"model": "unicopia:block/flowering_zap_leaves"
},
"stage=fruiting": {
"model": "unicopia:block/zap_leaves"
},
"stage=ripe": {
"model": "unicopia:block/zap_leaves"
}
}
}

View file

@ -0,0 +1,16 @@
{
"variants": {
"axis=x": {
"model": "unicopia:block/zap_log_horizontal",
"x": 90,
"y": 90
},
"axis=y": {
"model": "unicopia:block/zap_log"
},
"axis=z": {
"model": "unicopia:block/zap_log_horizontal",
"x": 90
}
}
}

View file

@ -0,0 +1,7 @@
{
"variants": {
"": {
"model": "unicopia:block/zapling"
}
}
}

View file

@ -26,6 +26,7 @@
"item.unicopia.rotten_apple": "Rotten Apple",
"item.unicopia.cooked_zap_apple": "Cooked Zap Apple",
"item.unicopia.zap_apple": "Zap Apple",
"item.unicopia.zap_bulb": "Unripened Zap Apple",
"item.unicopia.empty_jar": "Glass Jar",
"item.unicopia.filled_jar": "%s in a Jar",
@ -87,6 +88,11 @@
"item.unicopia.music_disc_funk.desc": "funk, just funk",
"block.unicopia.rocks": "Rocks",
"block.unicopia.zapling": "Zapling",
"block.unicopia.zap_log": "Zap Log",
"block.unicopia.zap_leaves": "Zap Leaves",
"block.unicopia.zap_apple": "Zap Apple",
"block.unicopia.zap_bulb": "Unripened Zap Apple",
"entity.unicopia.butterfly": "Butterfly",
"entity.unicopia.twittermite": "Twittermite",

View file

@ -0,0 +1,6 @@
{
"parent": "minecraft:block/leaves",
"textures": {
"all": "unicopia:block/flowering_zap_leaves"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "minecraft:block/cross",
"textures": {
"cross": "unicopia:item/zap_apple"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "minecraft:block/cross",
"textures": {
"cross": "unicopia:item/zap_bulb"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "minecraft:block/leaves",
"textures": {
"all": "unicopia:block/zap_leaves"
}
}

View file

@ -0,0 +1,7 @@
{
"parent": "minecraft:block/cube_column",
"textures": {
"end": "unicopia:block/zap_log_top",
"side": "unicopia:block/zap_log"
}
}

View file

@ -0,0 +1,7 @@
{
"parent": "minecraft:block/cube_column_horizontal",
"textures": {
"end": "unicopia:block/zap_log_top",
"side": "unicopia:block/zap_log"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "minecraft:block/cross",
"textures": {
"cross": "unicopia:item/zapling"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "item/generated",
"textures": {
"layer0": "unicopia:item/zap_bulb"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "item/generated",
"textures": {
"layer0": "unicopia:item/zapling"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 256 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View file

@ -0,0 +1,20 @@
{
"type": "minecraft:block",
"pools": [
{
"rolls": 1.0,
"bonus_rolls": 0.0,
"entries": [
{
"type": "minecraft:item",
"name": "unicopia:zap_apple"
}
],
"conditions": [
{
"condition": "minecraft:survives_explosion"
}
]
}
]
}

View file

@ -0,0 +1,20 @@
{
"type": "minecraft:block",
"pools": [
{
"rolls": 1.0,
"bonus_rolls": 0.0,
"entries": [
{
"type": "minecraft:item",
"name": "unicopia:zap_bulb"
}
],
"conditions": [
{
"condition": "minecraft:survives_explosion"
}
]
}
]
}

View file

@ -0,0 +1,20 @@
{
"type": "minecraft:block",
"pools": [
{
"rolls": 1.0,
"bonus_rolls": 0.0,
"entries": [
{
"type": "minecraft:item",
"name": "unicopia:zapling"
}
],
"conditions": [
{
"condition": "minecraft:survives_explosion"
}
]
}
]
}

View file

@ -0,0 +1,7 @@
{
"replace": false,
"values": [
"unicopia:zap_leaves",
"unicopia:zap_log"
]
}

View file

@ -0,0 +1,11 @@
{
"replace": false,
"values": [
"unicopia:wooden_polearm",
"unicopia:stone_polearm",
"unicopia:iron_polearm",
"unicopia:golden_polearm",
"unicopia:diamond_polearm",
"unicopia:netherite_polearm"
]
}