mirror of
https://github.com/GeyserMC/Geyser.git
synced 2024-08-14 23:57:35 +00:00
Add world border translation (#1839)
As Bedrock does not have world border support, this PR translates what the Java server sends us for a world border into particles and fog, while also preventing the Bedrock client from moving outside of the world border. Co-authored-by: Luke <32024335+lukeeey@users.noreply.github.com> Co-authored-by: ofunny <play@ofunny.world>
This commit is contained in:
parent
8461cf76b7
commit
f22d286ea1
14 changed files with 661 additions and 15 deletions
|
@ -81,6 +81,13 @@ public class BoatEntity extends Entity {
|
|||
session.sendUpstreamPacket(moveEntityPacket);
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the boat without making the adjustments needed to translate from Java
|
||||
*/
|
||||
public void moveAbsoluteWithoutAdjustments(GeyserSession session, Vector3f position, Vector3f rotation, boolean isOnGround, boolean teleported) {
|
||||
super.moveAbsolute(session, position, Vector3f.from(rotation.getX(), 0, rotation.getX()), isOnGround, teleported);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveRelative(GeyserSession session, double relX, double relY, double relZ, Vector3f rotation, boolean isOnGround) {
|
||||
super.moveRelative(session, relX, relY, relZ, Vector3f.from(rotation.getX(), 0, rotation.getX()), isOnGround);
|
||||
|
|
|
@ -88,7 +88,9 @@ public class ConnectorServerEventHandler implements BedrockServerEventHandler {
|
|||
|
||||
@Override
|
||||
public BedrockPong onQuery(InetSocketAddress inetSocketAddress) {
|
||||
connector.getLogger().debug(LanguageUtils.getLocaleStringLog("geyser.network.pinged", inetSocketAddress));
|
||||
if (connector.getConfig().isDebugMode()) {
|
||||
connector.getLogger().debug(LanguageUtils.getLocaleStringLog("geyser.network.pinged", inetSocketAddress));
|
||||
}
|
||||
|
||||
GeyserConfiguration config = connector.getConfig();
|
||||
|
||||
|
|
|
@ -154,6 +154,12 @@ public class GeyserSession implements CommandSender {
|
|||
|
||||
private final Int2ObjectMap<TeleportCache> teleportMap = new Int2ObjectOpenHashMap<>();
|
||||
|
||||
private final WorldBorder worldBorder;
|
||||
/**
|
||||
* Whether simulated fog has been sent to the client or not.
|
||||
*/
|
||||
private boolean isInWorldBorderWarningArea = false;
|
||||
|
||||
private final PlayerInventory playerInventory;
|
||||
@Setter
|
||||
private Inventory openInventory;
|
||||
|
@ -452,6 +458,8 @@ public class GeyserSession implements CommandSender {
|
|||
this.tagCache = new TagCache();
|
||||
this.worldCache = new WorldCache(this);
|
||||
|
||||
this.worldBorder = new WorldBorder(this);
|
||||
|
||||
this.collisionManager = new CollisionManager(this);
|
||||
|
||||
this.playerEntity = new SessionPlayerEntity(this);
|
||||
|
@ -928,6 +936,25 @@ public class GeyserSession implements CommandSender {
|
|||
lastMovementTimestamp = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
if (worldBorder.isResizing()) {
|
||||
worldBorder.resize();
|
||||
}
|
||||
|
||||
if (!worldBorder.isWithinWarningBoundaries()) {
|
||||
// Show particles representing where the world border is
|
||||
worldBorder.drawWall();
|
||||
// Set the mood
|
||||
if (!isInWorldBorderWarningArea) {
|
||||
isInWorldBorderWarningArea = true;
|
||||
WorldBorder.sendFog(this, "minecraft:fog_crimson_forest");
|
||||
}
|
||||
} else if (isInWorldBorderWarningArea) {
|
||||
// Clear fog as we are outside the world border now
|
||||
WorldBorder.removeFog(this);
|
||||
isInWorldBorderWarningArea = false;
|
||||
}
|
||||
|
||||
|
||||
for (Tickable entity : entityCache.getTickableEntities()) {
|
||||
entity.tick(this);
|
||||
}
|
||||
|
|
291
connector/src/main/java/org/geysermc/connector/network/session/cache/WorldBorder.java
vendored
Normal file
291
connector/src/main/java/org/geysermc/connector/network/session/cache/WorldBorder.java
vendored
Normal file
|
@ -0,0 +1,291 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.network.session.cache;
|
||||
|
||||
import com.nukkitx.math.GenericMath;
|
||||
import com.nukkitx.math.vector.Vector2f;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.LevelEventType;
|
||||
import com.nukkitx.protocol.bedrock.packet.LevelEventPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.PlayerFogPacket;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.geysermc.connector.entity.player.PlayerEntity;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.Collections;
|
||||
|
||||
public class WorldBorder {
|
||||
private static final double DEFAULT_WORLD_BORDER_SIZE = 5.9999968E7D;
|
||||
|
||||
@Getter @Setter
|
||||
private @Nonnull Vector2f center = Vector2f.ZERO;
|
||||
/**
|
||||
* The diameter in blocks of the world border before it got changed or similar to newDiameter if not changed.
|
||||
*/
|
||||
@Getter @Setter
|
||||
private double oldDiameter = DEFAULT_WORLD_BORDER_SIZE;
|
||||
/**
|
||||
* The diameter in blocks of the new world border.
|
||||
*/
|
||||
@Getter @Setter
|
||||
private double newDiameter = DEFAULT_WORLD_BORDER_SIZE;
|
||||
/**
|
||||
* The speed to apply an expansion/shrinking of the world border.
|
||||
* When a client joins they get the actual border oldDiameter and the time left to reach the newDiameter.
|
||||
*/
|
||||
@Getter @Setter
|
||||
private long speed = 0;
|
||||
/**
|
||||
* The time in seconds before a shrinking world border would hit a not moving player.
|
||||
* Creates the same visual warning effect as warningBlocks.
|
||||
*/
|
||||
@Getter @Setter
|
||||
private int warningDelay = 15;
|
||||
/**
|
||||
* Block length before you reach the border to show warning particles.
|
||||
*/
|
||||
@Getter @Setter
|
||||
private int warningBlocks = 5;
|
||||
|
||||
@Getter
|
||||
private boolean resizing;
|
||||
private double currentDiameter;
|
||||
|
||||
/*
|
||||
* Boundaries of the actual world border.
|
||||
* (The will get updated on expanding or shrinking)
|
||||
*/
|
||||
private double minX = 0.0D;
|
||||
private double minZ = 0.0D;
|
||||
private double maxX = 0.0D;
|
||||
private double maxZ = 0.0D;
|
||||
|
||||
/*
|
||||
* The boundaries for the for the warning visuals.
|
||||
*/
|
||||
private double warningMaxX = 0.0D;
|
||||
private double warningMaxZ = 0.0D;
|
||||
private double warningMinX = 0.0D;
|
||||
private double warningMinZ = 0.0D;
|
||||
|
||||
/**
|
||||
* To track when to send wall particle packets.
|
||||
*/
|
||||
private int currentWallTick;
|
||||
|
||||
/**
|
||||
* If the world border is resizing, this variable saves how many ticks have progressed in the resizing
|
||||
*/
|
||||
private long lastUpdatedWorldBorderTime = 0;
|
||||
|
||||
private final GeyserSession session;
|
||||
|
||||
public WorldBorder(GeyserSession session) {
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true as long the entity is within the world limits.
|
||||
*/
|
||||
public boolean isInsideBorderBoundaries() {
|
||||
Vector3f entityPosition = session.getPlayerEntity().getPosition();
|
||||
return entityPosition.getX() > minX && entityPosition.getX() < maxX && entityPosition.getZ() > minZ && entityPosition.getZ() < maxZ;
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirms that the entity is within world border boundaries when they move.
|
||||
* Otherwise, if {@code adjustPosition} is true, this function will push the player back.
|
||||
*
|
||||
* @return if this player was indeed against the world border. Will return false if no world border was defined for us.
|
||||
*/
|
||||
public boolean isPassingIntoBorderBoundaries(Vector3f newPosition, boolean adjustPosition) {
|
||||
boolean isInWorldBorder = isPassingIntoBorderBoundaries(newPosition);
|
||||
if (isInWorldBorder && adjustPosition) {
|
||||
PlayerEntity playerEntity = session.getPlayerEntity();
|
||||
// Move the player back, but allow gravity to take place
|
||||
// Teleported = true makes going back better, but disconnects the player from their mounted entity
|
||||
playerEntity.moveAbsolute(session,
|
||||
Vector3f.from(playerEntity.getPosition().getX(), (newPosition.getY() - EntityType.PLAYER.getOffset()), playerEntity.getPosition().getZ()),
|
||||
playerEntity.getRotation(), playerEntity.isOnGround(), session.getRidingVehicleEntity() == null);
|
||||
}
|
||||
return isInWorldBorder;
|
||||
}
|
||||
|
||||
public boolean isPassingIntoBorderBoundaries(Vector3f newEntityPosition) {
|
||||
int entityX = GenericMath.floor(newEntityPosition.getX());
|
||||
int entityZ = GenericMath.floor(newEntityPosition.getZ());
|
||||
Vector3f currentEntityPosition = session.getPlayerEntity().getPosition();
|
||||
// Make sure we can't move out of the world border, but if we're out of the world border, we can move in
|
||||
return (entityX == (int) minX && currentEntityPosition.getX() > newEntityPosition.getX()) ||
|
||||
(entityX == (int) maxX && currentEntityPosition.getX() < newEntityPosition.getX()) ||
|
||||
(entityZ == (int) minZ && currentEntityPosition.getZ() > newEntityPosition.getZ()) ||
|
||||
(entityZ == (int) maxZ && currentEntityPosition.getZ() < newEntityPosition.getZ());
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as {@link #isInsideBorderBoundaries()} but using the warning boundaries.
|
||||
*
|
||||
* @return true as long the entity is within the world limits and not in the warning zone at the edge to the border.
|
||||
*/
|
||||
public boolean isWithinWarningBoundaries() {
|
||||
Vector3f entityPosition = session.getPlayerEntity().getPosition();
|
||||
return entityPosition.getX() > warningMinX && entityPosition.getX() < warningMaxX && entityPosition.getZ() > warningMinZ && entityPosition.getZ() < warningMaxZ;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the world border's minimum and maximum properties
|
||||
*/
|
||||
public void update() {
|
||||
/*
|
||||
* Setting the correct boundary of our world border's square.
|
||||
*/
|
||||
double radius;
|
||||
if (resizing) {
|
||||
radius = this.currentDiameter / 2.0D;
|
||||
} else {
|
||||
radius = this.newDiameter / 2.0D;
|
||||
}
|
||||
this.minX = center.getX() - radius;
|
||||
this.minZ = center.getY() - radius; // Mapping 2D vector to 3D coordinates >> Y becomes Z
|
||||
this.maxX = center.getX() + radius;
|
||||
this.maxZ = center.getY() + radius; // Mapping 2D vector to 3D coordinates >> Y becomes Z
|
||||
|
||||
/*
|
||||
* Caching the warning boundaries.
|
||||
*/
|
||||
this.warningMinX = this.minX + this.warningBlocks;
|
||||
this.warningMinZ = this.minZ + this.warningBlocks;
|
||||
this.warningMaxX = this.maxX - this.warningBlocks;
|
||||
this.warningMaxZ = this.maxZ - this.warningBlocks;
|
||||
}
|
||||
|
||||
public void resize() {
|
||||
if (this.lastUpdatedWorldBorderTime >= this.speed) {
|
||||
// Diameter has now updated to the new diameter
|
||||
this.resizing = false;
|
||||
this.lastUpdatedWorldBorderTime = 0;
|
||||
} else if (resizing) {
|
||||
this.currentDiameter = this.oldDiameter + ((double) this.lastUpdatedWorldBorderTime / (double) this.speed) * (this.newDiameter - this.oldDiameter);
|
||||
this.lastUpdatedWorldBorderTime += 50;
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
public void setResizing(boolean resizing) {
|
||||
this.resizing = resizing;
|
||||
if (!resizing) {
|
||||
this.lastUpdatedWorldBorderTime = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private static final LevelEventType WORLD_BORDER_PARTICLE = LevelEventType.PARTICLE_DENY_BLOCK;
|
||||
|
||||
/**
|
||||
* Draws a wall of particles where the world border resides
|
||||
*/
|
||||
public void drawWall() {
|
||||
if (currentWallTick++ != 20) {
|
||||
// Only draw a wall once every second
|
||||
return;
|
||||
}
|
||||
currentWallTick = 0;
|
||||
Vector3f entityPosition = session.getPlayerEntity().getPosition();
|
||||
float particlePosX = entityPosition.getX();
|
||||
float particlePosY = entityPosition.getY();
|
||||
float particlePosZ = entityPosition.getZ();
|
||||
|
||||
if (entityPosition.getX() > warningMaxX) {
|
||||
drawWall(Vector3f.from(maxX, particlePosY, particlePosZ), true);
|
||||
}
|
||||
if (entityPosition.getX() < warningMinX) {
|
||||
drawWall(Vector3f.from(minX, particlePosY, particlePosZ), true);
|
||||
}
|
||||
if (entityPosition.getZ() > warningMaxZ) {
|
||||
drawWall(Vector3f.from(particlePosX, particlePosY, maxZ), false);
|
||||
}
|
||||
if (entityPosition.getZ() < warningMinZ) {
|
||||
drawWall(Vector3f.from(particlePosX, particlePosY, minZ), false);
|
||||
}
|
||||
}
|
||||
|
||||
private void drawWall(Vector3f position, boolean drawWallX) {
|
||||
int initialY = (int) (position.getY() - EntityType.PLAYER.getOffset() - 1);
|
||||
for (int y = initialY; y < (initialY + 5); y++) {
|
||||
if (drawWallX) {
|
||||
float x = position.getX();
|
||||
for (int z = (int) position.getZ() - 3; z < ((int) position.getZ() + 3); z++) {
|
||||
if (z < minZ) {
|
||||
continue;
|
||||
}
|
||||
if (z > maxZ) {
|
||||
break;
|
||||
}
|
||||
|
||||
sendWorldBorderParticle(x, y, z);
|
||||
}
|
||||
} else {
|
||||
float z = position.getZ();
|
||||
for (int x = (int) position.getX() - 3; x < ((int) position.getX() + 3); x++) {
|
||||
if (x < minX) {
|
||||
continue;
|
||||
}
|
||||
if (x > maxX) {
|
||||
break;
|
||||
}
|
||||
|
||||
sendWorldBorderParticle(x, y, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void sendWorldBorderParticle(float x, float y, float z) {
|
||||
LevelEventPacket effectPacket = new LevelEventPacket();
|
||||
effectPacket.setPosition(Vector3f.from(x, y, z));
|
||||
effectPacket.setType(WORLD_BORDER_PARTICLE);
|
||||
session.getUpstream().sendPacket(effectPacket);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the following fog IDs to the client
|
||||
*/
|
||||
public static void sendFog(GeyserSession session, String... fogNameSpaces) {
|
||||
PlayerFogPacket packet = new PlayerFogPacket();
|
||||
Collections.addAll(packet.getFogStack(), fogNameSpaces);
|
||||
session.sendUpstreamPacket(packet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear any additional fog sent to the client
|
||||
*/
|
||||
public static void removeFog(GeyserSession session) {
|
||||
session.sendUpstreamPacket(new PlayerFogPacket());
|
||||
}
|
||||
|
||||
}
|
|
@ -144,6 +144,12 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
|||
"Not in range" doesn't refer to how far a vanilla client goes (that's a whole other mess),
|
||||
but how much a server will accept from the client maximum
|
||||
*/
|
||||
// Blocks cannot be placed or destroyed outside of the world border
|
||||
if (!session.getWorldBorder().isInsideBorderBoundaries()) {
|
||||
restoreCorrectBlock(session, blockPos, packet);
|
||||
return;
|
||||
}
|
||||
|
||||
// CraftBukkit+ check - see https://github.com/PaperMC/Paper/blob/458db6206daae76327a64f4e2a17b67a7e38b426/Spigot-Server-Patches/0532-Move-range-check-for-block-placing-up.patch
|
||||
Vector3f playerPosition = session.getPlayerEntity().getPosition();
|
||||
|
||||
|
@ -289,6 +295,11 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
|||
session.setLastBlockPlacePosition(null);
|
||||
|
||||
// Same deal with vanilla block placing as above.
|
||||
if (!session.getWorldBorder().isInsideBorderBoundaries()) {
|
||||
restoreCorrectBlock(session, packet.getBlockPosition(), packet);
|
||||
return;
|
||||
}
|
||||
|
||||
// This is working out the distance using 3d Pythagoras and the extra value added to the Y is the sneaking height of a java player.
|
||||
playerPosition = session.getPlayerEntity().getPosition();
|
||||
Vector3f floatBlockPosition = packet.getBlockPosition().toFloat();
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
package org.geysermc.connector.network.translators.bedrock;
|
||||
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.world.ClientVehicleMovePacket;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.packet.MoveEntityAbsolutePacket;
|
||||
import org.geysermc.connector.entity.BoatEntity;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
|
@ -43,6 +44,23 @@ public class BedrockMoveEntityAbsoluteTranslator extends PacketTranslator<MoveEn
|
|||
public void translate(GeyserSession session, MoveEntityAbsolutePacket packet) {
|
||||
session.setLastVehicleMoveTimestamp(System.currentTimeMillis());
|
||||
|
||||
if (session.getRidingVehicleEntity() != null && session.getWorldBorder().isPassingIntoBorderBoundaries(packet.getPosition(), false)) {
|
||||
Vector3f position = Vector3f.from(session.getRidingVehicleEntity().getPosition().getX(), packet.getPosition().getY(),
|
||||
session.getRidingVehicleEntity().getPosition().getZ());
|
||||
if (session.getRidingVehicleEntity() instanceof BoatEntity) {
|
||||
// Undo the changes usually applied to the boat
|
||||
session.getRidingVehicleEntity().as(BoatEntity.class).moveAbsoluteWithoutAdjustments(session,
|
||||
position, session.getRidingVehicleEntity().getRotation(),
|
||||
session.getRidingVehicleEntity().isOnGround(), true);
|
||||
} else {
|
||||
// This doesn't work if teleported is false
|
||||
session.getRidingVehicleEntity().moveAbsolute(session, position,
|
||||
session.getRidingVehicleEntity().getRotation(),
|
||||
session.getRidingVehicleEntity().isOnGround(), true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
float y = packet.getPosition().getY();
|
||||
if (session.getRidingVehicleEntity() instanceof BoatEntity) {
|
||||
// Remove the offset to prevents boats from looking like they're floating in water
|
||||
|
|
|
@ -92,6 +92,10 @@ public class BedrockMovePlayerTranslator extends PacketTranslator<MovePlayerPack
|
|||
|
||||
session.sendDownstreamPacket(playerRotationPacket);
|
||||
} else {
|
||||
if (session.getWorldBorder().isPassingIntoBorderBoundaries(packet.getPosition(), true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isValidMove(session, packet.getMode(), entity.getPosition(), packet.getPosition())) {
|
||||
Vector3d position = session.getCollisionManager().adjustBedrockPosition(packet.getPosition(), packet.isOnGround());
|
||||
if (position != null) { // A null return value cancels the packet
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.network.translators.java.world.border;
|
||||
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.world.border.ServerInitializeBorderPacket;
|
||||
import com.nukkitx.math.vector.Vector2f;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.session.cache.WorldBorder;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.network.translators.Translator;
|
||||
|
||||
@Translator(packet = ServerInitializeBorderPacket.class)
|
||||
public class JavaInitializeBorderTranslator extends PacketTranslator<ServerInitializeBorderPacket> {
|
||||
|
||||
@Override
|
||||
public void translate(GeyserSession session, ServerInitializeBorderPacket packet) {
|
||||
WorldBorder worldBorder = session.getWorldBorder();
|
||||
worldBorder.setCenter(Vector2f.from(packet.getNewCenterX(), packet.getNewCenterZ()));
|
||||
worldBorder.setOldDiameter(packet.getOldSize());
|
||||
worldBorder.setNewDiameter(packet.getNewSize());
|
||||
worldBorder.setSpeed(packet.getLerpTime());
|
||||
worldBorder.setWarningDelay(packet.getWarningTime());
|
||||
worldBorder.setWarningBlocks(packet.getWarningBlocks());
|
||||
worldBorder.setResizing(packet.getLerpTime() > 0);
|
||||
|
||||
worldBorder.update();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.network.translators.java.world.border;
|
||||
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.world.border.ServerSetBorderCenterPacket;
|
||||
import com.nukkitx.math.vector.Vector2f;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.session.cache.WorldBorder;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.network.translators.Translator;
|
||||
|
||||
@Translator(packet = ServerSetBorderCenterPacket.class)
|
||||
public class JavaSetBorderCenterPacket extends PacketTranslator<ServerSetBorderCenterPacket> {
|
||||
|
||||
@Override
|
||||
public void translate(GeyserSession session, ServerSetBorderCenterPacket packet) {
|
||||
WorldBorder worldBorder = session.getWorldBorder();
|
||||
worldBorder.setCenter(Vector2f.from(packet.getNewCenterX(), packet.getNewCenterZ()));
|
||||
|
||||
worldBorder.update();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.network.translators.java.world.border;
|
||||
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.world.border.ServerSetBorderLerpSizePacket;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.session.cache.WorldBorder;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.network.translators.Translator;
|
||||
|
||||
@Translator(packet = ServerSetBorderLerpSizePacket.class)
|
||||
public class JavaSetBorderLerpSizeTranslator extends PacketTranslator<ServerSetBorderLerpSizePacket> {
|
||||
|
||||
@Override
|
||||
public void translate(GeyserSession session, ServerSetBorderLerpSizePacket packet) {
|
||||
WorldBorder worldBorder = session.getWorldBorder();
|
||||
worldBorder.setOldDiameter(packet.getOldSize());
|
||||
worldBorder.setNewDiameter(packet.getNewSize());
|
||||
worldBorder.setSpeed(packet.getLerpTime());
|
||||
worldBorder.setResizing(true);
|
||||
|
||||
worldBorder.update();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.network.translators.java.world.border;
|
||||
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.world.border.ServerSetBorderSizePacket;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.session.cache.WorldBorder;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.network.translators.Translator;
|
||||
|
||||
@Translator(packet = ServerSetBorderSizePacket.class)
|
||||
public class JavaSetBorderSizeTranslator extends PacketTranslator<ServerSetBorderSizePacket> {
|
||||
|
||||
@Override
|
||||
public void translate(GeyserSession session, ServerSetBorderSizePacket packet) {
|
||||
WorldBorder worldBorder = session.getWorldBorder();
|
||||
worldBorder.setOldDiameter(packet.getSize());
|
||||
worldBorder.setNewDiameter(packet.getSize());
|
||||
worldBorder.setResizing(false);
|
||||
|
||||
worldBorder.update();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.network.translators.java.world.border;
|
||||
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.world.border.ServerSetBorderWarningDelayPacket;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.session.cache.WorldBorder;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.network.translators.Translator;
|
||||
|
||||
@Translator(packet = ServerSetBorderWarningDelayPacket.class)
|
||||
public class JavaSetBorderWarningDelayTranslator extends PacketTranslator<ServerSetBorderWarningDelayPacket> {
|
||||
|
||||
@Override
|
||||
public void translate(GeyserSession session, ServerSetBorderWarningDelayPacket packet) {
|
||||
WorldBorder worldBorder = session.getWorldBorder();
|
||||
worldBorder.setWarningDelay(packet.getWarningDelay());
|
||||
|
||||
worldBorder.update();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.network.translators.java.world.border;
|
||||
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.world.border.ServerSetBorderWarningDistancePacket;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.session.cache.WorldBorder;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.network.translators.Translator;
|
||||
|
||||
@Translator(packet = ServerSetBorderWarningDistancePacket.class)
|
||||
public class JavaSetBorderWarningDistanceTranslator extends PacketTranslator<ServerSetBorderWarningDistancePacket> {
|
||||
|
||||
@Override
|
||||
public void translate(GeyserSession session, ServerSetBorderWarningDistancePacket packet) {
|
||||
WorldBorder worldBorder = session.getWorldBorder();
|
||||
worldBorder.setWarningBlocks(packet.getWarningBlocks());
|
||||
|
||||
worldBorder.update();
|
||||
}
|
||||
}
|
|
@ -117,20 +117,26 @@ public class LanguageUtils {
|
|||
if (formatString == null) {
|
||||
properties = LOCALE_MAPPINGS.get(getDefaultLocale());
|
||||
formatString = properties.getProperty(key);
|
||||
|
||||
// Try and get the key from en_US (this should only ever happen in development)
|
||||
if (formatString == null) {
|
||||
properties = LOCALE_MAPPINGS.get("en_US");
|
||||
formatString = properties.getProperty(key);
|
||||
|
||||
// Final fallback
|
||||
if (formatString == null) {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Try and get the key from en_US (this should only ever happen in development)
|
||||
if (formatString == null) {
|
||||
properties = LOCALE_MAPPINGS.get("en_US");
|
||||
formatString = properties.getProperty(key);
|
||||
String message = formatString.replace("&", "\u00a7");
|
||||
if (values == null || values.length == 0) {
|
||||
// Nothing to replace
|
||||
return message;
|
||||
}
|
||||
|
||||
// Final fallback
|
||||
if (formatString == null) {
|
||||
return key;
|
||||
}
|
||||
|
||||
return MessageFormat.format(formatString.replace("'", "''").replace("&", "\u00a7"), values);
|
||||
return MessageFormat.format(message.replace("'", "''"), values);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -140,12 +146,15 @@ public class LanguageUtils {
|
|||
* @return The formatted locale
|
||||
*/
|
||||
public static String formatLocale(String locale) {
|
||||
try {
|
||||
String[] parts = locale.toLowerCase().split("_");
|
||||
return parts[0] + "_" + parts[1].toUpperCase();
|
||||
} catch (Exception e) {
|
||||
// Currently, all valid Geyser locales follow the same pattern of ll_CC, where ll is the language and
|
||||
// CC is the country
|
||||
if (locale.length() != 5 || locale.indexOf('_') != 2) {
|
||||
// Invalid locale
|
||||
return locale;
|
||||
}
|
||||
String language = locale.substring(0, 2);
|
||||
String country = locale.substring(3);
|
||||
return language.toLowerCase(Locale.ENGLISH) + "_" + country.toUpperCase(Locale.ENGLISH);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in a new issue