diff --git a/internal/generateutils/utils.go b/internal/generateutils/utils.go index 226bc6d..f27ce0b 100644 --- a/internal/generateutils/utils.go +++ b/internal/generateutils/utils.go @@ -21,3 +21,10 @@ func ToGoTypeName(name string) string { } return strings.Join(words, "") } + +func ToFuncReceiverName(name string) string { + if len(name) > 0 { + name = string(unicode.ToLower([]rune(name)[0])) + } + return name +} diff --git a/level/biome/list.go b/level/biome/list.go index f240f53..33f7b6c 100644 --- a/level/biome/list.go +++ b/level/biome/list.go @@ -2,74 +2,82 @@ package biome import "math/bits" -var BitsPerBiome int +type Type int -var biomesNames = []string{ - "the_void", - "plains", - "sunflower_plains", - "snowy_plains", - "ice_spikes", - "desert", - "swamp", - "mangrove_swamp", - "forest", - "flower_forest", - "birch_forest", - "dark_forest", - "old_growth_birch_forest", - "old_growth_pine_taiga", - "old_growth_spruce_taiga", - "taiga", - "snowy_taiga", - "savanna", - "savanna_plateau", - "windswept_hills", - "windswept_gravelly_hills", - "windswept_forest", - "windswept_savanna", - "jungle", - "sparse_jungle", - "bamboo_jungle", - "badlands", - "eroded_badlands", - "wooded_badlands", - "meadow", - "grove", - "snowy_slopes", - "frozen_peaks", - "jagged_peaks", - "stony_peaks", - "river", - "frozen_river", - "beach", - "snowy_beach", - "stony_shore", - "warm_ocean", - "lukewarm_ocean", - "deep_lukewarm_ocean", - "ocean", - "deep_ocean", - "cold_ocean", - "deep_cold_ocean", - "frozen_ocean", - "deep_frozen_ocean", - "mushroom_fields", - "dripstone_caves", - "lush_caves", - "deep_dark", - "nether_wastes", - "warped_forest", - "crimson_forest", - "soul_sand_valley", - "basalt_deltas", - "the_end", - "end_highlands", - "end_midlands", - "small_end_islands", - "end_barrens", -} +var ( + BitsPerBiome int + BiomesIDs map[string]Type + BiomesNames = []string{ + "the_void", + "plains", + "sunflower_plains", + "snowy_plains", + "ice_spikes", + "desert", + "swamp", + "mangrove_swamp", + "forest", + "flower_forest", + "birch_forest", + "dark_forest", + "old_growth_birch_forest", + "old_growth_pine_taiga", + "old_growth_spruce_taiga", + "taiga", + "snowy_taiga", + "savanna", + "savanna_plateau", + "windswept_hills", + "windswept_gravelly_hills", + "windswept_forest", + "windswept_savanna", + "jungle", + "sparse_jungle", + "bamboo_jungle", + "badlands", + "eroded_badlands", + "wooded_badlands", + "meadow", + "grove", + "snowy_slopes", + "frozen_peaks", + "jagged_peaks", + "stony_peaks", + "river", + "frozen_river", + "beach", + "snowy_beach", + "stony_shore", + "warm_ocean", + "lukewarm_ocean", + "deep_lukewarm_ocean", + "ocean", + "deep_ocean", + "cold_ocean", + "deep_cold_ocean", + "frozen_ocean", + "deep_frozen_ocean", + "mushroom_fields", + "dripstone_caves", + "lush_caves", + "deep_dark", + "nether_wastes", + "warped_forest", + "crimson_forest", + "soul_sand_valley", + "basalt_deltas", + "the_end", + "end_highlands", + "end_midlands", + "small_end_islands", + "end_barrens", + } +) func init() { - BitsPerBiome = bits.Len(uint(len(biomesNames))) + BitsPerBiome = bits.Len(uint(len(BiomesNames))) + BiomesIDs = make(map[string]Type, len(BiomesNames)) + for i, v := range BiomesNames { + BiomesIDs[v] = Type(i) + } } diff --git a/level/block/block_entities.nbt b/level/block/block_entities.nbt new file mode 100644 index 0000000..96c7840 Binary files /dev/null and b/level/block/block_entities.nbt differ diff --git a/level/block/blockentities.go b/level/block/blockentities.go new file mode 100644 index 0000000..f473450 --- /dev/null +++ b/level/block/blockentities.go @@ -0,0 +1,397 @@ +// Code generated by generator/blockentities/main.go; DO NOT EDIT. + +package block + +var EntityList = [...]Entity{ + FurnaceEntity{}, + ChestEntity{}, + TrappedChestEntity{}, + EnderChestEntity{}, + JukeboxEntity{}, + DispenserEntity{}, + DropperEntity{}, + SignEntity{}, + HangingSignEntity{}, + MobSpawnerEntity{}, + PistonEntity{}, + BrewingStandEntity{}, + EnchantingTableEntity{}, + EndPortalEntity{}, + BeaconEntity{}, + SkullEntity{}, + DaylightDetectorEntity{}, + HopperEntity{}, + ComparatorEntity{}, + BannerEntity{}, + StructureBlockEntity{}, + EndGatewayEntity{}, + CommandBlockEntity{}, + ShulkerBoxEntity{}, + BedEntity{}, + ConduitEntity{}, + BarrelEntity{}, + SmokerEntity{}, + BlastFurnaceEntity{}, + LecternEntity{}, + BellEntity{}, + JigsawEntity{}, + CampfireEntity{}, + BeehiveEntity{}, + SculkSensorEntity{}, + SculkCatalystEntity{}, + SculkShriekerEntity{}, + ChiseledBookshelfEntity{}, +} + +func (FurnaceEntity) ID() string { return "minecraft:furnace" } +func (ChestEntity) ID() string { return "minecraft:chest" } +func (TrappedChestEntity) ID() string { return "minecraft:trapped_chest" } +func (EnderChestEntity) ID() string { return "minecraft:ender_chest" } +func (JukeboxEntity) ID() string { return "minecraft:jukebox" } +func (DispenserEntity) ID() string { return "minecraft:dispenser" } +func (DropperEntity) ID() string { return "minecraft:dropper" } +func (SignEntity) ID() string { return "minecraft:sign" } +func (HangingSignEntity) ID() string { return "minecraft:hanging_sign" } +func (MobSpawnerEntity) ID() string { return "minecraft:mob_spawner" } +func (PistonEntity) ID() string { return "minecraft:piston" } +func (BrewingStandEntity) ID() string { return "minecraft:brewing_stand" } +func (EnchantingTableEntity) ID() string { return "minecraft:enchanting_table" } +func (EndPortalEntity) ID() string { return "minecraft:end_portal" } +func (BeaconEntity) ID() string { return "minecraft:beacon" } +func (SkullEntity) ID() string { return "minecraft:skull" } +func (DaylightDetectorEntity) ID() string { return "minecraft:daylight_detector" } +func (HopperEntity) ID() string { return "minecraft:hopper" } +func (ComparatorEntity) ID() string { return "minecraft:comparator" } +func (BannerEntity) ID() string { return "minecraft:banner" } +func (StructureBlockEntity) ID() string { return "minecraft:structure_block" } +func (EndGatewayEntity) ID() string { return "minecraft:end_gateway" } +func (CommandBlockEntity) ID() string { return "minecraft:command_block" } +func (ShulkerBoxEntity) ID() string { return "minecraft:shulker_box" } +func (BedEntity) ID() string { return "minecraft:bed" } +func (ConduitEntity) ID() string { return "minecraft:conduit" } +func (BarrelEntity) ID() string { return "minecraft:barrel" } +func (SmokerEntity) ID() string { return "minecraft:smoker" } +func (BlastFurnaceEntity) ID() string { return "minecraft:blast_furnace" } +func (LecternEntity) ID() string { return "minecraft:lectern" } +func (BellEntity) ID() string { return "minecraft:bell" } +func (JigsawEntity) ID() string { return "minecraft:jigsaw" } +func (CampfireEntity) ID() string { return "minecraft:campfire" } +func (BeehiveEntity) ID() string { return "minecraft:beehive" } +func (SculkSensorEntity) ID() string { return "minecraft:sculk_sensor" } +func (SculkCatalystEntity) ID() string { return "minecraft:sculk_catalyst" } +func (SculkShriekerEntity) ID() string { return "minecraft:sculk_shrieker" } +func (ChiseledBookshelfEntity) ID() string { return "minecraft:chiseled_bookshelf" } + +func (m FurnaceEntity) IsValidBlock(block Block) bool { + return block.ID() == "minecraft:furnace" +} + +func (m ChestEntity) IsValidBlock(block Block) bool { + return block.ID() == "minecraft:chest" +} + +func (m TrappedChestEntity) IsValidBlock(block Block) bool { + return block.ID() == "minecraft:trapped_chest" +} + +func (m EnderChestEntity) IsValidBlock(block Block) bool { + return block.ID() == "minecraft:ender_chest" +} + +func (m JukeboxEntity) IsValidBlock(block Block) bool { + return block.ID() == "minecraft:jukebox" +} + +func (m DispenserEntity) IsValidBlock(block Block) bool { + return block.ID() == "minecraft:dispenser" +} + +func (m DropperEntity) IsValidBlock(block Block) bool { + return block.ID() == "minecraft:dropper" +} + +func (m SignEntity) IsValidBlock(block Block) bool { + switch block.ID() { + case "minecraft:oak_sign", + "minecraft:spruce_sign", + "minecraft:birch_sign", + "minecraft:acacia_sign", + "minecraft:jungle_sign", + "minecraft:dark_oak_sign", + "minecraft:oak_wall_sign", + "minecraft:spruce_wall_sign", + "minecraft:birch_wall_sign", + "minecraft:acacia_wall_sign", + "minecraft:jungle_wall_sign", + "minecraft:dark_oak_wall_sign", + "minecraft:crimson_sign", + "minecraft:crimson_wall_sign", + "minecraft:warped_sign", + "minecraft:warped_wall_sign", + "minecraft:mangrove_sign", + "minecraft:mangrove_wall_sign", + "minecraft:bamboo_sign", + "minecraft:bamboo_wall_sign": + return true + default: + return false + } +} + +func (m HangingSignEntity) IsValidBlock(block Block) bool { + switch block.ID() { + case "minecraft:oak_hanging_sign", + "minecraft:spruce_hanging_sign", + "minecraft:birch_hanging_sign", + "minecraft:acacia_hanging_sign", + "minecraft:jungle_hanging_sign", + "minecraft:dark_oak_hanging_sign", + "minecraft:crimson_hanging_sign", + "minecraft:warped_hanging_sign", + "minecraft:mangrove_hanging_sign", + "minecraft:bamboo_hanging_sign", + "minecraft:oak_wall_hanging_sign", + "minecraft:spruce_wall_hanging_sign", + "minecraft:birch_wall_hanging_sign", + "minecraft:acacia_wall_hanging_sign", + "minecraft:jungle_wall_hanging_sign", + "minecraft:dark_oak_wall_hanging_sign", + "minecraft:crimson_wall_hanging_sign", + "minecraft:warped_wall_hanging_sign", + "minecraft:mangrove_wall_hanging_sign", + "minecraft:bamboo_wall_hanging_sign": + return true + default: + return false + } +} + +func (m MobSpawnerEntity) IsValidBlock(block Block) bool { + return block.ID() == "minecraft:spawner" +} + +func (m PistonEntity) IsValidBlock(block Block) bool { + return block.ID() == "minecraft:moving_piston" +} + +func (m BrewingStandEntity) IsValidBlock(block Block) bool { + return block.ID() == "minecraft:brewing_stand" +} + +func (m EnchantingTableEntity) IsValidBlock(block Block) bool { + return block.ID() == "minecraft:enchanting_table" +} + +func (m EndPortalEntity) IsValidBlock(block Block) bool { + return block.ID() == "minecraft:end_portal" +} + +func (m BeaconEntity) IsValidBlock(block Block) bool { + return block.ID() == "minecraft:beacon" +} + +func (m SkullEntity) IsValidBlock(block Block) bool { + switch block.ID() { + case "minecraft:skeleton_skull", + "minecraft:skeleton_wall_skull", + "minecraft:creeper_head", + "minecraft:creeper_wall_head", + "minecraft:dragon_head", + "minecraft:dragon_wall_head", + "minecraft:zombie_head", + "minecraft:zombie_wall_head", + "minecraft:wither_skeleton_skull", + "minecraft:wither_skeleton_wall_skull", + "minecraft:player_head", + "minecraft:player_wall_head", + "minecraft:piglin_head", + "minecraft:piglin_wall_head": + return true + default: + return false + } +} + +func (m DaylightDetectorEntity) IsValidBlock(block Block) bool { + return block.ID() == "minecraft:daylight_detector" +} + +func (m HopperEntity) IsValidBlock(block Block) bool { + return block.ID() == "minecraft:hopper" +} + +func (m ComparatorEntity) IsValidBlock(block Block) bool { + return block.ID() == "minecraft:comparator" +} + +func (m BannerEntity) IsValidBlock(block Block) bool { + switch block.ID() { + case "minecraft:white_banner", + "minecraft:orange_banner", + "minecraft:magenta_banner", + "minecraft:light_blue_banner", + "minecraft:yellow_banner", + "minecraft:lime_banner", + "minecraft:pink_banner", + "minecraft:gray_banner", + "minecraft:light_gray_banner", + "minecraft:cyan_banner", + "minecraft:purple_banner", + "minecraft:blue_banner", + "minecraft:brown_banner", + "minecraft:green_banner", + "minecraft:red_banner", + "minecraft:black_banner", + "minecraft:white_wall_banner", + "minecraft:orange_wall_banner", + "minecraft:magenta_wall_banner", + "minecraft:light_blue_wall_banner", + "minecraft:yellow_wall_banner", + "minecraft:lime_wall_banner", + "minecraft:pink_wall_banner", + "minecraft:gray_wall_banner", + "minecraft:light_gray_wall_banner", + "minecraft:cyan_wall_banner", + "minecraft:purple_wall_banner", + "minecraft:blue_wall_banner", + "minecraft:brown_wall_banner", + "minecraft:green_wall_banner", + "minecraft:red_wall_banner", + "minecraft:black_wall_banner": + return true + default: + return false + } +} + +func (m StructureBlockEntity) IsValidBlock(block Block) bool { + return block.ID() == "minecraft:structure_block" +} + +func (m EndGatewayEntity) IsValidBlock(block Block) bool { + return block.ID() == "minecraft:end_gateway" +} + +func (m CommandBlockEntity) IsValidBlock(block Block) bool { + switch block.ID() { + case "minecraft:command_block", + "minecraft:chain_command_block", + "minecraft:repeating_command_block": + return true + default: + return false + } +} + +func (m ShulkerBoxEntity) IsValidBlock(block Block) bool { + switch block.ID() { + case "minecraft:shulker_box", + "minecraft:black_shulker_box", + "minecraft:blue_shulker_box", + "minecraft:brown_shulker_box", + "minecraft:cyan_shulker_box", + "minecraft:gray_shulker_box", + "minecraft:green_shulker_box", + "minecraft:light_blue_shulker_box", + "minecraft:light_gray_shulker_box", + "minecraft:lime_shulker_box", + "minecraft:magenta_shulker_box", + "minecraft:orange_shulker_box", + "minecraft:pink_shulker_box", + "minecraft:purple_shulker_box", + "minecraft:red_shulker_box", + "minecraft:white_shulker_box", + "minecraft:yellow_shulker_box": + return true + default: + return false + } +} + +func (m BedEntity) IsValidBlock(block Block) bool { + switch block.ID() { + case "minecraft:red_bed", + "minecraft:black_bed", + "minecraft:blue_bed", + "minecraft:brown_bed", + "minecraft:cyan_bed", + "minecraft:gray_bed", + "minecraft:green_bed", + "minecraft:light_blue_bed", + "minecraft:light_gray_bed", + "minecraft:lime_bed", + "minecraft:magenta_bed", + "minecraft:orange_bed", + "minecraft:pink_bed", + "minecraft:purple_bed", + "minecraft:white_bed", + "minecraft:yellow_bed": + return true + default: + return false + } +} + +func (m ConduitEntity) IsValidBlock(block Block) bool { + return block.ID() == "minecraft:conduit" +} + +func (m BarrelEntity) IsValidBlock(block Block) bool { + return block.ID() == "minecraft:barrel" +} + +func (m SmokerEntity) IsValidBlock(block Block) bool { + return block.ID() == "minecraft:smoker" +} + +func (m BlastFurnaceEntity) IsValidBlock(block Block) bool { + return block.ID() == "minecraft:blast_furnace" +} + +func (m LecternEntity) IsValidBlock(block Block) bool { + return block.ID() == "minecraft:lectern" +} + +func (m BellEntity) IsValidBlock(block Block) bool { + return block.ID() == "minecraft:bell" +} + +func (m JigsawEntity) IsValidBlock(block Block) bool { + return block.ID() == "minecraft:jigsaw" +} + +func (m CampfireEntity) IsValidBlock(block Block) bool { + switch block.ID() { + case "minecraft:campfire", + "minecraft:soul_campfire": + return true + default: + return false + } +} + +func (m BeehiveEntity) IsValidBlock(block Block) bool { + switch block.ID() { + case "minecraft:bee_nest", + "minecraft:beehive": + return true + default: + return false + } +} + +func (m SculkSensorEntity) IsValidBlock(block Block) bool { + return block.ID() == "minecraft:sculk_sensor" +} + +func (m SculkCatalystEntity) IsValidBlock(block Block) bool { + return block.ID() == "minecraft:sculk_catalyst" +} + +func (m SculkShriekerEntity) IsValidBlock(block Block) bool { + return block.ID() == "minecraft:sculk_shrieker" +} + +func (m ChiseledBookshelfEntity) IsValidBlock(block Block) bool { + return block.ID() == "minecraft:chiseled_bookshelf" +} diff --git a/level/block/blockentity.go b/level/block/blockentity.go new file mode 100644 index 0000000..2180c82 --- /dev/null +++ b/level/block/blockentity.go @@ -0,0 +1,59 @@ +package block + +//go:generate go run ./generator/blockentities/main.go +type Entity interface { + ID() string + IsValidBlock(block Block) bool +} + +type ( + FurnaceEntity struct{} + ChestEntity struct{} + TrappedChestEntity struct{} + EnderChestEntity struct{} + JukeboxEntity struct{} + DispenserEntity struct{} + DropperEntity struct{} + SignEntity struct{} + HangingSignEntity struct{} + MobSpawnerEntity struct{} + PistonEntity struct{} + BrewingStandEntity struct{} + EnchantingTableEntity struct{} + EndPortalEntity struct{} + BeaconEntity struct{} + SkullEntity struct{} + DaylightDetectorEntity struct{} + HopperEntity struct{} + ComparatorEntity struct{} + BannerEntity struct{} + StructureBlockEntity struct{} + EndGatewayEntity struct{} + CommandBlockEntity struct{} + ShulkerBoxEntity struct{} + BedEntity struct{} + ConduitEntity struct{} + BarrelEntity struct{} + SmokerEntity struct{} + BlastFurnaceEntity struct{} + LecternEntity struct{} + BellEntity struct{} + JigsawEntity struct{} + CampfireEntity struct{} + BeehiveEntity struct{} + SculkSensorEntity struct{} + SculkCatalystEntity struct{} + SculkShriekerEntity struct{} + ChiseledBookshelfEntity struct{} +) + +type EntityType int32 + +var EntityTypes map[string]EntityType + +func init() { + EntityTypes = make(map[string]EntityType, len(EntityList)) + for i, v := range EntityList { + EntityTypes[v.ID()] = EntityType(i) + } +} diff --git a/level/block/generator/Main.java b/level/block/generator/GenBlocks.java similarity index 71% rename from level/block/generator/Main.java rename to level/block/generator/GenBlocks.java index ccb25fd..e20bc38 100644 --- a/level/block/generator/Main.java +++ b/level/block/generator/GenBlocks.java @@ -1,15 +1,15 @@ -package tnze.github.com; +package pers.tnze.gomc.gen; import com.google.common.collect.ImmutableMap; import net.minecraft.SharedConstants; +import net.minecraft.core.DefaultedRegistry; import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.ListTag; -import net.minecraft.nbt.NbtIo; -import net.minecraft.nbt.NbtUtils; +import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.*; import net.minecraft.server.Bootstrap; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.properties.EnumProperty; import net.minecraft.world.level.block.state.properties.Property; @@ -18,9 +18,10 @@ import java.io.DataOutput; import java.io.DataOutputStream; import java.io.FileOutputStream; import java.util.Map; +import java.util.Set; import java.util.zip.GZIPOutputStream; -public class Main { +public class GenBlocks { public static void main(String[] args) throws Exception { System.out.println("program start!"); @@ -40,6 +41,12 @@ public class Main { NbtIo.writeUnnamedTag(getBlockStates(), writer); } } + try (FileOutputStream f = new FileOutputStream("block_entities.nbt")) { + try (GZIPOutputStream g = new GZIPOutputStream(f)) { + DataOutput writer = new DataOutputStream(g); + NbtIo.writeUnnamedTag(genBlockEntities(), writer); + } + } } private static ListTag getBlocksWithMeta() throws Exception { @@ -84,4 +91,21 @@ public class Main { } return list; } + + private static ListTag genBlockEntities() { + ListTag list = new ListTag(); + for (BlockEntityType blockEntity : BuiltInRegistries.BLOCK_ENTITY_TYPE) { + ListTag validBlocksList = new ListTag(); + Set validBlocks = blockEntity.validBlocks; + for (Block validBlock : validBlocks){ + validBlocksList.add(StringTag.valueOf(BuiltInRegistries.BLOCK.getKey(validBlock).toString())); + } + CompoundTag be = new CompoundTag(); + be.putString("Name", BuiltInRegistries.BLOCK_ENTITY_TYPE.getKey(blockEntity).toString()); + be.putString("ValidBlocks", BuiltInRegistries.BLOCK_ENTITY_TYPE.getKey(blockEntity).toString()); + + list.add(be); + } + return list; + } } diff --git a/level/block/generator/blockentities/blockentities.go.tmpl b/level/block/generator/blockentities/blockentities.go.tmpl new file mode 100644 index 0000000..c4dd202 --- /dev/null +++ b/level/block/generator/blockentities/blockentities.go.tmpl @@ -0,0 +1,31 @@ +// Code generated by {{Generator}}; DO NOT EDIT. + +package block + +{{/* type ( +{{- range .}} + {{.Name | ToGoTypeName}}Entity struct {} +{{- end}} +) */}} + +var EntityList = [...]Entity{ + {{- range .}} + {{.Name | ToGoTypeName}}Entity{}, + {{- end}} +} + +{{- range .}} +func ({{.Name | ToGoTypeName}}Entity) ID() string { return {{.Name | printf "%q"}} } +{{- end}} + +{{range .}} +func ({{.Name | ToFuncReceiverName}} {{.Name | ToGoTypeName}}Entity) IsValidBlock(block Block) bool { + {{if eq 1 (len .ValidBlocks)}}return block.ID() == {{index .ValidBlocks 0 | printf "%q"}}{{else}}switch block.ID() { + case {{index .ValidBlocks 0 | printf "%q"}}{{range slice .ValidBlocks 1}}, + {{. | printf "%q"}}{{end}}: + return true + default: + return false + }{{end}} +} +{{end}} diff --git a/level/block/generator/blockentities/main.go b/level/block/generator/blockentities/main.go new file mode 100644 index 0000000..413d090 --- /dev/null +++ b/level/block/generator/blockentities/main.go @@ -0,0 +1,77 @@ +package main + +import ( + "bytes" + "compress/gzip" + _ "embed" + "go/format" + "log" + "os" + "text/template" + + "github.com/Tnze/go-mc/internal/generateutils" + "github.com/Tnze/go-mc/nbt" +) + +//go:embed blockentities.go.tmpl +var tempSource string + +var temp = template.Must(template. + New("block_template"). + Funcs(template.FuncMap{ + "UpperTheFirst": generateutils.UpperTheFirst, + "ToGoTypeName": generateutils.ToGoTypeName, + "ToFuncReceiverName": generateutils.ToFuncReceiverName, + "Generator": func() string { return "generator/blockentities/main.go" }, + }). + Parse(tempSource), +) + +type BlockEntity struct { + Name string + ValidBlocks []string +} + +func main() { + var states []BlockEntity + readBlockEntities(&states) + + // generate go source file + genSourceFile(states) +} + +func readBlockEntities(states *[]BlockEntity) { + f, err := os.Open("block_entities.nbt") + if err != nil { + log.Panic(err) + } + defer f.Close() + + r, err := gzip.NewReader(f) + if err != nil { + log.Panic(err) + } + + // parse the nbt format + if _, err := nbt.NewDecoder(r).Decode(states); err != nil { + log.Panic(err) + } +} + +func genSourceFile(states []BlockEntity) { + var source bytes.Buffer + if err := temp.Execute(&source, states); err != nil { + log.Panic(err) + } + + formattedSource, err := format.Source(source.Bytes()) + if err != nil { + panic(err) + } + + err = os.WriteFile("blockentities.go", formattedSource, 0o666) + if err != nil { + panic(err) + } + log.Print("Generated blockentities.go") +} diff --git a/level/chunk.go b/level/chunk.go index b7233c1..6f22984 100644 --- a/level/chunk.go +++ b/level/chunk.go @@ -2,11 +2,14 @@ package level import ( "bytes" + "errors" "fmt" "io" "math/bits" + "strconv" "strings" + "github.com/Tnze/go-mc/level/biome" "github.com/Tnze/go-mc/level/block" "github.com/Tnze/go-mc/nbt" pk "github.com/Tnze/go-mc/net/packet" @@ -62,81 +65,6 @@ func EmptyChunk(secs int) *Chunk { } } -var biomesIDs map[string]BiomesState - -var biomesNames = []string{ - "the_void", - "plains", - "sunflower_plains", - "snowy_plains", - "ice_spikes", - "desert", - "swamp", - "mangrove_swamp", - "forest", - "flower_forest", - "birch_forest", - "dark_forest", - "old_growth_birch_forest", - "old_growth_pine_taiga", - "old_growth_spruce_taiga", - "taiga", - "snowy_taiga", - "savanna", - "savanna_plateau", - "windswept_hills", - "windswept_gravelly_hills", - "windswept_forest", - "windswept_savanna", - "jungle", - "sparse_jungle", - "bamboo_jungle", - "badlands", - "eroded_badlands", - "wooded_badlands", - "meadow", - "grove", - "snowy_slopes", - "frozen_peaks", - "jagged_peaks", - "stony_peaks", - "river", - "frozen_river", - "beach", - "snowy_beach", - "stony_shore", - "warm_ocean", - "lukewarm_ocean", - "deep_lukewarm_ocean", - "ocean", - "deep_ocean", - "cold_ocean", - "deep_cold_ocean", - "frozen_ocean", - "deep_frozen_ocean", - "mushroom_fields", - "dripstone_caves", - "lush_caves", - "deep_dark", - "nether_wastes", - "warped_forest", - "crimson_forest", - "soul_sand_valley", - "basalt_deltas", - "the_end", - "end_highlands", - "end_midlands", - "small_end_islands", - "end_barrens", -} - -func init() { - biomesIDs = make(map[string]BiomesState, len(biomesNames)) - for i, v := range biomesNames { - biomesIDs[v] = BiomesState(i) - } -} - // ChunkFromSave convert save.Chunk to level.Chunk. func ChunkFromSave(c *save.Chunk) (*Chunk, error) { secs := len(c.Sections) @@ -159,6 +87,25 @@ func ChunkFromSave(c *save.Chunk) (*Chunk, error) { sections[i].BlockLight = v.BlockLight } + blockEntities := make([]BlockEntity, len(c.BlockEntities)) + for i, v := range c.BlockEntities { + var tmp struct { + ID string `nbt:"id"` + X int32 `nbt:"x"` + Y int32 `nbt:"y"` + Z int32 `nbt:"z"` + } + if err := v.Unmarshal(&tmp); err != nil { + return nil, err + } + blockEntities[i].Data = v + if x, z := int(tmp.X-c.XPos<<4), int(tmp.Z-c.ZPos<<4); !blockEntities[i].PackXZ(x, z) { + return nil, errors.New("Packing a XZ(" + strconv.Itoa(x) + ", " + strconv.Itoa(z) + ") out of bound") + } + blockEntities[i].Y = int16(tmp.Y) + blockEntities[i].Type = block.EntityTypes[tmp.ID] + } + motionBlocking := c.Heightmaps.MotionBlocking motionBlockingNoLeaves := c.Heightmaps.MotionBlockingNoLeaves oceanFloor := c.Heightmaps.OceanFloor @@ -173,7 +120,8 @@ func ChunkFromSave(c *save.Chunk) (*Chunk, error) { OceanFloor: NewBitStorage(bitsForHeight, 16*16, oceanFloor), WorldSurface: NewBitStorage(bitsForHeight, 16*16, worldSurface), }, - Status: ChunkStatus(c.Status), + BlockEntity: blockEntities, + Status: ChunkStatus(c.Status), }, nil } @@ -206,7 +154,7 @@ func readBiomesPalette(palette []string, data []uint64) (*PaletteContainer[Biome biomesRawPalette := make([]BiomesState, len(palette)) var ok bool for i, v := range palette { - biomesRawPalette[i], ok = biomesIDs[strings.TrimPrefix(v, "minecraft:")] + biomesRawPalette[i], ok = biome.BiomesIDs[strings.TrimPrefix(v, "minecraft:")] if !ok { return nil, fmt.Errorf("unknown biomes: %s", v) } @@ -264,7 +212,7 @@ func writeBiomesPalette(paletteData *PaletteContainer[BiomesState]) (palette []s rawPalette := paletteData.palette.export() palette = make([]string, len(rawPalette)) for i, v := range rawPalette { - palette[i] = biomesNames[v] + palette[i] = biome.BiomesNames[v] } data = append(data, paletteData.data.Raw()...) @@ -367,7 +315,7 @@ type HeightMaps struct { type BlockEntity struct { XZ int8 Y int16 - Type int32 + Type block.EntityType Data nbt.RawMessage } @@ -375,6 +323,14 @@ func (b BlockEntity) UnpackXZ() (X, Z int) { return int((uint8(b.XZ) >> 4) & 0xF), int(uint8(b.XZ) & 0xF) } +func (b *BlockEntity) PackXZ(X, Z int) bool { + if X > 0xF || Z > 0xF || X < 0 || Z < 0 { + return false + } + b.XZ = int8(X<<4 | Z) + return true +} + func (b BlockEntity) WriteTo(w io.Writer) (n int64, err error) { return pk.Tuple{ pk.Byte(b.XZ), diff --git a/level/palette.go b/level/palette.go index 5d301e3..99a98ac 100644 --- a/level/palette.go +++ b/level/palette.go @@ -15,7 +15,7 @@ type State interface { } type ( BlocksState = block.StateID - BiomesState int + BiomesState = biome.Type ) type PaletteContainer[T State] struct {