-
Notifications
You must be signed in to change notification settings - Fork 4
feat: expand movement simulation parity #6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
456eacb
feat: expand movement simulation parity
HashimTheArab f6d99e6
fix: preserve legacy depth strider fallback
HashimTheArab 2c01d35
fix: keep movement semantics Bedrock-native
HashimTheArab 10c3d99
feat: convert simulation to native float32 math
HashimTheArab 20f1d63
Revert "feat: convert simulation to native float32 math"
HashimTheArab 9a88dc3
Merge main into agent/boar-movement-parity
HashimTheArab 27d2738
Fix pose transitions and riptide conditions
HashimTheArab f8c6441
Fix queued block effect handling
HashimTheArab bcfb917
Preserve fitting pose across swim transitions
HashimTheArab dff5fc5
Initialize pose heights for state-only simulation
HashimTheArab File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| package bedsim | ||
|
|
||
| import ( | ||
| "github.com/chewxy/math32" | ||
| "testing" | ||
|
|
||
| "github.com/df-mc/dragonfly/server/block/cube" | ||
| "github.com/df-mc/dragonfly/server/world" | ||
| "github.com/go-gl/mathgl/mgl32" | ||
| ) | ||
|
|
||
| func TestBlockAirRecognisesOnlyBedrockAirIdentifier(t *testing.T) { | ||
| sim := &Simulator{BlockSemantics: encodedBlockSemantics{}} | ||
| tests := []struct { | ||
| name string | ||
| want bool | ||
| }{ | ||
| {name: "minecraft:air", want: true}, | ||
| {name: "minecraft:cave_air", want: false}, | ||
| {name: "minecraft:void_air", want: false}, | ||
| } | ||
|
|
||
| for _, tt := range tests { | ||
| t.Run(tt.name, func(t *testing.T) { | ||
| if got := sim.blockAir(semanticsNamedBlock{name: tt.name}); got != tt.want { | ||
| t.Fatalf("blockAir(%q) = %v, want %v", tt.name, got, tt.want) | ||
| } | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| func TestJavaWebIdentifierHasNoBedrockMovementEffect(t *testing.T) { | ||
| w := environmentWorld{blocks: map[cube.Pos]world.Block{ | ||
| {0, 0, 0}: semanticsNamedBlock{name: "minecraft:cobweb"}, | ||
| }} | ||
| state := newBaseState() | ||
| state.Pos = mgl32.Vec3{0.5, 0, 0.5} | ||
| state.Vel = mgl32.Vec3{0.1, 0, 0} | ||
| state.HasGravity = false | ||
|
|
||
| result := (&Simulator{World: w, BlockSemantics: encodedBlockSemantics{}}).SimulateState(state) | ||
|
|
||
| if want := float32(0.1); math32.Abs(result.Movement.X()-want) > 1e-6 { | ||
| t.Fatalf("Java web identifier changed Bedrock movement: got %v, want %v", result.Movement.X(), want) | ||
| } | ||
| } | ||
|
|
||
| func TestDefaultSneakingHeightMatchesDragonflyBedrockPlayer(t *testing.T) { | ||
| state := newBaseState() | ||
|
|
||
| (&Simulator{}).applyInput(state, InputState{StartSneaking: true}) | ||
|
|
||
| if state.Size.Y() != 1.49 { | ||
| t.Fatalf("sneaking height = %v, want 1.49", state.Size.Y()) | ||
| } | ||
| } | ||
|
|
||
| func TestCrawlingCannotStartInOpenAir(t *testing.T) { | ||
| state := newBaseState() | ||
|
|
||
| (&Simulator{World: environmentWorld{}}).applyInput(state, InputState{StartCrawling: true}) | ||
|
|
||
| if state.Crawling || state.Size.Y() != 1.8 { | ||
| t.Fatalf("open-air crawl was accepted: crawling=%v size=%v", state.Crawling, state.Size) | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| package block | ||
|
|
||
| import "github.com/df-mc/dragonfly/server/world" | ||
|
|
||
| type environmentRule struct { | ||
| name string | ||
| inside InsideMovement | ||
| traversal Traversal | ||
| honey bool | ||
| } | ||
|
|
||
| func (r environmentRule) Matches(_ world.Block, name string) bool { | ||
| return name == r.name | ||
| } | ||
|
|
||
| func (r environmentRule) Apply(s *resolution) { | ||
| s.InsideMovement = r.inside | ||
| s.Traversal = r.traversal | ||
| s.Honey = r.honey | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,118 @@ | ||
| package bedsim | ||
|
|
||
| import ( | ||
| "github.com/chewxy/math32" | ||
|
|
||
| "github.com/df-mc/dragonfly/server/block/cube" | ||
| "github.com/go-gl/mathgl/mgl32" | ||
| movementblock "github.com/oomph-ac/bedsim/block" | ||
| ) | ||
|
|
||
| func applyInsideBlockMovement(state *MovementState, movement movementblock.InsideMovement) { | ||
| switch movement { | ||
| case movementblock.InsideMovementSweetBerryBush: | ||
| queueStuckSpeedMultiplier(state, mgl32.Vec3{0.8, 0.75, 0.8}) | ||
| case movementblock.InsideMovementPowderSnow: | ||
| queueStuckSpeedMultiplier(state, mgl32.Vec3{0.9, 1.5, 0.9}) | ||
| } | ||
| } | ||
|
|
||
| func queueStuckSpeedMultiplier(state *MovementState, multiplier mgl32.Vec3) { | ||
| queued := state.StuckSpeedMultiplier | ||
| if queued.LenSqr() <= 1e-7 { | ||
| state.StuckSpeedMultiplier = multiplier | ||
| return | ||
| } | ||
| for axis := range 3 { | ||
| queued[axis] = min(queued[axis], multiplier[axis]) | ||
| } | ||
| state.StuckSpeedMultiplier = queued | ||
| } | ||
|
|
||
| func applyStuckSpeedMultiplier(state *MovementState) bool { | ||
| multiplier := state.StuckSpeedMultiplier | ||
| if multiplier.LenSqr() <= 1e-7 { | ||
| return false | ||
| } | ||
| if state.NoClip { | ||
| state.StuckSpeedMultiplier = mgl32.Vec3{} | ||
| return false | ||
| } | ||
| state.SetVel(mgl32.Vec3{ | ||
| state.Vel.X() * multiplier.X(), | ||
| state.Vel.Y() * multiplier.Y(), | ||
| state.Vel.Z() * multiplier.Z(), | ||
| }) | ||
| state.StuckSpeedMultiplier = mgl32.Vec3{} | ||
| return true | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
| } | ||
|
|
||
| func applyAscendableMovement(state *MovementState, traversal movementblock.Traversal, leatherBoots bool) { | ||
| velocity := state.Vel | ||
| switch traversal { | ||
| case movementblock.TraversalScaffolding: | ||
| if state.PressingDescend { | ||
| velocity[1] = -0.15 | ||
| } else if state.PressingAscend { | ||
| velocity[1] = 0.15 | ||
| } | ||
| case movementblock.TraversalPowderSnow: | ||
| if state.PressingDescend { | ||
| velocity[1] = -0.15 | ||
| } else if state.PressingAscend && leatherBoots { | ||
| velocity[1] = 0.2 | ||
| } | ||
| } | ||
| state.SetVel(velocity) | ||
| } | ||
|
|
||
| func (s *Simulator) applyInsideBlockEffects(state *MovementState) { | ||
| if s.World == nil { | ||
| return | ||
| } | ||
| bb := state.BoundingBox(s.Options.UseSlideOffset) | ||
| min, maxPoint := bb.Min(), bb.Max() | ||
| for x := int(math32.Floor(min.X())); x < int(math32.Ceil(maxPoint.X())); x++ { | ||
| for y := int(math32.Floor(min.Y())); y < int(math32.Ceil(maxPoint.Y())); y++ { | ||
| for z := int(math32.Floor(min.Z())); z < int(math32.Ceil(maxPoint.Z())); z++ { | ||
| pos := cube.Pos{x, y, z} | ||
| if !bb.IntersectsWith(cube.Box32(0, 0, 0, 1, 1, 1).Translate(posVec3(pos))) { | ||
| continue | ||
| } | ||
| b := s.World.Block(pos) | ||
| if s.blockAir(b) { | ||
| continue | ||
| } | ||
| semantics := s.blockMovementSemantics(b) | ||
| applyInsideBlockMovement(state, semantics.InsideMovement) | ||
| } | ||
| } | ||
| } | ||
| s.applyHoneyWallSlide(state) | ||
| } | ||
|
|
||
| func (s *Simulator) applyHoneyWallSlide(state *MovementState) { | ||
| if !state.CollideX && !state.CollideZ { | ||
| return | ||
| } | ||
| bb := state.BoundingBox(s.Options.UseSlideOffset).GrowVec3(mgl32.Vec3{1e-3, 0, 1e-3}) | ||
| min, maxPoint := bb.Min(), bb.Max() | ||
| for x := int(math32.Floor(min.X())); x < int(math32.Ceil(maxPoint.X())); x++ { | ||
| for y := int(math32.Floor(min.Y())); y < int(math32.Ceil(maxPoint.Y())); y++ { | ||
| for z := int(math32.Floor(min.Z())); z < int(math32.Ceil(maxPoint.Z())); z++ { | ||
| pos := cube.Pos{x, y, z} | ||
| if !bb.IntersectsWith(cube.Box32(0, 0, 0, 1, 1, 1).Translate(posVec3(pos))) { | ||
| continue | ||
| } | ||
| if s.blockMovementSemantics(s.World.Block(pos)).Honey { | ||
| velocity := state.Vel | ||
| velocity[0] *= 0.4 | ||
| velocity[1] = max(-0.12, velocity[1]) | ||
| velocity[2] *= 0.4 | ||
| state.SetVel(velocity) | ||
| return | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This only scales the existing velocity, but the slowdown also applies to the pending movement request. With a queued berry/powder-snow multiplier, a zero-velocity player with new input reaches moveRelative unchanged, and the later stuckMovement branch only clears velocity after recording the full displacement. Scale the pending horizontal impulse/request too and add a two-tick input-driven regression test.