Yes. ><
This commit is contained in:
parent
37717a1c59
commit
113eb04e0d
146 changed files with 9112 additions and 463 deletions
|
@ -1,10 +1,22 @@
|
|||
package org.dimdev.dimdoors;
|
||||
|
||||
import dev.architectury.utils.GameInstance;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.world.level.Level;
|
||||
|
||||
public class DimensionalDoors {
|
||||
public static final String MOD_ID = "dimdoors";
|
||||
public static ResourceLocation id(String 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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
package org.dimdev.dimdoors.api.block;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.util.ActionResult;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.InteractionResult;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
public interface AfterMoveCollidableBlock {
|
||||
// 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);
|
||||
}
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
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 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;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Only works in cases where {@link net.minecraft.block.AbstractBlock#getStateForNeighborUpdate AbstractBlock#getStateForNeighborUpdate} returns an air {@link BlockState}
|
||||
*/
|
||||
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.
|
||||
|
@ -26,13 +26,13 @@ public interface CustomBreakBlock {
|
|||
private final 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.blockEntityConsumer = blockEntityConsumer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState getBlockState() {
|
||||
public BlockState createLegacyBlock() {
|
||||
return blockState;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
package org.dimdev.dimdoors.api.block;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.util.ActionResult;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.InteractionResult;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
|
||||
public interface ExplosionConvertibleBlock {
|
||||
ActionResult explode(World world, BlockPos pos, BlockState state, BlockEntity blockEntity);
|
||||
InteractionResult explode(Level world, BlockPos pos, BlockState state, BlockEntity blockEntity);
|
||||
}
|
||||
|
|
|
@ -1,73 +1,71 @@
|
|||
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.HashSet;
|
||||
import java.util.List;
|
||||
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)
|
||||
public final class DimensionalPortalRenderer {
|
||||
public static final Identifier WARP_PATH;
|
||||
private static final RenderPhase.ShaderProgram DIMENSIONAL_PORTAL_SHADER;
|
||||
private static final RenderLayer RENDER_LAYER;
|
||||
public static final ResourceLocation WARP_PATH;
|
||||
private static final RenderStateShard.ShaderStateShard DIMENSIONAL_PORTAL_SHADER;
|
||||
private static final RenderType RENDER_LAYER;
|
||||
private static final ModelPart 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);
|
||||
}
|
||||
|
||||
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;
|
||||
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);
|
||||
model.render(matrixStack, vertexConsumerProvider.getBuffer(RENDER_LAYER), light, overlay);
|
||||
}
|
||||
|
||||
static {
|
||||
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(
|
||||
"dimensional_portal",
|
||||
VertexFormats.POSITION,
|
||||
VertexFormat.DrawMode.QUADS,
|
||||
DefaultVertexFormat.POSITION,
|
||||
VertexFormat.Mode.QUADS,
|
||||
256,
|
||||
false,
|
||||
false,
|
||||
RenderLayer.MultiPhaseParameters.builder()
|
||||
.program(DIMENSIONAL_PORTAL_SHADER)
|
||||
.texture(
|
||||
RenderPhase.Textures.create()
|
||||
.add(EndPortalBlockEntityRenderer.SKY_TEXTURE, false, false)
|
||||
RenderType.CompositeState.builder()
|
||||
.setShaderState(DIMENSIONAL_PORTAL_SHADER)
|
||||
.setTextureState(
|
||||
RenderStateShard.MultiTextureStateShard.builder()
|
||||
.add(TheEndPortalRenderer.END_SKY_LOCATION, false, false)
|
||||
.add(WARP_PATH, false, false)
|
||||
.build()
|
||||
)
|
||||
.build(false)
|
||||
.createCompositeState(false)
|
||||
);
|
||||
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());
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,16 +1,13 @@
|
|||
package org.dimdev.dimdoors.api.client;
|
||||
|
||||
import net.minecraft.client.render.RenderLayer;
|
||||
import net.minecraft.client.render.VertexFormat;
|
||||
|
||||
import com.mojang.blaze3d.vertex.VertexFormat;
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
|
||||
import org.dimdev.dimdoors.mixin.client.accessor.RenderLayerAccessor;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
public class RenderLayerFactory {
|
||||
public static RenderLayer create(String name, VertexFormat vertexFormat, VertexFormat.DrawMode drawMode, int expectedBufferSize, boolean hasCrumbling, boolean translucent, RenderLayer.MultiPhaseParameters phases) {
|
||||
return RenderLayerAccessor.callOf(name, vertexFormat, drawMode, expectedBufferSize, hasCrumbling, translucent, phases);
|
||||
public static RenderType create(String name, VertexFormat vertexFormat, VertexFormat.Mode drawMode, int expectedBufferSize, boolean hasCrumbling, boolean translucent, RenderType.CompositeState phases) {
|
||||
return RenderType.create(name, vertexFormat, drawMode, expectedBufferSize, hasCrumbling, translucent, phases);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package org.dimdev.dimdoors.api.entity;
|
||||
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
public interface LastPositionProvider {
|
||||
Vec3d getLastPos();
|
||||
Vec3 getLastPos();
|
||||
}
|
||||
|
|
|
@ -1,28 +1,27 @@
|
|||
package org.dimdev.dimdoors.api.event;
|
||||
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.util.ActionResult;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.hit.BlockHitResult;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import net.fabricmc.fabric.api.event.Event;
|
||||
import net.fabricmc.fabric.api.event.EventFactory;
|
||||
import dev.architectury.event.Event;
|
||||
import dev.architectury.event.EventFactory;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.InteractionResult;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
|
||||
public interface UseItemOnBlockCallback {
|
||||
Event<UseItemOnBlockCallback> EVENT = EventFactory.createArrayBacked(UseItemOnBlockCallback.class,
|
||||
Event<UseItemOnBlockCallback> EVENT = EventFactory.of(
|
||||
listeners -> (player, world, hand, hitresult) -> {
|
||||
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 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);
|
||||
}
|
||||
|
|
|
@ -1,26 +1,27 @@
|
|||
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.Map;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
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 {
|
||||
public enum BlockPlacementType implements StringRepresentable {
|
||||
// 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("section_no_update", true, false, World::addBlockEntity),
|
||||
SECTION_UPDATE("section_update", true, true, World::addBlockEntity),
|
||||
SET_BLOCK_STATE("set_block_state", false, false, World::addBlockEntity),
|
||||
SECTION_NO_UPDATE("section_no_update", true, false, Level::setBlockEntity),
|
||||
SECTION_UPDATE("section_update", true, true, Level::setBlockEntity),
|
||||
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);
|
||||
|
||||
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 {
|
||||
for (BlockPlacementType type : BlockPlacementType.values()) {
|
||||
|
@ -31,10 +32,10 @@ public enum BlockPlacementType implements StringIdentifiable {
|
|||
final String id;
|
||||
final boolean useSection;
|
||||
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.useSection = useSection;
|
||||
this.markForUpdate = markForUpdate;
|
||||
|
@ -49,7 +50,7 @@ public enum BlockPlacementType implements StringIdentifiable {
|
|||
return markForUpdate;
|
||||
}
|
||||
|
||||
public BiConsumer<World, BlockEntity> getBlockEntityPlacer() {
|
||||
public BiConsumer<Level, BlockEntity> getBlockEntityPlacer() {
|
||||
return blockEntityPlacer;
|
||||
}
|
||||
|
||||
|
@ -61,13 +62,13 @@ public enum BlockPlacementType implements StringIdentifiable {
|
|||
return idMap.get(id);
|
||||
}
|
||||
|
||||
private static void queueBlockEntity(World world, BlockEntity blockEntity) {
|
||||
private static void queueBlockEntity(Level world, BlockEntity blockEntity) {
|
||||
MinecraftServer server = world.getServer();
|
||||
server.send(new ServerTask(server.getTicks(), () -> world.addBlockEntity(blockEntity)));
|
||||
server.tell(new TickTask(server.getTickCount(), () -> world.setBlockEntity(blockEntity)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String asString() {
|
||||
public String getSerializedName() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,43 +2,41 @@ package org.dimdev.dimdoors.api.util;
|
|||
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.fluid.FluidState;
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
import net.minecraft.registry.RegistryKey;
|
||||
import net.minecraft.registry.RegistryKeys;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
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 org.dimdev.dimdoors.DimensionalDoors;
|
||||
|
||||
public class Location {
|
||||
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;
|
||||
}), BlockPos.CODEC.fieldOf("pos").forGetter(location -> {
|
||||
return location.pos;
|
||||
})).apply(instance, Location::new);
|
||||
});
|
||||
|
||||
public final RegistryKey<World> world;
|
||||
public final ResourceKey<Level> world;
|
||||
public final BlockPos pos;
|
||||
|
||||
public Location(RegistryKey<World> world, BlockPos pos) {
|
||||
public Location(ResourceKey<Level> world, BlockPos pos) {
|
||||
this.world = world;
|
||||
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));
|
||||
}
|
||||
|
||||
public Location(ServerWorld world, BlockPos pos) {
|
||||
this(world.getRegistryKey(), pos);
|
||||
public Location(ServerLevel world, BlockPos pos) {
|
||||
this(world.dimension(), pos);
|
||||
}
|
||||
|
||||
public int getX() {
|
||||
|
@ -81,25 +79,25 @@ public class Location {
|
|||
return this.world.hashCode() * 31 + this.pos.hashCode();
|
||||
}
|
||||
|
||||
public RegistryKey<World> getWorldId() {
|
||||
public ResourceKey<Level> getWorldId() {
|
||||
return this.world;
|
||||
}
|
||||
|
||||
public ServerWorld getWorld() {
|
||||
return DimensionalDoors.getServer().getWorld(this.world);
|
||||
public ServerLevel getWorld() {
|
||||
return DimensionalDoors.getServer().getLevel(this.world);
|
||||
}
|
||||
|
||||
public static NbtCompound toNbt(Location location) {
|
||||
NbtCompound nbt = new NbtCompound();
|
||||
nbt.putString("world", location.world.getValue().toString());
|
||||
public static CompoundTag toNbt(Location location) {
|
||||
CompoundTag nbt = new CompoundTag();
|
||||
nbt.putString("world", location.world.location().toString());
|
||||
nbt.putIntArray("pos", new int[]{location.getX(), location.getY(), location.getZ()});
|
||||
return nbt;
|
||||
}
|
||||
|
||||
public static Location fromNbt(NbtCompound nbt) {
|
||||
public static Location fromNbt(CompoundTag nbt) {
|
||||
int[] pos = nbt.getIntArray("pos");
|
||||
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])
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,35 +1,35 @@
|
|||
package org.dimdev.dimdoors.api.util;
|
||||
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
import net.minecraft.registry.RegistryKey;
|
||||
import net.minecraft.registry.RegistryKeys;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.level.Level;
|
||||
|
||||
public class RotatedLocation extends Location {
|
||||
public final float yaw;
|
||||
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);
|
||||
this.yaw = yaw;
|
||||
this.pitch = pitch;
|
||||
}
|
||||
|
||||
public static NbtCompound serialize(RotatedLocation location) {
|
||||
NbtCompound nbt = new NbtCompound();
|
||||
nbt.putString("world", location.world.getValue().toString());
|
||||
public static CompoundTag serialize(RotatedLocation location) {
|
||||
CompoundTag nbt = new CompoundTag();
|
||||
nbt.putString("world", location.world.location().toString());
|
||||
nbt.putIntArray("pos", new int[]{location.getX(), location.getY(), location.getZ()});
|
||||
nbt.putFloat("yaw", location.pitch);
|
||||
nbt.putFloat("pitch", location.pitch);
|
||||
return nbt;
|
||||
}
|
||||
|
||||
public static RotatedLocation deserialize(NbtCompound nbt) {
|
||||
public static RotatedLocation deserialize(CompoundTag nbt) {
|
||||
int[] pos = nbt.getIntArray("pos");
|
||||
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]),
|
||||
nbt.getFloat("yaw"),
|
||||
nbt.getFloat("pitch")
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
package org.dimdev.dimdoors.block;
|
||||
|
||||
import net.minecraft.block.BlockSetType;
|
||||
import net.minecraft.sound.SoundEvent;
|
||||
import net.minecraft.sound.SoundEvents;
|
||||
import net.minecraft.sounds.SoundEvent;
|
||||
import net.minecraft.sounds.SoundEvents;
|
||||
import net.minecraft.world.level.block.state.properties.BlockSetType;
|
||||
|
||||
public interface DoorSoundProvider {
|
||||
public static final DoorSoundProvider DUMMY = new DoorSoundProvider() {};
|
||||
|
||||
// TODO: remove these two
|
||||
public default SoundEvent getOpenSound() {
|
||||
return SoundEvents.BLOCK_WOODEN_DOOR_OPEN;
|
||||
return SoundEvents.WOODEN_DOOR_OPEN;
|
||||
}
|
||||
public default SoundEvent getCloseSound() {
|
||||
return SoundEvents.BLOCK_WOODEN_DOOR_CLOSE;
|
||||
return SoundEvents.WOODEN_DOOR_CLOSE;
|
||||
}
|
||||
|
||||
default BlockSetType getSetType() {
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
package org.dimdev.dimdoors.block;
|
||||
|
||||
import dev.architectury.registry.client.rendering.RenderTypeRegistry;
|
||||
import dev.architectury.registry.registries.DeferredRegister;
|
||||
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.world.item.BlockItem;
|
||||
import net.minecraft.world.item.DyeColor;
|
||||
|
@ -231,11 +235,11 @@ public final class ModBlocks {
|
|||
return block;
|
||||
}
|
||||
|
||||
// @Environment(EnvType.CLIENT)
|
||||
// public static void initClient() {
|
||||
// BlockRenderLayerMap.INSTANCE.putBlocks(RenderLayer.getCutout(), ModBlocks.QUARTZ_DOOR, ModBlocks.GOLD_DOOR);
|
||||
@Environment(EnvType.CLIENT)
|
||||
public static void initClient() {
|
||||
RenderTypeRegistry.register(RenderType.cutout(), ModBlocks.QUARTZ_DOOR.get(), ModBlocks.GOLD_DOOR.get());
|
||||
// DoorData.DOORS.forEach(door -> BlockRenderLayerMap.INSTANCE.putBlock(door, RenderLayer.getCutout()));
|
||||
// }
|
||||
}
|
||||
|
||||
public static RegistrySupplier<Block> ancientFabricFromDye(DyeColor color) {
|
||||
return ANCIENT_FABRIC_BLOCKS.get(color);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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");
|
||||
// }
|
||||
//}
|
|
@ -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;
|
||||
// }
|
||||
//}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
353
common/src/main/java/org/dimdev/dimdoors/client/RiftCurves.java
Normal file
353
common/src/main/java/org/dimdev/dimdoors/client/RiftCurves.java
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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() {
|
||||
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
// }
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -1,39 +1,12 @@
|
|||
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.registry.CreativeTabRegistry;
|
||||
import dev.architectury.registry.registries.DeferredRegister;
|
||||
import dev.architectury.registry.registries.RegistrySupplier;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.world.item.*;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
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.entity.ModEntityTypes;
|
||||
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.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;
|
||||
|
||||
public final class ModItems {
|
||||
// DO NOT REMOVE!!!
|
||||
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(),
|
||||
new Item.Properties().stacksTo(1),
|
||||
properties.stacksTo(1),
|
||||
rift -> rift.setDestination(
|
||||
RandomTarget.builder()
|
||||
.acceptedGroups(Collections.singleton(0))
|
||||
|
@ -62,73 +41,73 @@ public final class ModItems {
|
|||
.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_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<>();
|
||||
|
||||
|
|
|
@ -1,28 +1,26 @@
|
|||
package org.dimdev.dimdoors.item;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.projectile.ProjectileUtil;
|
||||
import net.minecraft.util.hit.BlockHitResult;
|
||||
import net.minecraft.util.hit.EntityHitResult;
|
||||
import net.minecraft.util.hit.HitResult;
|
||||
import net.minecraft.util.math.Box;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.BlockView;
|
||||
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.projectile.ProjectileUtil;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.EntityHitResult;
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.dimdev.dimdoors.block.entity.DetachedRiftBlockEntity;
|
||||
import org.dimdev.dimdoors.block.entity.RiftBlockEntity;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public final class RaycastHelper {
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -31,10 +29,10 @@ public final class RaycastHelper {
|
|||
}
|
||||
|
||||
public static HitResult raycast(Entity entity, double maxDistance, float tickDelta, Predicate<Entity> predicate) {
|
||||
Vec3d vec3d = entity.getCameraPosVec(tickDelta);
|
||||
Vec3d vec3d2 = entity.getRotationVec(tickDelta);
|
||||
Vec3d 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);
|
||||
return ProjectileUtil.raycast(entity, vec3d, vec3d3, box, predicate, maxDistance);
|
||||
Vec3 vec3d = entity.getEyePosition(tickDelta);
|
||||
Vec3 vec3d2 = entity.getViewVector(tickDelta);
|
||||
Vec3 vec3d3 = vec3d.add(vec3d2.x * maxDistance, vec3d2.y * maxDistance, vec3d2.z * maxDistance);
|
||||
var box = entity.getBoundingBox().expandTowards(vec3d2.scale(maxDistance)).inflate(1.0D, 1.0D, 1.0D);
|
||||
return ProjectileUtil.getEntityHitResult(entity, vec3d, vec3d3, box, predicate, maxDistance);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,40 +1,30 @@
|
|||
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.Environment;
|
||||
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.SwordItem;
|
||||
import net.minecraft.world.item.Tier;
|
||||
import net.minecraft.world.item.Tiers;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Vec3i;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
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.block.DimensionalPortalBlock;
|
||||
import org.dimdev.dimdoors.block.ModBlocks;
|
||||
import org.dimdev.dimdoors.block.entity.EntranceRiftBlockEntity;
|
||||
import org.dimdev.dimdoors.block.entity.RiftBlockEntity;
|
||||
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 static final String ID = "rift_blade";
|
||||
|
@ -45,23 +35,23 @@ public class RiftBladeItem extends SwordItem {
|
|||
|
||||
@Environment(EnvType.CLIENT)
|
||||
@Override
|
||||
public void appendTooltip(ItemStack itemStack, World world, List<Text> list, TooltipContext tooltipContext) {
|
||||
ToolTipHelper.processTranslation(list, this.getTranslationKey() + ".info");
|
||||
public void appendHoverText(ItemStack itemStack, @Nullable Level level, List<Component> list, TooltipFlag tooltipFlag) {
|
||||
ToolTipHelper.processTranslation(list, this.getDescriptionId() + ".info");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasGlint(ItemStack itemStack) {
|
||||
public boolean isFoil(ItemStack itemStack) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canRepair(ItemStack item, ItemStack repairingItem) {
|
||||
return Objects.equals(ModItems.STABLE_FABRIC, repairingItem.getItem());
|
||||
public boolean isValidRepairItem(ItemStack item, ItemStack repairingItem) {
|
||||
return Objects.equals(ModItems.STABLE_FABRIC.get(), repairingItem.getItem());
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypedActionResult<ItemStack> use(World world, PlayerEntity player, Hand hand) {
|
||||
ItemStack stack = player.getStackInHand(hand);
|
||||
public InteractionResultHolder<ItemStack> use(Level world, Player player, InteractionHand hand) {
|
||||
ItemStack stack = player.getItemInHand(hand);
|
||||
HitResult hit = RaycastHelper.raycast(player, 16, 0.0F, LivingEntity.class::isInstance);
|
||||
|
||||
if (hit == null) {
|
||||
|
@ -69,54 +59,54 @@ public class RiftBladeItem extends SwordItem {
|
|||
}
|
||||
|
||||
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) {
|
||||
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)) {
|
||||
return new TypedActionResult<>(ActionResult.SUCCESS, stack);
|
||||
return new InteractionResultHolder<>(InteractionResult.SUCCESS, stack);
|
||||
} 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;
|
||||
return new TypedActionResult<>(ActionResult.FAIL, stack);
|
||||
return new InteractionResultHolder<>(InteractionResult.FAIL, stack);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
double offsetDistance = Math.random() * damageMultiplier * 7 + 2; //TODO: make these offset distances configurable
|
||||
double offsetRotationYaw = (Math.random() - 0.5) * damageMultiplier * 360;
|
||||
|
||||
Vec3d playerVec = player.getPos();
|
||||
Vec3d entityVec = hit.getPos();
|
||||
Vec3d offsetDirection = playerVec.subtract(entityVec).normalize();
|
||||
offsetDirection = offsetDirection.rotateY((float) (offsetRotationYaw * Math.PI) / 180);
|
||||
var playerVec = player.position();
|
||||
var entityVec = hit.getLocation();
|
||||
var offsetDirection = playerVec.subtract(entityVec).normalize();
|
||||
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));
|
||||
while (world.getBlockState(teleportPosition).getMaterial().blocksMovement())
|
||||
teleportPosition = teleportPosition.up();
|
||||
player.teleport(teleportPosition.getX(), teleportPosition.getY(), teleportPosition.getZ());
|
||||
player.setYaw((float) (Math.random() * 2 * Math.PI));
|
||||
while (world.getBlockState(teleportPosition).getMaterial().blocksMotion())
|
||||
teleportPosition = teleportPosition.above();
|
||||
player.teleportTo(teleportPosition.getX(), teleportPosition.getY(), teleportPosition.getZ());
|
||||
player.setYRot((float) (Math.random() * 2 * Math.PI));
|
||||
|
||||
stack.damage(1, player, a -> a.sendToolBreakStatus(hand));
|
||||
return new TypedActionResult<>(ActionResult.SUCCESS, stack);
|
||||
stack.hurtAndBreak(1, player, a -> a.broadcastBreakEvent(hand));
|
||||
return new InteractionResultHolder<>(InteractionResult.SUCCESS, stack);
|
||||
} else if (RaycastHelper.hitsDetachedRift(hit, world)) {
|
||||
BlockHitResult blockHitResult = (BlockHitResult) hit;
|
||||
BlockPos pos = 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());
|
||||
|
||||
stack.damage(1, player, a -> a.sendToolBreakStatus(hand));
|
||||
return new TypedActionResult<>(ActionResult.SUCCESS, stack);
|
||||
stack.hurtAndBreak(1, player, a -> a.broadcastBreakEvent(hand));
|
||||
return new InteractionResultHolder<>(InteractionResult.SUCCESS, stack);
|
||||
}
|
||||
return new TypedActionResult<>(ActionResult.FAIL, stack);
|
||||
return new InteractionResultHolder<>(InteractionResult.FAIL, stack);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,11 +57,6 @@ public class RiftKeyItem extends Item {
|
|||
return !isEmpty(stack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNbtSynced() {
|
||||
return super.isNbtSynced();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxUseTime(ItemStack stack) {
|
||||
return 30;
|
||||
|
|
|
@ -11,8 +11,12 @@ import net.minecraft.item.ItemStack;
|
|||
import net.minecraft.loot.context.LootContext;
|
||||
import net.minecraft.loot.context.LootContextParameters;
|
||||
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.sound.SoundCategory;
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
import net.minecraft.text.MutableText;
|
||||
import net.minecraft.text.Text;
|
||||
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.HitResult;
|
||||
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.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
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.block.entity.DetachedRiftBlockEntity;
|
||||
import org.dimdev.dimdoors.block.entity.RiftBlockEntity;
|
||||
import org.dimdev.dimdoors.client.ToolTipHelper;
|
||||
import org.dimdev.dimdoors.sound.ModSoundEvents;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class RiftRemoverItem extends Item {
|
||||
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) {
|
||||
super(settings);
|
||||
|
@ -46,21 +65,21 @@ public class RiftRemoverItem extends Item {
|
|||
|
||||
@Environment(EnvType.CLIENT)
|
||||
@Override
|
||||
public void appendTooltip(ItemStack itemStack, World world, List<Text> list, TooltipContext tooltipContext) {
|
||||
ToolTipHelper.processTranslation(list, this.getTranslationKey() + ".info");
|
||||
public void appendHoverText(ItemStack itemStack, @Nullable Level level, List<Component> list, TooltipFlag tooltipFlag) {
|
||||
ToolTipHelper.processTranslation(list, this.getDescription() + ".info");
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypedActionResult<ItemStack> use(World world, PlayerEntity player, Hand hand) {
|
||||
ItemStack stack = player.getStackInHand(hand);
|
||||
HitResult hit = player.raycast(RaycastHelper.REACH_DISTANCE, 0, false);
|
||||
public InteractionResultHolder<ItemStack> use(Level world, Player player, InteractionHand hand) {
|
||||
ItemStack stack = player.getItemInHand(hand);
|
||||
HitResult hit = player.pick(RaycastHelper.REACH_DISTANCE, 0, false);
|
||||
|
||||
if (world.isClient) {
|
||||
if (world.isClientSide) {
|
||||
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;
|
||||
}
|
||||
return new TypedActionResult<>(ActionResult.FAIL, stack);
|
||||
return new InteractionResultHolder<>(InteractionResult.FAIL, stack);
|
||||
}
|
||||
|
||||
if (RaycastHelper.hitsDetachedRift(hit, world)) {
|
||||
|
@ -68,19 +87,19 @@ public class RiftRemoverItem extends Item {
|
|||
DetachedRiftBlockEntity rift = (DetachedRiftBlockEntity) world.getBlockEntity(((BlockHitResult) hit).getBlockPos());
|
||||
if (!Objects.requireNonNull(rift).closing) {
|
||||
rift.setClosing(true);
|
||||
world.playSound(null, player.getBlockPos(), ModSoundEvents.RIFT_CLOSE, SoundCategory.BLOCKS, 0.6f, 1);
|
||||
stack.damage(10, player, a -> a.sendToolBreakStatus(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);
|
||||
((ServerWorld) world).getServer().getLootManager().getTable(REMOVED_RIFT_LOOT_TABLE).generateLoot(ctx).forEach(stack1 -> {
|
||||
ItemScatterer.spawn(world, ((BlockHitResult) hit).getBlockPos().getX(), ((BlockHitResult) hit).getBlockPos().getY(), ((BlockHitResult) hit).getBlockPos().getZ(), stack1);
|
||||
world.playSound(null, player.blockPosition(), ModSoundEvents.RIFT_CLOSE.get(), SoundSource.BLOCKS, 0.6f, 1);
|
||||
stack.hurtAndBreak(10, player, a -> a.broadcastBreakEvent(hand));
|
||||
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);
|
||||
((ServerLevel) world).getServer().getLootTables().get(REMOVED_RIFT_LOOT_TABLE).getRandomItems(ctx).forEach(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);
|
||||
return new TypedActionResult<>(ActionResult.SUCCESS, stack);
|
||||
player.displayClientMessage(Component.translatable(this.getDescriptionId() + ".closing"), true);
|
||||
return new InteractionResultHolder<>(InteractionResult.SUCCESS, stack);
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,32 +1,21 @@
|
|||
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 org.jetbrains.annotations.NotNull;
|
||||
|
||||
import net.minecraft.client.item.TooltipContext;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.Item;
|
||||
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 net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.TooltipFlag;
|
||||
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.api.util.Location;
|
||||
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.world.ModDimensions;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class RiftSignatureItem extends Item {
|
||||
public static final String ID = "rift_signature";
|
||||
|
||||
|
@ -45,105 +36,103 @@ public class RiftSignatureItem extends Item {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean hasGlint(ItemStack stack) {
|
||||
return stack.getNbt() != null && stack.getNbt().contains("destination");
|
||||
public boolean isFoil(ItemStack stack) {
|
||||
return stack.getTag() != null && stack.getTag().contains("destination");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionResult useOnBlock(@NotNull ItemUsageContext itemUsageContext) {
|
||||
PlayerEntity player = itemUsageContext.getPlayer();
|
||||
World world = itemUsageContext.getWorld();
|
||||
BlockPos pos = itemUsageContext.getBlockPos();
|
||||
Hand hand = itemUsageContext.getHand();
|
||||
Direction side = itemUsageContext.getSide();
|
||||
public InteractionResult useOn(UseOnContext itemUsageContext) {
|
||||
Player player = itemUsageContext.getPlayer();
|
||||
Level world = itemUsageContext.getLevel();
|
||||
BlockPos pos = itemUsageContext.getClickedPos();
|
||||
InteractionHand hand = itemUsageContext.getHand();
|
||||
Direction side = itemUsageContext.getClickedFace();
|
||||
|
||||
ItemPlacementContext placementContext = new ItemPlacementContext(itemUsageContext);
|
||||
BlockPlaceContext placementContext = new BlockPlaceContext(itemUsageContext);
|
||||
|
||||
ItemStack stack = player.getStackInHand(hand);
|
||||
pos = world.getBlockState(pos).getBlock().canReplace(world.getBlockState(pos), placementContext) ? pos : pos.offset(side);
|
||||
ItemStack stack = player.getItemInHand(hand);
|
||||
pos = world.getBlockState(pos).getBlock().canBeReplaced(world.getBlockState(pos), placementContext) ? pos : pos.relative(side);
|
||||
|
||||
// Fail if the player can't place a block there
|
||||
if (!player.canPlaceOn(pos, side.getOpposite(), stack)) {
|
||||
return ActionResult.FAIL;
|
||||
if (!player.mayUseItemAt(pos, side.getOpposite(), stack)) {
|
||||
return InteractionResult.FAIL;
|
||||
}
|
||||
|
||||
if (world.isClient) {
|
||||
return ActionResult.SUCCESS;
|
||||
if (world.isClientSide) {
|
||||
return InteractionResult.SUCCESS;
|
||||
}
|
||||
|
||||
if(ModDimensions.isPrivatePocketDimension(world) && !DimensionalDoors.getConfig().getPocketsConfig().canUseRiftSignatureInPrivatePockets) {
|
||||
player.sendMessage(Text.translatable("tools.signature_blocked").formatted(Formatting.BLACK), true);
|
||||
return ActionResult.FAIL;
|
||||
player.displayClientMessage(Component.translatable("tools.signature_blocked").withStyle(ChatFormatting.BLACK), true);
|
||||
return InteractionResult.FAIL;
|
||||
}
|
||||
|
||||
RotatedLocation target = getSource(stack);
|
||||
|
||||
if (target == null) {
|
||||
// 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));
|
||||
player.sendMessage(Text.translatable(this.getTranslationKey() + ".stored"), true);
|
||||
world.playSound(null, player.getBlockPos(), ModSoundEvents.RIFT_START, SoundCategory.BLOCKS, 0.6f, 1);
|
||||
setSource(stack, new RotatedLocation(world.dimension(), pos, player.getYRot(), 0));
|
||||
player.displayClientMessage(Component.translatable(this.getDescriptionId() + ".stored"), true);
|
||||
world.playSound(null, player.blockPosition(), ModSoundEvents.RIFT_START.get(), SoundSource.BLOCKS, 0.6f, 1);
|
||||
} else {
|
||||
// Place a rift at the saved point
|
||||
if (target.getBlockState().getBlock() != ModBlocks.DETACHED_RIFT) {
|
||||
if (!target.getBlockState().getBlock().canMobSpawnInside()) {
|
||||
player.sendMessage(Text.translatable("tools.target_became_block"), true);
|
||||
if (!target.getBlockState().getBlock().isPossibleToRespawnInThis()) {
|
||||
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!
|
||||
return ActionResult.FAIL;
|
||||
return InteractionResult.FAIL;
|
||||
}
|
||||
World sourceWorld = DimensionalDoors.getWorld(target.world);
|
||||
sourceWorld.setBlockState(target.getBlockPos(), ModBlocks.DETACHED_RIFT.getDefaultState());
|
||||
Level sourceWorld = DimensionalDoors.getWorld(target.world);
|
||||
sourceWorld.setBlockAndUpdate(target.getBlockPos(), ModBlocks.DETACHED_RIFT.get().defaultBlockState());
|
||||
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();
|
||||
}
|
||||
|
||||
// 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);
|
||||
rift2.setDestination(RiftReference.tryMakeRelative(new Location((ServerWorld) world, pos), target));
|
||||
rift2.setDestination(RiftReference.tryMakeRelative(new Location((ServerLevel) world, pos), target));
|
||||
rift2.register();
|
||||
|
||||
stack.damage(1, player, a -> {
|
||||
}); // TODO: calculate damage based on position?
|
||||
stack.hurtAndBreak(1, player, a -> {}); // TODO: calculate damage based on position?
|
||||
|
||||
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
|
||||
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) {
|
||||
if (!itemStack.hasNbt()) itemStack.setNbt(new NbtCompound());
|
||||
itemStack.getNbt().put("destination", RotatedLocation.serialize(destination));
|
||||
if (!itemStack.hasTag()) itemStack.setTag(new CompoundTag());
|
||||
itemStack.getTag().put("destination", RotatedLocation.serialize(destination));
|
||||
}
|
||||
|
||||
public static void clearSource(ItemStack itemStack) {
|
||||
if (itemStack.hasNbt()) {
|
||||
itemStack.getNbt().remove("destination");
|
||||
if (itemStack.hasTag()) {
|
||||
itemStack.getTag().remove("destination");
|
||||
}
|
||||
}
|
||||
|
||||
public static RotatedLocation getSource(ItemStack itemStack) {
|
||||
if (itemStack.hasNbt() && itemStack.getNbt().contains("destination")) {
|
||||
return RotatedLocation.deserialize(itemStack.getNbt().getCompound("destination"));
|
||||
if (itemStack.hasTag() && itemStack.getTag().contains("destination")) {
|
||||
return RotatedLocation.deserialize(itemStack.getTag().getCompound("destination"));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Environment(EnvType.CLIENT)
|
||||
public void appendTooltip(ItemStack itemStack, World world, List<Text> list, TooltipContext tooltipContext) {
|
||||
public void appendHoverText(ItemStack itemStack, Level world, List<Component> list, TooltipFlag tooltipContext) {
|
||||
RotatedLocation transform = getSource(itemStack);
|
||||
if (transform != null) {
|
||||
list.add(Text.translatable(this.getTranslationKey() + ".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.info0", transform.getX(), transform.getY(), transform.getZ(), transform.getWorldId().getValue()));
|
||||
list.add(Component.translatable(this.getDescriptionId() + ".bound.info1", transform.getWorldId().location()));
|
||||
} else {
|
||||
ToolTipHelper.processTranslation(list, this.getTranslationKey() + ".unbound.info");
|
||||
ToolTipHelper.processTranslation(list, this.getDescriptionId() + ".unbound.info");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,10 +3,14 @@ package org.dimdev.dimdoors.item;
|
|||
import java.util.List;
|
||||
|
||||
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.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.sound.SoundCategory;
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
import net.minecraft.text.MutableText;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.text.TranslatableTextContent;
|
||||
|
@ -16,57 +20,67 @@ import net.minecraft.util.TypedActionResult;
|
|||
import net.minecraft.util.hit.HitResult;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
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.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
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.block.entity.DetachedRiftBlockEntity;
|
||||
import org.dimdev.dimdoors.block.entity.RiftBlockEntity;
|
||||
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 RiftStabilizerItem(Item.Properties settings) {
|
||||
super(settings);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypedActionResult<ItemStack> use(World world, PlayerEntity player, Hand hand) {
|
||||
ItemStack stack = player.getStackInHand(hand);
|
||||
HitResult hit = player.raycast(RaycastHelper.REACH_DISTANCE, 0, false);
|
||||
|
||||
if (world.isClient) {
|
||||
@Override
|
||||
public InteractionResultHolder<ItemStack> use(Level world, Player player, InteractionHand hand) {
|
||||
ItemStack stack = player.getItemInHand(hand);
|
||||
HitResult hit = player.pick(RaycastHelper.REACH_DISTANCE, 0, false);
|
||||
|
||||
if (world.isClientSide) {
|
||||
if (RaycastHelper.hitsDetachedRift(hit, world)) {
|
||||
// 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 {
|
||||
player.sendMessage(Text.translatable("tools.rift_miss"), true);
|
||||
player.displayClientMessage(Component.translatable("tools.rift_miss"), true);
|
||||
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)) {
|
||||
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) {
|
||||
rift.setStabilized(true);
|
||||
world.playSound(null, player.getBlockPos(), ModSoundEvents.RIFT_CLOSE, SoundCategory.BLOCKS, 0.6f, 1); // TODO: different sound
|
||||
stack.damage(1, player, a -> {
|
||||
});
|
||||
player.sendMessage(Text.translatable(this.getTranslationKey() + ".stabilized"), true);
|
||||
return new TypedActionResult<>(ActionResult.SUCCESS, stack);
|
||||
world.playSound(null, player.blockPosition(), ModSoundEvents.RIFT_CLOSE.get(), SoundSource.BLOCKS, 0.6f, 1); // TODO: different sound
|
||||
stack.hurtAndBreak(1, player, a -> {});
|
||||
player.displayClientMessage(Component.translatable(this.getDescriptionId() + ".stabilized"), true);
|
||||
return new InteractionResultHolder<>(InteractionResult.SUCCESS, stack);
|
||||
} 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
|
||||
public void appendTooltip(ItemStack itemStack, World world, List<Text> list, TooltipContext tooltipContext) {
|
||||
list.add(Text.translatable(this.getTranslationKey() + ".info"));
|
||||
public void appendHoverText(ItemStack itemStack, @Nullable Level level, List<Component> list, TooltipFlag tooltipFlag) {
|
||||
list.add(Component.translatable(this.getDescriptionId() + ".info"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,23 +1,26 @@
|
|||
package org.dimdev.dimdoors.item;
|
||||
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.item.ItemPlacementContext;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.ItemUsageContext;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
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.sound.SoundCategory;
|
||||
import net.minecraft.text.MutableText;
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.text.TranslatableTextContent;
|
||||
import net.minecraft.util.ActionResult;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.InteractionResult;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
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.api.util.Location;
|
||||
import org.dimdev.dimdoors.api.util.RotatedLocation;
|
||||
|
@ -34,82 +37,81 @@ public class StabilizedRiftSignatureItem extends Item { // TODO: common supercla
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean hasGlint(ItemStack stack) {
|
||||
return stack.getNbt() != null && stack.getNbt().contains("destination");
|
||||
public boolean isFoil(ItemStack stack) {
|
||||
return stack.getTag() != null && stack.getTag().contains("destination");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionResult useOnBlock(ItemUsageContext itemUsageContext) {
|
||||
PlayerEntity player = itemUsageContext.getPlayer();
|
||||
World world = itemUsageContext.getWorld();
|
||||
BlockPos pos = itemUsageContext.getBlockPos();
|
||||
Hand hand = itemUsageContext.getHand();
|
||||
Direction side = itemUsageContext.getSide();
|
||||
public InteractionResult useOn(UseOnContext itemUsageContext) {
|
||||
Player player = itemUsageContext.getPlayer();
|
||||
Level world = itemUsageContext.getLevel();
|
||||
BlockPos pos = itemUsageContext.getClickedPos()();
|
||||
InteractionHand hand = itemUsageContext.getHand();
|
||||
Direction side = itemUsageContext.getClickedFace();
|
||||
|
||||
ItemPlacementContext itemPlacementContext = new ItemPlacementContext(itemUsageContext);
|
||||
BlockPlaceContext itemPlacementContext = new BlockPlaceContext(itemUsageContext);
|
||||
|
||||
ItemStack stack = player.getStackInHand(hand);
|
||||
pos = world.getBlockState(pos).getBlock().canReplace(world.getBlockState(pos), new ItemPlacementContext(itemUsageContext)) ? pos : pos.offset(side);
|
||||
ItemStack stack = player.getItemInHand(hand);
|
||||
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
|
||||
if (!player.canPlaceOn(pos, side.getOpposite(), stack)) {
|
||||
return ActionResult.FAIL;
|
||||
if (!player.mayUseItemAt(pos, side.getOpposite(), stack)) {
|
||||
return InteractionResult.FAIL;
|
||||
}
|
||||
|
||||
if (world.isClient) {
|
||||
return ActionResult.SUCCESS;
|
||||
if (world.isClientSide) {
|
||||
return InteractionResult.SUCCESS;
|
||||
}
|
||||
|
||||
RotatedLocation target = getTarget(stack);
|
||||
|
||||
if (target == null) {
|
||||
// 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));
|
||||
player.sendMessage(Text.translatable(this.getTranslationKey() + ".stored"), true);
|
||||
world.playSound(null, player.getBlockPos(), ModSoundEvents.RIFT_START, SoundCategory.BLOCKS, 0.6f, 1);
|
||||
setSource(stack, new RotatedLocation(world.dimension(), pos, player.getYRot(), 0));
|
||||
player.displayClientMessage(Component.translatable(this.getDescriptionId() + ".stored"), true);
|
||||
world.playSound(null, player.blockPosition(), ModSoundEvents.RIFT_START.get(), SoundSource.BLOCKS, 0.6f, 1);
|
||||
} else {
|
||||
// Place a rift at the target point
|
||||
if (target.getBlockState().getBlock() != ModBlocks.DETACHED_RIFT) {
|
||||
if (!target.getBlockState().getBlock().canReplace(world.getBlockState(target.getBlockPos()), itemPlacementContext)) {
|
||||
player.sendMessage(Text.translatable("tools.target_became_block"), true);
|
||||
if (!target.getBlockState().getBlock().canBeReplaced(world.getBlockState(target.getBlockPos()), itemPlacementContext)) {
|
||||
player.displayClientMessage(Component.translatable("tools.target_became_block"), true);
|
||||
// Don't clear source, stabilized signatures always stay bound
|
||||
return ActionResult.FAIL;
|
||||
return InteractionResult.FAIL;
|
||||
}
|
||||
World targetWorld = DimensionalDoors.getWorld(target.world);
|
||||
targetWorld.setBlockState(target.getBlockPos(), ModBlocks.DETACHED_RIFT.getDefaultState());
|
||||
Level targetWorld = DimensionalDoors.getWorld(target.world);
|
||||
targetWorld.setBlockAndUpdate(target.getBlockPos(), ModBlocks.DETACHED_RIFT.get().defaultBlockState());
|
||||
DetachedRiftBlockEntity rift1 = (DetachedRiftBlockEntity) target.getBlockEntity();
|
||||
rift1.register();
|
||||
}
|
||||
|
||||
// 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);
|
||||
rift2.setDestination(RiftReference.tryMakeRelative(new Location((ServerWorld) world, pos), target));
|
||||
rift2.setDestination(RiftReference.tryMakeRelative(new Location((ServerLevel) world, pos), target));
|
||||
rift2.register();
|
||||
|
||||
stack.damage(1, player, playerEntity -> {
|
||||
});
|
||||
stack.hurtAndBreak(1, player, playerEntity -> {});
|
||||
|
||||
player.sendMessage(Text.translatable(this.getTranslationKey() + ".created"), true);
|
||||
world.playSound(null, player.getBlockPos(), ModSoundEvents.RIFT_END, SoundCategory.BLOCKS, 0.6f, 1);
|
||||
player.displayClientMessage(Component.translatable(this.getDescriptionId() + ".created"), true);
|
||||
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) {
|
||||
if (!itemStack.hasNbt()) itemStack.setNbt(new NbtCompound());
|
||||
itemStack.getNbt().put("destination", RotatedLocation.serialize(destination));
|
||||
if (!itemStack.hasTag()) itemStack.setTag(new CompoundTag());
|
||||
itemStack.getTag().put("destination", RotatedLocation.serialize(destination));
|
||||
}
|
||||
|
||||
public static void clearSource(ItemStack itemStack) {
|
||||
if (itemStack.hasNbt()) {
|
||||
itemStack.getNbt().remove("destination");
|
||||
if (itemStack.hasTag()) {
|
||||
itemStack.getTag().remove("destination");
|
||||
}
|
||||
}
|
||||
|
||||
public static RotatedLocation getTarget(ItemStack itemStack) {
|
||||
if (itemStack.hasNbt() && itemStack.getNbt().contains("destination")) {
|
||||
return RotatedLocation.deserialize(itemStack.getNbt().getCompound("destination"));
|
||||
if (itemStack.hasTag() && itemStack.getTag().contains("destination")) {
|
||||
return RotatedLocation.deserialize(itemStack.getTag().getCompound("destination"));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -1,21 +1,18 @@
|
|||
package org.dimdev.dimdoors.item.door;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
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.core.BlockPos;
|
||||
import net.minecraft.world.InteractionResult;
|
||||
import net.minecraft.world.item.BlockItem;
|
||||
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.state.BlockState;
|
||||
import org.dimdev.dimdoors.block.RiftProvider;
|
||||
import org.dimdev.dimdoors.block.entity.EntranceRiftBlockEntity;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class DimensionalTrapdoorItem extends BlockItem {
|
||||
private final Consumer<? super EntranceRiftBlockEntity> setupFunction;
|
||||
|
||||
|
@ -25,20 +22,20 @@ public class DimensionalTrapdoorItem extends BlockItem {
|
|||
}
|
||||
|
||||
@Override
|
||||
public ActionResult place(ItemPlacementContext context) {
|
||||
World world = context.getWorld();
|
||||
BlockPos pos = context.getBlockPos();
|
||||
public InteractionResult place(BlockPlaceContext context) {
|
||||
Level world = context.getLevel();
|
||||
BlockPos pos = context.getClickedPos();
|
||||
|
||||
if (world.isClient) {
|
||||
if (world.isClientSide) {
|
||||
return super.place(context);
|
||||
}
|
||||
|
||||
boolean replaceable = world.getBlockState(pos).canReplace(context); // Check this before calling super, since that changes the block
|
||||
ActionResult result = super.place(context);
|
||||
boolean replaceable = world.getBlockState(pos).canBeReplaced(context); // Check this before calling super, since that changes the block
|
||||
InteractionResult result = super.place(context);
|
||||
|
||||
if (result == ActionResult.SUCCESS) {
|
||||
if (result == InteractionResult.SUCCESS) {
|
||||
if (!replaceable) {
|
||||
pos = pos.offset(context.getPlayerLookDirection());
|
||||
pos = pos.relative(context.getNearestLookingDirection());
|
||||
}
|
||||
|
||||
BlockState state = world.getBlockState(pos);
|
||||
|
@ -49,7 +46,7 @@ public class DimensionalTrapdoorItem extends BlockItem {
|
|||
this.setupRift(entranceRift);
|
||||
|
||||
// Register the rift in the registry
|
||||
entranceRift.markDirty();
|
||||
entranceRift.setChanged();
|
||||
entranceRift.register();
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
||||
// )
|
||||
// )
|
||||
|
||||
|
||||
}
|
|
@ -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 {
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
// }
|
||||
//}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
// }
|
||||
}
|
|
@ -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);
|
||||
// }
|
||||
// }
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -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) {
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
// }
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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
Loading…
Reference in a new issue