Portal fixes and optimization

This commit is contained in:
Aleksey 2020-10-30 21:19:02 +03:00
parent 81e4098a72
commit 31f057eca5
11 changed files with 151 additions and 471 deletions

View file

@ -7,18 +7,24 @@ import com.google.common.collect.Sets;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtHelper;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.state.property.BooleanProperty;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.util.registry.Registry;
import net.minecraft.world.Heightmap;
import net.minecraft.world.World;
import net.minecraft.world.dimension.DimensionType;
import ru.betterend.blocks.BlockProperties;
import ru.betterend.blocks.EndPortalBlock;
import ru.betterend.blocks.RunedFlavolite;
import ru.betterend.blocks.entities.PedestalBlockEntity;
import ru.betterend.registry.EndBlocks;
import ru.betterend.registry.EndTags;
public class EternalRitual {
private final static Set<Point> structureMap = Sets.newHashSet(
@ -47,6 +53,7 @@ public class EternalRitual {
private World world;
private Direction.Axis axis;
private BlockPos center;
private BlockPos exit;
private boolean active = false;
public EternalRitual(World world) {
@ -66,8 +73,13 @@ public class EternalRitual {
this.world = world;
}
private boolean isValid() {
return world != null && !world.isClient() &&
center != null && axis != null;
}
public void checkStructure() {
if (center == null || axis == null) return;
if (!isValid()) return;
Direction moveX, moveY;
if (Direction.Axis.X == axis) {
moveX = Direction.EAST;
@ -108,18 +120,29 @@ public class EternalRitual {
private void activatePortal() {
if (active) return;
this.activatePortal(world, center);
if (exit == null) {
this.exit = this.findPortalPos();
} else {
World overworld = world.getServer().getWorld(World.OVERWORLD);
this.activatePortal(overworld, exit);
}
this.active = true;
}
private void activatePortal(World world, BlockPos center) {
BlockPos framePos = center.down();
Direction moveDir = Direction.Axis.X == axis ? Direction.NORTH: Direction.EAST;
BlockState frame = FRAME.getDefaultState().with(ACTIVE, true);
frameMap.forEach(point -> {
BlockPos pos = framePos.offset(moveDir, point.x).offset(Direction.UP, point.y);
BlockState state = world.getBlockState(pos);
if (!state.get(ACTIVE)) {
if (state.contains(ACTIVE) && !state.get(ACTIVE)) {
world.setBlockState(pos, frame);
}
pos = framePos.offset(moveDir, -point.x).offset(Direction.UP, point.y);
state = world.getBlockState(pos);
if (!state.get(ACTIVE)) {
if (state.contains(ACTIVE) && !state.get(ACTIVE)) {
world.setBlockState(pos, frame);
}
});
@ -135,11 +158,16 @@ public class EternalRitual {
world.setBlockState(pos, portal);
}
});
this.active = true;
}
public void removePortal() {
if (!active) return;
if (!active || !isValid()) return;
World overworld = world.getServer().getWorld(World.OVERWORLD);
this.removePortal(world, center);
this.removePortal(overworld, exit);
}
private void removePortal(World world, BlockPos center) {
BlockPos framePos = center.down();
Direction moveDir = Direction.Axis.X == axis ? Direction.NORTH: Direction.EAST;
frameMap.forEach(point -> {
@ -167,9 +195,89 @@ public class EternalRitual {
this.active = false;
}
private BlockPos findPortalPos() {
MinecraftServer server = world.getServer();
ServerWorld overworld = server.getWorld(World.OVERWORLD);
Registry<DimensionType> registry = server.getRegistryManager().getDimensionTypes();
double mult = registry.get(DimensionType.THE_END_ID).getCoordinateScale();
BlockPos.Mutable basePos = center.mutableCopy().set(center.getX() / mult, center.getY(), center.getZ() / mult);
Direction.Axis portalAxis = Direction.Axis.X == axis ? Direction.Axis.Z : Direction.Axis.X;
if (checkIsAreaValid(overworld, basePos, portalAxis)) {
EternalRitual.generatePortal(overworld, basePos, portalAxis);
if (portalAxis.equals(Direction.Axis.X)) {
return basePos.toImmutable();
} else {
return basePos.toImmutable();
}
} else {
Direction direction = Direction.EAST;
BlockPos.Mutable checkPos = basePos.mutableCopy();
for (int step = 1; step < 64; step++) {
for (int i = 0; i < step; i++) {
checkPos.setY(5);
while(checkPos.getY() < world.getHeight()) {
if(checkIsAreaValid(overworld, checkPos, portalAxis)) {
EternalRitual.generatePortal(overworld, checkPos, portalAxis);
if (portalAxis.equals(Direction.Axis.X)) {
return checkPos.toImmutable();
} else {
return checkPos.toImmutable();
}
}
checkPos.move(Direction.UP);
}
checkPos.move(direction);
}
direction = direction.rotateYClockwise();
}
}
basePos.setY(overworld.getChunk(basePos).sampleHeightmap(Heightmap.Type.WORLD_SURFACE, basePos.getX(), basePos.getZ()));
EternalRitual.generatePortal(overworld, basePos, portalAxis);
if (portalAxis.equals(Direction.Axis.X)) {
return basePos.toImmutable();
} else {
return basePos.toImmutable();
}
}
private boolean checkIsAreaValid(World world, BlockPos pos, Direction.Axis axis) {
if (!isBaseValid(world, pos, axis)) return false;
return EternalRitual.checkArea(world, pos, axis);
}
private boolean isBaseValid(World world, BlockPos pos, Direction.Axis axis) {
boolean solid = true;
if (axis.equals(Direction.Axis.X)) {
pos = pos.down().add(0, 0, -3);
for (int i = 0; i < 7; i++) {
BlockPos checkPos = pos.add(0, 0, i);
BlockState state = world.getBlockState(checkPos);
solid &= this.validBlock(world, checkPos, state);
}
} else {
pos = pos.down().add(-3, 0, 0);
for (int i = 0; i < 7; i++) {
BlockPos checkPos = pos.add(i, 0, 0);
BlockState state = world.getBlockState(checkPos);
solid &= this.validBlock(world, checkPos, state);
}
}
return solid;
}
private boolean validBlock(World world, BlockPos pos, BlockState state) {
BlockState surfaceBlock = world.getBiome(pos).getGenerationSettings().getSurfaceConfig().getTopMaterial();
return state.isSolidBlock(world, pos) &&
(EndTags.validGenBlock(state) ||
state.isOf(surfaceBlock.getBlock()) ||
state.isOf(Blocks.STONE) ||
state.isOf(Blocks.SAND) ||
state.isOf(Blocks.GRAVEL));
}
public static void generatePortal(World world, BlockPos center, Direction.Axis axis) {
BlockPos framePos = center.down();
Direction moveDir = Direction.Axis.X == axis ? Direction.NORTH: Direction.EAST;
Direction moveDir = Direction.Axis.X == axis ? Direction.EAST: Direction.NORTH;
BlockState frame = FRAME.getDefaultState().with(ACTIVE, true);
frameMap.forEach(point -> {
BlockPos pos = framePos.offset(moveDir, point.x).offset(Direction.UP, point.y);
@ -177,8 +285,7 @@ public class EternalRitual {
pos = framePos.offset(moveDir, -point.x).offset(Direction.UP, point.y);
world.setBlockState(pos, frame);
});
Direction.Axis portalAxis = Direction.Axis.X == axis ? Direction.Axis.Z : Direction.Axis.X;
BlockState portal = PORTAL.getDefaultState().with(EndPortalBlock.AXIS, portalAxis);
BlockState portal = PORTAL.getDefaultState().with(EndPortalBlock.AXIS, axis);
portalMap.forEach(point -> {
BlockPos pos = center.offset(moveDir, point.x).offset(Direction.UP, point.y);
world.setBlockState(pos, portal);
@ -214,7 +321,6 @@ public class EternalRitual {
if (!world.getBlockState(pos).isAir()) return false;
}
}
return true;
}
@ -311,6 +417,9 @@ public class EternalRitual {
public CompoundTag toTag(CompoundTag tag) {
tag.put("center", NbtHelper.fromBlockPos(center));
if (exit != null) {
tag.put("exit", NbtHelper.fromBlockPos(exit));
}
tag.putString("axis", axis.getName());
tag.putBoolean("active", active);
return tag;
@ -320,5 +429,8 @@ public class EternalRitual {
this.axis = Direction.Axis.fromName(tag.getString("axis"));
this.center = NbtHelper.toBlockPos(tag.getCompound("center"));
this.active = tag.getBoolean("active");
if (tag.contains("exit")) {
this.exit = NbtHelper.toBlockPos(tag.getCompound("exit"));
}
}
}

View file

@ -73,6 +73,10 @@ public class MHelper {
return max(a, max(b, c));
}
public static boolean isEven(int num) {
return (num & 1) == 0;
}
public static float lengthSqr(float x, float y, float z) {
return x * x + y * y + z * z;
}

View file

@ -1,181 +0,0 @@
package ru.betterend.util;
import java.util.Random;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.World;
import ru.betterend.registry.EndBlocks;
import ru.betterend.registry.EndFeatures;
public class PortalFrameHelper {
public static boolean checkPortalFrame(ServerWorld world, BlockPos pos, Block frameBlock) {
if (world == null || pos == null) return false;
if (!world.getBlockState(pos).isOf(frameBlock)) return false;
BlockPos bottomCorner = findBottomCorner(world, pos, frameBlock);
BlockPos topCorner = findTopCorner(world, pos, frameBlock);
if (bottomCorner == null || topCorner == null) return false;
boolean valid = true;
int width = 1, height = 1;
Direction.Axis axis = Direction.Axis.X;
BlockPos.Mutable checkPos = bottomCorner.up().mutableCopy();
Direction moveDir = Direction.UP;
while(valid && !checkPos.equals(bottomCorner)) {
valid = world.getBlockState(checkPos).isOf(frameBlock);
if (!valid) {
checkPos = checkPos.move(moveDir.getOpposite());
switch(moveDir) {
case UP: {
if (world.getBlockState(checkPos.east()).isOf(frameBlock)) {
moveDir = Direction.EAST;
valid = true;
} else if (world.getBlockState(checkPos.south()).isOf(frameBlock)) {
axis = Direction.Axis.Z;
moveDir = Direction.SOUTH;
valid = true;
}
break;
}
case DOWN: {
if (world.getBlockState(checkPos.west()).isOf(frameBlock)) {
moveDir = Direction.WEST;
valid = true;
} else if (world.getBlockState(checkPos.north()).isOf(frameBlock)) {
moveDir = Direction.NORTH;
valid = true;
}
break;
}
case SOUTH:
case EAST: {
if (world.getBlockState(checkPos.down()).isOf(frameBlock)) {
moveDir = Direction.DOWN;
valid = true;
}
break;
}
default:
return false;
}
if (!valid) return false;
checkPos = checkPos.move(moveDir);
} else {
if (moveDir.equals(Direction.EAST) || moveDir.equals(Direction.SOUTH)) {
width++;
} else if (moveDir.equals(Direction.UP)) {
height++;
}
checkPos = checkPos.move(moveDir);
}
}
if (width < 4 || height < 5 || width > 20 || height > 25) return false;
if (axis.equals(Direction.Axis.X)) {
if(!checkIsAreaEmpty(world, bottomCorner.add(1, 1, 0), topCorner.add(-1, -1, 0))) return false;
} else {
if(!checkIsAreaEmpty(world, bottomCorner.add(0, 1, 1), topCorner.add(0, -1, -1))) return false;
}
if (valid) {
if (world.getBlockState(bottomCorner).isOf(EndBlocks.FLAVOLITE_RUNED)) {
generatePortalFrame(world, bottomCorner, axis, width, height, true);
} else {
generateEternalPortalFrame(world, bottomCorner, axis, width, height, true);
}
}
return valid;
}
public static BlockPos findBottomCorner(World world, BlockPos pos, Block frameBlock) {
BlockState up = world.getBlockState(pos.up());
BlockState down = world.getBlockState(pos.down());
BlockState north = world.getBlockState(pos.north());
BlockState south = world.getBlockState(pos.south());
BlockState west = world.getBlockState(pos.west());
BlockState east = world.getBlockState(pos.east());
BlockPos.Mutable mutable = pos instanceof BlockPos.Mutable ? (BlockPos.Mutable) pos : pos.mutableCopy();
if (up.isOf(frameBlock) && !down.isOf(frameBlock)) {
if (south.isOf(frameBlock) || east.isOf(frameBlock)) {
return pos.toImmutable();
} else if (west.isOf(frameBlock)) {
return findBottomCorner(world, mutable.move(Direction.WEST), frameBlock);
} else if (north.isOf(frameBlock)){
return findBottomCorner(world, mutable.move(Direction.NORTH), frameBlock);
}
return null;
} else if (down.isOf(frameBlock)) {
if (west.isOf(frameBlock)) {
return findBottomCorner(world, mutable.move(Direction.WEST), frameBlock);
} else if (north.isOf(frameBlock)) {
return findBottomCorner(world, mutable.move(Direction.NORTH), frameBlock);
} else {
return findBottomCorner(world, mutable.move(Direction.DOWN), frameBlock);
}
} else if (west.isOf(frameBlock)) {
return findBottomCorner(world, mutable.move(Direction.WEST), frameBlock);
} else if (north.isOf(frameBlock)) {
return findBottomCorner(world, mutable.move(Direction.NORTH), frameBlock);
}
return null;
}
public static BlockPos findTopCorner(World world, BlockPos pos, Block frameBlock) {
BlockState up = world.getBlockState(pos.up());
BlockState down = world.getBlockState(pos.down());
BlockState north = world.getBlockState(pos.north());
BlockState south = world.getBlockState(pos.south());
BlockState west = world.getBlockState(pos.west());
BlockState east = world.getBlockState(pos.east());
BlockPos.Mutable mutable = pos instanceof BlockPos.Mutable ? (BlockPos.Mutable) pos : pos.mutableCopy();
if (!up.isOf(frameBlock) && down.isOf(frameBlock)) {
if (north.isOf(frameBlock) || west.isOf(frameBlock)) {
return pos.toImmutable();
} else if (east.isOf(frameBlock)) {
return findTopCorner(world, mutable.move(Direction.EAST), frameBlock);
} else if (south.isOf(frameBlock)){
return findTopCorner(world, mutable.move(Direction.SOUTH), frameBlock);
}
return null;
} else if (up.isOf(frameBlock)) {
if (east.isOf(frameBlock)) {
return findTopCorner(world, mutable.move(Direction.EAST), frameBlock);
} else if (south.isOf(frameBlock)){
return findTopCorner(world, mutable.move(Direction.SOUTH), frameBlock);
} else {
return findTopCorner(world, mutable.move(Direction.UP), frameBlock);
}
} else if (east.isOf(frameBlock)) {
return findTopCorner(world, mutable.move(Direction.EAST), frameBlock);
} else if (south.isOf(frameBlock)){
return findTopCorner(world, mutable.move(Direction.SOUTH), frameBlock);
}
return null;
}
private static boolean checkIsAreaEmpty(World world, BlockPos bottom, BlockPos top) {
boolean valid = true;
for (BlockPos current : BlockPos.iterate(bottom, top)) {
BlockState state = world.getBlockState(current);
valid &= state.isAir();
}
return valid;
}
public static void generatePortalFrame(ServerWorld world, BlockPos pos, Direction.Axis axis, int width, int height, boolean active) {
EndFeatures.END_PORTAL.configure(axis, width, height, active).getFeatureConfigured().generate(world, world.getChunkManager().getChunkGenerator(), new Random(), pos);
}
public static void generateEternalPortalFrame(ServerWorld world, BlockPos pos, Direction.Axis axis, int width, int height, boolean active) {
EndFeatures.END_PORTAL_ETERNAL.configure(axis, width, height, active).getFeatureConfigured().generate(world, world.getChunkManager().getChunkGenerator(), new Random(), pos);
}
public static void generatePortalFrame(ServerWorld world, BlockPos pos, Direction.Axis axis, boolean active) {
EndFeatures.END_PORTAL.configure(axis, active).getFeatureConfigured().generate(world, world.getChunkManager().getChunkGenerator(), new Random(), pos);
}
public static void generateEternalPortalFrame(ServerWorld world, BlockPos pos, Direction.Axis axis, boolean active) {
EndFeatures.END_PORTAL_ETERNAL.configure(axis, active).getFeatureConfigured().generate(world, world.getChunkManager().getChunkGenerator(), new Random(), pos);
}
}