1.16 support (network), dimension flattening update

This commit is contained in:
Bixilon 2020-07-29 22:08:59 +02:00
parent b66212a7b2
commit a05a9ea8ac
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
30 changed files with 466 additions and 115 deletions

View File

@ -1,39 +0,0 @@
/*
* Codename Minosoft
* Copyright (C) 2020 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.game.datatypes;
public enum Dimension {
NETHER(-1),
OVERWORLD(0),
END(1);
final int id;
Dimension(int id) {
this.id = id;
}
public static Dimension byId(int id) {
for (Dimension g : values()) {
if (g.getId() == id) {
return g;
}
}
return null;
}
public int getId() {
return id;
}
}

View File

@ -20,7 +20,8 @@ public enum LevelType {
AMPLIFIED("amplified"), AMPLIFIED("amplified"),
DEFAULT_1_1("default_1_1"), DEFAULT_1_1("default_1_1"),
CUSTOMIZED("customized"), CUSTOMIZED("customized"),
BUFFET("buffet"); BUFFET("buffet"),
UNKNOWN("unknown");
final String type; final String type;

View File

@ -166,15 +166,13 @@ public class TextComponent {
if (json.has("extra")) { if (json.has("extra")) {
JsonArray arr = json.getAsJsonArray("extra"); JsonArray arr = json.getAsJsonArray("extra");
for (int i = 0; i < arr.size(); i++) { for (int i = 0; i < arr.size(); i++) {
JsonObject object; if (arr.get(i).isJsonPrimitive()) {
try {
object = arr.get(i).getAsJsonObject();
} catch (Exception e) {
// reset text
buffer.append(ChatAttributes.RESET); buffer.append(ChatAttributes.RESET);
buffer.append(" ");
buffer.append(arr.get(i).getAsString()); buffer.append(arr.get(i).getAsString());
continue; continue;
} }
JsonObject object = arr.get(i).getAsJsonObject();
if (object.has("bold") && object.get("bold").getAsBoolean()) { if (object.has("bold") && object.get("bold").getAsBoolean()) {
buffer.append(ChatAttributes.BOLD); buffer.append(ChatAttributes.BOLD);
} }
@ -196,9 +194,22 @@ public class TextComponent {
buffer.append(object.get("text").getAsString()); buffer.append(object.get("text").getAsString());
} }
buffer.append(ChatAttributes.RESET); buffer.append(ChatAttributes.RESET);
return buffer.toString();
} }
return ""; if (json.has("with")) {
JsonArray arr = json.getAsJsonArray("with");
for (int i = 0; i < arr.size(); i++) {
if (arr.get(i).isJsonPrimitive()) {
buffer.append(ChatAttributes.RESET);
buffer.append(" ");
buffer.append(arr.get(i).getAsString());
continue;
}
JsonObject object = arr.get(i).getAsJsonObject();
buffer.append(object.get("text").getAsString());
}
buffer.append(ChatAttributes.RESET);
}
return buffer.toString();
} }
@Override @Override

View File

@ -95,8 +95,8 @@ public abstract class Entity implements EntityInterface {
this.pitch = pitch; this.pitch = pitch;
} }
public void setEquipment(InventorySlots.EntityInventory slot, Slot data) { public void setEquipment(HashMap<InventorySlots.EntityInventory, Slot> slots) {
equipment.put(slot, data); equipment.putAll(slots);
} }
public Slot getEquipment(InventorySlots.EntityInventory slot) { public Slot getEquipment(InventorySlots.EntityInventory slot) {

View File

@ -19,6 +19,7 @@ import de.bixilon.minosoft.game.datatypes.Mappings;
import de.bixilon.minosoft.game.datatypes.objectLoader.blockIds.BlockIds; import de.bixilon.minosoft.game.datatypes.objectLoader.blockIds.BlockIds;
import de.bixilon.minosoft.game.datatypes.objectLoader.blocks.Block; import de.bixilon.minosoft.game.datatypes.objectLoader.blocks.Block;
import de.bixilon.minosoft.game.datatypes.objectLoader.blocks.Blocks; import de.bixilon.minosoft.game.datatypes.objectLoader.blocks.Blocks;
import de.bixilon.minosoft.game.datatypes.objectLoader.dimensions.Dimensions;
import de.bixilon.minosoft.game.datatypes.objectLoader.effects.MobEffects; import de.bixilon.minosoft.game.datatypes.objectLoader.effects.MobEffects;
import de.bixilon.minosoft.game.datatypes.objectLoader.enchantments.Enchantments; import de.bixilon.minosoft.game.datatypes.objectLoader.enchantments.Enchantments;
import de.bixilon.minosoft.game.datatypes.objectLoader.entities.Entities; import de.bixilon.minosoft.game.datatypes.objectLoader.entities.Entities;
@ -60,6 +61,9 @@ public class ObjectLoader {
Motives.load(mod, modJSON.getAsJsonObject("motive").getAsJsonObject("entries"), version); Motives.load(mod, modJSON.getAsJsonObject("motive").getAsJsonObject("entries"), version);
Particles.load(mod, modJSON.getAsJsonObject("particle_type").getAsJsonObject("entries"), version); Particles.load(mod, modJSON.getAsJsonObject("particle_type").getAsJsonObject("entries"), version);
MobEffects.load(mod, modJSON.getAsJsonObject("mob_effect").getAsJsonObject("entries"), version); MobEffects.load(mod, modJSON.getAsJsonObject("mob_effect").getAsJsonObject("entries"), version);
if (modJSON.has("dimension_type")) {
Dimensions.load(mod, modJSON.getAsJsonObject("dimension_type").getAsJsonObject("entries"), version);
}
break; break;
case BLOCKS: case BLOCKS:
Blocks.load(mod, modJSON, version); Blocks.load(mod, modJSON, version);

View File

@ -0,0 +1,60 @@
/*
* Codename Minosoft
* Copyright (C) 2020 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.game.datatypes.objectLoader.dimensions;
public class Dimension {
final String mod;
final String identifier;
final boolean hasSkyLight;
public Dimension(String mod, String identifier, boolean hasSkyLight) {
this.mod = mod;
this.identifier = identifier;
this.hasSkyLight = hasSkyLight;
}
public String getMod() {
return mod;
}
public String getIdentifier() {
return identifier;
}
public boolean hasSkyLight() {
return hasSkyLight;
}
@Override
public String toString() {
return String.format("%s:%s", getMod(), getIdentifier());
}
@Override
public int hashCode() {
return mod.hashCode() * identifier.hashCode();
}
@Override
public boolean equals(Object obj) {
if (super.equals(obj)) {
return true;
}
if (hashCode() != obj.hashCode()) {
return false;
}
Dimension their = (Dimension) obj;
return getIdentifier().equals(their.getIdentifier()) && getMod().equals(their.getMod()) && hasSkyLight() == their.hasSkyLight();
}
}

View File

@ -0,0 +1,66 @@
/*
* Codename Minosoft
* Copyright (C) 2020 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.game.datatypes.objectLoader.dimensions;
import com.google.common.collect.HashBiMap;
import com.google.gson.JsonObject;
import de.bixilon.minosoft.protocol.protocol.ProtocolVersion;
import java.util.HashMap;
public class Dimensions {
static HashMap<ProtocolVersion, HashBiMap<Integer, Dimension>> dimensionIdMap = new HashMap<>(); // version -> (protocolId > Dimension)
static HashBiMap<String, Dimension> dimensionIdentifierMap = HashBiMap.create(); // Identifier, Dimension
static HashMap<String, HashMap<String, Dimension>> customDimensionIdentifierMap = new HashMap<>(); // Mod -> (Identifier, Dimension): used > 1.16
public static Dimension byId(int protocolId, ProtocolVersion version) {
if (version.getVersionNumber() < ProtocolVersion.VERSION_1_12_2.getVersionNumber()) {
version = ProtocolVersion.VERSION_1_12_2;
}
return dimensionIdMap.get(version).get(protocolId);
}
public static Dimension byIdentifier(String identifier) {
String[] splitted = identifier.split(":", 2);
return byIdentifier(splitted[0], splitted[1]);
}
public static Dimension byIdentifier(String mod, String identifier) {
if (mod == "minecraft") {
return dimensionIdentifierMap.get(identifier);
}
if (customDimensionIdentifierMap.containsKey(mod)) {
return customDimensionIdentifierMap.get(mod).get(identifier);
}
return null;
}
public static void load(String mod, JsonObject json, ProtocolVersion version) {
HashBiMap<Integer, Dimension> versionIdMapping = HashBiMap.create();
for (String identifierName : json.keySet()) {
JsonObject identifierJSON = json.getAsJsonObject(identifierName);
Dimension dimension = new Dimension(mod, identifierName, identifierJSON.get("has_skylight").getAsBoolean());
if (identifierJSON.has("id")) {
versionIdMapping.put(identifierJSON.get("id").getAsInt(), dimension);
continue;
}
dimensionIdentifierMap.put(identifierName, dimension);
}
if (versionIdMapping.size() > 0) {
dimensionIdMap.put(version, versionIdMapping);
}
}
}

View File

@ -48,6 +48,12 @@ public class Recipe {
this.result = result; this.result = result;
} }
public Recipe(RecipeTypes type, Ingredient base, Ingredient addition, Slot result) {
this.type = type;
this.ingredients = new Ingredient[]{base, addition};
this.result = result;
}
public Recipe(RecipeTypes type, String group, Ingredient ingredient, Slot result, float experience, int cookingTime) { public Recipe(RecipeTypes type, String group, Ingredient ingredient, Slot result, float experience, int cookingTime) {
this.type = type; this.type = type;
this.group = group; this.group = group;

View File

@ -34,7 +34,8 @@ public enum RecipeTypes {
BLASTING("blasting"), BLASTING("blasting"),
SMOKING("smoking"), SMOKING("smoking"),
CAMPFIRE("campfire_cooking"), CAMPFIRE("campfire_cooking"),
STONE_CUTTING("stonecutting"); STONE_CUTTING("stonecutting"),
SMITHING("smithing");
final String name; final String name;

View File

@ -13,10 +13,10 @@
package de.bixilon.minosoft.game.datatypes.world; package de.bixilon.minosoft.game.datatypes.world;
import de.bixilon.minosoft.game.datatypes.Dimension;
import de.bixilon.minosoft.game.datatypes.entities.Entity; import de.bixilon.minosoft.game.datatypes.entities.Entity;
import de.bixilon.minosoft.game.datatypes.objectLoader.blocks.Block; import de.bixilon.minosoft.game.datatypes.objectLoader.blocks.Block;
import de.bixilon.minosoft.game.datatypes.objectLoader.blocks.Blocks; import de.bixilon.minosoft.game.datatypes.objectLoader.blocks.Blocks;
import de.bixilon.minosoft.game.datatypes.objectLoader.dimensions.Dimension;
import de.bixilon.minosoft.nbt.tag.CompoundTag; import de.bixilon.minosoft.nbt.tag.CompoundTag;
import java.util.HashMap; import java.util.HashMap;

View File

@ -157,8 +157,9 @@ public class Network {
} }
InPacketBuffer inPacketBuffer = new InPacketBuffer(data, connection.getVersion()); InPacketBuffer inPacketBuffer = new InPacketBuffer(data, connection.getVersion());
Packets.Clientbound p = null;
try { try {
Packets.Clientbound p = connection.getVersion().getProtocol().getPacketByCommand(connection.getConnectionState(), inPacketBuffer.getCommand()); p = connection.getVersion().getProtocol().getPacketByCommand(connection.getConnectionState(), inPacketBuffer.getCommand());
Class<? extends ClientboundPacket> clazz = Protocol.getPacketByPacket(p); Class<? extends ClientboundPacket> clazz = Protocol.getPacketByPacket(p);
if (clazz == null) { if (clazz == null) {
@ -195,7 +196,7 @@ public class Network {
e.printStackTrace(); e.printStackTrace();
} }
} catch (Exception e) { } catch (Exception e) {
Log.protocol(String.format("An error occurred while parsing an packet: %s", e)); Log.protocol(String.format("An error occurred while parsing an packet (%s): %s", p, e));
e.printStackTrace(); e.printStackTrace();
} }
} }

View File

@ -35,12 +35,12 @@ public class PacketBlockEntityMetadata implements ClientboundPacket {
case VERSION_1_7_10: case VERSION_1_7_10:
position = buffer.readBlockPositionShort(); position = buffer.readBlockPositionShort();
action = Actions.byId(buffer.readByte(), buffer.getVersion()); action = Actions.byId(buffer.readByte(), buffer.getVersion());
nbt = buffer.readNBT(true); nbt = (CompoundTag) buffer.readNBT(true);
return true; return true;
default: default:
position = buffer.readPosition(); position = buffer.readPosition();
action = Actions.byId(buffer.readByte(), buffer.getVersion()); action = Actions.byId(buffer.readByte(), buffer.getVersion());
nbt = buffer.readNBT(); nbt = (CompoundTag) buffer.readNBT();
return true; return true;
} }
} }

View File

@ -13,7 +13,7 @@
package de.bixilon.minosoft.protocol.packets.clientbound.play; package de.bixilon.minosoft.protocol.packets.clientbound.play;
import de.bixilon.minosoft.game.datatypes.Dimension; import de.bixilon.minosoft.game.datatypes.objectLoader.dimensions.Dimension;
import de.bixilon.minosoft.game.datatypes.world.BlockPosition; import de.bixilon.minosoft.game.datatypes.world.BlockPosition;
import de.bixilon.minosoft.game.datatypes.world.Chunk; import de.bixilon.minosoft.game.datatypes.world.Chunk;
import de.bixilon.minosoft.game.datatypes.world.ChunkLocation; import de.bixilon.minosoft.game.datatypes.world.ChunkLocation;
@ -43,7 +43,7 @@ public class PacketChunkData implements ClientboundPacket {
} }
public boolean read(InPacketBuffer buffer, Dimension dimension) { public boolean read(InPacketBuffer buffer, Dimension dimension) {
boolean containsSkyLight = dimension == Dimension.OVERWORLD; boolean containsSkyLight = dimension.hasSkyLight();
if (buffer.getVersion().getVersionNumber() <= ProtocolVersion.VERSION_1_7_10.getVersionNumber()) { if (buffer.getVersion().getVersionNumber() <= ProtocolVersion.VERSION_1_7_10.getVersionNumber()) {
this.location = new ChunkLocation(buffer.readInt(), buffer.readInt()); this.location = new ChunkLocation(buffer.readInt(), buffer.readInt());
boolean groundUpContinuous = buffer.readBoolean(); boolean groundUpContinuous = buffer.readBoolean();
@ -74,7 +74,7 @@ public class PacketChunkData implements ClientboundPacket {
} }
short sectionBitMask = (short) buffer.readVarInt(); short sectionBitMask = (short) buffer.readVarInt();
if (buffer.getVersion().getVersionNumber() >= ProtocolVersion.VERSION_1_14_4.getVersionNumber()) { if (buffer.getVersion().getVersionNumber() >= ProtocolVersion.VERSION_1_14_4.getVersionNumber()) {
heightMap = buffer.readNBT(); heightMap = (CompoundTag) buffer.readNBT();
} }
if (groundUpContinuous) { if (groundUpContinuous) {
if (buffer.getVersion().getVersionNumber() >= ProtocolVersion.VERSION_1_16_2.getVersionNumber()) { if (buffer.getVersion().getVersionNumber() >= ProtocolVersion.VERSION_1_16_2.getVersionNumber()) {
@ -93,7 +93,7 @@ public class PacketChunkData implements ClientboundPacket {
} }
int blockEntitiesCount = buffer.readVarInt(); int blockEntitiesCount = buffer.readVarInt();
for (int i = 0; i < blockEntitiesCount; i++) { for (int i = 0; i < blockEntitiesCount; i++) {
CompoundTag tag = buffer.readNBT(); CompoundTag tag = (CompoundTag) buffer.readNBT();
blockEntities.put(new BlockPosition(tag.getIntTag("x").getValue(), (short) tag.getIntTag("y").getValue(), tag.getIntTag("z").getValue()), tag); blockEntities.put(new BlockPosition(tag.getIntTag("x").getValue(), (short) tag.getIntTag("y").getValue(), tag.getIntTag("z").getValue()), tag);
} }
return true; return true;

View File

@ -79,6 +79,13 @@ public class PacketDeclareRecipes implements ClientboundPacket {
recipe = new Recipe(type, group, ingredient, result); recipe = new Recipe(type, group, ingredient, result);
break; break;
} }
case SMITHING: {
Ingredient base = buffer.readIngredient();
Ingredient addition = buffer.readIngredient();
Slot result = buffer.readSlot();
recipe = new Recipe(type, base, addition, result);
break;
}
default: default:
recipe = new Recipe(type); recipe = new Recipe(type);
break; break;

View File

@ -19,41 +19,53 @@ import de.bixilon.minosoft.logging.Log;
import de.bixilon.minosoft.protocol.packets.ClientboundPacket; import de.bixilon.minosoft.protocol.packets.ClientboundPacket;
import de.bixilon.minosoft.protocol.protocol.InByteBuffer; import de.bixilon.minosoft.protocol.protocol.InByteBuffer;
import de.bixilon.minosoft.protocol.protocol.PacketHandler; import de.bixilon.minosoft.protocol.protocol.PacketHandler;
import de.bixilon.minosoft.protocol.protocol.ProtocolVersion;
import java.util.HashMap;
import java.util.Map;
public class PacketEntityEquipment implements ClientboundPacket { public class PacketEntityEquipment implements ClientboundPacket {
int entityId; int entityId;
InventorySlots.EntityInventory slot; HashMap<InventorySlots.EntityInventory, Slot> slots = new HashMap<>();
Slot data;
@Override @Override
public boolean read(InByteBuffer buffer) { public boolean read(InByteBuffer buffer) {
switch (buffer.getVersion()) { if (buffer.getVersion() == ProtocolVersion.VERSION_1_7_10) {
case VERSION_1_7_10: entityId = buffer.readInt();
entityId = buffer.readInt(); slots.put(InventorySlots.EntityInventory.byId(buffer.readShort(), buffer.getVersion()), buffer.readSlot());
this.slot = InventorySlots.EntityInventory.byId(buffer.readShort(), buffer.getVersion()); return true;
this.data = buffer.readSlot();
return true;
case VERSION_1_8:
entityId = buffer.readVarInt();
this.slot = InventorySlots.EntityInventory.byId(buffer.readShort(), buffer.getVersion());
this.data = buffer.readSlot();
return true;
default:
entityId = buffer.readVarInt();
this.slot = InventorySlots.EntityInventory.byId(buffer.readVarInt(), buffer.getVersion());
this.data = buffer.readSlot();
return true;
} }
if (buffer.getVersion() == ProtocolVersion.VERSION_1_8) {
entityId = buffer.readVarInt();
slots.put(InventorySlots.EntityInventory.byId(buffer.readShort(), buffer.getVersion()), buffer.readSlot());
return true;
}
if (buffer.getVersion().getVersionNumber() < ProtocolVersion.VERSION_1_16_2.getVersionNumber()) {
entityId = buffer.readVarInt();
slots.put(InventorySlots.EntityInventory.byId(buffer.readVarInt(), buffer.getVersion()), buffer.readSlot());
return true;
}
entityId = buffer.readVarInt();
boolean slotAvailable = true;
while (slotAvailable) {
int slotId = buffer.readByte();
if (slotId >= 0) {
slotAvailable = false;
}
slotId &= 0x7F;
slots.put(InventorySlots.EntityInventory.byId(slotId, buffer.getVersion()), buffer.readSlot());
}
return true;
} }
@Override @Override
public void log() { public void log() {
if (data != null) { if (slots.size() == 1) {
Log.protocol(String.format("Entity equipment changed (entityId=%d, slot=%s): %dx %s", entityId, slot, data.getItemCount(), data.getDisplayName())); Map.Entry<InventorySlots.EntityInventory, Slot> set = slots.entrySet().iterator().next();
Log.protocol(String.format("Entity equipment changed (entityId=%d, slot=%s): %dx %s", entityId, set.getKey(), set.getValue().getItemCount(), set.getValue().getDisplayName()));
} else { } else {
// null means nothing, means air Log.protocol(String.format("Entity equipment changed (entityId=%d, slotCount=%d)", entityId, slots.size()));
Log.protocol(String.format("Entity equipment changed (entityId=%d, slot=%s): AIR", entityId, slot));
} }
} }
@ -66,11 +78,7 @@ public class PacketEntityEquipment implements ClientboundPacket {
return entityId; return entityId;
} }
public InventorySlots.EntityInventory getSlot() { public HashMap<InventorySlots.EntityInventory, Slot> getSlots() {
return slot; return slots;
}
public Slot getData() {
return data;
} }
} }

View File

@ -14,16 +14,22 @@
package de.bixilon.minosoft.protocol.packets.clientbound.play; package de.bixilon.minosoft.protocol.packets.clientbound.play;
import de.bixilon.minosoft.game.datatypes.Difficulty; import de.bixilon.minosoft.game.datatypes.Difficulty;
import de.bixilon.minosoft.game.datatypes.Dimension;
import de.bixilon.minosoft.game.datatypes.GameMode; import de.bixilon.minosoft.game.datatypes.GameMode;
import de.bixilon.minosoft.game.datatypes.LevelType; import de.bixilon.minosoft.game.datatypes.LevelType;
import de.bixilon.minosoft.game.datatypes.objectLoader.dimensions.Dimension;
import de.bixilon.minosoft.game.datatypes.objectLoader.dimensions.Dimensions;
import de.bixilon.minosoft.logging.Log; import de.bixilon.minosoft.logging.Log;
import de.bixilon.minosoft.nbt.tag.CompoundTag;
import de.bixilon.minosoft.nbt.tag.ListTag;
import de.bixilon.minosoft.nbt.tag.NBTTag;
import de.bixilon.minosoft.protocol.packets.ClientboundPacket; import de.bixilon.minosoft.protocol.packets.ClientboundPacket;
import de.bixilon.minosoft.protocol.protocol.InByteBuffer; import de.bixilon.minosoft.protocol.protocol.InByteBuffer;
import de.bixilon.minosoft.protocol.protocol.PacketHandler; import de.bixilon.minosoft.protocol.protocol.PacketHandler;
import de.bixilon.minosoft.protocol.protocol.ProtocolVersion; import de.bixilon.minosoft.protocol.protocol.ProtocolVersion;
import de.bixilon.minosoft.util.BitByte; import de.bixilon.minosoft.util.BitByte;
import java.util.HashMap;
public class PacketJoinGame implements ClientboundPacket { public class PacketJoinGame implements ClientboundPacket {
int entityId; int entityId;
boolean hardcore; boolean hardcore;
@ -35,7 +41,7 @@ public class PacketJoinGame implements ClientboundPacket {
LevelType levelType; LevelType levelType;
boolean reducedDebugScreen; boolean reducedDebugScreen;
boolean enableRespawnScreen = true; boolean enableRespawnScreen = true;
HashMap<String, HashMap<String, Dimension>> dimensions;
@Override @Override
public boolean read(InByteBuffer buffer) { public boolean read(InByteBuffer buffer) {
@ -49,7 +55,7 @@ public class PacketJoinGame implements ClientboundPacket {
gameModeRaw &= ~0x8; gameModeRaw &= ~0x8;
gameMode = GameMode.byId(gameModeRaw); gameMode = GameMode.byId(gameModeRaw);
dimension = Dimension.byId(buffer.readByte()); dimension = Dimensions.byId(buffer.readInt(), buffer.getVersion());
difficulty = Difficulty.byId(buffer.readByte()); difficulty = Difficulty.byId(buffer.readByte());
maxPlayers = buffer.readByte(); maxPlayers = buffer.readByte();
levelType = LevelType.byType(buffer.readString()); levelType = LevelType.byType(buffer.readString());
@ -72,7 +78,7 @@ public class PacketJoinGame implements ClientboundPacket {
gameModeRaw &= ~0x8; gameModeRaw &= ~0x8;
gameMode = GameMode.byId(gameModeRaw); gameMode = GameMode.byId(gameModeRaw);
dimension = Dimension.byId(buffer.readInt()); dimension = Dimensions.byId(buffer.readInt(), buffer.getVersion());
difficulty = Difficulty.byId(buffer.readByte()); difficulty = Difficulty.byId(buffer.readByte());
maxPlayers = buffer.readByte(); maxPlayers = buffer.readByte();
levelType = LevelType.byType(buffer.readString()); levelType = LevelType.byType(buffer.readString());
@ -87,7 +93,7 @@ public class PacketJoinGame implements ClientboundPacket {
gameModeRaw &= ~0x8; gameModeRaw &= ~0x8;
gameMode = GameMode.byId(gameModeRaw); gameMode = GameMode.byId(gameModeRaw);
dimension = Dimension.byId(buffer.readInt()); dimension = Dimensions.byId(buffer.readInt(), buffer.getVersion());
maxPlayers = buffer.readByte(); maxPlayers = buffer.readByte();
levelType = LevelType.byType(buffer.readString()); levelType = LevelType.byType(buffer.readString());
viewDistance = buffer.readVarInt(); viewDistance = buffer.readVarInt();
@ -102,7 +108,7 @@ public class PacketJoinGame implements ClientboundPacket {
gameModeRaw &= ~0x8; gameModeRaw &= ~0x8;
gameMode = GameMode.byId(gameModeRaw); gameMode = GameMode.byId(gameModeRaw);
dimension = Dimension.byId(buffer.readInt()); dimension = Dimensions.byId(buffer.readInt(), buffer.getVersion());
long hashedSeed = buffer.readLong(); long hashedSeed = buffer.readLong();
maxPlayers = buffer.readByte(); maxPlayers = buffer.readByte();
levelType = LevelType.byType(buffer.readString()); levelType = LevelType.byType(buffer.readString());
@ -111,9 +117,31 @@ public class PacketJoinGame implements ClientboundPacket {
enableRespawnScreen = buffer.readBoolean(); enableRespawnScreen = buffer.readBoolean();
return true; return true;
} }
default: {
this.entityId = buffer.readInt();
hardcore = buffer.readBoolean();
gameMode = GameMode.byId(buffer.readByte());
buffer.readByte(); // previous game mode
// worlds
String[] worlds = buffer.readStringArray(buffer.readVarInt());
NBTTag dimensionCodec = buffer.readNBT();
dimensions = parseDimensionCodec(dimensionCodec);
String[] currentDimensionSplit = buffer.readString().split(":", 2);
dimension = dimensions.get(currentDimensionSplit[0]).get(currentDimensionSplit[1]);
buffer.readString(); // world name
long hashedSeed = buffer.readLong();
maxPlayers = buffer.readByte();
levelType = LevelType.UNKNOWN;
viewDistance = buffer.readVarInt();
reducedDebugScreen = buffer.readBoolean();
enableRespawnScreen = buffer.readBoolean();
boolean isDebug = buffer.readBoolean();
if (buffer.readBoolean()) {
levelType = LevelType.FLAT;
}
return true;
}
} }
return false;
} }
@Override @Override
@ -126,6 +154,21 @@ public class PacketJoinGame implements ClientboundPacket {
h.handle(this); h.handle(this);
} }
private HashMap<String, HashMap<String, Dimension>> parseDimensionCodec(NBTTag nbt) {
HashMap<String, HashMap<String, Dimension>> dimensionMap = new HashMap<>();
ListTag listTag = ((CompoundTag) nbt).getCompoundTag("minecraft:dimension_type").getListTag("value");
for (NBTTag tag : listTag.getValue()) {
CompoundTag compoundTag = (CompoundTag) tag;
String[] name = compoundTag.getStringTag("name").getValue().split(":", 2);
if (!dimensionMap.containsKey(name[0])) {
dimensionMap.put(name[0], new HashMap<>());
}
dimensionMap.get(name[0]).put(name[1], new Dimension(name[0], name[1], compoundTag.getByteTag("has_skylight").getValue() == 0x01));
}
return dimensionMap;
}
public boolean isHardcore() { public boolean isHardcore() {
return hardcore; return hardcore;
} }

View File

@ -27,7 +27,7 @@ public class PacketNBTQueryResponse implements ClientboundPacket {
@Override @Override
public boolean read(InByteBuffer buffer) { public boolean read(InByteBuffer buffer) {
transactionId = buffer.readVarInt(); transactionId = buffer.readVarInt();
tag = buffer.readNBT(); tag = (CompoundTag) buffer.readNBT();
return true; return true;
} }

View File

@ -14,9 +14,10 @@
package de.bixilon.minosoft.protocol.packets.clientbound.play; package de.bixilon.minosoft.protocol.packets.clientbound.play;
import de.bixilon.minosoft.game.datatypes.Difficulty; import de.bixilon.minosoft.game.datatypes.Difficulty;
import de.bixilon.minosoft.game.datatypes.Dimension;
import de.bixilon.minosoft.game.datatypes.GameMode; import de.bixilon.minosoft.game.datatypes.GameMode;
import de.bixilon.minosoft.game.datatypes.LevelType; import de.bixilon.minosoft.game.datatypes.LevelType;
import de.bixilon.minosoft.game.datatypes.objectLoader.dimensions.Dimension;
import de.bixilon.minosoft.game.datatypes.objectLoader.dimensions.Dimensions;
import de.bixilon.minosoft.logging.Log; import de.bixilon.minosoft.logging.Log;
import de.bixilon.minosoft.protocol.packets.ClientboundPacket; import de.bixilon.minosoft.protocol.packets.ClientboundPacket;
import de.bixilon.minosoft.protocol.protocol.InByteBuffer; import de.bixilon.minosoft.protocol.protocol.InByteBuffer;
@ -27,7 +28,10 @@ public class PacketRespawn implements ClientboundPacket {
Difficulty difficulty; Difficulty difficulty;
GameMode gameMode; GameMode gameMode;
LevelType levelType; LevelType levelType;
long hashedSeed;
boolean isDebug = false;
boolean isFlat = false;
boolean copyMetaData = false;
@Override @Override
public boolean read(InByteBuffer buffer) { public boolean read(InByteBuffer buffer) {
@ -39,21 +43,31 @@ public class PacketRespawn implements ClientboundPacket {
case VERSION_1_11_2: case VERSION_1_11_2:
case VERSION_1_12_2: case VERSION_1_12_2:
case VERSION_1_13_2: case VERSION_1_13_2:
dimension = Dimension.byId(buffer.readInt()); dimension = Dimensions.byId(buffer.readInt(), buffer.getVersion());
difficulty = Difficulty.byId(buffer.readByte()); difficulty = Difficulty.byId(buffer.readByte());
gameMode = GameMode.byId(buffer.readByte()); gameMode = GameMode.byId(buffer.readByte());
levelType = LevelType.byType(buffer.readString()); levelType = LevelType.byType(buffer.readString());
return true; return true;
case VERSION_1_14_4: case VERSION_1_14_4:
dimension = Dimension.byId(buffer.readInt()); dimension = Dimensions.byId(buffer.readInt(), buffer.getVersion());
gameMode = GameMode.byId(buffer.readByte());
levelType = LevelType.byType(buffer.readString());
return true;
case VERSION_1_15_2:
dimension = Dimensions.byId(buffer.readInt(), buffer.getVersion());
hashedSeed = buffer.readLong();
gameMode = GameMode.byId(buffer.readByte()); gameMode = GameMode.byId(buffer.readByte());
levelType = LevelType.byType(buffer.readString()); levelType = LevelType.byType(buffer.readString());
return true; return true;
default: default:
dimension = Dimension.byId(buffer.readInt()); dimension = Dimensions.byIdentifier(buffer.readString());
long hashedSeed = buffer.readLong(); buffer.readString(); // world
hashedSeed = buffer.readLong();
gameMode = GameMode.byId(buffer.readByte()); gameMode = GameMode.byId(buffer.readByte());
levelType = LevelType.byType(buffer.readString()); buffer.readByte(); // previous game mode
isDebug = buffer.readBoolean();
isFlat = buffer.readBoolean();
copyMetaData = buffer.readBoolean();
return true; return true;
} }
} }

View File

@ -19,13 +19,18 @@ import de.bixilon.minosoft.logging.Log;
import de.bixilon.minosoft.protocol.packets.ClientboundPacket; import de.bixilon.minosoft.protocol.packets.ClientboundPacket;
import de.bixilon.minosoft.protocol.protocol.InByteBuffer; import de.bixilon.minosoft.protocol.protocol.InByteBuffer;
import de.bixilon.minosoft.protocol.protocol.PacketHandler; import de.bixilon.minosoft.protocol.protocol.PacketHandler;
import de.bixilon.minosoft.protocol.protocol.ProtocolVersion;
public class PacketUnlockRecipes implements ClientboundPacket { public class PacketUnlockRecipes implements ClientboundPacket {
UnlockRecipeActions action; UnlockRecipeActions action;
boolean isCraftingBookOpen; boolean isCraftingBookOpen;
boolean isSmeltingBookOpen; boolean isSmeltingBookOpen = false;
boolean isBlastFurnaceBookOpen = false;
boolean isSmokerBookOpen = false;
boolean isCraftingFilteringActive; boolean isCraftingFilteringActive;
boolean isSmeltingFilteringActive; boolean isSmeltingFilteringActive = false;
boolean isBlastFurnaceFilteringActive = false;
boolean isSmokerFilteringActive = false;
Recipe[] listed; Recipe[] listed;
Recipe[] tagged; Recipe[] tagged;
@ -54,6 +59,12 @@ public class PacketUnlockRecipes implements ClientboundPacket {
isCraftingFilteringActive = buffer.readBoolean(); isCraftingFilteringActive = buffer.readBoolean();
isSmeltingBookOpen = buffer.readBoolean(); isSmeltingBookOpen = buffer.readBoolean();
isSmeltingFilteringActive = buffer.readBoolean(); isSmeltingFilteringActive = buffer.readBoolean();
if (buffer.getVersion().getVersionNumber() >= ProtocolVersion.VERSION_1_16_2.getVersionNumber()) {
isBlastFurnaceBookOpen = buffer.readBoolean();
isBlastFurnaceFilteringActive = buffer.readBoolean();
isSmokerBookOpen = buffer.readBoolean();
isSmokerFilteringActive = buffer.readBoolean();
}
listed = new Recipe[buffer.readVarInt()]; listed = new Recipe[buffer.readVarInt()];
for (int i = 0; i < listed.length; i++) { for (int i = 0; i < listed.length; i++) {
listed[i] = Recipes.getRecipe(buffer.readString()); listed[i] = Recipes.getRecipe(buffer.readString());
@ -86,6 +97,30 @@ public class PacketUnlockRecipes implements ClientboundPacket {
return isCraftingFilteringActive; return isCraftingFilteringActive;
} }
public boolean isBlastFurnaceBookOpen() {
return isBlastFurnaceBookOpen;
}
public boolean isBlastFurnaceFilteringActive() {
return isBlastFurnaceFilteringActive;
}
public boolean isSmeltingBookOpen() {
return isSmeltingBookOpen;
}
public boolean isSmeltingFilteringActive() {
return isSmeltingFilteringActive;
}
public boolean isSmokerBookOpen() {
return isSmokerBookOpen;
}
public boolean isSmokerFilteringActive() {
return isSmokerFilteringActive;
}
public Recipe[] getListed() { public Recipe[] getListed() {
return listed; return listed;
} }

View File

@ -0,0 +1,48 @@
/*
* Codename Minosoft
* Copyright (C) 2020 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.protocol.packets.serverbound.play;
import de.bixilon.minosoft.game.datatypes.world.BlockPosition;
import de.bixilon.minosoft.logging.Log;
import de.bixilon.minosoft.protocol.packets.ServerboundPacket;
import de.bixilon.minosoft.protocol.protocol.OutPacketBuffer;
import de.bixilon.minosoft.protocol.protocol.Packets;
import de.bixilon.minosoft.protocol.protocol.ProtocolVersion;
public class PacketGenerateStructure implements ServerboundPacket {
final BlockPosition position;
final int levels;
final boolean keepJigsaw;
public PacketGenerateStructure(BlockPosition position, int levels, boolean keepJigsaw) {
this.position = position;
this.levels = levels;
this.keepJigsaw = keepJigsaw;
}
@Override
public OutPacketBuffer write(ProtocolVersion version) {
OutPacketBuffer buffer = new OutPacketBuffer(version, version.getPacketCommand(Packets.Serverbound.PLAY_GENERATE_STRUCTURE));
buffer.writePosition(position);
buffer.writeVarInt(levels);
buffer.writeBoolean(keepJigsaw);
return buffer;
}
@Override
public void log() {
Log.protocol(String.format("Sending generate structure packet (position=%s, levels=%d, keepJigsaw=%s)", position, levels, keepJigsaw));
}
}

View File

@ -28,6 +28,7 @@ public class PacketInteractEntity implements ServerboundPacket {
final Location location; final Location location;
final Hand hand; final Hand hand;
boolean sneaking;
public PacketInteractEntity(Entity entity, Click click) { public PacketInteractEntity(Entity entity, Click click) {
this.entityId = entity.getEntityId(); this.entityId = entity.getEntityId();
@ -57,6 +58,14 @@ public class PacketInteractEntity implements ServerboundPacket {
this.hand = hand; this.hand = hand;
} }
public PacketInteractEntity(int entityId, Click click, Location location, Hand hand, boolean sneaking) {
this.entityId = entityId;
this.click = click;
this.location = location;
this.hand = hand;
this.sneaking = sneaking;
}
@Override @Override
public OutPacketBuffer write(ProtocolVersion version) { public OutPacketBuffer write(ProtocolVersion version) {
@ -86,6 +95,9 @@ public class PacketInteractEntity implements ServerboundPacket {
buffer.writeFloat((float) location.getZ()); buffer.writeFloat((float) location.getZ());
buffer.writeVarInt(hand.getId()); buffer.writeVarInt(hand.getId());
} }
if (version.getVersionNumber() >= ProtocolVersion.VERSION_1_16_2.getVersionNumber()) {
buffer.writeBoolean(sneaking);
}
break; break;
} }
return buffer; return buffer;

View File

@ -30,14 +30,16 @@ public class PacketPlayerAbilitiesSending implements ServerboundPacket {
@Override @Override
public OutPacketBuffer write(ProtocolVersion version) { public OutPacketBuffer write(ProtocolVersion version) {
OutPacketBuffer buffer = new OutPacketBuffer(version, version.getPacketCommand(Packets.Serverbound.PLAY_PLAYER_ABILITIES)); OutPacketBuffer buffer = new OutPacketBuffer(version, version.getPacketCommand(Packets.Serverbound.PLAY_PLAYER_ABILITIES));
// only fly matters, everything else ignored
byte flags = 0; byte flags = 0;
if (flying) { if (flying) {
flags |= 0b10; flags |= 0b10;
} }
buffer.writeByte(flags); buffer.writeByte(flags);
buffer.writeFloat(0.0F); if (version.getVersionNumber() < ProtocolVersion.VERSION_1_16_2.getVersionNumber()) {
buffer.writeFloat(0.0F); // only fly matters, everything else ignored
buffer.writeFloat(0.0F);
buffer.writeFloat(0.0F);
}
return buffer; return buffer;
} }

View File

@ -0,0 +1,41 @@
/*
* Codename Minosoft
* Copyright (C) 2020 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.protocol.packets.serverbound.play;
import de.bixilon.minosoft.game.datatypes.objectLoader.recipes.Recipe;
import de.bixilon.minosoft.logging.Log;
import de.bixilon.minosoft.protocol.packets.ServerboundPacket;
import de.bixilon.minosoft.protocol.protocol.OutPacketBuffer;
import de.bixilon.minosoft.protocol.protocol.Packets;
import de.bixilon.minosoft.protocol.protocol.ProtocolVersion;
public class PacketSetDisplayedRecipe implements ServerboundPacket {
final Recipe recipe;
public PacketSetDisplayedRecipe(Recipe recipe) {
this.recipe = recipe;
}
@Override
public OutPacketBuffer write(ProtocolVersion version) {
OutPacketBuffer buffer = new OutPacketBuffer(version, version.getPacketCommand(Packets.Serverbound.PLAY_SET_DISPLAYED_RECIPE));
buffer.writeString(recipe.getResult().getItem().getMod() + ":" + recipe.getResult().getItem().getIdentifier());
return buffer;
}
@Override
public void log() {
Log.protocol(String.format("Sending set displayed recipe packet (identifier=%s:%s)", recipe.getResult().getItem().getMod(), recipe.getResult().getItem().getIdentifier()));
}
}

View File

@ -22,9 +22,12 @@ import de.bixilon.minosoft.protocol.protocol.ProtocolVersion;
public class PacketUpdateJigsawBlock implements ServerboundPacket { public class PacketUpdateJigsawBlock implements ServerboundPacket {
final BlockPosition position; final BlockPosition position;
final String attachmentType; String attachmentType;
final String targetPool; final String targetPool;
final String finalState; final String finalState;
String name;
String target;
String jointType;
public PacketUpdateJigsawBlock(BlockPosition position, String attachmentType, String targetPool, String finalState) { public PacketUpdateJigsawBlock(BlockPosition position, String attachmentType, String targetPool, String finalState) {
this.position = position; this.position = position;
@ -34,10 +37,31 @@ public class PacketUpdateJigsawBlock implements ServerboundPacket {
} }
public PacketUpdateJigsawBlock(BlockPosition position, String name, String target, String targetPool, String finalState, String jointType) {
this.position = position;
this.name = name;
this.target = target;
this.targetPool = targetPool;
this.finalState = finalState;
this.jointType = jointType;
}
@Override @Override
public OutPacketBuffer write(ProtocolVersion version) { public OutPacketBuffer write(ProtocolVersion version) {
OutPacketBuffer buffer = new OutPacketBuffer(version, version.getPacketCommand(Packets.Serverbound.PLAY_UPDATE_JIGSAW_BLOCK)); OutPacketBuffer buffer = new OutPacketBuffer(version, version.getPacketCommand(Packets.Serverbound.PLAY_UPDATE_JIGSAW_BLOCK));
buffer.writePosition(position); buffer.writePosition(position);
if (version.getVersionNumber() < ProtocolVersion.VERSION_1_16_2.getVersionNumber()) {
buffer.writeString(attachmentType);
buffer.writeString(targetPool);
buffer.writeString(finalState);
return buffer;
}
buffer.writeString(name);
buffer.writeString(target);
buffer.writeString(targetPool);
buffer.writeString(finalState);
buffer.writeString(jointType);
return buffer; return buffer;
} }

View File

@ -286,7 +286,7 @@ public class InByteBuffer {
// shouldn't be a subtag // shouldn't be a subtag
return new CompoundTag(false, this); return new CompoundTag(false, this);
} }
return readNBT(); return readNBT(type);
} }
public NBTTag readNBT(TagTypes tagType) { public NBTTag readNBT(TagTypes tagType) {

View File

@ -182,6 +182,10 @@ public class PacketHandler {
connection.getPlayer().setFood(pkg.getFood()); connection.getPlayer().setFood(pkg.getFood());
connection.getPlayer().setHealth(pkg.getHealth()); connection.getPlayer().setHealth(pkg.getHealth());
connection.getPlayer().setSaturation(pkg.getSaturation()); connection.getPlayer().setSaturation(pkg.getSaturation());
if (pkg.getHealth() <= 0.0F) {
// do respawn
connection.getSender().respawn();
}
} }
public void handle(PacketPluginMessageReceiving pkg) { public void handle(PacketPluginMessageReceiving pkg) {
@ -286,7 +290,7 @@ public class PacketHandler {
} }
public void handle(PacketEntityEquipment pkg) { public void handle(PacketEntityEquipment pkg) {
connection.getPlayer().getWorld().getEntity(pkg.getEntityId()).setEquipment(pkg.getSlot(), pkg.getData()); connection.getPlayer().getWorld().getEntity(pkg.getEntityId()).setEquipment(pkg.getSlots());
} }
public void handle(PacketBlockChange pkg) { public void handle(PacketBlockChange pkg) {
@ -303,6 +307,8 @@ public class PacketHandler {
} }
public void handle(PacketRespawn pkg) { public void handle(PacketRespawn pkg) {
// clear all chunks
connection.getPlayer().getWorld().getAllChunks().clear();
connection.getPlayer().getWorld().setDimension(pkg.getDimension()); connection.getPlayer().getWorld().setDimension(pkg.getDimension());
connection.getPlayer().setSpawnConfirmed(false); connection.getPlayer().setSpawnConfirmed(false);
connection.getPlayer().setGameMode(pkg.getGameMode()); connection.getPlayer().setGameMode(pkg.getGameMode());

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long