Skip to content

Commit

Permalink
Holograms
Browse files Browse the repository at this point in the history
  • Loading branch information
ofek2608 committed Jan 2, 2025
1 parent 02f09d7 commit 8ab39cc
Show file tree
Hide file tree
Showing 5 changed files with 304 additions and 65 deletions.
10 changes: 10 additions & 0 deletions src/main/java/com/infinite_parkour/infinite_parkour/IPKUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,14 @@ public static void fill(Level level, BlockState state, int x0, int y0, int z0, i
}
}
}

public static int posToInt(BlockPos pos) {
return pos.getX() | pos.getY() << 6 | pos.getZ() << 12;
}

public static void intToPos(int posInt, BlockPos.MutableBlockPos pos) {
pos.setX(posInt & 0x3F);
pos.setY((posInt >> 6) & 0x3F);
pos.setZ((posInt >> 12) & 0x3F);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import net.minecraft.world.phys.EntityHitResult;
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;
Expand Down Expand Up @@ -116,7 +117,7 @@ protected boolean onBreakBlock(Player player, BlockPos blockPos, BlockState stat
// Internal functions

private void closeCallback() {
level.players().forEach(IPKLevels::teleportLobby);
new ArrayList<>(level.players()).forEach(IPKLevels::teleportLobby);
ENVIRONMENTS.remove(this.level, this);
onClose();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,77 +1,105 @@
package com.infinite_parkour.infinite_parkour.environment.editor;

import com.infinite_parkour.infinite_parkour.IPKUtils;
import com.infinite_parkour.infinite_parkour.data.JumpBlockData;
import com.infinite_parkour.infinite_parkour.data.JumpData;
import net.minecraft.core.BlockPos;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.core.particles.TrailParticleOption;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.Display;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.TrapDoorBlock;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.Nullable;

import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.*;

public class EditorCanvas {
private final ServerPlayer player;
private static final int STARTING_BLOCK_ID = IPKUtils.posToInt(new BlockPos(31, 31, 0));
private final ServerLevel level;
private int breakCooldown = 0;
private final Set<Long> trails = new HashSet<>();
private final Set<Integer> blocks = new HashSet<>();
private BlockPos trailFirstPos = null;
private UUID addStartingBlockText = null;

public EditorCanvas(ServerPlayer player) {
this.player = player;
public EditorCanvas(ServerLevel level) {
this.level = level;

BlockState blockBot = Blocks.BLACK_CONCRETE.defaultBlockState();
BlockState blockTop = Blocks.LIGHT_BLUE_CONCRETE.defaultBlockState();
BlockState blockSid = Blocks.WHITE_CONCRETE.defaultBlockState();
IPKUtils.fill(level, blockSid, -1, 0, 0, -1, 63, 63); // x=-1
IPKUtils.fill(level, blockSid, 64, 0, 0, 64, 63, 63); // x=64
IPKUtils.fill(level, blockBot, 0, -1, 0, 63, -1, 63); // y=-1
IPKUtils.fill(level, blockTop, 0, 64, 0, 63, 64, 63); // y=64
IPKUtils.fill(level, blockSid, 0, 0, -1, 63, 63, -1); // z=-1
IPKUtils.fill(level, blockSid, 0, 0, 64, 63, 63, 64); // z=64
}

public JumpData save(ServerLevel level, JumpData base) {
@Nullable
public JumpData save(JumpData base) {
if (blocks.isEmpty()) {
return null;
}
BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos();
List<JumpBlockData> resultBlocks = blocks.stream().map(posInt -> {
intToPos(posInt, pos);
IPKUtils.intToPos(posInt, pos);
var state = level.getBlockState(pos);
return new JumpBlockData(posInt, state);
}).toList();
List<Long> resultTrails = trails.stream().toList();
return new JumpData(resultBlocks, resultTrails, base.weight());
}

public void clear(ServerLevel level) {
public void clear() {
BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos();
for (int posInt : blocks) {
intToPos(posInt, pos);
IPKUtils.intToPos(posInt, pos);
level.setBlockAndUpdate(pos, Blocks.AIR.defaultBlockState());
}
blocks.clear();
trails.clear();
trailFirstPos = null;
}

public void load(ServerLevel level, JumpData jumpData) {
clear(level);
public void load(@Nullable JumpData jumpData) {
clear();
if (jumpData == null) {
return;
}
BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos();
for (JumpBlockData block : jumpData.blocks()) {
intToPos(block.pos(), pos);
IPKUtils.intToPos(block.pos(), pos);
level.setBlock(pos, block.state(), 2);
blocks.add(block.pos());
}
trails.addAll(jumpData.trails());
}

public final void tick(ServerLevel level) {
breakBlock(level);
public final void tick() {
breakBlock();
updateTrails();
updateBedrock();
}

private void updateTrails() {
if (trailFirstPos != null) {
if (blocks.contains(posToInt(trailFirstPos))) {
if (blocks.contains(IPKUtils.posToInt(trailFirstPos))) {
double x = trailFirstPos.getX() + 0.5;
double y = trailFirstPos.getY() + 1.5;
double z = trailFirstPos.getZ() + 0.5;
Expand Down Expand Up @@ -104,32 +132,53 @@ public final void tick(ServerLevel level) {
}
}

private void breakBlock(ServerLevel level) {
private void breakBlock() {
if (breakCooldown > 0) {
breakCooldown--;
return;
}
if (player.gameMode.isDestroyingBlock) {
BlockPos pos = player.gameMode.destroyPos;
if (isInCanvas(pos)) {
level.setBlockAndUpdate(pos, Blocks.AIR.defaultBlockState());
blocks.remove(posToInt(pos));
breakCooldown = 4;
for (ServerPlayer player : level.players()) {
if (player.gameMode.isDestroyingBlock) {
BlockPos pos = player.gameMode.destroyPos;
if (isInCanvas(pos)) {
level.setBlockAndUpdate(pos, Blocks.AIR.defaultBlockState());
blocks.remove(IPKUtils.posToInt(pos));
breakCooldown = 4;
}
}
}
}

private static int posToInt(BlockPos pos) {
return pos.getX() | pos.getY() << 6 | pos.getZ() << 12;
}
private void updateBedrock() {
boolean hasStartingBlock = blocks.contains(STARTING_BLOCK_ID);

BlockPos pos = new BlockPos(31, 30, 0);
BlockState state = (hasStartingBlock ? Blocks.AIR : Blocks.BEDROCK).defaultBlockState();
if (level.getBlockState(pos) != state) {
level.setBlockAndUpdate(pos, state);
}
if (hasStartingBlock) {
if (addStartingBlockText != null) {
Entity entity = level.getEntity(addStartingBlockText);
if (entity != null) {
entity.remove(Entity.RemovalReason.DISCARDED);
addStartingBlockText = null;
}
}
} else {
if (addStartingBlockText == null) {
Display.TextDisplay entity = new Display.TextDisplay(EntityType.TEXT_DISPLAY, level);
entity.setPos(31.5, 31.5, 0.5);
entity.setBillboardConstraints(Display.BillboardConstraints.CENTER);
entity.setText(Component.literal("Place starting block"));
level.addFreshEntity(entity);
addStartingBlockText = entity.getUUID();
}
}

private void intToPos(int posInt, BlockPos.MutableBlockPos pos) {
pos.setX(posInt & 0x3F);
pos.setY((posInt >> 6) & 0x3F);
pos.setZ((posInt >> 12) & 0x3F);
}

public InteractionResult useBlock(ServerLevel level, InteractionHand interactionHand, BlockHitResult blockHitResult) {
public InteractionResult useBlock(ServerPlayer player, InteractionHand interactionHand, BlockHitResult blockHitResult) {
BlockPos pos = blockHitResult.getBlockPos();
BlockState blockState = level.getBlockState(pos);
Block block = blockState.getBlock();
Expand All @@ -152,8 +201,8 @@ public InteractionResult useBlock(ServerLevel level, InteractionHand interaction
trailFirstPos = pos;
} else {
if (!trailFirstPos.equals(pos)) {
int p0 = posToInt(trailFirstPos);
int p1 = posToInt(pos);
int p0 = IPKUtils.posToInt(trailFirstPos);
int p1 = IPKUtils.posToInt(pos);
long trail = (long)p1 << 18 | p0;
long trailRev = (long)p0 << 18 | p1;
trails.remove(trailRev);
Expand All @@ -170,14 +219,14 @@ public InteractionResult useBlock(ServerLevel level, InteractionHand interaction
if (!isInCanvas(placePos)) {
return InteractionResult.FAIL;
}
blocks.add(posToInt(placePos));
blocks.add(IPKUtils.posToInt(placePos));
return InteractionResult.PASS;
}

private static boolean isInCanvas(BlockPos pos) {
int x = pos.getX();
int y = pos.getY();
int z = pos.getZ();
return 0 <= x && x < 64 && 0 <= y && y < 64 && 0 <= z && z < 64;
return 0 <= x && x < 64 && 0 <= y && y < 64 && 0 <= z && z < 64 && (x != 31 || y != 30 || z != 0);
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
package com.infinite_parkour.infinite_parkour.environment.editor;

import com.infinite_parkour.infinite_parkour.InfiniteParkour;
import com.infinite_parkour.infinite_parkour.environment.SinglePlayerEnvironment;
import com.infinite_parkour.infinite_parkour.IPKUtils;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.BlockHitResult;
Expand All @@ -20,25 +16,15 @@
import java.util.Collections;

public class EditorEnvironment extends SinglePlayerEnvironment {
private static final ResourceLocation STRUCT_HOLOGRAM = InfiniteParkour.loc("editor_hologram_room");
private final EditorItemsManager items;
private final EditorCanvas canvas;
private final EditorHolograms holograms;

public EditorEnvironment(ServerPlayer player) {
super(player);
this.items = new EditorItemsManager(player);
this.canvas = new EditorCanvas(player);

BlockState blockBot = Blocks.BLACK_CONCRETE.defaultBlockState();
BlockState blockTop = Blocks.LIGHT_BLUE_CONCRETE.defaultBlockState();
BlockState blockSid = Blocks.WHITE_CONCRETE.defaultBlockState();
IPKUtils.fill(level, blockSid, -1, 0, 0, -1, 63, 63); // x=-1
IPKUtils.fill(level, blockSid, 64, 0, 0, 64, 63, 63); // x=64
IPKUtils.fill(level, blockBot, 0, -1, 0, 63, -1, 63); // y=-1
IPKUtils.fill(level, blockTop, 0, 64, 0, 63, 64, 63); // y=64
IPKUtils.fill(level, blockSid, 0, 0, -1, 63, 63, -1); // z=-1
IPKUtils.fill(level, blockSid, 0, 0, 64, 63, 63, 64); // z=64
IPKUtils.placeStructure(level, new BlockPos(16, 31, -33), STRUCT_HOLOGRAM);
this.canvas = new EditorCanvas(level);
this.holograms = new EditorHolograms(level, canvas);
respawn();
}

Expand All @@ -50,7 +36,8 @@ public void onTick() {
}

giveAbilities();
canvas.tick(level);
canvas.tick();
holograms.tick();

if (player.getY() <= 0.01 && player.onGround()) {
respawn();
Expand All @@ -64,8 +51,13 @@ public InteractionResult onUseItem(Player player, InteractionHand interactionHan
}

@Override
public InteractionResult onUseBlock(Player player, InteractionHand interactionHand, BlockHitResult blockHitResult) {
return canvas.useBlock(level, interactionHand, blockHitResult);
public InteractionResult onUseBlock(Player player, InteractionHand hand, BlockHitResult blockHitResult) {
if (hand == InteractionHand.MAIN_HAND) {
if (holograms.onUseBlock(player, blockHitResult.getBlockPos())) {
return InteractionResult.SUCCESS;
}
}
return canvas.useBlock((ServerPlayer)player, hand, blockHitResult);
}

@Override
Expand Down
Loading

0 comments on commit 8ab39cc

Please sign in to comment.