Режим игры решает сервер: клиент больше не ломает блоки сам
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
package net.rustnotmc.client.net;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.RayTraceResult;
|
||||
import net.rustnotmc.protocol.Packets;
|
||||
|
||||
/**
|
||||
* What the player is allowed to do to the world, and how the game is told.
|
||||
*
|
||||
* In survival the player breaks nothing. Not the blocks, and not the outline
|
||||
* around the block they are looking at either: a highlight that leads nowhere
|
||||
* is worse than no highlight, because it says "here" and then nothing happens.
|
||||
*
|
||||
* In creative the player breaks the one block they are looking at, and only on
|
||||
* a deliberate click. The game sends a packet for every frame the button is
|
||||
* held, which is how a held button ends up breaking a line of blocks across
|
||||
* the world instead of the one under the crosshair.
|
||||
*/
|
||||
public final class RsxClientMode {
|
||||
|
||||
private static volatile int mode = Packets.GAMEMODE_SURVIVAL;
|
||||
|
||||
private RsxClientMode() {
|
||||
}
|
||||
|
||||
/** The mode the server says the player is in. */
|
||||
public static int mode() {
|
||||
return mode;
|
||||
}
|
||||
|
||||
/** The server said the mode changed. */
|
||||
public static void set(int newMode) {
|
||||
mode = newMode;
|
||||
}
|
||||
|
||||
/** True when the player may break blocks. */
|
||||
public static boolean canBreakBlocks() {
|
||||
return mode == Packets.GAMEMODE_CREATIVE;
|
||||
}
|
||||
|
||||
/**
|
||||
* The player clicked, and wants the block they are looking at broken.
|
||||
*
|
||||
* The game has already worked out what the crosshair is on, so that is what
|
||||
* gets broken. The server checks that the player was close enough to it.
|
||||
*/
|
||||
public static void onLeftClick(Minecraft minecraft) {
|
||||
if (!canBreakBlocks()) {
|
||||
return;
|
||||
}
|
||||
RayTraceResult hit = minecraft.objectMouseOver;
|
||||
if (hit == null || hit.typeOfHit != RayTraceResult.Type.BLOCK) {
|
||||
return;
|
||||
}
|
||||
RsxNetworkManager manager = RsxNetworkManager.active();
|
||||
if (manager == null) {
|
||||
return;
|
||||
}
|
||||
BlockPos pos = hit.getBlockPos();
|
||||
manager.sendBlockChange(pos.getX(), pos.getY(), pos.getZ(),
|
||||
net.rustnotmc.protocol.Blocks.AIR);
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,6 @@ import net.minecraft.network.INetHandler;
|
||||
import net.minecraft.network.NetworkManager;
|
||||
import net.minecraft.network.Packet;
|
||||
import net.minecraft.network.play.INetHandlerPlayClient;import net.minecraft.network.play.client.CPacketPlayer;
|
||||
import net.minecraft.network.play.client.CPacketPlayerDigging;
|
||||
import net.minecraft.util.text.ITextComponent;
|
||||
import net.minecraft.util.text.TextComponentTranslation;
|
||||
import net.rustnotmc.protocol.Buf;
|
||||
@@ -245,6 +244,11 @@ public final class RsxNetworkManager extends NetworkManager {
|
||||
case Packets.WORLD_JOIN:
|
||||
onWorldJoin(frame);
|
||||
return;
|
||||
case Packets.SET_GAME_MODE: {
|
||||
Packets.GameMode gameMode = Packets.GameMode.read(new Buf(frame.body()));
|
||||
RsxClientMode.set(gameMode.mode);
|
||||
return;
|
||||
}
|
||||
default:
|
||||
onPlay(frame);
|
||||
}
|
||||
@@ -295,8 +299,9 @@ public final class RsxNetworkManager extends NetworkManager {
|
||||
if (this.play == null) {
|
||||
return;
|
||||
}
|
||||
RsxClientMode.set(world.gameMode);
|
||||
List<Packet<INetHandlerPlayClient>> packets = RsxWorldBridge.join(world.entityId, 200,
|
||||
world.spawnX, world.spawnY, world.spawnZ);
|
||||
world.spawnX, world.spawnY, world.spawnZ, world.gameMode);
|
||||
for (int i = 0; i < packets.size(); i++) {
|
||||
packets.get(i).processPacket(this.play);
|
||||
}
|
||||
@@ -364,31 +369,37 @@ public final class RsxNetworkManager extends NetworkManager {
|
||||
* The game is sending something; the server does not speak the game's
|
||||
* language, so it is translated.
|
||||
*
|
||||
* Most of what the game sends has no counterpart on the server and is
|
||||
* dropped. The two that matter are where the player is and what the
|
||||
* player is breaking.
|
||||
* The dig packets are the one thing that is deliberately not translated.
|
||||
* The game sends one for every frame the button is held, so a held button
|
||||
* becomes a stream of block changes and a line of blocks disappears across
|
||||
* the world instead of the one under the crosshair. The client breaks
|
||||
* blocks on its own click instead, with the game's own raycast.
|
||||
*/
|
||||
@Override
|
||||
public void sendPacket(Packet<?> packet) {
|
||||
if (packet instanceof CPacketPlayer) {
|
||||
if (packet instanceof CPacketPlayer.Position
|
||||
|| packet instanceof CPacketPlayer.Rotation
|
||||
|| packet instanceof CPacketPlayer.PositionRotation) {
|
||||
CPacketPlayer move = (CPacketPlayer) packet;
|
||||
send(Packets.PLAYER_MOVE, new Packets.PlayerMove(
|
||||
move.getX(0.0D), move.getY(0.0D), move.getZ(0.0D),
|
||||
move.getYaw(0.0F), move.getPitch(0.0F), move.isOnGround()));
|
||||
return;
|
||||
}
|
||||
if (packet instanceof CPacketPlayerDigging) {
|
||||
CPacketPlayerDigging dig = (CPacketPlayerDigging) packet;
|
||||
if (dig.getAction() == CPacketPlayerDigging.Action.START_DESTROY_BLOCK) {
|
||||
net.minecraft.util.math.BlockPos pos = dig.getPosition();
|
||||
send(Packets.BLOCK_CHANGE, new Packets.BlockChange(pos.getX(), pos.getY(),
|
||||
pos.getZ(), net.rustnotmc.protocol.Blocks.AIR));
|
||||
}
|
||||
return;
|
||||
}
|
||||
// everything else the game sends has no place in our protocol yet
|
||||
}
|
||||
|
||||
/**
|
||||
* Asks the server to break a block.
|
||||
*
|
||||
* The server decides whether it happens: the player has to be close
|
||||
* enough to it, and in a survival world the player does not break blocks
|
||||
* at all.
|
||||
*/
|
||||
public void sendBlockChange(int x, int y, int z, byte id) {
|
||||
send(Packets.BLOCK_CHANGE, new Packets.BlockChange(x, y, z, id));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------- teardown
|
||||
|
||||
private void lost(String reason) {
|
||||
|
||||
@@ -55,10 +55,16 @@ public final class RsxWorldBridge {
|
||||
* world exists, because the player belongs to the world.
|
||||
*/
|
||||
public static List<Packet<INetHandlerPlayClient>> join(int entityId, int maxPlayers,
|
||||
double spawnX, double spawnY, double spawnZ) {
|
||||
double spawnX, double spawnY, double spawnZ,
|
||||
int gameMode) {
|
||||
List<Packet<INetHandlerPlayClient>> packets =
|
||||
new ArrayList<Packet<INetHandlerPlayClient>>();
|
||||
packets.add(new SPacketJoinGame(entityId, GameType.SURVIVAL, false, 0,
|
||||
// the game type in the join packet is what makes the game apply its own
|
||||
// rules: in creative the player may break blocks, in survival it may
|
||||
// not, and the outline follows
|
||||
GameType type = gameMode == net.rustnotmc.protocol.Packets.GAMEMODE_CREATIVE
|
||||
? GameType.CREATIVE : GameType.SURVIVAL;
|
||||
packets.add(new SPacketJoinGame(entityId, type, false, 0,
|
||||
EnumDifficulty.NORMAL, maxPlayers, WorldType.DEFAULT, false));
|
||||
packets.add(new SPacketSpawnPosition(
|
||||
new BlockPos((int) Math.floor(spawnX), (int) Math.floor(spawnY),
|
||||
|
||||
Reference in New Issue
Block a user