Skip to content

Commit

Permalink
dragonfly: Implement support for custom blocks (#512)
Browse files Browse the repository at this point in the history
Co-authored-by: TwistedAsylumMC <[email protected]>
Co-authored-by: DaPigGuy <[email protected]>
Co-authored-by: JustTalDevelops <[email protected]>
  • Loading branch information
4 people authored Dec 9, 2023
1 parent 2b7130d commit 3425d39
Show file tree
Hide file tree
Showing 31 changed files with 793 additions and 37 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ jobs:
runs-on: ubuntu-latest
steps:

- name: Set up Go 1.19
- name: Set up Go 1.21
uses: actions/setup-go@v1
with:
go-version: 1.19
go-version: 1.21
id: go

- name: Check out code into the Go module directory
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/push.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ jobs:
runs-on: ubuntu-latest
steps:

- name: Set up Go 1.19
- name: Set up Go 1.21
uses: actions/setup-go@v1
with:
go-version: 1.19
go-version: 1.21
id: go

- name: Check out code into the Go module directory
Expand Down
20 changes: 18 additions & 2 deletions cmd/blockhash/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,13 @@ func procPackage(pkg *ast.Package, fs *token.FileSet, w io.Writer) {

b.writePackage(w)
i := b.writeConstants(w)
b.writeNextHash(w)
b.writeMethods(w, i)
}

var (
packageFormat = "// Code generated by cmd/blockhash; DO NOT EDIT.\n\npackage %v\n\n"
methodFormat = "\nfunc (%v%v) Hash() uint64 {\n\treturn %v\n}\n"
methodFormat = "\n// Hash ...\nfunc (%v%v) Hash() uint64 {\n\treturn %v\n}\n"
constFormat = "\thash%v"
)

Expand Down Expand Up @@ -112,13 +113,28 @@ func (b *hashBuilder) writeConstants(w io.Writer) (bitSize int) {
i++
}

if _, err := fmt.Fprintln(w, ")"); err != nil {
if _, err := fmt.Fprintln(w, "\thashCustomBlockBase\n)"); err != nil {
log.Fatalln(err)
}

return bits.Len64(i)
}

func (b *hashBuilder) writeNextHash(w io.Writer) {
if _, err := fmt.Fprintln(w, "\n// customBlockBase represents the base hash for all custom blocks."); err != nil {
log.Fatalln(err)
}
if _, err := fmt.Fprintln(w, "var customBlockBase = uint64(hashCustomBlockBase - 1)"); err != nil {
log.Fatalln(err)
}
if _, err := fmt.Fprintln(w, "\n// NextHash returns the next free hash for custom blocks."); err != nil {
log.Fatalln(err)
}
if _, err := fmt.Fprintln(w, "func NextHash() uint64 {\n\tcustomBlockBase++\n\treturn customBlockBase\n}"); err != nil {
log.Fatalln(err)
}
}

func (b *hashBuilder) writeMethods(w io.Writer, baseBits int) {
for _, name := range b.names {
fields := b.blockFields[name]
Expand Down
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/df-mc/dragonfly

go 1.19
go 1.21

require (
github.com/brentp/intintmap v0.0.0-20190211203843-30dc0ade9af9
Expand All @@ -13,6 +13,7 @@ require (
github.com/pelletier/go-toml v1.9.5
github.com/rogpeppe/go-internal v1.9.0
github.com/sandertv/gophertunnel v1.34.0
github.com/segmentio/fasthash v1.0.3
github.com/sirupsen/logrus v1.9.0
go.uber.org/atomic v1.10.0
golang.org/x/exp v0.0.0-20230206171751-46f607a40771
Expand Down
5 changes: 5 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
Expand All @@ -50,13 +51,16 @@ github.com/sandertv/go-raknet v1.12.0 h1:olUzZlIJyX/pgj/mrsLCZYjKLNDsYiWdvQ4NIm3
github.com/sandertv/go-raknet v1.12.0/go.mod h1:Gx+WgZBMQ0V2UoouGoJ8Wj6CDrMBQ4SB2F/ggpl5/+Y=
github.com/sandertv/gophertunnel v1.34.0 h1:fHXTPL4+hUJFF5xObM9T07GpXkTdSvKmYAvx65k0IAw=
github.com/sandertv/gophertunnel v1.34.0/go.mod h1:+Dbhj3bs74gZoSkyab7kglx1Rbq8S5G7sJd/wr5Qm9g=
github.com/segmentio/fasthash v1.0.3 h1:EI9+KE1EwvMLBWwjpRDc+fEM+prwxDYbslddQGtrmhM=
github.com/segmentio/fasthash v1.0.3/go.mod h1:waKX8l2N8yckOgmSsXJi7x1ZfdKZ4x7KRMzBtS3oedY=
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
Expand Down Expand Up @@ -122,3 +126,4 @@ gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
14 changes: 13 additions & 1 deletion server/block/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package block

import (
"github.com/df-mc/dragonfly/server/block/cube"
"github.com/df-mc/dragonfly/server/block/customblock"
"github.com/df-mc/dragonfly/server/block/model"
"github.com/df-mc/dragonfly/server/item"
"github.com/df-mc/dragonfly/server/world"
Expand Down Expand Up @@ -73,13 +74,24 @@ type EntityInsider interface {
EntityInside(pos cube.Pos, w *world.World, e world.Entity)
}

// Frictional represents a block that may have a custom friction value, friction is used for entity drag when the
// Frictional represents a block that may have a custom friction value. Friction is used for entity drag when the
// entity is on ground. If a block does not implement this interface, it should be assumed that its friction is 0.6.
type Frictional interface {
// Friction returns the block's friction value.
Friction() float64
}

// Permutable represents a custom block that can have more permutations than its default state.
type Permutable interface {
// States returns a map of all the different properties for the block. The key is the property name, and the value
// is a slice of all the possible values for that property. It is important that a block is registered in dragonfly
// for each of the possible combinations of properties and values.
States() map[string][]any
// Permutations returns a slice of all the different permutations for the block. Multiple permutations can be
// applied at once if their conditions are met.
Permutations() []customblock.Permutation
}

func calculateFace(user item.User, placePos cube.Pos) cube.Face {
userPos := user.Position()
pos := cube.PosFromVec3(userPos)
Expand Down
58 changes: 58 additions & 0 deletions server/block/customblock/material.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package customblock

// Material represents a single material used for rendering part of a custom block.
type Material struct {
// texture is the name of the texture for the material.
texture string
// renderMethod is the method to use when rendering the material.
renderMethod Method
// faceDimming is if the material should be dimmed by the direction it's facing.
faceDimming bool
// ambientOcclusion is if the material should have ambient occlusion applied when lighting.
ambientOcclusion bool
}

// NewMaterial returns a new Material with the provided information. It enables face dimming by default and ambient
// occlusion based on the render method given.
func NewMaterial(texture string, method Method) Material {
return Material{
texture: texture,
renderMethod: method,
faceDimming: true,
ambientOcclusion: method.AmbientOcclusion(),
}
}

// WithFaceDimming returns a copy of the Material with face dimming enabled.
func (m Material) WithFaceDimming() Material {
m.faceDimming = true
return m
}

// WithoutFaceDimming returns a copy of the Material with face dimming disabled.
func (m Material) WithoutFaceDimming() Material {
m.faceDimming = false
return m
}

// WithAmbientOcclusion returns a copy of the Material with ambient occlusion enabled.
func (m Material) WithAmbientOcclusion() Material {
m.ambientOcclusion = true
return m
}

// WithoutAmbientOcclusion returns a copy of the Material with ambient occlusion disabled.
func (m Material) WithoutAmbientOcclusion() Material {
m.ambientOcclusion = false
return m
}

// Encode returns the material encoded as a map that can be sent over the network to the client.
func (m Material) Encode() map[string]any {
return map[string]any{
"texture": m.texture,
"render_method": m.renderMethod.String(),
"face_dimming": m.faceDimming,
"ambient_occlusion": m.ambientOcclusion,
}
}
44 changes: 44 additions & 0 deletions server/block/customblock/permutations.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package customblock

import (
"github.com/df-mc/dragonfly/server/block/cube"
"github.com/go-gl/mathgl/mgl64"
)

// Properties represents the different properties that can be applied to a block or a permutation.
type Properties struct {
// CollisionBox represents the bounding box of the block that the player can collide with. This cannot exceed the
// position of the current block in the world, otherwise it will be cut off at the edge.
CollisionBox cube.BBox
// Cube determines whether the block should inherit the default cube geometry. This will only be considered if the
// Geometry field is empty.
Cube bool
// Geometry represents the geometry identifier that should be used for the block. If you want to use the default
// cube geometry, leave this field empty and set Cube to true.
Geometry string
// MapColour represents the hex colour that should be used for the block on a map.
MapColour string
// Rotation represents the rotation of the block. Rotations are only applied in 90 degree increments, meaning
// 1 = 90 degrees, 2 = 180 degrees, 3 = 270 degrees and 4 = 360 degrees.
Rotation cube.Pos
// Scale is the scale of the block, with 1 being the default scale in all axes. When scaled, the block cannot
// exceed a 30x30x30 pixel area otherwise the client will not render the block.
Scale mgl64.Vec3
// SelectionBox represents the bounding box of the block that the player can interact with. This cannot exceed the
// position of the current block in the world, otherwise it will be cut off at the edge.
SelectionBox cube.BBox
// Textures define the textures that should be used for the block. The key is the target of the texture, such as
// "*" for all sides, or one of "up", "down", "north", "south", "east", "west" for a specific side.
Textures map[string]Material
// Translation is the translation of the block within itself. When translated, the block cannot exceed a 30x30x30
// pixel area otherwise the client will not render the block.
Translation mgl64.Vec3
}

// Permutation represents a specific permutation for a block that is only applied when the condition is met.
type Permutation struct {
Properties
// Condition is a molang query that is used to determine whether the permutation should be applied.
// Only the latest version of molang is supported.
Condition string
}
58 changes: 58 additions & 0 deletions server/block/customblock/render_method.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package customblock

// Method is the method to use when rendering a material for a custom block.
type Method struct {
renderMethod
}

// OpaqueRenderMethod returns the opaque rendering method for a material. It does not render an alpha layer, meaning it
// does not support transparent or translucent textures, only textures that are fully opaque.
func OpaqueRenderMethod() Method {
return Method{0}
}

// AlphaTestRenderMethod returns the alpha_test rendering method for a material. It does not allow for translucent
// textures, only textures that are fully opaque or fully transparent, used for blocks such as regular glass. It also
// disables ambient occlusion by default.
func AlphaTestRenderMethod() Method {
return Method{1}
}

// BlendRenderMethod returns the blend rendering method for a material. It allows for transparent and translucent
// textures, used for blocks such as stained-glass. It also disables ambient occlusion by default.
func BlendRenderMethod() Method {
return Method{2}
}

// DoubleSidedRenderMethod returns the double_sided rendering method for a material. It is used to completely disable
// backface culling, which would be used for flat faces visible from both sides.
func DoubleSidedRenderMethod() Method {
return Method{3}
}

type renderMethod uint8

// Uint8 returns the render method as a uint8.
func (m renderMethod) Uint8() uint8 {
return uint8(m)
}

// String ...
func (m renderMethod) String() string {
switch m {
case 0:
return "opaque"
case 1:
return "alpha_test"
case 2:
return "blend"
case 3:
return "double_sided"
}
panic("should never happen")
}

// AmbientOcclusion returns if ambient occlusion should be enabled by default for a material using this rendering method.
func (m renderMethod) AmbientOcclusion() bool {
return m != 1 && m != 2
}
Loading

0 comments on commit 3425d39

Please sign in to comment.