Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Start work on the new custom world border #3

Draft
wants to merge 7 commits into
base: main
Choose a base branch
from
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package net.casual.arcade.mixin.events;

import com.llamalad7.mixinextras.injector.WrapWithCondition;
import com.mojang.authlib.GameProfile;
import net.casual.arcade.events.GlobalEventHandler;
import net.casual.arcade.events.core.CancellableEvent;
Expand All @@ -8,12 +9,15 @@
import net.casual.arcade.events.network.PlayerDisconnectEvent;
import net.casual.arcade.events.player.PlayerClientboundPacketEvent;
import net.casual.arcade.resources.PackStatus;
import net.minecraft.network.Connection;
import net.minecraft.network.PacketSendListener;
import net.minecraft.network.chat.Component;
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.common.ServerboundResourcePackPacket;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.network.ServerCommonPacketListenerImpl;
import net.minecraft.server.network.ServerGamePacketListenerImpl;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
Expand All @@ -22,6 +26,8 @@
import org.spongepowered.asm.mixin.injection.ModifyVariable;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

import java.util.List;

@Mixin(ServerCommonPacketListenerImpl.class)
public abstract class ServerCommonPacketListenerImplMixin {
@Shadow @Final protected MinecraftServer server;
Expand All @@ -42,25 +48,28 @@ private void onResourcePackResponse(ServerboundResourcePackPacket packet, Callba
GlobalEventHandler.broadcast(event);
}

@ModifyVariable(
@WrapWithCondition(
method = "send(Lnet/minecraft/network/protocol/Packet;Lnet/minecraft/network/PacketSendListener;)V",
at = @At("HEAD"),
argsOnly = true
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/network/Connection;send(Lnet/minecraft/network/protocol/Packet;Lnet/minecraft/network/PacketSendListener;Z)V"
)
)
private Packet<?> onSendPacket(Packet<?> value) {
private boolean onSendPacket(Connection instance, Packet<?> packet, @Nullable PacketSendListener listener, boolean flush) {
ServerCommonPacketListenerImpl self = (ServerCommonPacketListenerImpl) (Object) this;
CancellableEvent.Typed<Packet<?>> event = new ClientboundPacketEvent(this.server, this.playerProfile(), value);
CancellableEvent.Default event = new ClientboundPacketEvent(this.server, this.playerProfile(), packet);
GlobalEventHandler.broadcast(event);

if (self instanceof ServerGamePacketListenerImpl connection) {
CancellableEvent.Typed<Packet<?>> old = event;
event = new PlayerClientboundPacketEvent(connection.player, value);
CancellableEvent.Default old = event;
event = new PlayerClientboundPacketEvent(connection.player, packet);
if (old.isCancelled()) {
event.cancel(old.result());
event.cancel();
}
GlobalEventHandler.broadcast(event);
}
return event.isCancelled() ? event.result() : value;

return !event.isCancelled();
}

@Inject(
Expand Down
27 changes: 27 additions & 0 deletions src/main/kotlin/net/casual/arcade/Arcade.kt
Original file line number Diff line number Diff line change
@@ -1,13 +1,25 @@
package net.casual.arcade

import net.casual.arcade.border.custom.PlayerWorldBorderExtension
import net.casual.arcade.commands.ArcadeCommands
import net.casual.arcade.events.GlobalEventHandler
import net.casual.arcade.events.level.LevelCreatedEvent
import net.casual.arcade.events.network.ClientboundPacketEvent
import net.casual.arcade.events.player.PlayerClientboundPacketEvent
import net.casual.arcade.events.player.PlayerCreatedEvent
import net.casual.arcade.events.server.ServerCreatedEvent
import net.casual.arcade.minigame.Minigames
import net.casual.arcade.utils.*
import net.casual.arcade.utils.LevelUtils.addExtension
import net.casual.arcade.utils.PlayerUtils.addExtension
import net.fabricmc.api.ModInitializer
import net.fabricmc.loader.api.FabricLoader
import net.fabricmc.loader.api.ModContainer
import net.minecraft.network.protocol.game.ClientboundInitializeBorderPacket
import net.minecraft.network.protocol.game.ClientboundSetBorderCenterPacket
import net.minecraft.network.protocol.game.ClientboundSetBorderLerpSizePacket
import net.minecraft.network.protocol.game.ClientboundSetBorderSizePacket
import net.minecraft.network.protocol.game.ClientboundSetBorderWarningDistancePacket
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.MinecraftServer
import org.apache.logging.log4j.LogManager
Expand Down Expand Up @@ -97,5 +109,20 @@ public object Arcade: ModInitializer {
LevelUtils.registerEvents()

ArcadeCommands.registerCommands()

//TODO: Move this | TODO Make this work with respawning.
GlobalEventHandler.register<PlayerCreatedEvent> { (player) ->
player.addExtension(PlayerWorldBorderExtension(player.connection))
}
GlobalEventHandler.register<PlayerClientboundPacketEvent> {
if (
it.packet is ClientboundInitializeBorderPacket ||
it.packet is ClientboundSetBorderSizePacket ||
it.packet is ClientboundSetBorderCenterPacket ||
it.packet is ClientboundSetBorderLerpSizePacket
) {
it.cancel()
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package net.casual.arcade.border.custom

import net.casual.arcade.border.state.CenterBorderState
import net.casual.arcade.border.state.CenterBorderStatus
import net.minecraft.world.level.border.BorderStatus
import net.minecraft.world.phys.Vec3

public interface CustomBorderState {




public fun getCenter(): Vec3

public fun getTargetCenter(): Vec3



public fun getLerpRemainingTicks(): Long {
TODO("Add this later!")
}


public fun update(): CustomBorderState

public fun getStatus(): CenterBorderStatus

public fun getType(): BorderStatus



}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package net.casual.arcade.border.custom



public enum class CustomBorderStatus(color: Int) {

GROWING(4259712),
SHRINKING(16724016),
STATIONARY(2138367),
//Moving should only be selected if it would otherwise be stationary. TODO: TBD, remove this?
MOVING(5);


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package net.casual.arcade.border.custom

import eu.pb4.polymer.virtualentity.api.ElementHolder
import eu.pb4.polymer.virtualentity.api.attachment.EntityAttachment
import eu.pb4.polymer.virtualentity.api.elements.BlockDisplayElement
import net.casual.arcade.extensions.PlayerExtension
import net.casual.arcade.scheduler.GlobalTickedScheduler
import net.minecraft.core.Direction.*
import net.minecraft.server.level.ServerPlayer
import net.minecraft.server.network.ServerGamePacketListenerImpl
import net.minecraft.world.level.block.Blocks
import net.minecraft.world.level.border.BorderStatus
import net.minecraft.world.level.border.WorldBorder
import org.joml.Vector3f

public class PlayerWorldBorderExtension(owner: ServerGamePacketListenerImpl): PlayerExtension(owner) {
private val holder = ElementHolder()

private val north = BlockDisplayElement()
private val south = BlockDisplayElement()
private val east = BlockDisplayElement()
private val west = BlockDisplayElement()

// TODO: Currently using the vanilla WB
// - This actually may not be an issue?
// As long as we are blocking the world border packets, we can use the
// vanilla border for the actual calculations and such, just change rendering.

//TODO: Either don't block border warning packets, or handle them ourselves.
private val border: WorldBorder
get() = this.player.level().worldBorder

init {
holder.addElement(north)
holder.addElement(south)
holder.addElement(east)
holder.addElement(west)

this.updateState()
this.updateScale()
this.updateTranslation()

GlobalTickedScheduler.later {
BorderAttachment()
}
}

private fun updateState() {
val state = when (this.border.status) {
BorderStatus.SHRINKING -> Blocks.RED_STAINED_GLASS
BorderStatus.GROWING -> Blocks.LIME_STAINED_GLASS
else -> Blocks.LIGHT_BLUE_STAINED_GLASS
}.defaultBlockState()

this.north.blockState = state
this.south.blockState = state
this.east.blockState = state
this.west.blockState = state
}

private fun updateScale() {
val diameter = this.border.size.toFloat()

// TODO: We probably only want to scale to what the
// player can actually see...
// We don't want to send the north border if it's thousands of blocks away...
this.north.scale = Vector3f(diameter, 300F, 0F)
this.south.scale = Vector3f(diameter, 300F, 0F)
this.east.scale = Vector3f(0F, 300F, diameter)
this.west.scale = Vector3f(0F, 300F, diameter)
}

private fun updateTranslation() {

val radius = this.border.size.toFloat() / 2.0F
val north = NORTH.step().mul(radius)
val west = WEST.step().mul(radius)
val playerPos = this.player.position().toVector3f()
val borderPos = Vector3f(this.border.centerX.toFloat(), 0F, this.border.centerZ.toFloat())


this.north.translation = north.add(west, Vector3f()).sub(playerPos).add(borderPos)
this.south.translation = north.negate(Vector3f()).add(west).sub(playerPos).add(borderPos)
this.east.translation = west.negate(Vector3f()).add(north).sub(playerPos).add(borderPos)
this.west.translation = west.add(north).sub(playerPos).add(borderPos)
}

private fun setupInterpolation() {
val lerpTime = this.border.lerpRemainingTime.toInt()
this.north.interpolationDuration = lerpTime
this.south.interpolationDuration = lerpTime
this.east.interpolationDuration = lerpTime
this.west.interpolationDuration = lerpTime

this.north.startInterpolation()
this.south.startInterpolation()
this.east.startInterpolation()
this.west.startInterpolation()

}

private fun isDirty(): Boolean {
return this.north.scale.x() != this.border.size.toFloat()
}

private inner class BorderAttachment: EntityAttachment(this.holder, this.player, true) {
init {
super.startWatching(player)
}

override fun startWatching(handler: ServerPlayer) {
// Do nothing...
}

override fun startWatching(handler: ServerGamePacketListenerImpl) {
// Do nothing...
}

override fun updateCurrentlyTracking(currentlyTracking: MutableCollection<ServerGamePacketListenerImpl>?) {
// Do nothing...
}

override fun tick() {
// TODO: Interpolate

updateState()
updateScale()
updateTranslation()



holder.tick()
}
}
}
2 changes: 2 additions & 0 deletions src/main/kotlin/net/casual/arcade/border/state/BorderState.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ public interface BorderState {

public fun getMaxZ(): Double


//Diameter
public fun getSize(): Double

public fun getLerpSpeed(): Double
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ public data class ClientboundPacketEvent(
val server: MinecraftServer,
val owner: GameProfile,
val packet: Packet<*>
): CancellableEvent.Typed<Packet<*>>(), ServerOffThreadEvent
): CancellableEvent.Default(), ServerOffThreadEvent
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ import net.minecraft.server.level.ServerPlayer
public data class PlayerClientboundPacketEvent(
override val player: ServerPlayer,
val packet: Packet<*>
): CancellableEvent.Typed<Packet<*>>(), PlayerEvent
): CancellableEvent.Default(), PlayerEvent
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ internal class PlayerNameTagExtension(
}

// Okay, so I think I should write some implementation comments just
// encase, because this might look confusing.
// in case, because this might look confusing.
// So a vanilla name tag is rendered twice - once for the 'background'
// nametag (the see-through rectangle and text), and once for the
// 'foreground' which is the non-see-through text, it has no rectangle.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,8 @@ MinigameEffectsManager(

val updated = this.updatePacket(player, packet)
if (updated !== packet) {
event.cancel(updated)
event.cancel()
event.player.connection.send(updated)
}
}

Expand Down
Loading