WIP, start integrating env attributes into dimension types

This commit is contained in:
booky committed 2025-12-08 00:39:16 +01:00
1 parent 5dd5de04a8
commit db647ba73a
4 files changed
+215 -2

No files matched your search

@@ -241,6 +241,10 @@ public class NBTCompound extends NBT {
return nbtByte != null ? nbtByte.getAsByte() != 0 : defaultValue;
}
public boolean getBooleanOrThrow(String string) {
return this.getTagOfTypeOrThrow(string, NBTNumber.class).getAsByte() != 0;
}
@Contract("_, _, !null, _ -> !null")
public <T> @Nullable T getOr(String key, NbtDecoder<T> decoder, @Nullable T def, PacketWrapper<?> wrapper) {
NBT tag = this.getTagOrNull(key);
@@ -92,6 +92,14 @@ public class EnvironmentAttributeMap {
return new EnvironmentAttributeMap(new HashMap<>(this.entries));
}
public <T> void set(EnvironmentAttribute<T> attribute, T value) {
this.set(attribute, value, AttributeModifier.override());
}
public <T, A> void set(EnvironmentAttribute<T> attribute, A value, AttributeModifier<T, A> modifier) {
this.entries.put(attribute, new Entry<>(value, modifier));
}
public <T> T applyToDefault(EnvironmentAttribute<T> attribute) {
return this.apply(attribute, attribute.getDefaultValue());
}
@@ -19,9 +19,12 @@
package com.github.retrooper.packetevents.protocol.world.dimension;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.mapper.CopyableEntity;
import com.github.retrooper.packetevents.protocol.mapper.DeepComparableEntity;
import com.github.retrooper.packetevents.protocol.mapper.MappedEntity;
import com.github.retrooper.packetevents.protocol.mapper.MappedEntityRefSet;
import com.github.retrooper.packetevents.protocol.mapper.MappedEntitySet;
import com.github.retrooper.packetevents.protocol.nbt.NBT;
import com.github.retrooper.packetevents.protocol.nbt.NBTByte;
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
@@ -32,8 +35,18 @@ import com.github.retrooper.packetevents.protocol.nbt.NBTLong;
import com.github.retrooper.packetevents.protocol.nbt.NBTNumber;
import com.github.retrooper.packetevents.protocol.nbt.NBTString;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.util.CodecNameable;
import com.github.retrooper.packetevents.protocol.util.NbtCodec;
import com.github.retrooper.packetevents.protocol.util.NbtCodecException;
import com.github.retrooper.packetevents.protocol.util.NbtCodecs;
import com.github.retrooper.packetevents.protocol.util.NbtMapCodec;
import com.github.retrooper.packetevents.protocol.world.attributes.EnvironmentAttributeMap;
import com.github.retrooper.packetevents.protocol.world.attributes.EnvironmentAttributes;
import com.github.retrooper.packetevents.protocol.world.attributes.timelines.Timeline;
import com.github.retrooper.packetevents.resources.ResourceLocation;
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
import org.jspecify.annotations.NullMarked;
@@ -42,14 +55,117 @@ import java.util.OptionalLong;
@NullMarked
public interface DimensionType extends MappedEntity, CopyableEntity<DimensionType>, DeepComparableEntity {
NbtCodec<DimensionType> CODEC = new NbtMapCodec<DimensionType>() {
@Override
public DimensionType decode(NBTCompound compound, PacketWrapper<?> wrapper) throws NbtCodecException {
boolean hasFixedTime;
Skybox skybox;
CardinalLight cardinalLight;
EnvironmentAttributeMap attributes;
MappedEntityRefSet<Timeline> timelines;
ServerVersion version = wrapper.getServerVersion();
if (version.isNewerThanOrEquals(ServerVersion.V_1_21_11)) {
hasFixedTime = compound.getBooleanOr("has_fixed_time", false);
skybox = compound.getOr("skybox", Skybox.CODEC, Skybox.OVERWORLD, wrapper);
cardinalLight = compound.getOr("cardinal_light", CardinalLight.CODEC, CardinalLight.DEFAULT, wrapper);
attributes = compound.getOr("attributes", EnvironmentAttributeMap.CODEC, EnvironmentAttributeMap.EMPTY, wrapper);
timelines = compound.getOr("timelines", MappedEntitySet::decodeRefSet, MappedEntitySet.createEmpty(), wrapper);
} else {
hasFixedTime = false;
skybox = Skybox.NONE;
cardinalLight = CardinalLight.DEFAULT;
attributes = EnvironmentAttributeMap.create();
timelines = MappedEntitySet.createEmpty();
}
double coordinateScale;
int minY = 0;
int height = 256;
NBT monsterSpawnLightLevel = null;
int monsterSpawnBlockLightLimit = 0;
if (version.isNewerThanOrEquals(ServerVersion.V_1_16_2)) {
coordinateScale = compound.getNumberTagOrThrow("coordinate_scale").getAsDouble();
if (version.isNewerThanOrEquals(ServerVersion.V_1_17)) {
minY = compound.getNumberTagOrThrow("min_y").getAsInt();
height = compound.getNumberTagOrThrow("height").getAsInt();
if (version.isNewerThanOrEquals(ServerVersion.V_1_19)) {
// TODO proper int provider decoding/encoding
monsterSpawnLightLevel = compound.getTagOrThrow("monster_spawn_light_level");
monsterSpawnBlockLightLimit = compound.getNumberTagOrThrow("monster_spawn_block_light_limit").getAsInt();
}
}
} else {
coordinateScale = compound.getBoolean("shrunk") ? 8d : 1d;
}
ResourceLocation effectsLocation = null;
OptionalLong fixedTime = OptionalLong.empty();
if (version.isOlderThan(ServerVersion.V_1_21_11)) {
Number fixedTimeNum = compound.getNumberTagValueOrNull("fixed_time");
if (fixedTimeNum != null) {
hasFixedTime = true;
fixedTime = OptionalLong.of(fixedTimeNum.longValue());
}
boolean ultrawarm = compound.getBoolean("ultrawarm");
boolean natural = compound.getBoolean("natural");
boolean bedWorking = compound.getBoolean("bed_works");
boolean respawnAnchorWorking = compound.getBoolean("respawn_anchor_works");
boolean piglinSafe = compound.getBoolean("piglin_safe");
boolean hasRaids = compound.getBoolean("has_raids");
if (version.isNewerThanOrEquals(ServerVersion.V_1_16_2)) {
effectsLocation = compound.getOrThrow("effects", ResourceLocation.CODEC, wrapper);
}
if (version.isNewerThanOrEquals(ServerVersion.V_1_21_6)) {
NBTNumber cloudHeightTag = compound.getNumberTagOrNull("cloud_height");
if (cloudHeightTag != null) {
attributes.set(EnvironmentAttributes.VISUAL_CLOUD_HEIGHT, cloudHeightTag.getAsFloat());
}
}
}
boolean hasSkylight = compound.getBooleanOrThrow("has_skylight");
boolean hasCeiling = compound.getBooleanOrThrow("has_ceiling");
int logicalHeight = compound.getNumberTagValueOrThrow("logical_height").intValue();
// TODO proper tag key decoding/encoding
String infiniburn = compound.getStringTagValueOrThrow("infiniburn");
float ambientLight = compound.getNumberTagValueOrThrow("ambient_light").floatValue();
// new
}
@Override
public void encode(NBTCompound compound, PacketWrapper<?> wrapper, DimensionType value) throws NbtCodecException {
}
}.codec;
/**
* @versions 1.21.11+
*/
boolean hasFixedTime();
/**
* @versions -1.21.10
*/
@ApiStatus.Obsolete
OptionalLong getFixedTime();
boolean hasSkyLight();
boolean hasCeiling();
/**
* @versions -1.21.10
*/
@ApiStatus.Obsolete
boolean isUltraWarm();
/**
* @versions -1.21.10
*/
@ApiStatus.Obsolete
boolean isNatural();
double getCoordinateScale();
@@ -58,20 +174,40 @@ public interface DimensionType extends MappedEntity, CopyableEntity<DimensionTyp
return this.getCoordinateScale() > 1d;
}
/**
* @versions -1.21.10
*/
@ApiStatus.Obsolete
boolean isBedWorking();
/**
* @versions -1.21.10
*/
@ApiStatus.Obsolete
boolean isRespawnAnchorWorking();
/**
* @versions 1.17+
*/
default int getMinY() {
return this.getMinY(PacketEvents.getAPI().getServerManager().getVersion().toClientVersion());
}
/**
* @versions 1.17+
*/
int getMinY(ClientVersion version);
/**
* @versions 1.17+
*/
default int getHeight() {
return this.getHeight(PacketEvents.getAPI().getServerManager().getVersion().toClientVersion());
}
/**
* @versions 1.17+
*/
int getHeight(ClientVersion version);
default int getLogicalHeight() {
@@ -82,23 +218,43 @@ public interface DimensionType extends MappedEntity, CopyableEntity<DimensionTyp
String getInfiniburnTag();
/**
* @versions 1.16.2-1.21.10
*/
@ApiStatus.Obsolete
ResourceLocation getEffectsLocation();
float getAmbientLight();
/**
* Added with 1.21.6
* @versions 1.21.6-1.21.10
*/
@ApiStatus.Obsolete
@Nullable Integer getCloudHeight();
// monster settings
/**
* @versions -1.21.10
*/
@ApiStatus.Obsolete
boolean isPiglinSafe();
/**
* @versions -1.21.10
*/
@ApiStatus.Obsolete
boolean hasRaids();
/**
* @versions 1.19+
*/
@ApiStatus.Experimental
NBT getMonsterSpawnLightLevel();
/**
* @versions 1.19+
*/
int getMonsterSpawnBlockLightLimit();
// conversion utilities
@@ -193,4 +349,49 @@ public interface DimensionType extends MappedEntity, CopyableEntity<DimensionTyp
}
return compound;
}
/**
* @versions 1.21.11+
*/
enum Skybox implements CodecNameable {
NONE("none"),
OVERWORLD("overworld"),
END("end"),
;
public static final NbtCodec<Skybox> CODEC = NbtCodecs.forEnum(values());
private final String name;
Skybox(String name) {
this.name = name;
}
@Override
public String getCodecName() {
return this.name;
}
}
enum CardinalLight implements CodecNameable {
DEFAULT("default"),
NETHER("nether"),
;
public static final NbtCodec<CardinalLight> CODEC = NbtCodecs.forEnum(values());
private final String name;
CardinalLight(String name) {
this.name = name;
}
@Override
public String getCodecName() {
return this.name;
}
}
}
@@ -94,7 +94,7 @@ public final class SynchronizedRegistriesHandler {
// packetevents ignores a few unimportant registries which aren't used anywhere else in the protocol:
// test_environment, test_instance
Stream.of(
new RegistryEntry<>(Biomes.getRegistry(), Biome::decode),
new RegistryEntry<>(Biomes.getRegistry(), Biome.CODEC),
new RegistryEntry<>(ChatTypes.getRegistry(), ChatType::decode),
new RegistryEntry<>(TrimPatterns.getRegistry(), (NbtEntryDecoder<TrimPattern>) TrimPattern::decode),
new RegistryEntry<>(TrimMaterials.getRegistry(), (NbtEntryDecoder<TrimMaterial>) TrimMaterial::decode),