add colourful pearl and air

This commit is contained in:
QuImUfu 2024-08-13 08:20:13 +02:00
parent 01ba9ca366
commit b4582640b7
207 changed files with 1492 additions and 213 deletions

View File

@ -1,3 +1,3 @@
# Colourful Portals Reimagined
A Fabric Minecraft mod adding colourful portalRepresentations, based on Immersive Portals
A Fabric Minecraft mod adding colourful portals, based on Immersive Portals

View File

@ -11,8 +11,8 @@ loader_version=0.15.11
# Mod Properties
mod_version=0.9.6
maven_group=quimufu.colourful-portalRepresentations
archives_base_name=colourful-portalRepresentations
maven_group=quimufu.colourful-portals
archives_base_name=colourful-portals
# Dependencies
fabric_version=0.100.1+1.21

View File

@ -0,0 +1,153 @@
package quimufu.colourful_portals;
import net.minecraft.block.*;
import net.minecraft.component.DataComponentTypes;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.fluid.Fluid;
import net.minecraft.fluid.FluidState;
import net.minecraft.item.*;
import net.minecraft.item.tooltip.TooltipType;
import net.minecraft.network.packet.s2c.play.ParticleS2CPacket;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.state.StateManager;
import net.minecraft.state.property.EnumProperty;
import net.minecraft.text.Text;
import net.minecraft.util.DyeColor;
import net.minecraft.util.Hand;
import net.minecraft.util.ItemActionResult;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.math.BlockPos;
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.WorldAccess;
import net.minecraft.world.WorldView;
import org.jetbrains.annotations.Nullable;
import java.util.List;
public class ColourfulAirBlock extends Block implements FluidFillable {
public static final EnumProperty<DyeColor> DYE_COLOR = EnumProperty.of("colour", DyeColor.class);
public ColourfulAirBlock(Settings settings) {
super(settings);
this.setDefaultState(this.stateManager.getDefaultState().with(DYE_COLOR, DyeColor.BLACK));
}
@Override
protected ItemActionResult onUseWithItem(ItemStack stack, BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) {
if(stack.getItem() == Items.GLASS_BOTTLE){
ItemStack filledBottle = getPickStack(world, pos, state);
player.setStackInHand(hand, ItemUsage.exchangeStack(stack, player, filledBottle));
if(!world.isClient){
world.setBlockState(pos, Blocks.AIR.getDefaultState());
}
return ItemActionResult.success(world.isClient);
}
return ItemActionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION;
}
@Override
protected void onBlockAdded(BlockState state, World world, BlockPos pos, BlockState oldState, boolean notify) {
scheduleTick(world, pos, true);
}
@Override
public void appendTooltip(ItemStack stack,
Item.TooltipContext context,
List<Text> tooltip, TooltipType options) {
DyeColor color = stack.getOrDefault(DataComponentTypes.BASE_COLOR, DyeColor.BLACK);
tooltip.add(Text.translatable("color.minecraft." + color.getName())
.withColor(color.getEntityColor()));
}
@Override
public ItemStack getPickStack(WorldView world, BlockPos pos, BlockState state) {
ItemStack stack = ColourfulPortalsMod.COLOURFUL_AIR_BOTTLE_ITEM.getDefaultStack();
stack.set(DataComponentTypes.BASE_COLOR, state.get(DYE_COLOR));
return stack;
}
@Override
public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos blockPos, ShapeContext shapeContext) {
if (shapeContext.isHolding(Items.DEBUG_STICK)
|| shapeContext.isHolding(ColourfulPortalsMod.COLOURFUL_AIR_BOTTLE_ITEM)
|| shapeContext.isHolding(Items.GLASS_BOTTLE)) {
return VoxelShapes.fullCube();
}
return VoxelShapes.empty();
}
@Override
protected BlockRenderType getRenderType(BlockState state) {
return BlockRenderType.INVISIBLE;
}
@Override
protected void randomTick(BlockState state, ServerWorld world, BlockPos pos, Random random) {
scheduleTick(world, pos, false);
}
@Override
protected void scheduledTick(BlockState state, ServerWorld world, BlockPos pos, Random random) {
DyeColor dyeColor = state.get(DYE_COLOR);
for (ServerPlayerEntity player : world.getPlayers()) {
double x = pos.getX() + .5D;
double y = pos.getY() + .5D;
double z = pos.getZ() + .5D;
ParticleS2CPacket particleS2CPacket = new ParticleS2CPacket(
ColourfulPortalsMod.COLOURFUL_AIR_PARTICLE_BY_COLOUR.get(dyeColor),
true,
x, y, z,
0.25F, 0.25F, 0.25F,
0,
1);
world.sendToPlayerIfNearby(player, true, x, y, z, particleS2CPacket);
}
scheduleTick(world, pos, false);
}
private void scheduleTick(WorldAccess world, BlockPos pos, boolean asap) {
if (!world.isClient() && !world.getBlockTickScheduler().isQueued(pos, this)) {
if(asap){
world.scheduleBlockTick(pos, this, 2);
} else if (world.getClosestPlayer(pos.getX(),pos.getY(),pos.getZ(),512,false) != null) {
world.scheduleBlockTick(pos, this, 20);
}
}
}
@Override
public BlockState getPlacementState(ItemPlacementContext ctx) {
DyeColor color = ctx.getStack().getOrDefault(DataComponentTypes.BASE_COLOR, DyeColor.BLACK);
return this.getDefaultState().with(DYE_COLOR, color);
}
public BlockState getRandomState(Random random) {
DyeColor color = DyeColor.values()[random.nextInt(DyeColor.values().length)];
return this.getDefaultState().with(DYE_COLOR, color);
}
@Override
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
builder.add(DYE_COLOR);
}
@Override
public boolean canFillWithFluid(@Nullable PlayerEntity player, BlockView world, BlockPos pos, BlockState state, Fluid fluid) {
return false;
}
@Override
public boolean tryFillWithFluid(WorldAccess world, BlockPos pos, BlockState state, FluidState fluidState) {
return false;
}
}

View File

@ -6,33 +6,42 @@ import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
import net.fabricmc.fabric.api.event.registry.FabricRegistryBuilder;
import net.fabricmc.fabric.api.itemgroup.v1.FabricItemGroupEntries;
import net.fabricmc.fabric.api.itemgroup.v1.ItemGroupEvents;
import net.fabricmc.fabric.api.particle.v1.FabricParticleTypes;
import net.minecraft.block.AbstractBlock;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.enums.NoteBlockInstrument;
import net.minecraft.component.DataComponentTypes;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.SpawnGroup;
import net.minecraft.item.*;
import net.minecraft.particle.SimpleParticleType;
import net.minecraft.registry.Registries;
import net.minecraft.registry.Registry;
import net.minecraft.registry.RegistryKey;
import net.minecraft.registry.RegistryKeys;
import net.minecraft.registry.tag.TagKey;
import net.minecraft.server.MinecraftServer;
import net.minecraft.sound.BlockSoundGroup;
import net.minecraft.sound.SoundEvent;
import net.minecraft.util.DyeColor;
import net.minecraft.util.Identifier;
import net.minecraft.util.Rarity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.BlockView;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import quimufu.colourful_portals.client.CommonPortalFluidRenderer;
import quimufu.colourful_portals.client.CommonPortalFluidRendererV1;
import quimufu.colourful_portals.client.CommonPortalFluidRendererV2;
import quimufu.colourful_portals.config.ColourfulPortalConfig;
import quimufu.colourful_portals.entity.ColourfulPearlEntity;
import quimufu.colourful_portals.general_util.WeightedSelector;
import quimufu.colourful_portals.item.ColourfulAirBottleItem;
import quimufu.colourful_portals.item.ColourfulPearlItem;
import quimufu.colourful_portals.portal.*;
import quimufu.colourful_portals.portal_fluid.PortalFluid;
import quimufu.colourful_portals.portal_fluid.PortalFluidBlock;
import quimufu.colourful_portals.portal_fluid.PortalFluidBucketItem;
import java.util.Comparator;
import java.util.HashSet;
import java.util.*;
import static quimufu.colourful_portals.Components.PORTAL_CANDIDATE_LIST;
import static quimufu.colourful_portals.Components.PORTAL_LIST;
@ -41,17 +50,41 @@ public class ColourfulPortalsMod implements ModInitializer {
public static final String MOD_ID = "colourful_portals";
public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID);
public static final HashSet<Identifier> PORTAL_BLOCKS = new HashSet<>();
public static final PortalBlock PORTAL_BLOCK = new PortalBlock(AbstractBlock.Settings.create().instrument(NoteBlockInstrument.HAT).sounds(BlockSoundGroup.GLASS).strength(-1.0f, 3600000.8f).dropsNothing().nonOpaque().luminance((bs) -> 15).allowsSpawning(ColourfulPortalsMod::never).solidBlock(ColourfulPortalsMod::never).suffocates(ColourfulPortalsMod::never).blockVision(ColourfulPortalsMod::never).ticksRandomly());
public static final ColourfulAirBlock COLOURFUL_AIR = new ColourfulAirBlock(AbstractBlock.Settings.create().instrument(NoteBlockInstrument.HAT).sounds(BlockSoundGroup.GLASS).strength(-1.0f, 3600000.8f).dropsNothing().noCollision().luminance((bs) -> 7).allowsSpawning(ColourfulPortalsMod::never).solidBlock(ColourfulPortalsMod::never).suffocates(ColourfulPortalsMod::never).blockVision(ColourfulPortalsMod::never).ticksRandomly());
public static final ColourfulAirBottleItem COLOURFUL_AIR_BOTTLE_ITEM = new ColourfulAirBottleItem(COLOURFUL_AIR, new Item.Settings().rarity(Rarity.RARE).component(DataComponentTypes.BASE_COLOR, DyeColor.BLACK));
public static final EnumMap<DyeColor, SimpleParticleType> COLOURFUL_AIR_PARTICLE_BY_COLOUR;
static {
COLOURFUL_AIR_PARTICLE_BY_COLOUR = new EnumMap<>(DyeColor.class);
for (DyeColor dyeColor : DyeColor.values()) {
COLOURFUL_AIR_PARTICLE_BY_COLOUR.put(dyeColor, FabricParticleTypes.simple(true));
}
}
public static final PortalBlock PORTAL_BLOCK = new PortalBlock(AbstractBlock.Settings.create().instrument(NoteBlockInstrument.HAT).sounds(BlockSoundGroup.GLASS).strength(-1.0f, 3600000.8f).dropsNothing().noCollision().luminance((bs) -> 15).allowsSpawning(ColourfulPortalsMod::never).solidBlock(ColourfulPortalsMod::never).suffocates(ColourfulPortalsMod::never).blockVision(ColourfulPortalsMod::never).ticksRandomly());
public static final BlockItem PORTAL_BLOCK_ITEM = new BlockItem(PORTAL_BLOCK, new Item.Settings().rarity(Rarity.EPIC));
public static final Item BLOB_DARK = new Item(new Item.Settings());
public static final Item BLOB_BRIGHT = new Item(new Item.Settings());
public static final Identifier COLOURFUL_PEARL_ID = Identifier.of(MOD_ID, "colourful_pearl");
public static final Item COLOURFUL_PEARL_ITEM = new ColourfulPearlItem(new Item.Settings().maxCount(8));
public static final TagKey<Block> COLOURFUL_PEARL_REPLACEABLE_BLOCK_TAG = TagKey.of(RegistryKeys.BLOCK, Identifier.of(MOD_ID, "colourful_pearl_replaceable"));
public static final WeightedSelector<Identifier> DIMENSION_WEIGHTS_COLOURFUL_PEARL = new WeightedSelector<>();
public static final EntityType<ColourfulPearlEntity> COLOURFUL_PEARL_ENTITY_TYPE = EntityType.Builder.<ColourfulPearlEntity>create(ColourfulPearlEntity::new, SpawnGroup.MISC).dimensions(0.25f, 0.25f).maxTrackingRange(4).trackingTickInterval(10).build(COLOURFUL_PEARL_ID.toString());
public static final TagKey<EntityType<?>> COLOURFUL_PEARL_NOT_TELEPORTABLE = TagKey.of(RegistryKeys.ENTITY_TYPE, Identifier.of(MOD_ID, "pearl_not_teleportable"));
public static final SoundEvent TELEPORT_AWAY_SOUND = SoundEvent.of(Identifier.of(MOD_ID, "entity.colourful_pearl.teleport_away"));
public static final PortalFluid PORTAL_FLUID = new PortalFluid();
public static final PortalFluidBlock PORTAL_FLUID_BLOCk = new PortalFluidBlock(PORTAL_FLUID, AbstractBlock.Settings.create().sounds(BlockSoundGroup.INTENTIONALLY_EMPTY).luminance((bs) -> 15).noCollision().strength(100.0f).dropsNothing());
public static final BucketItem PORTAL_FLUID_BUCKET_ITEM = new PortalFluidBucketItem(PORTAL_FLUID, new Item.Settings().recipeRemainder(Items.BUCKET).maxCount(1).rarity(Rarity.RARE));
public static PortalManager PORTAL_MANAGER;
public static PortalManager PORTAL_MANAGER;
public static final RegistryKey<Registry<PrioritizedPortalLinkingSystemBuilder>> PORTAL_LINKING_SYSTEM_BUILDER_REGISTRY_KEY = RegistryKey.ofRegistry(Identifier.of(MOD_ID, "portal_linking_system"));
public static final Registry<PrioritizedPortalLinkingSystemBuilder> PORTAL_LINKING_SYSTEM_BUILDER_REGISTRY = FabricRegistryBuilder.createSimple(PORTAL_LINKING_SYSTEM_BUILDER_REGISTRY_KEY).buildAndRegister();
@ -74,6 +107,10 @@ public class ColourfulPortalsMod implements ModInitializer {
if (!ColourfulPortalConfig.disableImmersivePortals && hasImmPtl()) {
Registry.register(PORTAL_LINKING_SYSTEM_BUILDER_REGISTRY, ImmersivePortalsLinkingSystem.IMMERSIVE_PORTALS_LINKING_SYSTEM, new PrioritizedPortalLinkingSystemBuilder(ImmersivePortalsLinkingSystem::new, 100));
}
for (Map.Entry<DyeColor, SimpleParticleType> entry : COLOURFUL_AIR_PARTICLE_BY_COLOUR.entrySet()) {
Registry.register(Registries.PARTICLE_TYPE, Identifier.of(MOD_ID, entry.getKey().getName() + "_colourful_air_sparkle"), entry.getValue());
}
Registry.register(PORTAL_LINKING_SYSTEM_BUILDER_REGISTRY, DefaultLinkingSystem.DEFAULT_LINKING_SYSTEM, new PrioritizedPortalLinkingSystemBuilder(DefaultLinkingSystem::new, 90));
Identifier identifier = Identifier.of(MOD_ID, "portal_block");
@ -81,6 +118,14 @@ public class ColourfulPortalsMod implements ModInitializer {
Registry.register(Registries.BLOCK, identifier, PORTAL_BLOCK);
Registry.register(Registries.ITEM, identifier, PORTAL_BLOCK_ITEM);
Registry.register(Registries.BLOCK, Identifier.of(MOD_ID, "colourful_air"), COLOURFUL_AIR);
Registry.register(Registries.ITEM, Identifier.of(MOD_ID, "colourful_air_bottle"), COLOURFUL_AIR_BOTTLE_ITEM);
Registry.register(Registries.ENTITY_TYPE, COLOURFUL_PEARL_ID, COLOURFUL_PEARL_ENTITY_TYPE);
Registry.register(Registries.ITEM, COLOURFUL_PEARL_ID, COLOURFUL_PEARL_ITEM);
Registry.register(Registries.SOUND_EVENT, TELEPORT_AWAY_SOUND.getId(), TELEPORT_AWAY_SOUND);
Registry.register(Registries.ITEM, Identifier.of(MOD_ID, "portal_fluid_bucket"), PORTAL_FLUID_BUCKET_ITEM);
Registry.register(Registries.FLUID, Identifier.of(MOD_ID, "portal_fluid"), PORTAL_FLUID);
Registry.register(Registries.BLOCK, Identifier.of(MOD_ID, "portal_fluid_block"), PORTAL_FLUID_BLOCk);
@ -104,6 +149,10 @@ public class ColourfulPortalsMod implements ModInitializer {
LOGGER.info(id);
PORTAL_BLOCKS.add(Identifier.tryParse(id));
}
DIMENSION_WEIGHTS_COLOURFUL_PEARL.clear();
for (Map.Entry<String, Integer> weight : ColourfulPortalConfig.pearlDimensionWeights.entrySet()) {
DIMENSION_WEIGHTS_COLOURFUL_PEARL.add(Identifier.of(weight.getKey()),weight.getValue());
}
}
private boolean hasImmPtl() {

View File

@ -1,33 +0,0 @@
package quimufu.colourful_portals;
import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.blockrenderlayer.v1.BlockRenderLayerMap;
import net.fabricmc.fabric.api.client.render.fluid.v1.FluidRenderHandlerRegistry;
import net.minecraft.client.render.RenderLayer;
import quimufu.colourful_portals.client.CommonPortalFluidRenderer;
import quimufu.colourful_portals.client.CommonPortalFluidRendererV1;
import quimufu.colourful_portals.client.CommonPortalFluidRendererV2;
import quimufu.colourful_portals.client.PortalFluidRenderHandler;
import quimufu.colourful_portals.config.ColourfulPortalConfig;
public class ColourfulPortalsModClient implements ClientModInitializer {
public static ThreadLocal<CommonPortalFluidRenderer> FLUID_RENDERER = ThreadLocal.withInitial(CommonPortalFluidRendererV2::new);
public void onInitializeClient() {
BlockRenderLayerMap.INSTANCE.putBlock(ColourfulPortalsMod.PORTAL_BLOCK, RenderLayer.getTranslucent());
BlockRenderLayerMap.INSTANCE.putFluid(ColourfulPortalsMod.PORTAL_FLUID, RenderLayer.getTranslucent());
FluidRenderHandlerRegistry.INSTANCE.register(ColourfulPortalsMod.PORTAL_FLUID, new PortalFluidRenderHandler());
ColourfulPortalConfig.registerListener(this::onConfigUpdate);
onConfigUpdate();
}
private void onConfigUpdate() {
if(ColourfulPortalConfig.blockyPortalFluid){
FLUID_RENDERER = ThreadLocal.withInitial(CommonPortalFluidRendererV1::new);
} else {
FLUID_RENDERER = ThreadLocal.withInitial(CommonPortalFluidRendererV2::new);
}
}
}

View File

@ -14,7 +14,7 @@ public class MixinConfig implements IMixinConfigPlugin {
private static final Supplier<Boolean> TRUE = () -> true;
private static final Map<String, Supplier<Boolean>> CONDITIONS = Map.of(
"quimufu.colourful_portals.mixin.client.SodiumFluidRendererMixin", () -> FabricLoader.getInstance().isModLoaded("sodium")
"quimufu.colourful_portals.client.mixin.SodiumFluidRendererMixin", () -> FabricLoader.getInstance().isModLoaded("sodium")
);
@Override

View File

@ -4,7 +4,6 @@ import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.FluidFillable;
import net.minecraft.block.ShapeContext;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.fluid.Fluid;
import net.minecraft.fluid.FluidState;
@ -23,7 +22,6 @@ import net.minecraft.world.BlockView;
import net.minecraft.world.World;
import net.minecraft.world.WorldAccess;
import org.jetbrains.annotations.Nullable;
import quimufu.colourful_portals.util.CollisionAwareShapeContext;
import static quimufu.colourful_portals.ColourfulPortalsMod.PORTAL_MANAGER;
@ -67,74 +65,18 @@ public class PortalBlock extends Block implements FluidFillable {
if (shapeContext.isHolding(Items.DEBUG_STICK)
|| shapeContext.isHolding(ColourfulPortalsMod.PORTAL_BLOCK_ITEM)
|| shapeContext.isHolding(ColourfulPortalsMod.PORTAL_FLUID_BUCKET_ITEM)) {
return getShape(state);
}
return VoxelShapes.empty();
}
public VoxelShape getShape(BlockState state) {
return switch (state.get(AXIS)) {
case Z -> Z_AABB;
case Y -> Y_AABB;
default -> X_AABB;
};
}
return VoxelShapes.empty();
}
protected void onEntityCollisionOld(BlockState state, World world, BlockPos pos, Entity entity) {
ColourfulPortalsMod.LOGGER.info("detected collision {}", entity.getType());
if (entity.getBoundingBox()
.intersects(getShape(state, world, pos).getBoundingBox())) {
Vec3d vec3d = new Vec3d(0.5, 0.5f, 0.5);
entity.slowMovement(state, vec3d);
}
Vec3d entityPos = entity.getPos();
Vec3d prevEntityPos = new Vec3d(entity.prevX, entity.prevY, entity.prevZ);
if(entityPos.equals(prevEntityPos) && entity.getVelocity().squaredDistanceTo(Vec3d.ZERO) >= 0.01D){
//in this case, the collision logic was called prior to the movement logic,
// so we'll have to calculate our own next postion
entityPos = entityPos.add(entity.getVelocity());
}
Vec3d movement = entityPos.subtract(prevEntityPos);
if (world instanceof ServerWorld) {
Direction.Axis axis = state.get(AXIS);
double centerPosAlongAxis = pos.toCenterPos().getComponentAlongAxis(axis);
double entityPosAlongAxis = entityPos.getComponentAlongAxis(axis);
double prevEntityPosAlongAxis = prevEntityPos.getComponentAlongAxis(axis);
double movementAlongAxis = entityPosAlongAxis - prevEntityPosAlongAxis;
if (prevEntityPosAlongAxis > entityPosAlongAxis) {
if (entityPosAlongAxis < centerPosAlongAxis
&& prevEntityPosAlongAxis >= centerPosAlongAxis) {
double plainHitAfter = (centerPosAlongAxis - entityPosAlongAxis) / movementAlongAxis;
Vec3d planeHitPoint = entityPos.add(movement.multiply(plainHitAfter));
if (Box.from(new BlockBox(pos)).contains(planeHitPoint)) {
PORTAL_MANAGER.onPortalPassed(entity, pos, (ServerWorld) world, axis);
}
}
} else if (prevEntityPosAlongAxis < entityPosAlongAxis) {
if (entityPosAlongAxis > centerPosAlongAxis
&& prevEntityPosAlongAxis <= centerPosAlongAxis) {
double plainHitAfter = (centerPosAlongAxis - entityPosAlongAxis) / movementAlongAxis;
Vec3d planeHitPoint = entityPos.add(movement.multiply(plainHitAfter));
if (Box.from(new BlockBox(pos)).contains(planeHitPoint)) {
PORTAL_MANAGER.onPortalPassed(entity, pos, (ServerWorld) world, axis);
}
}
}
}
}
public VoxelShape getShape(BlockState state, BlockView world, BlockPos pos) {
return switch (state.get(AXIS)) {
case Z -> Z_AABB;
case Y -> Y_AABB;
default -> X_AABB;
};
}
@Override
public VoxelShape getCollisionShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
if (context instanceof CollisionAwareShapeContext) {
return getShape(state, world, pos);
}
return VoxelShapes.empty();
}
@Override
public BlockState rotate(BlockState state, BlockRotation rotation) {
@ -159,7 +101,6 @@ public class PortalBlock extends Block implements FluidFillable {
public BlockState getStateWith(DyeColor color, Direction.Axis axis) {
return this.getDefaultState().with(AXIS, axis).with(DYE_COLOR, color);
}
@Override

View File

@ -0,0 +1,57 @@
package quimufu.colourful_portals.client;
import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.blockrenderlayer.v1.BlockRenderLayerMap;
import net.fabricmc.fabric.api.client.particle.v1.ParticleFactoryRegistry;
import net.fabricmc.fabric.api.client.render.fluid.v1.FluidRenderHandlerRegistry;
import net.fabricmc.fabric.api.client.rendering.v1.EntityRendererRegistry;
import net.minecraft.client.item.ModelPredicateProviderRegistry;
import net.minecraft.client.render.RenderLayer;
import net.minecraft.client.render.entity.FlyingItemEntityRenderer;
import net.minecraft.component.DataComponentTypes;
import net.minecraft.particle.SimpleParticleType;
import net.minecraft.util.DyeColor;
import net.minecraft.util.Identifier;
import quimufu.colourful_portals.ColourfulPortalsMod;
import quimufu.colourful_portals.client.particle.ColourfulAirSparkleParticle;
import quimufu.colourful_portals.client.rendering.fluid.CommonPortalFluidRenderer;
import quimufu.colourful_portals.client.rendering.fluid.CommonPortalFluidRendererV1;
import quimufu.colourful_portals.client.rendering.fluid.CommonPortalFluidRendererV2;
import quimufu.colourful_portals.client.rendering.fluid.PortalFluidRenderHandler;
import quimufu.colourful_portals.config.ColourfulPortalConfig;
import java.util.Map;
public class ColourfulPortalsModClient implements ClientModInitializer {
public static ThreadLocal<CommonPortalFluidRenderer> FLUID_RENDERER = ThreadLocal.withInitial(CommonPortalFluidRendererV2::new);
public void onInitializeClient() {
BlockRenderLayerMap.INSTANCE.putBlock(ColourfulPortalsMod.PORTAL_BLOCK, RenderLayer.getTranslucent());
BlockRenderLayerMap.INSTANCE.putBlock(ColourfulPortalsMod.COLOURFUL_AIR, RenderLayer.getTranslucent());
BlockRenderLayerMap.INSTANCE.putFluid(ColourfulPortalsMod.PORTAL_FLUID, RenderLayer.getTranslucent());
FluidRenderHandlerRegistry.INSTANCE.register(ColourfulPortalsMod.PORTAL_FLUID, new PortalFluidRenderHandler());
EntityRendererRegistry.register(ColourfulPortalsMod.COLOURFUL_PEARL_ENTITY_TYPE, FlyingItemEntityRenderer::new);
ColourfulPortalConfig.registerListener(this::onConfigUpdate);
onConfigUpdate();
for (Map.Entry<DyeColor, SimpleParticleType> entry : ColourfulPortalsMod.COLOURFUL_AIR_PARTICLE_BY_COLOUR.entrySet()) {
ParticleFactoryRegistry.getInstance()
.register(entry.getValue(), ColourfulAirSparkleParticle::create);
}
ModelPredicateProviderRegistry.register(ColourfulPortalsMod.COLOURFUL_AIR_BOTTLE_ITEM, Identifier.of(ColourfulPortalsMod.MOD_ID,"color_id"),((stack, world, entity, seed) -> stack.getOrDefault(DataComponentTypes.BASE_COLOR, DyeColor.BLACK).getId()));
}
private void onConfigUpdate() {
if (ColourfulPortalConfig.blockyPortalFluid) {
FLUID_RENDERER = ThreadLocal.withInitial(CommonPortalFluidRendererV1::new);
} else {
FLUID_RENDERER = ThreadLocal.withInitial(CommonPortalFluidRendererV2::new);
}
}
}

View File

@ -1,4 +1,4 @@
package quimufu.colourful_portals.mixin.client;
package quimufu.colourful_portals.client.mixin;
import net.minecraft.client.texture.Animator;
import net.minecraft.client.texture.SpriteContents;
@ -10,8 +10,8 @@ import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import quimufu.colourful_portals.client.AlphaBlendingAnimator;
import quimufu.colourful_portals.client.AlphaInterpolationHolder;
import quimufu.colourful_portals.client.rendering.AlphaBlendingAnimator;
import quimufu.colourful_portals.client.rendering.AlphaInterpolationHolder;
import java.util.List;

View File

@ -1,9 +1,9 @@
package quimufu.colourful_portals.mixin.client;
package quimufu.colourful_portals.client.mixin;
import net.minecraft.client.resource.metadata.AnimationResourceMetadata;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import quimufu.colourful_portals.client.AlphaInterpolationHolder;
import quimufu.colourful_portals.client.rendering.AlphaInterpolationHolder;
@Mixin(AnimationResourceMetadata.class)
public class AnimationResourceMetadataMixin implements AlphaInterpolationHolder {

View File

@ -1,4 +1,4 @@
package quimufu.colourful_portals.mixin.client;
package quimufu.colourful_portals.client.mixin;
import com.google.gson.JsonObject;
import net.minecraft.client.resource.metadata.AnimationResourceMetadata;
@ -8,7 +8,7 @@ import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import quimufu.colourful_portals.client.AlphaInterpolationHolder;
import quimufu.colourful_portals.client.rendering.AlphaInterpolationHolder;
@Mixin(AnimationResourceMetadataReader.class)
public class AnimationResourceMetadataReaderMixin {

View File

@ -0,0 +1,11 @@
package quimufu.colourful_portals.client.mixin;
import net.minecraft.client.MinecraftClient;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(MinecraftClient.class)
public interface MinecraftClientAccessor {
@Accessor
void setItemUseCooldown(int itemUseCooldown);
}

View File

@ -1,4 +1,4 @@
package quimufu.colourful_portals.mixin.client;
package quimufu.colourful_portals.client.mixin;
import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildBuffers;
import me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline.FluidRenderer;
@ -10,7 +10,7 @@ import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import quimufu.colourful_portals.client.SodiumPortalFluidRenderHandler;
import quimufu.colourful_portals.client.rendering.fluid.SodiumPortalFluidRenderHandler;
import static quimufu.colourful_portals.ColourfulPortalsMod.PORTAL_FLUID;

View File

@ -1,4 +1,4 @@
package quimufu.colourful_portals.mixin.client;
package quimufu.colourful_portals.client.mixin;
import net.minecraft.client.resource.metadata.AnimationResourceMetadata;
import net.minecraft.client.texture.SpriteContents;
@ -11,7 +11,7 @@ import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import quimufu.colourful_portals.client.AlphaInterpolationHolder;
import quimufu.colourful_portals.client.rendering.AlphaInterpolationHolder;
@Mixin(SpriteContents.class)
public abstract class SpriteContentsMixin {

View File

@ -0,0 +1,84 @@
package quimufu.colourful_portals.client.particle;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.fabricmc.fabric.api.client.particle.v1.FabricSpriteProvider;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.option.ParticlesMode;
import net.minecraft.client.particle.ParticleFactory;
import net.minecraft.client.particle.ParticleTextureSheet;
import net.minecraft.client.particle.SpriteBillboardParticle;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.particle.ParticleGroup;
import net.minecraft.particle.SimpleParticleType;
import org.joml.Random;
import java.util.EnumMap;
import java.util.Map;
import java.util.Optional;
import static net.minecraft.client.option.ParticlesMode.*;
@Environment(value = EnvType.CLIENT)
public class ColourfulAirSparkleParticle extends SpriteBillboardParticle {
public static ParticleGroup COLOURFUL_AIR_GROUP = new ParticleGroup(0) {
private static final Random rnd = new Random(747906141);
private static final EnumMap<ParticlesMode, Integer> COUNTS = new EnumMap<>(
Map.of(
ALL, 1 << 12,
DECREASED, 1 << 11,
MINIMAL, 1 << 8
)
);
@Override
public int getMaxCount() {
Integer count = COUNTS
.getOrDefault(MinecraftClient.getInstance().options.getParticles().getValue(), 0);
return count / 4 + rnd.nextInt((count * 3) / 4);
}
};
private final FabricSpriteProvider spriteProvider;
private final int variant;
protected ColourfulAirSparkleParticle(ClientWorld clientWorld,
double posX, double posY, double posZ,
FabricSpriteProvider spriteProvider
) {
super(clientWorld, posX, posY, posZ);
this.spriteProvider = spriteProvider;
int variants = spriteProvider.getSprites().size() / 2;
variant = random.nextInt(variants);
setSprite(spriteProvider.getSprites().get(variant * 2));
setMaxAge(20 + random.nextInt(20) + random.nextInt(20));
gravityStrength = 0;
}
@Override
public void tick() {
super.tick();
if (age == maxAge / 2) {
setSprite(spriteProvider.getSprites().get(variant * 2 + 1));
}
}
@Override
public Optional<ParticleGroup> getGroup() {
return Optional.ofNullable(COLOURFUL_AIR_GROUP);
}
@Override
public ParticleTextureSheet getType() {
return ParticleTextureSheet.PARTICLE_SHEET_TRANSLUCENT;
}
public static ParticleFactory<SimpleParticleType> create(FabricSpriteProvider provider) {
return (parameters, world, x, y, z, velocityX, velocityY, velocityZ) ->
new ColourfulAirSparkleParticle(world, x, y, z, provider);
}
}

View File

@ -1,4 +1,4 @@
package quimufu.colourful_portals.client;
package quimufu.colourful_portals.client.rendering;
import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.texture.Animator;

View File

@ -1,4 +1,4 @@
package quimufu.colourful_portals.client;
package quimufu.colourful_portals.client.rendering;
public interface AlphaInterpolationHolder {

View File

@ -1,4 +1,4 @@
package quimufu.colourful_portals.client;
package quimufu.colourful_portals.client.rendering.fluid;
import net.minecraft.fluid.FluidState;
import net.minecraft.util.math.BlockPos;

View File

@ -1,4 +1,4 @@
package quimufu.colourful_portals.client;
package quimufu.colourful_portals.client.rendering.fluid;
import net.fabricmc.fabric.api.client.render.fluid.v1.FluidRenderHandler;
import net.fabricmc.fabric.api.client.render.fluid.v1.FluidRenderHandlerRegistry;

View File

@ -1,4 +1,4 @@
package quimufu.colourful_portals.client;
package quimufu.colourful_portals.client.rendering.fluid;
import net.fabricmc.fabric.api.client.render.fluid.v1.FluidRenderHandler;
import net.fabricmc.fabric.api.client.render.fluid.v1.FluidRenderHandlerRegistry;

View File

@ -1,4 +1,4 @@
package quimufu.colourful_portals.client;
package quimufu.colourful_portals.client.rendering.fluid;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
@ -16,7 +16,7 @@ import org.jetbrains.annotations.Nullable;
import org.joml.Quaternionf;
import org.joml.Vector3f;
import quimufu.colourful_portals.ColourfulPortalsMod;
import quimufu.colourful_portals.ColourfulPortalsModClient;
import quimufu.colourful_portals.client.ColourfulPortalsModClient;
@Environment(value = EnvType.CLIENT)
public class PortalFluidRenderHandler implements FluidRenderHandler, VertexEater {

View File

@ -1,4 +1,4 @@
package quimufu.colourful_portals.client;
package quimufu.colourful_portals.client.rendering.fluid;
import me.jellysquid.mods.sodium.client.model.quad.ModelQuad;
import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView;
@ -18,8 +18,7 @@ import net.minecraft.util.math.Direction;
import net.minecraft.world.BlockRenderView;
import org.joml.Quaternionf;
import org.joml.Vector3f;
import quimufu.colourful_portals.ColourfulPortalsMod;
import quimufu.colourful_portals.ColourfulPortalsModClient;
import quimufu.colourful_portals.client.ColourfulPortalsModClient;
@Environment(value = EnvType.CLIENT)
public class SodiumPortalFluidRenderHandler implements VertexEater {

View File

@ -1,4 +1,4 @@
package quimufu.colourful_portals.client;
package quimufu.colourful_portals.client.rendering.fluid;
import net.minecraft.client.texture.Sprite;
import net.minecraft.util.math.Direction;

View File

@ -2,80 +2,99 @@ package quimufu.colourful_portals.config;
import com.google.common.collect.Lists;
import eu.midnightdust.lib.config.MidnightConfig;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.registry.RegistryKey;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.DyeColor;
import net.minecraft.world.World;
import quimufu.colourful_portals.ColourfulPortalsMod;
import quimufu.colourful_portals.util.Procedure;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.*;
public class ColourfulPortalConfig extends MidnightConfig {
@Entry(category = "text", name = "Disable Immersive Portals integration")
@Entry(category = "integrations", name = "Disable Immersive Portals integration")
public static boolean disableImmersivePortals = false;
@Comment(category = "text")
public static Comment explanation;
@Comment(category = "portal_colours")
public static Comment explanation1;
@Comment(category = "portal_colours")
public static Comment explanation2;
@Entry(category = "text", name = "Blocks that create white portals")
@Entry(category = "portal_colours")
public static List<String> white = Lists.newArrayList("minecraft:white_wool");
@Entry(category = "text", name = "Blocks that create orange portals")
@Entry(category = "portal_colours")
public static List<String> orange = Lists.newArrayList("minecraft:orange_wool");
@Entry(category = "text", name = "Blocks that create magenta portals")
@Entry(category = "portal_colours")
public static List<String> magenta = Lists.newArrayList("minecraft:magenta_wool");
@Entry(category = "text", name = "Blocks that create light blue portals")
@Entry(category = "portal_colours")
public static List<String> light_blue = Lists.newArrayList("minecraft:light_blue_wool");
@Entry(category = "text", name = "Blocks that create yellow portals")
@Entry(category = "portal_colours")
public static List<String> yellow = Lists.newArrayList("minecraft:yellow_wool");
@Entry(category = "text", name = "Blocks that create lime portals")
@Entry(category = "portal_colours")
public static List<String> lime = Lists.newArrayList("minecraft:lime_wool");
@Entry(category = "text", name = "Blocks that create pink portals")
@Entry(category = "portal_colours")
public static List<String> pink = Lists.newArrayList("minecraft:pink_wool");
@Entry(category = "text", name = "Blocks that create gray portals")
@Entry(category = "portal_colours")
public static List<String> gray = Lists.newArrayList("minecraft:gray_wool");
@Entry(category = "text", name = "Blocks that create light gray portals")
@Entry(category = "portal_colours")
public static List<String> light_gray = Lists.newArrayList("minecraft:light_gray_wool");
@Entry(category = "text", name = "Blocks that create cyan portals")
@Entry(category = "portal_colours")
public static List<String> cyan = Lists.newArrayList("minecraft:cyan_wool");
@Entry(category = "text", name = "Blocks that create purple portals")
@Entry(category = "portal_colours")
public static List<String> purple = Lists.newArrayList("minecraft:purple_wool");
@Entry(category = "text", name = "Blocks that create blue portals")
@Entry(category = "portal_colours")
public static List<String> blue = Lists.newArrayList("minecraft:blue_wool");
@Entry(category = "text", name = "Blocks that create brown portals")
@Entry(category = "portal_colours")
public static List<String> brown = Lists.newArrayList("minecraft:brown_wool");
@Entry(category = "text", name = "Blocks that create green portals")
@Entry(category = "portal_colours")
public static List<String> green = Lists.newArrayList("minecraft:green_wool");
@Entry(category = "text", name = "Blocks that create red portals")
@Entry(category = "portal_colours")
public static List<String> red = Lists.newArrayList("minecraft:red_wool");
@Entry(category = "text", name = "Blocks that create black portals")
@Entry(category = "portal_colours")
public static List<String> black = Lists.newArrayList("minecraft:black_wool");
@Entry(category = "text", name = "Blocks that create fully transparent portals")
@Entry(category = "portal_colours")
public static List<String> none = Lists.newArrayList();
@Entry(category = "text", name = "Use the old Portal Fluid look")
@Entry(category = "visuals")
public static boolean blockyPortalFluid = false;
@Entry(category = "colourful_pearl")
public static Map<String, Integer> pearlDimensionWeights = new HashMap<>(
Map.of("minecraft:overworld", 79,
"minecraft:the_nether", 20,
"minecraft:the_end", 1)
);
@Entry(category = "colourful_pearl", isSlider = true, min = 0f, max = 1f, precision = 1000)
public static double pearlSameDimensionLikelihood = 0.9D;
@Entry(category = "colourful_pearl", isSlider = true, min = 1 << 4, max = 1 << 16, precision = 10)
public static double maxPearlDistance = 1 << 14;
@Entry(category = "colourful_pearl", isSlider = true, min = 1 << 4, max = 1 << 16, precision = 10)
public static double minPearlDistance = 1 << 12;
private static final ArrayList<Procedure> onWrite = new ArrayList<>(2);
public static Set<String> getAllPortalBlocks() {
Set<String> allBlocks = new HashSet<>();
allBlocks.addAll(white);
@ -150,4 +169,24 @@ public class ColourfulPortalConfig extends MidnightConfig {
public static void registerListener(Procedure p) {
onWrite.add(p);
}
public static void addMissingDimensionsToConfig(MinecraftServer server) {
Set<RegistryKey<World>> worlds = server.getWorldRegistryKeys();
boolean changed = false;
for (RegistryKey<World> world : worlds) {
if (!pearlDimensionWeights.containsKey(world.getValue().toString())) {
pearlDimensionWeights.put(world.getValue().toString(), 1);
changed = true;
}
}
if (maxPearlDistance < minPearlDistance) {
double min = maxPearlDistance;
maxPearlDistance = minPearlDistance;
minPearlDistance = min;
changed = true;
}
if (changed) {
write(ColourfulPortalsMod.MOD_ID);
}
}
}

View File

@ -0,0 +1,268 @@
package quimufu.colourful_portals.entity;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.projectile.thrown.ThrownItemEntity;
import net.minecraft.item.Item;
import net.minecraft.particle.ParticleTypes;
import net.minecraft.predicate.entity.EntityPredicates;
import net.minecraft.registry.Registries;
import net.minecraft.registry.RegistryKey;
import net.minecraft.registry.RegistryKeys;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.sound.SoundCategory;
import net.minecraft.sound.SoundEvents;
import net.minecraft.util.Identifier;
import net.minecraft.util.hit.HitResult;
import net.minecraft.util.math.*;
import net.minecraft.world.Heightmap;
import net.minecraft.world.TeleportTarget;
import net.minecraft.world.World;
import net.minecraft.world.border.WorldBorder;
import net.minecraft.world.dimension.DimensionType;
import org.jetbrains.annotations.Nullable;
import org.joml.Vector3f;
import quimufu.colourful_portals.ColourfulPortalsMod;
import quimufu.colourful_portals.config.ColourfulPortalConfig;
import quimufu.colourful_portals.portal.PortalHelper;
import quimufu.colourful_portals.util.AdditionalMath;
import java.util.List;
public class ColourfulPearlEntity
extends ThrownItemEntity {
public ColourfulPearlEntity(EntityType<? extends ColourfulPearlEntity> entityType, World world) {
super(entityType, world);
}
public ColourfulPearlEntity(World world, LivingEntity owner) {
super(ColourfulPortalsMod.COLOURFUL_PEARL_ENTITY_TYPE, owner, world);
}
@Override
protected Item getDefaultItem() {
return ColourfulPortalsMod.COLOURFUL_PEARL_ITEM;
}
@Override
public void onRemoved() {
if (this.getRemovalReason() == RemovalReason.DISCARDED) {
if (getWorld() instanceof ClientWorld clientWorld) {
clientWorld.playSound(
this.getX(), this.getY(), this.getZ(),
ColourfulPortalsMod.TELEPORT_AWAY_SOUND,
SoundCategory.BLOCKS,
100F, 1.25F,
false);
}
List<Entity> entities = getWorld()
.getOtherEntities(this, this.getBoundingBox().expand(5));
entities.stream()
.filter(e -> e.squaredDistanceTo(this) < 25)
.forEach(this::spawnTeleportationParticles);
}
}
private void spawnTeleportationParticles(Entity entity) {
for (int i = 0; i < 64; ++i) {
Box box = entity.getBoundingBox();
float xOffset = (float) ((AdditionalMath.root(random.nextFloat() * 2 - 1, 3) / 2) * box.getLengthX() * 2);
float yOffset = (float) (AdditionalMath.root(random.nextFloat(), 3) * box.getLengthY() * 2);
float zOffset = (float) ((AdditionalMath.root(random.nextFloat() * 2 - 1, 3) / 2) * box.getLengthZ() * 2);
Vector3f offset = new Vector3f(xOffset, yOffset, zOffset);
addHitParticle(this.getWorld(), entity, offset);
}
}
@Override
protected void onCollision(HitResult hitResult) {
if (getWorld().isClient()) {
return;
}
if (isRemoved()) {
return;
}
List<Entity> entities = getWorld()
.getOtherEntities(this, this.getBoundingBox().expand(5), EntityPredicates.EXCEPT_SPECTATOR
.and(entity -> entity instanceof LivingEntity)
.and(entity -> !entity.getType().isIn(ColourfulPortalsMod.COLOURFUL_PEARL_NOT_TELEPORTABLE)));
entities.stream()
.filter(e -> e.squaredDistanceTo(this) < 25)
.forEach(this::tryTeleport);
this.discard();
}
private void tryTeleport(Entity entity) {
if (!(getWorld() instanceof ServerWorld serverWorld)) {
return;
}
if (entity == null || !canTeleportEntityTo(entity, serverWorld)) {
return;
}
if (entity.hasVehicle()) {
entity.detach();
}
TeleportTarget target = findTarget(serverWorld, entity, null);
while (target == null || !targetValid(target, entity)) {
target = findTarget(serverWorld, entity, target);
}
prepareTarget(target, entity);
if (entity instanceof ServerPlayerEntity serverPlayerEntity) {
if (serverPlayerEntity.networkHandler.isConnectionOpen()) {
Entity entityAfterTeleport = entity.teleportTo(target);
if (entityAfterTeleport == null) {
return;
}
entityAfterTeleport.onLanding();
serverPlayerEntity.clearCurrentExplosion();
entityAfterTeleport.damage(this.getDamageSources().fall(), 5.0f);
serverPlayerEntity.playSoundToPlayer(SoundEvents.ENTITY_PLAYER_TELEPORT, SoundCategory.PLAYERS, 1F, 0.75F);
}
} else {
Entity entityAfterTeleport = entity.teleportTo(target);
if (entityAfterTeleport == null) {
return;
}
entityAfterTeleport.onLanding();
serverWorld.playSound(entityAfterTeleport, entityAfterTeleport.getBlockPos(),
SoundEvents.ENTITY_PLAYER_TELEPORT, SoundCategory.NEUTRAL,
1F, 0.75F);
}
}
private void addHitParticle(World world, Entity entity, Vector3f offset) {
Vector3f endPos = randomInside(this.getDimensions(null).getBoxAt(entity.getPos()))
.add(offset);
world.addParticle(ParticleTypes.PORTAL,
endPos.x, endPos.y, endPos.z,
-offset.x, -offset.y, -offset.z);
}
private Vector3f randomInside(Box box) {
return box.getMinPos().toVector3f()
.add(((float) box.getLengthX()) * random.nextFloat(),
((float) box.getLengthY()) * random.nextFloat(),
((float) box.getLengthZ()) * random.nextFloat());
}
private boolean targetValid(TeleportTarget target, Entity entity) {
Box boundingBox = entity.getDimensions(entity.getPose())
.getBoxAt(target.pos())
.stretch(0, -1, 0);
boolean foundAir = false;
boolean foundNonAir = false;
for (BlockPos pos : PortalHelper.blockPosInBox(boundingBox)) {
BlockState blockState = target.world().getBlockState(pos);
if (!blockState.isIn(ColourfulPortalsMod.COLOURFUL_PEARL_REPLACEABLE_BLOCK_TAG)) {
ColourfulPortalsMod.LOGGER.info("invalid location at {}, block {}", pos, Registries.BLOCK.getId(blockState.getBlock()));
return false;
}
if (blockState.isAir()) {
foundAir = true;
} else {
foundNonAir = true;
}
}
return foundAir && foundNonAir;
}
private void prepareTarget(TeleportTarget target, Entity entity) {
Box entityBody = entity.getDimensions(entity.getPose()).getBoxAt(target.pos());
double minY = entityBody.getMinPos().getY();
Box floor = entityBody.withMinY(minY - 1).withMaxY(minY - 0.5);
for (BlockPos pos : PortalHelper.blockPosInBox(entityBody)) {
target.world().setBlockState(pos, ColourfulPortalsMod.COLOURFUL_AIR.getRandomState(random));
}
for (BlockPos pos : PortalHelper.blockPosInBox(floor)) {
target.world().setBlockState(pos, Blocks.STONE.getDefaultState());
}
}
private @Nullable TeleportTarget findTarget(ServerWorld serverWorld, Entity entity, TeleportTarget target) {
if (target != null
//position makes sense to retry
&& !isEmptyPosition(target)
//prevents potential infinite loop if position does have weird block compositions
&& random.nextInt(target.world().getLogicalHeight() * 2) != 0) {
return new TeleportTarget(target.world(),
target.pos().withAxis(Direction.Axis.Y, getTargetY(target.world())),
target.velocity(),
target.yaw(),
target.pitch(),
target.postDimensionTransition());
}
//re-use targetWorld to prevent dimensions with less valid spawning positions from becoming less likely
ServerWorld targetWorld = target == null ? getTargetWorld(serverWorld) : target.world();
if (targetWorld == null) {
return null;
}
//adjust position within target
Vec3d minPos = Vec3d.of(getTargetPos(serverWorld, targetWorld, getPos()));
int width = MathHelper.ceil(entity.getBoundingBox().getLengthX());
int depth = MathHelper.ceil(entity.getBoundingBox().getLengthZ());
Vec3d targetLocation = minPos.add((width % 2) * 0.5F, 0, (depth % 2) * 0.5F);
return new TeleportTarget(targetWorld, targetLocation, entity.getVelocity(), entity.getYaw(), entity.getPitch(), TeleportTarget.NO_OP);
}
private static boolean isEmptyPosition(TeleportTarget target) {
return target.world().getTopY(Heightmap.Type.WORLD_SURFACE, (int) target.pos().x, (int) target.pos().z) == target.world().getBottomY();
}
private @Nullable ServerWorld getTargetWorld(ServerWorld serverWorld) {
if (this.getRandom().nextDouble() < ColourfulPortalConfig.pearlSameDimensionLikelihood) {
return serverWorld;
}
MinecraftServer server = serverWorld.getServer();
ColourfulPortalConfig.addMissingDimensionsToConfig(server);
Identifier targetWorldId = ColourfulPortalsMod.DIMENSION_WEIGHTS_COLOURFUL_PEARL.getWeighted(random);
return server.getWorld(RegistryKey.of(RegistryKeys.WORLD, targetWorldId));
}
private BlockPos getTargetPos(ServerWorld fromWorld, ServerWorld toWorld, Vec3d pos) {
double distance = ColourfulPortalConfig.minPearlDistance +
getRandom().nextDouble() *
(ColourfulPortalConfig.maxPearlDistance - ColourfulPortalConfig.minPearlDistance);
double angle = Math.PI * 2 * getRandom().nextDouble();
int targetY = getTargetY(toWorld);
Vec3d target = new Vec3d(pos.getX() + Math.cos(angle) * distance, targetY, pos.getZ() + Math.sin(angle) * distance);
WorldBorder worldBorder = toWorld.getWorldBorder();
double d = DimensionType.getCoordinateScaleFactor(fromWorld.getDimension(), toWorld.getDimension());
return worldBorder.clamp(target.getX() * d, target.getY(), target.getZ() * d);
}
private int getTargetY(ServerWorld toWorld) {
return toWorld.getBottomY() + 4 + (getRandom().nextInt(toWorld.getLogicalHeight() - 8));
}
private static boolean canTeleportEntityTo(Entity entity, World world) {
if (entity.getWorld().getRegistryKey() == world.getRegistryKey()) {
if (entity instanceof LivingEntity livingEntity) {
return livingEntity.isAlive() && !livingEntity.isSleeping();
}
return entity.isAlive();
}
return entity.canUsePortals(true);
}
}

View File

@ -26,7 +26,6 @@ public class LinkedList<E> implements List<E> {
size++;
node = node.getNext();
}
LOGGER.info("" + size);
return size;
}

View File

@ -0,0 +1,33 @@
package quimufu.colourful_portals.general_util;
import net.minecraft.util.math.random.Random;
import java.util.TreeMap;
public class WeightedSelector <E> {
private final TreeMap<Integer, E> backingMap = new TreeMap<>();
private int total = 0;
public void add(E object, int weight){
if(weight <= 0){
return;
}
backingMap.put(total, object);
total += weight;
}
public void clear() {
total = 0;
backingMap.clear();
}
public E getWeighted(Random random) {
if(total == 0){
throw new IllegalStateException("tried to receive Weighted Result from empty Selector");
}
return backingMap.floorEntry(random.nextInt(total)).getValue();
}
}

View File

@ -0,0 +1,101 @@
package quimufu.colourful_portals.item;
import net.minecraft.advancement.criterion.Criteria;
import net.minecraft.block.Block;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.component.DataComponentTypes;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.*;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.sound.SoundEvent;
import net.minecraft.sound.SoundEvents;
import net.minecraft.stat.Stats;
import net.minecraft.util.*;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraft.world.event.GameEvent;
import org.jetbrains.annotations.Nullable;
import quimufu.colourful_portals.ColourfulAirBlock;
import quimufu.colourful_portals.ColourfulPortalsMod;
import quimufu.colourful_portals.client.mixin.MinecraftClientAccessor;
public class ColourfulAirBottleItem
extends AliasedBlockItem {
private static final int MAX_USE_TIME = 40;
public ColourfulAirBottleItem(Block block, Settings settings) {
super(block, settings);
}
@Override
public ItemStack finishUsing(ItemStack stack, World world, LivingEntity user) {
if (!tryPlaceAtHead(stack, world, user)) {
return stack;
}
user.emitGameEvent(GameEvent.DRINK);
if (user instanceof PlayerEntity playerEntity) {
stack = ItemUsage.exchangeStack(stack, playerEntity, new ItemStack(Items.GLASS_BOTTLE));
if(world.isClient){
((MinecraftClientAccessor)MinecraftClient.getInstance())
.setItemUseCooldown(16);
}
}
if (user instanceof ServerPlayerEntity serverPlayerEntity) {
Criteria.CONSUME_ITEM.trigger(serverPlayerEntity, stack);
serverPlayerEntity.incrementStat(Stats.USED.getOrCreateStat(this));
}
return stack;
}
private boolean tryPlaceAtHead(ItemStack stack, World world, LivingEntity user) {
BlockPos headPos = BlockPos.ofFloored(user.getEyePos());
if (world.getBlockState(headPos).isIn(ColourfulPortalsMod.COLOURFUL_PEARL_REPLACEABLE_BLOCK_TAG)) {
DyeColor color = stack.getOrDefault(DataComponentTypes.BASE_COLOR, DyeColor.BLACK);
return world.setBlockState(headPos, getBlock().getDefaultState()
.withIfExists(ColourfulAirBlock.DYE_COLOR, color),
Block.NOTIFY_ALL_AND_REDRAW);
}
return false;
}
@Override
public ActionResult useOnBlock(ItemUsageContext context) {
if (context.getPlayer() != null && context.getPlayer().isSneaking()) {
return ActionResult.PASS;
}
return super.useOnBlock(context);
}
@Override
public int getMaxUseTime(ItemStack stack, LivingEntity user) {
return MAX_USE_TIME;
}
@Override
public UseAction getUseAction(ItemStack stack) {
return UseAction.DRINK;
}
@Override
public SoundEvent getDrinkSound() {
//todo
return SoundEvents.ITEM_HONEY_BOTTLE_DRINK;
}
@Override
public SoundEvent getEatSound() {
//todo
return SoundEvents.ITEM_HONEY_BOTTLE_DRINK;
}
@Override
public TypedActionResult<ItemStack> use(World world, PlayerEntity user, Hand hand) {
return ItemUsage.consumeHeldItem(world, user, hand);
}
}

View File

@ -0,0 +1,36 @@
package quimufu.colourful_portals.item;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.sound.SoundCategory;
import net.minecraft.sound.SoundEvents;
import net.minecraft.stat.Stats;
import net.minecraft.util.Hand;
import net.minecraft.util.TypedActionResult;
import net.minecraft.world.World;
import quimufu.colourful_portals.entity.ColourfulPearlEntity;
public class ColourfulPearlItem
extends Item {
public ColourfulPearlItem(Item.Settings settings) {
super(settings);
}
@Override
public TypedActionResult<ItemStack> use(World world, PlayerEntity user, Hand hand) {
ItemStack stackInHand = user.getStackInHand(hand);
world.playSound(null, user.getX(), user.getY(), user.getZ(), SoundEvents.ENTITY_ENDER_PEARL_THROW, SoundCategory.NEUTRAL, 0.5f, 0.4f / (world.getRandom().nextFloat() * 0.4f + 0.8f));
user.getItemCooldownManager().set(this, 50);
if (!world.isClient) {
ColourfulPearlEntity colourfulPearlEntity = new ColourfulPearlEntity(world, user);
colourfulPearlEntity.setItem(stackInHand);
colourfulPearlEntity.setVelocity(user, user.getPitch(), user.getYaw(), 0.0f, 1.5f, 1.0f);
world.spawnEntity(colourfulPearlEntity);
}
user.incrementStat(Stats.USED.getOrCreateStat(this));
stackInHand.decrementUnlessCreative(1, user);
return TypedActionResult.success(stackInHand, world.isClient());
}
}

View File

@ -74,16 +74,29 @@ public abstract class BlockChangeAndEntityMovementMixin {
// This code is injected into the end of ServerWorld.onBlockChanged()V
if (oldBlock.getBlock() != newBlock.getBlock()) {
if (PORTAL_BLOCKS.contains(Registries.BLOCK.getId(newBlock.getBlock()))) {
LOGGER.info("onBlockNew {} -> {}", oldBlock, newBlock);
LOGGER.debug("onBlockNew {} -> {}", oldBlock, newBlock);
Identifier blockId = Registries.BLOCK.getId(newBlock.getBlock());
world.getServer().execute(() -> PORTAL_MANAGER.onPortalBlockPlaced(world, pos, blockId));
synchronized (PORTAL_MANAGER.pendingUpdates){
PORTAL_MANAGER.pendingUpdates.add(() ->
PORTAL_MANAGER.onPortalBlockPlaced(world, pos, blockId));
}
if(!PORTAL_MANAGER.blockUpdatesPending.getAndSet(true)){
world.getServer().execute(PORTAL_MANAGER::runPendingUpdates);
}
}
if (PORTAL_BLOCKS.contains(Registries.BLOCK.getId(oldBlock.getBlock()))) {
LOGGER.info("onBlockOld {} -> {}", oldBlock, newBlock);
LOGGER.debug("onBlockOld {} -> {}", oldBlock, newBlock);
Identifier blockId = Registries.BLOCK.getId(oldBlock.getBlock());
world.getServer().execute(() -> PORTAL_MANAGER.onPortalBlockBroken(world, pos, blockId));
synchronized (PORTAL_MANAGER.pendingUpdates){
PORTAL_MANAGER.pendingUpdates.add(() ->
PORTAL_MANAGER.onPortalBlockBroken(world, pos, blockId));
}
if(!PORTAL_MANAGER.blockUpdatesPending.getAndSet(true)){
world.getServer().execute(PORTAL_MANAGER::runPendingUpdates);
}
}
}
}
}

View File

@ -8,10 +8,8 @@ import net.minecraft.registry.RegistryKeys;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockBox;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.Vec3i;
import net.minecraft.util.math.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
@ -230,6 +228,10 @@ public class PortalHelper {
return world.getDimensionEntry().getKey().orElseThrow().getValue();
}
public static @NotNull Iterable<BlockPos> blockPosInBox(Box boundinBox) {
return BlockPos.iterate(MathHelper.floor(boundinBox.minX), MathHelper.floor(boundinBox.minY), MathHelper.floor(boundinBox.minZ), MathHelper.floor(boundinBox.maxX), MathHelper.floor(boundinBox.maxY), MathHelper.floor(boundinBox.maxZ));
}
private static class BlockPosIterator implements Iterator<BlockPos> {
private final BlockPos startPos;

View File

@ -15,7 +15,9 @@ import quimufu.colourful_portals.general_util.LinkedList;
import java.util.HashSet;
import java.util.List;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import static quimufu.colourful_portals.ColourfulPortalsMod.*;
@ -24,6 +26,9 @@ public class PortalManager {
private final PortalListComponent portalCandidateList;
private final PortalListComponent portalList;
public final AtomicBoolean blockUpdatesPending = new AtomicBoolean(false);
public final Queue<Runnable> pendingUpdates = new java.util.LinkedList<>();
public PortalLinkingSystem getLinkingSystem() {
return linkingSystem;
}
@ -275,4 +280,20 @@ public class PortalManager {
}
}
public void runPendingUpdates() {
if(pendingUpdates.size()<20){
blockUpdatesPending.set(false);
}
for (int i = 0; i < Math.min(20, pendingUpdates.size()); i++) {
Runnable runnable;
synchronized (pendingUpdates) {
runnable = pendingUpdates.poll();
}
if(runnable == null){
return;
}
runnable.run();
}
}
}

View File

@ -0,0 +1,17 @@
package quimufu.colourful_portals.util;
import static java.lang.Float.NaN;
public class AdditionalMath {
public static float root(float x, int nThRoot){
if(nThRoot<=0){
return NaN;
}
if(x<0 && nThRoot%2 == 1){
return -(float) Math.pow(-x, 1D / nThRoot);
}
return (float) Math.pow(x, 1D / nThRoot);
}
}

View File

@ -1,32 +0,0 @@
package quimufu.colourful_portals.util;
import net.minecraft.block.ShapeContext;
import net.minecraft.fluid.FluidState;
import net.minecraft.item.Item;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.shape.VoxelShape;
public class CollisionAwareShapeContext implements ShapeContext {
public CollisionAwareShapeContext() {
}
@Override
public boolean isDescending() {
return false;
}
@Override
public boolean isAbove(VoxelShape shape, BlockPos pos, boolean defaultValue) {
return false;
}
@Override
public boolean isHolding(Item item) {
return false;
}
@Override
public boolean canWalkOnFluid(FluidState stateAbove, FluidState state) {
return false;
}
}

View File

@ -1,28 +1,39 @@
{
"block.colourful_portals.portal_block": "Farbenfrohes Portal",
"block.colourful_portals.portal_fluid_block": "Farbenfrohe Flüssigkeit",
"colourful_portals.midnightconfig.disableImmersivePortals": "Immersive Portals integration deaktivieren",
"colourful_portals.midnightconfig.black": "Blöcke, die schwarze Portale erzeugen",
"colourful_portals.midnightconfig.blue": "Blöcke, die blaue Portale erzeugen",
"colourful_portals.midnightconfig.brown": "Blöcke, die braune Portale erzeugen",
"colourful_portals.midnightconfig.cyan": "Blöcke, die cyanfarbene Portale erzeugen",
"colourful_portals.midnightconfig.disableImmersivePortals": "Immersive Portals integration deaktivieren",
"colourful_portals.midnightconfig.explanation": "Diese Konfiguration erlaubt es, zusätzliche/andere Portalblocke zu definieren.\nPortale aus diesen verbinden sich mit anderen aus dem selben Block.\nDie Liste, der der Block hinzugefügt wird, bestimmt dabei nur die Portalfarbe.\nÄnderungen treten für neue Portale oder bei Aktualisierung eines Portals in Kraft.",
"colourful_portals.midnightconfig.explanation1": "Diese Konfiguration erlaubt es, zusätzliche/andere Portalblocke zu definieren.\nPortale aus diesen verbinden sich mit anderen aus dem selben Block.",
"colourful_portals.midnightconfig.explanation2": "Die Liste, der der Block hinzugefügt wird, bestimmt dabei nur die Portalfarbe.\nÄnderungen treten für neue Portale oder bei Aktualisierung eines Portals in Kraft.",
"colourful_portals.midnightconfig.gray": "Blöcke, die graue Portale erzeugen",
"colourful_portals.midnightconfig.green": "Blöcke, die grüne Portale erstellen",
"colourful_portals.midnightconfig.green": "Blöcke, die grüne Portale erzeugen",
"colourful_portals.midnightconfig.light_blue": "Blöcke, die hellblaue Portale erzeugen",
"colourful_portals.midnightconfig.light_gray": "Blöcke, die hellgraue Portale erzeugen",
"colourful_portals.midnightconfig.lime": "Blöcke, die limonenfarbene Portale erzeugen",
"colourful_portals.midnightconfig.magenta": "Blöcke, die magentafarbene Portale erzeugen",
"colourful_portals.midnightconfig.none": "Blöcke, die vollständig transparente Portale erstellen",
"colourful_portals.midnightconfig.none": "Blöcke, die vollständig transparente Portale erzeugen",
"colourful_portals.midnightconfig.orange": "Blöcke, die orangefarbene Portale erzeugen",
"colourful_portals.midnightconfig.pink": "Blöcke, die rosa Portale erzeugen",
"colourful_portals.midnightconfig.purple": "Blöcke, die violette Portale erzeugen",
"colourful_portals.midnightconfig.red": "Blöcke, die rote Portale erzeugen",
"colourful_portals.midnightconfig.white": "Blöcke, die weiße Portale erzeugen",
"colourful_portals.midnightconfig.yellow": "Blöcke, die gelbe Portale erzeugen",
"colourful_portals.midnightconfig.blockyPortalFluid": "Das alte Aussehen von der farbenfrohen Flüssigkeit wiederherstellen",
"colourful_portals.midnightconfig.pearlDimensionWeights": "Die Gewichtungen für verschiedene Dimensionen bei Dimensionswechsel (bearbeitbar nur über die Konfigurationsdatei)",
"colourful_portals.midnightconfig.pearlSameDimensionLikelihood": "Die Wahrscheinlichkeit bei einer Teleportation mit einer Farbenfrohen Perle in der selben Dimension zu verbleiben",
"colourful_portals.midnightconfig.maxPearlDistance": "Der Mindestabstand, um den der Spieler von einer farbenfrohen Perle teleportiert werden",
"colourful_portals.midnightconfig.minPearlDistance": "Der Maximalabstand, um den der Spieler von einer farbenfrohen Perle teleportiert werden",
"colourful_portals.midnightconfig.category.portal_colours": "Portalblöcke",
"colourful_portals.midnightconfig.category.visuals": "Visuell",
"colourful_portals.midnightconfig.category.colourful_pearl": "Farbenfrohe Perle",
"colourful_portals.midnightconfig.category.integrations": "Mod Integrationen",
"subtitles.colourful_portals.entity.colourful_pearl.teleport_away": "Farbenfrohe Perle teleportiert weg",
"item.colourful_portals.colour_blob_bright": "Heller Farbmix",
"item.colourful_portals.colour_blob_dark": "Dunkler Farbmix",
"item.colourful_portals.portal_fluid_bucket": "Farbeimer",
"tag.block.c.crystals": "Kristalle",
"tag.block.c.slime_balls": "Schleimbälle"
"tag.block.c.slime_balls": "Schleimbälle",
"tag.block.c.crystals": "Kristalle"
}

View File

@ -6,7 +6,8 @@
"colourful_portals.midnightconfig.blue": "Blocks that create blue portals",
"colourful_portals.midnightconfig.brown": "Blocks that create brown portals",
"colourful_portals.midnightconfig.cyan": "Blocks that create cyan portals",
"colourful_portals.midnightconfig.explanation": "This configuration allows you to define additional/other portal blocks.\nPortals from these connect to others from the same block.\nThe list to which the block is added only determines the portal color.\nChanges take effect for new portals or when a portal is updated.",
"colourful_portals.midnightconfig.explanation1": "This configuration allows you to define additional/other portal blocks.\nPortals from these connect to others from the same block.",
"colourful_portals.midnightconfig.explanation2": "The list to which the block is added only determines the portal color.\nChanges take effect for new portals or when a portal is updated.",
"colourful_portals.midnightconfig.gray": "Blocks that create gray portals",
"colourful_portals.midnightconfig.green": "Blocks that create green portals",
"colourful_portals.midnightconfig.light_blue": "Blocks that create light blue portals",
@ -20,6 +21,16 @@
"colourful_portals.midnightconfig.red": "Blocks that create red portals",
"colourful_portals.midnightconfig.white": "Blocks that create white portals",
"colourful_portals.midnightconfig.yellow": "Blocks that create yellow portals",
"colourful_portals.midnightconfig.blockyPortalFluid": "Use the old Portal Fluid look",
"colourful_portals.midnightconfig.pearlDimensionWeights": "The weight for the different dimensions on dimension switch (only editable in config file)",
"colourful_portals.midnightconfig.pearlSameDimensionLikelihood": "Likelihood for a colourful pearl to teleport within the same dimension",
"colourful_portals.midnightconfig.maxPearlDistance": "The maximal distance a colourful pearl will teleport the player",
"colourful_portals.midnightconfig.minPearlDistance": "The minimal distance a colourful pearl will teleport the player",
"colourful_portals.midnightconfig.category.portal_colours": "Portal Blocks",
"colourful_portals.midnightconfig.category.visuals": "Visual",
"colourful_portals.midnightconfig.category.colourful_pearl": "Colourful Pearl",
"colourful_portals.midnightconfig.category.integrations": "Mod Integrations",
"subtitles.colourful_portals.entity.colourful_pearl.teleport_away": "Colourful pearl teleporting away",
"item.colourful_portals.colour_blob_bright": "Bright Colour Mix",
"item.colourful_portals.colour_blob_dark": "Dark Colour Mix",
"item.colourful_portals.portal_fluid_bucket": "Colourful Bucket",

View File

@ -0,0 +1,24 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "minecraft:item/honey_bottle"
},
"overrides": [
{ "predicate": { "color_id": 0 }, "model": "colourful_portals:item/colourful_air_bottle/white" },
{ "predicate": { "color_id": 1 }, "model": "colourful_portals:item/colourful_air_bottle/orange" },
{ "predicate": { "color_id": 2 }, "model": "colourful_portals:item/colourful_air_bottle/magenta" },
{ "predicate": { "color_id": 3 }, "model": "colourful_portals:item/colourful_air_bottle/light_blue" },
{ "predicate": { "color_id": 4 }, "model": "colourful_portals:item/colourful_air_bottle/yellow" },
{ "predicate": { "color_id": 5 }, "model": "colourful_portals:item/colourful_air_bottle/lime" },
{ "predicate": { "color_id": 6 }, "model": "colourful_portals:item/colourful_air_bottle/pink" },
{ "predicate": { "color_id": 7 }, "model": "colourful_portals:item/colourful_air_bottle/gray" },
{ "predicate": { "color_id": 8 }, "model": "colourful_portals:item/colourful_air_bottle/light_gray" },
{ "predicate": { "color_id": 9 }, "model": "colourful_portals:item/colourful_air_bottle/cyan" },
{ "predicate": { "color_id": 10 }, "model": "colourful_portals:item/colourful_air_bottle/purple" },
{ "predicate": { "color_id": 11 }, "model": "colourful_portals:item/colourful_air_bottle/blue" },
{ "predicate": { "color_id": 12 }, "model": "colourful_portals:item/colourful_air_bottle/brown" },
{ "predicate": { "color_id": 13 }, "model": "colourful_portals:item/colourful_air_bottle/green" },
{ "predicate": { "color_id": 14 }, "model": "colourful_portals:item/colourful_air_bottle/red" },
{ "predicate": { "color_id": 15 }, "model": "colourful_portals:item/colourful_air_bottle/black" }
]
}

View File

@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "colourful_portals:item/colourful_air_bottle/black"
}
}

View File

@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "colourful_portals:item/colourful_air_bottle/blue"
}
}

View File

@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "colourful_portals:item/colourful_air_bottle/brown"
}
}

View File

@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "colourful_portals:item/colourful_air_bottle/cyan"
}
}

View File

@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "colourful_portals:item/colourful_air_bottle/gray"
}
}

View File

@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "colourful_portals:item/colourful_air_bottle/green"
}
}

View File

@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "colourful_portals:item/colourful_air_bottle/light_blue"
}
}

View File

@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "colourful_portals:item/colourful_air_bottle/light_gray"
}
}

View File

@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "colourful_portals:item/colourful_air_bottle/lime"
}
}

View File

@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "colourful_portals:item/colourful_air_bottle/magenta"
}
}

View File

@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "colourful_portals:item/colourful_air_bottle/orange"
}
}

View File

@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "colourful_portals:item/colourful_air_bottle/pink"
}
}

View File

@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "colourful_portals:item/colourful_air_bottle/purple"
}
}

View File

@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "colourful_portals:item/colourful_air_bottle/red"
}
}

View File

@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "colourful_portals:item/colourful_air_bottle/white"
}
}

View File

@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "colourful_portals:item/colourful_air_bottle/yellow"
}
}

View File

@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "colourful_portals:item/colourful_pearl"
}
}

View File

@ -0,0 +1,12 @@
{
"textures": [
"colourful_portals:colourful_air_particle/black_colourful_air_0_0",
"colourful_portals:colourful_air_particle/black_colourful_air_0_1",
"colourful_portals:colourful_air_particle/black_colourful_air_1_0",
"colourful_portals:colourful_air_particle/black_colourful_air_1_1",
"colourful_portals:colourful_air_particle/black_colourful_air_2_0",
"colourful_portals:colourful_air_particle/black_colourful_air_2_1",
"colourful_portals:colourful_air_particle/black_colourful_air_3_0",
"colourful_portals:colourful_air_particle/black_colourful_air_3_1"
]
}

View File

@ -0,0 +1,12 @@
{
"textures": [
"colourful_portals:colourful_air_particle/blue_colourful_air_0_0",
"colourful_portals:colourful_air_particle/blue_colourful_air_0_1",
"colourful_portals:colourful_air_particle/blue_colourful_air_1_0",
"colourful_portals:colourful_air_particle/blue_colourful_air_1_1",
"colourful_portals:colourful_air_particle/blue_colourful_air_2_0",
"colourful_portals:colourful_air_particle/blue_colourful_air_2_1",
"colourful_portals:colourful_air_particle/blue_colourful_air_3_0",
"colourful_portals:colourful_air_particle/blue_colourful_air_3_1"
]
}

View File

@ -0,0 +1,12 @@
{
"textures": [
"colourful_portals:colourful_air_particle/brown_colourful_air_0_0",
"colourful_portals:colourful_air_particle/brown_colourful_air_0_1",
"colourful_portals:colourful_air_particle/brown_colourful_air_1_0",
"colourful_portals:colourful_air_particle/brown_colourful_air_1_1",
"colourful_portals:colourful_air_particle/brown_colourful_air_2_0",
"colourful_portals:colourful_air_particle/brown_colourful_air_2_1",
"colourful_portals:colourful_air_particle/brown_colourful_air_3_0",
"colourful_portals:colourful_air_particle/brown_colourful_air_3_1"
]
}

View File

@ -0,0 +1,132 @@
{
"textures": [
"black_colourful_air_0_0",
"black_colourful_air_0_1",
"black_colourful_air_1_0",
"black_colourful_air_1_1",
"black_colourful_air_2_0",
"black_colourful_air_2_1",
"black_colourful_air_3_0",
"black_colourful_air_3_1",
"blue_colourful_air_0_0",
"blue_colourful_air_0_1",
"blue_colourful_air_1_0",
"blue_colourful_air_1_1",
"blue_colourful_air_2_0",
"blue_colourful_air_2_1",
"blue_colourful_air_3_0",
"blue_colourful_air_3_1",
"brown_colourful_air_0_0",
"brown_colourful_air_0_1",
"brown_colourful_air_1_0",
"brown_colourful_air_1_1",
"brown_colourful_air_2_0",
"brown_colourful_air_2_1",
"brown_colourful_air_3_0",
"brown_colourful_air_3_1",
"cyan_colourful_air_0_0",
"cyan_colourful_air_0_1",
"cyan_colourful_air_1_0",
"cyan_colourful_air_1_1",
"cyan_colourful_air_2_0",
"cyan_colourful_air_2_1",
"cyan_colourful_air_3_0",
"cyan_colourful_air_3_1",
"green_colourful_air_0_0",
"green_colourful_air_0_1",
"green_colourful_air_1_0",
"green_colourful_air_1_1",
"green_colourful_air_2_0",
"green_colourful_air_2_1",
"green_colourful_air_3_0",
"green_colourful_air_3_1",
"grey_colourful_air_0_0",
"grey_colourful_air_0_1",
"grey_colourful_air_1_0",
"grey_colourful_air_1_1",
"grey_colourful_air_2_0",
"grey_colourful_air_2_1",
"grey_colourful_air_3_0",
"grey_colourful_air_3_1",
"light_blue_colourful_air_0_0",
"light_blue_colourful_air_0_1",
"light_blue_colourful_air_1_0",
"light_blue_colourful_air_1_1",
"light_blue_colourful_air_2_0",
"light_blue_colourful_air_2_1",
"light_blue_colourful_air_3_0",
"light_blue_colourful_air_3_1",
"light_grey_colourful_air_0_0",
"light_grey_colourful_air_0_1",
"light_grey_colourful_air_1_0",
"light_grey_colourful_air_1_1",
"light_grey_colourful_air_2_0",
"light_grey_colourful_air_2_1",
"light_grey_colourful_air_3_0",
"light_grey_colourful_air_3_1",
"lime_colourful_air_0_0",
"lime_colourful_air_0_1",
"lime_colourful_air_1_0",
"lime_colourful_air_1_1",
"lime_colourful_air_2_0",
"lime_colourful_air_2_1",
"lime_colourful_air_3_0",
"lime_colourful_air_3_1",
"magenta_colourful_air_0_0",
"magenta_colourful_air_0_1",
"magenta_colourful_air_1_0",
"magenta_colourful_air_1_1",
"magenta_colourful_air_2_0",
"magenta_colourful_air_2_1",
"magenta_colourful_air_3_0",
"magenta_colourful_air_3_1",
"orange_colourful_air_0_0",
"orange_colourful_air_0_1",
"orange_colourful_air_1_0",
"orange_colourful_air_1_1",
"orange_colourful_air_2_0",
"orange_colourful_air_2_1",
"orange_colourful_air_3_0",
"orange_colourful_air_3_1",
"pink_colourful_air_0_0",
"pink_colourful_air_0_1",
"pink_colourful_air_1_0",
"pink_colourful_air_1_1",
"pink_colourful_air_2_0",
"pink_colourful_air_2_1",
"pink_colourful_air_3_0",
"pink_colourful_air_3_1",
"purple_colourful_air_0_0",
"purple_colourful_air_0_1",
"purple_colourful_air_1_0",
"purple_colourful_air_1_1",
"purple_colourful_air_2_0",
"purple_colourful_air_2_1",
"purple_colourful_air_3_0",
"purple_colourful_air_3_1",
"red_colourful_air_0_0",
"red_colourful_air_0_1",
"red_colourful_air_1_0",
"red_colourful_air_1_1",
"red_colourful_air_2_0",
"red_colourful_air_2_1",
"red_colourful_air_3_0",
"red_colourful_air_3_1",
"white_colourful_air_0_0",
"white_colourful_air_0_1",
"white_colourful_air_1_0",
"white_colourful_air_1_1",
"white_colourful_air_2_0",
"white_colourful_air_2_1",
"white_colourful_air_3_0",
"white_colourful_air_3_1",
"yellow_colourful_air_0_0",
"yellow_colourful_air_0_1",
"yellow_colourful_air_1_0",
"yellow_colourful_air_1_1",
"yellow_colourful_air_2_0",
"yellow_colourful_air_2_1",
"yellow_colourful_air_3_0",
"yellow_colourful_air_3_1"
]
}

View File

@ -0,0 +1,12 @@
{
"textures": [
"colourful_portals:colourful_air_particle/cyan_colourful_air_0_0",
"colourful_portals:colourful_air_particle/cyan_colourful_air_0_1",
"colourful_portals:colourful_air_particle/cyan_colourful_air_1_0",
"colourful_portals:colourful_air_particle/cyan_colourful_air_1_1",
"colourful_portals:colourful_air_particle/cyan_colourful_air_2_0",
"colourful_portals:colourful_air_particle/cyan_colourful_air_2_1",
"colourful_portals:colourful_air_particle/cyan_colourful_air_3_0",
"colourful_portals:colourful_air_particle/cyan_colourful_air_3_1"
]
}

View File

@ -0,0 +1,12 @@
{
"textures": [
"colourful_portals:colourful_air_particle/grey_colourful_air_0_0",
"colourful_portals:colourful_air_particle/grey_colourful_air_0_1",
"colourful_portals:colourful_air_particle/grey_colourful_air_1_0",
"colourful_portals:colourful_air_particle/grey_colourful_air_1_1",
"colourful_portals:colourful_air_particle/grey_colourful_air_2_0",
"colourful_portals:colourful_air_particle/grey_colourful_air_2_1",
"colourful_portals:colourful_air_particle/grey_colourful_air_3_0",
"colourful_portals:colourful_air_particle/grey_colourful_air_3_1"
]
}

View File

@ -0,0 +1,12 @@
{
"textures": [
"colourful_portals:colourful_air_particle/green_colourful_air_0_0",
"colourful_portals:colourful_air_particle/green_colourful_air_0_1",
"colourful_portals:colourful_air_particle/green_colourful_air_1_0",
"colourful_portals:colourful_air_particle/green_colourful_air_1_1",
"colourful_portals:colourful_air_particle/green_colourful_air_2_0",
"colourful_portals:colourful_air_particle/green_colourful_air_2_1",
"colourful_portals:colourful_air_particle/green_colourful_air_3_0",
"colourful_portals:colourful_air_particle/green_colourful_air_3_1"
]
}

View File

@ -0,0 +1,12 @@
{
"textures": [
"colourful_portals:colourful_air_particle/light_blue_colourful_air_0_0",
"colourful_portals:colourful_air_particle/light_blue_colourful_air_0_1",
"colourful_portals:colourful_air_particle/light_blue_colourful_air_1_0",
"colourful_portals:colourful_air_particle/light_blue_colourful_air_1_1",
"colourful_portals:colourful_air_particle/light_blue_colourful_air_2_0",
"colourful_portals:colourful_air_particle/light_blue_colourful_air_2_1",
"colourful_portals:colourful_air_particle/light_blue_colourful_air_3_0",
"colourful_portals:colourful_air_particle/light_blue_colourful_air_3_1"
]
}

View File

@ -0,0 +1,12 @@
{
"textures": [
"colourful_portals:colourful_air_particle/light_grey_colourful_air_0_0",
"colourful_portals:colourful_air_particle/light_grey_colourful_air_0_1",
"colourful_portals:colourful_air_particle/light_grey_colourful_air_1_0",
"colourful_portals:colourful_air_particle/light_grey_colourful_air_1_1",
"colourful_portals:colourful_air_particle/light_grey_colourful_air_2_0",
"colourful_portals:colourful_air_particle/light_grey_colourful_air_2_1",
"colourful_portals:colourful_air_particle/light_grey_colourful_air_3_0",
"colourful_portals:colourful_air_particle/light_grey_colourful_air_3_1"
]
}

View File

@ -0,0 +1,12 @@
{
"textures": [
"colourful_portals:colourful_air_particle/lime_colourful_air_0_0",
"colourful_portals:colourful_air_particle/lime_colourful_air_0_1",
"colourful_portals:colourful_air_particle/lime_colourful_air_1_0",
"colourful_portals:colourful_air_particle/lime_colourful_air_1_1",
"colourful_portals:colourful_air_particle/lime_colourful_air_2_0",
"colourful_portals:colourful_air_particle/lime_colourful_air_2_1",
"colourful_portals:colourful_air_particle/lime_colourful_air_3_0",
"colourful_portals:colourful_air_particle/lime_colourful_air_3_1"
]
}

View File

@ -0,0 +1,12 @@
{
"textures": [
"colourful_portals:colourful_air_particle/magenta_colourful_air_0_0",
"colourful_portals:colourful_air_particle/magenta_colourful_air_0_1",
"colourful_portals:colourful_air_particle/magenta_colourful_air_1_0",
"colourful_portals:colourful_air_particle/magenta_colourful_air_1_1",
"colourful_portals:colourful_air_particle/magenta_colourful_air_2_0",
"colourful_portals:colourful_air_particle/magenta_colourful_air_2_1",
"colourful_portals:colourful_air_particle/magenta_colourful_air_3_0",
"colourful_portals:colourful_air_particle/magenta_colourful_air_3_1"
]
}

View File

@ -0,0 +1,12 @@
{
"textures": [
"colourful_portals:colourful_air_particle/orange_colourful_air_0_0",
"colourful_portals:colourful_air_particle/orange_colourful_air_0_1",
"colourful_portals:colourful_air_particle/orange_colourful_air_1_0",
"colourful_portals:colourful_air_particle/orange_colourful_air_1_1",
"colourful_portals:colourful_air_particle/orange_colourful_air_2_0",
"colourful_portals:colourful_air_particle/orange_colourful_air_2_1",
"colourful_portals:colourful_air_particle/orange_colourful_air_3_0",
"colourful_portals:colourful_air_particle/orange_colourful_air_3_1"
]
}

View File

@ -0,0 +1,12 @@
{
"textures": [
"colourful_portals:colourful_air_particle/pink_colourful_air_0_0",
"colourful_portals:colourful_air_particle/pink_colourful_air_0_1",
"colourful_portals:colourful_air_particle/pink_colourful_air_1_0",
"colourful_portals:colourful_air_particle/pink_colourful_air_1_1",
"colourful_portals:colourful_air_particle/pink_colourful_air_2_0",
"colourful_portals:colourful_air_particle/pink_colourful_air_2_1",
"colourful_portals:colourful_air_particle/pink_colourful_air_3_0",
"colourful_portals:colourful_air_particle/pink_colourful_air_3_1"
]
}

View File

@ -0,0 +1,12 @@
{
"textures": [
"colourful_portals:colourful_air_particle/purple_colourful_air_0_0",
"colourful_portals:colourful_air_particle/purple_colourful_air_0_1",
"colourful_portals:colourful_air_particle/purple_colourful_air_1_0",
"colourful_portals:colourful_air_particle/purple_colourful_air_1_1",
"colourful_portals:colourful_air_particle/purple_colourful_air_2_0",
"colourful_portals:colourful_air_particle/purple_colourful_air_2_1",
"colourful_portals:colourful_air_particle/purple_colourful_air_3_0",
"colourful_portals:colourful_air_particle/purple_colourful_air_3_1"
]
}

View File

@ -0,0 +1,12 @@
{
"textures": [
"colourful_portals:colourful_air_particle/red_colourful_air_0_0",
"colourful_portals:colourful_air_particle/red_colourful_air_0_1",
"colourful_portals:colourful_air_particle/red_colourful_air_1_0",
"colourful_portals:colourful_air_particle/red_colourful_air_1_1",
"colourful_portals:colourful_air_particle/red_colourful_air_2_0",
"colourful_portals:colourful_air_particle/red_colourful_air_2_1",
"colourful_portals:colourful_air_particle/red_colourful_air_3_0",
"colourful_portals:colourful_air_particle/red_colourful_air_3_1"
]
}

View File

@ -0,0 +1,12 @@
{
"textures": [
"colourful_portals:colourful_air_particle/white_colourful_air_0_0",
"colourful_portals:colourful_air_particle/white_colourful_air_0_1",
"colourful_portals:colourful_air_particle/white_colourful_air_1_0",
"colourful_portals:colourful_air_particle/white_colourful_air_1_1",
"colourful_portals:colourful_air_particle/white_colourful_air_2_0",
"colourful_portals:colourful_air_particle/white_colourful_air_2_1",
"colourful_portals:colourful_air_particle/white_colourful_air_3_0",
"colourful_portals:colourful_air_particle/white_colourful_air_3_1"
]
}

View File

@ -0,0 +1,12 @@
{
"textures": [
"colourful_portals:colourful_air_particle/yellow_colourful_air_0_0",
"colourful_portals:colourful_air_particle/yellow_colourful_air_0_1",
"colourful_portals:colourful_air_particle/yellow_colourful_air_1_0",
"colourful_portals:colourful_air_particle/yellow_colourful_air_1_1",
"colourful_portals:colourful_air_particle/yellow_colourful_air_2_0",
"colourful_portals:colourful_air_particle/yellow_colourful_air_2_1",
"colourful_portals:colourful_air_particle/yellow_colourful_air_3_0",
"colourful_portals:colourful_air_particle/yellow_colourful_air_3_1"
]
}

View File

@ -0,0 +1,11 @@
{
"entity.colourful_pearl.teleport_away": {
"subtitle": "subtitles.colourful_portals.entity.colourful_pearl.teleport_away",
"sounds": [
{
"name": "colourful_portals:teleport_away",
"attenuation_distance": 64
}
]
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 572 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 373 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 365 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 365 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 353 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 357 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 353 B

Some files were not shown because too many files have changed in this diff Show More