This commit is contained in:
Waterpicker 2023-05-06 05:27:48 -05:00
parent 37717a1c59
commit 113eb04e0d
146 changed files with 9112 additions and 463 deletions

View file

@ -1,10 +1,22 @@
package org.dimdev.dimdoors; package org.dimdev.dimdoors;
import dev.architectury.utils.GameInstance;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.level.Level;
public class DimensionalDoors { public class DimensionalDoors {
public static final String MOD_ID = "dimdoors"; public static final String MOD_ID = "dimdoors";
public static ResourceLocation id(String id) { public static ResourceLocation id(String id) {
return new ResourceLocation(MOD_ID, id); return new ResourceLocation(MOD_ID, id);
} }
public static MinecraftServer getServer() {
return GameInstance.getServer();
}
public static Level getWorld(ResourceKey<Level> world) {
return getServer().getLevel(world);
}
} }

View file

@ -1,13 +1,13 @@
package org.dimdev.dimdoors.api.block; package org.dimdev.dimdoors.api.block;
import net.minecraft.block.BlockState; import net.minecraft.core.BlockPos;
import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.world.ServerWorld; import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.ActionResult; import net.minecraft.world.InteractionResult;
import net.minecraft.util.math.BlockPos; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.util.math.Vec3d; import net.minecraft.world.phys.Vec3;
public interface AfterMoveCollidableBlock { public interface AfterMoveCollidableBlock {
// only triggers on servers // only triggers on servers
ActionResult onAfterMovePlayerCollision(BlockState state, ServerWorld world, BlockPos pos, ServerPlayerEntity player, Vec3d positionChange); InteractionResult onAfterMovePlayerCollision(BlockState state, ServerLevel world, BlockPos pos, ServerPlayer player, Vec3 positionChange);
} }

View file

@ -1,21 +1,21 @@
package org.dimdev.dimdoors.api.block; package org.dimdev.dimdoors.api.block;
import java.util.function.Consumer; import com.mojang.datafixers.util.Pair;
import net.minecraft.core.BlockPos;
import net.minecraft.world.InteractionResultHolder;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.block.BlockState; import java.util.function.Consumer;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.entity.Entity;
import net.minecraft.fluid.FluidState;
import net.minecraft.util.Pair;
import net.minecraft.util.TypedActionResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
/** /**
* Only works in cases where {@link net.minecraft.block.AbstractBlock#getStateForNeighborUpdate AbstractBlock#getStateForNeighborUpdate} returns an air {@link BlockState} * Only works in cases where {@link net.minecraft.block.AbstractBlock#getStateForNeighborUpdate AbstractBlock#getStateForNeighborUpdate} returns an air {@link BlockState}
*/ */
public interface CustomBreakBlock { public interface CustomBreakBlock {
TypedActionResult<Pair<BlockState, Consumer<BlockEntity>>> customBreakBlock(World world, BlockPos pos, BlockState blockState, Entity breakingEntity); InteractionResultHolder<Pair<BlockState, Consumer<BlockEntity>>> customBreakBlock(Level world, BlockPos pos, BlockState blockState, Entity breakingEntity);
/* /*
If this causes any issue mixin into FluidState instead. If this causes any issue mixin into FluidState instead.
@ -26,13 +26,13 @@ public interface CustomBreakBlock {
private final Consumer<BlockEntity> blockEntityConsumer; private final Consumer<BlockEntity> blockEntityConsumer;
public HackyFluidState(BlockState blockState, Consumer<BlockEntity> blockEntityConsumer) { public HackyFluidState(BlockState blockState, Consumer<BlockEntity> blockEntityConsumer) {
super(blockState.getFluidState().getFluid(), blockState.getFluidState().getEntries(), blockState.getFluidState().codec); super(blockState.getFluidState().getType(), blockState.getFluidState().getValues(), blockState.getFluidState().propertiesCodec);
this.blockState = blockState; this.blockState = blockState;
this.blockEntityConsumer = blockEntityConsumer; this.blockEntityConsumer = blockEntityConsumer;
} }
@Override @Override
public BlockState getBlockState() { public BlockState createLegacyBlock() {
return blockState; return blockState;
} }

View file

@ -1,11 +1,11 @@
package org.dimdev.dimdoors.api.block; package org.dimdev.dimdoors.api.block;
import net.minecraft.block.BlockState; import net.minecraft.core.BlockPos;
import net.minecraft.block.entity.BlockEntity; import net.minecraft.world.InteractionResult;
import net.minecraft.util.ActionResult; import net.minecraft.world.level.Level;
import net.minecraft.util.math.BlockPos; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.World; import net.minecraft.world.level.block.state.BlockState;
public interface ExplosionConvertibleBlock { public interface ExplosionConvertibleBlock {
ActionResult explode(World world, BlockPos pos, BlockState state, BlockEntity blockEntity); InteractionResult explode(Level world, BlockPos pos, BlockState state, BlockEntity blockEntity);
} }

View file

@ -1,73 +1,71 @@
package org.dimdev.dimdoors.api.client; package org.dimdev.dimdoors.api.client;
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexFormat;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.model.geom.ModelPart;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderStateShard;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.blockentity.TheEndPortalRenderer;
import net.minecraft.core.Direction;
import net.minecraft.resources.ResourceLocation;
import org.dimdev.dimdoors.DimensionalDoors;
import org.dimdev.dimdoors.client.ModShaders;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import net.minecraft.client.model.ModelPart;
import net.minecraft.client.render.RenderLayer;
import net.minecraft.client.render.RenderPhase;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.VertexFormat;
import net.minecraft.client.render.VertexFormats;
import net.minecraft.client.render.block.entity.EndPortalBlockEntityRenderer;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.Direction;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import org.dimdev.dimdoors.DimensionalDoors;
import org.dimdev.dimdoors.client.ModShaders;
@Environment(EnvType.CLIENT) @Environment(EnvType.CLIENT)
public final class DimensionalPortalRenderer { public final class DimensionalPortalRenderer {
public static final Identifier WARP_PATH; public static final ResourceLocation WARP_PATH;
private static final RenderPhase.ShaderProgram DIMENSIONAL_PORTAL_SHADER; private static final RenderStateShard.ShaderStateShard DIMENSIONAL_PORTAL_SHADER;
private static final RenderLayer RENDER_LAYER; private static final RenderType RENDER_LAYER;
private static final ModelPart MODEL; private static final ModelPart MODEL;
private static final ModelPart TALL_MODEL; private static final ModelPart TALL_MODEL;
public static void renderDimensionalPortal(MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, Transformer transformer, float tickDelta, int light, int overlay) { public static void renderDimensionalPortal(PoseStack matrixStack, MultiBufferSource vertexConsumerProvider, Transformer transformer, float tickDelta, int light, int overlay) {
renderDimensionalPortal(matrixStack, vertexConsumerProvider, transformer, tickDelta, light, overlay, true); renderDimensionalPortal(matrixStack, vertexConsumerProvider, transformer, tickDelta, light, overlay, true);
} }
public static void renderDimensionalPortal(MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, Transformer transformer, float tickDelta, int light, int overlay, boolean tall) { public static void renderDimensionalPortal(PoseStack matrixStack, MultiBufferSource vertexConsumerProvider, Transformer transformer, float tickDelta, int light, int overlay, boolean tall) {
ModelPart model = tall ? TALL_MODEL : MODEL; ModelPart model = tall ? TALL_MODEL : MODEL;
renderModelWithPortalShader(model, matrixStack, vertexConsumerProvider, transformer, tickDelta, light, overlay); renderModelWithPortalShader(model, matrixStack, vertexConsumerProvider, transformer, tickDelta, light, overlay);
} }
public static void renderModelWithPortalShader(ModelPart model, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, Transformer transformer, float tickDelta, int light, int overlay) { public static void renderModelWithPortalShader(ModelPart model, PoseStack matrixStack, MultiBufferSource vertexConsumerProvider, Transformer transformer, float tickDelta, int light, int overlay) {
transformer.transform(matrixStack); transformer.transform(matrixStack);
model.render(matrixStack, vertexConsumerProvider.getBuffer(RENDER_LAYER), light, overlay); model.render(matrixStack, vertexConsumerProvider.getBuffer(RENDER_LAYER), light, overlay);
} }
static { static {
WARP_PATH = DimensionalDoors.id("textures/other/warp.png"); WARP_PATH = DimensionalDoors.id("textures/other/warp.png");
DIMENSIONAL_PORTAL_SHADER = new RenderPhase.ShaderProgram(ModShaders::getDimensionalPortal); DIMENSIONAL_PORTAL_SHADER = new RenderStateShard.ShaderStateShard(ModShaders::getDimensionalPortal);
RENDER_LAYER = RenderLayerFactory.create( RENDER_LAYER = RenderLayerFactory.create(
"dimensional_portal", "dimensional_portal",
VertexFormats.POSITION, DefaultVertexFormat.POSITION,
VertexFormat.DrawMode.QUADS, VertexFormat.Mode.QUADS,
256, 256,
false, false,
false, false,
RenderLayer.MultiPhaseParameters.builder() RenderType.CompositeState.builder()
.program(DIMENSIONAL_PORTAL_SHADER) .setShaderState(DIMENSIONAL_PORTAL_SHADER)
.texture( .setTextureState(
RenderPhase.Textures.create() RenderStateShard.MultiTextureStateShard.builder()
.add(EndPortalBlockEntityRenderer.SKY_TEXTURE, false, false) .add(TheEndPortalRenderer.END_SKY_LOCATION, false, false)
.add(WARP_PATH, false, false) .add(WARP_PATH, false, false)
.build() .build()
) )
.build(false) .createCompositeState(false)
); );
Set<Direction> directions = new HashSet<>(List.of(Direction.values())); Set<Direction> directions = new HashSet<>(List.of(Direction.values()));
ModelPart.Cuboid small = new ModelPart.Cuboid(0, 0, 0.2f, 0.2f, -0.1f, 15.8f, 15.8f, 0.01F, 0, 0, 0, false, 1024, 1024, directions); ModelPart.Cube small = new ModelPart.Cube(0, 0, 0.2f, 0.2f, -0.1f, 15.8f, 15.8f, 0.01F, 0, 0, 0, false, 1024, 1024, directions);
MODEL = new ModelPart(Collections.singletonList(small), Collections.emptyMap()); MODEL = new ModelPart(Collections.singletonList(small), Collections.emptyMap());
ModelPart.Cuboid big = new ModelPart.Cuboid(0, 0, 0.2f, 0.2f, -0.1f, 15.8f, 31.8f, 0.01F, 0, 0, 0, false, 1024, 1024, directions); ModelPart.Cube big = new ModelPart.Cube(0, 0, 0.2f, 0.2f, -0.1f, 15.8f, 31.8f, 0.01F, 0, 0, 0, false, 1024, 1024, directions);
TALL_MODEL = new ModelPart(Collections.singletonList(big), Collections.emptyMap()); TALL_MODEL = new ModelPart(Collections.singletonList(big), Collections.emptyMap());
} }
} }

View file

@ -1,16 +1,13 @@
package org.dimdev.dimdoors.api.client; package org.dimdev.dimdoors.api.client;
import net.minecraft.client.render.RenderLayer; import com.mojang.blaze3d.vertex.VertexFormat;
import net.minecraft.client.render.VertexFormat;
import net.fabricmc.api.EnvType; import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment; import net.fabricmc.api.Environment;
import net.minecraft.client.renderer.RenderType;
import org.dimdev.dimdoors.mixin.client.accessor.RenderLayerAccessor;
@Environment(EnvType.CLIENT) @Environment(EnvType.CLIENT)
public class RenderLayerFactory { public class RenderLayerFactory {
public static RenderLayer create(String name, VertexFormat vertexFormat, VertexFormat.DrawMode drawMode, int expectedBufferSize, boolean hasCrumbling, boolean translucent, RenderLayer.MultiPhaseParameters phases) { public static RenderType create(String name, VertexFormat vertexFormat, VertexFormat.Mode drawMode, int expectedBufferSize, boolean hasCrumbling, boolean translucent, RenderType.CompositeState phases) {
return RenderLayerAccessor.callOf(name, vertexFormat, drawMode, expectedBufferSize, hasCrumbling, translucent, phases); return RenderType.create(name, vertexFormat, drawMode, expectedBufferSize, hasCrumbling, translucent, phases);
} }
} }

View file

@ -1,7 +1,7 @@
package org.dimdev.dimdoors.api.entity; package org.dimdev.dimdoors.api.entity;
import net.minecraft.util.math.Vec3d; import net.minecraft.world.phys.Vec3;
public interface LastPositionProvider { public interface LastPositionProvider {
Vec3d getLastPos(); Vec3 getLastPos();
} }

View file

@ -1,28 +1,27 @@
package org.dimdev.dimdoors.api.event; package org.dimdev.dimdoors.api.event;
import net.minecraft.entity.player.PlayerEntity; import dev.architectury.event.Event;
import net.minecraft.util.ActionResult; import dev.architectury.event.EventFactory;
import net.minecraft.util.Hand; import net.minecraft.world.InteractionHand;
import net.minecraft.util.hit.BlockHitResult; import net.minecraft.world.InteractionResult;
import net.minecraft.world.World; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import net.fabricmc.fabric.api.event.Event; import net.minecraft.world.phys.BlockHitResult;
import net.fabricmc.fabric.api.event.EventFactory;
public interface UseItemOnBlockCallback { public interface UseItemOnBlockCallback {
Event<UseItemOnBlockCallback> EVENT = EventFactory.createArrayBacked(UseItemOnBlockCallback.class, Event<UseItemOnBlockCallback> EVENT = EventFactory.of(
listeners -> (player, world, hand, hitresult) -> { listeners -> (player, world, hand, hitresult) -> {
for (UseItemOnBlockCallback event : listeners) { for (UseItemOnBlockCallback event : listeners) {
ActionResult result = event.useItemOnBlock(player, world, hand, hitresult); InteractionResult result = event.useItemOnBlock(player, world, hand, hitresult);
if (result != ActionResult.PASS) { if (result != InteractionResult.PASS) {
return result; return result;
} }
} }
return ActionResult.PASS; return InteractionResult.PASS;
} }
); );
ActionResult useItemOnBlock(PlayerEntity player, World world, Hand hand, BlockHitResult hitResult); InteractionResult useItemOnBlock(Player player, Level world, InteractionHand hand, BlockHitResult hitResult);
} }

View file

@ -1,26 +1,27 @@
package org.dimdev.dimdoors.api.util; package org.dimdev.dimdoors.api.util;
import com.mojang.serialization.Codec;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.TickTask;
import net.minecraft.util.StringRepresentable;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import net.minecraft.block.entity.BlockEntity; public enum BlockPlacementType implements StringRepresentable {
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.ServerTask;
import net.minecraft.util.StringIdentifiable;
import net.minecraft.world.World;
public enum BlockPlacementType implements StringIdentifiable {
// TODO: do we need some update fluids only option? // TODO: do we need some update fluids only option?
SECTION_NO_UPDATE_QUEUE_BLOCK_ENTITY("section_no_update_queue_block_entity", true, false, BlockPlacementType::queueBlockEntity), SECTION_NO_UPDATE_QUEUE_BLOCK_ENTITY("section_no_update_queue_block_entity", true, false, BlockPlacementType::queueBlockEntity),
SECTION_NO_UPDATE("section_no_update", true, false, World::addBlockEntity), SECTION_NO_UPDATE("section_no_update", true, false, Level::setBlockEntity),
SECTION_UPDATE("section_update", true, true, World::addBlockEntity), SECTION_UPDATE("section_update", true, true, Level::setBlockEntity),
SET_BLOCK_STATE("set_block_state", false, false, World::addBlockEntity), SET_BLOCK_STATE("set_block_state", false, false, Level::setBlockEntity),
SET_BLOCK_STATE_QUEUE_BLOCK_ENTITY("set_block_state_queue_block_entity", false, false, BlockPlacementType::queueBlockEntity); SET_BLOCK_STATE_QUEUE_BLOCK_ENTITY("set_block_state_queue_block_entity", false, false, BlockPlacementType::queueBlockEntity);
private final static Map<String, BlockPlacementType> idMap = new HashMap<>(); private final static Map<String, BlockPlacementType> idMap = new HashMap<>();
public static final Codec<BlockPlacementType> CODEC = StringIdentifiable.createCodec(BlockPlacementType::values); public static final Codec<BlockPlacementType> CODEC = StringRepresentable.fromEnum(BlockPlacementType::values);
static { static {
for (BlockPlacementType type : BlockPlacementType.values()) { for (BlockPlacementType type : BlockPlacementType.values()) {
@ -31,10 +32,10 @@ public enum BlockPlacementType implements StringIdentifiable {
final String id; final String id;
final boolean useSection; final boolean useSection;
final boolean markForUpdate; final boolean markForUpdate;
final BiConsumer<World, BlockEntity> blockEntityPlacer; final BiConsumer<Level, BlockEntity> blockEntityPlacer;
BlockPlacementType(String id, boolean useSection, boolean markForUpdate, BiConsumer<World, BlockEntity> blockEntityPlacer) { BlockPlacementType(String id, boolean useSection, boolean markForUpdate, BiConsumer<Level, BlockEntity> blockEntityPlacer) {
this.id = id; this.id = id;
this.useSection = useSection; this.useSection = useSection;
this.markForUpdate = markForUpdate; this.markForUpdate = markForUpdate;
@ -49,7 +50,7 @@ public enum BlockPlacementType implements StringIdentifiable {
return markForUpdate; return markForUpdate;
} }
public BiConsumer<World, BlockEntity> getBlockEntityPlacer() { public BiConsumer<Level, BlockEntity> getBlockEntityPlacer() {
return blockEntityPlacer; return blockEntityPlacer;
} }
@ -61,13 +62,13 @@ public enum BlockPlacementType implements StringIdentifiable {
return idMap.get(id); return idMap.get(id);
} }
private static void queueBlockEntity(World world, BlockEntity blockEntity) { private static void queueBlockEntity(Level world, BlockEntity blockEntity) {
MinecraftServer server = world.getServer(); MinecraftServer server = world.getServer();
server.send(new ServerTask(server.getTicks(), () -> world.addBlockEntity(blockEntity))); server.tell(new TickTask(server.getTickCount(), () -> world.setBlockEntity(blockEntity)));
} }
@Override @Override
public String asString() { public String getSerializedName() {
return id; return id;
} }
} }

View file

@ -2,43 +2,41 @@ package org.dimdev.dimdoors.api.util;
import com.mojang.serialization.Codec; import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder; import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.core.BlockPos;
import net.minecraft.block.BlockState; import net.minecraft.core.registries.Registries;
import net.minecraft.block.entity.BlockEntity; import net.minecraft.nbt.CompoundTag;
import net.minecraft.fluid.FluidState; import net.minecraft.resources.ResourceKey;
import net.minecraft.nbt.NbtCompound; import net.minecraft.resources.ResourceLocation;
import net.minecraft.registry.RegistryKey; import net.minecraft.server.level.ServerLevel;
import net.minecraft.registry.RegistryKeys; import net.minecraft.world.level.Level;
import net.minecraft.server.world.ServerWorld; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.util.Identifier; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.util.math.BlockPos; import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.World;
import org.dimdev.dimdoors.DimensionalDoors; import org.dimdev.dimdoors.DimensionalDoors;
public class Location { public class Location {
public static final Codec<Location> CODEC = RecordCodecBuilder.create(instance -> { public static final Codec<Location> CODEC = RecordCodecBuilder.create(instance -> {
return instance.group(World.CODEC.fieldOf("world").forGetter(location -> { return instance.group(Level.RESOURCE_KEY_CODEC.fieldOf("world").forGetter(location -> {
return location.world; return location.world;
}), BlockPos.CODEC.fieldOf("pos").forGetter(location -> { }), BlockPos.CODEC.fieldOf("pos").forGetter(location -> {
return location.pos; return location.pos;
})).apply(instance, Location::new); })).apply(instance, Location::new);
}); });
public final RegistryKey<World> world; public final ResourceKey<Level> world;
public final BlockPos pos; public final BlockPos pos;
public Location(RegistryKey<World> world, BlockPos pos) { public Location(ResourceKey<Level> world, BlockPos pos) {
this.world = world; this.world = world;
this.pos = pos; this.pos = pos;
} }
public Location(ServerWorld world, int x, int y, int z) { public Location(ServerLevel world, int x, int y, int z) {
this(world, new BlockPos(x, y, z)); this(world, new BlockPos(x, y, z));
} }
public Location(ServerWorld world, BlockPos pos) { public Location(ServerLevel world, BlockPos pos) {
this(world.getRegistryKey(), pos); this(world.dimension(), pos);
} }
public int getX() { public int getX() {
@ -81,25 +79,25 @@ public class Location {
return this.world.hashCode() * 31 + this.pos.hashCode(); return this.world.hashCode() * 31 + this.pos.hashCode();
} }
public RegistryKey<World> getWorldId() { public ResourceKey<Level> getWorldId() {
return this.world; return this.world;
} }
public ServerWorld getWorld() { public ServerLevel getWorld() {
return DimensionalDoors.getServer().getWorld(this.world); return DimensionalDoors.getServer().getLevel(this.world);
} }
public static NbtCompound toNbt(Location location) { public static CompoundTag toNbt(Location location) {
NbtCompound nbt = new NbtCompound(); CompoundTag nbt = new CompoundTag();
nbt.putString("world", location.world.getValue().toString()); nbt.putString("world", location.world.location().toString());
nbt.putIntArray("pos", new int[]{location.getX(), location.getY(), location.getZ()}); nbt.putIntArray("pos", new int[]{location.getX(), location.getY(), location.getZ()});
return nbt; return nbt;
} }
public static Location fromNbt(NbtCompound nbt) { public static Location fromNbt(CompoundTag nbt) {
int[] pos = nbt.getIntArray("pos"); int[] pos = nbt.getIntArray("pos");
return new Location( return new Location(
RegistryKey.of(RegistryKeys.WORLD, new Identifier(nbt.getString("world"))), ResourceKey.create(Registries.DIMENSION, new ResourceLocation(nbt.getString("world"))),
new BlockPos(pos[0], pos[1], pos[2]) new BlockPos(pos[0], pos[1], pos[2])
); );
} }

View file

@ -1,35 +1,35 @@
package org.dimdev.dimdoors.api.util; package org.dimdev.dimdoors.api.util;
import net.minecraft.nbt.NbtCompound; import net.minecraft.core.BlockPos;
import net.minecraft.registry.RegistryKey; import net.minecraft.core.registries.Registries;
import net.minecraft.registry.RegistryKeys; import net.minecraft.nbt.CompoundTag;
import net.minecraft.util.Identifier; import net.minecraft.resources.ResourceKey;
import net.minecraft.util.math.BlockPos; import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.World; import net.minecraft.world.level.Level;
public class RotatedLocation extends Location { public class RotatedLocation extends Location {
public final float yaw; public final float yaw;
public final float pitch; public final float pitch;
public RotatedLocation(RegistryKey<World> world, BlockPos pos, float yaw, float pitch) { public RotatedLocation(ResourceKey<Level> world, BlockPos pos, float yaw, float pitch) {
super(world, pos); super(world, pos);
this.yaw = yaw; this.yaw = yaw;
this.pitch = pitch; this.pitch = pitch;
} }
public static NbtCompound serialize(RotatedLocation location) { public static CompoundTag serialize(RotatedLocation location) {
NbtCompound nbt = new NbtCompound(); CompoundTag nbt = new CompoundTag();
nbt.putString("world", location.world.getValue().toString()); nbt.putString("world", location.world.location().toString());
nbt.putIntArray("pos", new int[]{location.getX(), location.getY(), location.getZ()}); nbt.putIntArray("pos", new int[]{location.getX(), location.getY(), location.getZ()});
nbt.putFloat("yaw", location.pitch); nbt.putFloat("yaw", location.pitch);
nbt.putFloat("pitch", location.pitch); nbt.putFloat("pitch", location.pitch);
return nbt; return nbt;
} }
public static RotatedLocation deserialize(NbtCompound nbt) { public static RotatedLocation deserialize(CompoundTag nbt) {
int[] pos = nbt.getIntArray("pos"); int[] pos = nbt.getIntArray("pos");
return new RotatedLocation( return new RotatedLocation(
RegistryKey.of(RegistryKeys.WORLD, new Identifier(nbt.getString("world"))), ResourceKey.create(Registries.DIMENSION, new ResourceLocation(nbt.getString("world"))),
new BlockPos(pos[0], pos[1], pos[2]), new BlockPos(pos[0], pos[1], pos[2]),
nbt.getFloat("yaw"), nbt.getFloat("yaw"),
nbt.getFloat("pitch") nbt.getFloat("pitch")

View file

@ -1,18 +1,18 @@
package org.dimdev.dimdoors.block; package org.dimdev.dimdoors.block;
import net.minecraft.block.BlockSetType; import net.minecraft.sounds.SoundEvent;
import net.minecraft.sound.SoundEvent; import net.minecraft.sounds.SoundEvents;
import net.minecraft.sound.SoundEvents; import net.minecraft.world.level.block.state.properties.BlockSetType;
public interface DoorSoundProvider { public interface DoorSoundProvider {
public static final DoorSoundProvider DUMMY = new DoorSoundProvider() {}; public static final DoorSoundProvider DUMMY = new DoorSoundProvider() {};
// TODO: remove these two // TODO: remove these two
public default SoundEvent getOpenSound() { public default SoundEvent getOpenSound() {
return SoundEvents.BLOCK_WOODEN_DOOR_OPEN; return SoundEvents.WOODEN_DOOR_OPEN;
} }
public default SoundEvent getCloseSound() { public default SoundEvent getCloseSound() {
return SoundEvents.BLOCK_WOODEN_DOOR_CLOSE; return SoundEvents.WOODEN_DOOR_CLOSE;
} }
default BlockSetType getSetType() { default BlockSetType getSetType() {

View file

@ -1,7 +1,11 @@
package org.dimdev.dimdoors.block; package org.dimdev.dimdoors.block;
import dev.architectury.registry.client.rendering.RenderTypeRegistry;
import dev.architectury.registry.registries.DeferredRegister; import dev.architectury.registry.registries.DeferredRegister;
import dev.architectury.registry.registries.RegistrySupplier; import dev.architectury.registry.registries.RegistrySupplier;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.core.registries.Registries; import net.minecraft.core.registries.Registries;
import net.minecraft.world.item.BlockItem; import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.DyeColor; import net.minecraft.world.item.DyeColor;
@ -231,11 +235,11 @@ public final class ModBlocks {
return block; return block;
} }
// @Environment(EnvType.CLIENT) @Environment(EnvType.CLIENT)
// public static void initClient() { public static void initClient() {
// BlockRenderLayerMap.INSTANCE.putBlocks(RenderLayer.getCutout(), ModBlocks.QUARTZ_DOOR, ModBlocks.GOLD_DOOR); RenderTypeRegistry.register(RenderType.cutout(), ModBlocks.QUARTZ_DOOR.get(), ModBlocks.GOLD_DOOR.get());
// DoorData.DOORS.forEach(door -> BlockRenderLayerMap.INSTANCE.putBlock(door, RenderLayer.getCutout())); // DoorData.DOORS.forEach(door -> BlockRenderLayerMap.INSTANCE.putBlock(door, RenderLayer.getCutout()));
// } }
public static RegistrySupplier<Block> ancientFabricFromDye(DyeColor color) { public static RegistrySupplier<Block> ancientFabricFromDye(DyeColor color) {
return ANCIENT_FABRIC_BLOCKS.get(color); return ANCIENT_FABRIC_BLOCKS.get(color);

View file

@ -0,0 +1,70 @@
package org.dimdev.dimdoors.client;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.core.BlockPos;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;
@Environment(EnvType.CLIENT)
public class CustomBreakBlockHandler {
private static final Map<BlockPos, BreakBlockInfo> customBreakBlockMap = new ConcurrentHashMap<>();
private static final ReentrantLock lock = new ReentrantLock();
public static Map<BlockPos, BreakBlockInfo> getCustomBreakBlockMap(int ticks) {
lock.lock();
Set<BlockPos> expired = customBreakBlockMap.entrySet().stream().filter(entry -> ticks - entry.getValue().getLastUpdateTick() > 400).map(entry -> entry.getKey()).collect(Collectors.toSet());
expired.forEach(customBreakBlockMap::remove);
Map<BlockPos, BreakBlockInfo> copy = new HashMap<>(customBreakBlockMap);
lock.unlock();
return copy;
}
public static void customBreakBlock(BlockPos pos, int stage, int ticks) {
lock.lock();
if (stage < 0 || stage > 10) {
customBreakBlockMap.remove(pos);
} else {
if (customBreakBlockMap.containsKey(pos)) {
BreakBlockInfo info = customBreakBlockMap.get(pos);
info.setStage(stage);
info.setLastUpdateTick(ticks);
} else {
customBreakBlockMap.put(pos, new BreakBlockInfo(stage, ticks));
}
}
lock.unlock();
}
public static class BreakBlockInfo {
private int stage;
private int lastUpdateTick;
private BreakBlockInfo(int stage, int lastUpdateTick) {
this.stage = stage;
this.lastUpdateTick = lastUpdateTick;
}
public void setStage(int stage) {
this.stage = stage;
}
public int getStage() {
return stage;
}
public void setLastUpdateTick(int lastUpdateTick) {
this.lastUpdateTick = lastUpdateTick;
}
public int getLastUpdateTick() {
return lastUpdateTick;
}
}
}

View file

@ -0,0 +1,90 @@
package org.dimdev.dimdoors.client;
import com.flowpowered.math.TrigMath;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import dev.architectury.utils.GameInstance;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.render.LightmapTextureManager;
import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.text.Text;
import net.minecraft.util.Hand;
import net.minecraft.world.InteractionHand;
import org.dimdev.dimdoors.DimensionalDoors;
import org.dimdev.dimdoors.api.util.RGBA;
import org.dimdev.dimdoors.block.entity.DetachedRiftBlockEntity;
import org.dimdev.dimdoors.block.entity.RiftBlockEntity;
import org.dimdev.dimdoors.client.tesseract.Tesseract;
import org.dimdev.dimdoors.item.ModItems;
import org.dimdev.dimdoors.rift.targets.IdMarker;
import java.util.Objects;
@Environment(EnvType.CLIENT)
public class DetachedRiftBlockEntityRenderer implements BlockEntityRenderer<DetachedRiftBlockEntity> {
public static final ResourceLocation TESSERACT_PATH = DimensionalDoors.id("textures/other/tesseract.png");
private static final RGBA DEFAULT_COLOR = new RGBA(1, 0.5f, 1, 1);
private static final Tesseract TESSERACT = new Tesseract();
private static final RiftCurves.PolygonInfo CURVE = RiftCurves.CURVES.get(0);
@Override
public void render(DetachedRiftBlockEntity rift, float tickDelta, PoseStack matrices, MultiBufferSource vcs, int breakProgress, int alpha) {
if(GameInstance.getClient().player != null && GameInstance.getClient().player.getItemInHand(InteractionHand.MAIN_HAND).is(ModItems.RIFT_CONFIGURATION_TOOL.get()) && rift.getData().getDestination() instanceof IdMarker idMarker) {
matrices.pushPose();
matrices.translate(0.5, 0.5, 0.5);
GameInstance.getClient().font.drawInBatch(Component.literal(String.valueOf(idMarker.getId())), 0f,0f, 0xffffffff, false, matrices.last().pose(), vcs, TextRenderer.TextLayerType.NORMAL, 0x000000, LightmapTextureManager.MAX_LIGHT_COORDINATE);
matrices.popPose();
}
if (DimensionalDoors.getConfig().getGraphicsConfig().showRiftCore) {
this.renderTesseract(vcs.getBuffer(MyRenderLayer.TESSERACT), rift, matrices, tickDelta);
} else {
long timeLeft = RiftBlockEntity.showRiftCoreUntil - System.currentTimeMillis();
if (timeLeft >= 0) {
this.renderTesseract(vcs.getBuffer(MyRenderLayer.TESSERACT), rift, matrices, tickDelta);
}
}
this.renderCrack(vcs.getBuffer(MyRenderLayer.CRACK), matrices, rift);
}
private void renderCrack(VertexConsumer vc, PoseStack matrices, DetachedRiftBlockEntity rift) {
matrices.pushPose();
matrices.translate(0.5, 0.5, 0.5);
RiftCrackRenderer.drawCrack(matrices.last().pose(), vc, 0, CURVE, DimensionalDoors.getConfig().getGraphicsConfig().riftSize * rift.size / 150, 0);//0xF1234568L * rift.hashCode());
matrices.popPose();
}
private void renderTesseract(VertexConsumer vc, DetachedRiftBlockEntity rift, PoseStack matrices, float tickDelta) {
double radian = this.nextAngle(rift, tickDelta) * TrigMath.DEG_TO_RAD;
RGBA color = rift.getColor();
if (Objects.equals(color, RGBA.NONE)) {
color = DEFAULT_COLOR;
}
matrices.pushPose();
matrices.translate(0.5, 0.5, 0.5);
matrices.scale(0.25f, 0.25f, 0.25f);
TESSERACT.draw(matrices.last().pose(), vc, color, radian);
matrices.popPose();
}
private double nextAngle(DetachedRiftBlockEntity rift, float tickDelta) {
rift.renderAngle = (rift.renderAngle + 5 * tickDelta) % 360;
return rift.renderAngle;
}
}

View file

@ -0,0 +1,108 @@
package org.dimdev.dimdoors.client;
import java.util.List;
import com.mojang.blaze3d.systems.RenderSystem;
import org.joml.Matrix4f;
import net.minecraft.client.render.BufferBuilder;
import net.minecraft.client.render.GameRenderer;
import net.minecraft.client.render.Tessellator;
import net.minecraft.client.render.VertexFormat;
import net.minecraft.client.render.VertexFormats;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.registry.RegistryKey;
import net.minecraft.util.Identifier;
import net.minecraft.world.World;
import net.fabricmc.fabric.api.client.rendering.v1.DimensionRenderingRegistry;
import org.dimdev.dimdoors.DimensionalDoors;
import org.dimdev.dimdoors.listener.pocket.PocketListenerUtil;
import org.dimdev.dimdoors.world.ModDimensions;
import org.dimdev.dimdoors.world.pocket.type.addon.SkyAddon;
public class DimensionRenderering {
private static final Identifier MOON_RENDER_PATH = DimensionalDoors.id("textures/other/limbo_moon.png");
private static final Identifier SUN_RENDER_PATH = DimensionalDoors.id("textures/other/limbo_sun.png");
public static void initClient() {
DimensionRenderingRegistry.CloudRenderer noCloudRenderer = context -> {
};
DimensionRenderingRegistry.registerCloudRenderer(ModDimensions.LIMBO, noCloudRenderer);
DimensionRenderingRegistry.registerCloudRenderer(ModDimensions.DUNGEON, noCloudRenderer);
DimensionRenderingRegistry.registerCloudRenderer(ModDimensions.PERSONAL, noCloudRenderer);
DimensionRenderingRegistry.registerCloudRenderer(ModDimensions.PUBLIC, noCloudRenderer);
DimensionRenderingRegistry.registerSkyRenderer(ModDimensions.LIMBO, context -> renderLimboSky(context.matrixStack()));
DimensionRenderingRegistry.SkyRenderer pocketRenderer = context -> {
ClientWorld world = context.world();
MatrixStack matrices = context.matrixStack();
List<SkyAddon> skyAddons = PocketListenerUtil.applicableAddonsClient(SkyAddon.class, world, context.camera().getBlockPos());
SkyAddon skyAddon = null;
if (skyAddons.size() > 0) {
// There should really only be one of these.
// If anyone needs to use multiple SkyAddons then go ahead and change this.
skyAddon = skyAddons.get(0);
}
if (skyAddon != null) {
RegistryKey<World> key = skyAddon.getWorld();
DimensionRenderingRegistry.SkyRenderer skyRenderer = DimensionRenderingRegistry.getSkyRenderer(key);
if (skyRenderer != null) {
skyRenderer.render(context);
} else {
if (key.equals(World.END)) {
context.gameRenderer().getClient().worldRenderer.renderEndSky(matrices);
} else if (key.equals(ModDimensions.LIMBO)) {
renderLimboSky(matrices);
}
}
}
};
DimensionRenderingRegistry.registerSkyRenderer(ModDimensions.DUNGEON, pocketRenderer);
DimensionRenderingRegistry.registerSkyRenderer(ModDimensions.PERSONAL, pocketRenderer);
DimensionRenderingRegistry.registerSkyRenderer(ModDimensions.PUBLIC, pocketRenderer);
}
private static void renderLimboSky(MatrixStack matrices) {
Matrix4f matrix4f = matrices.peek().getPositionMatrix();
Tessellator tessellator = Tessellator.getInstance();
BufferBuilder bufferBuilder = tessellator.getBuffer();
RenderSystem.enableBlend();
RenderSystem.defaultBlendFunc();
RenderSystem.depthMask(false);
RenderSystem.setShader(GameRenderer::getPositionTexColorProgram);
RenderSystem.setShaderColor(1, 1, 1, 1);
float s = 30.0F;
RenderSystem.setShader(GameRenderer::getPositionTexProgram);
RenderSystem.setShaderTexture(0, SUN_RENDER_PATH);
bufferBuilder.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE);
bufferBuilder.vertex(matrix4f, -s, 100.0F, -s).texture(0.0F, 0.0F).next();
bufferBuilder.vertex(matrix4f, s, 100.0F, -s).texture(1.0F, 0.0F).next();
bufferBuilder.vertex(matrix4f, s, 100.0F, s).texture(1.0F, 1.0F).next();
bufferBuilder.vertex(matrix4f, -s, 100.0F, s).texture(0.0F, 1.0F).next();
tessellator.draw();
// BufferRenderer.draw(bufferBuilder);
RenderSystem.setShaderTexture(0, MOON_RENDER_PATH);
bufferBuilder.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE);
bufferBuilder.vertex(matrix4f, -s, -100.0F, -s).texture(0.0F, 0.0F).next();
bufferBuilder.vertex(matrix4f, s, -100.0F, -s).texture(1.0F, 0.0F).next();
bufferBuilder.vertex(matrix4f, s, -100.0F, s).texture(1.0F, 1.0F).next();
bufferBuilder.vertex(matrix4f, -s, -100.0F, s).texture(0.0F, 1.0F).next();
tessellator.draw();
// BufferRenderer.draw(bufferBuilder);
RenderSystem.depthMask(true);
// RenderSystem.enableTexture();
RenderSystem.disableBlend();
}
}

View file

@ -0,0 +1,53 @@
package org.dimdev.dimdoors.client;
import java.util.ArrayList;
import java.util.Set;
import java.util.stream.Collectors;
import org.jetbrains.annotations.Nullable;
import net.minecraft.block.Block;
import net.minecraft.client.render.model.UnbakedModel;
import net.minecraft.client.util.ModelIdentifier;
import net.minecraft.registry.Registries;
import net.minecraft.state.property.Property;
import net.minecraft.util.Identifier;
import net.fabricmc.fabric.api.client.model.ModelProviderContext;
import net.fabricmc.fabric.api.client.model.ModelProviderException;
import net.fabricmc.fabric.api.client.model.ModelVariantProvider;
import org.dimdev.dimdoors.DimensionalDoors;
import org.dimdev.dimdoors.block.door.DimensionalDoorBlockRegistrar;
import org.dimdev.dimdoors.item.door.DimensionalDoorItemRegistrar;
public class DimensionalDoorModelVariantProvider implements ModelVariantProvider { //TODO: Move to fabric if needed still
private static final Identifier childItem = DimensionalDoors.id("item/child_item");
@Override
public @Nullable UnbakedModel loadModelVariant(ModelIdentifier modelId, ModelProviderContext context) throws ModelProviderException {
Identifier identifier = new Identifier(modelId.getNamespace(), modelId.getPath());
DimensionalDoorBlockRegistrar blockRegistrar = DimensionalDoors.getDimensionalDoorBlockRegistrar();
if (blockRegistrar.isMapped(identifier)) {
Identifier mapped = blockRegistrar.get(identifier);
//ModelIdentifier newId = new ModelIdentifier(mapped, modelId.getVariant());
//UnbakedModel model = context.loadModel(newId);
//if (model != null) return model;
Block original = Registries.BLOCK.get(mapped);
Set<String> originalProperties = original.getStateManager().getProperties().stream().map(Property::getName).collect(Collectors.toSet());
ArrayList<String> variantArray = new ArrayList<>();
for (String part : modelId.getVariant().split(",")) {
if (originalProperties.contains(part.split("=")[0])) variantArray.add(part);
}
String variant = String.join(",", variantArray);
ModelIdentifier newId = new ModelIdentifier(mapped, variant);
return context.loadModel(newId);
} else if (identifier.getPath().startsWith(DimensionalDoorItemRegistrar.PREFIX)) {
return context.loadModel(childItem);
}
return null;
}
}

View file

@ -0,0 +1,54 @@
package org.dimdev.dimdoors.client;
import dev.architectury.event.events.client.ClientPlayerEvent;
import dev.architectury.registry.client.rendering.BlockEntityRendererRegistry;
import dev.architectury.registry.menu.MenuRegistry;
import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.fabricmc.fabric.api.client.model.ModelLoadingRegistry;
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
import net.minecraft.world.level.block.entity.BlockEntity;
import org.dimdev.dimdoors.block.ModBlocks;
import org.dimdev.dimdoors.block.entity.ModBlockEntityTypes;
import org.dimdev.dimdoors.client.screen.TesselatingLoomScreen;
import org.dimdev.dimdoors.entity.ModEntityTypes;
import org.dimdev.dimdoors.fluid.ModFluids;
import org.dimdev.dimdoors.network.client.ExtendedClientPlayNetworkHandler;
import org.dimdev.dimdoors.particle.ModParticleTypes;
import org.dimdev.dimdoors.screen.ModScreenHandlerTypes;
@Environment(EnvType.CLIENT)
public class DimensionalDoorsClientInitializer implements ClientModInitializer {
@Override
public void onInitializeClient() {
// ModelLoadingRegistry.INSTANCE.registerVariantProvider((manager) -> new DimensionalDoorModelVariantProvider());
MenuRegistry.registerScreenFactory(ModScreenHandlerTypes.TESSELATING_LOOM, TesselatingLoomScreen::new);
ModEntityTypes.initClient();
ModFluids.initClient();
ModBlockEntityTypes.initClient();
BlockEntityRendererRegistry.register(ModBlockEntityTypes.ENTRANCE_RIFT, new BlockEntityRendererProvider<>() {
@Override
public BlockEntityRenderer<BlockEntity> create(Context context) {
return new EntranceRiftBlockEntityRenderer(context);
return null;
}
});
BlockEntityRendererRegistry.register(ModBlockEntityTypes.DETACHED_RIFT, ctx -> new DetachedRiftBlockEntityRenderer());
ModBlocks.initClient();
ModEntityModelLayers.initClient();
ModParticleTypes.initClient();
DimensionRenderering.initClient();
registerListeners();
}
private void registerListeners() {
ClientPlayerEvent.CLIENT_PLAYER_JOIN.register(player -> ((ExtendedClientPlayNetworkHandler) player).getDimDoorsPacketHandler().init());
ClientPlayerEvent.CLIENT_PLAYER_QUIT.register(player -> ((ExtendedClientPlayNetworkHandler) player).getDimDoorsPacketHandler().unregister());
}
}

View file

@ -0,0 +1,35 @@
package org.dimdev.dimdoors.client;
import com.mojang.blaze3d.vertex.PoseStack;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Font;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
import net.minecraft.network.chat.Component;
import net.minecraft.world.InteractionHand;
import org.dimdev.dimdoors.api.client.DimensionalPortalRenderer;
import org.dimdev.dimdoors.block.entity.EntranceRiftBlockEntity;
import org.dimdev.dimdoors.item.ModItems;
import org.dimdev.dimdoors.rift.targets.IdMarker;
@Environment(EnvType.CLIENT)
public class EntranceRiftBlockEntityRenderer implements BlockEntityRenderer<EntranceRiftBlockEntity> {
@Override
public void render(EntranceRiftBlockEntity blockEntity, float tickDelta, PoseStack matrixStack, MultiBufferSource vertexConsumerProvider, int light, int overlay) {
if (Minecraft.getInstance().player != null)
if (Minecraft.getInstance().player.getItemInHand(InteractionHand.MAIN_HAND).is(ModItems.RIFT_CONFIGURATION_TOOL.get()))
if (blockEntity.getData().getDestination() instanceof IdMarker idMarker) {
matrixStack.pushPose();
matrixStack.translate(0.5, 0.5, 0.5);
Minecraft.getInstance().font.drawInBatch(Component.literal(String.valueOf(idMarker.getId())), 0f, 0f, 0xffffffff, false, matrixStack.last().pose(), vertexConsumerProvider, Font.DisplayMode.NORMAL, 0x000000, LightTexture.FULL_BRIGHT);
matrixStack.popPose();
}
DimensionalPortalRenderer.renderDimensionalPortal(matrixStack, vertexConsumerProvider, blockEntity.getTransformer(), tickDelta, light, overlay, blockEntity.isTall());
}
}

View file

@ -0,0 +1,20 @@
package org.dimdev.dimdoors.client;
//import software.bernie.geckolib3.model.AnimatedGeoModel;
//public class MaskModel extends AnimatedGeoModel<MaskEntity> {
// @Override
// public Identifier getModelLocation(MaskEntity object) {
// return Util.id("geo/mob/mask/mask.geo.json");
// }
//
// @Override
// public Identifier getTextureLocation(MaskEntity object) {
// return Util.id("textures/mob/mask/mask.png");
// }
//
// @Override
// public Identifier getAnimationFileLocation(MaskEntity animatable) {
// return Util.id("animations/mob/mask/mask.animation.json");
// }
//}

View file

@ -0,0 +1,11 @@
package org.dimdev.dimdoors.client;
//import software.bernie.geckolib3.renderers.geo.GeoEntityRenderer;
//@Environment(EnvType.CLIENT)
//public class MaskRenderer extends GeoEntityRenderer<MaskEntity> {
// public MaskRenderer(EntityRendererFactory.Context ctx) {
// super(ctx, new MaskModel());
// this.shadowRadius = 0.7f;
// }
//}

View file

@ -0,0 +1,17 @@
package org.dimdev.dimdoors.client;
import dev.architectury.registry.client.level.entity.EntityModelLayerRegistry;
import net.minecraft.client.model.geom.ModelLayerLocation;
import net.minecraft.client.render.entity.model.EntityModelLayer;
import net.fabricmc.fabric.api.client.rendering.v1.EntityModelLayerRegistry;
import org.dimdev.dimdoors.DimensionalDoors;
public class ModEntityModelLayers {
public static ModelLayerLocation MONOLITH = new ModelLayerLocation(DimensionalDoors.id("monolith"), "body");
public static void initClient() {
EntityModelLayerRegistry.register(MONOLITH, MonolithModel::getTexturedModelData);
}
}

View file

@ -0,0 +1,18 @@
package org.dimdev.dimdoors.client;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.renderer.ShaderInstance;
@Environment(EnvType.CLIENT)
public class ModShaders {
private static ShaderInstance DIMENSIONAL_PORTAL = null;
public static void setDimensionalPortal(ShaderInstance dimensionalPortal) {
DIMENSIONAL_PORTAL = dimensionalPortal;
}
public static ShaderInstance getDimensionalPortal() {
return DIMENSIONAL_PORTAL;
}
}

View file

@ -0,0 +1,79 @@
package org.dimdev.dimdoors.client;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.model.EntityModel;
import net.minecraft.client.model.geom.ModelPart;
import net.minecraft.client.model.geom.PartPose;
import net.minecraft.client.model.geom.builders.CubeListBuilder;
import net.minecraft.client.model.geom.builders.LayerDefinition;
import net.minecraft.client.model.geom.builders.MeshDefinition;
import net.minecraft.client.model.geom.builders.PartDefinition;
import net.minecraft.client.renderer.entity.EntityRendererProvider;
import org.dimdev.dimdoors.entity.MonolithEntity;
@Environment(EnvType.CLIENT)
public class MonolithModel extends EntityModel<MonolithEntity> {
private final ModelPart body;
public MonolithModel(EntityRendererProvider.Context context) {
super(MyRenderLayer::getMonolith);
this.body = context.bakeLayer(ModEntityModelLayers.MONOLITH);
}
public static LayerDefinition getTexturedModelData() {
MeshDefinition modelData = new MeshDefinition();
PartDefinition modelPartData = modelData.getRoot();
modelPartData.addOrReplaceChild("body", CubeListBuilder.create().texOffs(0, 0).addBox(-23.5F, -23.5F, 0, 49.0F, 49.0F, 1.0F, false), PartPose.ZERO);
return LayerDefinition.create(modelData, 102, 51);
}
@Override
public void renderToBuffer(PoseStack matrixStack, VertexConsumer consumer, int packedLight, int packedOverlay, float red, float green, float blue, float alpha) {
matrixStack.pushPose();
matrixStack.scale(3.0625f, 3.0625f, 3.0625f);
PoseStack.Pose entry = matrixStack.last();
consumer.vertex(entry.pose(), -1, -0.5f, 0)
.color(red, green, blue, alpha)
.uv(0,0)
.overlayCoords(packedOverlay)
.uv2(packedLight)
.normal(entry.normal(), 0, 0, 1)
.endVertex();
consumer.vertex(entry.pose(), -1, 0.5f, 0)
.color(red, green, blue, alpha)
.uv(0, 1)
.overlayCoords(packedOverlay)
.uv2(packedLight)
.normal(entry.normal(), 0, 0, 1)
.endVertex();
consumer.vertex(entry.pose(), 1, 0.5f, 0)
.color(red, green, blue, alpha)
.uv(1,1)
.overlayCoords(packedOverlay)
.uv2(packedLight)
.normal(entry.normal(), 0, 0, 1)
.endVertex();
consumer.vertex(entry.pose(), 1, -0.5f, 0)
.color(red, green, blue, alpha)
.uv(1, 0)
.overlayCoords(packedOverlay)
.uv2(packedLight)
.normal(entry.normal(), 0, 0, 1)
.endVertex();
matrixStack.popPose();
// this.body.render(matrixStack, consumer, packedLight, packedOverlay);
}
@Override
public void setupAnim(MonolithEntity entity, float limbSwing, float limbSwingAmount, float ageInTicks, float netHeadYaw, float headPitch) {
this.body.yRot = netHeadYaw * 0.017453292F;
this.body.xRot = headPitch * 0.017453292F;
}
}

View file

@ -0,0 +1,64 @@
package org.dimdev.dimdoors.client;
import com.mojang.blaze3d.vertex.PoseStack;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.renderer.entity.EntityRendererProvider;
import net.minecraft.client.renderer.entity.MobRenderer;
import net.minecraft.resources.ResourceLocation;
import org.dimdev.dimdoors.DimensionalDoors;
import org.dimdev.dimdoors.entity.MonolithEntity;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@Environment(EnvType.CLIENT)
public class MonolithRenderer extends MobRenderer<MonolithEntity, MonolithModel> {
public static final List<ResourceLocation> MONOLITH_TEXTURES = Stream.of(
DimensionalDoors.id("textures/mob/monolith/monolith0.png"),
DimensionalDoors.id("textures/mob/monolith/monolith1.png"),
DimensionalDoors.id("textures/mob/monolith/monolith2.png"),
DimensionalDoors.id("textures/mob/monolith/monolith3.png"),
DimensionalDoors.id("textures/mob/monolith/monolith4.png"),
DimensionalDoors.id("textures/mob/monolith/monolith5.png"),
DimensionalDoors.id("textures/mob/monolith/monolith6.png"),
DimensionalDoors.id("textures/mob/monolith/monolith7.png"),
DimensionalDoors.id("textures/mob/monolith/monolith8.png"),
DimensionalDoors.id("textures/mob/monolith/monolith9.png"),
DimensionalDoors.id("textures/mob/monolith/monolith10.png"),
DimensionalDoors.id("textures/mob/monolith/monolith11.png"),
DimensionalDoors.id("textures/mob/monolith/monolith12.png"),
DimensionalDoors.id("textures/mob/monolith/monolith13.png"),
DimensionalDoors.id("textures/mob/monolith/monolith14.png"),
DimensionalDoors.id("textures/mob/monolith/monolith15.png"),
DimensionalDoors.id("textures/mob/monolith/monolith16.png"),
DimensionalDoors.id("textures/mob/monolith/monolith17.png"),
DimensionalDoors.id("textures/mob/monolith/monolith18.png")
).collect(Collectors.toList());
private static MonolithModel INSTANCE;
public MonolithRenderer(EntityRendererProvider.Context ctx) {
super(ctx, INSTANCE = new MonolithModel(ctx), 0);
}
public static MonolithModel getInstance() {
return INSTANCE;
}
@Override
protected void scale(MonolithEntity entity, PoseStack matrices, float amount) {
matrices.scale(entity.getScale(), entity.getScale(), entity.getScale());
}
@Override
protected boolean shouldShowName(MonolithEntity mobEntity) {
return false;
}
@Override
public ResourceLocation getTextureLocation(MonolithEntity entity) {
return MonolithRenderer.MONOLITH_TEXTURES.get(entity.getTextureState());
}
}

View file

@ -0,0 +1,82 @@
package org.dimdev.dimdoors.client;
import com.flowpowered.math.vector.VectorNi;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
import com.mojang.blaze3d.vertex.VertexFormat;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.client.renderer.RenderStateShard;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.RandomSource;
import org.dimdev.dimdoors.DimensionalDoors;
import static org.lwjgl.opengl.GL11.GL_ONE_MINUS_DST_COLOR;
import static org.lwjgl.opengl.GL11.GL_ZERO;
@Environment(EnvType.CLIENT)
public class MyRenderLayer extends RenderType {
public static final ResourceLocation WARP_PATH = DimensionalDoors.id("textures/other/warp.png");
public static final VectorNi COLORLESS = new VectorNi(255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255);
private static final ResourceLocation KEY_PATH = DimensionalDoors.id("textures/other/keyhole.png");
private static final ResourceLocation KEYHOLE_LIGHT = DimensionalDoors.id("textures/other/keyhole_light.png");
private static final RandomSource RANDOM = RandomSource.create(31100L);
public MyRenderLayer(String string, VertexFormat vertexFormat, VertexFormat.Mode drawMode, int j, boolean bl, boolean bl2, Runnable runnable, Runnable runnable2) {
super(string, vertexFormat, drawMode, j, bl, bl2, runnable, runnable2);
}
public static RenderType CRACK = RenderType.create("crack",
DefaultVertexFormat.POSITION_COLOR,
VertexFormat.Mode.QUADS,
256,
false,
false,
CompositeState.builder()
.setCullState(CullStateShard.NO_CULL)
.setLightmapState(RenderStateShard.NO_LIGHTMAP)
.setTextureState(RenderStateShard.NO_TEXTURE)
.setTransparencyState(new TransparencyStateShard("crack_transparency",
() -> {
RenderSystem.enableBlend();
RenderSystem.blendFunc(GL_ONE_MINUS_DST_COLOR, GL_ZERO);
},
() -> {
RenderSystem.disableBlend();
RenderSystem.defaultBlendFunc();
})
)
.setShaderState(RenderStateShard.POSITION_COLOR_SHADER)
.createCompositeState(false)
);
public static RenderType TESSERACT = RenderType.create("tesseract",
DefaultVertexFormat.POSITION_COLOR_TEX,
VertexFormat.Mode.QUADS,
256,
false,
false,
CompositeState.builder()
.setCullState(RenderStateShard.NO_CULL)
.setLightmapState(RenderStateShard.NO_LIGHTMAP)
.setTextureState(new TextureStateShard(DetachedRiftBlockEntityRenderer.TESSERACT_PATH,
false,
false)
)
.setShaderState(RenderStateShard.POSITION_COLOR_TEX_SHADER)
.createCompositeState(false)
);
public static RenderType getMonolith(ResourceLocation texture) {
RenderType.CompositeState multiPhaseParameters = RenderType.CompositeState.builder().setTextureState(new TextureStateShard(texture, false, false))
.setShaderState(new ShaderStateShard(GameRenderer::getRendertypeEntityTranslucentShader))
.setTransparencyState(RenderStateShard.TRANSLUCENT_TRANSPARENCY)
.setCullState(RenderStateShard.NO_CULL)
.setLightmapState(RenderStateShard.LIGHTMAP)
.setDepthTestState(RenderStateShard.NO_DEPTH_TEST)
.setOverlayState(RenderStateShard.OVERLAY).createCompositeState(false);
return RenderType.create("monolith", DefaultVertexFormat.NEW_ENTITY, VertexFormat.Mode.QUADS, 256, true, true, multiPhaseParameters);
}
}

View file

@ -0,0 +1,68 @@
package org.dimdev.dimdoors.client;
import com.mojang.blaze3d.vertex.VertexConsumer;
import net.minecraft.Util;
import org.joml.Matrix4f;
import net.minecraft.client.render.VertexConsumer;
import net.minecraft.util.Util;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import org.dimdev.dimdoors.DimensionalDoors;
@Environment(EnvType.CLIENT)
public final class RiftCrackRenderer {
public static void drawCrack(Matrix4f model, VertexConsumer vc, float riftRotation, RiftCurves.PolygonInfo poly, double size, long riftRandom) {
// Calculate the proper size for the rift render
double scale = size / (poly.maxX - poly.minX);
// Calculate the midpoint of the fractal bounding box
double offsetX = (poly.maxX + poly.minX) / 2d;
double offsetY = (poly.maxY + poly.minY) / 2d;
double offsetZ = 0;
// Changes how far the triangles move
// TODO: Actually seems to control the glow around the rift
float motionMagnitude = 0.6F;
// Changes how quickly the triangles move
float motionSpeed = 0.014f;
// Number of individual jitter waveforms to generate
// changes how "together" the overall motions are
int jCount = 10;
float time = ((Util.getEpochMillis() + riftRandom) % 2000000) * motionSpeed;
double[] jitters = new double[jCount];
double jitterScale = DimensionalDoors.getConfig().getGraphicsConfig().riftJitter * size * size * size / 2000f;
// We use random constants here on purpose just to get different wave forms
double xJitter = jitterScale * Math.sin(1.1f * time*size) * Math.sin(0.8f * time);
double yJitter = jitterScale * Math.sin(1.2f * time*size) * Math.sin(0.9f * time);
double zJitter = jitterScale * Math.sin(1.3f * time*size) * Math.sin(0.7f * time);
// generate a series of waveforms
for (int i = 0; i < jCount; i += 1) {
jitters[i] = Math.sin((1F + i / 10F) * time) * Math.cos(1F - i / 10F * time) * motionMagnitude;
}
// Draw the rift
for (RiftCurves.Point p : poly.points) {
// Reduces most overlap between triangles inside the rift's center
int jIndex = Math.abs((p.x + p.y) * (p.x + p.y + 1) / 2 + p.y);
double x = (p.x + jitters[(jIndex + 1) % jCount] - offsetX) * Math.cos(Math.toRadians(riftRotation)) - jitters[(jIndex + 2) % jCount] * Math.sin(Math.toRadians(riftRotation));
double y = p.y + jitters[jIndex % jCount] - offsetY;
double z = (p.x + jitters[(jIndex + 2) % jCount] - offsetZ) * Math.sin(Math.toRadians(riftRotation)) + jitters[(jIndex + 2) % jCount] * Math.cos(Math.toRadians(riftRotation));
// Scale the rift
x *= scale;
y *= scale;
z *= scale;
vc.vertex(model, (float) (x + xJitter), (float) (y + yJitter), (float) (z + zJitter)).color(0.08f, 0.08f, 0.08f, .3f).endVertex();
}
}
}

View file

@ -0,0 +1,353 @@
package org.dimdev.dimdoors.client;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import org.poly2tri.Poly2Tri;
import org.poly2tri.geometry.polygon.Polygon;
import org.poly2tri.geometry.polygon.PolygonPoint;
import org.poly2tri.triangulation.TriangulationPoint;
import org.poly2tri.triangulation.delaunay.DelaunayTriangle;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
// https://en.wikipedia.org/wiki/L-system
//
// System: {rules, angle, start_string}
// Rules: rule1:rule_2:...:rule_n
// Rule: from_substring>to_substring
//
// Each iteration, rules are applied to the string. After, string
// is interpreted as commands for a pencil on a sheet of paper:
// F - move forward by one step
// + - turn clockwise by angle
// - - turn counter-clockwise by angle
// [ - save state (push to stack)
// ] - restore state (pop from stack)
@Environment(EnvType.CLIENT)
public final class RiftCurves {
public static final List<PolygonInfo> CURVES = new ArrayList<>();
public static final String[] TERDRAGON = {"F>+F----F++++F-", "60", "F"};
public static final String[] DRAGON = {"X>X+YF:Y>FX-Y", "90", "FX"};
public static final String[] TWINDRAGON = {"X>X+YF:Y>FX-Y", "90", "FX--FX"};
public static final String[] VORTEX = {"X>X+YF:Y>FX-Y", "90", "FX---FX"};
static {
CURVES.add(generate(TERDRAGON, 4));
CURVES.add(generate(TERDRAGON, 5));
CURVES.add(generate(TERDRAGON, 7));
CURVES.add(generate(VORTEX, 9));
CURVES.add(generate(VORTEX, 10));
CURVES.add(generate(VORTEX, 11));
CURVES.add(generate(TWINDRAGON, 7));
CURVES.add(generate(TWINDRAGON, 8));
CURVES.add(generate(TWINDRAGON, 9));
CURVES.add(generate(TWINDRAGON, 10));
CURVES.add(generate(DRAGON, 8));
CURVES.add(generate(DRAGON, 9));
CURVES.add(generate(DRAGON, 10));
CURVES.add(generate(DRAGON, 11));
}
private static PolygonInfo generate(String[] args, int steps) {
//Parse the rules from the first index
String[] rules = args[0].split(":");
HashMap<String, String> lSystemsRule = new HashMap<>();
for (String rule : rules) {
String[] parts = rule.split(">");
lSystemsRule.put(parts[0], parts[1]);
}
//get the angle for each turn
int angle = Integer.parseInt(args[1]);
//String to hold the output
//Initialize with starting string
String output;
//generate the l-system
output = generate(args[2], steps, lSystemsRule);
//get the boundary of the polygon
List<Point> polygon = getBoundary(convertToPoints(angle, output, steps));
//replace the boundary of the polygon with a series of points representing triangles for rendering
return new PolygonInfo(tesselate(polygon));
}
/**
* Takes an unordered list of points comprising a fractal curve and builds a
* closed polygon around it
*/
public static List<Point> getBoundary(ArrayList<double[]> input) {
// store max x and y values to create bounding box
int maxY = Integer.MIN_VALUE;
int maxX = Integer.MIN_VALUE;
int minY = Integer.MAX_VALUE;
int minX = Integer.MAX_VALUE;
// store possible singles here
HashSet<Point> singles = new HashSet<>();
// list to store confirmed singles and output in the correct order
ArrayList<Point> output = new ArrayList<>();
// sort into Hashmaps and hashsets to make contains operations possible,
// while testing for duplicates
for (double[] point : input) {
int xCoord = (int) Math.round(point[0]);
int yCoord = (int) Math.round(point[1]);
if (xCoord > maxX) maxX = xCoord;
if (xCoord < minX) minX = xCoord;
if (yCoord > maxY) maxY = yCoord;
if (yCoord < minY) minY = yCoord;
singles.add(new Point(xCoord, yCoord));
}
// find a suitable starting point
Point startPoint = new Point(minX, minY);
Point prevPoint = startPoint;
while (startPoint.y < maxY) {
if (singles.contains(startPoint)) {
break;
}
startPoint = new Point(startPoint.x, startPoint.y + 1);
}
// record the first point so we know where to stop
final Point firstPoint = startPoint;
// determine the direction to start searching from
Point direction = getVector(prevPoint, startPoint);
//output.add(startPoint);
// loop around in a clockwise circle, jumping to the next point when we
// find it and resetting the direction to start seaching from
// to the last found point. This ensures we always find the next
// *outside* point
do {
// get the next point
direction = rotateCounterClockwise(direction);
Point target = new Point(startPoint.x + direction.x, startPoint.y + direction.y);
// see if that point is part of our fractal curve
if (singles.contains(target)) {
if (target.equals(firstPoint)) {
output.remove(output.get(output.size() - 1));
break;
}
// get the vector to start from for the next cycle
direction = getVector(startPoint, target);
// prune zero width spikes
if (output.size() > 1 && output.get(output.size() - 2).equals(target)) {
output.remove(output.size() - 1);
} else {
if (output.contains(target) && !target.equals(output.get(0))) {
int index = output.indexOf(target);
while (output.size() > index) {
output.remove(output.size() - 1);
}
}
output.add(target);
}
startPoint = target;
}
}
while (!(output.get(output.size() - 1).equals(firstPoint) && output.size() > 1) && output.size() < singles.size());
return output;
}
/**
* using a point as a 2d vector, normalize it (sorta)
*/
public static Point getVector(Point origin, Point destination) {
int[] normals = {origin.x - destination.x, origin.y - destination.y};
for (int i = 0; i < normals.length; i++) {
if (normals[i] > 0) {
normals[i] = 1;
} else if (normals[i] == 0) {
normals[i] = 0;
} else if (normals[i] < 0) {
normals[i] = -1;
}
}
return new Point(normals[0], normals[1]);
}
/**
* rotate a normal around the origin
*/
public static Point rotateCounterClockwise(Point previous) {
return new Point(
(int) (previous.x * Math.cos(Math.toRadians(90)) - previous.y * Math.sin(Math.toRadians(90))),
(int) (previous.x * Math.sin(Math.toRadians(90)) + previous.y * Math.cos(Math.toRadians(90)))
);
}
/**
* Take an l-system string and convert it into a series of points on a
* cartesian grid. Designed to keep terdragons oriented the same direction
* regardless of iterations
*/
public static ArrayList<double[]> convertToPoints(double angle, String system, int generations) {
// determine the starting point and rotation to begin drawing from
int rotation = generations % 2 == 0 ? 2 : 4;
double[] currentState = {(generations + rotation) % 4 * 90, 0, 0};
// the output for a totally unordered list of points defining the curve
ArrayList<double[]> output = new ArrayList<>();
// the stack used to deal with branching l-systems that use [ and ]
ArrayDeque<double[]> state = new ArrayDeque<>();
// perform the rules corresponding to each symbol in the l-system
for (Character ch : system.toCharArray()) {
double motion = 1;
// move forward
if (ch == 'F') {
currentState[1] -= Math.cos(Math.toRadians(currentState[0])) * motion;
currentState[2] -= Math.sin(Math.toRadians(currentState[0])) * motion;
output.add(new double[]{currentState[1], currentState[2]});
}
// start branch
if (ch == '[') {
state.push(currentState.clone());
}
// turn left
if (ch == '-') {
currentState = new double[]{(currentState[0] - angle) % 360, currentState[1], currentState[2]};
}
// turn right
if (ch == '+') {
currentState[0] = (currentState[0] + angle) % 360;
}
// end branch and return to previous fork
if (ch == ']') {
currentState = state.pop();
}
}
return output;
}
/**
* grow and l-system string based on the rules provided in the args
*/
public static String generate(String start, int steps, HashMap<String, String> lSystemsRule) {
while (steps > 0) {
StringBuilder output = new StringBuilder();
for (Character ch : start.toCharArray()) {
// get the rule applicable for the variable
String data = lSystemsRule.get(ch.toString());
// handle constants for rule-less symbols
if (data == null) {
data = ch.toString();
}
output.append(data);
}
steps--;
start = output.toString();
}
return start;
}
// a data container class to transmit the important information about the polygon
public static class PolygonInfo {
public final ArrayList<Point> points;
public int maxX;
public final int maxY;
public final int minX;
public final int minY;
public PolygonInfo(ArrayList<Point> points) {
int minX, minY, maxX, maxY;
minX = minY = maxX = maxY = 0;
// Find bounding box of the polygon
this.points = points;
if (points.size() > 0) {
Point firstPoint = points.get(0);
minX = firstPoint.x;
minY = firstPoint.y;
maxX = firstPoint.x;
maxY = firstPoint.y;
for (Point point : points) {
if (point.x < minX) minX = point.x;
if (point.y < minY) minY = point.y;
if (point.x > maxX) maxX = point.x;
if (point.y > maxY) maxY = point.y;
}
}
this.minX = minX;
this.minY = minY;
this.maxX = maxX;
this.maxY = maxY;
}
}
// TODO: Use the GLU tesselator (GPU) instead of poly2tri (CPU): http://wiki.lwjgl.org/wiki/Using_GLU_Tesselator.html
public static ArrayList<Point> tesselate(List<Point> polygon) {
ArrayList<Point> points = new ArrayList<>();
ArrayList<PolygonPoint> polyPoints = new ArrayList<>();
for (Point p : polygon) {
polyPoints.add(new PolygonPoint(p.x, p.y));
}
Polygon poly = new Polygon(polyPoints);
Poly2Tri.triangulate(poly);
ArrayList<DelaunayTriangle> tris = (ArrayList<DelaunayTriangle>) poly.getTriangles();
for (DelaunayTriangle tri : tris) {
for (TriangulationPoint tpoint : tri.points) {
points.add(new Point((int) tpoint.getX(), (int) tpoint.getY()));
}
}
return points;
}
public static class Point {
public final int x;
public final int y;
private Point(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public boolean equals(Object o) {
return o instanceof Point && ((Point) o).x == this.x && ((Point) o).y == this.y;
}
@Override
public int hashCode() {
return this.x * 31 + this.y;
}
}
}

View file

@ -0,0 +1,18 @@
package org.dimdev.dimdoors.client;
import net.minecraft.client.resources.language.I18n;
import net.minecraft.network.chat.Component;
import java.util.List;
public class ToolTipHelper {
public static void processTranslation(List<Component> list, String key, Object... args) {
if(I18n.exists(key)) {
list.add(Component.translatable(key, args));
} else {
for (int i = 0; I18n.exists(key + i); i++) {
list.add(Component.translatable(key + i, args));
}
}
}
}

View file

@ -0,0 +1,57 @@
package org.dimdev.dimdoors.client;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.item.ItemRenderer;
import net.minecraft.client.render.model.json.ModelTransformationMode;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.fabricmc.fabric.api.client.rendering.v1.BuiltinItemRendererRegistry;
import org.dimdev.dimdoors.item.door.DimensionalDoorItemRegistrar;
@Environment(EnvType.CLIENT)
public class UnderlaidChildItemRenderer implements BuiltinItemRendererRegistry.DynamicItemRenderer {//TODO: Move to fabric if needed still
private final ItemStack underlay;
public UnderlaidChildItemRenderer(Item underlay) {
this.underlay = new ItemStack(underlay);
}
public UnderlaidChildItemRenderer(ItemStack underlay) {
this.underlay = underlay;
}
@Override
public void render(ItemStack stack, ModelTransformationMode mode, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay) {
if (!(stack.getItem() instanceof DimensionalDoorItemRegistrar.ChildItem childItem)) throw new UnsupportedOperationException("Can only use UnderlaidChildItemRenderer for ChildItems");
matrices.push();
matrices.translate(0.5D, 0.5D, 0.5D);
ItemRenderer itemRenderer = MinecraftClient.getInstance().getItemRenderer();
// TODO: refactor
matrices.push();
childItem.transform(matrices);
matrices.scale(1, 1, 0.5f);
itemRenderer.renderItem(underlay, ModelTransformationMode.NONE, light, overlay, matrices, vertexConsumers, null, 0);
matrices.pop();
ItemStack originalItemStack = new ItemStack(
childItem.getOriginalItem(),
stack.getCount());
originalItemStack.setNbt(stack.getNbt());
matrices.push();
// childItem.transform(matrices);
itemRenderer.renderItem(originalItemStack, ModelTransformationMode.NONE, light, overlay, matrices, vertexConsumers, null, 0);
matrices.pop();
matrices.pop();
}
}

View file

@ -0,0 +1,13 @@
package org.dimdev.dimdoors.client.config;
import me.shedaniel.autoconfig.AutoConfig;
import net.minecraft.client.gui.screen.Screen;
import org.dimdev.dimdoors.ModConfig;
public class ModMenu {
public static Screen getConfigScreen(Screen previous) {
return AutoConfig.getConfigScreen(ModConfig.class, previous).get();
}
}

View file

@ -0,0 +1,15 @@
package org.dimdev.dimdoors.client.config;
import com.terraformersmc.modmenu.api.ConfigScreenFactory;
import com.terraformersmc.modmenu.api.ModMenuApi;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
@Environment(EnvType.CLIENT)
public class ModMenuImpl implements ModMenuApi {//TODO: Move to fabric
@Override
public ConfigScreenFactory<?> getModConfigScreenFactory() {
return ModMenu::getConfigScreen;
}
}

View file

@ -0,0 +1,105 @@
package org.dimdev.dimdoors.client.screen;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.gui.GuiComponent;
import net.minecraft.client.gui.components.ImageButton;
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
import net.minecraft.client.gui.screens.recipebook.RecipeBookComponent;
import net.minecraft.client.gui.screens.recipebook.RecipeUpdateListener;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.inventory.ClickType;
import net.minecraft.world.inventory.Slot;
import org.dimdev.dimdoors.DimensionalDoors;
import org.dimdev.dimdoors.screen.TesselatingScreenHandler;
public class TesselatingLoomScreen extends AbstractContainerScreen<TesselatingScreenHandler> implements RecipeUpdateListener {
private static final ResourceLocation TEXTURE = DimensionalDoors.id("textures/screen/container/tesselating_loom.png");
private static final ResourceLocation RECIPE_BUTTON_TEXTURE = new ResourceLocation("textures/gui/recipe_button.png");
private final RecipeBookComponent recipeBook = new RecipeBookComponent();
private boolean narrow;
public TesselatingLoomScreen(TesselatingScreenHandler handler, Inventory inventory, Component title) {
super(handler, inventory, title);
}
public void init() {
super.init();
this.narrow = this.width < 379;
this.recipeBook.init(this.width, this.height, this.minecraft, this.narrow, this.menu);
this.leftPos = this.recipeBook.updateScreenPosition(this.width, this.imageWidth);
this.addRenderableWidget(new ImageButton(this.leftPos + 5, this.height / 2 - 49, 20, 18, 0, 0, 19, RECIPE_BUTTON_TEXTURE, (button) -> {
this.recipeBook.toggleVisibility();
this.leftPos = this.recipeBook.updateScreenPosition(this.width, this.imageWidth);
button.setPosition(this.leftPos + 5, this.height / 2 - 49);
}));
this.addWidget(this.recipeBook);
this.setInitialFocus(this.recipeBook);
this.titleLabelX = (this.imageWidth - this.font.width(this.title)) / 2;
}
public void render(PoseStack matrices, int mouseX, int mouseY, float delta) {
this.renderBackground(matrices);
if (this.recipeBook.isVisible() && this.narrow) {
this.renderBg(matrices, delta, mouseX, mouseY);
this.recipeBook.render(matrices, mouseX, mouseY, delta);
} else {
this.recipeBook.render(matrices, mouseX, mouseY, delta);
super.render(matrices, mouseX, mouseY, delta);
this.recipeBook.renderGhostRecipe(matrices, this.leftPos, this.topPos, true, delta);
}
this.renderTooltip(matrices, mouseX, mouseY);
this.recipeBook.renderTooltip(matrices, this.leftPos, this.topPos, mouseX, mouseY);
}
protected void renderBg(PoseStack matrices, float delta, int mouseX, int mouseY) {
RenderSystem.setShader(GameRenderer::getPositionTexShader);
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
RenderSystem.setShaderTexture(0, TEXTURE);
int i = this.leftPos;
int j = (this.height - this.imageHeight) / 2;
GuiComponent.blit(matrices, i, j, 0, 0, this.imageWidth, this.imageWidth);
if (this.menu.isWeaving()) {
int k = (this.menu).getBurnProgress(22);
GuiComponent.blit(matrices, i + 89, j + 34, 176, 0, k + 1, 16);
}
}
protected boolean isHovering(int x, int y, int width, int height, double pointX, double pointY) {
return (!this.narrow || !this.recipeBook.isVisible()) && super.isHovering(x, y, width, height, pointX, pointY);
}
public boolean mouseClicked(double mouseX, double mouseY, int button) {
if (this.recipeBook.mouseClicked(mouseX, mouseY, button)) {
this.setFocused(this.recipeBook);
return true;
} else {
return this.narrow && this.recipeBook.isVisible() || super.mouseClicked(mouseX, mouseY, button);
}
}
protected boolean hasClickedOutside(double mouseX, double mouseY, int left, int top, int button) {
boolean bl = mouseX < (double)left || mouseY < (double)top || mouseX >= (double)(left + this.imageWidth) || mouseY >= (double)(top + this.imageHeight);
return this.recipeBook.hasClickedOutside(mouseX, mouseY, this.leftPos, this.topPos, this.imageWidth, this.imageHeight, button) && bl;
}
protected void slotClicked(Slot slot, int slotId, int button, ClickType actionType) {
super.slotClicked(slot, slotId, button, actionType);
this.recipeBook.slotClicked(slot);
}
public void recipesUpdated() {
this.recipeBook.recipesUpdated();
}
public RecipeBookComponent getRecipeBookComponent() {
return this.recipeBook;
}
}

View file

@ -0,0 +1,77 @@
package org.dimdev.dimdoors.client.tesseract;
import com.flowpowered.math.matrix.Matrix4f;
import com.flowpowered.math.vector.Vector3f;
import com.flowpowered.math.vector.Vector4f;
import com.mojang.blaze3d.vertex.VertexConsumer;
import net.minecraft.client.render.VertexConsumer;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import org.dimdev.dimdoors.api.util.RGBA;
import static com.flowpowered.math.TrigMath.cos;
import static com.flowpowered.math.TrigMath.sin;
@Environment(EnvType.CLIENT)
public class Plane {
Vector4f[] vectors;
public Plane(Vector4f vec1, Vector4f vec2, Vector4f vec3, Vector4f vec4) {
this.vectors = new Vector4f[]{vec1, vec2, vec3, vec4};
}
public void draw(org.joml.Matrix4f model, VertexConsumer vc, RGBA color, double radian) {
drawVertex(model, vc, rotYW(this.vectors[0], radian), 0, 0, color);
drawVertex(model, vc, rotYW(this.vectors[1], radian), 0, 1, color);
drawVertex(model, vc, rotYW(this.vectors[2], radian), 1, 1, color);
drawVertex(model, vc, rotYW(this.vectors[3], radian), 1, 0, color);
}
private static void drawVertex(org.joml.Matrix4f model, VertexConsumer vc, Vector4f vector, int u, int v, RGBA color) {
double scalar = 1d / (vector.getW() + 1);
Vector3f scaled = vector.toVector3().mul(scalar);
vc.vertex(model, scaled.getX(), scaled.getY(), scaled.getZ())
.color(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha())
.texture(u, v)
.next();
}
private static Vector4f rotXW(Vector4f v, double angle) {
return Matrix4f.from(
cos(angle), 0, 0, sin(angle),
0, 1, 0, 0,
0, 0, 1, 0,
-sin(angle), 0, 0, cos(angle))
.transform(v);
}
private static Vector4f rotZW(Vector4f v, double angle) {
return Matrix4f.from(
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, cos(angle), -sin(angle),
0, 0, sin(angle), cos(angle))
.transform(v);
}
private static Vector4f rotYW(Vector4f v, double angle) {
return Matrix4f.from(
1, 0, 0, 0,
0, cos(angle), 0, sin(angle),
0, 0, 1, 0,
0, -sin(angle), 0, cos(angle))
.transform(v);
}
private static Vector4f rotXY(Vector4f v, double angle) {
return Matrix4f.from(
cos(angle), -sin(angle), 0, 0,
sin(angle), cos(angle), 0, 0,
0, 0, 1, 0,
0, 0, 0, 1)
.transform(v);
}
}

View file

@ -0,0 +1,193 @@
package org.dimdev.dimdoors.client.tesseract;
import com.flowpowered.math.vector.Vector4f;
import com.mojang.blaze3d.vertex.VertexConsumer;
import net.minecraft.client.render.VertexConsumer;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import org.dimdev.dimdoors.api.util.RGBA;
@Environment(EnvType.CLIENT)
public class Tesseract {
private final Plane[] planes = new Plane[24];
public Tesseract() {
this.planes[0] = new Plane(
new Vector4f(-0.5f, -0.5f, -0.5f, -0.5f),
new Vector4f(0.5f, -0.5f, -0.5f, -0.5f),
new Vector4f(0.5f, -0.5f, 0.5f, -0.5f),
new Vector4f(-0.5f, -0.5f, 0.5f, -0.5f)
);
this.planes[1] = new Plane(
new Vector4f(-0.5f, 0.5f, -0.5f, -0.5f),
new Vector4f(0.5f, 0.5f, -0.5f, -0.5f),
new Vector4f(0.5f, 0.5f, 0.5f, -0.5f),
new Vector4f(-0.5f, 0.5f, 0.5f, -0.5f)
);
this.planes[2] = new Plane(
new Vector4f(-0.5f, -0.5f, -0.5f, -0.5f),
new Vector4f(0.5f, -0.5f, -0.5f, -0.5f),
new Vector4f(0.5f, 0.5f, -0.5f, -0.5f),
new Vector4f(-0.5f, 0.5f, -0.5f, -0.5f)
);
this.planes[3] = new Plane(
new Vector4f(-0.5f, -0.5f, 0.5f, -0.5f),
new Vector4f(0.5f, -0.5f, 0.5f, -0.5f),
new Vector4f(0.5f, 0.5f, 0.5f, -0.5f),
new Vector4f(-0.5f, 0.5f, 0.5f, -0.5f)
);
this.planes[4] = new Plane(
new Vector4f(-0.5f, -0.5f, -0.5f, -0.5f),
new Vector4f(-0.5f, 0.5f, -0.5f, -0.5f),
new Vector4f(-0.5f, 0.5f, 0.5f, -0.5f),
new Vector4f(-0.5f, -0.5f, 0.5f, -0.5f)
);
this.planes[5] = new Plane(
new Vector4f(0.5f, -0.5f, -0.5f, -0.5f),
new Vector4f(0.5f, 0.5f, -0.5f, -0.5f),
new Vector4f(0.5f, 0.5f, 0.5f, -0.5f),
new Vector4f(0.5f, -0.5f, 0.5f, -0.5f)
);
this.planes[6] = new Plane(
new Vector4f(-0.5f, -0.5f, -0.5f, 0.5f),
new Vector4f(0.5f, -0.5f, -0.5f, 0.5f),
new Vector4f(0.5f, -0.5f, 0.5f, 0.5f),
new Vector4f(-0.5f, -0.5f, 0.5f, 0.5f)
);
this.planes[7] = new Plane(
new Vector4f(-0.5f, 0.5f, -0.5f, 0.5f),
new Vector4f(0.5f, 0.5f, -0.5f, 0.5f),
new Vector4f(0.5f, 0.5f, 0.5f, 0.5f),
new Vector4f(-0.5f, 0.5f, 0.5f, 0.5f)
);
this.planes[8] = new Plane(
new Vector4f(-0.5f, -0.5f, -0.5f, 0.5f),
new Vector4f(0.5f, -0.5f, -0.5f, 0.5f),
new Vector4f(0.5f, 0.5f, -0.5f, 0.5f),
new Vector4f(-0.5f, 0.5f, -0.5f, 0.5f)
);
this.planes[9] = new Plane(
new Vector4f(-0.5f, -0.5f, 0.5f, 0.5f),
new Vector4f(0.5f, -0.5f, 0.5f, 0.5f),
new Vector4f(0.5f, 0.5f, 0.5f, 0.5f),
new Vector4f(-0.5f, 0.5f, 0.5f, 0.5f)
);
this.planes[10] = new Plane(
new Vector4f(-0.5f, -0.5f, -0.5f, 0.5f),
new Vector4f(-0.5f, 0.5f, -0.5f, 0.5f),
new Vector4f(-0.5f, 0.5f, 0.5f, 0.5f),
new Vector4f(-0.5f, -0.5f, 0.5f, 0.5f)
);
this.planes[11] = new Plane(
new Vector4f(0.5f, -0.5f, -0.5f, 0.5f),
new Vector4f(0.5f, 0.5f, -0.5f, 0.5f),
new Vector4f(0.5f, 0.5f, 0.5f, 0.5f),
new Vector4f(0.5f, -0.5f, 0.5f, 0.5f)
);
this.planes[12] = new Plane(
new Vector4f(-0.5f, -0.5f, -0.5f, -0.5f),
new Vector4f(-0.5f, 0.5f, -0.5f, -0.5f),
new Vector4f(-0.5f, 0.5f, -0.5f, 0.5f),
new Vector4f(-0.5f, -0.5f, -0.5f, 0.5f)
);
this.planes[13] = new Plane(
new Vector4f(-0.5f, -0.5f, 0.5f, -0.5f),
new Vector4f(-0.5f, 0.5f, 0.5f, -0.5f),
new Vector4f(-0.5f, 0.5f, 0.5f, 0.5f),
new Vector4f(-0.5f, -0.5f, 0.5f, 0.5f)
);
this.planes[14] = new Plane(
new Vector4f(-0.5f, -0.5f, -0.5f, -0.5f),
new Vector4f(-0.5f, 0.5f, -0.5f, -0.5f),
new Vector4f(-0.5f, 0.5f, 0.5f, -0.5f),
new Vector4f(-0.5f, -0.5f, 0.5f, -0.5f)
);
this.planes[15] = new Plane(
new Vector4f(-0.5f, -0.5f, -0.5f, 0.5f),
new Vector4f(-0.5f, 0.5f, -0.5f, 0.5f),
new Vector4f(-0.5f, 0.5f, 0.5f, 0.5f),
new Vector4f(-0.5f, -0.5f, 0.5f, 0.5f)
);
this.planes[16] = new Plane(
new Vector4f(-0.5f, -0.5f, -0.5f, -0.5f),
new Vector4f(-0.5f, -0.5f, 0.5f, -0.5f),
new Vector4f(-0.5f, -0.5f, 0.5f, 0.5f),
new Vector4f(-0.5f, -0.5f, -0.5f, 0.5f)
);
this.planes[17] = new Plane(
new Vector4f(-0.5f, 0.5f, -0.5f, -0.5f),
new Vector4f(-0.5f, 0.5f, 0.5f, -0.5f),
new Vector4f(-0.5f, 0.5f, 0.5f, 0.5f),
new Vector4f(-0.5f, 0.5f, -0.5f, 0.5f)
);
this.planes[18] = new Plane(
new Vector4f(0.5f, -0.5f, -0.5f, -0.5f),
new Vector4f(0.5f, 0.5f, -0.5f, -0.5f),
new Vector4f(0.5f, 0.5f, -0.5f, 0.5f),
new Vector4f(0.5f, -0.5f, -0.5f, 0.5f)
);
this.planes[19] = new Plane(
new Vector4f(0.5f, -0.5f, 0.5f, -0.5f),
new Vector4f(0.5f, 0.5f, 0.5f, -0.5f),
new Vector4f(0.5f, 0.5f, 0.5f, 0.5f),
new Vector4f(0.5f, -0.5f, 0.5f, 0.5f)
);
this.planes[20] = new Plane(
new Vector4f(0.5f, -0.5f, -0.5f, -0.5f),
new Vector4f(0.5f, 0.5f, -0.5f, -0.5f),
new Vector4f(0.5f, 0.5f, 0.5f, -0.5f),
new Vector4f(0.5f, -0.5f, 0.5f, -0.5f)
);
this.planes[21] = new Plane(
new Vector4f(0.5f, -0.5f, -0.5f, 0.5f),
new Vector4f(0.5f, 0.5f, -0.5f, 0.5f),
new Vector4f(0.5f, 0.5f, 0.5f, 0.5f),
new Vector4f(0.5f, -0.5f, 0.5f, 0.5f)
);
this.planes[22] = new Plane(
new Vector4f(0.5f, -0.5f, -0.5f, -0.5f),
new Vector4f(0.5f, -0.5f, 0.5f, -0.5f),
new Vector4f(0.5f, -0.5f, 0.5f, 0.5f),
new Vector4f(0.5f, -0.5f, -0.5f, 0.5f)
);
this.planes[23] = new Plane(
new Vector4f(0.5f, 0.5f, -0.5f, -0.5f),
new Vector4f(0.5f, 0.5f, 0.5f, -0.5f),
new Vector4f(0.5f, 0.5f, 0.5f, 0.5f),
new Vector4f(0.5f, 0.5f, -0.5f, 0.5f)
);
}
@Environment(EnvType.CLIENT)
public void draw(org.joml.Matrix4f model, VertexConsumer vc, RGBA color, double radian) {
for (Plane plane : this.planes) {
plane.draw(model, vc, color, radian);
}
}
}

View file

@ -0,0 +1,38 @@
package org.dimdev.dimdoors.client.wthit;
import java.util.Objects;
import mcp.mobius.waila.api.IBlockAccessor;
import mcp.mobius.waila.api.IBlockComponentProvider;
import mcp.mobius.waila.api.IPluginConfig;
import mcp.mobius.waila.api.ITooltip;
import net.minecraft.text.MutableText;
import net.minecraft.text.Text;
import net.minecraft.text.TranslatableTextContent;
import net.minecraft.util.Identifier;
import org.dimdev.dimdoors.DimensionalDoors;
import org.dimdev.dimdoors.block.entity.EntranceRiftBlockEntity;
import org.dimdev.dimdoors.rift.targets.VirtualTarget;
// FIXME: is not actually client sided
public enum EntranceRiftProvider implements IBlockComponentProvider {
INSTANCE;
private static final Identifier ID = DimensionalDoors.id("entrance_rift_provider");
@Override
public void appendBody(ITooltip tooltip, IBlockAccessor accessor, IPluginConfig config) {
if (!config.getBoolean(ID)) {
return;
}
EntranceRiftBlockEntity blockEntity = ((EntranceRiftBlockEntity) accessor.getBlockEntity());
VirtualTarget destination = Objects.requireNonNull(blockEntity).getDestination();
if (destination != null) {
Text tKey = Text.translatable(destination.getType().getTranslationKey());
Text main = Text.translatable("dimdoors.destination").append(": ").append(tKey);
tooltip.addLine(main);
}
}
}

View file

@ -0,0 +1,15 @@
package org.dimdev.dimdoors.client.wthit;
import mcp.mobius.waila.api.IRegistrar;
import mcp.mobius.waila.api.IWailaPlugin;
import mcp.mobius.waila.api.TooltipPosition;
import org.dimdev.dimdoors.block.entity.EntranceRiftBlockEntity;
// FIXME: is not actually client sided
public class WthitPlugin implements IWailaPlugin {
@Override
public void register(IRegistrar registrar) {
registrar.addComponent(EntranceRiftProvider.INSTANCE, TooltipPosition.BODY, EntranceRiftBlockEntity.class);
}
}

View file

@ -0,0 +1,65 @@
package org.dimdev.dimdoors.command;
import com.mojang.brigadier.Command;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.arguments.FloatArgumentType;
import net.minecraft.command.argument.DimensionArgumentType;
import net.minecraft.command.argument.Vec3ArgumentType;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.server.command.CommandManager;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.math.EulerAngle;
import net.minecraft.util.math.Vec3d;
import org.dimdev.dimdoors.api.util.Location;
import org.dimdev.dimdoors.api.util.TeleportUtil;
import org.dimdev.dimdoors.api.util.math.MathUtil;
import org.dimdev.dimdoors.world.level.registry.DimensionalRegistry;
public class DimTeleportCommand {
public static void register(CommandDispatcher<ServerCommandSource> dispatcher) {
dispatcher.register(CommandManager.literal("dimteleport")
.requires(source -> source.hasPermissionLevel(4))
.then(CommandManager
.argument("dimension", DimensionArgumentType.dimension())
.executes(ctx -> {
ServerPlayerEntity player = ctx.getSource().getPlayer();
return teleport(player, DimensionArgumentType.getDimensionArgument(ctx, "dimension"), player.getPos(), MathUtil.entityEulerAngle(player));
})
.then(CommandManager
.argument("coordinates", Vec3ArgumentType.vec3())
.executes(ctx -> {
ServerPlayerEntity player = ctx.getSource().getPlayer();
return teleport(player, DimensionArgumentType.getDimensionArgument(ctx, "dimension"), Vec3ArgumentType.getVec3(ctx, "coordinates"), MathUtil.entityEulerAngle(player));
})
.then(CommandManager
.argument("yaw", FloatArgumentType.floatArg())
.executes( ctx -> {
ServerPlayerEntity player = ctx.getSource().getPlayer();
return teleport(player, DimensionArgumentType.getDimensionArgument(ctx, "dimension"), Vec3ArgumentType.getVec3(ctx, "coordinates"), new EulerAngle(player.getPitch(), FloatArgumentType.getFloat(ctx, "yaw"), 0));
})
.then(CommandManager
.argument("pitch", FloatArgumentType.floatArg())
.executes( ctx -> {
ServerPlayerEntity player = ctx.getSource().getPlayer();
return teleport(player, DimensionArgumentType.getDimensionArgument(ctx, "dimension"), Vec3ArgumentType.getVec3(ctx, "coordinates"), new EulerAngle(FloatArgumentType.getFloat(ctx, "pitch"), FloatArgumentType.getFloat(ctx, "yaw"), 0));
})
)
)
)
)
);
}
private static int teleport(Entity entity, ServerWorld dimension, Vec3d pos, EulerAngle angle) {
if(entity instanceof PlayerEntity) {
DimensionalRegistry.getRiftRegistry().setOverworldRift(entity.getUuid(), new Location((ServerWorld) entity.getEntityWorld(), entity.getBlockPos()));
}
TeleportUtil.teleport(entity, dimension, pos, angle, entity.getVelocity());
return Command.SINGLE_SUCCESS;
}
}

View file

@ -0,0 +1,12 @@
package org.dimdev.dimdoors.command;
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
public final class ModCommands {
public static void init() {
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, dedicated) -> {
DimTeleportCommand.register(dispatcher);
PocketCommand.register(dispatcher);
});
}
}

View file

@ -0,0 +1,126 @@
package org.dimdev.dimdoors.command;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import com.mojang.brigadier.Command;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.MutableText;
import net.minecraft.text.Text;
import net.minecraft.text.TranslatableTextContent;
import net.fabricmc.loader.api.FabricLoader;
import org.dimdev.dimdoors.api.util.BlockPlacementType;
import org.dimdev.dimdoors.command.arguments.BlockPlacementTypeArgumentType;
import org.dimdev.dimdoors.command.arguments.PocketTemplateArgumentType;
import org.dimdev.dimdoors.pockets.PocketLoader;
import org.dimdev.dimdoors.pockets.PocketTemplate;
import org.dimdev.dimdoors.util.schematic.SchematicPlacer;
import static net.minecraft.server.command.CommandManager.argument;
import static net.minecraft.server.command.CommandManager.literal;
public class PocketCommand {
private static final Logger LOGGER = LogManager.getLogger();
// TODO: probably move somewhere else
public static final Map<UUID, ServerCommandSource> logSetting = new HashMap<>();
public static void register(CommandDispatcher<ServerCommandSource> dispatcher) {
dispatcher.register(
literal("pocket")
.requires(source -> source.hasPermissionLevel(2))
.then(
literal("schematic")
.then(
literal("place")
.then(
argument("pocket_template", new PocketTemplateArgumentType())
.executes(ctx -> place(ctx.getSource().getPlayer(), PocketTemplateArgumentType.getValue(ctx, "pocket_template"), BlockPlacementType.SECTION_NO_UPDATE))
.then(
argument("placement_type", new BlockPlacementTypeArgumentType())
.executes(ctx -> place(ctx.getSource().getPlayer(), PocketTemplateArgumentType.getValue(ctx, "pocket_template"), BlockPlacementTypeArgumentType.getBlockPlacementType(ctx, "placement_type")))
)
)
)
.then(
literal("load")
.requires(source -> FabricLoader.getInstance().isModLoaded("worldedit"))
.then(
argument("pocket_template", new PocketTemplateArgumentType())
.executes(ctx -> load(ctx.getSource(), PocketTemplateArgumentType.getValue(ctx, "pocket_template")))
)
)
)
.then(
literal("log")
// TODO: make command toggle logging of pocket creation to console if used from console
.then(literal("creation")
.requires(commandSource -> commandSource.getEntity() instanceof ServerPlayerEntity)
.executes(ctx -> {
ServerCommandSource commandSource = ctx.getSource();
UUID playerUUID = commandSource.getPlayer().getUuid();
if (logSetting.containsKey(playerUUID)) {
logSetting.remove(playerUUID);
commandSource.sendFeedback(Text.translatable("commands.pocket.log.creation.off"), false);
} else {
logSetting.put(playerUUID, commandSource);
commandSource.sendFeedback(Text.translatable("commands.pocket.log.creation.on"), false);
}
return Command.SINGLE_SUCCESS;
})
)
)
.then(
literal("dump")
.requires(src -> src.hasPermissionLevel(4))
.executes(ctx -> {
ctx.getSource().sendFeedback(Text.of("Dumping pocket data"), false);
CompletableFuture.runAsync(() -> {
try {
PocketLoader.getInstance().dump();
} catch (Exception e) {
LOGGER.error("Error dumping pocket data", e);
}
}).thenRun(() -> {
ctx.getSource().getServer().execute(() -> {
ctx.getSource().sendFeedback(Text.of("Dumped pocket data"), false);
});
});
return Command.SINGLE_SUCCESS;
})
)
);
}
private static int load(ServerCommandSource source, PocketTemplate template) throws CommandSyntaxException {
try {
return WorldeditHelper.load(source, template);
} catch (NoClassDefFoundError e) {
return 0;
}
}
private static int place(ServerPlayerEntity source, PocketTemplate template, BlockPlacementType blockPlacementType) throws CommandSyntaxException {
SchematicPlacer.place(
template.getSchematic(),
source.getWorld(),
source.getBlockPos(),
blockPlacementType
);
String id = template.getId().toString();
source.getCommandSource().sendFeedback(Text.translatable("commands.pocket.placedSchem", id, "" + source.getBlockPos().getX() + ", " + source.getBlockPos().getY() + ", " + source.getBlockPos().getZ(), source.world.getRegistryKey().getValue().toString()), true);
return Command.SINGLE_SUCCESS;
}
}

View file

@ -0,0 +1,62 @@
package org.dimdev.dimdoors.command;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import com.mojang.brigadier.Command;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.sk89q.jnbt.NBTInputStream;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.extent.clipboard.io.SpongeSchematicReader;
import com.sk89q.worldedit.fabric.FabricAdapter;
import com.sk89q.worldedit.session.ClipboardHolder;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtIo;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.MutableText;
import net.minecraft.text.Text;
import net.minecraft.text.TranslatableTextContent;
import org.dimdev.dimdoors.DimensionalDoors;
import org.dimdev.dimdoors.pockets.PocketTemplate;
import org.dimdev.dimdoors.util.schematic.Schematic;
public class WorldeditHelper {
static int load(ServerCommandSource source, PocketTemplate template) throws CommandSyntaxException {
ServerPlayerEntity player = source.getPlayer();
boolean async = DimensionalDoors.getConfig().getPocketsConfig().asyncWorldEditPocketLoading;
Consumer<Runnable> taskAcceptor = async ? r -> source.getServer().execute(r) : Runnable::run;
Runnable task = () -> {
NbtCompound nbt = Schematic.toNbt(template.getSchematic());
ByteArrayOutputStream stream = new ByteArrayOutputStream();
try {
NbtIo.writeCompressed(nbt, stream);
} catch (IOException e) {
throw new RuntimeException(e); // Can't happen, the stream is a ByteArrayOutputStream
}
Clipboard clipboard;
try {
clipboard = new SpongeSchematicReader(new NBTInputStream(new ByteArrayInputStream(stream.toByteArray()))).read();
} catch (IOException e) {
throw new RuntimeException(e); // Can't happen, the stream is a ByteArrayInputStream
}
taskAcceptor.accept(() -> {
WorldEdit.getInstance().getSessionManager().get(FabricAdapter.adaptPlayer(player)).setClipboard(new ClipboardHolder(clipboard));
source.sendFeedback(Text.translatable("commands.pocket.loadedSchem", template.getId()), true);
});
};
if (async) {
CompletableFuture.runAsync(task);
} else {
task.run();
}
return Command.SINGLE_SUCCESS;
}
}

View file

@ -0,0 +1,20 @@
package org.dimdev.dimdoors.command.arguments;
import com.mojang.brigadier.context.CommandContext;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.arguments.StringRepresentableArgument;
import org.dimdev.dimdoors.api.util.BlockPlacementType;
public class BlockPlacementTypeArgumentType extends StringRepresentableArgument<BlockPlacementType> {
public BlockPlacementTypeArgumentType() {
super(BlockPlacementType.CODEC, BlockPlacementType::values);
}
public static StringRepresentableArgument<BlockPlacementType> blockPlacementType() {
return new BlockPlacementTypeArgumentType();
}
public static BlockPlacementType getBlockPlacementType(CommandContext<CommandSourceStack> context, String id) {
return context.getArgument(id, BlockPlacementType.class);
}
}

View file

@ -0,0 +1,46 @@
package org.dimdev.dimdoors.command.arguments;
import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.arguments.ArgumentType;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.exceptions.DynamicCommandExceptionType;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import net.minecraft.commands.SharedSuggestionProvider;
import net.minecraft.network.chat.Component;
import java.util.*;
import java.util.concurrent.CompletableFuture;
public class EnumArgumentType<T extends Enum<T>> implements ArgumentType<T> {
public static final DynamicCommandExceptionType UNKNOWN_VALUE = new DynamicCommandExceptionType(str -> Component.translatable("commands.generic.unknownValue", str));
private final Map<String, T> values;
private final Set<String> valueList;
public EnumArgumentType(Class<T> enumClass) {
values = new HashMap<>();
for (T enumConstant : enumClass.getEnumConstants()) {
values.put(enumConstant.name().toLowerCase(), enumConstant);
}
valueList = values.keySet();
}
@Override
public T parse(StringReader reader) throws CommandSyntaxException {
String str = reader.readString();
return Optional.ofNullable(str)
.map(values::get)
.orElseThrow(() -> UNKNOWN_VALUE.create(str));
}
@Override
public Collection<String> getExamples() {
return valueList;
}
@Override
public <S> CompletableFuture<Suggestions> listSuggestions(CommandContext<S> context, SuggestionsBuilder builder) {
return SharedSuggestionProvider.suggest(valueList, builder);
}
}

View file

@ -0,0 +1,60 @@
package org.dimdev.dimdoors.command.arguments;
import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.arguments.ArgumentType;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.exceptions.DynamicCommandExceptionType;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import net.minecraft.commands.SharedSuggestionProvider;
import net.minecraft.network.chat.Component;
import org.dimdev.dimdoors.api.util.Path;
import org.dimdev.dimdoors.api.util.SimpleTree;
import org.dimdev.dimdoors.pockets.PocketLoader;
import org.dimdev.dimdoors.pockets.PocketTemplate;
import java.util.Collection;
import java.util.Optional;
import java.util.TreeSet;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
public class PocketTemplateArgumentType implements ArgumentType<PocketTemplate> {
public static final DynamicCommandExceptionType UNKNOWN_POCKET_TEMPLATE = new DynamicCommandExceptionType(s -> Component.translatable("commands.pocket.unknownPocketTemplate",s));
@Override
public PocketTemplate parse(StringReader reader) throws CommandSyntaxException {
String strValue = reader.readString();
Path<String> value = Path.stringPath(strValue);
if (!getPocketTemplates().containsKey(value)) {
throw UNKNOWN_POCKET_TEMPLATE.create(value.toString());
}
return getPocketTemplates().get(value);
}
@Override
public <S> CompletableFuture<Suggestions> listSuggestions(CommandContext<S> context, SuggestionsBuilder builder) {
return SharedSuggestionProvider.suggest(getExamples(), builder);
}
@Override
public Collection<String> getExamples() {
return getPocketTemplates()
.keySet()
.parallelStream()
.map(path -> path.reduce(String::concat))
.filter(Optional::isPresent)
.map(Optional::get)
.map(id -> "\"" + id + "\"")
.collect(Collectors.toCollection(TreeSet::new));
}
private SimpleTree<String, PocketTemplate> getPocketTemplates() {
return PocketLoader.getInstance().getTemplates();
}
public static PocketTemplate getValue(CommandContext<?> context, final String name) {
return context.getArgument(name, PocketTemplate.class);
}
}

View file

@ -0,0 +1,13 @@
package org.dimdev.dimdoors.criteria;
import net.minecraft.advancements.CriteriaTriggers;
public class ModCriteria {
public static final RiftTrackedCriterion RIFT_TRACKED = CriteriaTriggers.register(new RiftTrackedCriterion());
public static final TagBlockBreakCriteria TAG_BLOCK_BREAK = CriteriaTriggers.register(new TagBlockBreakCriteria());
public static final PocketSpawnPointSetCondition POCKET_SPAWN_POINT_SET = CriteriaTriggers.register(new PocketSpawnPointSetCondition());
public static void init() {
}
}

View file

@ -0,0 +1,34 @@
package org.dimdev.dimdoors.criteria;
import com.google.gson.JsonObject;
import net.minecraft.advancements.critereon.AbstractCriterionTriggerInstance;
import net.minecraft.advancements.critereon.DeserializationContext;
import net.minecraft.advancements.critereon.EntityPredicate;
import net.minecraft.advancements.critereon.SimpleCriterionTrigger;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import org.dimdev.dimdoors.DimensionalDoors;
public class PocketSpawnPointSetCondition extends SimpleCriterionTrigger<PocketSpawnPointSetCondition.Conditions> {
public static final ResourceLocation ID = DimensionalDoors.id("pocket_spawn_point_set");
@Override
protected Conditions createInstance(JsonObject jsonObject, EntityPredicate.Composite composite, DeserializationContext deserializationContext) {
return new Conditions(composite);
}
public void trigger(ServerPlayer player) {
this.trigger(player, t -> true);
}
@Override
public ResourceLocation getId() {
return ID;
}
public static class Conditions extends AbstractCriterionTriggerInstance {
public Conditions(EntityPredicate.Composite playerPredicate) {
super(ID, playerPredicate);
}
}
}

View file

@ -0,0 +1,34 @@
package org.dimdev.dimdoors.criteria;
import com.google.gson.JsonObject;
import net.minecraft.advancements.critereon.AbstractCriterionTriggerInstance;
import net.minecraft.advancements.critereon.DeserializationContext;
import net.minecraft.advancements.critereon.EntityPredicate;
import net.minecraft.advancements.critereon.SimpleCriterionTrigger;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import org.dimdev.dimdoors.DimensionalDoors;
public class RiftTrackedCriterion extends SimpleCriterionTrigger<RiftTrackedCriterion.Conditions> {
public static final ResourceLocation ID = DimensionalDoors.id("rift_tracked");
@Override
protected Conditions createInstance(JsonObject obj, EntityPredicate.Composite playerPredicate, DeserializationContext predicateDeserializer) {
return new Conditions(playerPredicate);
}
public void trigger(ServerPlayer player) {
this.trigger(player, t -> true);
}
@Override
public ResourceLocation getId() {
return ID;
}
public static class Conditions extends AbstractCriterionTriggerInstance {
public Conditions(EntityPredicate.Composite playerPredicate) {
super(ID, playerPredicate);
}
}
}

View file

@ -0,0 +1,51 @@
package org.dimdev.dimdoors.criteria;
import com.google.gson.JsonObject;
import net.minecraft.advancements.critereon.*;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.tags.TagKey;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import org.dimdev.dimdoors.DimensionalDoors;
import java.util.Objects;
public class TagBlockBreakCriteria extends SimpleCriterionTrigger<TagBlockBreakCriteria.Conditions> {
public static final ResourceLocation ID = DimensionalDoors.id("tag_block_break");
@Override
protected Conditions createInstance(JsonObject obj, EntityPredicate.Composite playerPredicate, DeserializationContext predicateDeserializer) {
return new Conditions(playerPredicate, TagKey.create(Registries.BLOCK, ResourceLocation.tryParse(obj.get("tag").getAsString())));
}
public void trigger(ServerPlayer player, BlockState block) {
this.trigger(player, c -> block.is(c.getBlockTag()));
}
@Override
public ResourceLocation getId() {
return ID;
}
public static class Conditions extends AbstractCriterionTriggerInstance {
private final TagKey<Block> blockTag;
public Conditions(EntityPredicate.Composite playerPredicate, TagKey<Block> blockTag) {
super(ID, playerPredicate);
this.blockTag = Objects.requireNonNull(blockTag);
}
@Override
public JsonObject serializeToJson(SerializationContext predicateSerializer) {
JsonObject json = new JsonObject();
json.addProperty("tag", blockTag.location().toString());
return super.serializeToJson(predicateSerializer);
}
public TagKey<Block> getBlockTag() {
return blockTag;
}
}
}

View file

@ -0,0 +1,36 @@
package org.dimdev.dimdoors.entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.PathfinderMob;
import net.minecraft.world.level.Level;
//import software.bernie.geckolib3.core.IAnimatable;
//import software.bernie.geckolib3.core.PlayState;
//import software.bernie.geckolib3.core.builder.AnimationBuilder;
//import software.bernie.geckolib3.core.controller.AnimationController;
//import software.bernie.geckolib3.core.event.predicate.AnimationEvent;
//import software.bernie.geckolib3.core.manager.AnimationData;
//import software.bernie.geckolib3.core.manager.AnimationFactory;
public class MaskEntity extends PathfinderMob /*implements IAnimatable*/ { // TODO
// private AnimationFactory factory = new AnimationFactory(this);
protected MaskEntity(EntityType<? extends MaskEntity> entityType, Level world) {
super(entityType, world);
}
// private <E extends IAnimatable> PlayState predicate(AnimationEvent<E> event) {
// event.getController().setAnimation(new AnimationBuilder().addAnimation("animation.mask.hover", true));
// return PlayState.CONTINUE;
// }
// @Override
// public void registerControllers(AnimationData data) {
// data.addAnimationController(new AnimationController(this, "controller", 0, this::predicate));
// }
// @Override
// public AnimationFactory getFactory() {
// return this.factory;
// }
}

View file

@ -0,0 +1,60 @@
package org.dimdev.dimdoors.entity;
//import org.dimdev.dimdoors.client.MaskRenderer;
import dev.architectury.registry.client.level.entity.EntityRendererRegistry;
import dev.architectury.registry.client.rendering.BlockEntityRendererRegistry;
import dev.architectury.registry.level.entity.EntityAttributeRegistry;
import dev.architectury.registry.registries.DeferredRegister;
import dev.architectury.registry.registries.RegistrySupplier;
import net.minecraft.core.registries.Registries;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityDimensions;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.SpawnGroup;
import net.minecraft.registry.Registries;
import net.minecraft.registry.Registry;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.fabricmc.fabric.api.client.rendering.v1.EntityRendererRegistry;
import net.fabricmc.fabric.api.object.builder.v1.entity.FabricDefaultAttributeRegistry;
import net.fabricmc.fabric.api.object.builder.v1.entity.FabricEntityTypeBuilder;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.MobCategory;
import org.dimdev.dimdoors.DimensionalDoors;
import org.dimdev.dimdoors.client.MonolithRenderer;
public class ModEntityTypes {
public static final DeferredRegister<EntityType<?>> ENTITY_TYPES = DeferredRegister.create(DimensionalDoors.MOD_ID, Registries.ENTITY_TYPE);
public static final RegistrySupplier<EntityType<MonolithEntity>> MONOLITH = register(
"dimdoors:monolith",
MonolithEntity::new,
2f, 2.7f, false
);
public static final RegistrySupplier<EntityType<MaskEntity>> MASK = register(
"dimdoors:mask",
MaskEntity::new,
0.9375f, 0.9375f, true
);
public static void init() {
ENTITY_TYPES.register();
EntityAttributeRegistry.register(MONOLITH, MonolithEntity::createMobAttributes);
EntityAttributeRegistry.register(MASK, MonolithEntity::createMobAttributes);
}
@Environment(EnvType.CLIENT)
public static void initClient() {
EntityRendererRegistry.register(MONOLITH, MonolithRenderer::new);
// EntityRendererRegistry.INSTANCE.register(MASK, MaskRenderer::new);
}
private static <E extends Entity> RegistrySupplier<EntityType<E>> register(String id, EntityType.EntityFactory<E> factory, float width, float height, boolean fixed) {
return ENTITY_TYPES.register(id, () -> EntityType.Builder.of(factory, MobCategory.MONSTER).sized(width, height).canSpawnFarFromPlayer().fireImmune().build(null));
}
}

View file

@ -0,0 +1,337 @@
package org.dimdev.dimdoors.entity;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.Minecraft;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Vec3i;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.Tag;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.network.syncher.EntityDataSerializers;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.sounds.SoundSource;
import net.minecraft.util.Mth;
import net.minecraft.util.RandomSource;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.damagesource.DamageTypes;
import net.minecraft.world.entity.*;
import net.minecraft.world.entity.ai.control.LookControl;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
import org.dimdev.dimdoors.DimensionalDoors;
import org.dimdev.dimdoors.entity.ai.MonolithAggroGoal;
import org.dimdev.dimdoors.item.ModItems;
import org.dimdev.dimdoors.sound.ModSoundEvents;
import org.dimdev.dimdoors.world.ModDimensions;
import java.util.logging.Level;
public class MonolithEntity extends Mob {
public static final int MAX_AGGRO = 250;
private static final int MAX_AGGRO_CAP = 100;
private static final int MIN_AGGRO_CAP = 25;
private static final int MAX_TEXTURE_STATE = 18;
private static final int MAX_SOUND_COOLDOWN = 200;
public static final int MAX_AGGRO_RANGE = 35;
private static final EntityDataAccessor<Integer> AGGRO = SynchedEntityData.defineId(MonolithEntity.class, EntityDataSerializers.INT);
private static final EntityDataAccessor<Float> SCALE = SynchedEntityData.defineId(MonolithEntity.class, EntityDataSerializers.FLOAT);
private static final EntityDataAccessor<Float> PITCH = SynchedEntityData.defineId(MonolithEntity.class, EntityDataSerializers.FLOAT);
private static final float EYE_HEIGHT_PERCENTAGE = 0.55f;
@Environment(EnvType.CLIENT)
private static final RandomSource clientRandom = RandomSource.create();
private int soundTime = 0;
private final int aggroCap;
MonolithEntity(Level world) {
this(ModEntityTypes.MONOLITH, world);
}
public MonolithEntity(EntityType<? extends MonolithEntity> type, Level world) {
super(ModEntityTypes.MONOLITH, world);
this.noPhysics = true;
this.aggroCap = Mth.nextInt(this.getRandom(), MIN_AGGRO_CAP, MAX_AGGRO_CAP);
this.setNoGravity(true);
this.lookControl = new LookControl(this) {
@Override
protected boolean resetXRotOnTick() {
return false;
}
};
this.setInvulnerable(true);
}
public boolean isDangerous() {
return DimensionalDoors.getConfig().getMonolithsConfig().monolithTeleportation && (ModDimensions.isLimboDimension(this.world) || DimensionalDoors.getConfig().getMonolithsConfig().dangerousLimboMonoliths);
}
@Override
public boolean hurt(DamageSource source, float amount) {
if (!source.is(DamageTypes.IN_WALL)) {
setAggro(MAX_AGGRO);
}
return false;
}
@Override
protected int decreaseAirSupply(int i) {
return 10;
}
@Override
protected int increaseAirSupply(int i) {
return 10;
}
// @Override
// public Box getCollisionBox() {
// return null;
// }
//
// @Override
// public Box getHardCollisionBox(Entity entity) {
// return null;
// }
@Override
public boolean requiresCustomPersistence() {
return false;
}
@Override
public boolean isPushable() {
return false;
}
@Override
protected void defineSynchedData() {
super.defineSynchedData();
// Add a short for the aggro level
this.entityData.define(AGGRO, 0);
this.entityData.define(SCALE, 1f);
this.entityData.define(PITCH, 1f);
this.refreshDimensions();
}
@Override
public boolean isAlive() {
return false;
}
@Override
public void move(MoverType moverType, Vec3 vec3) {
}
@Override
protected void customServerAiStep() {
// Remove this Monolith if it's not in Limbo or in a pocket dungeon
if (!(ModDimensions.isLimboDimension(this.level) || ModDimensions.isPocketDimension(this.level))) {
this.remove(RemovalReason.DISCARDED);
super.customServerAiStep();
return;
}
super.customServerAiStep();
// Check for players and update aggro levels even if there are no players in range
}
public void updateAggroLevel(Player player, boolean visibility) {
// If we're working on the server side, adjust aggro level
// If we're working on the client side, retrieve aggro level from dataWatcher
if (player == null) {
return;
}
if ((player.getInventory().armor.get(0).getItem() == ModItems.WORLD_THREAD_HELMET && player.getInventory().armor.get(1).getItem() == ModItems.WORLD_THREAD_CHESTPLATE && player.getInventory().armor.get(2).getItem() == ModItems.WORLD_THREAD_LEGGINGS && player.getInventory().armor.get(3).getItem() == ModItems.WORLD_THREAD_BOOTS)) {
return;
}
if (!this.level.isClientSide) {
if (player.distanceTo(this) > 70) {
return;
}
int aggro = this.entityData.get(AGGRO);
// Server side...
// Rapidly increase the aggro level if this Monolith can see the player
if (visibility) {
if (ModDimensions.isLimboDimension(this.level)) {
if (this.isDangerous()) {
aggro++;
} else {
aggro += 36;
}
} else {
// Aggro increases faster outside of Limbo
aggro += 3;
}
} else {
if (this.isDangerous()) {
if (aggro > this.aggroCap) {
// Decrease aggro over time
aggro--;
} else if (aggro < this.aggroCap) {
// Increase aggro if a player is within range and aggro < aggroCap
aggro++;
}
} else {
aggro -= 3;
}
}
// Clamp the aggro level
int maxAggro = this.isDangerous() ? MAX_AGGRO : 180;
aggro = (short) Mth.clamp(aggro, 0, maxAggro);
this.entityData.set(AGGRO, aggro);
}
}
@Environment(EnvType.CLIENT)
public int getTextureState() {
// Determine texture state from aggro progress
return Mth.clamp(MAX_TEXTURE_STATE * this.entityData.get(AGGRO) / MAX_AGGRO, 0, MAX_TEXTURE_STATE);
}
/**
* Plays sounds at different levels of aggro, using soundTime to prevent too many sounds at once.
*
* @param pos The position to play the sounds at
*/
public void playSounds(Vec3 pos) {
float aggroPercent = this.getAggroProgress();
float pitch = getPitch();
if (this.soundTime <= 0) {
this.playSound(ModSoundEvents.MONK.get(), 1F, pitch);
this.soundTime = 100;
}
if (aggroPercent > 0.70 && this.soundTime < 100) {
this.level.playSound(null, new BlockPos(new Vec3i((int) pos.x, (int) pos.y, (int) pos.z)), ModSoundEvents.TEARING.get(), SoundSource.HOSTILE, 1F, (float) (1 + this.getRandom().nextGaussian()));
this.soundTime = 100 + this.getRandom().nextInt(75);
}
if (aggroPercent > 0.80 && this.soundTime < MAX_SOUND_COOLDOWN) {
this.level.playSound(null, new BlockPos(new Vec3i((int) pos.x, (int) pos.y, (int) pos.z)), ModSoundEvents.TEARING.get(), SoundSource.HOSTILE, 7, 1);
this.soundTime = 250;
}
this.soundTime--;
}
@Override
public float getEyeHeight(Pose pose) {
return getDimensions(pose).height * EYE_HEIGHT_PERCENTAGE;
}
@Override
protected float getStandingEyeHeight(Pose pose, EntityDimensions dimensions) {
return getDimensions(pose).height * EYE_HEIGHT_PERCENTAGE;
}
@Environment(EnvType.CLIENT)
public static void spawnParticles(int aggro) {
Player player = Minecraft.getInstance().player;
if (aggro < 120) {
return;
}
int count = 10 * aggro / MAX_AGGRO;
for (int i = 1; i < count; ++i) {
//noinspection ConstantConditions
player.level.addParticle(ParticleTypes.PORTAL, player.getX() + (clientRandom.nextDouble() - 0.5D) * 3.0,
player.getY() + clientRandom.nextDouble() * player.getBbHeight() - 0.75D,
player.getZ() + (clientRandom.nextDouble() - 0.5D) * player.getBbWidth(),
(clientRandom.nextDouble() - 0.5D) * 2.0D, -clientRandom.nextDouble(),
(clientRandom.nextDouble() - 0.5D) * 2.0D);
}
}
public float getAggroProgress() {
return ((float) getAggro()) / MAX_AGGRO;
}
@Override
protected void registerGoals() {
super.registerGoals();
this.goalSelector.addGoal(0, new MonolithAggroGoal(this, MAX_AGGRO_RANGE));
}
public void facePlayer(Player player) {
this.lookControl.setLookAt(player, 1.0f, 1.0f);
}
@Override
public void addAdditionalSaveData(CompoundTag nbt) {
super.addAdditionalSaveData(nbt);
nbt.putInt("Aggro", getAggro());
nbt.putFloat("scale", getScale());
nbt.putFloat("pitch", getPitch());
}
@Override
public void readAdditionalSaveData(CompoundTag nbt) {
super.readAdditionalSaveData(nbt);
setAggro(nbt.getInt("Aggro"));
if (nbt.contains("scale", Tag.TAG_FLOAT)) {
setScale(nbt.getFloat("scale"));
}
if (nbt.contains("pitch", Tag.TAG_FLOAT)) {
setPitch(nbt.getFloat("pitch"));
}
}
public int getAggro() {
return this.entityData.get(AGGRO);
}
public void setAggro(int aggro) {
this.entityData.set(AGGRO, aggro);
}
@Override
public float getScale() {
return this.entityData.get(SCALE);
}
public void setScale(float scale) {
this.entityData.set(SCALE, scale);
refreshDimensions();
}
public float getPitch() {
return this.entityData.get(PITCH);
}
public void setPitch(float pitch) {
this.entityData.set(PITCH, pitch);
}
@Override
protected AABB getBoundingBoxForPose(Pose pose) {
float scale = getScale();
return super.getBoundingBoxForPose(pose).inflate(scale, scale, scale);
}
@Override
public void onSyncedDataUpdated(EntityDataAccessor<?> data) {
if (SCALE.equals(data)) {
this.refreshDimensions();
}
super.onSyncedDataUpdated(data);
}
@Override
public boolean checkSpawnRules(LevelAccessor world, MobSpawnType spawnReason) {
if (spawnReason == MobSpawnType.CHUNK_GENERATION) {
return super.checkSpawnRules(world, spawnReason);
}
if (spawnReason == MobSpawnType.NATURAL) {
return this.getRandom().nextInt(32) == 2;
}
return false;
}
}

View file

@ -0,0 +1,113 @@
package org.dimdev.dimdoors.entity.ai;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Vec3i;
import net.minecraft.entity.ai.TargetPredicate;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.predicate.entity.EntityPredicates;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.sound.SoundCategory;
import net.minecraft.sounds.SoundSource;
import net.minecraft.util.RandomSource;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3i;
import net.minecraft.util.math.random.Random;
import net.minecraft.world.entity.EntitySelector;
import net.minecraft.world.entity.ai.goal.Goal;
import net.minecraft.world.entity.ai.targeting.TargetingConditions;
import net.minecraft.world.entity.player.Player;
import org.dimdev.dimdoors.DimensionalDoors;
import org.dimdev.dimdoors.entity.MonolithEntity;
import org.dimdev.dimdoors.entity.stat.ModStats;
import org.dimdev.dimdoors.item.ModItems;
import org.dimdev.dimdoors.network.ServerPacketHandler;
import org.dimdev.dimdoors.network.packet.s2c.MonolithAggroParticlesPacket;
import org.dimdev.dimdoors.network.packet.s2c.MonolithTeleportParticlesPacket;
import org.dimdev.dimdoors.sound.ModSoundEvents;
import java.util.EnumSet;
import static org.dimdev.dimdoors.entity.MonolithEntity.MAX_AGGRO;
public class MonolithAggroGoal extends Goal {
protected final MonolithEntity mob;
protected Player target;
protected final float range;
protected final TargetingConditions targetPredicate;
public MonolithAggroGoal(MonolithEntity mobEntity, float f) {
this.mob = mobEntity;
this.range = f;
this.setFlags(EnumSet.of(Goal.Flag.LOOK));
this.targetPredicate = (TargetingConditions.forCombat()).range(this.range).selector(EntitySelector.NO_CREATIVE_OR_SPECTATOR::test);
}
private Player getTarget() {
Player playerEntity = this.mob.level.getNearestPlayer(this.targetPredicate, this.mob, this.mob.getX(), this.mob.getEyeY(), this.mob.getZ());
return playerEntity != null && this.mob.hasLineOfSight(playerEntity) && playerEntity.distanceTo(this.mob) < 50 ? playerEntity : null;
}
public boolean canStart() {
return (this.target = this.getTarget()) != null && this.target.distanceTo(this.mob) <= 50;
}
public boolean shouldContinue() {
return (this.target = this.getTarget()) != null && this.target.distanceTo(this.mob) <= 50;
}
public void start() {
}
public void stop() {
this.target = null;
this.mob.setAggro(0);
}
public void tick() {
if (this.target != null && this.target.distanceTo(this.mob) > 70) {
this.stop();
return;
}
if (this.target != null && (this.target.getInventory().armor.get(0).getItem() == ModItems.WORLD_THREAD_HELMET && this.target.getInventory().armor.get(1).getItem() == ModItems.WORLD_THREAD_CHESTPLATE && this.target.getInventory().armor.get(2).getItem() == ModItems.WORLD_THREAD_LEGGINGS && this.target.getInventory().armor.get(3).getItem() == ModItems.WORLD_THREAD_BOOTS)) {
RandomSource random = RandomSource.create();
int i = random.nextInt(64);
if (this.target instanceof ServerPlayer) {
if (i < 4) {
this.target.getInventory().armor.get(0).hurt(i, random, (ServerPlayer) this.target);
this.target.getInventory().armor.get(1).hurt(i, random, (ServerPlayer) this.target);
this.target.getInventory().armor.get(2).hurt(i, random, (ServerPlayer) this.target);
this.target.getInventory().armor.get(3).hurt(i, random, (ServerPlayer) this.target);
}
}
return;
}
boolean visibility = this.target != null;
this.mob.updateAggroLevel(this.target, visibility);
// Change orientation and face a player if one is in range
if (this.target != null) {
this.mob.facePlayer(this.target);
if (this.mob.isDangerous()) {
// Play sounds on the server side, if the player isn't in Limbo.
// Limbo is excluded to avoid drowning out its background music.
// Also, since it's a large open area with many Monoliths, some
// of the sounds that would usually play for a moment would
// keep playing constantly and would get very annoying.
this.mob.playSounds(this.target.position());
ServerPacketHandler.get((ServerPlayer) this.target).sendPacket(new MonolithAggroParticlesPacket(this.mob.getAggro()));
}
// Teleport the target player if various conditions are met
if (this.mob.getAggro() >= MAX_AGGRO && DimensionalDoors.getConfig().getMonolithsConfig().monolithTeleportation && !this.target.isCreative() && this.mob.isDangerous()) {
this.mob.setAggro(0);
this.target.teleportTo(this.target.getX(), this.target.getY() + 256, this.target.getZ());
this.target.level.playSound(null, new BlockPos(new Vec3i((int) this.target.position().x, (int) this.target.position().y, (int) this.target.position().z)), ModSoundEvents.CRACK.get(), SoundSource.HOSTILE, 13, 1);
this.target.awardStat(ModStats.TIMES_TELEPORTED_BY_MONOLITH);
ServerPacketHandler.get((ServerPlayer) this.target).sendPacket(new MonolithTeleportParticlesPacket());
}
}
}
}

View file

@ -0,0 +1,33 @@
package org.dimdev.dimdoors.entity.limbo;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.contents.TranslatableContents;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.player.Player;
public abstract class LimboEntranceSource {
public abstract Component getMessage(Player player);
public void broadcast(Player player, MinecraftServer server) {
server.getPlayerList().broadcastSystemMessage(this.getMessage(player), false);
}
public static LimboDeathEntranceSource ofDamageSource(DamageSource source) {
return new LimboDeathEntranceSource(source);
}
public static class LimboDeathEntranceSource extends LimboEntranceSource {
private final DamageSource damageSource;
private LimboDeathEntranceSource(DamageSource damageSource) {
this.damageSource = damageSource;
}
@Override
public Component getMessage(Player player) {
TranslatableContents message = (TranslatableContents) this.damageSource.getLocalizedDeathMessage(player).getContents();
return Component.translatable("limbo." + message.getKey(), message.getArgs());
}
}
}

View file

@ -0,0 +1,23 @@
package org.dimdev.dimdoors.entity.limbo;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.text.MutableText;
import net.minecraft.text.Text;
import net.minecraft.text.TranslatableTextContent;
import net.minecraft.util.StringIdentifiable;
public enum LimboExitReason implements StringIdentifiable {
ETERNAL_FLUID,
GENERIC,
RIFT;
@Override
public String asString() {
return "limbo.exit." + this.name().toLowerCase();
}
public void broadcast(PlayerEntity player) {
//noinspection ConstantConditions
player.getServer().getPlayerManager().broadcast(Text.translatable(asString(), player.getGameProfile().getName()), false);
}
}

View file

@ -0,0 +1,28 @@
package org.dimdev.dimdoors.entity.stat;
import dev.architectury.registry.registries.DeferredRegister;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.stats.StatFormatter;
import net.minecraft.stats.Stats;
import org.dimdev.dimdoors.DimensionalDoors;
public class ModStats {
public static final DeferredRegister<ResourceLocation> STATS = DeferredRegister.create(DimensionalDoors.MOD_ID, Registries.CUSTOM_STAT);
public static final ResourceLocation DEATHS_IN_POCKETS = register("deaths_in_pocket", StatFormatter.DEFAULT);
public static final ResourceLocation TIMES_SENT_TO_LIMBO = register("times_sent_to_limbo", StatFormatter.DEFAULT);
public static final ResourceLocation TIMES_TELEPORTED_BY_MONOLITH = register("times_teleported_by_monolith", StatFormatter.DEFAULT);
public static final ResourceLocation TIMES_BEEN_TO_DUNGEON = register("times_been_to_dungeon", StatFormatter.DEFAULT);
private static ResourceLocation register(String string, StatFormatter statFormatter) {
ResourceLocation resourceLocation = DimensionalDoors.id(string);
STATS.register(string, () -> resourceLocation);
Stats.CUSTOM.get(resourceLocation, statFormatter);
return resourceLocation;
}
public static void init() {
// just loads the class
}
}

View file

@ -1,39 +1,12 @@
package org.dimdev.dimdoors.item; package org.dimdev.dimdoors.item;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Supplier;
import dev.architectury.core.item.ArchitecturyBucketItem; import dev.architectury.core.item.ArchitecturyBucketItem;
import dev.architectury.registry.CreativeTabRegistry; import dev.architectury.registry.CreativeTabRegistry;
import dev.architectury.registry.registries.DeferredRegister; import dev.architectury.registry.registries.DeferredRegister;
import dev.architectury.registry.registries.RegistrySupplier; import dev.architectury.registry.registries.RegistrySupplier;
import net.minecraft.core.registries.Registries; import net.minecraft.core.registries.Registries;
import net.minecraft.world.item.*; import net.minecraft.world.item.*;
import net.minecraft.world.level.block.Block;
import org.dimdev.dimdoors.DimensionalDoors; import org.dimdev.dimdoors.DimensionalDoors;
import org.dimdev.matrix.Matrix;
import org.dimdev.matrix.Registrar;
import org.dimdev.matrix.RegistryEntry;
import net.minecraft.block.Block;
import net.minecraft.block.Blocks;
import net.minecraft.item.ArmorItem;
import net.minecraft.item.BlockItem;
import net.minecraft.item.BucketItem;
import net.minecraft.item.Item;
import net.minecraft.item.ItemGroup;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.item.SpawnEggItem;
import net.minecraft.registry.Registries;
import net.minecraft.registry.Registry;
import net.fabricmc.fabric.api.event.registry.RegistryEntryAddedCallback;
import net.fabricmc.fabric.api.itemgroup.v1.FabricItemGroup;
import org.dimdev.dimdoors.block.ModBlocks; import org.dimdev.dimdoors.block.ModBlocks;
import org.dimdev.dimdoors.entity.ModEntityTypes; import org.dimdev.dimdoors.entity.ModEntityTypes;
import org.dimdev.dimdoors.fluid.ModFluids; import org.dimdev.dimdoors.fluid.ModFluids;
@ -41,15 +14,21 @@ import org.dimdev.dimdoors.item.door.DimensionalTrapdoorItem;
import org.dimdev.dimdoors.rift.targets.RandomTarget; import org.dimdev.dimdoors.rift.targets.RandomTarget;
import org.dimdev.dimdoors.sound.ModSoundEvents; import org.dimdev.dimdoors.sound.ModSoundEvents;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Supplier;
import static org.dimdev.dimdoors.DimensionalDoors.id; import static org.dimdev.dimdoors.DimensionalDoors.id;
public final class ModItems { public final class ModItems {
// DO NOT REMOVE!!! // DO NOT REMOVE!!!
public static final DeferredRegister<Item> REGISTRY = DeferredRegister.create(DimensionalDoors.MOD_ID, Registries.ITEM); public static final DeferredRegister<Item> REGISTRY = DeferredRegister.create(DimensionalDoors.MOD_ID, Registries.ITEM);
public static final RegistrySupplier<Item> OAK_DIMENSIONAL_TRAPDOOR = register("wood_dimensional_trapdoor", () -> new DimensionalTrapdoorItem( public static final RegistrySupplier<Item> OAK_DIMENSIONAL_TRAPDOOR = register("wood_dimensional_trapdoor", properties -> new DimensionalTrapdoorItem(
ModBlocks.OAK_DIMENSIONAL_TRAPDOOR.get(), ModBlocks.OAK_DIMENSIONAL_TRAPDOOR.get(),
new Item.Properties().stacksTo(1), properties.stacksTo(1),
rift -> rift.setDestination( rift -> rift.setDestination(
RandomTarget.builder() RandomTarget.builder()
.acceptedGroups(Collections.singleton(0)) .acceptedGroups(Collections.singleton(0))
@ -62,73 +41,73 @@ public final class ModItems {
.build()) .build())
)); ));
public static final RegistrySupplier<Item> WORLD_THREAD = register("world_thread", () -> new Item(new Item.Properties())); public static final RegistrySupplier<Item> WORLD_THREAD = register("world_thread", Item::new);
public static final RegistrySupplier<Item> INFRANGIBLE_FIBER = register("infrangible_fiber", () -> new Item(new Item.Properties())); public static final RegistrySupplier<Item> INFRANGIBLE_FIBER = register("infrangible_fiber", properties -> new Item(properties.fireResistant()));
public static final RegistrySupplier<Item> FRAYED_FILAMENTS = register("frayed_filament", () -> new Item(new Item.Properties())); public static final RegistrySupplier<Item> FRAYED_FILAMENTS = register("frayed_filament", Item::new);
public static final RegistrySupplier<Item> RIFT_CONFIGURATION_TOOL = register("rift_configuration_tool", RiftConfigurationToolItem::new); public static final RegistrySupplier<Item> RIFT_CONFIGURATION_TOOL = register("rift_configuration_tool", RiftConfigurationToolItem::new);
public static final RegistrySupplier<Item> RIFT_BLADE = register("rift_blade", () -> new RiftBladeItem(new Item.Properties().durability(100))); public static final RegistrySupplier<Item> RIFT_BLADE = register("rift_blade", properties -> new RiftBladeItem(properties.durability(100)));
public static final RegistrySupplier<Item> RIFT_REMOVER = register("rift_remover", () -> new RiftRemoverItem(new Item.Properties().stacksTo(1).durability(100))); public static final RegistrySupplier<Item> RIFT_REMOVER = register("rift_remover", properties -> new RiftRemoverItem(properties.stacksTo(1).durability(100)));
public static final RegistrySupplier<Item> RIFT_SIGNATURE = register("rift_signature", () -> new RiftSignatureItem(new Item.Properties().stacksTo(1).durability(1))); public static final RegistrySupplier<Item> RIFT_SIGNATURE = register("rift_signature", properties -> new RiftSignatureItem(properties.stacksTo(1).durability(1)));
public static final RegistrySupplier<Item> STABILIZED_RIFT_SIGNATURE = register("stabilized_rift_signature", () -> new StabilizedRiftSignatureItem(new Item.Properties().stacksTo(1).durability(20))); public static final RegistrySupplier<Item> STABILIZED_RIFT_SIGNATURE = register("stabilized_rift_signature", properties -> new StabilizedRiftSignatureItem(properties.stacksTo(1).durability(20)));
public static final RegistrySupplier<Item> RIFT_STABILIZER = register("rift_stabilizer", () -> new RiftStabilizerItem(new Item.Properties().stacksTo(1).durability(6))); public static final RegistrySupplier<Item> RIFT_STABILIZER = register("rift_stabilizer", properties -> new RiftStabilizerItem(properties.stacksTo(1).durability(6)));
public static final RegistrySupplier<Item> RIFT_KEY = register("rift_key", () -> new RiftKeyItem(new Item.Properties().fireResistant().stacksTo(1))); public static final RegistrySupplier<Item> RIFT_KEY = register("rift_key", properties -> new RiftKeyItem(properties.fireResistant().stacksTo(1)));
public static final RegistrySupplier<Item> DIMENSIONAL_ERASER = register("dimensional_eraser", () -> new DimensionalEraserItem(new Item.Properties().durability(100))); public static final RegistrySupplier<Item> DIMENSIONAL_ERASER = register("dimensional_eraser", properties -> new DimensionalEraserItem(properties.durability(100)));
public static final RegistrySupplier<Item> MONOLITH_SPAWNER = register("monolith_spawner", () -> new SpawnEggItem(ModEntityTypes.MONOLITH, 0xffffff, 0xffffff, new Item.Properties()); public static final RegistrySupplier<Item> MONOLITH_SPAWNER = register("monolith_spawner", properties -> new SpawnEggItem(ModEntityTypes.MONOLITH.get(), 0xffffff, 0xffffff, properties));
public static final RegistrySupplier<Item> WORLD_THREAD_HELMET = register("world_thread_helmet", () -> new ArmorItem(ModArmorMaterials.WORLD_THREAD, ArmorItem.Type.HELMET, new Item.Properties())); public static final RegistrySupplier<Item> WORLD_THREAD_HELMET = register("world_thread_helmet", properties -> new ArmorItem(ModArmorMaterials.WORLD_THREAD, ArmorItem.Type.HELMET, properties));
public static final RegistrySupplier<Item> WORLD_THREAD_CHESTPLATE = register("world_thread_chestplate", () -> new ArmorItem(ModArmorMaterials.WORLD_THREAD, ArmorItem.Type.CHESTPLATE, new Item.Properties())); public static final RegistrySupplier<Item> WORLD_THREAD_CHESTPLATE = register("world_thread_chestplate", properties -> new ArmorItem(ModArmorMaterials.WORLD_THREAD, ArmorItem.Type.CHESTPLATE, properties));
public static final RegistrySupplier<Item> WORLD_THREAD_LEGGINGS = register("world_thread_leggings", () -> new ArmorItem(ModArmorMaterials.WORLD_THREAD, ArmorItem.Type.LEGGINGS, new Item.Properties())); public static final RegistrySupplier<Item> WORLD_THREAD_LEGGINGS = register("world_thread_leggings", properties -> new ArmorItem(ModArmorMaterials.WORLD_THREAD, ArmorItem.Type.LEGGINGS, properties));
public static final RegistrySupplier<Item> WORLD_THREAD_BOOTS = register("world_thread_boots", () -> new ArmorItem(ModArmorMaterials.WORLD_THREAD, ArmorItem.Type.BOOTS, new Item.Properties())); public static final RegistrySupplier<Item> WORLD_THREAD_BOOTS = register("world_thread_boots", properties -> new ArmorItem(ModArmorMaterials.WORLD_THREAD, ArmorItem.Type.BOOTS, properties));
public static final RegistrySupplier<Item> MASK_WAND = register("mask_wand", () -> new MaskWandItem(new Item.Properties().stacksTo(100)/**/)); public static final RegistrySupplier<Item> MASK_WAND = register("mask_wand", properties -> new MaskWandItem(properties.stacksTo(100)));
public static final RegistrySupplier<Item> STABLE_FABRIC = register("stable_fabric", () -> new Item(new Item.Properties())); public static final RegistrySupplier<Item> STABLE_FABRIC = register("stable_fabric", Item::new);
public static final RegistrySupplier<Item> CREEPY_RECORD = register("creepy_record", () -> new RecordItem(10, ModSoundEvents.CREEPY.get(), new Item.Properties(), 317)); public static final RegistrySupplier<Item> CREEPY_RECORD = register("creepy_record", properties -> new RecordItem(10, ModSoundEvents.CREEPY.get(), properties, 317));
public static final RegistrySupplier<Item> WHITE_VOID_RECORD = register("white_void_record", () -> new RecordItem(10, ModSoundEvents.WHITE_VOID.get(), new Item.Properties(), 225)); public static final RegistrySupplier<Item> WHITE_VOID_RECORD = register("white_void_record", properties -> new RecordItem(10, ModSoundEvents.WHITE_VOID.get(), properties, 225));
public static final Item ETERNAL_FLUID_BUCKET = register("eternal_fluid_bucket", () -> new ArchitecturyBucketItem(ModFluids.ETERNAL_FLUID, new Item.Properties().craftRemainder(Items.BUCKET).stacksTo(1))); public static final RegistrySupplier<Item> ETERNAL_FLUID_BUCKET = register("eternal_fluid_bucket", properties -> new ArchitecturyBucketItem(ModFluids.ETERNAL_FLUID, properties.craftRemainder(Items.BUCKET).stacksTo(1)));
public static final RegistrySupplier<Item> MASK_SHARD = register("mask_shard", () -> new Item(new Item.Properties())); public static final RegistrySupplier<Item> MASK_SHARD = register("mask_shard", Item::new);
public static final RegistrySupplier<Item> FUZZY_FIREBALL = register("fuzzy_fireball", () -> new Item(new Item.Properties())); public static final RegistrySupplier<Item> FUZZY_FIREBALL = register("fuzzy_fireball", Item::new);
public static final RegistrySupplier<Item> FABRIC_OF_FINALITY = register("fabric_of_finality", () -> new Item(new Item.Properties())); public static final RegistrySupplier<Item> FABRIC_OF_FINALITY = register("fabric_of_finality", Item::new);
public static final RegistrySupplier<Item> LIMINAL_LINT = register("liminal_lint", () -> new Item(new Item.Properties())); public static final RegistrySupplier<Item> LIMINAL_LINT = register("liminal_lint", Item::new);
public static final RegistrySupplier<Item> ENDURING_FIBERS = register("enduring_fibers", () -> new Item(new Item.Properties())); public static final RegistrySupplier<Item> ENDURING_FIBERS = register("enduring_fibers", Item::new);
public static final RegistrySupplier<Item> RIFT_PEARL = register("rift_pearl", () -> new Item(new Item.Properties())); public static final RegistrySupplier<Item> RIFT_PEARL = register("rift_pearl", Item::new);
public static final RegistrySupplier<Item> FABRIC_OF_REALITY = register("fabric_of_reality", () -> new Item(new Item.Properties())); public static final RegistrySupplier<Item> FABRIC_OF_REALITY = register("fabric_of_reality", Item::new);
public static final RegistrySupplier<Item> AMALGAM_LUMP = register("amalgam_lump", () -> new Item(new Item.Properties())); public static final RegistrySupplier<Item> AMALGAM_LUMP = register("amalgam_lump", Item::new);
public static final RegistrySupplier<Item> CLOD = register("clod", () -> new Item(new Item.Properties())); public static final RegistrySupplier<Item> CLOD = register("clod", Item::new);
public static final RegistrySupplier<Item> GARMENT_OF_REALITY_HELMET = register("garment_of_reality_helmet", () -> new ArmorItem(ModArmorMaterials.GARMENT_OF_REALITY, ArmorItem.Type.HELMET, new Item.Properties())); public static final RegistrySupplier<Item> GARMENT_OF_REALITY_HELMET = register("garment_of_reality_helmet", properties -> new ArmorItem(ModArmorMaterials.GARMENT_OF_REALITY, ArmorItem.Type.HELMET, properties));
public static final RegistrySupplier<Item> GARMENT_OF_REALITY_CHESTPLATE = register("garment_of_reality_chestplate", () -> new ArmorItem(ModArmorMaterials.GARMENT_OF_REALITY, ArmorItem.Type.CHESTPLATE, new Item.Properties())); public static final RegistrySupplier<Item> GARMENT_OF_REALITY_CHESTPLATE = register("garment_of_reality_chestplate", properties -> new ArmorItem(ModArmorMaterials.GARMENT_OF_REALITY, ArmorItem.Type.CHESTPLATE, properties));
public static final RegistrySupplier<Item> GARMENT_OF_REALITY_LEGGINGS = register("garment_of_reality_leggings", () -> new ArmorItem(ModArmorMaterials.GARMENT_OF_REALITY, ArmorItem.Type.LEGGINGS, new Item.Properties())); public static final RegistrySupplier<Item> GARMENT_OF_REALITY_LEGGINGS = register("garment_of_reality_leggings", properties -> new ArmorItem(ModArmorMaterials.GARMENT_OF_REALITY, ArmorItem.Type.LEGGINGS, properties));
public static final RegistrySupplier<Item> GARMENT_OF_REALITY_BOOTS = register("garment_of_reality_boots", () -> new ArmorItem(ModArmorMaterials.GARMENT_OF_REALITY, ArmorItem.Type.BOOTS, new Item.Properties())); public static final RegistrySupplier<Item> GARMENT_OF_REALITY_BOOTS = register("garment_of_reality_boots", properties -> new ArmorItem(ModArmorMaterials.GARMENT_OF_REALITY, ArmorItem.Type.BOOTS, properties));
public static final Set<Item> DOOR_ITEMS = new HashSet<>(); public static final Set<Item> DOOR_ITEMS = new HashSet<>();

View file

@ -1,28 +1,26 @@
package org.dimdev.dimdoors.item; package org.dimdev.dimdoors.item;
import java.util.function.Predicate; import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.entity.Entity; import net.minecraft.world.entity.projectile.ProjectileUtil;
import net.minecraft.entity.LivingEntity; import net.minecraft.world.level.BlockGetter;
import net.minecraft.entity.projectile.ProjectileUtil; import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.util.hit.BlockHitResult; import net.minecraft.world.phys.EntityHitResult;
import net.minecraft.util.hit.EntityHitResult; import net.minecraft.world.phys.HitResult;
import net.minecraft.util.hit.HitResult; import net.minecraft.world.phys.Vec3;
import net.minecraft.util.math.Box;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.BlockView;
import org.dimdev.dimdoors.block.entity.DetachedRiftBlockEntity; import org.dimdev.dimdoors.block.entity.DetachedRiftBlockEntity;
import org.dimdev.dimdoors.block.entity.RiftBlockEntity; import org.dimdev.dimdoors.block.entity.RiftBlockEntity;
import java.util.function.Predicate;
public final class RaycastHelper { public final class RaycastHelper {
public static final int REACH_DISTANCE = 5; public static final int REACH_DISTANCE = 5;
public static boolean hitsDetachedRift(HitResult hit, BlockView world) { public static boolean hitsDetachedRift(HitResult hit, BlockGetter world) {
return hit != null && hit.getType() == HitResult.Type.BLOCK && world.getBlockEntity(((BlockHitResult) hit).getBlockPos()) instanceof DetachedRiftBlockEntity; return hit != null && hit.getType() == HitResult.Type.BLOCK && world.getBlockEntity(((BlockHitResult) hit).getBlockPos()) instanceof DetachedRiftBlockEntity;
} }
public static boolean hitsRift(HitResult hit, BlockView world) { public static boolean hitsRift(HitResult hit, BlockGetter world) {
return hit != null && hit.getType() == HitResult.Type.BLOCK && world.getBlockEntity(((BlockHitResult) hit).getBlockPos()) instanceof RiftBlockEntity; return hit != null && hit.getType() == HitResult.Type.BLOCK && world.getBlockEntity(((BlockHitResult) hit).getBlockPos()) instanceof RiftBlockEntity;
} }
@ -31,10 +29,10 @@ public final class RaycastHelper {
} }
public static HitResult raycast(Entity entity, double maxDistance, float tickDelta, Predicate<Entity> predicate) { public static HitResult raycast(Entity entity, double maxDistance, float tickDelta, Predicate<Entity> predicate) {
Vec3d vec3d = entity.getCameraPosVec(tickDelta); Vec3 vec3d = entity.getEyePosition(tickDelta);
Vec3d vec3d2 = entity.getRotationVec(tickDelta); Vec3 vec3d2 = entity.getViewVector(tickDelta);
Vec3d vec3d3 = vec3d.add(vec3d2.x * maxDistance, vec3d2.y * maxDistance, vec3d2.z * maxDistance); Vec3 vec3d3 = vec3d.add(vec3d2.x * maxDistance, vec3d2.y * maxDistance, vec3d2.z * maxDistance);
Box box = entity.getBoundingBox().stretch(vec3d2.multiply(maxDistance)).expand(1.0D, 1.0D, 1.0D); var box = entity.getBoundingBox().expandTowards(vec3d2.scale(maxDistance)).inflate(1.0D, 1.0D, 1.0D);
return ProjectileUtil.raycast(entity, vec3d, vec3d3, box, predicate, maxDistance); return ProjectileUtil.getEntityHitResult(entity, vec3d, vec3d3, box, predicate, maxDistance);
} }
} }

View file

@ -1,40 +1,30 @@
package org.dimdev.dimdoors.item; package org.dimdev.dimdoors.item;
import java.util.List;
import java.util.Objects;
import net.minecraft.client.item.TooltipContext;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.item.SwordItem;
import net.minecraft.item.ToolMaterials;
import net.minecraft.text.MutableText;
import net.minecraft.text.Text;
import net.minecraft.text.TranslatableTextContent;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.util.TypedActionResult;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.hit.HitResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.math.Vec3i;
import net.minecraft.world.World;
import net.fabricmc.api.EnvType; import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment; import net.fabricmc.api.Environment;
import net.minecraft.core.BlockPos;
import net.minecraft.world.item.Item; import net.minecraft.core.Vec3i;
import net.minecraft.world.item.SwordItem; import net.minecraft.network.chat.Component;
import net.minecraft.world.item.Tier; import net.minecraft.world.InteractionHand;
import net.minecraft.world.item.Tiers; import net.minecraft.world.InteractionResult;
import net.minecraft.world.InteractionResultHolder;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.*;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.HitResult;
import net.minecraft.world.phys.Vec3;
import org.dimdev.dimdoors.DimensionalDoors; import org.dimdev.dimdoors.DimensionalDoors;
import org.dimdev.dimdoors.block.DimensionalPortalBlock; import org.dimdev.dimdoors.block.DimensionalPortalBlock;
import org.dimdev.dimdoors.block.ModBlocks; import org.dimdev.dimdoors.block.ModBlocks;
import org.dimdev.dimdoors.block.entity.EntranceRiftBlockEntity; import org.dimdev.dimdoors.block.entity.EntranceRiftBlockEntity;
import org.dimdev.dimdoors.block.entity.RiftBlockEntity; import org.dimdev.dimdoors.block.entity.RiftBlockEntity;
import org.dimdev.dimdoors.client.ToolTipHelper; import org.dimdev.dimdoors.client.ToolTipHelper;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Objects;
public class RiftBladeItem extends SwordItem { public class RiftBladeItem extends SwordItem {
public static final String ID = "rift_blade"; public static final String ID = "rift_blade";
@ -45,23 +35,23 @@ public class RiftBladeItem extends SwordItem {
@Environment(EnvType.CLIENT) @Environment(EnvType.CLIENT)
@Override @Override
public void appendTooltip(ItemStack itemStack, World world, List<Text> list, TooltipContext tooltipContext) { public void appendHoverText(ItemStack itemStack, @Nullable Level level, List<Component> list, TooltipFlag tooltipFlag) {
ToolTipHelper.processTranslation(list, this.getTranslationKey() + ".info"); ToolTipHelper.processTranslation(list, this.getDescriptionId() + ".info");
} }
@Override @Override
public boolean hasGlint(ItemStack itemStack) { public boolean isFoil(ItemStack itemStack) {
return true; return true;
} }
@Override @Override
public boolean canRepair(ItemStack item, ItemStack repairingItem) { public boolean isValidRepairItem(ItemStack item, ItemStack repairingItem) {
return Objects.equals(ModItems.STABLE_FABRIC, repairingItem.getItem()); return Objects.equals(ModItems.STABLE_FABRIC.get(), repairingItem.getItem());
} }
@Override @Override
public TypedActionResult<ItemStack> use(World world, PlayerEntity player, Hand hand) { public InteractionResultHolder<ItemStack> use(Level world, Player player, InteractionHand hand) {
ItemStack stack = player.getStackInHand(hand); ItemStack stack = player.getItemInHand(hand);
HitResult hit = RaycastHelper.raycast(player, 16, 0.0F, LivingEntity.class::isInstance); HitResult hit = RaycastHelper.raycast(player, 16, 0.0F, LivingEntity.class::isInstance);
if (hit == null) { if (hit == null) {
@ -69,54 +59,54 @@ public class RiftBladeItem extends SwordItem {
} }
if (hit == null) { if (hit == null) {
hit = player.raycast(16, 1.0F, false); //TODO: make the range of the Rift Blade configurable hit = player.pick(16, 1.0F, false); //TODO: make the range of the Rift Blade configurable
} }
if (hit == null) { if (hit == null) {
hit = player.raycast(16, 0, false); hit = player.pick(16, 0, false);
} }
if (world.isClient) { if (world.isClientSide) {
if (RaycastHelper.hitsLivingEntity(hit) || RaycastHelper.hitsRift(hit, world)) { if (RaycastHelper.hitsLivingEntity(hit) || RaycastHelper.hitsRift(hit, world)) {
return new TypedActionResult<>(ActionResult.SUCCESS, stack); return new InteractionResultHolder<>(InteractionResult.SUCCESS, stack);
} else { } else {
player.sendMessage(Text.translatable(this.getTranslationKey() + ".rift_miss"), true); player.displayClientMessage(Component.translatable(this.getDescriptionId() + ".rift_miss"), true);
RiftBlockEntity.showRiftCoreUntil = System.currentTimeMillis() + DimensionalDoors.getConfig().getGraphicsConfig().highlightRiftCoreFor; RiftBlockEntity.showRiftCoreUntil = System.currentTimeMillis() + DimensionalDoors.getConfig().getGraphicsConfig().highlightRiftCoreFor;
return new TypedActionResult<>(ActionResult.FAIL, stack); return new InteractionResultHolder<>(InteractionResult.FAIL, stack);
} }
} }
if (RaycastHelper.hitsLivingEntity(hit)) { if (RaycastHelper.hitsLivingEntity(hit)) {
double damageMultiplier = (double) stack.getDamage() / (double) stack.getMaxDamage(); double damageMultiplier = (double) stack.getDamageValue() / (double) stack.getMaxDamage();
// TODO: gaussian, instead or random // TODO: gaussian, instead or random
double offsetDistance = Math.random() * damageMultiplier * 7 + 2; //TODO: make these offset distances configurable double offsetDistance = Math.random() * damageMultiplier * 7 + 2; //TODO: make these offset distances configurable
double offsetRotationYaw = (Math.random() - 0.5) * damageMultiplier * 360; double offsetRotationYaw = (Math.random() - 0.5) * damageMultiplier * 360;
Vec3d playerVec = player.getPos(); var playerVec = player.position();
Vec3d entityVec = hit.getPos(); var entityVec = hit.getLocation();
Vec3d offsetDirection = playerVec.subtract(entityVec).normalize(); var offsetDirection = playerVec.subtract(entityVec).normalize();
offsetDirection = offsetDirection.rotateY((float) (offsetRotationYaw * Math.PI) / 180); offsetDirection = offsetDirection.yRot((float) (offsetRotationYaw * Math.PI) / 180);
Vec3d added = entityVec.add(offsetDirection.multiply(offsetDistance)); Vec3 added = entityVec.add(offsetDirection.scale(offsetDistance));
BlockPos teleportPosition = new BlockPos(new Vec3i((int) added.x, (int) added. y, (int) added.z)); BlockPos teleportPosition = new BlockPos(new Vec3i((int) added.x, (int) added. y, (int) added.z));
while (world.getBlockState(teleportPosition).getMaterial().blocksMovement()) while (world.getBlockState(teleportPosition).getMaterial().blocksMotion())
teleportPosition = teleportPosition.up(); teleportPosition = teleportPosition.above();
player.teleport(teleportPosition.getX(), teleportPosition.getY(), teleportPosition.getZ()); player.teleportTo(teleportPosition.getX(), teleportPosition.getY(), teleportPosition.getZ());
player.setYaw((float) (Math.random() * 2 * Math.PI)); player.setYRot((float) (Math.random() * 2 * Math.PI));
stack.damage(1, player, a -> a.sendToolBreakStatus(hand)); stack.hurtAndBreak(1, player, a -> a.broadcastBreakEvent(hand));
return new TypedActionResult<>(ActionResult.SUCCESS, stack); return new InteractionResultHolder<>(InteractionResult.SUCCESS, stack);
} else if (RaycastHelper.hitsDetachedRift(hit, world)) { } else if (RaycastHelper.hitsDetachedRift(hit, world)) {
BlockHitResult blockHitResult = (BlockHitResult) hit; BlockHitResult blockHitResult = (BlockHitResult) hit;
BlockPos pos = blockHitResult.getBlockPos(); BlockPos pos = blockHitResult.getBlockPos();
RiftBlockEntity rift = (RiftBlockEntity) world.getBlockEntity(blockHitResult.getBlockPos()); RiftBlockEntity rift = (RiftBlockEntity) world.getBlockEntity(blockHitResult.getBlockPos());
world.setBlockState(pos, ModBlocks.DIMENSIONAL_PORTAL.getDefaultState().with(DimensionalPortalBlock.FACING, blockHitResult.getSide())); world.setBlockAndUpdate(pos, ModBlocks.DIMENSIONAL_PORTAL.get().defaultBlockState().setValue(DimensionalPortalBlock.FACING, blockHitResult.getDirection()));
((EntranceRiftBlockEntity) world.getBlockEntity(pos)).setData(rift.getData()); ((EntranceRiftBlockEntity) world.getBlockEntity(pos)).setData(rift.getData());
stack.damage(1, player, a -> a.sendToolBreakStatus(hand)); stack.hurtAndBreak(1, player, a -> a.broadcastBreakEvent(hand));
return new TypedActionResult<>(ActionResult.SUCCESS, stack); return new InteractionResultHolder<>(InteractionResult.SUCCESS, stack);
} }
return new TypedActionResult<>(ActionResult.FAIL, stack); return new InteractionResultHolder<>(InteractionResult.FAIL, stack);
} }
} }

View file

@ -57,11 +57,6 @@ public class RiftKeyItem extends Item {
return !isEmpty(stack); return !isEmpty(stack);
} }
@Override
public boolean isNbtSynced() {
return super.isNbtSynced();
}
@Override @Override
public int getMaxUseTime(ItemStack stack) { public int getMaxUseTime(ItemStack stack) {
return 30; return 30;

View file

@ -11,8 +11,12 @@ import net.minecraft.item.ItemStack;
import net.minecraft.loot.context.LootContext; import net.minecraft.loot.context.LootContext;
import net.minecraft.loot.context.LootContextParameters; import net.minecraft.loot.context.LootContextParameters;
import net.minecraft.loot.context.LootContextTypes; import net.minecraft.loot.context.LootContextTypes;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.world.ServerWorld; import net.minecraft.server.world.ServerWorld;
import net.minecraft.sound.SoundCategory; import net.minecraft.sound.SoundCategory;
import net.minecraft.sounds.SoundSource;
import net.minecraft.text.MutableText; import net.minecraft.text.MutableText;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.text.TranslatableTextContent; import net.minecraft.text.TranslatableTextContent;
@ -24,21 +28,36 @@ import net.minecraft.util.TypedActionResult;
import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.hit.HitResult; import net.minecraft.util.hit.HitResult;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import net.minecraft.world.Containers;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.InteractionResultHolder;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.fabricmc.api.EnvType; import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment; import net.fabricmc.api.Environment;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item; import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.TooltipFlag;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.storage.loot.LootContext;
import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets;
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.HitResult;
import net.minecraft.world.phys.Vec3;
import org.dimdev.dimdoors.DimensionalDoors; import org.dimdev.dimdoors.DimensionalDoors;
import org.dimdev.dimdoors.block.entity.DetachedRiftBlockEntity; import org.dimdev.dimdoors.block.entity.DetachedRiftBlockEntity;
import org.dimdev.dimdoors.block.entity.RiftBlockEntity; import org.dimdev.dimdoors.block.entity.RiftBlockEntity;
import org.dimdev.dimdoors.client.ToolTipHelper; import org.dimdev.dimdoors.client.ToolTipHelper;
import org.dimdev.dimdoors.sound.ModSoundEvents; import org.dimdev.dimdoors.sound.ModSoundEvents;
import org.jetbrains.annotations.Nullable;
public class RiftRemoverItem extends Item { public class RiftRemoverItem extends Item {
public static final String ID = "rift_remover"; public static final String ID = "rift_remover";
public static final Identifier REMOVED_RIFT_LOOT_TABLE = DimensionalDoors.id("removed_rift"); public static final ResourceLocation REMOVED_RIFT_LOOT_TABLE = DimensionalDoors.id("removed_rift");
public RiftRemoverItem(Item.Properties settings) { public RiftRemoverItem(Item.Properties settings) {
super(settings); super(settings);
@ -46,21 +65,21 @@ public class RiftRemoverItem extends Item {
@Environment(EnvType.CLIENT) @Environment(EnvType.CLIENT)
@Override @Override
public void appendTooltip(ItemStack itemStack, World world, List<Text> list, TooltipContext tooltipContext) { public void appendHoverText(ItemStack itemStack, @Nullable Level level, List<Component> list, TooltipFlag tooltipFlag) {
ToolTipHelper.processTranslation(list, this.getTranslationKey() + ".info"); ToolTipHelper.processTranslation(list, this.getDescription() + ".info");
} }
@Override @Override
public TypedActionResult<ItemStack> use(World world, PlayerEntity player, Hand hand) { public InteractionResultHolder<ItemStack> use(Level world, Player player, InteractionHand hand) {
ItemStack stack = player.getStackInHand(hand); ItemStack stack = player.getItemInHand(hand);
HitResult hit = player.raycast(RaycastHelper.REACH_DISTANCE, 0, false); HitResult hit = player.pick(RaycastHelper.REACH_DISTANCE, 0, false);
if (world.isClient) { if (world.isClientSide) {
if (!RaycastHelper.hitsDetachedRift(hit, world)) { if (!RaycastHelper.hitsDetachedRift(hit, world)) {
player.sendMessage(Text.translatable("tools.rift_miss"), true); player.displayClientMessage(Component.translatable("tools.rift_miss"), true);
RiftBlockEntity.showRiftCoreUntil = System.currentTimeMillis() + DimensionalDoors.getConfig().getGraphicsConfig().highlightRiftCoreFor; RiftBlockEntity.showRiftCoreUntil = System.currentTimeMillis() + DimensionalDoors.getConfig().getGraphicsConfig().highlightRiftCoreFor;
} }
return new TypedActionResult<>(ActionResult.FAIL, stack); return new InteractionResultHolder<>(InteractionResult.FAIL, stack);
} }
if (RaycastHelper.hitsDetachedRift(hit, world)) { if (RaycastHelper.hitsDetachedRift(hit, world)) {
@ -68,19 +87,19 @@ public class RiftRemoverItem extends Item {
DetachedRiftBlockEntity rift = (DetachedRiftBlockEntity) world.getBlockEntity(((BlockHitResult) hit).getBlockPos()); DetachedRiftBlockEntity rift = (DetachedRiftBlockEntity) world.getBlockEntity(((BlockHitResult) hit).getBlockPos());
if (!Objects.requireNonNull(rift).closing) { if (!Objects.requireNonNull(rift).closing) {
rift.setClosing(true); rift.setClosing(true);
world.playSound(null, player.getBlockPos(), ModSoundEvents.RIFT_CLOSE, SoundCategory.BLOCKS, 0.6f, 1); world.playSound(null, player.blockPosition(), ModSoundEvents.RIFT_CLOSE.get(), SoundSource.BLOCKS, 0.6f, 1);
stack.damage(10, player, a -> a.sendToolBreakStatus(hand)); stack.hurtAndBreak(10, player, a -> a.broadcastBreakEvent(hand));
LootContext ctx = new LootContext.Builder((ServerWorld) world).random(world.random).parameter(LootContextParameters.ORIGIN, Vec3d.ofCenter(((BlockHitResult) hit).getBlockPos())).optionalParameter(LootContextParameters.THIS_ENTITY, player).build(LootContextTypes.GENERIC); LootContext ctx = new LootContext.Builder((ServerLevel) world).withRandom(world.random).withParameter(LootContextParams.ORIGIN, Vec3.atCenterOf(((BlockHitResult) hit).getBlockPos())).withOptionalParameter(LootContextParams.THIS_ENTITY, player).create(LootContextParamSets.ALL_PARAMS);
((ServerWorld) world).getServer().getLootManager().getTable(REMOVED_RIFT_LOOT_TABLE).generateLoot(ctx).forEach(stack1 -> { ((ServerLevel) world).getServer().getLootTables().get(REMOVED_RIFT_LOOT_TABLE).getRandomItems(ctx).forEach(stack1 -> {
ItemScatterer.spawn(world, ((BlockHitResult) hit).getBlockPos().getX(), ((BlockHitResult) hit).getBlockPos().getY(), ((BlockHitResult) hit).getBlockPos().getZ(), stack1); Containers.dropItemStack(world, ((BlockHitResult) hit).getBlockPos().getX(), ((BlockHitResult) hit).getBlockPos().getY(), ((BlockHitResult) hit).getBlockPos().getZ(), stack1);
}); });
player.sendMessage(Text.translatable(this.getTranslationKey() + ".closing"), true); player.displayClientMessage(Component.translatable(this.getDescriptionId() + ".closing"), true);
return new TypedActionResult<>(ActionResult.SUCCESS, stack); return new InteractionResultHolder<>(InteractionResult.SUCCESS, stack);
} else { } else {
player.sendMessage(Text.translatable(this.getTranslationKey() + ".already_closing"), true); player.displayClientMessage(Component.translatable(this.getDescription() + ".already_closing"), true);
} }
} }
return new TypedActionResult<>(ActionResult.FAIL, stack); return new InteractionResultHolder<>(InteractionResult.FAIL, stack);
} }
} }

View file

@ -1,32 +1,21 @@
package org.dimdev.dimdoors.item; package org.dimdev.dimdoors.item;
import java.util.List; import net.minecraft.ChatFormatting;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item; import net.minecraft.world.item.Item;
import org.jetbrains.annotations.NotNull; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.TooltipFlag;
import net.minecraft.client.item.TooltipContext; import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.world.item.context.UseOnContext;
import net.minecraft.item.Item; import net.minecraft.world.level.Level;
import net.minecraft.item.ItemPlacementContext;
import net.minecraft.item.ItemStack;
import net.minecraft.item.ItemUsageContext;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.sound.SoundCategory;
import net.minecraft.text.MutableText;
import net.minecraft.text.Text;
import net.minecraft.text.TranslatableTextContent;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Formatting;
import net.minecraft.util.Hand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.World;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import org.dimdev.dimdoors.DimensionalDoors; import org.dimdev.dimdoors.DimensionalDoors;
import org.dimdev.dimdoors.api.util.Location; import org.dimdev.dimdoors.api.util.Location;
import org.dimdev.dimdoors.api.util.RotatedLocation; import org.dimdev.dimdoors.api.util.RotatedLocation;
@ -37,6 +26,8 @@ import org.dimdev.dimdoors.rift.targets.RiftReference;
import org.dimdev.dimdoors.sound.ModSoundEvents; import org.dimdev.dimdoors.sound.ModSoundEvents;
import org.dimdev.dimdoors.world.ModDimensions; import org.dimdev.dimdoors.world.ModDimensions;
import java.util.List;
public class RiftSignatureItem extends Item { public class RiftSignatureItem extends Item {
public static final String ID = "rift_signature"; public static final String ID = "rift_signature";
@ -45,105 +36,103 @@ public class RiftSignatureItem extends Item {
} }
@Override @Override
public boolean hasGlint(ItemStack stack) { public boolean isFoil(ItemStack stack) {
return stack.getNbt() != null && stack.getNbt().contains("destination"); return stack.getTag() != null && stack.getTag().contains("destination");
} }
@Override @Override
public ActionResult useOnBlock(@NotNull ItemUsageContext itemUsageContext) { public InteractionResult useOn(UseOnContext itemUsageContext) {
PlayerEntity player = itemUsageContext.getPlayer(); Player player = itemUsageContext.getPlayer();
World world = itemUsageContext.getWorld(); Level world = itemUsageContext.getLevel();
BlockPos pos = itemUsageContext.getBlockPos(); BlockPos pos = itemUsageContext.getClickedPos();
Hand hand = itemUsageContext.getHand(); InteractionHand hand = itemUsageContext.getHand();
Direction side = itemUsageContext.getSide(); Direction side = itemUsageContext.getClickedFace();
ItemPlacementContext placementContext = new ItemPlacementContext(itemUsageContext); BlockPlaceContext placementContext = new BlockPlaceContext(itemUsageContext);
ItemStack stack = player.getStackInHand(hand); ItemStack stack = player.getItemInHand(hand);
pos = world.getBlockState(pos).getBlock().canReplace(world.getBlockState(pos), placementContext) ? pos : pos.offset(side); pos = world.getBlockState(pos).getBlock().canBeReplaced(world.getBlockState(pos), placementContext) ? pos : pos.relative(side);
// Fail if the player can't place a block there // Fail if the player can't place a block there
if (!player.canPlaceOn(pos, side.getOpposite(), stack)) { if (!player.mayUseItemAt(pos, side.getOpposite(), stack)) {
return ActionResult.FAIL; return InteractionResult.FAIL;
} }
if (world.isClient) { if (world.isClientSide) {
return ActionResult.SUCCESS; return InteractionResult.SUCCESS;
} }
if(ModDimensions.isPrivatePocketDimension(world) && !DimensionalDoors.getConfig().getPocketsConfig().canUseRiftSignatureInPrivatePockets) { if(ModDimensions.isPrivatePocketDimension(world) && !DimensionalDoors.getConfig().getPocketsConfig().canUseRiftSignatureInPrivatePockets) {
player.sendMessage(Text.translatable("tools.signature_blocked").formatted(Formatting.BLACK), true); player.displayClientMessage(Component.translatable("tools.signature_blocked").withStyle(ChatFormatting.BLACK), true);
return ActionResult.FAIL; return InteractionResult.FAIL;
} }
RotatedLocation target = getSource(stack); RotatedLocation target = getSource(stack);
if (target == null) { if (target == null) {
// The link signature has not been used. Store its current target as the first location. // The link signature has not been used. Store its current target as the first location.
setSource(stack, new RotatedLocation(world.getRegistryKey(), pos, player.getYaw(), 0)); setSource(stack, new RotatedLocation(world.dimension(), pos, player.getYRot(), 0));
player.sendMessage(Text.translatable(this.getTranslationKey() + ".stored"), true); player.displayClientMessage(Component.translatable(this.getDescriptionId() + ".stored"), true);
world.playSound(null, player.getBlockPos(), ModSoundEvents.RIFT_START, SoundCategory.BLOCKS, 0.6f, 1); world.playSound(null, player.blockPosition(), ModSoundEvents.RIFT_START.get(), SoundSource.BLOCKS, 0.6f, 1);
} else { } else {
// Place a rift at the saved point // Place a rift at the saved point
if (target.getBlockState().getBlock() != ModBlocks.DETACHED_RIFT) { if (target.getBlockState().getBlock() != ModBlocks.DETACHED_RIFT) {
if (!target.getBlockState().getBlock().canMobSpawnInside()) { if (!target.getBlockState().getBlock().isPossibleToRespawnInThis()) {
player.sendMessage(Text.translatable("tools.target_became_block"), true); player.displayClientMessage(Component.translatable("tools.target_became_block"), true);
clearSource(stack); // TODO: But is this fair? It's a rather hidden way of unbinding your signature! clearSource(stack); // TODO: But is this fair? It's a rather hidden way of unbinding your signature!
return ActionResult.FAIL; return InteractionResult.FAIL;
} }
World sourceWorld = DimensionalDoors.getWorld(target.world); Level sourceWorld = DimensionalDoors.getWorld(target.world);
sourceWorld.setBlockState(target.getBlockPos(), ModBlocks.DETACHED_RIFT.getDefaultState()); sourceWorld.setBlockAndUpdate(target.getBlockPos(), ModBlocks.DETACHED_RIFT.get().defaultBlockState());
DetachedRiftBlockEntity rift1 = (DetachedRiftBlockEntity) target.getBlockEntity(); DetachedRiftBlockEntity rift1 = (DetachedRiftBlockEntity) target.getBlockEntity();
rift1.setDestination(RiftReference.tryMakeRelative(target, new Location((ServerWorld) world, pos))); rift1.setDestination(RiftReference.tryMakeRelative(target, new Location((ServerLevel) world, pos)));
rift1.register(); rift1.register();
} }
// Place a rift at the target point // Place a rift at the target point
world.setBlockState(pos, ModBlocks.DETACHED_RIFT.getDefaultState()); world.setBlockAndUpdate(pos, ModBlocks.DETACHED_RIFT.get().defaultBlockState());
DetachedRiftBlockEntity rift2 = (DetachedRiftBlockEntity) world.getBlockEntity(pos); DetachedRiftBlockEntity rift2 = (DetachedRiftBlockEntity) world.getBlockEntity(pos);
rift2.setDestination(RiftReference.tryMakeRelative(new Location((ServerWorld) world, pos), target)); rift2.setDestination(RiftReference.tryMakeRelative(new Location((ServerLevel) world, pos), target));
rift2.register(); rift2.register();
stack.damage(1, player, a -> { stack.hurtAndBreak(1, player, a -> {}); // TODO: calculate damage based on position?
}); // TODO: calculate damage based on position?
clearSource(stack); clearSource(stack);
player.sendMessage(Text.translatable(this.getTranslationKey() + ".created"), true); player.displayClientMessage(Component.translatable(this.getDescriptionId() + ".created"), true);
// null = send sound to the player too, we have to do this because this code is not run client-side // null = send sound to the player too, we have to do this because this code is not run client-side
world.playSound(null, player.getBlockPos(), ModSoundEvents.RIFT_END, SoundCategory.BLOCKS, 0.6f, 1); world.playSound(null, player.blockPosition(), ModSoundEvents.RIFT_END.get(), SoundSource.BLOCKS, 0.6f, 1);
} }
return ActionResult.SUCCESS; return InteractionResult.SUCCESS;
} }
public static void setSource(ItemStack itemStack, RotatedLocation destination) { public static void setSource(ItemStack itemStack, RotatedLocation destination) {
if (!itemStack.hasNbt()) itemStack.setNbt(new NbtCompound()); if (!itemStack.hasTag()) itemStack.setTag(new CompoundTag());
itemStack.getNbt().put("destination", RotatedLocation.serialize(destination)); itemStack.getTag().put("destination", RotatedLocation.serialize(destination));
} }
public static void clearSource(ItemStack itemStack) { public static void clearSource(ItemStack itemStack) {
if (itemStack.hasNbt()) { if (itemStack.hasTag()) {
itemStack.getNbt().remove("destination"); itemStack.getTag().remove("destination");
} }
} }
public static RotatedLocation getSource(ItemStack itemStack) { public static RotatedLocation getSource(ItemStack itemStack) {
if (itemStack.hasNbt() && itemStack.getNbt().contains("destination")) { if (itemStack.hasTag() && itemStack.getTag().contains("destination")) {
return RotatedLocation.deserialize(itemStack.getNbt().getCompound("destination")); return RotatedLocation.deserialize(itemStack.getTag().getCompound("destination"));
} else { } else {
return null; return null;
} }
} }
@Override @Override
@Environment(EnvType.CLIENT) public void appendHoverText(ItemStack itemStack, Level world, List<Component> list, TooltipFlag tooltipContext) {
public void appendTooltip(ItemStack itemStack, World world, List<Text> list, TooltipContext tooltipContext) {
RotatedLocation transform = getSource(itemStack); RotatedLocation transform = getSource(itemStack);
if (transform != null) { if (transform != null) {
list.add(Text.translatable(this.getTranslationKey() + ".bound.info0", transform.getX(), transform.getY(), transform.getZ(), transform.getWorldId().getValue())); list.add(Component.translatable(this.getDescriptionId() + ".bound.info0", transform.getX(), transform.getY(), transform.getZ(), transform.getWorldId().getValue()));
list.add(Text.translatable(this.getTranslationKey() + ".bound.info1", transform.getWorldId().getValue())); list.add(Component.translatable(this.getDescriptionId() + ".bound.info1", transform.getWorldId().location()));
} else { } else {
ToolTipHelper.processTranslation(list, this.getTranslationKey() + ".unbound.info"); ToolTipHelper.processTranslation(list, this.getDescriptionId() + ".unbound.info");
} }
} }
} }

View file

@ -3,10 +3,14 @@ package org.dimdev.dimdoors.item;
import java.util.List; import java.util.List;
import net.minecraft.client.item.TooltipContext; import net.minecraft.client.item.TooltipContext;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Vec3i;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.Item; import net.minecraft.item.Item;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.network.chat.Component;
import net.minecraft.sound.SoundCategory; import net.minecraft.sound.SoundCategory;
import net.minecraft.sounds.SoundSource;
import net.minecraft.text.MutableText; import net.minecraft.text.MutableText;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.text.TranslatableTextContent; import net.minecraft.text.TranslatableTextContent;
@ -16,16 +20,28 @@ import net.minecraft.util.TypedActionResult;
import net.minecraft.util.hit.HitResult; import net.minecraft.util.hit.HitResult;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3i; import net.minecraft.util.math.Vec3i;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.InteractionResultHolder;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.fabricmc.api.EnvType; import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment; import net.fabricmc.api.Environment;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item; import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.TooltipFlag;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.SoundType;
import net.minecraft.world.phys.HitResult;
import org.dimdev.dimdoors.DimensionalDoors; import org.dimdev.dimdoors.DimensionalDoors;
import org.dimdev.dimdoors.block.entity.DetachedRiftBlockEntity; import org.dimdev.dimdoors.block.entity.DetachedRiftBlockEntity;
import org.dimdev.dimdoors.block.entity.RiftBlockEntity; import org.dimdev.dimdoors.block.entity.RiftBlockEntity;
import org.dimdev.dimdoors.sound.ModSoundEvents; import org.dimdev.dimdoors.sound.ModSoundEvents;
import org.jetbrains.annotations.Nullable;
import static com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type.Text;
public class RiftStabilizerItem extends Item { public class RiftStabilizerItem extends Item {
public RiftStabilizerItem(Item.Properties settings) { public RiftStabilizerItem(Item.Properties settings) {
@ -33,40 +49,38 @@ public class RiftStabilizerItem extends Item {
} }
@Override @Override
public TypedActionResult<ItemStack> use(World world, PlayerEntity player, Hand hand) { public InteractionResultHolder<ItemStack> use(Level world, Player player, InteractionHand hand) {
ItemStack stack = player.getStackInHand(hand); ItemStack stack = player.getItemInHand(hand);
HitResult hit = player.raycast(RaycastHelper.REACH_DISTANCE, 0, false); HitResult hit = player.pick(RaycastHelper.REACH_DISTANCE, 0, false);
if (world.isClient) { if (world.isClientSide) {
if (RaycastHelper.hitsDetachedRift(hit, world)) { if (RaycastHelper.hitsDetachedRift(hit, world)) {
// TODO: not necessarily success, fix this and all other similar cases to make arm swing correct // TODO: not necessarily success, fix this and all other similar cases to make arm swing correct
return new TypedActionResult<>(ActionResult.SUCCESS, stack); return new InteractionResultHolder<>(InteractionResult.SUCCESS, stack);
} else { } else {
player.sendMessage(Text.translatable("tools.rift_miss"), true); player.displayClientMessage(Component.translatable("tools.rift_miss"), true);
RiftBlockEntity.showRiftCoreUntil = System.currentTimeMillis() + DimensionalDoors.getConfig().getGraphicsConfig().highlightRiftCoreFor; RiftBlockEntity.showRiftCoreUntil = System.currentTimeMillis() + DimensionalDoors.getConfig().getGraphicsConfig().highlightRiftCoreFor;
return new TypedActionResult<>(ActionResult.FAIL, stack); return new InteractionResultHolder<>(InteractionResult.FAIL, stack);
} }
} }
if (RaycastHelper.hitsDetachedRift(hit, world)) { if (RaycastHelper.hitsDetachedRift(hit, world)) {
DetachedRiftBlockEntity rift = (DetachedRiftBlockEntity) world.getBlockEntity(new BlockPos(new Vec3i((int) hit.getPos().x, (int) hit.getPos().y, (int) hit.getPos().z))); DetachedRiftBlockEntity rift = (DetachedRiftBlockEntity) world.getBlockEntity(new BlockPos(new Vec3i((int) hit.getLocation().x, (int) hit.getLocation().y, (int) hit.getLocation().z)));
if (!rift.stabilized && !rift.closing) { if (!rift.stabilized && !rift.closing) {
rift.setStabilized(true); rift.setStabilized(true);
world.playSound(null, player.getBlockPos(), ModSoundEvents.RIFT_CLOSE, SoundCategory.BLOCKS, 0.6f, 1); // TODO: different sound world.playSound(null, player.blockPosition(), ModSoundEvents.RIFT_CLOSE.get(), SoundSource.BLOCKS, 0.6f, 1); // TODO: different sound
stack.damage(1, player, a -> { stack.hurtAndBreak(1, player, a -> {});
}); player.displayClientMessage(Component.translatable(this.getDescriptionId() + ".stabilized"), true);
player.sendMessage(Text.translatable(this.getTranslationKey() + ".stabilized"), true); return new InteractionResultHolder<>(InteractionResult.SUCCESS, stack);
return new TypedActionResult<>(ActionResult.SUCCESS, stack);
} else { } else {
player.sendMessage(Text.translatable(this.getTranslationKey() + ".already_stabilized"), true); player.displayClientMessage(Component.translatable(this.getDescriptionId() + ".already_stabilized"), true);
} }
} }
return new TypedActionResult<>(ActionResult.FAIL, stack); return new InteractionResultHolder<>(InteractionResult.FAIL, stack);
} }
@Environment(EnvType.CLIENT)
@Override @Override
public void appendTooltip(ItemStack itemStack, World world, List<Text> list, TooltipContext tooltipContext) { public void appendHoverText(ItemStack itemStack, @Nullable Level level, List<Component> list, TooltipFlag tooltipFlag) {
list.add(Text.translatable(this.getTranslationKey() + ".info")); list.add(Component.translatable(this.getDescriptionId() + ".info"));
} }
} }

View file

@ -1,23 +1,26 @@
package org.dimdev.dimdoors.item; package org.dimdev.dimdoors.item;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.core.BlockPos;
import net.minecraft.item.Item; import net.minecraft.core.Direction;
import net.minecraft.item.ItemPlacementContext; import net.minecraft.item.ItemPlacementContext;
import net.minecraft.item.ItemStack; import net.minecraft.nbt.CompoundTag;
import net.minecraft.item.ItemUsageContext;
import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtCompound;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.world.ServerWorld; import net.minecraft.server.world.ServerWorld;
import net.minecraft.sound.SoundCategory; import net.minecraft.sound.SoundCategory;
import net.minecraft.text.MutableText; import net.minecraft.sounds.SoundSource;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.text.TranslatableTextContent;
import net.minecraft.util.ActionResult; import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand; import net.minecraft.world.InteractionHand;
import net.minecraft.util.math.BlockPos; import net.minecraft.world.InteractionResult;
import net.minecraft.util.math.Direction;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item; import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.item.context.UseOnContext;
import net.minecraft.world.level.Level;
import org.dimdev.dimdoors.DimensionalDoors; import org.dimdev.dimdoors.DimensionalDoors;
import org.dimdev.dimdoors.api.util.Location; import org.dimdev.dimdoors.api.util.Location;
import org.dimdev.dimdoors.api.util.RotatedLocation; import org.dimdev.dimdoors.api.util.RotatedLocation;
@ -34,82 +37,81 @@ public class StabilizedRiftSignatureItem extends Item { // TODO: common supercla
} }
@Override @Override
public boolean hasGlint(ItemStack stack) { public boolean isFoil(ItemStack stack) {
return stack.getNbt() != null && stack.getNbt().contains("destination"); return stack.getTag() != null && stack.getTag().contains("destination");
} }
@Override @Override
public ActionResult useOnBlock(ItemUsageContext itemUsageContext) { public InteractionResult useOn(UseOnContext itemUsageContext) {
PlayerEntity player = itemUsageContext.getPlayer(); Player player = itemUsageContext.getPlayer();
World world = itemUsageContext.getWorld(); Level world = itemUsageContext.getLevel();
BlockPos pos = itemUsageContext.getBlockPos(); BlockPos pos = itemUsageContext.getClickedPos()();
Hand hand = itemUsageContext.getHand(); InteractionHand hand = itemUsageContext.getHand();
Direction side = itemUsageContext.getSide(); Direction side = itemUsageContext.getClickedFace();
ItemPlacementContext itemPlacementContext = new ItemPlacementContext(itemUsageContext); BlockPlaceContext itemPlacementContext = new BlockPlaceContext(itemUsageContext);
ItemStack stack = player.getStackInHand(hand); ItemStack stack = player.getItemInHand(hand);
pos = world.getBlockState(pos).getBlock().canReplace(world.getBlockState(pos), new ItemPlacementContext(itemUsageContext)) ? pos : pos.offset(side); pos = world.getBlockState(pos).getBlock().canBeReplaced(world.getBlockState(pos), new BlockPlaceContext(itemUsageContext)) ? pos : pos.relative(side);
// Fail if the player can't place a block there // Fail if the player can't place a block there
if (!player.canPlaceOn(pos, side.getOpposite(), stack)) { if (!player.mayUseItemAt(pos, side.getOpposite(), stack)) {
return ActionResult.FAIL; return InteractionResult.FAIL;
} }
if (world.isClient) { if (world.isClientSide) {
return ActionResult.SUCCESS; return InteractionResult.SUCCESS;
} }
RotatedLocation target = getTarget(stack); RotatedLocation target = getTarget(stack);
if (target == null) { if (target == null) {
// The link signature has not been used. Store its current target as the first location. // The link signature has not been used. Store its current target as the first location.
setSource(stack, new RotatedLocation(world.getRegistryKey(), pos, player.getYaw(), 0)); setSource(stack, new RotatedLocation(world.dimension(), pos, player.getYRot(), 0));
player.sendMessage(Text.translatable(this.getTranslationKey() + ".stored"), true); player.displayClientMessage(Component.translatable(this.getDescriptionId() + ".stored"), true);
world.playSound(null, player.getBlockPos(), ModSoundEvents.RIFT_START, SoundCategory.BLOCKS, 0.6f, 1); world.playSound(null, player.blockPosition(), ModSoundEvents.RIFT_START.get(), SoundSource.BLOCKS, 0.6f, 1);
} else { } else {
// Place a rift at the target point // Place a rift at the target point
if (target.getBlockState().getBlock() != ModBlocks.DETACHED_RIFT) { if (target.getBlockState().getBlock() != ModBlocks.DETACHED_RIFT) {
if (!target.getBlockState().getBlock().canReplace(world.getBlockState(target.getBlockPos()), itemPlacementContext)) { if (!target.getBlockState().getBlock().canBeReplaced(world.getBlockState(target.getBlockPos()), itemPlacementContext)) {
player.sendMessage(Text.translatable("tools.target_became_block"), true); player.displayClientMessage(Component.translatable("tools.target_became_block"), true);
// Don't clear source, stabilized signatures always stay bound // Don't clear source, stabilized signatures always stay bound
return ActionResult.FAIL; return InteractionResult.FAIL;
} }
World targetWorld = DimensionalDoors.getWorld(target.world); Level targetWorld = DimensionalDoors.getWorld(target.world);
targetWorld.setBlockState(target.getBlockPos(), ModBlocks.DETACHED_RIFT.getDefaultState()); targetWorld.setBlockAndUpdate(target.getBlockPos(), ModBlocks.DETACHED_RIFT.get().defaultBlockState());
DetachedRiftBlockEntity rift1 = (DetachedRiftBlockEntity) target.getBlockEntity(); DetachedRiftBlockEntity rift1 = (DetachedRiftBlockEntity) target.getBlockEntity();
rift1.register(); rift1.register();
} }
// Place a rift at the source point // Place a rift at the source point
world.setBlockState(pos, ModBlocks.DETACHED_RIFT.getDefaultState()); world.setBlockAndUpdate(pos, ModBlocks.DETACHED_RIFT.get().defaultBlockState());
DetachedRiftBlockEntity rift2 = (DetachedRiftBlockEntity) world.getBlockEntity(pos); DetachedRiftBlockEntity rift2 = (DetachedRiftBlockEntity) world.getBlockEntity(pos);
rift2.setDestination(RiftReference.tryMakeRelative(new Location((ServerWorld) world, pos), target)); rift2.setDestination(RiftReference.tryMakeRelative(new Location((ServerLevel) world, pos), target));
rift2.register(); rift2.register();
stack.damage(1, player, playerEntity -> { stack.hurtAndBreak(1, player, playerEntity -> {});
});
player.sendMessage(Text.translatable(this.getTranslationKey() + ".created"), true); player.displayClientMessage(Component.translatable(this.getDescriptionId() + ".created"), true);
world.playSound(null, player.getBlockPos(), ModSoundEvents.RIFT_END, SoundCategory.BLOCKS, 0.6f, 1); world.playSound(null, player.blockPosition(), ModSoundEvents.RIFT_END.get(), SoundSource.BLOCKS, 0.6f, 1);
} }
return ActionResult.SUCCESS; return InteractionResult.SUCCESS;
} }
public static void setSource(ItemStack itemStack, RotatedLocation destination) { public static void setSource(ItemStack itemStack, RotatedLocation destination) {
if (!itemStack.hasNbt()) itemStack.setNbt(new NbtCompound()); if (!itemStack.hasTag()) itemStack.setTag(new CompoundTag());
itemStack.getNbt().put("destination", RotatedLocation.serialize(destination)); itemStack.getTag().put("destination", RotatedLocation.serialize(destination));
} }
public static void clearSource(ItemStack itemStack) { public static void clearSource(ItemStack itemStack) {
if (itemStack.hasNbt()) { if (itemStack.hasTag()) {
itemStack.getNbt().remove("destination"); itemStack.getTag().remove("destination");
} }
} }
public static RotatedLocation getTarget(ItemStack itemStack) { public static RotatedLocation getTarget(ItemStack itemStack) {
if (itemStack.hasNbt() && itemStack.getNbt().contains("destination")) { if (itemStack.hasTag() && itemStack.getTag().contains("destination")) {
return RotatedLocation.deserialize(itemStack.getNbt().getCompound("destination")); return RotatedLocation.deserialize(itemStack.getTag().getCompound("destination"));
} else { } else {
return null; return null;
} }

View file

@ -1,21 +1,18 @@
package org.dimdev.dimdoors.item.door; package org.dimdev.dimdoors.item.door;
import java.util.function.Consumer; import net.minecraft.core.BlockPos;
import net.minecraft.world.InteractionResult;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.item.BlockItem;
import net.minecraft.item.ItemPlacementContext;
import net.minecraft.util.ActionResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraft.world.item.BlockItem; import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.Item; import net.minecraft.world.item.Item;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import org.dimdev.dimdoors.block.RiftProvider; import org.dimdev.dimdoors.block.RiftProvider;
import org.dimdev.dimdoors.block.entity.EntranceRiftBlockEntity; import org.dimdev.dimdoors.block.entity.EntranceRiftBlockEntity;
import java.util.function.Consumer;
public class DimensionalTrapdoorItem extends BlockItem { public class DimensionalTrapdoorItem extends BlockItem {
private final Consumer<? super EntranceRiftBlockEntity> setupFunction; private final Consumer<? super EntranceRiftBlockEntity> setupFunction;
@ -25,20 +22,20 @@ public class DimensionalTrapdoorItem extends BlockItem {
} }
@Override @Override
public ActionResult place(ItemPlacementContext context) { public InteractionResult place(BlockPlaceContext context) {
World world = context.getWorld(); Level world = context.getLevel();
BlockPos pos = context.getBlockPos(); BlockPos pos = context.getClickedPos();
if (world.isClient) { if (world.isClientSide) {
return super.place(context); return super.place(context);
} }
boolean replaceable = world.getBlockState(pos).canReplace(context); // Check this before calling super, since that changes the block boolean replaceable = world.getBlockState(pos).canBeReplaced(context); // Check this before calling super, since that changes the block
ActionResult result = super.place(context); InteractionResult result = super.place(context);
if (result == ActionResult.SUCCESS) { if (result == InteractionResult.SUCCESS) {
if (!replaceable) { if (!replaceable) {
pos = pos.offset(context.getPlayerLookDirection()); pos = pos.relative(context.getNearestLookingDirection());
} }
BlockState state = world.getBlockState(pos); BlockState state = world.getBlockState(pos);
@ -49,7 +46,7 @@ public class DimensionalTrapdoorItem extends BlockItem {
this.setupRift(entranceRift); this.setupRift(entranceRift);
// Register the rift in the registry // Register the rift in the registry
entranceRift.markDirty(); entranceRift.setChanged();
entranceRift.register(); entranceRift.register();
} }

View file

@ -0,0 +1,28 @@
package org.dimdev.dimdoors.mixin;
import com.mojang.brigadier.arguments.ArgumentType;
import net.minecraft.commands.synchronization.ArgumentTypeInfo;
import net.minecraft.commands.synchronization.ArgumentTypeInfos;
import net.minecraft.commands.synchronization.SingletonArgumentInfo;
import net.minecraft.core.Registry;
import org.dimdev.dimdoors.command.arguments.BlockPlacementTypeArgumentType;
import org.dimdev.dimdoors.command.arguments.PocketTemplateArgumentType;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(ArgumentTypeInfos.class)
public abstract class ArgumentTypesMixin {
@Shadow
private static <A extends ArgumentType<?>, T extends ArgumentTypeInfo.Template<A>> ArgumentTypeInfo<A, T> register(Registry<ArgumentTypeInfo<?, ?>> registry, String string, Class<? extends A> clazz, ArgumentTypeInfo<A, T> argumentSerializer) {
throw new AssertionError("Nope.");
}
@Inject(method = "bootstrap", at = @At("RETURN"))
private static void register(Registry<ArgumentTypeInfo<?, ?>> registry, CallbackInfoReturnable<ArgumentTypeInfo<?, ?>> ci) {
register(registry, "pocket", PocketTemplateArgumentType.class, SingletonArgumentInfo.contextFree(PocketTemplateArgumentType::new));
register(registry, "block_placement_type", BlockPlacementTypeArgumentType.class, SingletonArgumentInfo.contextFree(BlockPlacementTypeArgumentType::blockPlacementType));
}
}

View file

@ -0,0 +1,23 @@
package org.dimdev.dimdoors.mixin;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import org.dimdev.dimdoors.criteria.ModCriteria;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(Block.class)
public class BlockMixin {
@Inject(method = "playerWillDestroy", at = @At(value = "INVOKE", shift = At.Shift.AFTER, target = "Lnet/minecraft/world/level/block/Block;spawnDestroyParticles(Lnet/minecraft/world/level/Level;Lnet/minecraft/world/entity/player/Player;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;)V"))
public void triggerTagBlockBreak(Level world, BlockPos pos, BlockState state, Player player, CallbackInfo ci) {
if (!world.isClientSide()) {
ModCriteria.TAG_BLOCK_BREAK.trigger((ServerPlayer) player, state);
}
}
}

View file

@ -0,0 +1,31 @@
package org.dimdev.dimdoors.mixin;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.world.level.block.state.properties.BlockSetType;
import org.dimdev.dimdoors.block.DoorSoundProvider;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@Mixin(DoorSoundProvider.class)
public abstract class DoorBlockMixin implements DoorSoundProvider {
@Shadow
@Final
private BlockSetType blockSetType;
@Override
public SoundEvent getOpenSound() {
return this.blockSetType.doorOpen();
}
@Override
public SoundEvent getCloseSound() {
return this.blockSetType.doorClose();
}
@Override
public BlockSetType getSetType() {
return this.blockSetType;
}
}

View file

@ -0,0 +1,24 @@
package org.dimdev.dimdoors.mixin;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.phys.Vec3;
import org.dimdev.dimdoors.api.entity.LastPositionProvider;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(Entity.class)
public abstract class EntityMixin implements LastPositionProvider {
private Vec3 lastPos;
@Inject(method = "checkInsideBlocks()V", at = @At("TAIL"))
public void checkBlockCollisionSaveLastPos(CallbackInfo ci) {
lastPos = ((Entity) (Object) this).position();
}
public Vec3 getLastPos() {
return lastPos == null ? ((Entity) (Object) this).position() : lastPos;
}
}

View file

@ -0,0 +1,44 @@
package org.dimdev.dimdoors.mixin;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import net.minecraft.core.BlockPos;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.level.Explosion;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import org.dimdev.dimdoors.api.block.ExplosionConvertibleBlock;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Mutable;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.stream.Collectors;
@Mixin(Explosion.class)
public class ExplosionMixin {
@Mutable
@Shadow
@Final
private ObjectArrayList<BlockPos> toBlow;
@Shadow
@Final
private Level level;
@Inject(method = "finalizeExplosion", at = @At(value = "INVOKE", target = "Lnet/minecraft/Util;shuffle(Lit/unimi/dsi/fastutil/objects/ObjectArrayList;Lnet/minecraft/util/RandomSource;)V", ordinal = 0, shift = At.Shift.AFTER))
private void handleExplosionConvertibleBlocks(boolean b1, CallbackInfo ci) {
this.toBlow = this.toBlow.stream().filter(blockPos -> {
BlockState state = this.level.getBlockState(blockPos);
Block block = state.getBlock();
if (!(block instanceof ExplosionConvertibleBlock)) {
return true;
}
InteractionResult result = ((ExplosionConvertibleBlock) block).explode(this.level, blockPos, state, state.hasBlockEntity() ? this.level.getBlockEntity(blockPos) : null);
return result == InteractionResult.PASS;
}).collect(Collectors.toCollection(ObjectArrayList::new));
}
}

View file

@ -0,0 +1,26 @@
package org.dimdev.dimdoors.mixin;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.network.ServerGamePacketListenerImpl;
import org.dimdev.dimdoors.network.ExtendedServerPlayNetworkHandler;
import org.dimdev.dimdoors.network.ServerPacketHandler;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@Mixin(ServerGamePacketListenerImpl.class)
public class ExtendedServerPlayNetworkhandlerMixin implements ExtendedServerPlayNetworkHandler {
@Final @Shadow
private MinecraftServer server;
private final ServerPacketHandler dimdoorsServerPacketHandler = new ServerPacketHandler((ServerGamePacketListenerImpl) (Object) this);
@Override
public ServerPacketHandler getDimDoorsPacketHandler() {
return dimdoorsServerPacketHandler;
}
@Override
public MinecraftServer dimdoorsGetServer() {
return server;
}
}

View file

@ -0,0 +1,37 @@
package org.dimdev.dimdoors.mixin;
import net.minecraft.world.item.Item;
import org.dimdev.dimdoors.item.ItemExtensions;
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.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(Item.class)
public class ItemMixin implements ItemExtensions {
@Unique
private Item.Properties settings;
@Inject(method = "<init>", at = @At("TAIL"))
public void cacheSettings(Item.Properties settings, CallbackInfo ci) {
this.settings = settings;
}
@Override
public Item.Properties dimdoors_getSettings() {
return settings;
}
@Mixin(Item.Properties.class)
public static class SettingsMixin implements SettingsExtensions {
@Override
public Item.Properties clone() {
try {
return (Item.Properties) super.clone();
} catch (CloneNotSupportedException e) {
throw new AssertionError(e); // Cant happen, we are Cloneable
}
}
}
}

View file

@ -0,0 +1,52 @@
package org.dimdev.dimdoors.mixin;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import org.dimdev.dimdoors.DimensionalDoors;
import org.dimdev.dimdoors.mixin.accessor.EntityAccessor;
import org.dimdev.dimdoors.world.ModDimensions;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(value = Player.class, priority = 900)
public abstract class PlayerEntityMixin extends LivingEntity {
@Shadow
public abstract void awardStat(ResourceLocation stat);
public PlayerEntityMixin(EntityType<? extends LivingEntity> entityType, Level world) {
super(entityType, world);
}
@Inject(method = "causeFallDamage", at = @At("HEAD"), cancellable = true)
public void handleLimboFallDamage(float fallDistance, float damageMultiplier, DamageSource damageSource, CallbackInfoReturnable<Boolean> cir) {
if (ModDimensions.isLimboDimension(level)) {
cir.setReturnValue(false);
}
}
@Inject(method = "die", at = @At("HEAD"), cancellable = true)
public void checkDeath(DamageSource source, CallbackInfo ci) {
this.doOnDeathStuff(source, ci);
}
@Unique
protected void doOnDeathStuff(DamageSource source, CallbackInfo ci) {
if (ModDimensions.isPocketDimension(this.level) || DimensionalDoors.getConfig().getLimboConfig().universalLimbo) {
((EntityAccessor) this).setRemovalReason(null);
this.dead = false;
this.setHealth(this.getMaxHealth());
ci.cancel();
}
}
}

View file

@ -0,0 +1,68 @@
package org.dimdev.dimdoors.mixin;
import net.minecraft.core.BlockPos;
import net.minecraft.network.protocol.game.ServerboundMovePlayerPacket;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.network.ServerGamePacketListenerImpl;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.AABB;
import org.dimdev.dimdoors.api.block.AfterMoveCollidableBlock;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(ServerGamePacketListenerImpl.class)
public class ServerPlayNetworkHandlerMixin {
@Shadow
public ServerPlayer player;
@Shadow
private double firstGoodX;
@Shadow
private double firstGoodY;
@Shadow
private double firstGoodZ;
@Shadow private double lastGoodX;
@Shadow private double lastGoodY;
@Shadow private double lastGoodZ;
@Inject(method = "handleMovePlayer", at = @At("TAIL"))
protected void checkBlockCollision(ServerboundMovePlayerPacket packet, CallbackInfo ci) {
// stolen from Entity#checkBlockCollision
AABB box = player.getBoundingBox();
BlockPos blockPos = new BlockPos((int) (box.minX + 0.001D), (int) (box.minY + 0.001D), (int) (box.minZ + 0.001D));
BlockPos blockPos2 = new BlockPos((int) (box.maxX - 0.001D), (int) (box.maxY - 0.001D), (int) (box.maxZ - 0.001D));
if (player.level.hasChunksAt(blockPos, blockPos2)) {
BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos();
boolean done = false;
for(int i = blockPos.getX(); i <= blockPos2.getX(); ++i) {
for(int j = blockPos.getY(); j <= blockPos2.getY(); ++j) {
for(int k = blockPos.getZ(); k <= blockPos2.getZ(); ++k) {
mutable.set(i, j, k);
BlockState blockState = player.level.getBlockState(mutable);
Block block = blockState.getBlock();
if (block instanceof AfterMoveCollidableBlock && ((AfterMoveCollidableBlock) block).onAfterMovePlayerCollision(blockState, player.getLevel(), mutable, player, player.position().subtract(lastGoodX, lastGoodY, lastGoodZ)).consumesAction()) {
done = true;
}
if (done) {
break;
}
}
if (done) {
break;
}
}
if (done) {
break;
}
}
}
}
}

View file

@ -0,0 +1,155 @@
package org.dimdev.dimdoors.mixin;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.stats.ServerRecipeBook;
import net.minecraft.stats.Stat;
import net.minecraft.util.RandomSource;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState;
import org.dimdev.dimdoors.api.util.TeleportUtil;
import org.dimdev.dimdoors.block.UnravelledFabricBlock;
import org.dimdev.dimdoors.criteria.ModCriteria;
import org.dimdev.dimdoors.entity.limbo.LimboEntranceSource;
import org.dimdev.dimdoors.entity.stat.ModStats;
import org.dimdev.dimdoors.world.ModDimensions;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(value = ServerPlayer.class, priority = 900)
public abstract class ServerPlayerEntityMixin extends PlayerEntityMixin {
@Shadow
@Final
private ServerRecipeBook recipeBook;
@Shadow
public abstract void readAdditionalSaveData(CompoundTag nbt);
@Shadow public abstract void awardStat(Stat<?> arg, int i);
private static final float RANDOM_ACTION_CHANCE = 0.1F;
private static final float CHANCE_TO_MAKE_LIMBO_LIKE_OTHER_DIMENSIONS = 0.1F;
private static final int CHUNK_SIZES = 25;
private static final int POSITION_AWAY = 50;
private static final float RANDOM_LIQUID_CHANCE = 0.7F;
@Unique
RandomSource dimdoors_random = RandomSource.create();
public ServerPlayerEntityMixin(EntityType<? extends LivingEntity> entityType, Level world) {
super(entityType, world);
}
@Inject(method = "tick", at = @At("HEAD"))
public void playerTickMixin(CallbackInfo ci) {
if (dimdoors_random.nextFloat() <= RANDOM_ACTION_CHANCE) {
if(ModDimensions.isLimboDimension(((Player)(Object)(this)).getLevel())) {
tryMakingLimboLikeOtherDimensions((Player)(Object)this);
}
}
}
private boolean isValidBlockToReplace(Level world, BlockPos pos) {
return world.getBlockState(pos.above()).isAir() && world.getBlockState(pos).getBlock() instanceof UnravelledFabricBlock;
}
private void makeLimboLikeOverworld(Player player) {
/*
World world = player.getEntityWorld();
BlockPos pos = player.getBlockPos().add(random.nextInt(random.nextInt(POSITION_AWAY)), 0, random.nextInt(POSITION_AWAY));
if(random.nextFloat() <= RANDOM_LIQUID_CHANCE) {
makeSpotOfLiquid(world, pos, Blocks.WATER.getDefaultState(), 3);
}
BlockPos.iterateOutwards(pos, CHUNK_SIZES, 15, CHUNK_SIZES).forEach( (blockPos -> {
if(isValidBlockToReplace(world, blockPos)) {
world.setBlockState(blockPos, Blocks.GRASS_BLOCK.getDefaultState());
}
}));
*/
}
private void makeLimboLikeEnd(Player player) {
/*
World world = player.getEntityWorld();
BlockPos pos = player.getBlockPos().add(random.nextInt(POSITION_AWAY), 0, random.nextInt(POSITION_AWAY));
BlockPos.iterateOutwards(pos, CHUNK_SIZES, 15, CHUNK_SIZES).forEach( (blockPos -> {
if(isValidBlockToReplace(world, blockPos)) {
world.setBlockState(blockPos, Blocks.END_STONE.getDefaultState());
}
}));
*/
}
private void makeSpotOfLiquid(Level world, BlockPos pos, BlockState state, int range) {
BlockPos.withinManhattan(pos, dimdoors_random.nextInt(range), dimdoors_random.nextInt(range), dimdoors_random.nextInt(range)).forEach( (blockPos -> {
if(isValidBlockToReplace(world, blockPos)) {
world.setBlockAndUpdate(blockPos, state);
}
}));
}
private void makeLimboLikeNether(Player player) {
/*
World world = player.getEntityWorld();
BlockPos pos = player.getBlockPos().add(random.nextInt(POSITION_AWAY), 0, random.nextInt(POSITION_AWAY));
if(random.nextFloat() <= RANDOM_LIQUID_CHANCE) {
makeSpotOfLiquid(world, pos, Blocks.LAVA.getDefaultState(), 10);
}
BlockPos.iterateOutwards(pos, CHUNK_SIZES, 15, CHUNK_SIZES).forEach( (blockPos -> {
if(isValidBlockToReplace(world, blockPos)) {
world.setBlockState(blockPos, Blocks.NETHERRACK.getDefaultState());
}
}));
*/
}
private void tryMakingLimboLikeOtherDimensions(Player player) {
if(dimdoors_random.nextFloat() > CHANCE_TO_MAKE_LIMBO_LIKE_OTHER_DIMENSIONS) {
return;
}
switch (dimdoors_random.nextInt(3)) {
case 0 -> makeLimboLikeOverworld(player);
case 1 -> makeLimboLikeNether(player);
case 2 -> makeLimboLikeEnd(player);
}
}
@Inject(method = "die", at = @At("HEAD"), cancellable = true)
public void checkDeathServer(DamageSource source, CallbackInfo ci) {
this.doOnDeathStuff(source, ci);
if (ci.isCancelled()) {
if (ModDimensions.isPocketDimension(this.level)) {
this.awardStat(ModStats.DEATHS_IN_POCKETS);
}
this.awardStat(ModStats.TIMES_SENT_TO_LIMBO);
TeleportUtil.teleportRandom(this, ModDimensions.LIMBO_DIMENSION, 512);
//noinspection ConstantConditions
LimboEntranceSource.ofDamageSource(source).broadcast((Player) (Object) this, this.getServer());
}
}
@Inject(method = "setRespawnPosition", at = @At("TAIL"))
public void onSpawnPointSet(ResourceKey<Level> dimension, BlockPos pos, float angle, boolean spawnPointSet, boolean bl, CallbackInfo ci) {
if (ModDimensions.isPocketDimension(dimension)) {
ModCriteria.POCKET_SPAWN_POINT_SET.trigger((ServerPlayer) (Object) this);
}
}
}

View file

@ -0,0 +1,27 @@
package org.dimdev.dimdoors.mixin;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.level.ServerPlayerGameMode;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.BlockHitResult;
import org.dimdev.dimdoors.api.event.UseItemOnBlockCallback;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(ServerPlayerGameMode.class)
public class ServerPlayerInteractionManagerMixin {
@Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerPlayerGameMode;isCreative()Z", ordinal = 0), method = "useItemOn", cancellable = true)
public void useItemOnBlock(ServerPlayer serverPlayer, Level level, ItemStack itemStack, InteractionHand interactionHand, BlockHitResult blockHitResult, CallbackInfoReturnable<InteractionResult> cir) {
InteractionResult result = UseItemOnBlockCallback.EVENT.invoker().useItemOnBlock(serverPlayer, level, interactionHand, blockHitResult);
if (result != InteractionResult.PASS) {
cir.setReturnValue(result);
cir.cancel();
}
}
}

View file

@ -0,0 +1,19 @@
package org.dimdev.dimdoors.mixin;
import net.minecraft.server.level.ServerLevel;
import org.dimdev.dimdoors.world.decay.LimboDecay;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.function.BooleanSupplier;
@Mixin(ServerLevel.class)
public abstract class ServerWorldMixin {
@Inject(method = "tick(Ljava/util/function/BooleanSupplier;)V", at = @At(target = "Lnet/minecraft/server/level/ServerLevel;fluidTicks:Lnet/minecraft/world/ticks/LevelTicks;", value = "FIELD", ordinal = 0, shift = At.Shift.AFTER))
public void afterScheduledTick(BooleanSupplier shouldKeepTicking, CallbackInfo ci) {
LimboDecay.tick((ServerLevel) (Object) this);
}
}

View file

@ -0,0 +1,32 @@
package org.dimdev.dimdoors.mixin;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.world.level.block.TrapDoorBlock;
import net.minecraft.world.level.block.state.properties.BlockSetType;
import org.dimdev.dimdoors.block.DoorSoundProvider;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@Mixin(TrapDoorBlock.class)
public class TrapDoorMixin implements DoorSoundProvider {
@Shadow
@Final
private BlockSetType type;
@Override
public SoundEvent getOpenSound() {
return this.type.doorOpen();
}
@Override
public SoundEvent getCloseSound() {
return this.type.doorClose();
}
@Override
public BlockSetType getSetType() {
return this.type;
}
}

View file

@ -0,0 +1,86 @@
package org.dimdev.dimdoors.mixin;
import com.mojang.datafixers.util.Pair;
import net.minecraft.core.BlockPos;
import net.minecraft.world.InteractionResultHolder;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.FluidState;
import org.dimdev.dimdoors.api.block.CustomBreakBlock;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
import java.util.function.Consumer;
@Mixin(Level.class)
public abstract class WorldMixin {
/*
I thought about redirecting the entire break method to be handled by the block itself,
but I am not quite sure what that would mean for compatibility with other mixins,
since then a large part of the method would need to be canceled. This is rather hacky, but it should fulfill the purpose best
~CreepyCre
*/
@Redirect(method = "destroyBlock",
at = @At(value = "INVOKE_ASSIGN",
target = "Lnet/minecraft/world/level/Level;getFluidState(Lnet/minecraft/core/BlockPos;)Lnet/minecraft/world/level/material/FluidState;",
ordinal = 0))
private FluidState replaceFluidStateWithCustomHackyFluidState(FluidState original, BlockPos pos, boolean drop, @Nullable Entity breakingEntity, int maxUpdateDepth) { //TODO: Fix
Level world = (Level) (Object) this;
BlockState blockState = world.getBlockState(pos);
Block block = blockState.getBlock();
if (!(block instanceof CustomBreakBlock)) {
return original;
}
InteractionResultHolder<Pair<BlockState, Consumer<BlockEntity>>> result = ((CustomBreakBlock) block).customBreakBlock(world, pos, blockState, breakingEntity);
if (!result.getResult().consumesAction()) {
return original;
}
Pair<BlockState, Consumer<BlockEntity>> pair = result.getObject();
return new CustomBreakBlock.HackyFluidState(pair.getFirst(), pair.getSecond());
}
@Inject(method = "destroyBlock",
locals = LocalCapture.CAPTURE_FAILHARD,
at = @At(value = "INVOKE",
target = "Lnet/minecraft/world/level/Level;setBlock(Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;II)Z",
ordinal = 0,
shift = At.Shift.AFTER))
private void applyBlockEntityModification(BlockPos pos, boolean drop, Entity breakingEntity, int maxUpdateDepth, CallbackInfoReturnable<Boolean> cir, BlockState blockState, FluidState fluidState) {
if (!(fluidState instanceof CustomBreakBlock.HackyFluidState)) {
return;
}
Consumer<BlockEntity> blockEntityConsumer = ((CustomBreakBlock.HackyFluidState) fluidState).getBlockEntityConsumer();
if (blockEntityConsumer == null) {
return;
}
BlockEntity blockEntity = ((Level) (Object) this).getBlockEntity(pos);
if (blockEntity != null) {
blockEntityConsumer.accept(blockEntity);
}
}
/*
This is where I'd inject if it turns out the method used above does actually have an issue
*/
// @Inject(method = "Lnet/minecraft/world/World;breakBlock(Lnet/minecraft/util/math/BlockPos;ZLnet/minecraft/entity/Entity;I)Z",
// cancellable = true,
// at = @At(
// value = "INVOKE",
// target = "Lnet/minecraft/world/WorldAccess;syncWorldEvent(ILnet/minecraft/util/math/BlockPos;I)V",
// ordinal = 0,
// shift = At.Shift.BY,
// by = 2
// )
// )
}

View file

@ -0,0 +1,8 @@
package org.dimdev.dimdoors.mixin.accessor;
import net.minecraft.world.level.chunk.ChunkGenerator;
import org.spongepowered.asm.mixin.Mixin;
@Mixin(ChunkGenerator.class)
public interface ChunkGeneratorAccessor {
}

View file

@ -0,0 +1,15 @@
package org.dimdev.dimdoors.mixin.accessor;
import net.minecraft.core.NonNullList;
import net.minecraft.world.inventory.CraftingContainer;
import net.minecraft.world.item.ItemStack;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Mutable;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(CraftingContainer.class)
public interface CraftingInventoryAccessor {
@Mutable
@Accessor("items")
void setInventory(NonNullList<ItemStack> inventory);
}

View file

@ -0,0 +1,13 @@
package org.dimdev.dimdoors.mixin.accessor;
import net.minecraft.core.particles.SimpleParticleType;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;
@Mixin(SimpleParticleType.class)
public interface DefaultParticleTypeAccessor {
@Invoker("<init>")
static SimpleParticleType createDefaultParticleType(boolean alwaysShow) {
throw new UnsupportedOperationException();
}
}

View file

@ -0,0 +1,13 @@
package org.dimdev.dimdoors.mixin.accessor;
import net.minecraft.core.Direction;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(Direction.class)
public interface DirectionAccessor {
@Accessor("BY_2D_DATA")
static Direction[] getHorizontal() {
throw new AssertionError();
}
}

View file

@ -0,0 +1,11 @@
package org.dimdev.dimdoors.mixin.accessor;
import net.minecraft.world.entity.Entity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(Entity.class)
public interface EntityAccessor {
@Accessor
void setRemovalReason(Entity.RemovalReason removalReason);
}

View file

@ -0,0 +1,17 @@
package org.dimdev.dimdoors.mixin.accessor;
import net.minecraft.core.HolderSet;
import net.minecraft.world.level.biome.BiomeGenerationSettings;
import net.minecraft.world.level.levelgen.placement.PlacedFeature;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Mutable;
import org.spongepowered.asm.mixin.gen.Accessor;
import java.util.List;
@Mixin(BiomeGenerationSettings.class)
public interface GenerationSettingsAccessor {
@Mutable
@Accessor
void setFeatures(List<HolderSet<PlacedFeature>> features);
}

View file

@ -0,0 +1,16 @@
package org.dimdev.dimdoors.mixin.accessor;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.Tag;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;
import java.util.List;
@Mixin(ListTag.class)
public interface ListTagAccessor {
@Invoker("<init>")
static ListTag createListTag(List<Tag> list, byte type) {
throw new UnsupportedOperationException();
}
}

View file

@ -0,0 +1,23 @@
package org.dimdev.dimdoors.mixin.accessor;//TODO: Disabled unsure if needed.
//package org.dimdev.dimdoors.mixin.accessor;
//
//import com.google.gson.JsonObject;
//import net.minecraft.data.DataWriter;
//import net.minecraft.data.server.recipe.RecipeProvider;
//import org.spongepowered.asm.mixin.Mixin;
//import org.spongepowered.asm.mixin.gen.Invoker;
//
//import java.nio.file.Path;
//
//@Mixin(RecipeProvider.class)
//public interface RecipesProviderAccessor {
// @Invoker
// static void callSaveRecipe(DataWriter cache, JsonObject json, Path path) {
// throw new UnsupportedOperationException();
// }
//
// @Invoker
// static void callSaveRecipeAdvancement(DataWriter cache, JsonObject json, Path path) {
// throw new UnsupportedOperationException();
// }
//}

View file

@ -0,0 +1,15 @@
package org.dimdev.dimdoors.mixin.accessor;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.block.RedStoneWireBlock;
import net.minecraft.world.level.block.state.properties.RedstoneSide;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;
@Mixin(RedStoneWireBlock.class)
public interface RedstoneWireBlockAccessor {
@Invoker
RedstoneSide invokeGetConnectingSide(BlockGetter blockGetter, BlockPos blockPos, Direction direction);
}

View file

@ -0,0 +1,22 @@
package org.dimdev.dimdoors.mixin.client;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.renderer.FogRenderer;
import org.spongepowered.asm.mixin.Mixin;
@Environment(EnvType.CLIENT)
@Mixin(FogRenderer.class)
public class BackgroundRendererMixin {
// @ModifyVariable(
// method = "render",
// at = @At(value = "STORE", ordinal = 0),
// ordinal = 0
// )
// private static double modifyVoidColor(double scale) {
// if(ModDimensions.isPrivatePocketDimension(MinecraftClient.getInstance().world)) {
// scale = 1.0;
// }
// return scale;
// }
}

View file

@ -0,0 +1,20 @@
package org.dimdev.dimdoors.mixin.client;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import org.dimdev.dimdoors.network.client.ClientPacketListener;
import org.spongepowered.asm.mixin.Mixin;
@Environment(EnvType.CLIENT)
@Mixin(ClientPacketListener.class)
public class ClientPlayNetworkHandlerMixin {
// @Shadow
// private ClientWorld world;
//
// @Inject(method = "onPlayerPositionLook", at = @At("RETURN"), locals = LocalCapture.CAPTURE_FAILHARD)
// public void onPlayerLookPositionPacket(PlayerPositionLookS2CPacket packet, CallbackInfo ci, PlayerEntity playerEntity, Vec3d vec3d, boolean bl, boolean bl2, boolean bl3, double f, double g, double j, double k, double n, double o, float p, float q) {
// if (ModDimensions.isLimboDimension(this.world)) {
// this.world.addParticle(ModParticleTypes.MONOLITH, playerEntity.getX(), playerEntity.getY(), playerEntity.getZ(), 0.0D, 0.0D, 0.0D);
// }
// }
}

View file

@ -0,0 +1,42 @@
package org.dimdev.dimdoors.mixin.client;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.multiplayer.MultiPlayerGameMode;
import net.minecraft.client.multiplayer.prediction.PredictiveAction;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.network.protocol.game.ServerboundUseItemOnPacket;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.phys.BlockHitResult;
import org.dimdev.dimdoors.api.event.UseItemOnBlockCallback;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(MultiPlayerGameMode.class)
public abstract class ClientPlayerInteractionManagerMixin {
@Shadow
@Final
private Minecraft minecraft;
@Shadow
protected abstract void startPrediction(ClientLevel world, PredictiveAction packetCreator);
@Inject(method = "useItemOn", cancellable = true, at = @At(value = "NEW", target = "org/apache/commons/lang3/mutable/MutableObject", remap = false))
public void useItemOnBlock(LocalPlayer player, InteractionHand hand, BlockHitResult hitResult, CallbackInfoReturnable<InteractionResult> info) {
InteractionResult result = UseItemOnBlockCallback.EVENT.invoker().useItemOnBlock(player, minecraft.level, hand, hitResult);
if (result == InteractionResult.PASS) {
return;
}
info.setReturnValue(result);
info.cancel();
if (result == InteractionResult.SUCCESS) {
this.startPrediction(this.minecraft.level, sequence -> new ServerboundUseItemOnPacket(hand, hitResult, sequence));
}
}
}

View file

@ -0,0 +1,30 @@
package org.dimdev.dimdoors.mixin.client;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientPacketListener;
import org.dimdev.dimdoors.network.client.ClientPacketHandler;
import org.dimdev.dimdoors.network.client.ExtendedClientPlayNetworkHandler;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
@Environment(EnvType.CLIENT)
@Mixin(ClientPacketListener.class)
public class ExtendedClientPlayNetworkHandlerMixin implements ExtendedClientPlayNetworkHandler {
@Final @Shadow
private Minecraft minecraft;
private final ClientPacketHandler dimdoors_PacketHandler = new ClientPacketHandler((ClientPacketListener) (Object) this);
@Unique
public ClientPacketHandler getDimDoorsPacketHandler() {
return dimdoors_PacketHandler;
}
@Unique
public Minecraft dimdoorsGetClient() {
return minecraft;
}
}

View file

@ -0,0 +1,36 @@
package org.dimdev.dimdoors.mixin.client;
import java.io.IOException;
import java.util.List;
import java.util.function.Consumer;
import com.mojang.datafixers.util.Pair;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
import net.minecraft.client.gl.ShaderProgram;
import net.minecraft.client.render.GameRenderer;
import net.minecraft.client.render.VertexFormat;
import net.minecraft.client.render.VertexFormats;
import net.minecraft.resource.ResourceFactory;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import org.dimdev.dimdoors.client.ModShaders;
@Environment(EnvType.CLIENT)
@Mixin(GameRenderer.class)
public abstract class GameRendererMixin {
@Shadow
protected abstract ShaderProgram preloadProgram(ResourceFactory arg, String string, VertexFormat vertexFormat) throws IOException;
@Inject(method = "loadPrograms", at = @At(value = "INVOKE", shift = At.Shift.AFTER, ordinal = 1, target = "java/util/List.add(Ljava/lang/Object;)Z"), locals = LocalCapture.CAPTURE_FAILSOFT)
public void onReload(ResourceFactory manager, CallbackInfo ci, List list, List list2) throws IOException {
list2.add(Pair.of(new ShaderProgram(manager, "dimensional_portal", VertexFormats.POSITION), (Consumer<ShaderProgram>) ModShaders::setDimensionalPortal));
}
}

View file

@ -0,0 +1,36 @@
package org.dimdev.dimdoors.mixin.client;
import com.mojang.blaze3d.vertex.PoseStack;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.gui.Gui;
import net.minecraft.world.entity.player.Player;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Environment(EnvType.CLIENT)
@Mixin(Gui.class)
public abstract class InGameHudMixin{
private int frame = 0;
private static final float OVERLAY_OPACITY_ADJUSTEMENT = 1.5F;
@Shadow
private int screenHeight;
@Shadow
private int screenWidth;
@Shadow
protected abstract Player getCameraPlayer();
// @Inject(at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/systems/RenderSystem;setShader(Ljava/util/function/Supplier;)V"), method = "renderVignetteOverlay(Lnet/minecraft/entity/Entity;)V")
// public void renderVignetteOverlay(Entity entity, CallbackInfo info) {
// if (ModDimensions.isLimboDimension(entity.world)) {
// RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
// }
// }
@Inject(method = "render", at = @At("HEAD"), cancellable = true)
public void renderOverlayMixin(PoseStack matrices, float tickDelta, CallbackInfo ci) {
}
}

View file

@ -0,0 +1,28 @@
package org.dimdev.dimdoors.mixin.client;
import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.EffectInstance;
import net.minecraft.client.renderer.PostPass;
import net.minecraft.world.entity.player.Player;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(PostPass.class)
public class PostProcessShaderMixin {
@Shadow @Final private EffectInstance effect;
@Inject(method = "process(F)V", at = @At("HEAD"), cancellable = true)
public void render(float time, CallbackInfo cir) {
effect.safeGetUniform("GameTime").set(RenderSystem.getShaderGameTime());
}
private Player getCameraPlayer() {
return !(Minecraft.getInstance().getCameraEntity() instanceof Player player) ? null : player;
}
}

View file

@ -0,0 +1,88 @@
package org.dimdev.dimdoors.mixin.client;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.SheetedDecalTextureGenerator;
import com.mojang.blaze3d.vertex.VertexConsumer;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.Camera;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.renderer.*;
import net.minecraft.client.resources.model.ModelBakery;
import net.minecraft.core.BlockPos;
import net.minecraft.world.phys.Vec3;
import org.dimdev.dimdoors.client.CustomBreakBlockHandler;
import org.joml.Matrix4f;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.Map;
@Mixin(LevelRenderer.class)
@Environment(EnvType.CLIENT)
public abstract class WorldRendererMixin {
@Shadow
private ClientLevel level;
@Shadow
private Minecraft minecraft;
@Shadow
@Final
private RenderBuffers renderBuffers;
@Shadow
private int ticks;
@Inject(method = "renderLevel",
at = @At(value = "FIELD", target = "Lnet/minecraft/client/renderer/LevelRenderer;destructionProgress:Lit/unimi/dsi/fastutil/longs/Long2ObjectMap;", ordinal = 1)) // bytecode order is flipped from java code order, notice the ordinal
public void renderCustomBreakBlockAnimation(PoseStack matrices, float tickDelta, long limitTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightTexture lightmapTextureManager, Matrix4f matrix4f, CallbackInfo ci) {
Vec3 vec3d = camera.getPosition();
double d = vec3d.x();
double e = vec3d.y();
double f = vec3d.z();
Map<BlockPos, CustomBreakBlockHandler.BreakBlockInfo> breakBlocks = CustomBreakBlockHandler.getCustomBreakBlockMap(this.ticks);
// stolen from WorldRenderer#render
for (Map.Entry<BlockPos, CustomBreakBlockHandler.BreakBlockInfo> entry : breakBlocks.entrySet()) {
BlockPos pos = entry.getKey();
double h = (double) pos.getX() - d;
double x = (double) pos.getY() - e;
double y = (double) pos.getZ() - f;
if (!(h * h + x * x + y * y > 1024.0D)) {
int stage = entry.getValue().getStage();
matrices.pushPose();
matrices.translate((double) pos.getX() - d, (double) pos.getY() - e, (double) pos.getZ() - f);
PoseStack.Pose entry3 = matrices.last();
VertexConsumer vertexConsumer2 = new SheetedDecalTextureGenerator(this.renderBuffers.crumblingBufferSource().getBuffer((RenderType) ModelBakery.DESTROY_TYPES.get(stage)), entry3.pose(), entry3.normal(), 1.0F);
this.minecraft.getBlockRenderer().renderBreakingTexture(this.level.getBlockState(pos), pos, this.level, matrices, vertexConsumer2);
matrices.popPose();
}
}
}
// TODO:Fix or find out alternative.
// @ModifyConstant(
// method = "renderSky(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/util/math/Matrix4f;FLjava/lang/Runnable;)V",
// constant = @Constant(doubleValue = 0.0, ordinal = 0),
// slice = @Slice(
// from = @At(
// value = "INVOKE",
// target = "Lnet/minecraft/client/world/ClientWorld$Properties;getSkyDarknessHeight(Lnet/minecraft/world/HeightLimitView;)D"
// )
// )
// )
// private double modifyVoidBackgroundCondition(double zero) {
// if(ModDimensions.isPrivatePocketDimension(world)) {
// zero = Double.NEGATIVE_INFINITY;
// }
// return zero;
// }
}

View file

@ -0,0 +1,11 @@
package org.dimdev.dimdoors.mixin.client.accessor;
import net.minecraft.client.renderer.LevelRenderer;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(LevelRenderer.class)
public interface WorldRendererAccessor {
@Accessor
int getTicks();
}

View file

@ -0,0 +1,14 @@
package org.dimdev.dimdoors.network;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.network.ServerPlayNetworkHandler;
public interface ExtendedServerPlayNetworkHandler {
static ExtendedServerPlayNetworkHandler get(ServerPlayNetworkHandler networkHandler) {
return (ExtendedServerPlayNetworkHandler) networkHandler;
}
ServerPacketHandler getDimDoorsPacketHandler();
MinecraftServer dimdoorsGetServer();
}

View file

@ -0,0 +1,166 @@
package org.dimdev.dimdoors.network;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Supplier;
import dev.architectury.networking.NetworkManager;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.network.ServerGamePacketListenerImpl;
import net.minecraft.world.level.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.registry.RegistryKey;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.network.ServerPlayNetworkHandler;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.util.Hand;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.fabricmc.fabric.api.networking.v1.PacketByteBufs;
import net.fabricmc.fabric.api.networking.v1.PacketSender;
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
import org.dimdev.dimdoors.api.item.ExtendedItem;
import org.dimdev.dimdoors.network.packet.c2s.HitBlockWithItemC2SPacket;
import org.dimdev.dimdoors.network.packet.c2s.NetworkHandlerInitializedC2SPacket;
import org.dimdev.dimdoors.network.packet.s2c.PlayerInventorySlotUpdateS2CPacket;
import org.dimdev.dimdoors.network.packet.s2c.SyncPocketAddonsS2CPacket;
import org.dimdev.dimdoors.world.ModDimensions;
import org.dimdev.dimdoors.world.level.registry.DimensionalRegistry;
import org.dimdev.dimdoors.world.pocket.PocketDirectory;
import org.dimdev.dimdoors.world.pocket.type.Pocket;
import org.dimdev.dimdoors.world.pocket.type.addon.AutoSyncedAddon;
// each client has their own corresponding ServerPacketHandler, so feel free to add client specific data in here
public class ServerPacketHandler implements ServerPacketListener {
private static final Logger LOGGER = LogManager.getLogger();
private final net.minecraft.network.protocol.game.ServerPacketListener networkHandler;
private final Set<ResourceLocation> registeredChannels = new HashSet<>();
private boolean initialized = false;
private ResourceKey<Level> lastSyncedPocketWorld;
private int lastSyncedPocketId = Integer.MIN_VALUE;
private boolean pocketSyncDirty = true;
public void init() {
if (initialized) throw new RuntimeException("ServerPacketHandler has already been initialized.");
initialized = true;
registerReceiver(NetworkHandlerInitializedC2SPacket.ID, NetworkHandlerInitializedC2SPacket::new);
registerReceiver(HitBlockWithItemC2SPacket.ID, HitBlockWithItemC2SPacket::new);
}
public static ServerPacketHandler get(ServerPlayer player) {
return get(player.connection);
}
public static ServerPacketHandler get(ServerGamePacketListenerImpl networkHandler) {
return ((ExtendedServerPlayNetworkHandler) networkHandler).getDimDoorsPacketHandler();
}
public static boolean sendPacket(ServerPlayer player, SimplePacket<?> packet) {
try {
NetworkManager.sendToPlayer(player, packet.channelId(), packet.write(PacketByteBufs.create()));
return true;
} catch (IOException e) {
LOGGER.error(e);
return false;
}
}
public boolean sendPacket(SimplePacket<?> packet) {
return sendPacket(getPlayer(), packet);
}
public ServerPacketHandler(net.minecraft.network.protocol.game.ServerPacketListener networkHandler) {
this.networkHandler = networkHandler;
}
private void registerReceiver(ResourceLocation channelName, Supplier<? extends SimplePacket<ServerPacketListener>> supplier) {
NetworkManager.registerReceiver(NetworkManager.Side.S2C, channelName, new NetworkManager.NetworkReceiver() {
@Override
public void receive(FriendlyByteBuf buf, NetworkManager.PacketContext context) {
context.getPlayer()
}
});
ServerPlayNetworking.registerReceiver(networkHandler, channelName,
(MinecraftServer server, ServerPlayerEntity player, ServerPlayNetworkHandler handler, PacketByteBuf buf, PacketSender responseSender) -> {
try {
supplier.get().read(buf).apply(this);
} catch (IOException e) {
LOGGER.error(e);
}
});
registeredChannels.add(channelName);
}
private void unregisterReceiver(Identifier channelName) {
ServerPlayNetworking.unregisterReceiver(networkHandler, channelName);
registeredChannels.remove(channelName);
}
public void unregister() {
new HashSet<>(registeredChannels).forEach(this::unregisterReceiver);
}
public MinecraftServer getServer() {
return ((ExtendedServerPlayNetworkHandler) networkHandler).dimdoorsGetServer();
}
public ServerPlayerEntity getPlayer() {
return networkHandler.player;
}
// TODO: attach this to some event to detect other kinds teleportation
public void syncPocketAddonsIfNeeded(World world, BlockPos pos) {
if (!ModDimensions.isPocketDimension(world)) return;
PocketDirectory directory = DimensionalRegistry.getPocketDirectory(world.getRegistryKey());
Pocket pocket = directory.getPocketAt(pos);
if (pocket == null) return;
if ((pocketSyncDirty || pocket.getId() != lastSyncedPocketId || !world.getRegistryKey().getValue().equals(lastSyncedPocketWorld.getValue()))) {
pocketSyncDirty = false;
lastSyncedPocketId = pocket.getId();
lastSyncedPocketWorld = world.getRegistryKey();
sendPacket(getPlayer(), new SyncPocketAddonsS2CPacket(world.getRegistryKey(), directory.getGridSize(), pocket.getId(), pocket.getRange(), pocket.getAddonsInstanceOf(AutoSyncedAddon.class)));
}
}
public void markPocketSyncDirty(int id) {
if (lastSyncedPocketId == id) pocketSyncDirty = true;
}
public void sync(ItemStack stack, Hand hand) {
if (hand == Hand.OFF_HAND) {
sendPacket(new PlayerInventorySlotUpdateS2CPacket(45, stack));
} else {
sendPacket(new PlayerInventorySlotUpdateS2CPacket(getPlayer().getInventory().selectedSlot, stack));
}
}
@Override
public void onAttackBlock(HitBlockWithItemC2SPacket packet) {
getServer().execute(() -> {
Item item = getPlayer().getStackInHand(packet.getHand()).getItem();
if (item instanceof ExtendedItem) {
((ExtendedItem) item).onAttackBlock(getPlayer().world, getPlayer(), packet.getHand(), packet.getPos(), packet.getDirection());
}
});
}
@Override
public void onNetworkHandlerInitialized(NetworkHandlerInitializedC2SPacket packet) {
syncPocketAddonsIfNeeded(getPlayer().world, getPlayer().getBlockPos());
}
}

View file

@ -0,0 +1,10 @@
package org.dimdev.dimdoors.network;
import org.dimdev.dimdoors.network.packet.c2s.HitBlockWithItemC2SPacket;
import org.dimdev.dimdoors.network.packet.c2s.NetworkHandlerInitializedC2SPacket;
public interface ServerPacketListener {
void onAttackBlock(HitBlockWithItemC2SPacket packet);
void onNetworkHandlerInitialized(NetworkHandlerInitializedC2SPacket packet);
}

View file

@ -0,0 +1,16 @@
package org.dimdev.dimdoors.network;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
import java.io.IOException;
public interface SimplePacket<T> {
SimplePacket<T> read(FriendlyByteBuf buf) throws IOException;
FriendlyByteBuf write(FriendlyByteBuf buf) throws IOException;
void apply(T listener);
ResourceLocation channelId();
}

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