mirror of
https://github.com/Sollace/Unicopia.git
synced 2024-11-27 23:27:59 +01:00
Added zap apple trees
This commit is contained in:
parent
94d81ff5f5
commit
def7e37712
40 changed files with 755 additions and 8 deletions
|
@ -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) {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"variants": {
|
||||
"": {
|
||||
"model": "unicopia:block/zap_apple"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"variants": {
|
||||
"": {
|
||||
"model": "unicopia:block/zap_bulb"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
16
src/main/resources/assets/unicopia/blockstates/zap_log.json
Normal file
16
src/main/resources/assets/unicopia/blockstates/zap_log.json
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"variants": {
|
||||
"": {
|
||||
"model": "unicopia:block/zapling"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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",
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"parent": "minecraft:block/leaves",
|
||||
"textures": {
|
||||
"all": "unicopia:block/flowering_zap_leaves"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"parent": "minecraft:block/cross",
|
||||
"textures": {
|
||||
"cross": "unicopia:item/zap_apple"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"parent": "minecraft:block/cross",
|
||||
"textures": {
|
||||
"cross": "unicopia:item/zap_bulb"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"parent": "minecraft:block/leaves",
|
||||
"textures": {
|
||||
"all": "unicopia:block/zap_leaves"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"parent": "minecraft:block/cube_column",
|
||||
"textures": {
|
||||
"end": "unicopia:block/zap_log_top",
|
||||
"side": "unicopia:block/zap_log"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"parent": "minecraft:block/cube_column_horizontal",
|
||||
"textures": {
|
||||
"end": "unicopia:block/zap_log_top",
|
||||
"side": "unicopia:block/zap_log"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"parent": "minecraft:block/cross",
|
||||
"textures": {
|
||||
"cross": "unicopia:item/zapling"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"parent": "item/generated",
|
||||
"textures": {
|
||||
"layer0": "unicopia:item/zap_bulb"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"parent": "item/generated",
|
||||
"textures": {
|
||||
"layer0": "unicopia:item/zapling"
|
||||
}
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 1.8 KiB |
BIN
src/main/resources/assets/unicopia/textures/block/zap_leaves.png
Normal file
BIN
src/main/resources/assets/unicopia/textures/block/zap_leaves.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 256 B |
BIN
src/main/resources/assets/unicopia/textures/block/zap_log.png
Normal file
BIN
src/main/resources/assets/unicopia/textures/block/zap_log.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.7 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.7 KiB |
BIN
src/main/resources/assets/unicopia/textures/item/zap_bulb.png
Normal file
BIN
src/main/resources/assets/unicopia/textures/item/zap_bulb.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.6 KiB |
BIN
src/main/resources/assets/unicopia/textures/item/zapling.png
Normal file
BIN
src/main/resources/assets/unicopia/textures/item/zapling.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.7 KiB |
|
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
"unicopia:zap_leaves",
|
||||
"unicopia:zap_log"
|
||||
]
|
||||
}
|
11
src/main/resources/data/unicopia/tags/items/polearms.json
Normal file
11
src/main/resources/data/unicopia/tags/items/polearms.json
Normal 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"
|
||||
]
|
||||
}
|
Loading…
Reference in a new issue