Compare commits
5 Commits
4ee1a066ac
...
a9ce715750
Author | SHA1 | Date | |
---|---|---|---|
a9ce715750 | |||
7aefd13755 | |||
562a16c4f8 | |||
b4582640b7 | |||
01ba9ca366 |
|
@ -1,3 +1,3 @@
|
||||||
# Colourful Portals Reimagined
|
# 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
|
22
build.gradle
|
@ -1,6 +1,6 @@
|
||||||
plugins {
|
plugins {
|
||||||
id "com.modrinth.minotaur" version "2.+"
|
id "com.modrinth.minotaur" version "2.+"
|
||||||
id 'fabric-loom' version '1.6-SNAPSHOT'
|
id 'fabric-loom' version '1.7-SNAPSHOT'
|
||||||
id 'maven-publish'
|
id 'maven-publish'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,10 +17,6 @@ repositories {
|
||||||
// Loom adds the essential maven repositories to download Minecraft and libraries from automatically.
|
// Loom adds the essential maven repositories to download Minecraft and libraries from automatically.
|
||||||
// See https://docs.gradle.org/current/userguide/declaring_repositories.html
|
// See https://docs.gradle.org/current/userguide/declaring_repositories.html
|
||||||
// for more information about repositories.
|
// for more information about repositories.
|
||||||
maven {
|
|
||||||
name = 'Ladysnake Mods'
|
|
||||||
url = 'https://ladysnake.jfrog.io/artifactory/mods'
|
|
||||||
}
|
|
||||||
maven {
|
maven {
|
||||||
name = "Ladysnake Mods"
|
name = "Ladysnake Mods"
|
||||||
url = 'https://maven.ladysnake.org/releases'
|
url = 'https://maven.ladysnake.org/releases'
|
||||||
|
@ -54,7 +50,7 @@ dependencies {
|
||||||
|
|
||||||
// modImplementation "net.fabricmc.fabric-api:fabric-api-deprecated:${project.fabric_version}"
|
// modImplementation "net.fabricmc.fabric-api:fabric-api-deprecated:${project.fabric_version}"
|
||||||
|
|
||||||
modCompileOnly ("com.github.iPortalTeam:ImmersivePortalsMod:${project.immersive_portals_version}")
|
modImplementation ("com.github.iPortalTeam:ImmersivePortalsMod:${project.immersive_portals_version}")
|
||||||
|
|
||||||
// Replace modImplementation with modApi if you expose components in your own API
|
// Replace modImplementation with modApi if you expose components in your own API
|
||||||
modImplementation "org.ladysnake.cardinal-components-api:cardinal-components-base:${project.cca_version}"
|
modImplementation "org.ladysnake.cardinal-components-api:cardinal-components-base:${project.cca_version}"
|
||||||
|
@ -66,21 +62,11 @@ dependencies {
|
||||||
// Includes Cardinal Components API as a Jar-in-Jar dependency (optional but recommended)
|
// Includes Cardinal Components API as a Jar-in-Jar dependency (optional but recommended)
|
||||||
include "org.ladysnake.cardinal-components-api:cardinal-components-level:${project.cca_version}"
|
include "org.ladysnake.cardinal-components-api:cardinal-components-level:${project.cca_version}"
|
||||||
|
|
||||||
//include(modApi(platform("de.siphalor.tweed4:tweed4-bom-$project.minecraft_version_major:$project.tweed_version")))
|
//Config lib
|
||||||
// Pick any modules you want to use, e.g.:
|
|
||||||
//include(modApi("de.siphalor.tweed4:tweed4-base-$project.minecraft_version_major"))
|
|
||||||
//include(modApi("de.siphalor.tweed4:tweed4-annotated-$project.minecraft_version_major"))
|
|
||||||
//include(modApi("de.siphalor.tweed4:tweed4-data-$project.minecraft_version_major"))
|
|
||||||
//include(modApi("de.siphalor.tweed4:tweed4-data-hjson-$project.minecraft_version_major"))
|
|
||||||
//include(modApi("de.siphalor.tweed4:tweed4-tailor-cloth-$project.minecraft_version_major"))
|
|
||||||
//include(modApi("de.siphalor.tweed4:tweed4-tailor-screen-$project.minecraft_version_major"))
|
|
||||||
|
|
||||||
modImplementation "maven.modrinth:midnightlib:${project.midnightlib_version}"
|
modImplementation "maven.modrinth:midnightlib:${project.midnightlib_version}"
|
||||||
include "maven.modrinth:midnightlib:${project.midnightlib_version}"
|
include "maven.modrinth:midnightlib:${project.midnightlib_version}"
|
||||||
|
|
||||||
modImplementation("me.shedaniel.cloth:cloth-config-fabric:$project.cloth_config_version")
|
modImplementation("maven.modrinth:sodium:${project.sodium_version}")
|
||||||
|
|
||||||
modCompileOnly("maven.modrinth:sodium:${project.sodium_version}")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
loom {
|
loom {
|
||||||
|
|
|
@ -4,22 +4,20 @@ org.gradle.parallel=true
|
||||||
|
|
||||||
# Fabric Properties
|
# Fabric Properties
|
||||||
# check these on https://fabricmc.net/develop
|
# check these on https://fabricmc.net/develop
|
||||||
minecraft_version=1.21
|
minecraft_version=1.21.1
|
||||||
minecraft_version_major=1.21
|
minecraft_version_major=1.21
|
||||||
yarn_mappings=1.21+build.2
|
yarn_mappings=1.21.1+build.3
|
||||||
loader_version=0.15.11
|
loader_version=0.16.7
|
||||||
|
|
||||||
# Mod Properties
|
# Mod Properties
|
||||||
mod_version=0.9.5.2
|
mod_version=0.9.7
|
||||||
maven_group=quimufu.colourful-portalRepresentations
|
maven_group=quimufu.colourful-portals
|
||||||
archives_base_name=colourful-portalRepresentations
|
archives_base_name=colourful-portals
|
||||||
|
|
||||||
# Dependencies
|
# Dependencies
|
||||||
fabric_version=0.100.1+1.21
|
fabric_version=0.105.0+1.21.1
|
||||||
cca_version = 6.1.0
|
cca_version = 6.1.1
|
||||||
immersive_portals_version_short=5.1.7
|
immersive_portals_version_short=6.0.3
|
||||||
immersive_portals_version=v5.1.7-mc1.20.4
|
immersive_portals_version=v6.0.3-mc1.21.1
|
||||||
tweed_version=1.3.0+mc1.20.2
|
sodium_version=mc1.21-0.5.11
|
||||||
sodium_version=mc1.21-0.5.9
|
midnightlib_version=1.6.3-fabric
|
||||||
cloth_config_version=15.0.127
|
|
||||||
midnightlib_version=1.5.7-fabric
|
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
5
gradle/wrapper/gradle-wrapper.properties
vendored
|
@ -1,6 +1,7 @@
|
||||||
#Sun Jun 16 00:12:45 CEST 2024
|
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
|
||||||
|
networkTimeout=10000
|
||||||
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
|
24
gradlew
vendored
|
@ -55,7 +55,7 @@
|
||||||
# Darwin, MinGW, and NonStop.
|
# Darwin, MinGW, and NonStop.
|
||||||
#
|
#
|
||||||
# (3) This script is generated from the Groovy template
|
# (3) This script is generated from the Groovy template
|
||||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||||
# within the Gradle project.
|
# within the Gradle project.
|
||||||
#
|
#
|
||||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||||
|
@ -83,7 +83,8 @@ done
|
||||||
# This is normally unused
|
# This is normally unused
|
||||||
# shellcheck disable=SC2034
|
# shellcheck disable=SC2034
|
||||||
APP_BASE_NAME=${0##*/}
|
APP_BASE_NAME=${0##*/}
|
||||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||||
|
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
|
||||||
|
|
||||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
MAX_FD=maximum
|
MAX_FD=maximum
|
||||||
|
@ -130,18 +131,21 @@ location of your Java installation."
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
JAVACMD=java
|
JAVACMD=java
|
||||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
if ! command -v java >/dev/null 2>&1
|
||||||
|
then
|
||||||
|
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
|
||||||
Please set the JAVA_HOME variable in your environment to match the
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
location of your Java installation."
|
location of your Java installation."
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
# Increase the maximum file descriptors if we can.
|
# Increase the maximum file descriptors if we can.
|
||||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||||
case $MAX_FD in #(
|
case $MAX_FD in #(
|
||||||
max*)
|
max*)
|
||||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||||
# shellcheck disable=SC3045
|
# shellcheck disable=SC2039,SC3045
|
||||||
MAX_FD=$( ulimit -H -n ) ||
|
MAX_FD=$( ulimit -H -n ) ||
|
||||||
warn "Could not query maximum file descriptor limit"
|
warn "Could not query maximum file descriptor limit"
|
||||||
esac
|
esac
|
||||||
|
@ -149,7 +153,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||||
'' | soft) :;; #(
|
'' | soft) :;; #(
|
||||||
*)
|
*)
|
||||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||||
# shellcheck disable=SC3045
|
# shellcheck disable=SC2039,SC3045
|
||||||
ulimit -n "$MAX_FD" ||
|
ulimit -n "$MAX_FD" ||
|
||||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||||
esac
|
esac
|
||||||
|
@ -198,11 +202,11 @@ fi
|
||||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||||
|
|
||||||
# Collect all arguments for the java command;
|
# Collect all arguments for the java command:
|
||||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||||
# shell script including quotes and variable substitutions, so put them in
|
# and any embedded shellness will be escaped.
|
||||||
# double quotes to make sure that they get re-expanded; and
|
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||||
# * put everything else in single quotes, so that it's not re-expanded.
|
# treated as '${Hostname}' itself on the command line.
|
||||||
|
|
||||||
set -- \
|
set -- \
|
||||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||||
|
|
20
gradlew.bat
vendored
|
@ -43,11 +43,11 @@ set JAVA_EXE=java.exe
|
||||||
%JAVA_EXE% -version >NUL 2>&1
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
if %ERRORLEVEL% equ 0 goto execute
|
if %ERRORLEVEL% equ 0 goto execute
|
||||||
|
|
||||||
echo.
|
echo. 1>&2
|
||||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||||
echo.
|
echo. 1>&2
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the
|
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||||
echo location of your Java installation.
|
echo location of your Java installation. 1>&2
|
||||||
|
|
||||||
goto fail
|
goto fail
|
||||||
|
|
||||||
|
@ -57,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||||
|
|
||||||
if exist "%JAVA_EXE%" goto execute
|
if exist "%JAVA_EXE%" goto execute
|
||||||
|
|
||||||
echo.
|
echo. 1>&2
|
||||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||||
echo.
|
echo. 1>&2
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the
|
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||||
echo location of your Java installation.
|
echo location of your Java installation. 1>&2
|
||||||
|
|
||||||
goto fail
|
goto fail
|
||||||
|
|
||||||
|
|
153
src/main/java/quimufu/colourful_portals/ColourfulAirBlock.java
Normal 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(org.joml.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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,16 +6,25 @@ import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
|
||||||
import net.fabricmc.fabric.api.event.registry.FabricRegistryBuilder;
|
import net.fabricmc.fabric.api.event.registry.FabricRegistryBuilder;
|
||||||
import net.fabricmc.fabric.api.itemgroup.v1.FabricItemGroupEntries;
|
import net.fabricmc.fabric.api.itemgroup.v1.FabricItemGroupEntries;
|
||||||
import net.fabricmc.fabric.api.itemgroup.v1.ItemGroupEvents;
|
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.AbstractBlock;
|
||||||
|
import net.minecraft.block.Block;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.block.enums.NoteBlockInstrument;
|
import net.minecraft.block.enums.NoteBlockInstrument;
|
||||||
|
import net.minecraft.component.DataComponentTypes;
|
||||||
import net.minecraft.entity.EntityType;
|
import net.minecraft.entity.EntityType;
|
||||||
|
import net.minecraft.entity.SpawnGroup;
|
||||||
import net.minecraft.item.*;
|
import net.minecraft.item.*;
|
||||||
|
import net.minecraft.particle.SimpleParticleType;
|
||||||
import net.minecraft.registry.Registries;
|
import net.minecraft.registry.Registries;
|
||||||
import net.minecraft.registry.Registry;
|
import net.minecraft.registry.Registry;
|
||||||
import net.minecraft.registry.RegistryKey;
|
import net.minecraft.registry.RegistryKey;
|
||||||
|
import net.minecraft.registry.RegistryKeys;
|
||||||
|
import net.minecraft.registry.tag.TagKey;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.sound.BlockSoundGroup;
|
import net.minecraft.sound.BlockSoundGroup;
|
||||||
|
import net.minecraft.sound.SoundEvent;
|
||||||
|
import net.minecraft.util.DyeColor;
|
||||||
import net.minecraft.util.Identifier;
|
import net.minecraft.util.Identifier;
|
||||||
import net.minecraft.util.Rarity;
|
import net.minecraft.util.Rarity;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
@ -23,13 +32,16 @@ import net.minecraft.world.BlockView;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import quimufu.colourful_portals.config.ColourfulPortalConfig;
|
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.*;
|
||||||
import quimufu.colourful_portals.portal_fluid.PortalFluid;
|
import quimufu.colourful_portals.portal_fluid.PortalFluid;
|
||||||
import quimufu.colourful_portals.portal_fluid.PortalFluidBlock;
|
import quimufu.colourful_portals.portal_fluid.PortalFluidBlock;
|
||||||
import quimufu.colourful_portals.portal_fluid.PortalFluidBucketItem;
|
import quimufu.colourful_portals.portal_fluid.PortalFluidBucketItem;
|
||||||
|
|
||||||
import java.util.Comparator;
|
import java.util.*;
|
||||||
import java.util.HashSet;
|
|
||||||
|
|
||||||
import static quimufu.colourful_portals.Components.PORTAL_CANDIDATE_LIST;
|
import static quimufu.colourful_portals.Components.PORTAL_CANDIDATE_LIST;
|
||||||
import static quimufu.colourful_portals.Components.PORTAL_LIST;
|
import static quimufu.colourful_portals.Components.PORTAL_LIST;
|
||||||
|
@ -38,17 +50,42 @@ public class ColourfulPortalsMod implements ModInitializer {
|
||||||
|
|
||||||
public static final String MOD_ID = "colourful_portals";
|
public static final String MOD_ID = "colourful_portals";
|
||||||
public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID);
|
public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID);
|
||||||
|
|
||||||
public static final HashSet<Identifier> PORTAL_BLOCKS = new HashSet<>();
|
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 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_DARK = new Item(new Item.Settings());
|
||||||
public static final Item BLOB_BRIGHT = 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 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 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 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 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();
|
public static final Registry<PrioritizedPortalLinkingSystemBuilder> PORTAL_LINKING_SYSTEM_BUILDER_REGISTRY = FabricRegistryBuilder.createSimple(PORTAL_LINKING_SYSTEM_BUILDER_REGISTRY_KEY).buildAndRegister();
|
||||||
|
|
||||||
|
@ -65,21 +102,31 @@ public class ColourfulPortalsMod implements ModInitializer {
|
||||||
public void onInitialize() {
|
public void onInitialize() {
|
||||||
LOGGER.info("Colouring Portals...");
|
LOGGER.info("Colouring Portals...");
|
||||||
MidnightConfig.init(MOD_ID, ColourfulPortalConfig.class);
|
MidnightConfig.init(MOD_ID, ColourfulPortalConfig.class);
|
||||||
|
ColourfulPortalConfig.registerListener(this::onConfigUpdate);
|
||||||
|
|
||||||
for (String id : ColourfulPortalConfig.getAllPortalBlocks()) {
|
onConfigUpdate();
|
||||||
LOGGER.info(id);
|
if (hasImmPtl()) {
|
||||||
PORTAL_BLOCKS.add(Identifier.tryParse(id));
|
Registry.register(PORTAL_LINKING_SYSTEM_BUILDER_REGISTRY, ImmersivePortalsLinkingSystem.IMMERSIVE_PORTALS_LINKING_SYSTEM, new PrioritizedPortalLinkingSystemBuilder(ImmersivePortalsLinkingSystem::new, () -> ColourfulPortalConfig.disableImmersivePortals ? -1 : 100));
|
||||||
}
|
}
|
||||||
if (!ColourfulPortalConfig.disableImmersivePortals && hasImmPtl()) {
|
for (Map.Entry<DyeColor, SimpleParticleType> entry : COLOURFUL_AIR_PARTICLE_BY_COLOUR.entrySet()) {
|
||||||
Registry.register(PORTAL_LINKING_SYSTEM_BUILDER_REGISTRY, ImmersivePortalsLinkingSystem.IMMERSIVE_PORTALS_LINKING_SYSTEM, new PrioritizedPortalLinkingSystemBuilder(ImmersivePortalsLinkingSystem::new, 100));
|
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));
|
|
||||||
|
Registry.register(PORTAL_LINKING_SYSTEM_BUILDER_REGISTRY, DefaultLinkingSystem.DEFAULT_LINKING_SYSTEM, new PrioritizedPortalLinkingSystemBuilder(DefaultLinkingSystem::new, () -> 90));
|
||||||
|
|
||||||
Identifier identifier = Identifier.of(MOD_ID, "portal_block");
|
Identifier identifier = Identifier.of(MOD_ID, "portal_block");
|
||||||
|
|
||||||
Registry.register(Registries.BLOCK, identifier, PORTAL_BLOCK);
|
Registry.register(Registries.BLOCK, identifier, PORTAL_BLOCK);
|
||||||
Registry.register(Registries.ITEM, identifier, PORTAL_BLOCK_ITEM);
|
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.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.FLUID, Identifier.of(MOD_ID, "portal_fluid"), PORTAL_FLUID);
|
||||||
Registry.register(Registries.BLOCK, Identifier.of(MOD_ID, "portal_fluid_block"), PORTAL_FLUID_BLOCk);
|
Registry.register(Registries.BLOCK, Identifier.of(MOD_ID, "portal_fluid_block"), PORTAL_FLUID_BLOCk);
|
||||||
|
@ -97,6 +144,18 @@ public class ColourfulPortalsMod implements ModInitializer {
|
||||||
LOGGER.info("Portals Colourful!");
|
LOGGER.info("Portals Colourful!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void onConfigUpdate() {
|
||||||
|
PORTAL_BLOCKS.clear();
|
||||||
|
for (String id : ColourfulPortalConfig.getAllPortalBlocks()) {
|
||||||
|
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() {
|
private boolean hasImmPtl() {
|
||||||
try {
|
try {
|
||||||
Class.forName("qouteall.imm_ptl.core.IPModMain", false, this.getClass().getClassLoader());
|
Class.forName("qouteall.imm_ptl.core.IPModMain", false, this.getClass().getClassLoader());
|
||||||
|
@ -112,7 +171,7 @@ public class ColourfulPortalsMod implements ModInitializer {
|
||||||
PortalListComponent portalList = PORTAL_LIST.get(minecraftServer.getSaveProperties().getMainWorldProperties());
|
PortalListComponent portalList = PORTAL_LIST.get(minecraftServer.getSaveProperties().getMainWorldProperties());
|
||||||
|
|
||||||
PortalLinkingSystem currentLinkingSystem = getCurrentlyConfiguredLinkingSystem(minecraftServer);
|
PortalLinkingSystem currentLinkingSystem = getCurrentlyConfiguredLinkingSystem(minecraftServer);
|
||||||
if (currentLinkingSystem.getLinkingSystemId() != portalList.lastPortalLinkingSystemId() || currentLinkingSystem.needsReInit()) {
|
if (!Objects.equals(currentLinkingSystem.getLinkingSystemId(), portalList.lastPortalLinkingSystemId()) || currentLinkingSystem.needsReInit()) {
|
||||||
PrioritizedPortalLinkingSystemBuilder prevSystem;
|
PrioritizedPortalLinkingSystemBuilder prevSystem;
|
||||||
if ((prevSystem = PORTAL_LINKING_SYSTEM_BUILDER_REGISTRY.get(portalList.lastPortalLinkingSystemId())) != null) {
|
if ((prevSystem = PORTAL_LINKING_SYSTEM_BUILDER_REGISTRY.get(portalList.lastPortalLinkingSystemId())) != null) {
|
||||||
PortalLinkingSystem prevLS = prevSystem.portalLinkingSystemBuilder().build(minecraftServer);
|
PortalLinkingSystem prevLS = prevSystem.portalLinkingSystemBuilder().build(minecraftServer);
|
||||||
|
@ -133,7 +192,8 @@ public class ColourfulPortalsMod implements ModInitializer {
|
||||||
private PortalLinkingSystem getCurrentlyConfiguredLinkingSystem(MinecraftServer minecraftServer) {
|
private PortalLinkingSystem getCurrentlyConfiguredLinkingSystem(MinecraftServer minecraftServer) {
|
||||||
return PORTAL_LINKING_SYSTEM_BUILDER_REGISTRY
|
return PORTAL_LINKING_SYSTEM_BUILDER_REGISTRY
|
||||||
.stream()
|
.stream()
|
||||||
.min(Comparator.comparing(PrioritizedPortalLinkingSystemBuilder::priority))
|
.filter(prio -> prio.priority().getAsInt() >= 0)
|
||||||
|
.max(Comparator.comparing(prio -> prio.priority().getAsInt()))
|
||||||
.map(PrioritizedPortalLinkingSystemBuilder::portalLinkingSystemBuilder)
|
.map(PrioritizedPortalLinkingSystemBuilder::portalLinkingSystemBuilder)
|
||||||
.orElse(DefaultLinkingSystem::new)
|
.orElse(DefaultLinkingSystem::new)
|
||||||
.build(minecraftServer);
|
.build(minecraftServer);
|
||||||
|
|
|
@ -1,16 +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.PortalFluidRenderHandler;
|
|
||||||
|
|
||||||
public class ColourfulPortalsModClient implements ClientModInitializer {
|
|
||||||
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());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -15,8 +15,8 @@ public class Components implements LevelComponentInitializer {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void registerLevelComponentFactories(LevelComponentFactoryRegistry registry) {
|
public void registerLevelComponentFactories(LevelComponentFactoryRegistry registry) {
|
||||||
registry.register(PORTAL_LIST, PortalListComponent::new);
|
registry.register(PORTAL_LIST, worldProperties1 -> new PortalListComponent());
|
||||||
registry.register(PORTAL_CANDIDATE_LIST, PortalListComponent::new);
|
registry.register(PORTAL_CANDIDATE_LIST, worldProperties -> new PortalListComponent());
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ public class MixinConfig implements IMixinConfigPlugin {
|
||||||
private static final Supplier<Boolean> TRUE = () -> true;
|
private static final Supplier<Boolean> TRUE = () -> true;
|
||||||
|
|
||||||
private static final Map<String, Supplier<Boolean>> CONDITIONS = Map.of(
|
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
|
@Override
|
||||||
|
|
|
@ -4,7 +4,6 @@ import net.minecraft.block.Block;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.block.FluidFillable;
|
import net.minecraft.block.FluidFillable;
|
||||||
import net.minecraft.block.ShapeContext;
|
import net.minecraft.block.ShapeContext;
|
||||||
import net.minecraft.entity.Entity;
|
|
||||||
import net.minecraft.entity.player.PlayerEntity;
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
import net.minecraft.fluid.Fluid;
|
import net.minecraft.fluid.Fluid;
|
||||||
import net.minecraft.fluid.FluidState;
|
import net.minecraft.fluid.FluidState;
|
||||||
|
@ -23,7 +22,6 @@ import net.minecraft.world.BlockView;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
import net.minecraft.world.WorldAccess;
|
import net.minecraft.world.WorldAccess;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import quimufu.colourful_portals.util.CollisionAwareShapeContext;
|
|
||||||
|
|
||||||
import static quimufu.colourful_portals.ColourfulPortalsMod.PORTAL_MANAGER;
|
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)
|
if (shapeContext.isHolding(Items.DEBUG_STICK)
|
||||||
|| shapeContext.isHolding(ColourfulPortalsMod.PORTAL_BLOCK_ITEM)
|
|| shapeContext.isHolding(ColourfulPortalsMod.PORTAL_BLOCK_ITEM)
|
||||||
|| shapeContext.isHolding(ColourfulPortalsMod.PORTAL_FLUID_BUCKET_ITEM)) {
|
|| shapeContext.isHolding(ColourfulPortalsMod.PORTAL_FLUID_BUCKET_ITEM)) {
|
||||||
|
return getShape(state);
|
||||||
|
}
|
||||||
|
return VoxelShapes.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public VoxelShape getShape(BlockState state) {
|
||||||
return switch (state.get(AXIS)) {
|
return switch (state.get(AXIS)) {
|
||||||
case Z -> Z_AABB;
|
case Z -> Z_AABB;
|
||||||
case Y -> Y_AABB;
|
case Y -> Y_AABB;
|
||||||
default -> X_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
|
@Override
|
||||||
public BlockState rotate(BlockState state, BlockRotation rotation) {
|
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) {
|
public BlockState getStateWith(DyeColor color, Direction.Axis axis) {
|
||||||
return this.getDefaultState().with(AXIS, axis).with(DYE_COLOR, color);
|
return this.getDefaultState().with(AXIS, axis).with(DYE_COLOR, color);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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.Animator;
|
||||||
import net.minecraft.client.texture.SpriteContents;
|
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.Inject;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
import quimufu.colourful_portals.client.AlphaBlendingAnimator;
|
import quimufu.colourful_portals.client.rendering.AlphaBlendingAnimator;
|
||||||
import quimufu.colourful_portals.client.AlphaInterpolationHolder;
|
import quimufu.colourful_portals.client.rendering.AlphaInterpolationHolder;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
package quimufu.colourful_portals.mixin.client;
|
package quimufu.colourful_portals.client.mixin;
|
||||||
|
|
||||||
import net.minecraft.client.resource.metadata.AnimationResourceMetadata;
|
import net.minecraft.client.resource.metadata.AnimationResourceMetadata;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.Unique;
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
import quimufu.colourful_portals.client.AlphaInterpolationHolder;
|
import quimufu.colourful_portals.client.rendering.AlphaInterpolationHolder;
|
||||||
|
|
||||||
@Mixin(AnimationResourceMetadata.class)
|
@Mixin(AnimationResourceMetadata.class)
|
||||||
public class AnimationResourceMetadataMixin implements AlphaInterpolationHolder {
|
public class AnimationResourceMetadataMixin implements AlphaInterpolationHolder {
|
|
@ -1,4 +1,4 @@
|
||||||
package quimufu.colourful_portals.mixin.client;
|
package quimufu.colourful_portals.client.mixin;
|
||||||
|
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import net.minecraft.client.resource.metadata.AnimationResourceMetadata;
|
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.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
import quimufu.colourful_portals.client.AlphaInterpolationHolder;
|
import quimufu.colourful_portals.client.rendering.AlphaInterpolationHolder;
|
||||||
|
|
||||||
@Mixin(AnimationResourceMetadataReader.class)
|
@Mixin(AnimationResourceMetadataReader.class)
|
||||||
public class AnimationResourceMetadataReaderMixin {
|
public class AnimationResourceMetadataReaderMixin {
|
|
@ -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);
|
||||||
|
}
|
|
@ -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.ChunkBuildBuffers;
|
||||||
import me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline.FluidRenderer;
|
import me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline.FluidRenderer;
|
||||||
|
@ -6,22 +6,24 @@ import me.jellysquid.mods.sodium.client.world.WorldSlice;
|
||||||
import net.minecraft.fluid.FluidState;
|
import net.minecraft.fluid.FluidState;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
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;
|
import static quimufu.colourful_portals.ColourfulPortalsMod.PORTAL_FLUID;
|
||||||
|
|
||||||
@Mixin(FluidRenderer.class)
|
@Mixin(FluidRenderer.class)
|
||||||
public class SodiumFluidRendererMixin {
|
public class SodiumFluidRendererMixin {
|
||||||
|
|
||||||
private final SodiumPortalFluidRenderHandler sodiumPortalFluidRenderHandler = new SodiumPortalFluidRenderHandler();
|
@Unique
|
||||||
|
private final ThreadLocal<SodiumPortalFluidRenderHandler> sodiumPortalFluidRenderHandler = ThreadLocal.withInitial(SodiumPortalFluidRenderHandler::new);
|
||||||
|
|
||||||
@Inject(at = @At("HEAD"), method = "render", cancellable = true, remap = false)
|
@Inject(at = @At("HEAD"), method = "render", cancellable = true, remap = false)
|
||||||
private void init(WorldSlice world, FluidState fluidState, BlockPos blockPos, BlockPos offset, ChunkBuildBuffers buffers, CallbackInfo ci) {
|
private void init(WorldSlice world, FluidState fluidState, BlockPos blockPos, BlockPos offset, ChunkBuildBuffers buffers, CallbackInfo ci) {
|
||||||
if (fluidState.isOf(PORTAL_FLUID)) {
|
if (fluidState.isOf(PORTAL_FLUID)) {
|
||||||
sodiumPortalFluidRenderHandler.render(world, fluidState, blockPos, offset, buffers);
|
sodiumPortalFluidRenderHandler.get().render(world, fluidState, blockPos, offset, buffers);
|
||||||
ci.cancel();
|
ci.cancel();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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.resource.metadata.AnimationResourceMetadata;
|
||||||
import net.minecraft.client.texture.SpriteContents;
|
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.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
import quimufu.colourful_portals.client.AlphaInterpolationHolder;
|
import quimufu.colourful_portals.client.rendering.AlphaInterpolationHolder;
|
||||||
|
|
||||||
@Mixin(SpriteContents.class)
|
@Mixin(SpriteContents.class)
|
||||||
public abstract class SpriteContentsMixin {
|
public abstract class SpriteContentsMixin {
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package quimufu.colourful_portals.client;
|
package quimufu.colourful_portals.client.rendering;
|
||||||
|
|
||||||
import com.mojang.blaze3d.systems.RenderSystem;
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
import net.minecraft.client.texture.Animator;
|
import net.minecraft.client.texture.Animator;
|
||||||
|
@ -9,7 +9,7 @@ import org.jetbrains.annotations.Nullable;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This code is mostly copies from minecraft source. it is owned by mojang.
|
* This code is mostly copies from minecraft source. It is owned by mojang.
|
||||||
*/
|
*/
|
||||||
public class AlphaBlendingAnimator implements Animator {
|
public class AlphaBlendingAnimator implements Animator {
|
||||||
int frame;
|
int frame;
|
|
@ -1,4 +1,4 @@
|
||||||
package quimufu.colourful_portals.client;
|
package quimufu.colourful_portals.client.rendering;
|
||||||
|
|
||||||
public interface AlphaInterpolationHolder {
|
public interface AlphaInterpolationHolder {
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
package quimufu.colourful_portals.client.rendering.fluid;
|
||||||
|
|
||||||
|
import net.minecraft.fluid.FluidState;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.world.BlockRenderView;
|
||||||
|
import org.joml.Vector3f;
|
||||||
|
|
||||||
|
public interface CommonPortalFluidRenderer {
|
||||||
|
boolean render(BlockRenderView world,
|
||||||
|
FluidState fluidState,
|
||||||
|
BlockPos pos,
|
||||||
|
Vector3f offset,
|
||||||
|
VertexEater vertexEater);
|
||||||
|
}
|
|
@ -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.FluidRenderHandler;
|
||||||
import net.fabricmc.fabric.api.client.render.fluid.v1.FluidRenderHandlerRegistry;
|
import net.fabricmc.fabric.api.client.render.fluid.v1.FluidRenderHandlerRegistry;
|
||||||
|
@ -8,15 +8,25 @@ import net.minecraft.fluid.FluidState;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.util.math.Direction;
|
import net.minecraft.util.math.Direction;
|
||||||
import net.minecraft.world.BlockRenderView;
|
import net.minecraft.world.BlockRenderView;
|
||||||
|
import org.joml.Quaternionf;
|
||||||
|
import org.joml.Vector3f;
|
||||||
import quimufu.colourful_portals.ColourfulPortalsMod;
|
import quimufu.colourful_portals.ColourfulPortalsMod;
|
||||||
import quimufu.colourful_portals.portal_fluid.PortalFluid;
|
import quimufu.colourful_portals.portal_fluid.PortalFluid;
|
||||||
|
|
||||||
public class CommonPortalFluidRenderer {
|
public class CommonPortalFluidRendererV1 implements CommonPortalFluidRenderer {
|
||||||
|
|
||||||
|
public static final Quaternionf IDENTITY = new Quaternionf();
|
||||||
private Sprite sprite = null;
|
private Sprite sprite = null;
|
||||||
private final float[] uIu2IvIv2 = new float[4];
|
private final float[] uIu2IvIv2 = new float[4];
|
||||||
|
|
||||||
public boolean render(BlockRenderView world, FluidState fluidState, BlockPos pos, BlockPos offset, VertexEater vertexEater) {
|
@Override
|
||||||
|
public boolean render(BlockRenderView world,
|
||||||
|
FluidState fluidState,
|
||||||
|
BlockPos pos,
|
||||||
|
Vector3f offset,
|
||||||
|
VertexEater vertexEater) {
|
||||||
|
|
||||||
|
offset.sub(0.5f,0.5f,0.5f);
|
||||||
|
|
||||||
FluidRenderHandler handler = FluidRenderHandlerRegistry.INSTANCE.get(fluidState.getFluid());
|
FluidRenderHandler handler = FluidRenderHandlerRegistry.INSTANCE.get(fluidState.getFluid());
|
||||||
sprite = handler.getFluidSprites(null, null, fluidState)[0];
|
sprite = handler.getFluidSprites(null, null, fluidState)[0];
|
||||||
|
@ -151,7 +161,7 @@ public class CommonPortalFluidRenderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void drawSilvers(VertexEater buffers, Direction direction, Direction.Axis axis, float offsetInSquishedDir, float neighbourOffsetInSquishedDir, BlockPos offset, boolean odd) {
|
private void drawSilvers(VertexEater buffers, Direction direction, Direction.Axis axis, float offsetInSquishedDir, float neighbourOffsetInSquishedDir, Vector3f offset, boolean odd) {
|
||||||
|
|
||||||
float x = 0F;
|
float x = 0F;
|
||||||
float x2 = 1F;
|
float x2 = 1F;
|
||||||
|
@ -194,7 +204,7 @@ public class CommonPortalFluidRenderer {
|
||||||
drawSide(buffers, x, y, z, x2, y2, z2, direction, uIu2IvIv2[0], uIu2IvIv2[2], uIu2IvIv2[1], uIu2IvIv2[3], offset);
|
drawSide(buffers, x, y, z, x2, y2, z2, direction, uIu2IvIv2[0], uIu2IvIv2[2], uIu2IvIv2[1], uIu2IvIv2[3], offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void drawSide(VertexEater vertexConsumer, float x, float y, float z, float x2, float y2, float z2, Direction direction, float frameU, float frameV, float frameU2, float frameV2, BlockPos offset) {
|
private void drawSide(VertexEater vertexConsumer, float x, float y, float z, float x2, float y2, float z2, Direction direction, float frameU, float frameV, float frameU2, float frameV2, Vector3f offset) {
|
||||||
vertexConsumer.setSprite(sprite);
|
vertexConsumer.setSprite(sprite);
|
||||||
switch (direction) {
|
switch (direction) {
|
||||||
case DOWN -> {
|
case DOWN -> {
|
||||||
|
@ -202,50 +212,44 @@ public class CommonPortalFluidRenderer {
|
||||||
vertexConsumer.eatVertex(x2, y, z, frameU2, frameV2);
|
vertexConsumer.eatVertex(x2, y, z, frameU2, frameV2);
|
||||||
vertexConsumer.eatVertex(x2, y, z2, frameU2, frameV);
|
vertexConsumer.eatVertex(x2, y, z2, frameU2, frameV);
|
||||||
vertexConsumer.eatVertex(x, y, z2, frameU, frameV);
|
vertexConsumer.eatVertex(x, y, z2, frameU, frameV);
|
||||||
vertexConsumer.drawQuad(offset, direction);
|
vertexConsumer.drawQuad(offset, IDENTITY, direction);
|
||||||
}
|
}
|
||||||
case UP -> {
|
case UP -> {
|
||||||
vertexConsumer.eatVertex(x, y2, z2, frameU, frameV2);
|
vertexConsumer.eatVertex(x, y2, z2, frameU, frameV2);
|
||||||
vertexConsumer.eatVertex(x2, y2, z2, frameU2, frameV2);
|
vertexConsumer.eatVertex(x2, y2, z2, frameU2, frameV2);
|
||||||
vertexConsumer.eatVertex(x2, y2, z, frameU2, frameV);
|
vertexConsumer.eatVertex(x2, y2, z, frameU2, frameV);
|
||||||
vertexConsumer.eatVertex(x, y2, z, frameU, frameV);
|
vertexConsumer.eatVertex(x, y2, z, frameU, frameV);
|
||||||
vertexConsumer.drawQuad(offset, direction);
|
vertexConsumer.drawQuad(offset, IDENTITY, direction);
|
||||||
}
|
}
|
||||||
case NORTH -> {
|
case NORTH -> {
|
||||||
vertexConsumer.eatVertex(x, y2, z, frameU, frameV);
|
vertexConsumer.eatVertex(x, y2, z, frameU, frameV);
|
||||||
vertexConsumer.eatVertex(x2, y2, z, frameU2, frameV);
|
vertexConsumer.eatVertex(x2, y2, z, frameU2, frameV);
|
||||||
vertexConsumer.eatVertex(x2, y, z, frameU2, frameV2);
|
vertexConsumer.eatVertex(x2, y, z, frameU2, frameV2);
|
||||||
vertexConsumer.eatVertex(x, y, z, frameU, frameV2);
|
vertexConsumer.eatVertex(x, y, z, frameU, frameV2);
|
||||||
vertexConsumer.drawQuad(offset, direction);
|
vertexConsumer.drawQuad(offset, IDENTITY, direction);
|
||||||
}
|
}
|
||||||
case SOUTH -> {
|
case SOUTH -> {
|
||||||
vertexConsumer.eatVertex(x, y, z2, frameU, frameV);
|
vertexConsumer.eatVertex(x, y, z2, frameU, frameV);
|
||||||
vertexConsumer.eatVertex(x2, y, z2, frameU2, frameV);
|
vertexConsumer.eatVertex(x2, y, z2, frameU2, frameV);
|
||||||
vertexConsumer.eatVertex(x2, y2, z2, frameU2, frameV2);
|
vertexConsumer.eatVertex(x2, y2, z2, frameU2, frameV2);
|
||||||
vertexConsumer.eatVertex(x, y2, z2, frameU, frameV2);
|
vertexConsumer.eatVertex(x, y2, z2, frameU, frameV2);
|
||||||
vertexConsumer.drawQuad(offset, direction);
|
vertexConsumer.drawQuad(offset, IDENTITY, direction);
|
||||||
}
|
}
|
||||||
case WEST -> {
|
case WEST -> {
|
||||||
vertexConsumer.eatVertex(x, y, z, frameU, frameV);
|
vertexConsumer.eatVertex(x, y, z, frameU, frameV);
|
||||||
vertexConsumer.eatVertex(x, y, z2, frameU2, frameV);
|
vertexConsumer.eatVertex(x, y, z2, frameU2, frameV);
|
||||||
vertexConsumer.eatVertex(x, y2, z2, frameU2, frameV2);
|
vertexConsumer.eatVertex(x, y2, z2, frameU2, frameV2);
|
||||||
vertexConsumer.eatVertex(x, y2, z, frameU, frameV2);
|
vertexConsumer.eatVertex(x, y2, z, frameU, frameV2);
|
||||||
vertexConsumer.drawQuad(offset, direction);
|
vertexConsumer.drawQuad(offset, IDENTITY, direction);
|
||||||
}
|
}
|
||||||
case EAST -> {
|
case EAST -> {
|
||||||
vertexConsumer.eatVertex(x2, y2, z, frameU, frameV);
|
vertexConsumer.eatVertex(x2, y2, z, frameU, frameV);
|
||||||
vertexConsumer.eatVertex(x2, y2, z2, frameU2, frameV);
|
vertexConsumer.eatVertex(x2, y2, z2, frameU2, frameV);
|
||||||
vertexConsumer.eatVertex(x2, y, z2, frameU2, frameV2);
|
vertexConsumer.eatVertex(x2, y, z2, frameU2, frameV2);
|
||||||
vertexConsumer.eatVertex(x2, y, z, frameU, frameV2);
|
vertexConsumer.eatVertex(x2, y, z, frameU, frameV2);
|
||||||
vertexConsumer.drawQuad(offset, direction);
|
vertexConsumer.drawQuad(offset, IDENTITY, direction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface VertexEater {
|
|
||||||
|
|
||||||
void setSprite(Sprite sprite);
|
|
||||||
void eatVertex(float x, float y, float z, float frameU, float frameV);
|
|
||||||
void drawQuad(BlockPos offset, Direction direction);
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -0,0 +1,349 @@
|
||||||
|
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;
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.client.texture.Sprite;
|
||||||
|
import net.minecraft.fluid.FluidState;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
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.portal_fluid.NullableAxis;
|
||||||
|
import quimufu.colourful_portals.portal_fluid.PortalFluid;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.EnumMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static quimufu.colourful_portals.ColourfulPortalsMod.LOGGER;
|
||||||
|
|
||||||
|
public class CommonPortalFluidRendererV2 implements CommonPortalFluidRenderer {
|
||||||
|
|
||||||
|
private Sprite sprite = null;
|
||||||
|
|
||||||
|
private final float[] heights = new float[9];
|
||||||
|
private final int[] heightsC = new int[9];
|
||||||
|
|
||||||
|
private static final EnumMap<NullableAxis, Quaternionf> quaternions =
|
||||||
|
new EnumMap<>(Map.of(
|
||||||
|
NullableAxis.X, new Quaternionf()
|
||||||
|
.rotationTo(0,1,0,-1,0,0),
|
||||||
|
NullableAxis.Y, new Quaternionf(),//identity
|
||||||
|
NullableAxis.Z, new Quaternionf()
|
||||||
|
.rotationTo(0,1,0,0,0,-1),
|
||||||
|
NullableAxis.NULL, new Quaternionf()//identity
|
||||||
|
));
|
||||||
|
|
||||||
|
private final int[] amounts = new int[9];
|
||||||
|
|
||||||
|
private final float[] quads = new float[]{
|
||||||
|
//Up
|
||||||
|
-0.5f, 0.5f, 0.0f,
|
||||||
|
0.0f, 0.5f, 0.0f,
|
||||||
|
0.0f, 0.5f, -0.5f,
|
||||||
|
-0.5f, 0.5f, -0.5f,
|
||||||
|
|
||||||
|
0.0f, 0.5f, 0.0f,
|
||||||
|
0.5f, 0.5f, 0.0f,
|
||||||
|
0.5f, 0.5f, -0.5f,
|
||||||
|
0.0f, 0.5f, -0.5f,
|
||||||
|
|
||||||
|
-0.5f, 0.5f, 0.5f,
|
||||||
|
0.0f, 0.5f, 0.5f,
|
||||||
|
0.0f, 0.5f, 0.0f,
|
||||||
|
-0.5f, 0.5f, 0.0f,
|
||||||
|
|
||||||
|
0.0f, 0.5f, 0.5f,
|
||||||
|
0.5f, 0.5f, 0.5f,
|
||||||
|
0.5f, 0.5f, 0.0f,
|
||||||
|
0.0f, 0.5f, 0.0f,
|
||||||
|
|
||||||
|
//Down
|
||||||
|
-0.5f, -0.5f, -0.5f,
|
||||||
|
0.0f, -0.5f, -0.5f,
|
||||||
|
0.0f, -0.5f, 0.0f,
|
||||||
|
-0.5f, -0.5f, 0.0f,
|
||||||
|
|
||||||
|
0.0f, -0.5f, -0.5f,
|
||||||
|
0.5f, -0.5f, -0.5f,
|
||||||
|
0.5f, -0.5f, 0.0f,
|
||||||
|
0.0f, -0.5f, 0.0f,
|
||||||
|
|
||||||
|
-0.5f, -0.5f, 0.0f,
|
||||||
|
0.0f, -0.5f, 0.0f,
|
||||||
|
0.0f, -0.5f, 0.5f,
|
||||||
|
-0.5f, -0.5f, 0.5f,
|
||||||
|
|
||||||
|
0.0f, -0.5f, 0.0f,
|
||||||
|
0.5f, -0.5f, 0.0f,
|
||||||
|
0.5f, -0.5f, 0.5f,
|
||||||
|
0.0f, -0.5f, 0.5f,
|
||||||
|
|
||||||
|
//NORTH
|
||||||
|
-0.5f, 0.5f, -0.5f,
|
||||||
|
0.0f, 0.5f, -0.5f,
|
||||||
|
0.0f, -0.5f, -0.5f,
|
||||||
|
-0.5f, -0.5f, -0.5f,
|
||||||
|
|
||||||
|
0.0f, 0.5f, -0.5f,
|
||||||
|
0.5f, 0.5f, -0.5f,
|
||||||
|
0.5f, -0.5f, -0.5f,
|
||||||
|
0.0f, -0.5f, -0.5f,
|
||||||
|
|
||||||
|
//SOUTH
|
||||||
|
-0.5f, -0.5f, 0.5f,
|
||||||
|
0.0f, -0.5f, 0.5f,
|
||||||
|
0.0f, 0.5f, 0.5f,
|
||||||
|
-0.5f, 0.5f, 0.5f,
|
||||||
|
|
||||||
|
0.0f, -0.5f, 0.5f,
|
||||||
|
0.5f, -0.5f, 0.5f,
|
||||||
|
0.5f, 0.5f, 0.5f,
|
||||||
|
0.0f, 0.5f, 0.5f,
|
||||||
|
|
||||||
|
//WEST
|
||||||
|
-0.5f, -0.5f, -0.5f,
|
||||||
|
-0.5f, -0.5f, 0.0f,
|
||||||
|
-0.5f, 0.5f, 0.0f,
|
||||||
|
-0.5f, 0.5f, -0.5f,
|
||||||
|
|
||||||
|
-0.5f, -0.5f, 0.0f,
|
||||||
|
-0.5f, -0.5f, 0.5f,
|
||||||
|
-0.5f, 0.5f, 0.5f,
|
||||||
|
-0.5f, 0.5f, 0.0f,
|
||||||
|
|
||||||
|
//EAST
|
||||||
|
0.5f, 0.5f, -0.5f,
|
||||||
|
0.5f, 0.5f, 0.0f,
|
||||||
|
0.5f, -0.5f, 0.0f,
|
||||||
|
0.5f, -0.5f, -0.5f,
|
||||||
|
|
||||||
|
0.5f, 0.5f, 0.0f,
|
||||||
|
0.5f, 0.5f, 0.5f,
|
||||||
|
0.5f, -0.5f, 0.5f,
|
||||||
|
0.5f, -0.5f, 0.0f,
|
||||||
|
};
|
||||||
|
|
||||||
|
public boolean render(BlockRenderView world, FluidState fluidState, BlockPos pos, Vector3f offset, VertexEater vertexEater) {
|
||||||
|
|
||||||
|
FluidRenderHandler handler = FluidRenderHandlerRegistry.INSTANCE.get(fluidState.getFluid());
|
||||||
|
sprite = handler.getFluidSprites(null, null, fluidState)[0];
|
||||||
|
|
||||||
|
NullableAxis axis = fluidState.get(PortalFluid.AXIS);
|
||||||
|
|
||||||
|
int amount = fluidState.get(PortalFluid.AMOUNT);
|
||||||
|
if (amount == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
//get neighbours heights:
|
||||||
|
saveAmounts(world, pos, axis);
|
||||||
|
|
||||||
|
//offsets of corners:
|
||||||
|
Arrays.fill(heights, 0);
|
||||||
|
Arrays.fill(heightsC, 0);
|
||||||
|
for (int a = 0; a < 3; a++) {
|
||||||
|
for (int b = 0; b < 3; b++) {
|
||||||
|
if (amounts[a * 3 + b] <= -1) {
|
||||||
|
if ((a == 1) ^ (b == 1)) {
|
||||||
|
heights[a * 3 + b] += amounts[4] / 32f;
|
||||||
|
heightsC[a * 3 + b]++;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (a < 2 && b < 2) {
|
||||||
|
heights[0] += amounts[a * 3 + b] / 32f;
|
||||||
|
heightsC[0]++;
|
||||||
|
}
|
||||||
|
if (a < 2 && b > 0) {
|
||||||
|
heights[2] += amounts[a * 3 + b] / 32f;
|
||||||
|
heightsC[2]++;
|
||||||
|
}
|
||||||
|
if (a > 0 && b < 2) {
|
||||||
|
heights[6] += amounts[a * 3 + b] / 32f;
|
||||||
|
heightsC[6]++;
|
||||||
|
}
|
||||||
|
if (a > 0 && b > 0) {
|
||||||
|
heights[8] += amounts[a * 3 + b] / 32f;
|
||||||
|
heightsC[8]++;
|
||||||
|
}
|
||||||
|
if ((a == 1) ^ (b == 1)) {
|
||||||
|
heights[a * 3 + b] += amounts[a * 3 + b] / 32f;
|
||||||
|
heights[a * 3 + b] += amounts[4] / 32f; //always != -1
|
||||||
|
heightsC[a * 3 + b] += 2;
|
||||||
|
}
|
||||||
|
if ((a == 1) && (b == 1)) {
|
||||||
|
heights[4] = amounts[4] / 32f;//always != -1
|
||||||
|
heightsC[4]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int a = 0; a < 9; a++) {
|
||||||
|
heights[a] = heights[a] / heightsC[a];
|
||||||
|
}
|
||||||
|
for (int i = 0; i < quads.length / 3; i++) {
|
||||||
|
int x = (int) ((quads[i * 3] + 0.5f) * 2);
|
||||||
|
int z = (int) ((quads[i * 3 + 2] + 0.5f) * 2);
|
||||||
|
if (quads[i * 3 + 1] > 0f) {
|
||||||
|
quads[i * 3 + 1] = 0f + heights[x * 3 + z];
|
||||||
|
} else {
|
||||||
|
quads[i * 3 + 1] = 0f - heights[x * 3 + z];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vertexEater.setSprite(sprite);
|
||||||
|
int endUp = 4;
|
||||||
|
int endDown = 8;
|
||||||
|
int endNorth = 10;
|
||||||
|
int endSouth = 12;
|
||||||
|
int endWest = 14;
|
||||||
|
int endEast = 16;
|
||||||
|
for (Direction value : Direction.values()) {
|
||||||
|
switch (value) {
|
||||||
|
case UP -> {
|
||||||
|
for (int i = 0; i < endUp; i++) {
|
||||||
|
for (int j = 0; j < 4; j++) {
|
||||||
|
|
||||||
|
vertexEater.eatVertex(
|
||||||
|
quads[i * 12 + j * 3],
|
||||||
|
quads[i * 12 + j * 3 + 1],
|
||||||
|
quads[i * 12 + j * 3 + 2],
|
||||||
|
sprite.getFrameU(quads[i * 12 + j * 3] + 0.5f),
|
||||||
|
sprite.getFrameV(quads[i * 12 + j * 3 + 2] + 0.5f));
|
||||||
|
}
|
||||||
|
vertexEater.drawQuad(offset, quaternions.get(axis), Direction.UP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case DOWN -> {
|
||||||
|
for (int i = endUp; i < endDown; i++) {
|
||||||
|
for (int j = 0; j < 4; j++) {
|
||||||
|
vertexEater.eatVertex(
|
||||||
|
quads[i * 12 + j * 3],
|
||||||
|
quads[i * 12 + j * 3 + 1],
|
||||||
|
quads[i * 12 + j * 3 + 2],
|
||||||
|
sprite.getFrameU(quads[i * 12 + j * 3] + 0.5f),
|
||||||
|
sprite.getFrameV(quads[i * 12 + j * 3 + 2] + 0.5f));
|
||||||
|
}
|
||||||
|
vertexEater.drawQuad(offset, quaternions.get(axis), Direction.DOWN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case NORTH -> {
|
||||||
|
if (amounts[3] >= -1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (int i = endDown; i < endNorth; i++) {
|
||||||
|
for (int j = 0; j < 4; j++) {
|
||||||
|
vertexEater.eatVertex(
|
||||||
|
quads[i * 12 + j * 3],
|
||||||
|
quads[i * 12 + j * 3 + 1],
|
||||||
|
quads[i * 12 + j * 3 + 2],
|
||||||
|
sprite.getFrameU(quads[i * 12 + j * 3] + 0.5f),
|
||||||
|
sprite.getFrameV(quads[i * 12 + j * 3 + 1] + 0.5f));
|
||||||
|
}
|
||||||
|
vertexEater.drawQuad(offset, quaternions.get(axis), Direction.NORTH);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case SOUTH -> {
|
||||||
|
if (amounts[5] >= -1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (int i = endNorth; i < endSouth; i++) {
|
||||||
|
for (int j = 0; j < 4; j++) {
|
||||||
|
vertexEater.eatVertex(
|
||||||
|
quads[i * 12 + j * 3],
|
||||||
|
quads[i * 12 + j * 3 + 1],
|
||||||
|
quads[i * 12 + j * 3 + 2],
|
||||||
|
sprite.getFrameU(quads[i * 12 + j * 3] + 0.5f),
|
||||||
|
sprite.getFrameV(quads[i * 12 + j * 3 + 1] + 0.5f));
|
||||||
|
}
|
||||||
|
vertexEater.drawQuad(offset, quaternions.get(axis), Direction.SOUTH);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case WEST -> {
|
||||||
|
if (amounts[1] >= -1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (int i = endSouth; i < endWest; i++) {
|
||||||
|
for (int j = 0; j < 4; j++) {
|
||||||
|
vertexEater.eatVertex(
|
||||||
|
quads[i * 12 + j * 3],
|
||||||
|
quads[i * 12 + j * 3 + 1],
|
||||||
|
quads[i * 12 + j * 3 + 2],
|
||||||
|
sprite.getFrameU(quads[i * 12 + j * 3 + 1] + 0.5f),
|
||||||
|
sprite.getFrameV(quads[i * 12 + j * 3 + 2] + 0.5f));
|
||||||
|
}
|
||||||
|
vertexEater.drawQuad(offset, quaternions.get(axis), Direction.WEST);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case EAST -> {
|
||||||
|
if (amounts[7] >= -1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (int i = endWest; i < endEast; i++) {
|
||||||
|
for (int j = 0; j < 4; j++) {
|
||||||
|
vertexEater.eatVertex(
|
||||||
|
quads[i * 12 + j * 3],
|
||||||
|
quads[i * 12 + j * 3 + 1],
|
||||||
|
quads[i * 12 + j * 3 + 2],
|
||||||
|
sprite.getFrameU(quads[i * 12 + j * 3 + 1] + 0.5f),
|
||||||
|
sprite.getFrameV(quads[i * 12 + j * 3 + 2] + 0.5f));
|
||||||
|
}
|
||||||
|
vertexEater.drawQuad(offset, quaternions.get(axis), Direction.EAST);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveAmounts(BlockRenderView world, BlockPos pos, NullableAxis axis) {
|
||||||
|
BlockPos.Mutable curr = new BlockPos.Mutable();
|
||||||
|
switch (axis) {
|
||||||
|
case NULL -> {
|
||||||
|
Arrays.fill(amounts, -2);
|
||||||
|
amounts[4] = 16;
|
||||||
|
}
|
||||||
|
case X -> {
|
||||||
|
for (int y = 0; y < 3; y++) {
|
||||||
|
for (int z = 0; z < 3; z++) {
|
||||||
|
saveAmount(world, pos, curr, 0, y - 1, z - 1, y, z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case Y -> {
|
||||||
|
for (int x = 0; x < 3; x++) {
|
||||||
|
for (int z = 0; z < 3; z++) {
|
||||||
|
saveAmount(world, pos, curr, x - 1, 0, z - 1, x, z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case Z -> {
|
||||||
|
for (int x = 0; x < 3; x++) {
|
||||||
|
for (int y = 0; y < 3; y++) {
|
||||||
|
saveAmount(world, pos, curr, x - 1, y - 1, 0, x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveAmount(BlockRenderView world, BlockPos pos, BlockPos.Mutable curr, int dx, int dy, int dz, int major, int minor) {
|
||||||
|
curr.set(pos);
|
||||||
|
curr.move(dx, dy, dz);
|
||||||
|
BlockState blockState = world.getBlockState(curr);
|
||||||
|
FluidState fluidState = blockState
|
||||||
|
.getFluidState();
|
||||||
|
if (fluidState.isOf(ColourfulPortalsMod.PORTAL_FLUID)) {
|
||||||
|
amounts[major * 3 + minor] = fluidState.get(PortalFluid.AMOUNT);
|
||||||
|
} else {
|
||||||
|
Direction direction = Direction.fromVector(dx, dy, dz);
|
||||||
|
if (direction != null && blockState.isSideSolidFullSquare(world, curr, direction.getOpposite())) {
|
||||||
|
amounts[major * 3 + minor] = -1;
|
||||||
|
} else {
|
||||||
|
amounts[major * 3 + minor] = -2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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.EnvType;
|
||||||
import net.fabricmc.api.Environment;
|
import net.fabricmc.api.Environment;
|
||||||
|
@ -13,18 +13,21 @@ import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.util.math.Direction;
|
import net.minecraft.util.math.Direction;
|
||||||
import net.minecraft.world.BlockRenderView;
|
import net.minecraft.world.BlockRenderView;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.joml.Quaternionf;
|
||||||
|
import org.joml.Vector3f;
|
||||||
import quimufu.colourful_portals.ColourfulPortalsMod;
|
import quimufu.colourful_portals.ColourfulPortalsMod;
|
||||||
|
import quimufu.colourful_portals.client.ColourfulPortalsModClient;
|
||||||
|
|
||||||
@Environment(value = EnvType.CLIENT)
|
@Environment(value = EnvType.CLIENT)
|
||||||
public class PortalFluidRenderHandler implements FluidRenderHandler, CommonPortalFluidRenderer.VertexEater {
|
public class PortalFluidRenderHandler implements FluidRenderHandler, VertexEater {
|
||||||
Identifier PORTAL_FLUID_STILL = Identifier.of(ColourfulPortalsMod.MOD_ID, "block/portal_still");
|
Identifier PORTAL_FLUID_STILL = Identifier.of(ColourfulPortalsMod.MOD_ID, "block/portal_still");
|
||||||
|
|
||||||
private final CommonPortalFluidRenderer commonPortalFluidRenderer = new CommonPortalFluidRenderer();
|
|
||||||
private Sprite sprite = null;
|
private Sprite sprite = null;
|
||||||
private final ThreadLocal<VertexConsumer> vertexConsumer = new ThreadLocal<>();
|
private final ThreadLocal<VertexConsumer> vertexConsumer = new ThreadLocal<>();
|
||||||
private final ThreadLocal<Integer> i = new ThreadLocal<>();
|
private final ThreadLocal<Integer> i = new ThreadLocal<>();
|
||||||
|
|
||||||
private final ThreadLocal<float[][]> vertices = new ThreadLocal<>();
|
private final ThreadLocal<float[][]> vertices = new ThreadLocal<>();
|
||||||
|
private final ThreadLocal<Vector3f> tmpVector = ThreadLocal.withInitial(Vector3f::new);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Sprite[] getFluidSprites(@Nullable BlockRenderView view, @Nullable BlockPos pos, FluidState state) {
|
public Sprite[] getFluidSprites(@Nullable BlockRenderView view, @Nullable BlockPos pos, FluidState state) {
|
||||||
|
@ -39,11 +42,13 @@ public class PortalFluidRenderHandler implements FluidRenderHandler, CommonPorta
|
||||||
@Override
|
@Override
|
||||||
public void renderFluid(BlockPos pos, BlockRenderView world, VertexConsumer vertexConsumer, BlockState blockState, FluidState fluidState) {
|
public void renderFluid(BlockPos pos, BlockRenderView world, VertexConsumer vertexConsumer, BlockState blockState, FluidState fluidState) {
|
||||||
this.vertexConsumer.set(vertexConsumer);
|
this.vertexConsumer.set(vertexConsumer);
|
||||||
BlockPos offset = new BlockPos(pos.getX() & 0xF, pos.getY() & 0xF, pos.getZ() & 0xF);
|
Vector3f offset = new Vector3f(pos.getX() & 0xF, pos.getY() & 0xF, pos.getZ() & 0xF);
|
||||||
|
offset.add(0.5f,0.5f,0.5f);
|
||||||
if (vertices.get() == null) {
|
if (vertices.get() == null) {
|
||||||
vertices.set(new float[4][5]);
|
vertices.set(new float[4][5]);
|
||||||
}
|
}
|
||||||
commonPortalFluidRenderer.render(world, fluidState, pos, offset, this);
|
ColourfulPortalsModClient.FLUID_RENDERER.get()
|
||||||
|
.render(world, fluidState, pos, offset, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -71,14 +76,16 @@ public class PortalFluidRenderHandler implements FluidRenderHandler, CommonPorta
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void drawQuad(BlockPos offset, Direction direction) {
|
public void drawQuad(Vector3f offset, Quaternionf rotation, Direction direction) {
|
||||||
float offX = offset.getX();
|
float offX = offset.x;
|
||||||
float offY = offset.getY();
|
float offY = offset.y;
|
||||||
float offZ = offset.getZ();
|
float offZ = offset.z;
|
||||||
|
Vector3f f = tmpVector.get();
|
||||||
for (float[] v : vertices.get()) {
|
for (float[] v : vertices.get()) {
|
||||||
|
f.set(v);
|
||||||
|
rotation.transform(f);
|
||||||
vertexConsumer.get()
|
vertexConsumer.get()
|
||||||
.vertex(offX + v[0], offY + v[1], offZ + v[2])
|
.vertex(offX + f.x, offY + f.y, offZ + f.z)
|
||||||
.color(1f, 1f, 1f, 1.0f)
|
.color(1f, 1f, 1f, 1.0f)
|
||||||
.texture(v[3], v[4])
|
.texture(v[3], v[4])
|
||||||
.light(16)
|
.light(16)
|
|
@ -1,17 +1,14 @@
|
||||||
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.ModelQuad;
|
||||||
import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView;
|
import me.jellysquid.mods.sodium.client.model.quad.ModelQuadView;
|
||||||
import me.jellysquid.mods.sodium.client.model.quad.ModelQuadViewMutable;
|
import me.jellysquid.mods.sodium.client.model.quad.ModelQuadViewMutable;
|
||||||
import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing;
|
import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing;
|
||||||
import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadWinding;
|
|
||||||
import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildBuffers;
|
import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildBuffers;
|
||||||
import me.jellysquid.mods.sodium.client.render.chunk.compile.buffers.ChunkModelBuilder;
|
import me.jellysquid.mods.sodium.client.render.chunk.compile.buffers.ChunkModelBuilder;
|
||||||
import me.jellysquid.mods.sodium.client.render.chunk.terrain.material.DefaultMaterials;
|
import me.jellysquid.mods.sodium.client.render.chunk.terrain.material.DefaultMaterials;
|
||||||
import me.jellysquid.mods.sodium.client.render.chunk.terrain.material.Material;
|
import me.jellysquid.mods.sodium.client.render.chunk.terrain.material.Material;
|
||||||
import me.jellysquid.mods.sodium.client.render.chunk.vertex.builder.ChunkMeshBufferBuilder;
|
|
||||||
import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkVertexEncoder;
|
import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkVertexEncoder;
|
||||||
import me.jellysquid.mods.sodium.client.render.chunk.vertex.format.ChunkVertexEncoder.Vertex;
|
|
||||||
import net.fabricmc.api.EnvType;
|
import net.fabricmc.api.EnvType;
|
||||||
import net.fabricmc.api.Environment;
|
import net.fabricmc.api.Environment;
|
||||||
import net.minecraft.client.texture.Sprite;
|
import net.minecraft.client.texture.Sprite;
|
||||||
|
@ -19,18 +16,22 @@ import net.minecraft.fluid.FluidState;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.util.math.Direction;
|
import net.minecraft.util.math.Direction;
|
||||||
import net.minecraft.world.BlockRenderView;
|
import net.minecraft.world.BlockRenderView;
|
||||||
|
import org.joml.Quaternionf;
|
||||||
|
import org.joml.Vector3f;
|
||||||
|
import quimufu.colourful_portals.client.ColourfulPortalsModClient;
|
||||||
|
|
||||||
@Environment(value = EnvType.CLIENT)
|
@Environment(value = EnvType.CLIENT)
|
||||||
public class SodiumPortalFluidRenderHandler implements CommonPortalFluidRenderer.VertexEater {
|
public class SodiumPortalFluidRenderHandler implements VertexEater {
|
||||||
|
|
||||||
private Sprite sprite = null;
|
private Sprite sprite = null;
|
||||||
private final ModelQuadViewMutable quad = new ModelQuad();
|
private final ModelQuadViewMutable quad = new ModelQuad();
|
||||||
|
|
||||||
private final CommonPortalFluidRenderer commonPortalFluidRenderer = new CommonPortalFluidRenderer();
|
private final CommonPortalFluidRenderer commonPortalFluidRenderer = ColourfulPortalsModClient.FLUID_RENDERER.get();
|
||||||
private final ChunkVertexEncoder.Vertex[] vertices = ChunkVertexEncoder.Vertex.uninitializedQuad();
|
private final ChunkVertexEncoder.Vertex[] vertices = ChunkVertexEncoder.Vertex.uninitializedQuad();
|
||||||
private int i;
|
private int i;
|
||||||
private ChunkModelBuilder chunkModelBuilder;
|
private ChunkModelBuilder chunkModelBuilder;
|
||||||
private Material material;
|
private Material material;
|
||||||
|
private Vector3f rotBuffer = new Vector3f();
|
||||||
|
|
||||||
public SodiumPortalFluidRenderHandler() {
|
public SodiumPortalFluidRenderHandler() {
|
||||||
}
|
}
|
||||||
|
@ -38,7 +39,9 @@ public class SodiumPortalFluidRenderHandler implements CommonPortalFluidRenderer
|
||||||
public boolean render(BlockRenderView world, FluidState fluidState, BlockPos pos, BlockPos offset, ChunkBuildBuffers buffers) {
|
public boolean render(BlockRenderView world, FluidState fluidState, BlockPos pos, BlockPos offset, ChunkBuildBuffers buffers) {
|
||||||
material = DefaultMaterials.forFluidState(fluidState);
|
material = DefaultMaterials.forFluidState(fluidState);
|
||||||
this.chunkModelBuilder = buffers.get(material);
|
this.chunkModelBuilder = buffers.get(material);
|
||||||
return commonPortalFluidRenderer.render(world,fluidState,pos,offset,this);
|
Vector3f vOffset = new Vector3f(offset.getX(), offset.getY(), offset.getZ());
|
||||||
|
vOffset.add(0.5f, 0.5f, 0.5f);
|
||||||
|
return commonPortalFluidRenderer.render(world, fluidState, pos, vOffset, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -59,18 +62,19 @@ public class SodiumPortalFluidRenderHandler implements CommonPortalFluidRenderer
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void drawQuad(BlockPos offset, Direction direction) {
|
public void drawQuad(Vector3f offset, Quaternionf rot, Direction direction) {
|
||||||
writeQuad(chunkModelBuilder, material, offset, quad, ModelQuadFacing.fromDirection(direction), false);
|
writeQuad(chunkModelBuilder, material, offset, quad, rot, ModelQuadFacing.fromDirection(direction), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeQuad(ChunkModelBuilder builder, Material material, BlockPos offset, ModelQuadView quad, ModelQuadFacing facing, boolean flip) {
|
private void writeQuad(ChunkModelBuilder builder, Material material, Vector3f offset, ModelQuadView quad, Quaternionf rot, ModelQuadFacing facing, boolean flip) {
|
||||||
var vertices = this.vertices;
|
var vertices = this.vertices;
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
var out = vertices[flip ? 3 - i : i];
|
var out = vertices[flip ? 3 - i : i];
|
||||||
out.x = offset.getX() + quad.getX(i);
|
rot.transform(quad.getX(i), quad.getY(i), quad.getZ(i), rotBuffer);
|
||||||
out.y = offset.getY() + quad.getY(i);
|
out.x = offset.x + rotBuffer.x;
|
||||||
out.z = offset.getZ() + quad.getZ(i);
|
out.y = offset.y + rotBuffer.y;
|
||||||
|
out.z = offset.z + rotBuffer.z;
|
||||||
out.color = 0xFFFFFFFF;
|
out.color = 0xFFFFFFFF;
|
||||||
out.u = quad.getTexU(i);
|
out.u = quad.getTexU(i);
|
||||||
out.v = quad.getTexV(i);
|
out.v = quad.getTexV(i);
|
||||||
|
@ -88,5 +92,4 @@ public class SodiumPortalFluidRenderHandler implements CommonPortalFluidRenderer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
package quimufu.colourful_portals.client.rendering.fluid;
|
||||||
|
|
||||||
|
import net.minecraft.client.texture.Sprite;
|
||||||
|
import net.minecraft.util.math.Direction;
|
||||||
|
import org.joml.Quaternionf;
|
||||||
|
import org.joml.Vector3f;
|
||||||
|
|
||||||
|
public interface VertexEater {
|
||||||
|
|
||||||
|
void setSprite(Sprite sprite);
|
||||||
|
|
||||||
|
void eatVertex(float x, float y, float z, float frameU, float frameV);
|
||||||
|
|
||||||
|
void drawQuad(Vector3f offset, Quaternionf quaternionf, Direction direction);
|
||||||
|
}
|
|
@ -2,72 +2,99 @@ package quimufu.colourful_portals.config;
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import eu.midnightdust.lib.config.MidnightConfig;
|
import eu.midnightdust.lib.config.MidnightConfig;
|
||||||
|
import net.minecraft.registry.RegistryKey;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.util.DyeColor;
|
import net.minecraft.util.DyeColor;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import quimufu.colourful_portals.ColourfulPortalsMod;
|
||||||
|
import quimufu.colourful_portals.util.Procedure;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
public class ColourfulPortalConfig extends MidnightConfig {
|
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;
|
public static boolean disableImmersivePortals = false;
|
||||||
|
|
||||||
@Comment(category = "text")
|
@Comment(category = "portal_colours")
|
||||||
public static Comment explanation;
|
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");
|
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");
|
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");
|
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");
|
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");
|
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");
|
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");
|
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");
|
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");
|
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");
|
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");
|
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");
|
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");
|
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");
|
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");
|
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");
|
public static List<String> black = Lists.newArrayList("minecraft:black_wool");
|
||||||
|
|
||||||
//todo: disabled until i find a good solution
|
@Entry(category = "portal_colours")
|
||||||
//@Entry(category = "text", name = "Blocks that create fully transparent portals")
|
|
||||||
public static List<String> none = Lists.newArrayList();
|
public static List<String> none = Lists.newArrayList();
|
||||||
|
|
||||||
|
@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() {
|
public static Set<String> getAllPortalBlocks() {
|
||||||
Set<String> allBlocks = new HashSet<>();
|
Set<String> allBlocks = new HashSet<>();
|
||||||
allBlocks.addAll(white);
|
allBlocks.addAll(white);
|
||||||
|
@ -129,4 +156,37 @@ public class ColourfulPortalConfig extends MidnightConfig {
|
||||||
throw new IllegalArgumentException("Invalid portal block: " + block);
|
throw new IllegalArgumentException("Invalid portal block: " + block);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeChanges(String modid) {
|
||||||
|
super.writeChanges(modid);
|
||||||
|
for (Procedure procedure : onWrite) {
|
||||||
|
procedure.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
package quimufu.colourful_portals.entity;
|
||||||
|
|
||||||
|
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.predicate.entity.EntityPredicates;
|
||||||
|
import net.minecraft.server.world.ServerWorld;
|
||||||
|
import net.minecraft.sound.SoundCategory;
|
||||||
|
import net.minecraft.util.hit.HitResult;
|
||||||
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import quimufu.colourful_portals.ColourfulPortalsMod;
|
||||||
|
import quimufu.colourful_portals.util.TeleportParticleHelper;
|
||||||
|
import quimufu.colourful_portals.util.TeleportHelper;
|
||||||
|
|
||||||
|
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(entity -> TeleportParticleHelper.spawnTeleportationParticles(entity, getWorld()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCollision(HitResult hitResult) {
|
||||||
|
if (!(getWorld() instanceof ServerWorld serverWorld)) {
|
||||||
|
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(entity -> {
|
||||||
|
Vec3d pos = this.getPos();
|
||||||
|
TeleportHelper.markForTeleport(entity,pos.toVector3f(), serverWorld);
|
||||||
|
});
|
||||||
|
this.discard();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -26,7 +26,6 @@ public class LinkedList<E> implements List<E> {
|
||||||
size++;
|
size++;
|
||||||
node = node.getNext();
|
node = node.getNext();
|
||||||
}
|
}
|
||||||
LOGGER.info("" + size);
|
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
package quimufu.colourful_portals.general_util;
|
||||||
|
|
||||||
|
|
||||||
|
import org.joml.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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,98 @@
|
||||||
|
package quimufu.colourful_portals.item;
|
||||||
|
|
||||||
|
import net.minecraft.advancement.criterion.Criteria;
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
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 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
package quimufu.colourful_portals.item;
|
||||||
|
|
||||||
|
import net.minecraft.entity.LivingEntity;
|
||||||
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
|
import net.minecraft.item.Item;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.item.ItemUsage;
|
||||||
|
import net.minecraft.server.world.ServerWorld;
|
||||||
|
import net.minecraft.sound.SoundCategory;
|
||||||
|
import net.minecraft.sound.SoundEvent;
|
||||||
|
import net.minecraft.sound.SoundEvents;
|
||||||
|
import net.minecraft.stat.Stats;
|
||||||
|
import net.minecraft.util.Hand;
|
||||||
|
import net.minecraft.util.TypedActionResult;
|
||||||
|
import net.minecraft.util.UseAction;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraft.world.event.GameEvent;
|
||||||
|
import quimufu.colourful_portals.entity.ColourfulPearlEntity;
|
||||||
|
import quimufu.colourful_portals.util.TeleportParticleHelper;
|
||||||
|
import quimufu.colourful_portals.util.TeleportHelper;
|
||||||
|
|
||||||
|
public class ColourfulPearlItem
|
||||||
|
extends Item {
|
||||||
|
private static final int MAX_USE_TIME = 5;
|
||||||
|
|
||||||
|
public ColourfulPearlItem(Item.Settings settings) {
|
||||||
|
super(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ItemStack finishUsing(ItemStack stack, World world, LivingEntity user) {
|
||||||
|
if(user instanceof PlayerEntity player){
|
||||||
|
player.getItemCooldownManager().set(this, 50);
|
||||||
|
}
|
||||||
|
if (world instanceof ServerWorld serverWorld) {
|
||||||
|
TeleportHelper.markForTeleport(user, user.getPos().toVector3f(), serverWorld);
|
||||||
|
}
|
||||||
|
stack.decrementUnlessCreative(1, user);
|
||||||
|
user.emitGameEvent(GameEvent.EAT);
|
||||||
|
return stack;
|
||||||
|
}
|
||||||
|
|
||||||
|
@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 int getMaxUseTime(ItemStack stack, LivingEntity user) {
|
||||||
|
return MAX_USE_TIME;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TypedActionResult<ItemStack> use(World world, PlayerEntity user, Hand hand) {
|
||||||
|
if (user.isSneaking()) {
|
||||||
|
TeleportParticleHelper.spawnTeleportationParticles(user, world);
|
||||||
|
return ItemUsage.consumeHeldItem(world, user, 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());
|
||||||
|
}
|
||||||
|
}
|
|
@ -74,16 +74,29 @@ public abstract class BlockChangeAndEntityMovementMixin {
|
||||||
// This code is injected into the end of ServerWorld.onBlockChanged()V
|
// This code is injected into the end of ServerWorld.onBlockChanged()V
|
||||||
if (oldBlock.getBlock() != newBlock.getBlock()) {
|
if (oldBlock.getBlock() != newBlock.getBlock()) {
|
||||||
if (PORTAL_BLOCKS.contains(Registries.BLOCK.getId(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());
|
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()))) {
|
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());
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
package quimufu.colourful_portals.mixin;
|
||||||
|
|
||||||
|
import net.minecraft.entity.Entity;
|
||||||
|
import net.minecraft.server.world.ServerEntityManager;
|
||||||
|
import net.minecraft.server.world.ServerWorld;
|
||||||
|
import net.minecraft.world.EntityList;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||||
|
|
||||||
|
@Mixin(ServerWorld.class)
|
||||||
|
public interface ServerWorldAccessor {
|
||||||
|
@Accessor
|
||||||
|
EntityList getEntityList();
|
||||||
|
}
|
|
@ -42,7 +42,7 @@ public class DefaultLinkingSystem implements PortalLinkingSystem {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void linkPortals(LinkedList<PortalRepresentation> portalRepresentations) {
|
public void linkPortals(LinkedList<PortalRepresentation> portalRepresentations) {
|
||||||
LOGGER.info("start linkPortals");
|
LOGGER.debug("start linkPortals");
|
||||||
for (Node<PortalRepresentation> node = portalRepresentations.getNode(0); node != null; node = node.getNext()) {
|
for (Node<PortalRepresentation> node = portalRepresentations.getNode(0); node != null; node = node.getNext()) {
|
||||||
PortalRepresentation portalRepresentation = node.getValue();
|
PortalRepresentation portalRepresentation = node.getValue();
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@ public class DefaultLinkingSystem implements PortalLinkingSystem {
|
||||||
portalsAtPosition.add(finalNode);
|
portalsAtPosition.add(finalNode);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
LOGGER.info("end linkPortals");
|
LOGGER.debug("end linkPortals");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -72,7 +72,6 @@ public class DefaultLinkingSystem implements PortalLinkingSystem {
|
||||||
prevEntityPos = new Vec3d(entity.prevX, entity.prevY, entity.prevZ);
|
prevEntityPos = new Vec3d(entity.prevX, entity.prevY, entity.prevZ);
|
||||||
}
|
}
|
||||||
if (RaycastHelper.passedOnAxis(prevEntityPos, entity.getPos(), pos, axis)) {
|
if (RaycastHelper.passedOnAxis(prevEntityPos, entity.getPos(), pos, axis)) {
|
||||||
//LOGGER.info("passed on Axis!");
|
|
||||||
if (onPortalPassed(entity, pos, world, axis)) {
|
if (onPortalPassed(entity, pos, world, axis)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,8 @@ import net.minecraft.util.TypeFilter;
|
||||||
import net.minecraft.util.math.*;
|
import net.minecraft.util.math.*;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
import qouteall.imm_ptl.core.api.PortalAPI;
|
import qouteall.imm_ptl.core.api.PortalAPI;
|
||||||
|
import qouteall.imm_ptl.core.portal.Portal;
|
||||||
|
import qouteall.imm_ptl.core.portal.global_portals.GlobalPortalStorage;
|
||||||
import qouteall.q_misc_util.my_util.DQuaternion;
|
import qouteall.q_misc_util.my_util.DQuaternion;
|
||||||
import quimufu.colourful_portals.general_util.LinkedList;
|
import quimufu.colourful_portals.general_util.LinkedList;
|
||||||
|
|
||||||
|
@ -44,17 +46,17 @@ public class ImmersivePortalsLinkingSystem implements PortalLinkingSystem {
|
||||||
BlockBox linkedToPortalBlockBox = linkedToPortalRepresentation.location();
|
BlockBox linkedToPortalBlockBox = linkedToPortalRepresentation.location();
|
||||||
Box linkedToPortalBox = Box.from(linkedToPortalBlockBox);
|
Box linkedToPortalBox = Box.from(linkedToPortalBlockBox);
|
||||||
|
|
||||||
List<qouteall.imm_ptl.core.portal.Portal> outgoingPortals = new ArrayList<>(getPortalList(fromPortalRepresentation));
|
List<Portal> outgoingPortals = new ArrayList<>(getPortalList(fromPortalRepresentation));
|
||||||
|
|
||||||
if (outgoingPortals.size() > 2) {
|
if (outgoingPortals.size() > 2) {
|
||||||
LOGGER.warn("Found more then 2 portals in {}, cleaning up", fromPortalBox);
|
LOGGER.warn("Found more then 2 portals in {}, cleaning up", fromPortalBox);
|
||||||
for (int i = 2; i < outgoingPortals.size(); i++) {
|
for (int i = 2; i < outgoingPortals.size(); i++) {
|
||||||
qouteall.imm_ptl.core.portal.Portal outgoingPortal = outgoingPortals.get(i);
|
Portal outgoingPortal = outgoingPortals.get(i);
|
||||||
outgoingPortal.kill();
|
PortalAPI.removeGlobalPortal(getPortalWorld(fromPortalRepresentation), outgoingPortal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (outgoingPortals.isEmpty()) {
|
if (outgoingPortals.isEmpty()) {
|
||||||
qouteall.imm_ptl.core.portal.Portal portal = qouteall.imm_ptl.core.portal.Portal.ENTITY_TYPE.create(fromPortalWorld);
|
Portal portal = Portal.ENTITY_TYPE.create(fromPortalWorld);
|
||||||
if (portal == null) {
|
if (portal == null) {
|
||||||
LOGGER.error("could not create PortalRepresentation entity for {}", fromPortalRepresentation);
|
LOGGER.error("could not create PortalRepresentation entity for {}", fromPortalRepresentation);
|
||||||
return;
|
return;
|
||||||
|
@ -72,25 +74,19 @@ public class ImmersivePortalsLinkingSystem implements PortalLinkingSystem {
|
||||||
);
|
);
|
||||||
portal.setRotationTransformation(DQuaternion.getRotationBetween(axisW, Vec3d.of(PortalHelper.getAxisW(linkedToPortalBlockBox).getVector())));
|
portal.setRotationTransformation(DQuaternion.getRotationBetween(axisW, Vec3d.of(PortalHelper.getAxisW(linkedToPortalBlockBox).getVector())));
|
||||||
outgoingPortals.add(portal);
|
outgoingPortals.add(portal);
|
||||||
if (!fromPortalWorld.spawnEntity(portal)) {
|
PortalAPI.addGlobalPortal(fromPortalWorld, portal);
|
||||||
LOGGER.error("could not spawn PortalRepresentation entity for {}", fromPortalRepresentation);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (outgoingPortals.size() == 1) {
|
if (outgoingPortals.size() == 1) {
|
||||||
qouteall.imm_ptl.core.portal.Portal portal = PortalAPI.createFlippedPortal(outgoingPortals.getFirst());
|
Portal portal = PortalAPI.createFlippedPortal(outgoingPortals.getFirst());
|
||||||
outgoingPortals.add(portal);
|
outgoingPortals.add(portal);
|
||||||
if (!fromPortalWorld.spawnEntity(portal)) {
|
PortalAPI.addGlobalPortal(fromPortalWorld, portal);
|
||||||
LOGGER.error("could not spawn second PortalRepresentation entity for {}", fromPortalRepresentation);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
for (Portal outgoingPortal : outgoingPortals) {
|
||||||
for (qouteall.imm_ptl.core.portal.Portal outgoingPortal : outgoingPortals) {
|
|
||||||
outgoingPortal.setDestinationDimension(linkedToPortalWorldRegKey);
|
outgoingPortal.setDestinationDimension(linkedToPortalWorldRegKey);
|
||||||
outgoingPortal.setDestination(linkedToPortalBox.getCenter());
|
outgoingPortal.setDestination(linkedToPortalBox.getCenter());
|
||||||
Vec3d axisW = Vec3d.of(PortalHelper.getAxisW(fromPortalBlockBox).getVector());
|
Vec3d axisW = Vec3d.of(PortalHelper.getAxisW(fromPortalBlockBox).getVector());
|
||||||
outgoingPortal.setRotationTransformation(DQuaternion.getRotationBetween(axisW, Vec3d.of(PortalHelper.getAxisW(linkedToPortalBlockBox).getVector())));
|
outgoingPortal.setRotationTransformation(DQuaternion.getRotationBetween(axisW, Vec3d.of(PortalHelper.getAxisW(linkedToPortalBlockBox).getVector())));
|
||||||
outgoingPortal.reloadAndSyncToClient();
|
GlobalPortalStorage.get(getPortalWorld(fromPortalRepresentation)).onDataChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,7 +102,7 @@ public class ImmersivePortalsLinkingSystem implements PortalLinkingSystem {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void unLinkPortal(PortalRepresentation portalRepresentation) {
|
public void unLinkPortal(PortalRepresentation portalRepresentation) {
|
||||||
List<qouteall.imm_ptl.core.portal.Portal> portals = getPortalList(portalRepresentation);
|
List<Portal> portals = getPortalList(portalRepresentation);
|
||||||
portals.forEach(portalEntity -> PortalAPI.removeGlobalPortal(getPortalWorld(portalRepresentation), portalEntity));
|
portals.forEach(portalEntity -> PortalAPI.removeGlobalPortal(getPortalWorld(portalRepresentation), portalEntity));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,10 +127,12 @@ public class ImmersivePortalsLinkingSystem implements PortalLinkingSystem {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<qouteall.imm_ptl.core.portal.Portal> getPortalList(PortalRepresentation portalRepresentation) {
|
private List<Portal> getPortalList(PortalRepresentation portalRepresentation) {
|
||||||
Box portalBox = Box.from(portalRepresentation.location());
|
Box portalBox = Box.from(portalRepresentation.location());
|
||||||
return getPortalWorld(portalRepresentation)
|
getPortalWorld(portalRepresentation)
|
||||||
.getEntitiesByType(TypeFilter.instanceOf(qouteall.imm_ptl.core.portal.Portal.class), portalBox, e -> e.isAlive() && contains(portalBox, e.getBoundingBox()));
|
.getEntitiesByType(TypeFilter.instanceOf(Portal.class), portalBox, e -> e.isAlive() && contains(portalBox, e.getBoundingBox()))
|
||||||
|
.forEach(GlobalPortalStorage::convertNormalPortalIntoGlobalPortal);
|
||||||
|
return GlobalPortalStorage.get(getPortalWorld(portalRepresentation)).data.stream().filter(portal -> contains(portalBox, portal.getThinBoundingBox())).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean contains(Box outside, Box inside) {
|
private boolean contains(Box outside, Box inside) {
|
||||||
|
|
|
@ -8,10 +8,8 @@ import net.minecraft.registry.RegistryKeys;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.server.world.ServerWorld;
|
import net.minecraft.server.world.ServerWorld;
|
||||||
import net.minecraft.util.Identifier;
|
import net.minecraft.util.Identifier;
|
||||||
import net.minecraft.util.math.BlockBox;
|
import net.minecraft.util.math.*;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import net.minecraft.util.math.Direction;
|
|
||||||
import net.minecraft.util.math.Vec3i;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
@ -230,6 +228,10 @@ public class PortalHelper {
|
||||||
return world.getDimensionEntry().getKey().orElseThrow().getValue();
|
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 static class BlockPosIterator implements Iterator<BlockPos> {
|
||||||
private final BlockPos startPos;
|
private final BlockPos startPos;
|
||||||
|
|
|
@ -8,7 +8,6 @@ import net.minecraft.registry.RegistryWrapper;
|
||||||
import net.minecraft.util.Identifier;
|
import net.minecraft.util.Identifier;
|
||||||
import net.minecraft.util.math.BlockBox;
|
import net.minecraft.util.math.BlockBox;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.world.WorldProperties;
|
|
||||||
import org.ladysnake.cca.api.v3.component.Component;
|
import org.ladysnake.cca.api.v3.component.Component;
|
||||||
import quimufu.colourful_portals.general_util.LinkedList;
|
import quimufu.colourful_portals.general_util.LinkedList;
|
||||||
import quimufu.colourful_portals.general_util.Node;
|
import quimufu.colourful_portals.general_util.Node;
|
||||||
|
@ -21,13 +20,11 @@ import static quimufu.colourful_portals.ColourfulPortalsMod.*;
|
||||||
|
|
||||||
public class PortalListComponent implements Component {
|
public class PortalListComponent implements Component {
|
||||||
public static final int CURRENT_VERSION = 1;
|
public static final int CURRENT_VERSION = 1;
|
||||||
private final WorldProperties worldProperties;
|
|
||||||
HashMap<Identifier, LinkedList<PortalRepresentation>> portalsPerPortalBlock = new HashMap<>();
|
HashMap<Identifier, LinkedList<PortalRepresentation>> portalsPerPortalBlock = new HashMap<>();
|
||||||
|
|
||||||
Identifier lastPortalLinkingSystem = Identifier.of(MOD_ID, "immersive_portals_linking_system");
|
Identifier lastPortalLinkingSystem = Identifier.of(MOD_ID, "immersive_portals_linking_system");
|
||||||
|
|
||||||
public PortalListComponent(WorldProperties worldProperties) {
|
public PortalListComponent() {
|
||||||
this.worldProperties = worldProperties;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -40,7 +37,7 @@ public class PortalListComponent implements Component {
|
||||||
LOGGER.warn("portals component comes from a newer version! Hopefully backwards compatible. Proceeding");
|
LOGGER.warn("portals component comes from a newer version! Hopefully backwards compatible. Proceeding");
|
||||||
}
|
}
|
||||||
if (tag.contains("linking_system")) {
|
if (tag.contains("linking_system")) {
|
||||||
lastPortalLinkingSystem = Identifier.tryParse(tag.getString("version"));
|
lastPortalLinkingSystem = Identifier.tryParse(tag.getString("linking_system"));
|
||||||
}
|
}
|
||||||
NbtCompound blocks = tag.getCompound("blocks");
|
NbtCompound blocks = tag.getCompound("blocks");
|
||||||
for (String block : blocks.getKeys()) {
|
for (String block : blocks.getKeys()) {
|
||||||
|
@ -116,7 +113,7 @@ public class PortalListComponent implements Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
LOGGER.info("portals {}", tag);
|
LOGGER.debug("portals {}", tag);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -147,16 +144,12 @@ public class PortalListComponent implements Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
public PortalRepresentation getNext(Identifier blockId, PortalRepresentation portalRepresentationWithDim) {
|
public PortalRepresentation getNext(Identifier blockId, PortalRepresentation portalRepresentationWithDim) {
|
||||||
LOGGER.info("gn");
|
|
||||||
LinkedList<PortalRepresentation> portals = getPortals(blockId);
|
LinkedList<PortalRepresentation> portals = getPortals(blockId);
|
||||||
Node<PortalRepresentation> node;
|
Node<PortalRepresentation> node;
|
||||||
if ((node = portals.getNodeOf(portalRepresentationWithDim)) == null) {
|
if ((node = portals.getNodeOf(portalRepresentationWithDim)) == null) {
|
||||||
|
|
||||||
return portals.getFirst();
|
return portals.getFirst();
|
||||||
}
|
}
|
||||||
PortalRepresentation portalRepresentation = node.getNext() == null ? portals.getFirst() : node.getNext().getValue();
|
return node.getNext() == null ? portals.getFirst() : node.getNext().getValue();
|
||||||
LOGGER.info("gne");
|
|
||||||
return portalRepresentation;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean containsPortal(Identifier blockId, PortalRepresentation portalRepresentation) {
|
public boolean containsPortal(Identifier blockId, PortalRepresentation portalRepresentation) {
|
||||||
|
|
|
@ -15,7 +15,9 @@ import quimufu.colourful_portals.general_util.LinkedList;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Queue;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
import static quimufu.colourful_portals.ColourfulPortalsMod.*;
|
import static quimufu.colourful_portals.ColourfulPortalsMod.*;
|
||||||
|
|
||||||
|
@ -24,6 +26,9 @@ public class PortalManager {
|
||||||
private final PortalListComponent portalCandidateList;
|
private final PortalListComponent portalCandidateList;
|
||||||
private final PortalListComponent portalList;
|
private final PortalListComponent portalList;
|
||||||
|
|
||||||
|
public final AtomicBoolean blockUpdatesPending = new AtomicBoolean(false);
|
||||||
|
public final Queue<Runnable> pendingUpdates = new java.util.LinkedList<>();
|
||||||
|
|
||||||
public PortalLinkingSystem getLinkingSystem() {
|
public PortalLinkingSystem getLinkingSystem() {
|
||||||
return linkingSystem;
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
package quimufu.colourful_portals.portal;
|
package quimufu.colourful_portals.portal;
|
||||||
|
|
||||||
|
import java.util.function.IntSupplier;
|
||||||
|
|
||||||
public record PrioritizedPortalLinkingSystemBuilder(PortalLinkingSystemBuilder portalLinkingSystemBuilder,
|
public record PrioritizedPortalLinkingSystemBuilder(PortalLinkingSystemBuilder portalLinkingSystemBuilder,
|
||||||
int priority) {}
|
IntSupplier priority) {}
|
||||||
|
|
|
@ -13,7 +13,6 @@ public enum NullableAxis implements StringIdentifiable {
|
||||||
private final Direction.Axis axis;
|
private final Direction.Axis axis;
|
||||||
|
|
||||||
NullableAxis(Direction.Axis axis) {
|
NullableAxis(Direction.Axis axis) {
|
||||||
|
|
||||||
this.axis = axis;
|
this.axis = axis;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
20
src/main/java/quimufu/colourful_portals/util/Procedure.java
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
package quimufu.colourful_portals.util;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface Procedure {
|
||||||
|
void run();
|
||||||
|
|
||||||
|
default Procedure andThen(Procedure after){
|
||||||
|
return () -> {
|
||||||
|
this.run();
|
||||||
|
after.run();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
default Procedure compose(Procedure before){
|
||||||
|
return () -> {
|
||||||
|
before.run();
|
||||||
|
this.run();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,7 +3,6 @@ package quimufu.colourful_portals.util;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.util.math.Direction;
|
import net.minecraft.util.math.Direction;
|
||||||
import net.minecraft.util.math.Vec3d;
|
import net.minecraft.util.math.Vec3d;
|
||||||
import quimufu.colourful_portals.ColourfulPortalsMod;
|
|
||||||
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -72,8 +71,6 @@ public class RaycastHelper {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//ColourfulPortalsMod.LOGGER.info("{}, {}: {} -> {}", hitAfter,axis, from, to);
|
|
||||||
|
|
||||||
return BlockPos.ofFloored(from.add(diff.multiply(hitAfter)))
|
return BlockPos.ofFloored(from.add(diff.multiply(hitAfter)))
|
||||||
.equals(blockPos);
|
.equals(blockPos);
|
||||||
}
|
}
|
||||||
|
|
358
src/main/java/quimufu/colourful_portals/util/TeleportHelper.java
Normal file
|
@ -0,0 +1,358 @@
|
||||||
|
package quimufu.colourful_portals.util;
|
||||||
|
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.block.Blocks;
|
||||||
|
import net.minecraft.entity.Entity;
|
||||||
|
import net.minecraft.entity.LivingEntity;
|
||||||
|
import net.minecraft.entity.mob.MobEntity;
|
||||||
|
import net.minecraft.registry.Registries;
|
||||||
|
import net.minecraft.registry.RegistryKey;
|
||||||
|
import net.minecraft.registry.RegistryKeys;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.server.ServerTask;
|
||||||
|
import net.minecraft.server.network.ServerPlayerEntity;
|
||||||
|
import net.minecraft.server.world.ChunkTicketType;
|
||||||
|
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.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.chunk.Chunk;
|
||||||
|
import net.minecraft.world.dimension.DimensionType;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.joml.Random;
|
||||||
|
import org.joml.Vector3f;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import quimufu.colourful_portals.ColourfulPortalsMod;
|
||||||
|
import quimufu.colourful_portals.config.ColourfulPortalConfig;
|
||||||
|
import quimufu.colourful_portals.mixin.ServerWorldAccessor;
|
||||||
|
import quimufu.colourful_portals.portal.PortalHelper;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.ConcurrentSkipListSet;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
public class TeleportHelper extends ServerTask {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(TeleportHelper.class);
|
||||||
|
public static final int TICK_DELAY = 2;
|
||||||
|
private final Random random;
|
||||||
|
private final MinecraftServer minecraftServer;
|
||||||
|
private final ConcurrentSkipListSet<TeleportRequest> toTeleport = new ConcurrentSkipListSet<>();
|
||||||
|
private static TeleportHelper INSTANCE;
|
||||||
|
private final AtomicBoolean tickScheduled = new AtomicBoolean(false);
|
||||||
|
private int lastExecTick;
|
||||||
|
private final ScheduledExecutorService sleeperExecutor = Executors.newSingleThreadScheduledExecutor();
|
||||||
|
|
||||||
|
private static TeleportHelper getInstance(MinecraftServer server) {
|
||||||
|
if (INSTANCE == null) {
|
||||||
|
INSTANCE = new TeleportHelper(server);
|
||||||
|
}
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TeleportHelper(MinecraftServer server) {
|
||||||
|
super(server.getTicks(), null);
|
||||||
|
this.minecraftServer = server;
|
||||||
|
this.random = new Random();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private boolean targetValid(Entity entity, ServerWorld world, Vector3f targetPos, boolean force) {
|
||||||
|
Box boundingBox = entity.getDimensions(entity.getPose())
|
||||||
|
.getBoxAt(new Vec3d(targetPos))
|
||||||
|
.stretch(0, -1, 0);
|
||||||
|
boolean foundAir = false;
|
||||||
|
boolean foundNonAir = false;
|
||||||
|
for (BlockPos pos : PortalHelper.blockPosInBox(boundingBox)) {
|
||||||
|
BlockState blockState = 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 (foundNonAir) && (foundAir || force);
|
||||||
|
}
|
||||||
|
|
||||||
|
private @Nullable TeleportTarget getTarget(Entity entity, ServerWorld serverWorld, Vector3f from, ServerWorld targetWorld, BlockPos targetBlockPos) {
|
||||||
|
minecraftServer.getProfiler().push("getChunk");
|
||||||
|
Chunk chunk = targetWorld.getChunk(targetBlockPos);
|
||||||
|
minecraftServer.getProfiler().pop();
|
||||||
|
|
||||||
|
if (isEmptyPosition(targetWorld, targetBlockPos, chunk)) {
|
||||||
|
log.info("empty at {}, retrying", targetBlockPos);
|
||||||
|
TeleportHelper.markForTeleport(entity, from, serverWorld);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Vector3f targetPos = Vec3d.of(targetBlockPos).toVector3f();
|
||||||
|
int width = MathHelper.ceil(entity.getBoundingBox().getLengthX());
|
||||||
|
int depth = MathHelper.ceil(entity.getBoundingBox().getLengthZ());
|
||||||
|
targetPos.add((width % 2) * 0.5F, 0, (depth % 2) * 0.5F);
|
||||||
|
minecraftServer.getProfiler().push("valid check");
|
||||||
|
int tries = 0;
|
||||||
|
while (!targetValid(entity, targetWorld, targetPos, tries > targetWorld.getLogicalHeight() * 2)) {
|
||||||
|
if (tries > targetWorld.getLogicalHeight() * 4) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
targetPos.y = getTargetY(targetWorld);
|
||||||
|
tries++;
|
||||||
|
}
|
||||||
|
minecraftServer.getProfiler().pop();
|
||||||
|
return new TeleportTarget(targetWorld, new Vec3d(targetPos), entity.getVelocity(), entity.getYaw(), entity.getPitch(), TeleportTarget.NO_OP);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isEmptyPosition(ServerWorld world, BlockPos target, Chunk chunk) {
|
||||||
|
minecraftServer.getProfiler().push("sampleHeightmap");
|
||||||
|
int height = chunk.sampleHeightmap(Heightmap.Type.WORLD_SURFACE, target.getX() & 0xF, target.getZ() & 0xF) + 1;
|
||||||
|
minecraftServer.getProfiler().pop();
|
||||||
|
return height == world.getBottomY();
|
||||||
|
}
|
||||||
|
|
||||||
|
private @Nullable ServerWorld getTargetWorld(ServerWorld serverWorld) {
|
||||||
|
if (random.nextFloat() < 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, Vector3f pos) {
|
||||||
|
|
||||||
|
double distance = ColourfulPortalConfig.minPearlDistance +
|
||||||
|
random.nextFloat() *
|
||||||
|
(ColourfulPortalConfig.maxPearlDistance - ColourfulPortalConfig.minPearlDistance);
|
||||||
|
|
||||||
|
double angle = Math.PI * 2 * random.nextFloat();
|
||||||
|
int targetY = getTargetY(toWorld);
|
||||||
|
|
||||||
|
Vec3d target = new Vec3d(pos.x + Math.cos(angle) * distance, targetY, pos.z + 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 + (random.nextInt(toWorld.getLogicalHeight() - 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void tryTeleport(Entity entity, Vector3f from, ServerWorld serverWorld, BlockPos to, ServerWorld toWorld) {
|
||||||
|
if (entity == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (entity.hasVehicle()) {
|
||||||
|
entity.detach();
|
||||||
|
}
|
||||||
|
minecraftServer.getProfiler().push("getTarget");
|
||||||
|
TeleportTarget target = getTarget(entity, serverWorld, from, toWorld, to);
|
||||||
|
minecraftServer.getProfiler().pop();
|
||||||
|
if (target == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
prepareTarget(target, entity);
|
||||||
|
((ServerWorldAccessor) serverWorld).getEntityList()
|
||||||
|
.add(entity);
|
||||||
|
|
||||||
|
minecraftServer.getProfiler().push("teleportTo");
|
||||||
|
if (entity instanceof ServerPlayerEntity serverPlayerEntity) {
|
||||||
|
if (serverPlayerEntity.networkHandler.isConnectionOpen()) {
|
||||||
|
|
||||||
|
Entity entityAfterTeleport = entity.teleportTo(target);
|
||||||
|
if (entityAfterTeleport == null) {
|
||||||
|
minecraftServer.getProfiler().pop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
entityAfterTeleport.onLanding();
|
||||||
|
serverPlayerEntity.clearCurrentExplosion();
|
||||||
|
entityAfterTeleport.damage(entityAfterTeleport.getDamageSources().fall(), 5.0f);
|
||||||
|
serverPlayerEntity.playSoundToPlayer(SoundEvents.ENTITY_PLAYER_TELEPORT, SoundCategory.PLAYERS, 1F, 0.75F);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Entity entityAfterTeleport = entity.teleportTo(target);
|
||||||
|
if (entityAfterTeleport == null) {
|
||||||
|
minecraftServer.getProfiler().pop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
entityAfterTeleport.onLanding();
|
||||||
|
serverWorld.playSound(entityAfterTeleport, entityAfterTeleport.getBlockPos(),
|
||||||
|
SoundEvents.ENTITY_PLAYER_TELEPORT, SoundCategory.NEUTRAL,
|
||||||
|
1F, 0.75F);
|
||||||
|
}
|
||||||
|
minecraftServer.getProfiler().pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void addTeleportRequest(Entity entity, Vector3f from,
|
||||||
|
ServerWorld fromWorld,
|
||||||
|
boolean originalInvulnerability) {
|
||||||
|
ServerWorld targetWorld = getTargetWorld(fromWorld);
|
||||||
|
if (targetWorld == null) {
|
||||||
|
log.info("couldn't find target world");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
BlockPos targetBlockPos = getTargetPos(fromWorld, targetWorld, from);
|
||||||
|
if (entity instanceof MobEntity mobEntity
|
||||||
|
&& !mobEntity.isPersistent()
|
||||||
|
&& !mobEntity.cannotDespawn()
|
||||||
|
&& mobEntity.canImmediatelyDespawn(targetBlockPos.getSquaredDistance(new Vec3d(from)))
|
||||||
|
&& !targetWorld.isChunkLoaded(targetBlockPos)) {
|
||||||
|
log.info("despawning {} instead of teleporting it OOB", mobEntity.getName().getString());
|
||||||
|
|
||||||
|
((ServerWorldAccessor) fromWorld).getEntityList().add(entity);
|
||||||
|
mobEntity.discard();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!canTeleportEntityTo(entity, targetWorld)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
targetWorld.getChunkManager()
|
||||||
|
.addTicket(ChunkTicketType.PORTAL, new ChunkPos(targetBlockPos), 2, targetBlockPos);
|
||||||
|
toTeleport.add(new TeleportRequest(entity.getUuid(),
|
||||||
|
from,
|
||||||
|
fromWorld.getRegistryKey().getValue(),
|
||||||
|
originalInvulnerability,
|
||||||
|
targetBlockPos,
|
||||||
|
targetWorld.getRegistryKey().getValue()
|
||||||
|
));
|
||||||
|
|
||||||
|
if (!tickScheduled.getAndSet(true)) {
|
||||||
|
long nanosPerTick = minecraftServer.getTickManager().getNanosPerTick();
|
||||||
|
sleeperExecutor.schedule(() -> minecraftServer.send(this), nanosPerTick * 16, TimeUnit.NANOSECONDS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
log.info("{}", minecraftServer.getTicks());
|
||||||
|
int nextExecIn = (lastExecTick + TICK_DELAY) - minecraftServer.getTicks();
|
||||||
|
long nanosPerTick = minecraftServer.getTickManager().getNanosPerTick();
|
||||||
|
if (nextExecIn > 0) {
|
||||||
|
minecraftServer.send(this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.lastExecTick = minecraftServer.getTicks();
|
||||||
|
minecraftServer.getProfiler().push("teleportLoaded");
|
||||||
|
teleportLoaded();
|
||||||
|
minecraftServer.getProfiler().pop();
|
||||||
|
log.info("there are currently {} entities awaiting teleportation", toTeleport.size());
|
||||||
|
if (!toTeleport.isEmpty()) {
|
||||||
|
minecraftServer.send(this);
|
||||||
|
} else {
|
||||||
|
tickScheduled.set(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void teleportLoaded() {
|
||||||
|
Iterator<TeleportRequest> iterator = toTeleport.iterator();
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
TeleportRequest teleportRequest = iterator.next();
|
||||||
|
if (teleportRequest == null) {
|
||||||
|
//empty for some reason!
|
||||||
|
iterator.remove();
|
||||||
|
log.error("null teleportRequest");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ServerWorld fromWorld = minecraftServer.getWorld(RegistryKey.of(RegistryKeys.WORLD, teleportRequest.fromWorldId));
|
||||||
|
if (fromWorld == null) {
|
||||||
|
iterator.remove();
|
||||||
|
log.error("lost from world");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ServerWorld toWorld = minecraftServer.getWorld(RegistryKey.of(RegistryKeys.WORLD, teleportRequest.toWorldId));
|
||||||
|
if (toWorld == null) {
|
||||||
|
iterator.remove();
|
||||||
|
log.error("lost to world");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Entity entity = fromWorld.getEntity(teleportRequest.entity);
|
||||||
|
if (entity == null) {
|
||||||
|
iterator.remove();
|
||||||
|
log.error("lost entity");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int x = teleportRequest.to.getX();
|
||||||
|
int z = teleportRequest.to.getZ();
|
||||||
|
if (toWorld.getChunkManager().isChunkLoaded(ChunkSectionPos.getSectionCoord(x), ChunkSectionPos.getSectionCoord(z))) {
|
||||||
|
log.info("chunkLoaded {}", teleportRequest.to);
|
||||||
|
minecraftServer.getProfiler().push("tryTeleport");
|
||||||
|
tryTeleport(entity, teleportRequest.from, fromWorld, teleportRequest.to, toWorld);
|
||||||
|
minecraftServer.getProfiler().pop();
|
||||||
|
iterator.remove();
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
toWorld.getChunkManager()
|
||||||
|
.addTicket(ChunkTicketType.PORTAL, new ChunkPos(teleportRequest.to), 2, teleportRequest.to);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void markForTeleport(Entity entity, Vector3f from, ServerWorld serverWorld) {
|
||||||
|
((ServerWorldAccessor) serverWorld).getEntityList()
|
||||||
|
.remove(entity);
|
||||||
|
boolean originalInvulnerability = entity.isInvulnerable();
|
||||||
|
entity.setInvulnerable(true);
|
||||||
|
getInstance(serverWorld.getServer())
|
||||||
|
.addTeleportRequest(entity, from, serverWorld, originalInvulnerability);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private record TeleportRequest(UUID entity, Vector3f from,
|
||||||
|
Identifier fromWorldId,
|
||||||
|
boolean originalInvulnerability,
|
||||||
|
BlockPos to,
|
||||||
|
Identifier toWorldId) implements Comparable<TeleportRequest> {
|
||||||
|
@Override
|
||||||
|
public int compareTo(@NotNull TeleportHelper.TeleportRequest other) {
|
||||||
|
Comparator<TeleportRequest> comparator = Comparator
|
||||||
|
.comparing((TeleportRequest teleportRequest) -> teleportRequest.entity);
|
||||||
|
return comparator.compare(this, other);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
package quimufu.colourful_portals.util;
|
||||||
|
|
||||||
|
import net.minecraft.entity.Entity;
|
||||||
|
import net.minecraft.entity.EntityDimensions;
|
||||||
|
import net.minecraft.particle.ParticleTypes;
|
||||||
|
import net.minecraft.util.math.Box;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import org.joml.Random;
|
||||||
|
import org.joml.Vector3f;
|
||||||
|
|
||||||
|
public class TeleportParticleHelper {
|
||||||
|
private static final Random random = new Random();
|
||||||
|
|
||||||
|
public static void spawnTeleportationParticles(Entity entity, World world) {
|
||||||
|
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);
|
||||||
|
EntityDimensions dimensions = EntityDimensions.fixed(0.25f, 0.25f);
|
||||||
|
Vector3f endPos = randomInside(dimensions.getBoxAt(entity.getPos())).add(offset);
|
||||||
|
world.addParticle(ParticleTypes.PORTAL,
|
||||||
|
endPos.x, endPos.y, endPos.z,
|
||||||
|
-offset.x, -offset.y, -offset.z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Vector3f randomInside(Box box) {
|
||||||
|
return box.getMinPos().toVector3f()
|
||||||
|
.add(((float) box.getLengthX()) * random.nextFloat(),
|
||||||
|
((float) box.getLengthY()) * random.nextFloat(),
|
||||||
|
((float) box.getLengthZ()) * random.nextFloat());
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,28 +1,39 @@
|
||||||
{
|
{
|
||||||
"block.colourful_portals.portal_block": "Farbenfrohes Portal",
|
"block.colourful_portals.portal_block": "Farbenfrohes Portal",
|
||||||
"block.colourful_portals.portal_fluid_block": "Farbenfrohe Flüssigkeit",
|
"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.black": "Blöcke, die schwarze Portale erzeugen",
|
||||||
"colourful_portals.midnightconfig.blue": "Blöcke, die blaue 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.brown": "Blöcke, die braune Portale erzeugen",
|
||||||
"colourful_portals.midnightconfig.cyan": "Blöcke, die cyanfarbene Portale erzeugen",
|
"colourful_portals.midnightconfig.cyan": "Blöcke, die cyanfarbene Portale erzeugen",
|
||||||
"colourful_portals.midnightconfig.disableImmersivePortals": "Immersive Portals integration deaktivieren",
|
"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.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.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.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_blue": "Blöcke, die hellblaue Portale erzeugen",
|
||||||
"colourful_portals.midnightconfig.light_gray": "Blöcke, die hellgraue 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.lime": "Blöcke, die limonenfarbene Portale erzeugen",
|
||||||
"colourful_portals.midnightconfig.magenta": "Blöcke, die magentafarbene 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.orange": "Blöcke, die orangefarbene Portale erzeugen",
|
||||||
"colourful_portals.midnightconfig.pink": "Blöcke, die rosa 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.purple": "Blöcke, die violette Portale erzeugen",
|
||||||
"colourful_portals.midnightconfig.red": "Blöcke, die rote 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.white": "Blöcke, die weiße Portale erzeugen",
|
||||||
"colourful_portals.midnightconfig.yellow": "Blöcke, die gelbe 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_bright": "Heller Farbmix",
|
||||||
"item.colourful_portals.colour_blob_dark": "Dunkler Farbmix",
|
"item.colourful_portals.colour_blob_dark": "Dunkler Farbmix",
|
||||||
"item.colourful_portals.portal_fluid_bucket": "Farbeimer",
|
"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"
|
||||||
}
|
}
|
|
@ -6,7 +6,8 @@
|
||||||
"colourful_portals.midnightconfig.blue": "Blocks that create blue portals",
|
"colourful_portals.midnightconfig.blue": "Blocks that create blue portals",
|
||||||
"colourful_portals.midnightconfig.brown": "Blocks that create brown portals",
|
"colourful_portals.midnightconfig.brown": "Blocks that create brown portals",
|
||||||
"colourful_portals.midnightconfig.cyan": "Blocks that create cyan 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.gray": "Blocks that create gray portals",
|
||||||
"colourful_portals.midnightconfig.green": "Blocks that create green portals",
|
"colourful_portals.midnightconfig.green": "Blocks that create green portals",
|
||||||
"colourful_portals.midnightconfig.light_blue": "Blocks that create light blue 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.red": "Blocks that create red portals",
|
||||||
"colourful_portals.midnightconfig.white": "Blocks that create white portals",
|
"colourful_portals.midnightconfig.white": "Blocks that create white portals",
|
||||||
"colourful_portals.midnightconfig.yellow": "Blocks that create yellow 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_bright": "Bright Colour Mix",
|
||||||
"item.colourful_portals.colour_blob_dark": "Dark Colour Mix",
|
"item.colourful_portals.colour_blob_dark": "Dark Colour Mix",
|
||||||
"item.colourful_portals.portal_fluid_bucket": "Colourful Bucket",
|
"item.colourful_portals.portal_fluid_bucket": "Colourful Bucket",
|
||||||
|
|
|
@ -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" }
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"parent": "minecraft:item/generated",
|
||||||
|
"textures": {
|
||||||
|
"layer0": "colourful_portals:item/colourful_air_bottle/black"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"parent": "minecraft:item/generated",
|
||||||
|
"textures": {
|
||||||
|
"layer0": "colourful_portals:item/colourful_air_bottle/blue"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"parent": "minecraft:item/generated",
|
||||||
|
"textures": {
|
||||||
|
"layer0": "colourful_portals:item/colourful_air_bottle/brown"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"parent": "minecraft:item/generated",
|
||||||
|
"textures": {
|
||||||
|
"layer0": "colourful_portals:item/colourful_air_bottle/cyan"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"parent": "minecraft:item/generated",
|
||||||
|
"textures": {
|
||||||
|
"layer0": "colourful_portals:item/colourful_air_bottle/gray"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"parent": "minecraft:item/generated",
|
||||||
|
"textures": {
|
||||||
|
"layer0": "colourful_portals:item/colourful_air_bottle/green"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"parent": "minecraft:item/generated",
|
||||||
|
"textures": {
|
||||||
|
"layer0": "colourful_portals:item/colourful_air_bottle/light_blue"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"parent": "minecraft:item/generated",
|
||||||
|
"textures": {
|
||||||
|
"layer0": "colourful_portals:item/colourful_air_bottle/light_gray"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"parent": "minecraft:item/generated",
|
||||||
|
"textures": {
|
||||||
|
"layer0": "colourful_portals:item/colourful_air_bottle/lime"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"parent": "minecraft:item/generated",
|
||||||
|
"textures": {
|
||||||
|
"layer0": "colourful_portals:item/colourful_air_bottle/magenta"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"parent": "minecraft:item/generated",
|
||||||
|
"textures": {
|
||||||
|
"layer0": "colourful_portals:item/colourful_air_bottle/orange"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"parent": "minecraft:item/generated",
|
||||||
|
"textures": {
|
||||||
|
"layer0": "colourful_portals:item/colourful_air_bottle/pink"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"parent": "minecraft:item/generated",
|
||||||
|
"textures": {
|
||||||
|
"layer0": "colourful_portals:item/colourful_air_bottle/purple"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"parent": "minecraft:item/generated",
|
||||||
|
"textures": {
|
||||||
|
"layer0": "colourful_portals:item/colourful_air_bottle/red"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"parent": "minecraft:item/generated",
|
||||||
|
"textures": {
|
||||||
|
"layer0": "colourful_portals:item/colourful_air_bottle/white"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"parent": "minecraft:item/generated",
|
||||||
|
"textures": {
|
||||||
|
"layer0": "colourful_portals:item/colourful_air_bottle/yellow"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"parent": "minecraft:item/generated",
|
||||||
|
"textures": {
|
||||||
|
"layer0": "colourful_portals:item/colourful_pearl"
|
||||||
|
}
|
||||||
|
}
|
|
@ -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"
|
||||||
|
]
|
||||||
|
}
|
|
@ -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"
|
||||||
|
]
|
||||||
|
}
|
|
@ -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"
|
||||||
|
]
|
||||||
|
}
|
|
@ -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"
|
||||||
|
]
|
||||||
|
}
|
|
@ -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"
|
||||||
|
]
|
||||||
|
}
|
|
@ -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"
|
||||||
|
]
|
||||||
|
}
|
|
@ -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"
|
||||||
|
]
|
||||||
|
}
|
|
@ -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"
|
||||||
|
]
|
||||||
|
}
|
|
@ -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"
|
||||||
|
]
|
||||||
|
}
|
|
@ -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"
|
||||||
|
]
|
||||||
|
}
|
|
@ -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"
|
||||||
|
]
|
||||||
|
}
|
|
@ -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"
|
||||||
|
]
|
||||||
|
}
|
|
@ -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"
|
||||||
|
]
|
||||||
|
}
|
|
@ -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"
|
||||||
|
]
|
||||||
|
}
|
|
@ -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"
|
||||||
|
]
|
||||||
|
}
|
|
@ -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"
|
||||||
|
]
|
||||||
|
}
|
|
@ -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"
|
||||||
|
]
|
||||||
|
}
|
11
src/main/resources/assets/colourful_portals/sounds.json
Normal 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
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
After Width: | Height: | Size: 572 B |
After Width: | Height: | Size: 362 B |
After Width: | Height: | Size: 358 B |
After Width: | Height: | Size: 358 B |
After Width: | Height: | Size: 358 B |
After Width: | Height: | Size: 358 B |
After Width: | Height: | Size: 358 B |
After Width: | Height: | Size: 362 B |
After Width: | Height: | Size: 358 B |
After Width: | Height: | Size: 373 B |
After Width: | Height: | Size: 361 B |