package server import ( "iter" "git.citrons.xyz/metronode/classic" ) type blockType int16 const ( walkThrough = classic.WalkThrough swimThrough = classic.SwimThrough solid = classic.Solid partiallySlippery = classic.PartiallySlippery fullySlippery = classic.FullySlippery water = classic.Water lava = classic.Lava rope = classic.Rope ) type blockSolidity byte const ( noSound = classic.NoSound woodSound = classic.WoodSound gravelSound = classic.GravelSound grassSound = classic.GrassSound stoneSound = classic.StoneSound metalSound = classic.MetalSound glassSound = classic.GlassSound woolSound = classic.WoolSound sandSound = classic.SandSound snowSound = classic.SnowSound ) type blockSound byte const ( opaque = classic.Opaque transparentGlass = classic.TransparentGlass transparentLeaves = classic.TransparentLeaves translucent = classic.Translucent invisible = classic.Invisible ) type blockOpacity byte const ( cubeShape = iota spriteShape cuboidShape ) type blockShape byte type textureId int const fillTextures = -1 type blockDef struct { Name string Solidity blockSolidity MovementSpeed byte Textures [6]textureId TransmitsLight bool WalkSound blockSound FullBright bool Shape blockShape Min [3]byte Max [3]byte Opacity blockOpacity FogDensity byte FogColor [3]byte Variants map[any]blockType } type rotateVariant int type slabMaterial struct{} type slabVariant bool func markVariants(variants map[any]blockType) { for _, block := range variants { def := blockDefinitions[block] if def.Variants == nil { def.Variants = make(map[any]blockType) blockDefinitions[block] = def } for variation, block := range variants { def.Variants[variation] = block } } } func assertNoDef(block blockType) { if _, ok := blockDefinitions[block]; ok { panic("variant would override existing block") } } var rotationNames = []string {"-N", "-E", "-S", "-W"} func makeRotations(block blockType) { oldDef := blockDefinitions[block] variants := make(map[any]blockType) for i := 0; i < 4; i++ { newBlock := block + blockType(i) if i != 0 { assertNoDef(newBlock) } newDef := oldDef for j := 0; j < 4; j++ { k := (j + i) % 4 newDef.Textures[j + 1] = oldDef.Textures[k + 1] } var minX, minZ, maxX, maxZ byte switch i { case 1: minX = oldDef.Min[2] minZ = 16 - oldDef.Min[0] maxX = oldDef.Max[2] maxZ = 16 - oldDef.Max[0] case 2: minX = 16 - oldDef.Min[0] minZ = 16 - oldDef.Min[2] maxX = 16 - oldDef.Max[0] maxZ = 16 - oldDef.Max[2] case 3: minX = oldDef.Min[2] minZ = 16 - oldDef.Min[0] maxX = oldDef.Max[2] maxZ = 16 - oldDef.Max[0] } newDef.Min = [3]byte {byte(minX), oldDef.Min[1], byte(minZ)} newDef.Max = [3]byte {byte(maxX), oldDef.Max[1], byte(maxZ)} newDef.Name = newDef.Name + rotationNames[i] variants[rotateVariant(i)] = newBlock blockDefinitions[newBlock] = newDef } markVariants(variants) } func makeSlabs(material blockType, slab blockType, name string) { materialDef := blockDefinitions[material] variants := make(map[any]blockType) variants[slabMaterial{}] = material if name == "" { name = materialDef.Name + " Slab" } bottomSlab := materialDef bottomSlab.Name = name + "-D" bottomSlab.Shape = cuboidShape bottomSlab.Min = [3]byte {0, 0, 0} bottomSlab.Max = [3]byte {16, 8, 16} switch material { default: assertNoDef(slab) variants[slabVariant(false)] = slab blockDefinitions[slab] = bottomSlab case blockDoubleSlab: variants[slabVariant(false)] = blockSlab blockDefinitions[blockSlab] = bottomSlab slab-- case blockCobblestone: variants[slabVariant(false)] = blockCobblestoneSlab blockDefinitions[blockCobblestoneSlab] = bottomSlab slab-- } topSlab := materialDef topSlab.Name = name + "-U" topSlab.Shape = cuboidShape topSlab.Min = [3]byte {0, 8, 0} topSlab.Max = [3]byte {16, 16, 16} assertNoDef(slab + 1) variants[slabVariant(true)] = slab + 1 blockDefinitions[slab + 1] = topSlab markVariants(variants) } func getBlockDefPackets() iter.Seq[classic.Packet] { return func(yield func(classic.Packet) bool) { for id, def := range blockDefinitions { var packet classic.Packet var ( transmitsLight byte fullBright byte ) if def.TransmitsLight { transmitsLight = 1 } if def.FullBright { fullBright = 1 } if def.Shape != spriteShape { var (i int; texture textureId) for i, texture = range def.Textures { if texture == fillTextures { break } } if texture == fillTextures { for i = i; i < len(def.Textures); i++ { def.Textures[i] = def.Textures[i - 1] } } if def.Shape == cubeShape { def.Min = [3]byte {0, 0, 0} def.Max = [3]byte {16, 16, 16} } packet = &classic.DefineBlockExt { BlockId: byte(id), Name: classic.PadString(def.Name), Solidity: byte(def.Solidity), MovementSpeed: def.MovementSpeed, TopTextureId: byte(def.Textures[0]), LeftTextureId: byte(def.Textures[4]), RightTextureId: byte(def.Textures[2]), FrontTextureId: byte(def.Textures[3]), BackTextureId: byte(def.Textures[1]), BottomTextureId: byte(def.Textures[5]), TransmitsLight: transmitsLight, WalkSound: byte(def.WalkSound), FullBright: fullBright, Min: def.Min, Max: def.Max, BlockDraw: byte(def.Opacity), FogDensity: def.FogDensity, FogColor: def.FogColor, } } else { packet = &classic.DefineBlock { BlockId: byte(id), Name: classic.PadString(def.Name), Solidity: byte(def.Solidity), MovementSpeed: def.MovementSpeed, SideTextureId: byte(def.Textures[1]), TransmitsLight: transmitsLight, WalkSound: byte(def.WalkSound), FullBright: fullBright, Shape: 0, BlockDraw: byte(def.Opacity), FogDensity: def.FogDensity, FogColor: def.FogColor, } } if !yield(packet) { return } } } }