void ApplyLiquidForcesTo(Entity e, double dt) { if (e.Mass <= 0) { return; } RigidTransform ert = new RigidTransform(e.Position, e.Orientation); BoundingBox entbb; e.CollisionInformation.Shape.GetBoundingBox(ref ert, out entbb); Location min = new Location(entbb.Min); Location max = new Location(entbb.Max); min = min.GetBlockLocation(); max = max.GetUpperBlockBorder(); for (int x = (int)min.X; x < max.X; x++) { for (int y = (int)min.Y; y < max.Y; y++) { for (int z = (int)min.Z; z < max.Z; z++) { Location c = new Location(x, y, z); Material mat = (Material)TheRegion.GetBlockInternal_NoLoad(c).BlockMaterial; if (mat.GetSolidity() != MaterialSolidity.LIQUID) { continue; } // TODO: Account for block shape? double vol = e.CollisionInformation.Shape.Volume; double dens = (e.Mass / vol); double WaterDens = 5; // TODO: Read from material. // TODO: Sanity of values. double modifier = (double)(WaterDens / dens); double submod = 0.125f; // TODO: Tracing accuracy! Vector3 impulse = -(TheRegion.PhysicsWorld.ForceUpdater.Gravity + TheRegion.GravityNormal.ToBVector() * 0.4f) * e.Mass * dt * modifier * submod; // TODO: Don't apply smaller logic this if scale is big! for (double x2 = 0.25f; x2 < 1; x2 += 0.5f) { for (double y2 = 0.25f; y2 < 1; y2 += 0.5f) { for (double z2 = 0.25f; z2 < 1; z2 += 0.5f) { Location lc = c + new Location(x2, y2, z2); RayHit rh; if (e.CollisionInformation.RayCast(new Ray(lc.ToBVector(), new Vector3(0, 0, 1)), 0.01f, out rh)) // TODO: Efficiency! { Vector3 center = lc.ToBVector(); e.ApplyImpulse(ref center, ref impulse); e.ModifyLinearDamping(mat.GetSpeedMod()); e.ModifyAngularDamping(mat.GetSpeedMod()); } } } } } } } }