diff --git a/examples/frameworkServer/DimensionCodec.snbt b/examples/frameworkServer/DimensionCodec.snbt index 44ea6d5..69072ab 100644 --- a/examples/frameworkServer/DimensionCodec.snbt +++ b/examples/frameworkServer/DimensionCodec.snbt @@ -22,6 +22,71 @@ ultrawarm: 0b, has_ceiling: 0b } + }, + { + name: "minecraft:overworld_caves", + id: 1, + element: { + piglin_safe: 0b, + natural: 1b, + ambient_light: 0.0f, + infiniburn: "minecraft:infiniburn_overworld", + respawn_anchor_works: 0b, + has_skylight: 1b, + bed_works: 1b, + effects: "minecraft:overworld", + has_raids: 1b, + min_y: 0, + height: 256, + logical_height: 256, + coordinate_scale: 1.0d, + ultrawarm: 0b, + has_ceiling: 1b + } + }, + { + name: "minecraft:the_nether", + id: 2, + element: { + piglin_safe: 1b, + natural: 0b, + ambient_light: 0.1f, + infiniburn: "minecraft:infiniburn_nether", + respawn_anchor_works: 1b, + has_skylight: 0b, + bed_works: 0b, + effects: "minecraft:the_nether", + fixed_time: 18000L, + has_raids: 0b, + min_y: 0, + height: 256, + logical_height: 128, + coordinate_scale: 8.0d, + ultrawarm: 1b, + has_ceiling: 1b + } + }, + { + name: "minecraft:the_end", + id: 3, + element: { + piglin_safe: 0b, + natural: 0b, + ambient_light: 0.0f, + infiniburn: "minecraft:infiniburn_end", + respawn_anchor_works: 0b, + has_skylight: 0b, + bed_works: 0b, + effects: "minecraft:the_end", + fixed_time: 6000L, + has_raids: 1b, + min_y: 0, + height: 256, + logical_height: 256, + coordinate_scale: 1.0d, + ultrawarm: 0b, + has_ceiling: 0b + } } ] }, diff --git a/net/packet/types.go b/net/packet/types.go index 0fe48d1..71c7b0b 100644 --- a/net/packet/types.go +++ b/net/packet/types.go @@ -3,11 +3,10 @@ package packet import ( "bytes" "errors" + "github.com/google/uuid" "io" "math" - "github.com/google/uuid" - "github.com/Tnze/go-mc/nbt" ) diff --git a/net/packet/util.go b/net/packet/util.go index aa69e56..f66e8ef 100644 --- a/net/packet/util.go +++ b/net/packet/util.go @@ -78,6 +78,20 @@ func (a Ary) ReadFrom(r io.Reader) (n int64, err error) { return n, err } +// Array return an Ary but handled the previous Length field +// +// Warning: unstable API, may change in later version +func Array(array interface{}) Field { + length := VarInt(reflect.ValueOf(array).Len()) + return Tuple{ + &length, + Ary{ + Len: &length, + Ary: array, + }, + } +} + type Opt struct { Has interface{} // Pointer of bool, or `func() bool` Field interface{} // FieldEncoder, FieldDecoder or both (Field) diff --git a/save/bitstorage.go b/save/bitstorage.go index c9e4f9c..4622d95 100644 --- a/save/bitstorage.go +++ b/save/bitstorage.go @@ -2,6 +2,8 @@ package save import ( "fmt" + pk "github.com/Tnze/go-mc/net/packet" + "io" "math" ) @@ -128,3 +130,41 @@ func (b *BitStorage) Longs() []uint64 { } return b.data } + +func (b *BitStorage) ReadFrom(r io.Reader) (int64, error) { + var Len pk.VarInt + n, err := Len.ReadFrom(r) + if err != nil { + return n, err + } + if cap(b.data) >= int(Len) { + b.data = b.data[:Len] + } else { + b.data = make([]uint64, Len) + } + var v pk.Long + for i := range b.data { + nn, err := v.ReadFrom(r) + n += nn + if err != nil { + return n, err + } + b.data[i] = uint64(v) + } + return n, nil +} + +func (b *BitStorage) WriteTo(w io.Writer) (int64, error) { + n, err := pk.VarInt(len(b.data)).WriteTo(w) + if err != nil { + return n, err + } + for _, v := range b.data { + nn, err := pk.Long(v).WriteTo(w) + n += nn + if err != nil { + return n, err + } + } + return n, nil +} diff --git a/save/palette.go b/save/palette.go index 8106e7e..6bf90f4 100644 --- a/save/palette.go +++ b/save/palette.go @@ -3,25 +3,76 @@ package save import ( "io" - "github.com/Tnze/go-mc/nbt" pk "github.com/Tnze/go-mc/net/packet" ) type BlockState interface { } +type PaletteContainer struct { + maps blockMaps + palette + BitStorage +} + +func (p *PaletteContainer) ReadFrom(r io.Reader) (n int64, err error) { + var bits pk.UnsignedByte + n, err = bits.ReadFrom(r) + if err != nil { + return + } + switch bits { + case 0: + // TODO: SingleValuePalette + case 1, 2, 3, 4: + p.palette = &linearPalette{ + onResize: nil, + maps: p.maps, + bits: 4, + } + case 5, 6, 7, 8: + // TODO: HashMapPalette + default: + // TODO: GlobalPalette + } + + nn, err := p.palette.ReadFrom(r) + n += nn + if err != nil { + return n, err + } + + nn, err = p.BitStorage.ReadFrom(r) + n += nn + if err != nil { + return n, err + } + return n, nil +} + +func (p *PaletteContainer) WriteTo(w io.Writer) (n int64, err error) { + return pk.Tuple{ + pk.UnsignedByte(p.bits), + p.palette, + p.BitStorage, + }.WriteTo(w) +} + type palette interface { - id(v BlockState) int - value(i int) BlockState pk.FieldEncoder pk.FieldDecoder - read(r nbt.DecoderReader) (int, error) + id(v BlockState) int + value(i int) BlockState +} + +type blockMaps interface { + getID(state BlockState) (id int) + getValue(id int) (state BlockState) } type linearPalette struct { onResize func(n int, v BlockState) int - sToID map[BlockState]int - idTos map[int]BlockState + maps blockMaps values []BlockState bits int } @@ -57,7 +108,7 @@ func (l *linearPalette) ReadFrom(r io.Reader) (n int64, err error) { } else { n += nn } - l.values[i] = l.idTos[int(value)] + l.values[i] = l.maps.getValue(int(value)) } return } @@ -67,7 +118,7 @@ func (l *linearPalette) WriteTo(w io.Writer) (n int64, err error) { return } for _, v := range l.values { - if nn, err := pk.VarInt(l.sToID[v]).WriteTo(w); err != nil { + if nn, err := pk.VarInt(l.maps.getID(v)).WriteTo(w); err != nil { return n + nn, err } else { n += nn @@ -76,6 +127,8 @@ func (l *linearPalette) WriteTo(w io.Writer) (n int64, err error) { return } -func (l *linearPalette) read(r nbt.DecoderReader) (int, error) { - panic("not implemented yet") +type hashMapPalette struct { + maps blockMaps + values map[int]BlockState + bits int } diff --git a/server/Dimension.snbt b/server/Dimension.snbt new file mode 100644 index 0000000..2b9092d --- /dev/null +++ b/server/Dimension.snbt @@ -0,0 +1,17 @@ +{ + piglin_safe: 0b, + natural: 1b, + ambient_light: 0.0f, + infiniburn: "minecraft:infiniburn_overworld", + respawn_anchor_works: 0b, + has_skylight: 1b, + bed_works: 1b, + effects: "minecraft:overworld", + has_raids: 1b, + min_y: 0, + height: 256, + logical_height: 256, + coordinate_scale: 1.0d, + ultrawarm: 0b, + has_ceiling: 0b +} \ No newline at end of file diff --git a/server/DimensionCodec.snbt b/server/DimensionCodec.snbt new file mode 100644 index 0000000..69072ab --- /dev/null +++ b/server/DimensionCodec.snbt @@ -0,0 +1,2093 @@ +{ + "minecraft:dimension_type": { + type: "minecraft:dimension_type", + value: [ + { + name: "minecraft:overworld", + id: 0, + element: { + piglin_safe: 0b, + natural: 1b, + ambient_light: 0.0f, + infiniburn: "minecraft:infiniburn_overworld", + respawn_anchor_works: 0b, + has_skylight: 1b, + bed_works: 1b, + effects: "minecraft:overworld", + has_raids: 1b, + min_y: 0, + height: 256, + logical_height: 256, + coordinate_scale: 1.0d, + ultrawarm: 0b, + has_ceiling: 0b + } + }, + { + name: "minecraft:overworld_caves", + id: 1, + element: { + piglin_safe: 0b, + natural: 1b, + ambient_light: 0.0f, + infiniburn: "minecraft:infiniburn_overworld", + respawn_anchor_works: 0b, + has_skylight: 1b, + bed_works: 1b, + effects: "minecraft:overworld", + has_raids: 1b, + min_y: 0, + height: 256, + logical_height: 256, + coordinate_scale: 1.0d, + ultrawarm: 0b, + has_ceiling: 1b + } + }, + { + name: "minecraft:the_nether", + id: 2, + element: { + piglin_safe: 1b, + natural: 0b, + ambient_light: 0.1f, + infiniburn: "minecraft:infiniburn_nether", + respawn_anchor_works: 1b, + has_skylight: 0b, + bed_works: 0b, + effects: "minecraft:the_nether", + fixed_time: 18000L, + has_raids: 0b, + min_y: 0, + height: 256, + logical_height: 128, + coordinate_scale: 8.0d, + ultrawarm: 1b, + has_ceiling: 1b + } + }, + { + name: "minecraft:the_end", + id: 3, + element: { + piglin_safe: 0b, + natural: 0b, + ambient_light: 0.0f, + infiniburn: "minecraft:infiniburn_end", + respawn_anchor_works: 0b, + has_skylight: 0b, + bed_works: 0b, + effects: "minecraft:the_end", + fixed_time: 6000L, + has_raids: 1b, + min_y: 0, + height: 256, + logical_height: 256, + coordinate_scale: 1.0d, + ultrawarm: 0b, + has_ceiling: 0b + } + } + ] + }, + "minecraft:worldgen/biome": { + type: "minecraft:worldgen/biome", + value: [ + { + name: "minecraft:ocean", + id: 0, + element: { + precipitation: "rain", + effects: { + sky_color: 8103167, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: -1.0f, + temperature: 0.5f, + scale: 0.1f, + downfall: 0.5f, + category: "ocean" + } + }, + { + name: "minecraft:plains", + id: 1, + element: { + precipitation: "rain", + effects: { + sky_color: 7907327, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 0.125f, + temperature: 0.8f, + scale: 0.05f, + downfall: 0.4f, + category: "plains" + } + }, + { + name: "minecraft:desert", + id: 2, + element: { + precipitation: "none", + effects: { + sky_color: 7254527, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 0.125f, + temperature: 2.0f, + scale: 0.05f, + downfall: 0.0f, + category: "desert" + } + }, + { + name: "minecraft:mountains", + id: 3, + element: { + precipitation: "rain", + effects: { + sky_color: 8233727, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 1.0f, + temperature: 0.2f, + scale: 0.5f, + downfall: 0.3f, + category: "extreme_hills" + } + }, + { + name: "minecraft:forest", + id: 4, + element: { + precipitation: "rain", + effects: { + sky_color: 7972607, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 0.1f, + temperature: 0.7f, + scale: 0.2f, + downfall: 0.8f, + category: "forest" + } + }, + { + name: "minecraft:taiga", + id: 5, + element: { + precipitation: "rain", + effects: { + sky_color: 8233983, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 0.2f, + temperature: 0.25f, + scale: 0.2f, + downfall: 0.8f, + category: "taiga" + } + }, + { + name: "minecraft:swamp", + id: 6, + element: { + precipitation: "rain", + effects: { + grass_color_modifier: "swamp", + sky_color: 7907327, + foliage_color: 6975545, + water_fog_color: 2302743, + fog_color: 12638463, + water_color: 6388580, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: -0.2f, + temperature: 0.8f, + scale: 0.1f, + downfall: 0.9f, + category: "swamp" + } + }, + { + name: "minecraft:river", + id: 7, + element: { + precipitation: "rain", + effects: { + sky_color: 8103167, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: -0.5f, + temperature: 0.5f, + scale: 0.0f, + downfall: 0.5f, + category: "river" + } + }, + { + name: "minecraft:nether_wastes", + id: 8, + element: { + precipitation: "none", + effects: { + music: { + replace_current_music: 0b, + max_delay: 24000, + sound: "minecraft:music.nether.nether_wastes", + min_delay: 12000 + }, + sky_color: 7254527, + ambient_sound: "minecraft:ambient.nether_wastes.loop", + additions_sound: { + sound: "minecraft:ambient.nether_wastes.additions", + tick_chance: 0.0111d + }, + water_fog_color: 329011, + fog_color: 3344392, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.nether_wastes.mood", + block_search_extent: 8 + } + }, + depth: 0.1f, + temperature: 2.0f, + scale: 0.2f, + downfall: 0.0f, + category: "nether" + } + }, + { + name: "minecraft:the_end", + id: 9, + element: { + precipitation: "none", + effects: { + sky_color: 0, + water_fog_color: 329011, + fog_color: 10518688, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 0.1f, + temperature: 0.5f, + scale: 0.2f, + downfall: 0.5f, + category: "the_end" + } + }, + { + name: "minecraft:frozen_ocean", + id: 10, + element: { + precipitation: "snow", + effects: { + sky_color: 8364543, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 3750089, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: -1.0f, + temperature: 0.0f, + scale: 0.1f, + downfall: 0.5f, + category: "ocean", + temperature_modifier: "frozen" + } + }, + { + name: "minecraft:frozen_river", + id: 11, + element: { + precipitation: "snow", + effects: { + sky_color: 8364543, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 3750089, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: -0.5f, + temperature: 0.0f, + scale: 0.0f, + downfall: 0.5f, + category: "river" + } + }, + { + name: "minecraft:snowy_tundra", + id: 12, + element: { + precipitation: "snow", + effects: { + sky_color: 8364543, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 0.125f, + temperature: 0.0f, + scale: 0.05f, + downfall: 0.5f, + category: "icy" + } + }, + { + name: "minecraft:snowy_mountains", + id: 13, + element: { + precipitation: "snow", + effects: { + sky_color: 8364543, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 0.45f, + temperature: 0.0f, + scale: 0.3f, + downfall: 0.5f, + category: "icy" + } + }, + { + name: "minecraft:mushroom_fields", + id: 14, + element: { + precipitation: "rain", + effects: { + sky_color: 7842047, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 0.2f, + temperature: 0.9f, + scale: 0.3f, + downfall: 1.0f, + category: "mushroom" + } + }, + { + name: "minecraft:mushroom_field_shore", + id: 15, + element: { + precipitation: "rain", + effects: { + sky_color: 7842047, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 0.0f, + temperature: 0.9f, + scale: 0.025f, + downfall: 1.0f, + category: "mushroom" + } + }, + { + name: "minecraft:beach", + id: 16, + element: { + precipitation: "rain", + effects: { + sky_color: 7907327, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 0.0f, + temperature: 0.8f, + scale: 0.025f, + downfall: 0.4f, + category: "beach" + } + }, + { + name: "minecraft:desert_hills", + id: 17, + element: { + precipitation: "none", + effects: { + sky_color: 7254527, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 0.45f, + temperature: 2.0f, + scale: 0.3f, + downfall: 0.0f, + category: "desert" + } + }, + { + name: "minecraft:wooded_hills", + id: 18, + element: { + precipitation: "rain", + effects: { + sky_color: 7972607, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 0.45f, + temperature: 0.7f, + scale: 0.3f, + downfall: 0.8f, + category: "forest" + } + }, + { + name: "minecraft:taiga_hills", + id: 19, + element: { + precipitation: "rain", + effects: { + sky_color: 8233983, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 0.45f, + temperature: 0.25f, + scale: 0.3f, + downfall: 0.8f, + category: "taiga" + } + }, + { + name: "minecraft:mountain_edge", + id: 20, + element: { + precipitation: "rain", + effects: { + sky_color: 8233727, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 0.8f, + temperature: 0.2f, + scale: 0.3f, + downfall: 0.3f, + category: "extreme_hills" + } + }, + { + name: "minecraft:jungle", + id: 21, + element: { + precipitation: "rain", + effects: { + sky_color: 7842047, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 0.1f, + temperature: 0.95f, + scale: 0.2f, + downfall: 0.9f, + category: "jungle" + } + }, + { + name: "minecraft:jungle_hills", + id: 22, + element: { + precipitation: "rain", + effects: { + sky_color: 7842047, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 0.45f, + temperature: 0.95f, + scale: 0.3f, + downfall: 0.9f, + category: "jungle" + } + }, + { + name: "minecraft:jungle_edge", + id: 23, + element: { + precipitation: "rain", + effects: { + sky_color: 7842047, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 0.1f, + temperature: 0.95f, + scale: 0.2f, + downfall: 0.8f, + category: "jungle" + } + }, + { + name: "minecraft:deep_ocean", + id: 24, + element: { + precipitation: "rain", + effects: { + sky_color: 8103167, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: -1.8f, + temperature: 0.5f, + scale: 0.1f, + downfall: 0.5f, + category: "ocean" + } + }, + { + name: "minecraft:stone_shore", + id: 25, + element: { + precipitation: "rain", + effects: { + sky_color: 8233727, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 0.1f, + temperature: 0.2f, + scale: 0.8f, + downfall: 0.3f, + category: "none" + } + }, + { + name: "minecraft:snowy_beach", + id: 26, + element: { + precipitation: "snow", + effects: { + sky_color: 8364543, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4020182, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 0.0f, + temperature: 0.05f, + scale: 0.025f, + downfall: 0.3f, + category: "beach" + } + }, + { + name: "minecraft:birch_forest", + id: 27, + element: { + precipitation: "rain", + effects: { + sky_color: 8037887, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 0.1f, + temperature: 0.6f, + scale: 0.2f, + downfall: 0.6f, + category: "forest" + } + }, + { + name: "minecraft:birch_forest_hills", + id: 28, + element: { + precipitation: "rain", + effects: { + sky_color: 8037887, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 0.45f, + temperature: 0.6f, + scale: 0.3f, + downfall: 0.6f, + category: "forest" + } + }, + { + name: "minecraft:dark_forest", + id: 29, + element: { + precipitation: "rain", + effects: { + grass_color_modifier: "dark_forest", + sky_color: 7972607, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 0.1f, + temperature: 0.7f, + scale: 0.2f, + downfall: 0.8f, + category: "forest" + } + }, + { + name: "minecraft:snowy_taiga", + id: 30, + element: { + precipitation: "snow", + effects: { + sky_color: 8625919, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4020182, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 0.2f, + temperature: -0.5f, + scale: 0.2f, + downfall: 0.4f, + category: "taiga" + } + }, + { + name: "minecraft:snowy_taiga_hills", + id: 31, + element: { + precipitation: "snow", + effects: { + sky_color: 8625919, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4020182, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 0.45f, + temperature: -0.5f, + scale: 0.3f, + downfall: 0.4f, + category: "taiga" + } + }, + { + name: "minecraft:giant_tree_taiga", + id: 32, + element: { + precipitation: "rain", + effects: { + sky_color: 8168447, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 0.2f, + temperature: 0.3f, + scale: 0.2f, + downfall: 0.8f, + category: "taiga" + } + }, + { + name: "minecraft:giant_tree_taiga_hills", + id: 33, + element: { + precipitation: "rain", + effects: { + sky_color: 8168447, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 0.45f, + temperature: 0.3f, + scale: 0.3f, + downfall: 0.8f, + category: "taiga" + } + }, + { + name: "minecraft:wooded_mountains", + id: 34, + element: { + precipitation: "rain", + effects: { + sky_color: 8233727, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 1.0f, + temperature: 0.2f, + scale: 0.5f, + downfall: 0.3f, + category: "extreme_hills" + } + }, + { + name: "minecraft:savanna", + id: 35, + element: { + precipitation: "none", + effects: { + sky_color: 7711487, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 0.125f, + temperature: 1.2f, + scale: 0.05f, + downfall: 0.0f, + category: "savanna" + } + }, + { + name: "minecraft:savanna_plateau", + id: 36, + element: { + precipitation: "none", + effects: { + sky_color: 7776511, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 1.5f, + temperature: 1.0f, + scale: 0.025f, + downfall: 0.0f, + category: "savanna" + } + }, + { + name: "minecraft:badlands", + id: 37, + element: { + precipitation: "none", + effects: { + sky_color: 7254527, + grass_color: 9470285, + foliage_color: 10387789, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 0.1f, + temperature: 2.0f, + scale: 0.2f, + downfall: 0.0f, + category: "mesa" + } + }, + { + name: "minecraft:wooded_badlands_plateau", + id: 38, + element: { + precipitation: "none", + effects: { + sky_color: 7254527, + grass_color: 9470285, + foliage_color: 10387789, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 1.5f, + temperature: 2.0f, + scale: 0.025f, + downfall: 0.0f, + category: "mesa" + } + }, + { + name: "minecraft:badlands_plateau", + id: 39, + element: { + precipitation: "none", + effects: { + sky_color: 7254527, + grass_color: 9470285, + foliage_color: 10387789, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 1.5f, + temperature: 2.0f, + scale: 0.025f, + downfall: 0.0f, + category: "mesa" + } + }, + { + name: "minecraft:small_end_islands", + id: 40, + element: { + precipitation: "none", + effects: { + sky_color: 0, + water_fog_color: 329011, + fog_color: 10518688, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 0.1f, + temperature: 0.5f, + scale: 0.2f, + downfall: 0.5f, + category: "the_end" + } + }, + { + name: "minecraft:end_midlands", + id: 41, + element: { + precipitation: "none", + effects: { + sky_color: 0, + water_fog_color: 329011, + fog_color: 10518688, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 0.1f, + temperature: 0.5f, + scale: 0.2f, + downfall: 0.5f, + category: "the_end" + } + }, + { + name: "minecraft:end_highlands", + id: 42, + element: { + precipitation: "none", + effects: { + sky_color: 0, + water_fog_color: 329011, + fog_color: 10518688, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 0.1f, + temperature: 0.5f, + scale: 0.2f, + downfall: 0.5f, + category: "the_end" + } + }, + { + name: "minecraft:end_barrens", + id: 43, + element: { + precipitation: "none", + effects: { + sky_color: 0, + water_fog_color: 329011, + fog_color: 10518688, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 0.1f, + temperature: 0.5f, + scale: 0.2f, + downfall: 0.5f, + category: "the_end" + } + }, + { + name: "minecraft:warm_ocean", + id: 44, + element: { + precipitation: "rain", + effects: { + sky_color: 8103167, + water_fog_color: 270131, + fog_color: 12638463, + water_color: 4445678, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: -1.0f, + temperature: 0.5f, + scale: 0.1f, + downfall: 0.5f, + category: "ocean" + } + }, + { + name: "minecraft:lukewarm_ocean", + id: 45, + element: { + precipitation: "rain", + effects: { + sky_color: 8103167, + water_fog_color: 267827, + fog_color: 12638463, + water_color: 4566514, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: -1.0f, + temperature: 0.5f, + scale: 0.1f, + downfall: 0.5f, + category: "ocean" + } + }, + { + name: "minecraft:cold_ocean", + id: 46, + element: { + precipitation: "rain", + effects: { + sky_color: 8103167, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4020182, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: -1.0f, + temperature: 0.5f, + scale: 0.1f, + downfall: 0.5f, + category: "ocean" + } + }, + { + name: "minecraft:deep_warm_ocean", + id: 47, + element: { + precipitation: "rain", + effects: { + sky_color: 8103167, + water_fog_color: 270131, + fog_color: 12638463, + water_color: 4445678, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: -1.8f, + temperature: 0.5f, + scale: 0.1f, + downfall: 0.5f, + category: "ocean" + } + }, + { + name: "minecraft:deep_lukewarm_ocean", + id: 48, + element: { + precipitation: "rain", + effects: { + sky_color: 8103167, + water_fog_color: 267827, + fog_color: 12638463, + water_color: 4566514, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: -1.8f, + temperature: 0.5f, + scale: 0.1f, + downfall: 0.5f, + category: "ocean" + } + }, + { + name: "minecraft:deep_cold_ocean", + id: 49, + element: { + precipitation: "rain", + effects: { + sky_color: 8103167, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4020182, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: -1.8f, + temperature: 0.5f, + scale: 0.1f, + downfall: 0.5f, + category: "ocean" + } + }, + { + name: "minecraft:deep_frozen_ocean", + id: 50, + element: { + precipitation: "rain", + effects: { + sky_color: 8103167, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 3750089, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: -1.8f, + temperature: 0.5f, + scale: 0.1f, + downfall: 0.5f, + category: "ocean", + temperature_modifier: "frozen" + } + }, + { + name: "minecraft:the_void", + id: 127, + element: { + precipitation: "none", + effects: { + sky_color: 8103167, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 0.1f, + temperature: 0.5f, + scale: 0.2f, + downfall: 0.5f, + category: "none" + } + }, + { + name: "minecraft:sunflower_plains", + id: 129, + element: { + precipitation: "rain", + effects: { + sky_color: 7907327, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 0.125f, + temperature: 0.8f, + scale: 0.05f, + downfall: 0.4f, + category: "plains" + } + }, + { + name: "minecraft:desert_lakes", + id: 130, + element: { + precipitation: "none", + effects: { + sky_color: 7254527, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 0.225f, + temperature: 2.0f, + scale: 0.25f, + downfall: 0.0f, + category: "desert" + } + }, + { + name: "minecraft:gravelly_mountains", + id: 131, + element: { + precipitation: "rain", + effects: { + sky_color: 8233727, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 1.0f, + temperature: 0.2f, + scale: 0.5f, + downfall: 0.3f, + category: "extreme_hills" + } + }, + { + name: "minecraft:flower_forest", + id: 132, + element: { + precipitation: "rain", + effects: { + sky_color: 7972607, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 0.1f, + temperature: 0.7f, + scale: 0.4f, + downfall: 0.8f, + category: "forest" + } + }, + { + name: "minecraft:taiga_mountains", + id: 133, + element: { + precipitation: "rain", + effects: { + sky_color: 8233983, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 0.3f, + temperature: 0.25f, + scale: 0.4f, + downfall: 0.8f, + category: "taiga" + } + }, + { + name: "minecraft:swamp_hills", + id: 134, + element: { + precipitation: "rain", + effects: { + grass_color_modifier: "swamp", + sky_color: 7907327, + foliage_color: 6975545, + water_fog_color: 2302743, + fog_color: 12638463, + water_color: 6388580, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: -0.1f, + temperature: 0.8f, + scale: 0.3f, + downfall: 0.9f, + category: "swamp" + } + }, + { + name: "minecraft:ice_spikes", + id: 140, + element: { + precipitation: "snow", + effects: { + sky_color: 8364543, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 0.425f, + temperature: 0.0f, + scale: 0.45000002f, + downfall: 0.5f, + category: "icy" + } + }, + { + name: "minecraft:modified_jungle", + id: 149, + element: { + precipitation: "rain", + effects: { + sky_color: 7842047, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 0.2f, + temperature: 0.95f, + scale: 0.4f, + downfall: 0.9f, + category: "jungle" + } + }, + { + name: "minecraft:modified_jungle_edge", + id: 151, + element: { + precipitation: "rain", + effects: { + sky_color: 7842047, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 0.2f, + temperature: 0.95f, + scale: 0.4f, + downfall: 0.8f, + category: "jungle" + } + }, + { + name: "minecraft:tall_birch_forest", + id: 155, + element: { + precipitation: "rain", + effects: { + sky_color: 8037887, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 0.2f, + temperature: 0.6f, + scale: 0.4f, + downfall: 0.6f, + category: "forest" + } + }, + { + name: "minecraft:tall_birch_hills", + id: 156, + element: { + precipitation: "rain", + effects: { + sky_color: 8037887, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 0.55f, + temperature: 0.6f, + scale: 0.5f, + downfall: 0.6f, + category: "forest" + } + }, + { + name: "minecraft:dark_forest_hills", + id: 157, + element: { + precipitation: "rain", + effects: { + grass_color_modifier: "dark_forest", + sky_color: 7972607, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 0.2f, + temperature: 0.7f, + scale: 0.4f, + downfall: 0.8f, + category: "forest" + } + }, + { + name: "minecraft:snowy_taiga_mountains", + id: 158, + element: { + precipitation: "snow", + effects: { + sky_color: 8625919, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4020182, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 0.3f, + temperature: -0.5f, + scale: 0.4f, + downfall: 0.4f, + category: "taiga" + } + }, + { + name: "minecraft:giant_spruce_taiga", + id: 160, + element: { + precipitation: "rain", + effects: { + sky_color: 8233983, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 0.2f, + temperature: 0.25f, + scale: 0.2f, + downfall: 0.8f, + category: "taiga" + } + }, + { + name: "minecraft:giant_spruce_taiga_hills", + id: 161, + element: { + precipitation: "rain", + effects: { + sky_color: 8233983, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 0.2f, + temperature: 0.25f, + scale: 0.2f, + downfall: 0.8f, + category: "taiga" + } + }, + { + name: "minecraft:modified_gravelly_mountains", + id: 162, + element: { + precipitation: "rain", + effects: { + sky_color: 8233727, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 1.0f, + temperature: 0.2f, + scale: 0.5f, + downfall: 0.3f, + category: "extreme_hills" + } + }, + { + name: "minecraft:shattered_savanna", + id: 163, + element: { + precipitation: "none", + effects: { + sky_color: 7776767, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 0.3625f, + temperature: 1.1f, + scale: 1.225f, + downfall: 0.0f, + category: "savanna" + } + }, + { + name: "minecraft:shattered_savanna_plateau", + id: 164, + element: { + precipitation: "none", + effects: { + sky_color: 7776511, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 1.05f, + temperature: 1.0f, + scale: 1.2125001f, + downfall: 0.0f, + category: "savanna" + } + }, + { + name: "minecraft:eroded_badlands", + id: 165, + element: { + precipitation: "none", + effects: { + sky_color: 7254527, + grass_color: 9470285, + foliage_color: 10387789, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 0.1f, + temperature: 2.0f, + scale: 0.2f, + downfall: 0.0f, + category: "mesa" + } + }, + { + name: "minecraft:modified_wooded_badlands_plateau", + id: 166, + element: { + precipitation: "none", + effects: { + sky_color: 7254527, + grass_color: 9470285, + foliage_color: 10387789, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 0.45f, + temperature: 2.0f, + scale: 0.3f, + downfall: 0.0f, + category: "mesa" + } + }, + { + name: "minecraft:modified_badlands_plateau", + id: 167, + element: { + precipitation: "none", + effects: { + sky_color: 7254527, + grass_color: 9470285, + foliage_color: 10387789, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 0.45f, + temperature: 2.0f, + scale: 0.3f, + downfall: 0.0f, + category: "mesa" + } + }, + { + name: "minecraft:bamboo_jungle", + id: 168, + element: { + precipitation: "rain", + effects: { + sky_color: 7842047, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 0.1f, + temperature: 0.95f, + scale: 0.2f, + downfall: 0.9f, + category: "jungle" + } + }, + { + name: "minecraft:bamboo_jungle_hills", + id: 169, + element: { + precipitation: "rain", + effects: { + sky_color: 7842047, + water_fog_color: 329011, + fog_color: 12638463, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.cave", + block_search_extent: 8 + } + }, + depth: 0.45f, + temperature: 0.95f, + scale: 0.3f, + downfall: 0.9f, + category: "jungle" + } + }, + { + name: "minecraft:soul_sand_valley", + id: 170, + element: { + precipitation: "none", + effects: { + music: { + replace_current_music: 0b, + max_delay: 24000, + sound: "minecraft:music.nether.soul_sand_valley", + min_delay: 12000 + }, + sky_color: 7254527, + ambient_sound: "minecraft:ambient.soul_sand_valley.loop", + additions_sound: { + sound: "minecraft:ambient.soul_sand_valley.additions", + tick_chance: 0.0111d + }, + particle: { + probability: 0.00625f, + options: { + type: "minecraft:ash" + } + }, + water_fog_color: 329011, + fog_color: 1787717, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.soul_sand_valley.mood", + block_search_extent: 8 + } + }, + depth: 0.1f, + temperature: 2.0f, + scale: 0.2f, + downfall: 0.0f, + category: "nether" + } + }, + { + name: "minecraft:crimson_forest", + id: 171, + element: { + precipitation: "none", + effects: { + music: { + replace_current_music: 0b, + max_delay: 24000, + sound: "minecraft:music.nether.crimson_forest", + min_delay: 12000 + }, + sky_color: 7254527, + ambient_sound: "minecraft:ambient.crimson_forest.loop", + additions_sound: { + sound: "minecraft:ambient.crimson_forest.additions", + tick_chance: 0.0111d + }, + particle: { + probability: 0.025f, + options: { + type: "minecraft:crimson_spore" + } + }, + water_fog_color: 329011, + fog_color: 3343107, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.crimson_forest.mood", + block_search_extent: 8 + } + }, + depth: 0.1f, + temperature: 2.0f, + scale: 0.2f, + downfall: 0.0f, + category: "nether" + } + }, + { + name: "minecraft:warped_forest", + id: 172, + element: { + precipitation: "none", + effects: { + music: { + replace_current_music: 0b, + max_delay: 24000, + sound: "minecraft:music.nether.warped_forest", + min_delay: 12000 + }, + sky_color: 7254527, + ambient_sound: "minecraft:ambient.warped_forest.loop", + additions_sound: { + sound: "minecraft:ambient.warped_forest.additions", + tick_chance: 0.0111d + }, + particle: { + probability: 0.01428f, + options: { + type: "minecraft:warped_spore" + } + }, + water_fog_color: 329011, + fog_color: 1705242, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.warped_forest.mood", + block_search_extent: 8 + } + }, + depth: 0.1f, + temperature: 2.0f, + scale: 0.2f, + downfall: 0.0f, + category: "nether" + } + }, + { + name: "minecraft:basalt_deltas", + id: 173, + element: { + precipitation: "none", + effects: { + music: { + replace_current_music: 0b, + max_delay: 24000, + sound: "minecraft:music.nether.basalt_deltas", + min_delay: 12000 + }, + sky_color: 7254527, + ambient_sound: "minecraft:ambient.basalt_deltas.loop", + additions_sound: { + sound: "minecraft:ambient.basalt_deltas.additions", + tick_chance: 0.0111d + }, + particle: { + probability: 0.118093334f, + options: { + type: "minecraft:white_ash" + } + }, + water_fog_color: 4341314, + fog_color: 6840176, + water_color: 4159204, + mood_sound: { + tick_delay: 6000, + offset: 2.0d, + sound: "minecraft:ambient.basalt_deltas.mood", + block_search_extent: 8 + } + }, + depth: 0.1f, + temperature: 2.0f, + scale: 0.2f, + downfall: 0.0f, + category: "nether" + } + } + ] + } +} \ No newline at end of file diff --git a/server/dimension.go b/server/dimension.go new file mode 100644 index 0000000..203931e --- /dev/null +++ b/server/dimension.go @@ -0,0 +1,104 @@ +package server + +import ( + "bytes" + "github.com/Tnze/go-mc/data/packetid" + pk "github.com/Tnze/go-mc/net/packet" + "github.com/Tnze/go-mc/save" + "io" + "sync" +) + +type Dimension interface { + Info() DimInfo + PlayerJoin(p *Player) + PlayerQuit(p *Player) +} + +type DimInfo struct { + Name string + HashedSeed uint64 +} + +type SimpleDim struct { + Columns map[struct{ X, Z int }]*struct { + sync.Mutex + } +} + +type chunkData struct { + HeightMaps save.BitStorage + BlockState save.BitStorage + Biomes save.BitStorage +} + +func (c *chunkData) WriteTo(w io.Writer) (int64, error) { + return pk.Tuple{ + // Heightmaps + pk.NBT(struct { + MotionBlocking []uint64 `nbt:"MOTION_BLOCKING"` + }{c.HeightMaps.Longs()}), + pk.ByteArray(c.Data()), // TODO: Chunk Data + pk.VarInt(0), // TODO: Block Entity + }.WriteTo(w) +} + +func (c *chunkData) Data() []byte { + var buff bytes.Buffer + _, _ = pk.Short(0).WriteTo(&buff) + return buff.Bytes() +} + +type lightData struct { + SkyLightMask pk.BitSet + BlockLightMask pk.BitSet + SkyLight []pk.ByteArray + BlockLight []pk.ByteArray +} + +func bitSetRev(set pk.BitSet) pk.BitSet { + rev := make(pk.BitSet, len(set)) + for i := range rev { + rev[i] = ^set[i] + } + return rev +} + +func (l *lightData) WriteTo(w io.Writer) (int64, error) { + return pk.Tuple{ + pk.Boolean(true), // Trust Edges + l.SkyLightMask, + l.BlockLightMask, + bitSetRev(l.SkyLightMask), + bitSetRev(l.BlockLightMask), + pk.Array(l.SkyLight), + pk.Array(l.BlockLight), + }.WriteTo(w) +} + +func (s *SimpleDim) PlayerJoin(p *Player) { + for pos, column := range s.Columns { + column.Lock() + packet := pk.Marshal( + packetid.ClientboundLevelChunkWithLight, + pk.Int(pos.X), pk.Int(pos.Z), + &chunkData{}, + &lightData{ + SkyLightMask: make(pk.BitSet, (16*16*16-1)>>6+1), + BlockLightMask: make(pk.BitSet, (16*16*16-1)>>6+1), + SkyLight: []pk.ByteArray{}, + BlockLight: []pk.ByteArray{}, + }, + ) + column.Unlock() + + err := p.WritePacket(Packet757(packet)) + if err != nil { + return + } + } +} + +func (s *SimpleDim) PlayerQuit(p *Player) { + +} diff --git a/server/gameplay.go b/server/gameplay.go index efccff1..8c4a955 100644 --- a/server/gameplay.go +++ b/server/gameplay.go @@ -1,8 +1,15 @@ package server import ( - "github.com/Tnze/go-mc/net" + _ "embed" + "github.com/Tnze/go-mc/nbt" + "sync/atomic" + "github.com/google/uuid" + + "github.com/Tnze/go-mc/data/packetid" + "github.com/Tnze/go-mc/net" + pk "github.com/Tnze/go-mc/net/packet" ) type GamePlay interface { @@ -12,3 +19,50 @@ type GamePlay interface { // You don't need to close the connection, but to keep not returning while the player is playing. AcceptPlayer(name string, id uuid.UUID, protocol int32, conn *net.Conn) } + +type Game struct { + eid int32 + Dim Dimension +} + +//go:embed DimensionCodec.snbt +var dimensionCodecSNBT string + +//go:embed Dimension.snbt +var dimensionSNBT string + +func (g *Game) AcceptPlayer(name string, id uuid.UUID, protocol int32, conn *net.Conn) { + p := &Player{ + Conn: conn, + EntityID: g.newEID(), + Gamemode: 1, + } + dimInfo := g.Dim.Info() + err := p.WritePacket(Packet757(pk.Marshal( + packetid.ClientboundLogin, + pk.Int(p.EntityID), // Entity ID + pk.Boolean(false), // Is hardcore + pk.Byte(p.Gamemode), // Gamemode + pk.Byte(-1), // Prev Gamemode + pk.Array([]pk.Identifier{pk.Identifier(dimInfo.Name)}), + pk.NBT(nbt.StringifiedMessage(dimensionCodecSNBT)), + pk.NBT(nbt.StringifiedMessage(dimensionSNBT)), + pk.Identifier(dimInfo.Name), // World Name + pk.Long(dimInfo.HashedSeed), // Hashed seed + pk.VarInt(0), // Max Players (Ignored by client) + pk.VarInt(15), // View Distance + pk.VarInt(15), // Simulation Distance + pk.Boolean(false), // Reduced Debug Info + pk.Boolean(true), // Enable respawn screen + pk.Boolean(false), // Is Debug + pk.Boolean(true), // Is Flat + ))) + if err != nil { + return + } + g.Dim.PlayerJoin(p) +} + +func (g *Game) newEID() int32 { + return atomic.AddInt32(&g.eid, 1) +} diff --git a/server/login.go b/server/login.go index 5defdb1..8c40808 100644 --- a/server/login.go +++ b/server/login.go @@ -20,10 +20,10 @@ type LoginHandler interface { } // LoginChecker is the interface to check if a player is allowed to log in the server. -// The checking could be anything, server player number, blacklist or whitelist. +// The checking could be anything, server player number, protocol version, blacklist or whitelist. // If a player is not allowed to, the reason should be returned and will be sent to client by "LoginDisconnect" packet. type LoginChecker interface { - CheckPlayer(name string, id uuid.UUID) (ok bool, reason chat.Message) + CheckPlayer(name string, id uuid.UUID, protocol int32) (ok bool, reason chat.Message) } // MojangLoginHandler is a standard LoginHandler that implement both online and offline login progress. @@ -92,7 +92,7 @@ func (d *MojangLoginHandler) AcceptLogin(conn *net.Conn, protocol int32) (name s // check if player can join (whitelist, blacklist, server full or something else) if d.LoginChecker != nil { - if ok, result := d.CheckPlayer(name, id); !ok { + if ok, result := d.CheckPlayer(name, id, protocol); !ok { // player is not allowed to join the server err = conn.WritePacket(pk.Marshal( packetid.LoginDisconnect, diff --git a/server/player.go b/server/player.go new file mode 100644 index 0000000..565eeb8 --- /dev/null +++ b/server/player.go @@ -0,0 +1,21 @@ +package server + +import ( + "github.com/Tnze/go-mc/net" + pk "github.com/Tnze/go-mc/net/packet" +) + +type Player struct { + *net.Conn + EntityID int32 + Gamemode byte +} + +// Packet757 is a packet in protocol 757. +// We are using type system to force programmers to update packets. +type Packet757 pk.Packet + +// WritePacket to player client. The type of parameter will update per version. +func (p *Player) WritePacket(packet Packet757) error { + return p.Conn.WritePacket(pk.Packet(packet)) +} diff --git a/server/server.go b/server/server.go index 17d59e0..52cd67f 100644 --- a/server/server.go +++ b/server/server.go @@ -2,6 +2,8 @@ // You can build the server you want by combining the various functional modules provided here. // An example can be found in examples/frameworkServer. // +// This package is under rapid development, and any API may be subject to break changes +// // A server is roughly divided into two parts: Gate and GamePlay // // +---------------------------------------------------------------------+ @@ -24,7 +26,9 @@ // The implement of Gameplay will provide later. package server -import "github.com/Tnze/go-mc/net" +import ( + "github.com/Tnze/go-mc/net" +) const ProtocolName = "1.18.1" const ProtocolVersion = 757