Configured portals

This commit is contained in:
Aleksey 2021-03-28 19:18:16 +03:00
parent 0a7391a35e
commit 068fa540be
4 changed files with 112 additions and 80 deletions

View file

@ -84,6 +84,7 @@ public class EndPortalBlock extends NetherPortalBlock implements IRenderTypeable
public void onEntityCollision(BlockState state, World world, BlockPos pos, Entity entity) { public void onEntityCollision(BlockState state, World world, BlockPos pos, Entity entity) {
if (world instanceof ServerWorld && !entity.hasVehicle() && !entity.hasPassengers() && entity.canUsePortals()) { if (world instanceof ServerWorld && !entity.hasVehicle() && !entity.hasPassengers() && entity.canUsePortals()) {
if (entity.hasNetherPortalCooldown()) return; if (entity.hasNetherPortalCooldown()) return;
entity.resetNetherPortalCooldown();
ServerWorld currentWorld = (ServerWorld) world; ServerWorld currentWorld = (ServerWorld) world;
MinecraftServer server = currentWorld.getServer(); MinecraftServer server = currentWorld.getServer();
ServerWorld targetWorld = EndPortals.getWorld(server, state.get(PORTAL)); ServerWorld targetWorld = EndPortals.getWorld(server, state.get(PORTAL));
@ -121,47 +122,45 @@ public class EndPortalBlock extends NetherPortalBlock implements IRenderTypeable
return ERenderLayer.TRANSLUCENT; return ERenderLayer.TRANSLUCENT;
} }
private BlockPos findExitPos(ServerWorld current, ServerWorld target, BlockPos pos, Entity entity) { private BlockPos findExitPos(ServerWorld currentWorld, ServerWorld targetWorld, BlockPos currentPos, Entity entity) {
if (target == null) return null; if (targetWorld == null) return null;
Registry<DimensionType> registry = targetWorld.getRegistryManager().getDimensionTypes();
Registry<DimensionType> registry = target.getRegistryManager().getDimensionTypes(); Identifier targetWorldId = targetWorld.getRegistryKey().getValue();
Identifier targetWorldId = target.getRegistryKey().getValue(); Identifier currentWorldId = currentWorld.getRegistryKey().getValue();
Identifier currentWorldId = current.getRegistryKey().getValue();
double targetMultiplier = Objects.requireNonNull(registry.get(targetWorldId)).getCoordinateScale(); double targetMultiplier = Objects.requireNonNull(registry.get(targetWorldId)).getCoordinateScale();
double currentMultiplier = Objects.requireNonNull(registry.get(currentWorldId)).getCoordinateScale(); double currentMultiplier = Objects.requireNonNull(registry.get(currentWorldId)).getCoordinateScale();
double multiplier = targetMultiplier > currentMultiplier ? 1.0 / targetMultiplier : currentMultiplier; double multiplier = targetMultiplier > currentMultiplier ? 1.0 / targetMultiplier : currentMultiplier;
BlockPos.Mutable basePos = pos.mutableCopy().set(pos.getX() * multiplier, pos.getY(), pos.getZ() * multiplier); BlockPos.Mutable basePos = currentPos.mutableCopy().set(currentPos.getX() * multiplier, currentPos.getY(), currentPos.getZ() * multiplier);
Direction direction = Direction.EAST; Direction direction = Direction.EAST;
BlockPos.Mutable checkPos = basePos.mutableCopy(); BlockPos.Mutable checkPos = basePos.mutableCopy();
for (int step = 1; step < 128; step++) { for (int step = 1; step < 64; step++) {
for (int i = 0; i < (step >> 1); i++) { for (int i = 0; i < (step >> 1); i++) {
Chunk chunk = target.getChunk(checkPos); Chunk chunk = targetWorld.getChunk(checkPos);
if (chunk != null) { if (chunk != null) {
int surfaceY = chunk.sampleHeightmap(Heightmap.Type.WORLD_SURFACE, checkPos.getX() & 15, checkPos.getZ() & 15); int surfaceY = chunk.sampleHeightmap(Heightmap.Type.WORLD_SURFACE, checkPos.getX() & 15, checkPos.getZ() & 15);
int motionY = chunk.sampleHeightmap(Heightmap.Type.MOTION_BLOCKING, checkPos.getX() & 15, checkPos.getZ() & 15); int motionY = chunk.sampleHeightmap(Heightmap.Type.MOTION_BLOCKING, checkPos.getX() & 15, checkPos.getZ() & 15);
int ceil = Math.max(surfaceY, motionY) + 1; int ceil = Math.max(surfaceY, motionY) + 1;
if (ceil > 5) { if (ceil < 5) continue;
checkPos.setY(ceil); checkPos.setY(ceil);
while (checkPos.getY() > 5) { while (checkPos.getY() >= 5) {
BlockState state = target.getBlockState(checkPos); BlockState state = targetWorld.getBlockState(checkPos);
if (state.isOf(this)) { if (state.isOf(this)) {
Axis axis = state.get(AXIS); Axis axis = state.get(AXIS);
checkPos = findCenter(target, checkPos, axis); checkPos = findCenter(targetWorld, checkPos, axis);
Direction frontDir = Direction.from(axis, AxisDirection.POSITIVE).rotateYClockwise(); Direction frontDir = Direction.from(axis, AxisDirection.POSITIVE).rotateYClockwise();
Direction entityDir = entity.getMovementDirection(); Direction entityDir = entity.getMovementDirection();
if (entityDir.getAxis().isVertical()) { if (entityDir.getAxis().isVertical()) {
entityDir = frontDir; entityDir = frontDir;
}
if (frontDir != entityDir && frontDir.getOpposite() != entityDir) {
entity.applyRotation(BlockRotation.CLOCKWISE_90);
entityDir = entityDir.rotateYClockwise();
}
return checkPos.offset(entityDir);
} }
checkPos.move(Direction.DOWN);
if (frontDir != entityDir && frontDir.getOpposite() != entityDir) {
entity.applyRotation(BlockRotation.CLOCKWISE_90);
entityDir = entityDir.rotateYClockwise();
}
return checkPos.offset(entityDir);
} }
checkPos.move(Direction.DOWN);
} }
} }
checkPos.move(direction); checkPos.move(direction);

View file

@ -9,7 +9,6 @@ import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks; import net.minecraft.block.Blocks;
import net.minecraft.block.entity.BlockEntity; import net.minecraft.block.entity.BlockEntity;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.loot.context.LootContext; import net.minecraft.loot.context.LootContext;
import net.minecraft.loot.context.LootContextParameters; import net.minecraft.loot.context.LootContextParameters;
@ -43,12 +42,19 @@ public class EternalPedestal extends PedestalBlock {
if (blockEntity instanceof EternalPedestalEntity) { if (blockEntity instanceof EternalPedestalEntity) {
EternalPedestalEntity pedestal = (EternalPedestalEntity) blockEntity; EternalPedestalEntity pedestal = (EternalPedestalEntity) blockEntity;
BlockState updatedState = world.getBlockState(pos); BlockState updatedState = world.getBlockState(pos);
if (pedestal.isEmpty() && updatedState.get(ACTIVATED)) { if (pedestal.isEmpty()) {
if (pedestal.hasRitual()) { if (pedestal.hasRitual()) {
EternalRitual ritual = pedestal.getRitual(); EternalRitual ritual = pedestal.getRitual();
Item item = pedestal.getStack(0).getItem(); if (ritual.isActive()) {
int dim = EndPortals.getPortalState(Registry.ITEM.getId(item)); Identifier targetWorld = ritual.getTargetWorldId();
ritual.removePortal(dim); int portalId;
if (targetWorld != null) {
portalId = EndPortals.getPortalIdByWorld(targetWorld);
} else {
portalId = EndPortals.getPortalIdByWorld(EndPortals.OVERWORLD_ID);
}
ritual.disablePortal(portalId);
}
} }
world.setBlockState(pos, updatedState.with(ACTIVATED, false).with(HAS_LIGHT, false)); world.setBlockState(pos, updatedState.with(ACTIVATED, false).with(HAS_LIGHT, false));
} else { } else {

View file

@ -8,12 +8,17 @@ import com.google.gson.JsonObject;
import net.minecraft.server.MinecraftServer; import net.minecraft.server.MinecraftServer;
import net.minecraft.server.world.ServerWorld; import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.registry.Registry;
import net.minecraft.world.World;
import ru.betterend.BetterEnd; import ru.betterend.BetterEnd;
import ru.betterend.config.ConfigWriter; import ru.betterend.config.ConfigWriter;
import ru.betterend.util.JsonFactory; import ru.betterend.util.JsonFactory;
import ru.betterend.util.MHelper; import ru.betterend.util.MHelper;
public class EndPortals { public class EndPortals {
public final static Identifier OVERWORLD_ID = World.OVERWORLD.getValue();
private static PortalInfo[] portals; private static PortalInfo[] portals;
public static void loadPortals() { public static void loadPortals() {
@ -43,14 +48,21 @@ public class EndPortals {
return MHelper.max(portals.length - 1, 1); return MHelper.max(portals.length - 1, 1);
} }
public static ServerWorld getWorld(MinecraftServer server, int state) { public static ServerWorld getWorld(MinecraftServer server, int portalId) {
if (state >= portals.length) { if (portalId < 0 || portalId >= portals.length) {
return server.getOverworld(); return server.getOverworld();
} }
return portals[state].getWorld(server); return portals[portalId].getWorld(server);
} }
public static int getPortalState(Identifier item) { public static Identifier getWorldId(int portalId) {
if (portalId < 0 || portalId >= portals.length) {
return OVERWORLD_ID;
}
return portals[portalId].dimension;
}
public static int getPortalIdByItem(Identifier item) {
for (int i = 0; i < portals.length; i++) { for (int i = 0; i < portals.length; i++) {
if (portals[i].item.equals(item)) { if (portals[i].item.equals(item)) {
return i; return i;
@ -58,6 +70,14 @@ public class EndPortals {
} }
return 0; return 0;
} }
public static int getPortalIdByWorld(Identifier world) {
for (int i = 0; i < portals.length; i++) {
if (portals[i].dimension.equals(world)) {
return i;
}
}
return 0;
}
public static int getColor(int state) { public static int getColor(int state) {
return portals[state].color; return portals[state].color;

View file

@ -30,6 +30,7 @@ import net.minecraft.world.World;
import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.dimension.DimensionType; import net.minecraft.world.dimension.DimensionType;
import net.minecraft.world.gen.feature.ConfiguredFeatures; import net.minecraft.world.gen.feature.ConfiguredFeatures;
import org.jetbrains.annotations.Nullable;
import ru.betterend.blocks.BlockProperties; import ru.betterend.blocks.BlockProperties;
import ru.betterend.blocks.EndPortalBlock; import ru.betterend.blocks.EndPortalBlock;
import ru.betterend.blocks.RunedFlavolite; import ru.betterend.blocks.RunedFlavolite;
@ -64,6 +65,7 @@ public class EternalRitual {
private World world; private World world;
private Direction.Axis axis; private Direction.Axis axis;
private Identifier targetWorldId;
private BlockPos center; private BlockPos center;
private BlockPos exit; private BlockPos exit;
private boolean active = false; private boolean active = false;
@ -81,10 +83,14 @@ public class EternalRitual {
this.world = world; this.world = world;
} }
@Nullable
public Identifier getTargetWorldId() {
return targetWorldId;
}
private boolean isInvalid() { private boolean isInvalid() {
return world == null || world.isClient() || return world == null || world.isClient() ||
center == null || axis == null || center == null || axis == null;
world.getRegistryKey() == World.NETHER;
} }
public void checkStructure() { public void checkStructure() {
@ -98,7 +104,7 @@ public class EternalRitual {
moveX = Direction.SOUTH; moveX = Direction.SOUTH;
moveY = Direction.EAST; moveY = Direction.EAST;
} }
boolean valid = checkFrame(); boolean valid = checkFrame(world, center.down());
Item item = null; Item item = null;
for (Point pos : STRUCTURE_MAP) { for (Point pos : STRUCTURE_MAP) {
BlockPos.Mutable checkPos = center.mutableCopy(); BlockPos.Mutable checkPos = center.mutableCopy();
@ -121,8 +127,7 @@ public class EternalRitual {
} }
} }
private boolean checkFrame() { private boolean checkFrame(World world, BlockPos framePos) {
BlockPos framePos = center.down();
Direction moveDir = Direction.Axis.X == axis ? Direction.NORTH : Direction.EAST; Direction moveDir = Direction.Axis.X == axis ? Direction.NORTH : Direction.EAST;
boolean valid = true; boolean valid = true;
for (Point point : FRAME_MAP) { for (Point point : FRAME_MAP) {
@ -137,23 +142,24 @@ public class EternalRitual {
} }
public boolean isActive() { public boolean isActive() {
return this.active; return active;
} }
private void activatePortal(Item item) { private void activatePortal(Item keyItem) {
if (active) return; if (active) return;
int state = EndPortals.getPortalState(Registry.ITEM.getId(item)); Identifier itemId = Registry.ITEM.getId(keyItem);
activatePortal(world, center, state); int portalId = EndPortals.getPortalIdByItem(itemId);
activatePortal(world, center, portalId);
doEffects((ServerWorld) world, center); doEffects((ServerWorld) world, center);
if (exit == null) { if (exit == null) {
this.exit = findPortalPos(state); exit = findPortalPos(portalId);
} else { } else {
World targetWorld = getTargetWorld(state); World targetWorld = getTargetWorld(portalId);
if (targetWorld.getBlockState(exit.up()).isOf(EndBlocks.END_PORTAL_BLOCK)) { if (!checkFrame(targetWorld, exit)) {
this.exit = findPortalPos(state); Direction.Axis portalAxis = (Direction.Axis.X == axis) ? Direction.Axis.Z : Direction.Axis.X;
} else { generatePortal(targetWorld, exit, portalAxis, portalId);
activatePortal(targetWorld, exit, state);
} }
activatePortal(targetWorld, exit, portalId);
} }
this.active = true; this.active = true;
} }
@ -214,17 +220,14 @@ public class EternalRitual {
}); });
} }
public void removePortal(int state) { public void disablePortal(int state) {
if (!active || isInvalid()) return; if (!active || isInvalid()) return;
System.out.println(getTargetWorld(state).getRegistryKey());
System.out.println(exit);
removePortal(getTargetWorld(state), exit); removePortal(getTargetWorld(state), exit);
removePortal(world, center); removePortal(world, center);
} }
private void removePortal(World world, BlockPos center) { private void removePortal(World world, BlockPos center) {
BlockPos framePos = center.down(); BlockPos framePos = center.down();
System.out.println(framePos);
Direction moveDir = Direction.Axis.X == axis ? Direction.NORTH : Direction.EAST; Direction moveDir = Direction.Axis.X == axis ? Direction.NORTH : Direction.EAST;
FRAME_MAP.forEach(point -> { FRAME_MAP.forEach(point -> {
BlockPos pos = framePos.mutableCopy().move(moveDir, point.x).move(Direction.UP, point.y); BlockPos pos = framePos.mutableCopy().move(moveDir, point.x).move(Direction.UP, point.y);
@ -251,33 +254,33 @@ public class EternalRitual {
this.active = false; this.active = false;
} }
private BlockPos findPortalPos(int state) { private BlockPos findPortalPos(int portalId) {
targetWorldId = EndPortals.getWorldId(portalId);
MinecraftServer server = world.getServer(); MinecraftServer server = world.getServer();
assert server != null; ServerWorld targetWorld = (ServerWorld) getTargetWorld(portalId);
ServerWorld targetWorld = (ServerWorld) getTargetWorld(state); Registry<DimensionType> registry = Objects.requireNonNull(server).getRegistryManager().getDimensionTypes();
Identifier targetWorldId = targetWorld.getRegistryKey().getValue();
Registry<DimensionType> registry = server.getRegistryManager().getDimensionTypes();
double multiplier = Objects.requireNonNull(registry.get(targetWorldId)).getCoordinateScale(); double multiplier = Objects.requireNonNull(registry.get(targetWorldId)).getCoordinateScale();
BlockPos.Mutable basePos = center.mutableCopy().set(center.getX() / multiplier, center.getY(), center.getZ() / multiplier); BlockPos.Mutable basePos = center.mutableCopy().set(center.getX() / multiplier, center.getY(), center.getZ() / multiplier);
Direction.Axis portalAxis = (Direction.Axis.X == axis) ? Direction.Axis.Z : Direction.Axis.X; Direction.Axis portalAxis = (Direction.Axis.X == axis) ? Direction.Axis.Z : Direction.Axis.X;
int worldCeil = targetWorld.getDimensionHeight() - 1; int worldCeil = targetWorld.getDimensionHeight() - 1;
if (checkIsAreaValid(targetWorld, basePos, portalAxis)) { if (checkIsAreaValid(targetWorld, basePos, portalAxis)) {
EternalRitual.generatePortal(targetWorld, basePos, portalAxis); EternalRitual.generatePortal(targetWorld, basePos, portalAxis, portalId);
return basePos.toImmutable(); return basePos.toImmutable();
} else { } else {
Direction direction = Direction.EAST; Direction direction = Direction.EAST;
BlockPos.Mutable checkPos = basePos.mutableCopy(); BlockPos.Mutable checkPos = basePos.mutableCopy();
for (int step = 1; step < 128; step++) { for (int step = 1; step < 64; step++) {
for (int i = 0; i < (step >> 1); i++) { for (int i = 0; i < (step >> 1); i++) {
Chunk chunk = world.getChunk(checkPos); Chunk chunk = targetWorld.getChunk(checkPos);
if (chunk != null) { if (chunk != null) {
int ceil = chunk.sampleHeightmap(Heightmap.Type.WORLD_SURFACE, checkPos.getX() & 15, checkPos.getZ() & 15) + 1; int surfaceY = chunk.sampleHeightmap(Heightmap.Type.WORLD_SURFACE, checkPos.getX() & 15, checkPos.getZ() & 15);
ceil = Math.min(ceil, worldCeil); int motionY = chunk.sampleHeightmap(Heightmap.Type.MOTION_BLOCKING, checkPos.getX() & 15, checkPos.getZ() & 15);
int ceil = Math.min(Math.max(surfaceY, motionY) + 1, worldCeil);
if (ceil < 5) continue; if (ceil < 5) continue;
checkPos.setY(ceil); checkPos.setY(ceil);
while (checkPos.getY() > 2) { while (checkPos.getY() >= 5) {
if(checkIsAreaValid(targetWorld, checkPos, portalAxis)) { if(checkIsAreaValid(targetWorld, checkPos, portalAxis)) {
EternalRitual.generatePortal(targetWorld, checkPos, portalAxis); generatePortal(targetWorld, checkPos, portalAxis, portalId);
return checkPos.toImmutable(); return checkPos.toImmutable();
} }
checkPos.move(Direction.DOWN); checkPos.move(Direction.DOWN);
@ -290,12 +293,11 @@ public class EternalRitual {
} }
if (targetWorld.getRegistryKey() == World.END) { if (targetWorld.getRegistryKey() == World.END) {
ConfiguredFeatures.END_ISLAND.generate(targetWorld, targetWorld.getChunkManager().getChunkGenerator(), new Random(basePos.asLong()), basePos.down()); ConfiguredFeatures.END_ISLAND.generate(targetWorld, targetWorld.getChunkManager().getChunkGenerator(), new Random(basePos.asLong()), basePos.down());
} } else if (targetWorld.getRegistryKey() == World.OVERWORLD) {
else {
basePos.setY(targetWorld.getChunk(basePos).sampleHeightmap(Heightmap.Type.WORLD_SURFACE, basePos.getX(), basePos.getZ()) + 1); basePos.setY(targetWorld.getChunk(basePos).sampleHeightmap(Heightmap.Type.WORLD_SURFACE, basePos.getX(), basePos.getZ()) + 1);
EndFeatures.OVERWORLD_ISLAND.getFeatureConfigured().generate(targetWorld, targetWorld.getChunkManager().getChunkGenerator(), new Random(basePos.asLong()), basePos.down()); EndFeatures.OVERWORLD_ISLAND.getFeatureConfigured().generate(targetWorld, targetWorld.getChunkManager().getChunkGenerator(), new Random(basePos.asLong()), basePos.down());
} }
EternalRitual.generatePortal(targetWorld, basePos, portalAxis); generatePortal(targetWorld, basePos, portalAxis, portalId);
return basePos.toImmutable(); return basePos.toImmutable();
} }
@ -307,7 +309,6 @@ public class EternalRitual {
} }
private boolean checkIsAreaValid(World world, BlockPos pos, Direction.Axis axis) { private boolean checkIsAreaValid(World world, BlockPos pos, Direction.Axis axis) {
System.out.println(pos.getY());
if (pos.getY() >= world.getDimensionHeight() - 1) return false; if (pos.getY() >= world.getDimensionHeight() - 1) return false;
if (!isBaseValid(world, pos, axis)) return false; if (!isBaseValid(world, pos, axis)) return false;
return EternalRitual.checkArea(world, pos, axis); return EternalRitual.checkArea(world, pos, axis);
@ -338,7 +339,7 @@ public class EternalRitual {
return state.isSolidBlock(world, pos) && state.isFullCube(world, pos); return state.isSolidBlock(world, pos) && state.isFullCube(world, pos);
} }
public static void generatePortal(World world, BlockPos center, Direction.Axis axis) { public static void generatePortal(World world, BlockPos center, Direction.Axis axis, int portalId) {
BlockPos framePos = center.down(); BlockPos framePos = center.down();
Direction moveDir = Direction.Axis.X == axis ? Direction.EAST : Direction.NORTH; Direction moveDir = Direction.Axis.X == axis ? Direction.EAST : Direction.NORTH;
BlockState frame = FRAME.getDefaultState().with(ACTIVE, true); BlockState frame = FRAME.getDefaultState().with(ACTIVE, true);
@ -348,7 +349,7 @@ public class EternalRitual {
pos = framePos.mutableCopy().move(moveDir, -point.x).move(Direction.UP, point.y); pos = framePos.mutableCopy().move(moveDir, -point.x).move(Direction.UP, point.y);
world.setBlockState(pos, frame); world.setBlockState(pos, frame);
}); });
BlockState portal = PORTAL.getDefaultState().with(EndPortalBlock.AXIS, axis); BlockState portal = PORTAL.getDefaultState().with(EndPortalBlock.AXIS, axis).with(EndPortalBlock.PORTAL, portalId);
PORTAL_MAP.forEach(point -> { PORTAL_MAP.forEach(point -> {
BlockPos pos = center.mutableCopy().move(moveDir, point.x).move(Direction.UP, point.y); BlockPos pos = center.mutableCopy().move(moveDir, point.x).move(Direction.UP, point.y);
world.setBlockState(pos, portal); world.setBlockState(pos, portal);
@ -489,20 +490,26 @@ public class EternalRitual {
public CompoundTag toTag(CompoundTag tag) { public CompoundTag toTag(CompoundTag tag) {
tag.put("center", NbtHelper.fromBlockPos(center)); tag.put("center", NbtHelper.fromBlockPos(center));
tag.putString("axis", axis.getName());
tag.putBoolean("active", active);
if (targetWorldId != null) {
tag.putString("key_item", targetWorldId.toString());
}
if (exit != null) { if (exit != null) {
tag.put("exit", NbtHelper.fromBlockPos(exit)); tag.put("exit", NbtHelper.fromBlockPos(exit));
} }
tag.putString("axis", axis.getName());
tag.putBoolean("active", active);
return tag; return tag;
} }
public void fromTag(CompoundTag tag) { public void fromTag(CompoundTag tag) {
this.axis = Direction.Axis.fromName(tag.getString("axis")); axis = Direction.Axis.fromName(tag.getString("axis"));
this.center = NbtHelper.toBlockPos(tag.getCompound("center")); center = NbtHelper.toBlockPos(tag.getCompound("center"));
this.active = tag.getBoolean("active"); active = tag.getBoolean("active");
if (tag.contains("exit")) { if (tag.contains("exit")) {
this.exit = NbtHelper.toBlockPos(tag.getCompound("exit")); exit = NbtHelper.toBlockPos(tag.getCompound("exit"));
}
if (tag.contains("key_item")) {
targetWorldId = new Identifier(tag.getString("key_item"));
} }
} }