Created
February 22, 2024 16:33
-
-
Save iam4722202468/2f6cd17062d0194959605674051bf3b9 to your computer and use it in GitHub Desktop.
force view
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import net.minestom.server.MinecraftServer; | |
import net.minestom.server.collision.BoundingBox; | |
import net.minestom.server.collision.CollisionUtils; | |
import net.minestom.server.collision.PhysicsResult; | |
import net.minestom.server.coordinate.Pos; | |
import net.minestom.server.coordinate.Vec; | |
import net.minestom.server.entity.Entity; | |
import net.minestom.server.entity.EntityType; | |
import net.minestom.server.entity.PlayerExtended; | |
import net.minestom.server.event.player.PlayerPacketEvent; | |
import net.minestom.server.network.packet.client.play.ClientPlayerRotationPacket; | |
import net.minestom.server.network.packet.client.play.ClientSteerVehiclePacket; | |
import net.minestom.server.timer.TaskSchedule; | |
import net.worldseed.contexts.ItemContext; | |
import net.worldseed.entities.WorldSeedFakePlayer; | |
import net.worldseed.regions.RegionAction; | |
import net.worldseed.regions.WorldSeedInstance; | |
import java.util.List; | |
import java.util.UUID; | |
import java.util.concurrent.atomic.AtomicBoolean; | |
public class ForcedViewHandler { | |
private final PlayerExtended player; | |
private AtomicBoolean active = new AtomicBoolean(false); | |
private double distance = 5; | |
private Pos pos = null; | |
private Entity viewing = null; | |
private float yaw, pitch; | |
private static final BoundingBox cameraBoundingBox = new BoundingBox(0.5, 0.5, 0.5, new Pos(0, 1.5, 0)); | |
private List<RegionAction> onJump; | |
private List<RegionAction> onSneak; | |
public ForcedViewHandler(PlayerExtended player) { | |
this.player = player; | |
player.eventNode().addListener(PlayerPacketEvent.class, (event) -> { | |
if (active.get()) { | |
if (event.getPacket() instanceof ClientPlayerRotationPacket rotation) { | |
updateView(rotation.yaw(), rotation.pitch()); | |
} | |
if (event.getPacket() instanceof ClientSteerVehiclePacket packet) { | |
var fakePlayer = player.getFakePlayer(); | |
if (fakePlayer != null && player.getInstance() instanceof WorldSeedInstance wsi) { | |
if (fakePlayer.isSneaking() && packet.flags() == 0) { | |
fakePlayer.setSneaking(false); | |
} else if (!fakePlayer.isSneaking() && packet.flags() == 2) { | |
fakePlayer.setSneaking(true); | |
var context = new ItemContext<>(wsi, player, null); | |
if (onSneak != null) player.getExecutor().executeActions(onSneak, context, UUID.randomUUID(), List.of()); | |
} else if (player.isOnGround() && packet.flags() == 1) { | |
var context = new ItemContext<>(wsi, player, null); | |
if (onJump != null) player.getExecutor().executeActions(onJump, context, UUID.randomUUID(), List.of()); | |
} | |
} | |
} | |
} | |
}); | |
} | |
public void setPositionView(Pos p) { | |
this.pos = p; | |
if (!active.get()) { | |
active.set(true); | |
start(); | |
} | |
} | |
public void stopView() { | |
if (viewing != null) { | |
player.teleport(player.getFakePlayer().getPosition().withView(yaw, pitch)).thenRun(() -> { | |
player.stopSpectating(); | |
viewing.removePassenger(player); | |
viewing.remove(); | |
viewing = null; | |
onJump = null; | |
onSneak = null; | |
active.set(false); | |
player.setInvisible(false); | |
}); | |
player.getFakePlayer().remove(); | |
player.setFakePlayer(null); | |
} | |
} | |
private void start() { | |
if (active.get()) stopView(); | |
if (!(player.getInstance() instanceof WorldSeedInstance wsi)) return; | |
this.viewing = new Entity(EntityType.ZOMBIE); | |
viewing.setNoGravity(true); | |
viewing.setHasPhysics(false); | |
viewing.setHasCollision(false); | |
viewing.setInvisible(true); | |
this.yaw = 180-pos.yaw(); | |
this.pitch = pos.pitch(); | |
viewing.setInstance(player.getInstance(), player.getPosition().sub(0, 1.5, 0).withView(-pos.yaw(), pos.pitch())).thenRun(() -> { | |
MinecraftServer.getSchedulerManager().scheduleTask(() -> { | |
player.setInvisible(true); | |
viewing.addPassenger(player); | |
player.spectate(viewing); | |
}, TaskSchedule.tick(4), TaskSchedule.stop()); | |
var fakePlayer = new WorldSeedFakePlayer(player, wsi, player.getPosition(), 4); | |
player.setFakePlayer(fakePlayer); | |
fakePlayer.setHasPhysics(true); | |
fakePlayer.setNoGravity(false); | |
redraw(); | |
}); | |
} | |
private void updateView(float yaw, float pitch) { | |
this.yaw = 180-yaw; | |
this.pitch = pitch; | |
redraw(); | |
} | |
private void redraw() { | |
if (viewing == null) return; | |
if (pos == null) return; | |
double pr = Math.toRadians(yaw); | |
double yr = Math.toRadians(pitch); | |
final double xz = Math.cos(yr); | |
double x = xz * Math.sin(pr) * distance + pos.x(); | |
double y = Math.sin(yr) * distance + pos.y() - 1.5; | |
double z = xz * Math.cos(pr) * distance + pos.z(); | |
Vec desiredPos = new Vec(x, y, z); | |
PhysicsResult result = CollisionUtils.handlePhysics(player.getInstance(), player.getInstance().getChunkAt(pos), cameraBoundingBox, pos, desiredPos.sub(pos), null, true); | |
viewing.setView(180 - yaw, pitch); | |
viewing.teleport(result.newPosition().withView(180 - yaw, pitch)); | |
if (player.getFakePlayer() != null) player.getFakePlayer().setView(180 - yaw, pitch); | |
} | |
public void setSneakHandler(List<RegionAction> actionListSneak) { | |
this.onSneak = actionListSneak; | |
} | |
public void setJumpHandler(List<RegionAction> actionListJump) { | |
this.onJump = actionListJump; | |
} | |
public void setDistanceView(double distance) { | |
this.distance = distance; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment