Mostly port entity components to C.

This commit is contained in:
UnknownShadow200 2018-04-19 21:52:16 +10:00
parent 468e958e36
commit bfe4bc05e0
42 changed files with 861 additions and 443 deletions

View File

@ -82,7 +82,7 @@ namespace ClassicalSharp {
public int ToArgb() { return A << 24 | R << 16 | G << 8 | B; } public int ToArgb() { return A << 24 | R << 16 | G << 8 | B; }
public static FastColour Argb(int c) { public static FastColour Argb(int c) {
FastColour col = default(FastColour); FastColour col;
col.A = (byte)(c >> 24); col.A = (byte)(c >> 24);
col.R = (byte)(c >> 16); col.R = (byte)(c >> 16);
col.G = (byte)(c >> 8); col.G = (byte)(c >> 8);
@ -102,7 +102,7 @@ namespace ClassicalSharp {
} }
public static FastColour Unpack(int c) { public static FastColour Unpack(int c) {
FastColour col = default(FastColour); FastColour col;
col.A = (byte)(c >> 24); col.A = (byte)(c >> 24);
col.G = (byte)(c >> 8); col.G = (byte)(c >> 8);
#if USE_DX #if USE_DX

View File

@ -144,7 +144,6 @@
<Compile Include="Entities\Mobs\AI.cs" /> <Compile Include="Entities\Mobs\AI.cs" />
<Compile Include="Entities\Components\AnimatedComponent.cs" /> <Compile Include="Entities\Components\AnimatedComponent.cs" />
<Compile Include="Entities\Components\HacksComponent.cs" /> <Compile Include="Entities\Components\HacksComponent.cs" />
<Compile Include="Entities\Components\InputComponent.cs" />
<Compile Include="Entities\Components\CollisionsComponent.cs" /> <Compile Include="Entities\Components\CollisionsComponent.cs" />
<Compile Include="Entities\Components\NewCollisionsComponent.cs" /> <Compile Include="Entities\Components\NewCollisionsComponent.cs" />
<Compile Include="Entities\Components\PhysicsComponent.cs" /> <Compile Include="Entities\Components\PhysicsComponent.cs" />

View File

@ -117,7 +117,7 @@ namespace ClassicalSharp.Entities {
// TODO: the Tilt code was designed for 60 ticks/second, fix it up for 20 ticks/second // TODO: the Tilt code was designed for 60 ticks/second, fix it up for 20 ticks/second
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
AnimatedComponent.DoTilt(ref velTiltStrengthN, p.Hacks.Noclip || p.Hacks.Flying); AnimatedComponent.DoTilt(ref velTiltStrengthN, p.Hacks.Floating);
} }
} }

View File

@ -111,7 +111,7 @@ namespace ClassicalSharp.Entities {
} }
void ClipXMin(ref AABB blockBB, ref AABB entityBB, bool wasOn, ref AABB finalBB, ref AABB extentBB, ref Vector3 size) { void ClipXMin(ref AABB blockBB, ref AABB entityBB, bool wasOn, ref AABB finalBB, ref AABB extentBB, ref Vector3 size) {
if (!wasOn || !DidSlide(blockBB, ref size, ref finalBB, ref entityBB, ref extentBB)) { if (!wasOn || !DidSlide(ref blockBB, ref size, ref finalBB, ref entityBB, ref extentBB)) {
entity.Position.X = blockBB.Min.X - size.X / 2 - Adjustment; entity.Position.X = blockBB.Min.X - size.X / 2 - Adjustment;
ClipX(ref size, ref entityBB, ref extentBB); ClipX(ref size, ref entityBB, ref extentBB);
hitXMin = true; hitXMin = true;
@ -119,7 +119,7 @@ namespace ClassicalSharp.Entities {
} }
void ClipXMax(ref AABB blockBB, ref AABB entityBB, bool wasOn, ref AABB finalBB, ref AABB extentBB, ref Vector3 size) { void ClipXMax(ref AABB blockBB, ref AABB entityBB, bool wasOn, ref AABB finalBB, ref AABB extentBB, ref Vector3 size) {
if (!wasOn || !DidSlide(blockBB, ref size, ref finalBB, ref entityBB, ref extentBB)) { if (!wasOn || !DidSlide(ref blockBB, ref size, ref finalBB, ref entityBB, ref extentBB)) {
entity.Position.X = blockBB.Max.X + size.X / 2 + Adjustment; entity.Position.X = blockBB.Max.X + size.X / 2 + Adjustment;
ClipX(ref size, ref entityBB, ref extentBB); ClipX(ref size, ref entityBB, ref extentBB);
hitXMax = true; hitXMax = true;
@ -127,7 +127,7 @@ namespace ClassicalSharp.Entities {
} }
void ClipZMax(ref AABB blockBB, ref AABB entityBB, bool wasOn, ref AABB finalBB, ref AABB extentBB, ref Vector3 size) { void ClipZMax(ref AABB blockBB, ref AABB entityBB, bool wasOn, ref AABB finalBB, ref AABB extentBB, ref Vector3 size) {
if (!wasOn || !DidSlide(blockBB, ref size, ref finalBB, ref entityBB, ref extentBB)) { if (!wasOn || !DidSlide(ref blockBB, ref size, ref finalBB, ref entityBB, ref extentBB)) {
entity.Position.Z = blockBB.Max.Z + size.Z / 2 + Adjustment; entity.Position.Z = blockBB.Max.Z + size.Z / 2 + Adjustment;
ClipZ(ref size, ref entityBB, ref extentBB); ClipZ(ref size, ref entityBB, ref extentBB);
hitZMax = true; hitZMax = true;
@ -135,7 +135,7 @@ namespace ClassicalSharp.Entities {
} }
void ClipZMin(ref AABB blockBB, ref AABB entityBB, bool wasOn, ref AABB finalBB, ref AABB extentBB, ref Vector3 size) { void ClipZMin(ref AABB blockBB, ref AABB entityBB, bool wasOn, ref AABB finalBB, ref AABB extentBB, ref Vector3 size) {
if (!wasOn || !DidSlide(blockBB, ref size, ref finalBB, ref entityBB, ref extentBB)) { if (!wasOn || !DidSlide(ref blockBB, ref size, ref finalBB, ref entityBB, ref extentBB)) {
entity.Position.Z = blockBB.Min.Z - size.Z / 2 - Adjustment; entity.Position.Z = blockBB.Min.Z - size.Z / 2 - Adjustment;
ClipZ(ref size, ref entityBB, ref extentBB); ClipZ(ref size, ref entityBB, ref extentBB);
hitZMin = true; hitZMin = true;
@ -155,26 +155,24 @@ namespace ClassicalSharp.Entities {
hitYMax = true; hitYMax = true;
} }
bool DidSlide(AABB blockBB, ref Vector3 size, ref AABB finalBB, ref AABB entityBB, ref AABB extentBB) { bool DidSlide(ref AABB blockBB, ref Vector3 size, ref AABB finalBB, ref AABB entityBB, ref AABB extentBB) {
float yDist = blockBB.Max.Y - entityBB.Min.Y; float yDist = blockBB.Max.Y - entityBB.Min.Y;
if (yDist > 0 && yDist <= entity.StepSize + 0.01f) { if (yDist > 0 && yDist <= entity.StepSize + 0.01f) {
float blockXMin = blockBB.Min.X, blockZMin = blockBB.Min.Z; float blockBB_MinX = Math.Max(blockBB.Min.X, blockBB.Max.X - size.X / 2);
blockBB.Min.X = Math.Max(blockBB.Min.X, blockBB.Max.X - size.X / 2); float blockBB_MaxX = Math.Min(blockBB.Max.X, blockBB.Min.X + size.X / 2);
blockBB.Max.X = Math.Min(blockBB.Max.X, blockXMin + size.X / 2); float blockBB_MinZ = Math.Max(blockBB.Min.Z, blockBB.Max.Z - size.Z / 2);
blockBB.Min.Z = Math.Max(blockBB.Min.Z, blockBB.Max.Z - size.Z / 2); float blockBB_MaxZ = Math.Min(blockBB.Max.Z, blockBB.Min.Z + size.Z / 2);
blockBB.Max.Z = Math.Min(blockBB.Max.Z, blockZMin + size.Z / 2);
AABB adjBB; AABB adjBB;
adjBB.Min.X = Math.Min(finalBB.Min.X, blockBB.Min.X + Adjustment); adjBB.Min.X = Math.Min(finalBB.Min.X, blockBB_MinX + Adjustment);
adjBB.Max.X = Math.Max(finalBB.Max.X, blockBB.Max.X - Adjustment); adjBB.Max.X = Math.Max(finalBB.Max.X, blockBB_MaxX - Adjustment);
adjBB.Min.Y = blockBB.Max.Y + Adjustment; adjBB.Min.Y = blockBB.Max.Y + Adjustment;
adjBB.Max.Y = adjBB.Min.Y + size.Y; adjBB.Max.Y = adjBB.Min.Y + size.Y;
adjBB.Min.Z = Math.Min(finalBB.Min.Z, blockBB.Min.Z + Adjustment); adjBB.Min.Z = Math.Min(finalBB.Min.Z, blockBB_MinZ + Adjustment);
adjBB.Max.Z = Math.Max(finalBB.Max.Z, blockBB.Max.Z - Adjustment); adjBB.Max.Z = Math.Max(finalBB.Max.Z, blockBB_MaxZ - Adjustment);
if (!CanSlideThrough(ref adjBB)) return false; if (!CanSlideThrough(ref adjBB)) return false;
entity.Position.Y = adjBB.Min.Y;
entity.Position.Y = blockBB.Max.Y + Adjustment;
entity.onGround = true; entity.onGround = true;
ClipY(ref size, ref entityBB, ref extentBB); ClipY(ref size, ref entityBB, ref extentBB);
return true; return true;
@ -187,13 +185,15 @@ namespace ClassicalSharp.Entities {
Vector3I bbMax = Vector3I.Floor(adjFinalBB.Max); Vector3I bbMax = Vector3I.Floor(adjFinalBB.Max);
AABB blockBB; AABB blockBB;
Vector3 pos;
for (int y = bbMin.Y; y <= bbMax.Y; y++) for (int y = bbMin.Y; y <= bbMax.Y; y++)
for (int z = bbMin.Z; z <= bbMax.Z; z++) for (int z = bbMin.Z; z <= bbMax.Z; z++)
for (int x = bbMin.X; x <= bbMax.X; x++) for (int x = bbMin.X; x <= bbMax.X; x++)
{ {
pos.X = x; pos.Y = y; pos.Z = z;
BlockID block = game.World.GetPhysicsBlock(x, y, z); BlockID block = game.World.GetPhysicsBlock(x, y, z);
blockBB.Min = new Vector3(x, y, z) + BlockInfo.MinBB[block]; blockBB.Min = pos + BlockInfo.MinBB[block];
blockBB.Max = new Vector3(x, y, z) + BlockInfo.MaxBB[block]; blockBB.Max = pos + BlockInfo.MaxBB[block];
if (!blockBB.Intersects(adjFinalBB)) continue; if (!blockBB.Intersects(adjFinalBB)) continue;
if (BlockInfo.Collide[block] == CollideType.Solid) return false; if (BlockInfo.Collide[block] == CollideType.Solid) return false;

View File

@ -51,7 +51,7 @@ namespace ClassicalSharp.Entities {
public bool Noclip, Flying, FlyingUp, FlyingDown, Speeding, HalfSpeeding; public bool Noclip, Flying, FlyingUp, FlyingDown, Speeding, HalfSpeeding;
public bool CanJumpHigher { get { return Enabled && CanAnyHacks && CanSpeed; } } public bool CanJumpHigher { get { return Enabled && CanAnyHacks && CanSpeed; } }
public bool Floating { get { return Noclip || Flying; } } public bool Floating; // true if Noclip or Flying
public string HacksFlags; public string HacksFlags;
string GetFlagValue(string flag) { string GetFlagValue(string flag) {

View File

@ -1,93 +0,0 @@
// Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3
using System;
using ClassicalSharp.Physics;
using OpenTK;
using OpenTK.Input;
using BlockID = System.UInt16;
namespace ClassicalSharp.Entities {
/// <summary> Entity component that performs input handling. </summary>
public sealed class InputComponent {
Entity entity;
Game game;
public HacksComponent Hacks;
public PhysicsComponent physics;
public InputComponent(Game game, Entity entity) {
this.game = game;
this.entity = entity;
}
internal bool Handles(Key key) {
LocalPlayer p = (LocalPlayer)entity;
KeyMap keys = game.Input.Keys;
if (key == keys[KeyBind.Respawn] && Hacks.CanRespawn) {
DoRespawn();
} else if (key == keys[KeyBind.SetSpawn] && Hacks.CanRespawn) {
p.Spawn = entity.Position;
p.Spawn.X = Utils.Floor(p.Spawn.X) + 0.5f;
p.Spawn.Z = Utils.Floor(p.Spawn.Z) + 0.5f;
p.SpawnRotY = entity.RotY;
p.SpawnHeadX = entity.HeadX;
DoRespawn();
} else if (key == keys[KeyBind.Fly] && Hacks.CanFly && Hacks.Enabled) {
Hacks.Flying = !Hacks.Flying;
} else if (key == keys[KeyBind.NoClip] && Hacks.CanNoclip && Hacks.Enabled && !Hacks.WOMStyleHacks) {
if (Hacks.Noclip) entity.Velocity.Y = 0;
Hacks.Noclip = !Hacks.Noclip;
} else if (key == keys[KeyBind.Jump] && !entity.onGround && !(Hacks.Flying || Hacks.Noclip)) {
int maxJumps = Hacks.CanDoubleJump && Hacks.WOMStyleHacks ? 2 : 0;
maxJumps = Math.Max(maxJumps, Hacks.MaxJumps - 1);
if (physics.multiJumps < maxJumps) {
physics.DoNormalJump();
physics.multiJumps++;
}
} else {
return false;
}
return true;
}
void DoRespawn() {
if (!game.World.HasBlocks) return;
LocalPlayer p = (LocalPlayer)entity;
Vector3 spawn = p.Spawn;
if (game.World.IsValidPos(Vector3I.Floor(spawn)))
FindHighestFree(ref spawn);
spawn.Y += 2/16f;
LocationUpdate update = LocationUpdate.MakePosAndOri(spawn, p.SpawnRotY, p.SpawnHeadX, false);
entity.SetLocation(update, false);
entity.Velocity = Vector3.Zero;
// Update onGround, otherwise if 'respawn' then 'space' is pressed, you still jump into the air if onGround was true before
AABB bb = entity.Bounds;
bb.Min.Y -= 0.01f; bb.Max.Y = bb.Min.Y;
entity.onGround = entity.TouchesAny(bb, touchesAnySolid);
}
static Predicate<BlockID> touchesAnySolid = IsSolidCollide;
static bool IsSolidCollide(BlockID b) { return BlockInfo.Collide[b] == CollideType.Solid; }
void FindHighestFree(ref Vector3 spawn) {
AABB bb = AABB.Make(spawn, entity.Size);
Vector3I P = Vector3I.Floor(spawn);
// Spawn player at highest valid position.
for (int y = P.Y; y <= game.World.Height; y++) {
float spawnY = Respawn.HighestFreeY(game, ref bb);
if (spawnY == float.NegativeInfinity) {
BlockID block = game.World.GetPhysicsBlock(P.X, y, P.Z);
float height = BlockInfo.Collide[block] == CollideType.Solid ? BlockInfo.MaxBB[block].Y : 0;
spawn.Y = y + height + Entity.Adjustment;
return;
}
bb.Min.Y += 1; bb.Max.Y += 1;
}
}
}
}

View File

@ -7,7 +7,7 @@ using BlockID = System.UInt16;
namespace ClassicalSharp.Entities { namespace ClassicalSharp.Entities {
/// <summary> Entity component that performs collision detection. </summary> /// <summary> Entity component that performs collisions. </summary>
public sealed class PhysicsComponent { public sealed class PhysicsComponent {
bool useLiquidGravity = false; // used by BlockDefinitions. bool useLiquidGravity = false; // used by BlockDefinitions.
@ -63,11 +63,12 @@ namespace ClassicalSharp.Entities {
if (hacks.Speeding && hacks.CanSpeed) entity.Velocity.Y += 0.04f; if (hacks.Speeding && hacks.CanSpeed) entity.Velocity.Y += 0.04f;
if (hacks.HalfSpeeding && hacks.CanSpeed) entity.Velocity.Y += 0.02f; if (hacks.HalfSpeeding && hacks.CanSpeed) entity.Velocity.Y += 0.02f;
} else if (pastJumpPoint) { } else if (pastJumpPoint) {
// either A) jump bob in water B) climb up solid on side // either A) climb up solid on side B) jump bob in water
if (collisions.HorizontalCollision) if (collisions.HorizontalCollision) {
entity.Velocity.Y += touchLava ? 0.30f : 0.13f; entity.Velocity.Y += touchLava ? 0.30f : 0.13f;
else if (canLiquidJump) } else if (canLiquidJump) {
entity.Velocity.Y += touchLava ? 0.20f : 0.10f; entity.Velocity.Y += touchLava ? 0.20f : 0.10f;
}
canLiquidJump = false; canLiquidJump = false;
} }
} else if (useLiquidGravity) { } else if (useLiquidGravity) {
@ -152,17 +153,14 @@ namespace ClassicalSharp.Entities {
bool OnIce(Entity entity) { bool OnIce(Entity entity) {
Vector3 under = entity.Position; under.Y -= 0.01f; Vector3 under = entity.Position; under.Y -= 0.01f;
if (BlockInfo.ExtendedCollide[GetBlock(under)] == CollideType.Ice) return true; BlockID blockUnder = game.World.SafeGetBlock(Vector3I.Floor(under));
if (BlockInfo.ExtendedCollide[blockUnder] == CollideType.Ice) return true;
AABB bounds = entity.Bounds; AABB bounds = entity.Bounds;
bounds.Min.Y -= 0.01f; bounds.Max.Y = bounds.Min.Y; bounds.Min.Y -= 0.01f; bounds.Max.Y = bounds.Min.Y;
return entity.TouchesAny(bounds, touchesSlipperyIce); return entity.TouchesAny(bounds, touchesSlipperyIce);
} }
BlockID GetBlock(Vector3 coords) {
return game.World.SafeGetBlock(Vector3I.Floor(coords));
}
static Predicate<BlockID> touchesSlipperyIce = IsSlipperyIce; static Predicate<BlockID> touchesSlipperyIce = IsSlipperyIce;
static bool IsSlipperyIce(BlockID b) { return BlockInfo.ExtendedCollide[b] == CollideType.SlipperyIce; } static bool IsSlipperyIce(BlockID b) { return BlockInfo.ExtendedCollide[b] == CollideType.SlipperyIce; }
@ -227,7 +225,7 @@ namespace ClassicalSharp.Entities {
Vector3I max = Vector3I.Floor(bounds.Max); Vector3I max = Vector3I.Floor(bounds.Max);
float modifier = inf; float modifier = inf;
AABB blockBB = default(AABB); AABB blockBB;
min.X = min.X < 0 ? 0 : min.X; max.X = max.X > game.World.MaxX ? game.World.MaxX : max.X; min.X = min.X < 0 ? 0 : min.X; max.X = max.X > game.World.MaxX ? game.World.MaxX : max.X;
min.Y = min.Y < 0 ? 0 : min.Y; max.Y = max.Y > game.World.MaxY ? game.World.MaxY : max.Y; min.Y = min.Y < 0 ? 0 : min.Y; max.Y = max.Y > game.World.MaxY ? game.World.MaxY : max.Y;
min.Z = min.Z < 0 ? 0 : min.Z; max.Z = max.Z > game.World.MaxZ ? game.World.MaxZ : max.Z; min.Z = min.Z < 0 ? 0 : min.Z; max.Z = max.Z > game.World.MaxZ ? game.World.MaxZ : max.Z;
@ -237,7 +235,7 @@ namespace ClassicalSharp.Entities {
for (int x = min.X; x <= max.X; x++) for (int x = min.X; x <= max.X; x++)
{ {
BlockID block = game.World.GetBlock(x, y, z); BlockID block = game.World.GetBlock(x, y, z);
if (block == 0) continue; if (block == Block.Air) continue;
byte collide = BlockInfo.Collide[block]; byte collide = BlockInfo.Collide[block];
if (collide == CollideType.Solid && !checkSolid) continue; if (collide == CollideType.Solid && !checkSolid) continue;

View File

@ -170,7 +170,7 @@ namespace ClassicalSharp.Entities {
Vector3I min = Vector3I.Floor(bounds.Min); Vector3I min = Vector3I.Floor(bounds.Min);
Vector3I max = Vector3I.Floor(bounds.Max); Vector3I max = Vector3I.Floor(bounds.Max);
AABB blockBB = default(AABB); AABB blockBB;
Vector3 v; Vector3 v;
min.X = min.X < 0 ? 0 : min.X; max.X = max.X > game.World.MaxX ? game.World.MaxX : max.X; min.X = min.X < 0 ? 0 : min.X; max.X = max.X > game.World.MaxX ? game.World.MaxX : max.X;
min.Y = min.Y < 0 ? 0 : min.Y; max.Y = max.Y > game.World.MaxY ? game.World.MaxY : max.Y; min.Y = min.Y < 0 ? 0 : min.Y; max.Y = max.Y > game.World.MaxY ? game.World.MaxY : max.Y;

View File

@ -1,9 +1,11 @@
// Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3 // Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3
using System; using System;
using System.Drawing; using System.Drawing;
using ClassicalSharp.Physics;
using ClassicalSharp.Renderers; using ClassicalSharp.Renderers;
using OpenTK; using OpenTK;
using OpenTK.Input; using OpenTK.Input;
using BlockID = System.UInt16;
namespace ClassicalSharp.Entities { namespace ClassicalSharp.Entities {
@ -27,7 +29,6 @@ namespace ClassicalSharp.Entities {
internal CollisionsComponent collisions; internal CollisionsComponent collisions;
public HacksComponent Hacks; public HacksComponent Hacks;
internal PhysicsComponent physics; internal PhysicsComponent physics;
internal InputComponent input;
internal SoundComponent sound; internal SoundComponent sound;
internal LocalInterpComponent interp; internal LocalInterpComponent interp;
internal TiltComponent tilt; internal TiltComponent tilt;
@ -39,31 +40,28 @@ namespace ClassicalSharp.Entities {
collisions = new CollisionsComponent(game, this); collisions = new CollisionsComponent(game, this);
Hacks = new HacksComponent(game); Hacks = new HacksComponent(game);
physics = new PhysicsComponent(game, this); physics = new PhysicsComponent(game, this);
input = new InputComponent(game, this);
sound = new SoundComponent(game, this); sound = new SoundComponent(game, this);
interp = new LocalInterpComponent(game, this); interp = new LocalInterpComponent(game, this);
tilt = new TiltComponent(game); tilt = new TiltComponent(game);
physics.hacks = Hacks; physics.collisions = collisions;
physics.hacks = Hacks; input.Hacks = Hacks;
physics.collisions = collisions;
input.physics = physics;
} }
public override void Tick(double delta) { public override void Tick(double delta) {
if (!game.World.HasBlocks) return; if (!game.World.HasBlocks) return;
StepSize = Hacks.FullBlockStep && Hacks.Enabled && Hacks.CanAnyHacks StepSize = Hacks.FullBlockStep && Hacks.Enabled && Hacks.CanAnyHacks && Hacks.CanSpeed ? 1 : 0.5f;
&& Hacks.CanSpeed ? 1 : 0.5f;
OldVelocity = Velocity; OldVelocity = Velocity;
float xMoving = 0, zMoving = 0; float xMoving = 0, zMoving = 0;
interp.AdvanceState(); interp.AdvanceState();
bool wasOnGround = onGround; bool wasOnGround = onGround;
HandleInput(ref xMoving, ref zMoving); HandleInput(ref xMoving, ref zMoving);
Hacks.Floating = Hacks.Noclip || Hacks.Flying;
if (!Hacks.Floating && Hacks.CanBePushed) physics.DoEntityPush(); if (!Hacks.Floating && Hacks.CanBePushed) physics.DoEntityPush();
// Immediate stop in noclip mode // Immediate stop in noclip mode
if (!Hacks.NoclipSlide && (Hacks.Noclip && xMoving == 0 && zMoving == 0)) if (!Hacks.NoclipSlide && (Hacks.Noclip && xMoving == 0 && zMoving == 0)) {
Velocity = Vector3.Zero; Velocity = Vector3.Zero;
}
physics.UpdateVelocityState(); physics.UpdateVelocityState();
physics.PhysicsTick(GetHeadingVelocity(zMoving, xMoving)); physics.PhysicsTick(GetHeadingVelocity(zMoving, xMoving));
@ -161,5 +159,70 @@ namespace ClassicalSharp.Entities {
physics.serverJumpVel = 0.42f; physics.serverJumpVel = 0.42f;
Health = 20; Health = 20;
} }
static Predicate<BlockID> touchesAnySolid = IsSolidCollide;
static bool IsSolidCollide(BlockID b) { return BlockInfo.Collide[b] == CollideType.Solid; }
void DoRespawn() {
if (!game.World.HasBlocks) return;
Vector3 spawn = Spawn;
Vector3I P = Vector3I.Floor(spawn);
AABB bb;
// Spawn player at highest valid position
if (game.World.IsValidPos(P)) {
bb = AABB.Make(spawn, Size);
for (int y = P.Y; y <= game.World.Height; y++) {
float spawnY = Respawn.HighestFreeY(game, ref bb);
if (spawnY == float.NegativeInfinity) {
BlockID block = game.World.GetPhysicsBlock(P.X, y, P.Z);
float height = BlockInfo.Collide[block] == CollideType.Solid ? BlockInfo.MaxBB[block].Y : 0;
spawn.Y = y + height + Entity.Adjustment;
break;
}
bb.Min.Y += 1; bb.Max.Y += 1;
}
}
spawn.Y += 2/16f;
LocationUpdate update = LocationUpdate.MakePosAndOri(spawn, SpawnRotY, SpawnHeadX, false);
SetLocation(update, false);
Velocity = Vector3.Zero;
// Update onGround, otherwise if 'respawn' then 'space' is pressed, you still jump into the air if onGround was true before
bb = Bounds;
bb.Min.Y -= 0.01f; bb.Max.Y = bb.Min.Y;
onGround = TouchesAny(bb, touchesAnySolid);
}
public bool HandlesKey(Key key) {
KeyMap keys = game.Input.Keys;
if (key == keys[KeyBind.Respawn] && Hacks.CanRespawn) {
DoRespawn();
} else if (key == keys[KeyBind.SetSpawn] && Hacks.CanRespawn) {
Spawn = Position;
Spawn.X = Utils.Floor(Spawn.X) + 0.5f;
Spawn.Z = Utils.Floor(Spawn.Z) + 0.5f;
SpawnRotY = RotY;
SpawnHeadX = HeadX;
DoRespawn();
} else if (key == keys[KeyBind.Fly] && Hacks.CanFly && Hacks.Enabled) {
Hacks.Flying = !Hacks.Flying;
} else if (key == keys[KeyBind.NoClip] && Hacks.CanNoclip && Hacks.Enabled && !Hacks.WOMStyleHacks) {
if (Hacks.Noclip) Velocity.Y = 0;
Hacks.Noclip = !Hacks.Noclip;
} else if (key == keys[KeyBind.Jump] && !onGround && !(Hacks.Flying || Hacks.Noclip)) {
int maxJumps = Hacks.CanDoubleJump && Hacks.WOMStyleHacks ? 2 : 0;
maxJumps = Math.Max(maxJumps, Hacks.MaxJumps - 1);
if (physics.multiJumps < maxJumps) {
physics.DoNormalJump();
physics.multiJumps++;
}
} else {
return false;
}
return true;
}
} }
} }

View File

@ -160,7 +160,7 @@ namespace ClassicalSharp {
} else if (key == Keys[KeyBind.Screenshot]) { } else if (key == Keys[KeyBind.Screenshot]) {
game.screenshotRequested = true; game.screenshotRequested = true;
} else if (!game.Gui.ActiveScreen.HandlesKeyDown(key)) { } else if (!game.Gui.ActiveScreen.HandlesKeyDown(key)) {
if (!HandleBuiltinKey(key) && !game.LocalPlayer.input.Handles(key)) if (!HandleBuiltinKey(key) && !game.LocalPlayer.HandlesKey(key))
HandleHotkey(key); HandleHotkey(key);
} }
lastKey = key; lastKey = key;

View File

@ -160,8 +160,11 @@ namespace ClassicalSharp.Renderers {
// TODO: rewrite this to avoid raising the event? want to avoid recreating vbos too many times often // TODO: rewrite this to avoid raising the event? want to avoid recreating vbos too many times often
if (fogDensity != 0) { if (fogDensity != 0) {
// Exp fog mode: f = e^(-density*coord) // Exp fog mode: f = e^(-density*coord)
// Solve for f = 0.05 to figure out coord (good approx for fog end) // Solve coord for f = 0.05 (good approx for fog end)
float dist = (float)Math.Log(0.05) / -fogDensity; // i.e. log(0.05) = -density * coord
const double log005 = -2.99573227355399;
double dist = log005 / -fogDensity;
game.SetViewDistance((int)dist, false); game.SetViewDistance((int)dist, false);
} else { } else {
game.SetViewDistance(game.UserViewDistance, false); game.SetViewDistance(game.UserViewDistance, false);
@ -233,7 +236,9 @@ namespace ClassicalSharp.Renderers {
// 0.99=z/end --> z=end*0.99 // 0.99=z/end --> z=end*0.99
// therefore // therefore
// d = -ln(0.01)/(end*0.99) // d = -ln(0.01)/(end*0.99)
double density = -Math.Log(0.01) / (game.ViewDistance * 0.99);
const double log001 = -4.60517018598809;
double density = -log001 / (game.ViewDistance * 0.99);
gfx.SetFogDensity((float)density); gfx.SetFogDensity((float)density);
} else { } else {
gfx.SetFogMode(Fog.Linear); gfx.SetFogMode(Fog.Linear);

View File

@ -16,7 +16,7 @@ namespace ClassicalSharp {
int minZ = Utils.Floor(bb.Min.Z), maxZ = Utils.Floor(bb.Max.Z); int minZ = Utils.Floor(bb.Min.Z), maxZ = Utils.Floor(bb.Max.Z);
float spawnY = float.NegativeInfinity; float spawnY = float.NegativeInfinity;
AABB blockBB = default(AABB); AABB blockBB;
for (int y = minY; y <= maxY; y++) for (int y = minY; y <= maxY; y++)
for (int z = minZ; z <= maxZ; z++) for (int z = minZ; z <= maxZ; z++)

View File

@ -74,8 +74,6 @@ namespace OpenTK {
public static readonly Vector3 One = new Vector3(1, 1, 1); public static readonly Vector3 One = new Vector3(1, 1, 1);
public static readonly int SizeInBytes = 3 * sizeof( float );
public static void Add(ref Vector3 a, ref Vector3 b, out Vector3 result) { public static void Add(ref Vector3 a, ref Vector3 b, out Vector3 result) {
result = new Vector3(a.X + b.X, a.Y + b.Y, a.Z + b.Z); result = new Vector3(a.X + b.X, a.Y + b.Y, a.Z + b.Z);
} }

View File

@ -30,8 +30,8 @@ void LavaAnimation_Tick(UInt32* ptr, Int32 size) {
for (y = 0; y < size; y++) { for (y = 0; y < size; y++) {
for (x = 0; x < size; x++) { for (x = 0; x < size; x++) {
/* Calculate the colour at this coordinate in the heatmap */ /* Calculate the colour at this coordinate in the heatmap */
Int32 xx = x + (Int32)(1.2f * Math_Sin(y * 22.5f * MATH_DEG2RAD)); Int32 xx = x + (Int32)(1.2f * Math_SinF(y * 22.5f * MATH_DEG2RAD));
Int32 yy = y + (Int32)(1.2f * Math_Sin(x * 22.5f * MATH_DEG2RAD)); Int32 yy = y + (Int32)(1.2f * Math_SinF(x * 22.5f * MATH_DEG2RAD));
Real32 lSoupHeat = Real32 lSoupHeat =
L_soupHeat[((yy - 1) & mask) << shift | ((xx - 1) & mask)] + L_soupHeat[((yy - 1) & mask) << shift | ((xx - 1) & mask)] +
L_soupHeat[((yy - 1) & mask) << shift | (xx & mask)] + L_soupHeat[((yy - 1) & mask) << shift | (xx & mask)] +

View File

@ -487,7 +487,7 @@ BlockID AutoRotate_RotateBlock(BlockID block) {
Vector3 translated, offset; Vector3 translated, offset;
Vector3I_ToVector3(&translated, &Game_SelectedPos.TranslatedPos); Vector3I_ToVector3(&translated, &Game_SelectedPos.TranslatedPos);
Vector3_Subtract(&offset, &Game_SelectedPos.Intersect, &translated); Vector3_Sub(&offset, &Game_SelectedPos.Intersect, &translated);
if (AR_EQ2(dir, 'n', 'w') || AR_EQ2(dir, 'n', 'e') || AR_EQ2(dir, 's', 'w') || AR_EQ2(dir, 's', 'e')) { if (AR_EQ2(dir, 'n', 'w') || AR_EQ2(dir, 'n', 'e') || AR_EQ2(dir, 's', 'w') || AR_EQ2(dir, 's', 'e')) {
return AutoRotate_RotateCorner(block, &baseName, offset); return AutoRotate_RotateCorner(block, &baseName, offset);

View File

@ -148,8 +148,8 @@ Vector3 FirstPersonCamera_GetCameraPos(Real32 t) {
camPos.Y += Camera_BobbingVer; camPos.Y += Camera_BobbingVer;
Real32 headY = (p->HeadY * MATH_DEG2RAD); Real32 headY = (p->HeadY * MATH_DEG2RAD);
camPos.X += Camera_BobbingHor * Math_Cos(headY); camPos.X += Camera_BobbingHor * Math_CosF(headY);
camPos.Z += Camera_BobbingHor * Math_Sin(headY); camPos.Z += Camera_BobbingHor * Math_SinF(headY);
return camPos; return camPos;
} }

View File

@ -138,6 +138,7 @@
<BufferSecurityCheck>false</BufferSecurityCheck> <BufferSecurityCheck>false</BufferSecurityCheck>
<AdditionalOptions> <AdditionalOptions>
</AdditionalOptions> </AdditionalOptions>
<EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Windows</SubSystem> <SubSystem>Windows</SubSystem>
@ -166,6 +167,7 @@
<BufferSecurityCheck>false</BufferSecurityCheck> <BufferSecurityCheck>false</BufferSecurityCheck>
<AdditionalOptions> <AdditionalOptions>
</AdditionalOptions> </AdditionalOptions>
<EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Windows</SubSystem> <SubSystem>Windows</SubSystem>

View File

@ -16,12 +16,13 @@
#include "AsyncDownloader.h" #include "AsyncDownloader.h"
#include "ErrorHandler.h" #include "ErrorHandler.h"
#include "IModel.h" #include "IModel.h"
#include "Input.h"
const UInt8* NameMode_Names[NAME_MODE_COUNT] = { "None", "Hovered", "All", "AllHovered", "AllUnscaled" }; const UInt8* NameMode_Names[NAME_MODE_COUNT] = { "None", "Hovered", "All", "AllHovered", "AllUnscaled" };
const UInt8* ShadowMode_Names[SHADOW_MODE_COUNT] = { "None", "SnapToBlock", "Circle", "CircleAll" }; const UInt8* ShadowMode_Names[SHADOW_MODE_COUNT] = { "None", "SnapToBlock", "Circle", "CircleAll" };
Real32 LocationUpdate_Clamp(Real32 degrees) { Real32 LocationUpdate_Clamp(Real32 degrees) {
degrees = Math_Mod(degrees, 360.0f); degrees = Math_ModF(degrees, 360.0f);
if (degrees < 0) degrees += 360.0f; if (degrees < 0) degrees += 360.0f;
return degrees; return degrees;
} }
@ -154,33 +155,29 @@ void Entity_SetModel(Entity* entity, STRING_PURE String* model) {
void Entity_UpdateModelBounds(Entity* entity) { void Entity_UpdateModelBounds(Entity* entity) {
IModel* model = entity->Model; IModel* model = entity->Model;
Vector3 baseSize = model->GetCollisionSize(); Vector3 baseSize = model->GetCollisionSize();
Vector3_Multiply3(&entity->Size, &baseSize, &entity->ModelScale); Vector3_Mul3(&entity->Size, &baseSize, &entity->ModelScale);
AABB* bb = &entity->ModelAABB; AABB* bb = &entity->ModelAABB;
model->GetPickingBounds(bb); model->GetPickingBounds(bb);
Vector3_Multiply3(&bb->Min, &bb->Min, &entity->ModelScale); Vector3_Mul3By(&bb->Min, &entity->ModelScale);
Vector3_Multiply3(&bb->Max, &bb->Max, &entity->ModelScale); Vector3_Mul3By(&bb->Max, &entity->ModelScale);
} }
bool Entity_TouchesAny(AABB* bounds, bool (*touches_condition)(BlockID block__)) { bool Entity_TouchesAny(AABB* bounds, bool (*touches_condition)(BlockID block__)) {
Vector3I bbMin, bbMax; Vector3I bbMin, bbMax;
Vector3I_Floor(&bbMin, &bounds->Min); Vector3I_Floor(&bbMin, &bounds->Min);
Vector3I_Floor(&bbMax, &bounds->Max); Vector3I_Floor(&bbMax, &bounds->Max);
AABB blockBB;
Vector3 v;
bbMin.X = max(bbMin.X, 0); bbMax.X = min(bbMax.X, World_MaxX); bbMin.X = max(bbMin.X, 0); bbMax.X = min(bbMax.X, World_MaxX);
bbMin.Y = max(bbMin.Y, 0); bbMax.Y = min(bbMax.Y, World_MaxY); bbMin.Y = max(bbMin.Y, 0); bbMax.Y = min(bbMax.Y, World_MaxY);
bbMin.Z = max(bbMin.Z, 0); bbMax.Z = min(bbMax.Z, World_MaxZ); bbMin.Z = max(bbMin.Z, 0); bbMax.Z = min(bbMax.Z, World_MaxZ);
AABB blockBB;
Vector3 v;
Int32 x, y, z; Int32 x, y, z;
for (y = bbMin.Y; y <= bbMax.Y; y++) { for (y = bbMin.Y; y <= bbMax.Y; y++) { v.Y = (Real32)y;
v.Y = (Real32)y; for (z = bbMin.Z; z <= bbMax.Z; z++) { v.Z = (Real32)z;
for (z = bbMin.Z; z <= bbMax.Z; z++) { for (x = bbMin.X; x <= bbMax.X; x++) { v.X = (Real32)x;
v.Z = (Real32)z;
for (x = bbMin.X; x <= bbMax.X; x++) {
v.X = (Real32)x;
BlockID block = World_GetBlock(x, y, z); BlockID block = World_GetBlock(x, y, z);
Vector3_Add(&blockBB.Min, &v, &Block_MinBB[block]); Vector3_Add(&blockBB.Min, &v, &Block_MinBB[block]);
Vector3_Add(&blockBB.Max, &v, &Block_MaxBB[block]); Vector3_Add(&blockBB.Max, &v, &Block_MaxBB[block]);
@ -728,3 +725,84 @@ void Player_Init(Player* player) {
entity->VTABLE->ContextRecreated = Player_ContextRecreated; entity->VTABLE->ContextRecreated = Player_ContextRecreated;
entity->VTABLE->Despawn = Player_Despawn; entity->VTABLE->Despawn = Player_Despawn;
} }
Real32 LocalPlayer_JumpHeight(void) {
LocalPlayer* p = &LocalPlayer_Instance;
return (Real32)PhysicsComp_GetMaxHeight(p->Physics.JumpVel);
}
void LocalPlayer_CheckHacksConsistency(void) {
LocalPlayer* p = &LocalPlayer_Instance;
HacksComp_CheckConsistency(&p->Hacks);
if (!HacksComp_CanJumpHigher(&p->Hacks)) {
p->Physics.JumpVel = p->Physics.ServerJumpVel;
}
}
bool LocalPlayer_IsSolidCollide(BlockID b) { return Block_Collide[b] == COLLIDE_SOLID; }
void LocalPlayer_DoRespawn(void) {
if (World_Blocks == NULL) return;
LocalPlayer* p = &LocalPlayer_Instance;
Vector3 spawn = p->Spawn;
Vector3I P; Vector3I_Floor(&P, &spawn);
AABB bb;
/* Spawn player at highest valid position */
if (World_IsValidPos_3I(P)) {
AAABB_Make(&bb, &spawn, &p->Base.Size);
Int32 y;
for (y = P.Y; y <= World_Height; y++) {
Real32 spawnY = Respawn_HighestFreeY(&bb);
if (spawnY == RESPAWN_NOT_FOUND) {
BlockID block = World_GetPhysicsBlock(P.X, y, P.Z);
Real32 height = Block_Collide[block] == COLLIDE_SOLID ? Block_MaxBB[block].Y : 0.0f;
spawn.Y = y + height + ENTITY_ADJUSTMENT;
break;
}
bb.Min.Y += 1.0f; bb.Max.Y += 1.0f;
}
}
spawn.Y += 2.0f / 16.0f;
LocationUpdate update; LocationUpdate_MakePosAndOri(&update, spawn, p->SpawnRotY, p->SpawnHeadX, false);
p->Base.VTABLE->SetLocation(&p->Base, &update, false);
Vector3 zero = Vector3_Zero; p->Base.Velocity = zero;
/* Update onGround, otherwise if 'respawn' then 'space' is pressed, you still jump into the air if onGround was true before */
Entity_GetBounds(&p->Base, &bb);
bb.Min.Y -= 0.01f; bb.Max.Y = bb.Min.Y;
p->Base.OnGround = Entity_TouchesAny(&bb, LocalPlayer_IsSolidCollide);
}
bool LocalPlayer_HandlesKey(Int32 key) {
LocalPlayer* p = &LocalPlayer_Instance;
HacksComp* hacks = &p->Hacks;
PhysicsComp* physics = &p->Physics;
if (key == KeyBind_Get(KeyBind_Respawn) && hacks->CanRespawn) {
DoRespawn();
} else if (key == KeyBind_Get(KeyBind_SetSpawn) && hacks->CanRespawn) {
p->Spawn = p->Base.Position;
p->Spawn.X = Math_Floor(p->Spawn.X) + 0.5f;
p->Spawn.Z = Math_Floor(p->Spawn.Z) + 0.5f;
p->SpawnRotY = p->Base.RotY;
p->SpawnHeadX = p->Base.HeadX;
DoRespawn();
} else if (key == KeyBind_Get(KeyBind_Fly) && hacks->CanFly && hacks->Enabled) {
hacks->Flying = !hacks->Flying;
} else if (key == KeyBind_Get(KeyBind_NoClip) && hacks->CanNoclip && hacks->Enabled && !hacks->WOMStyleHacks) {
if (hacks->Noclip) p->Base.Velocity.Y = 0;
hacks->Noclip = !hacks->Noclip;
} else if (key == KeyBind_Get(KeyBind_Jump) && !p->Base.OnGround && !(hacks->Flying || hacks->Noclip)) {
Int32 maxJumps = hacks->CanDoubleJump && hacks->WOMStyleHacks ? 2 : 0;
maxJumps = max(maxJumps, hacks->MaxJumps - 1);
if (physics->MultiJumps < maxJumps) {
PhysicsComp_DoNormalJump(physics);
physics->MultiJumps++;
}
} else {
return false;
}
return true;
}

View File

@ -52,15 +52,16 @@ void LocationUpdate_MakeOri(LocationUpdate* update, Real32 rotY, Real32 headX);
void LocationUpdate_MakePos(LocationUpdate* update, Vector3 pos, bool rel); void LocationUpdate_MakePos(LocationUpdate* update, Vector3 pos, bool rel);
void LocationUpdate_MakePosAndOri(LocationUpdate* update, Vector3 pos, Real32 rotY, Real32 headX, bool rel); void LocationUpdate_MakePosAndOri(LocationUpdate* update, Vector3 pos, Real32 rotY, Real32 headX, bool rel);
typedef struct Entity_ Entity;
typedef struct EntityVTABLE_ { typedef struct EntityVTABLE_ {
void (*Tick)(struct Entity_* entity, ScheduledTask* task); void (*Tick)(Entity* entity, ScheduledTask* task);
void (*SetLocation)(struct Entity_* entity, LocationUpdate* update, bool interpolate); void (*SetLocation)(Entity* entity, LocationUpdate* update, bool interpolate);
void (*RenderModel)(struct Entity_* entity, Real64 deltaTime, Real32 t); void (*RenderModel)(Entity* entity, Real64 deltaTime, Real32 t);
void (*RenderName)(struct Entity_* entity); void (*RenderName)(Entity* entity);
void (*ContextLost)(struct Entity_* entity); void (*ContextLost)(Entity* entity);
void (*ContextRecreated)(struct Entity_* entity); void (*ContextRecreated)(Entity* entity);
void (*Despawn)(struct Entity_* entity); void (*Despawn)(Entity* entity);
PackedCol (*GetCol)(struct Entity_* entity); PackedCol (*GetCol)(Entity* entity);
} EntityVTABLE; } EntityVTABLE;
/* Contains a model, along with position, velocity, and rotation. May also contain other fields and properties. */ /* Contains a model, along with position, velocity, and rotation. May also contain other fields and properties. */
@ -149,10 +150,13 @@ typedef struct LocalPlayer_ {
HacksComp Hacks; HacksComp Hacks;
TiltComp Tilt; TiltComp Tilt;
InterpComp Interp; InterpComp Interp;
CollisionsComp Collisions;
PhysicsComp Physics;
} LocalPlayer; } LocalPlayer;
LocalPlayer LocalPlayer_Instance; LocalPlayer LocalPlayer_Instance;
void LocalPlayer_Init(void); void LocalPlayer_Init(void);
Real32 LocalPlayer_JumpHeight(void); Real32 LocalPlayer_JumpHeight(void);
void LocalPlayer_ChecksHackConsistency(); void LocalPlayer_CheckHacksConsistency(void);
bool LocalPlayer_HandlesKey(Int32 key);
#endif #endif

View File

@ -1,4 +1,4 @@
#include "EntityComponents.h" #include "EntityComponents.h"
#include "ExtMath.h" #include "ExtMath.h"
#include "World.h" #include "World.h"
#include "Block.h" #include "Block.h"
@ -36,9 +36,9 @@ void AnimatedComp_DoTilt(Real32* tilt, bool reduce) {
} }
void AnimatedComp_PerpendicularAnim(AnimatedComp* anim, Real32 flapSpeed, Real32 idleXRot, Real32 idleZRot, bool left) { void AnimatedComp_PerpendicularAnim(AnimatedComp* anim, Real32 flapSpeed, Real32 idleXRot, Real32 idleZRot, bool left) {
Real32 verAngle = 0.5f + 0.5f * Math_Sin(anim->WalkTime * flapSpeed); Real32 verAngle = 0.5f + 0.5f * Math_SinF(anim->WalkTime * flapSpeed);
Real32 zRot = -idleZRot - verAngle * anim->Swing * ANIM_MAX_ANGLE; Real32 zRot = -idleZRot - verAngle * anim->Swing * ANIM_MAX_ANGLE;
Real32 horAngle = Math_Cos(anim->WalkTime) * anim->Swing * ANIM_ARM_MAX * 1.5f; Real32 horAngle = Math_CosF(anim->WalkTime) * anim->Swing * ANIM_ARM_MAX * 1.5f;
Real32 xRot = idleXRot + horAngle; Real32 xRot = idleXRot + horAngle;
if (left) { if (left) {
@ -64,7 +64,7 @@ void AnimatedComp_Update(AnimatedComp* anim, Vector3 oldPos, Vector3 newPos, Rea
anim->SwingO = anim->SwingN; anim->SwingO = anim->SwingN;
Real32 dx = newPos.X - oldPos.X; Real32 dx = newPos.X - oldPos.X;
Real32 dz = newPos.Z - oldPos.Z; Real32 dz = newPos.Z - oldPos.Z;
Real32 distance = Math_Sqrt(dx * dx + dz * dz); Real32 distance = Math_SqrtF(dx * dx + dz * dz);
if (distance > 0.05f) { if (distance > 0.05f) {
Real32 walkDelta = distance * 2 * (Real32)(20 * delta); Real32 walkDelta = distance * 2 * (Real32)(20 * delta);
@ -90,20 +90,20 @@ void AnimatedComp_GetCurrent(AnimatedComp* anim, Real32 t, bool calcHumanAnims)
anim->BobStrength = Math_Lerp(anim->BobStrengthO, anim->BobStrengthN, t); anim->BobStrength = Math_Lerp(anim->BobStrengthO, anim->BobStrengthN, t);
Real32 idleTime = (Real32)Game_Accumulator; Real32 idleTime = (Real32)Game_Accumulator;
Real32 idleXRot = Math_Sin(idleTime * ANIM_IDLE_XPERIOD) * ANIM_IDLE_MAX; Real32 idleXRot = Math_SinF(idleTime * ANIM_IDLE_XPERIOD) * ANIM_IDLE_MAX;
Real32 idleZRot = ANIM_IDLE_MAX + Math_Cos(idleTime * ANIM_IDLE_ZPERIOD) * ANIM_IDLE_MAX; Real32 idleZRot = ANIM_IDLE_MAX + Math_CosF(idleTime * ANIM_IDLE_ZPERIOD) * ANIM_IDLE_MAX;
anim->LeftArmX = (Math_Cos(anim->WalkTime) * anim->Swing * ANIM_ARM_MAX) - idleXRot; anim->LeftArmX = (Math_CosF(anim->WalkTime) * anim->Swing * ANIM_ARM_MAX) - idleXRot;
anim->LeftArmZ = -idleZRot; anim->LeftArmZ = -idleZRot;
anim->LeftLegX = -(Math_Cos(anim->WalkTime) * anim->Swing * ANIM_LEG_MAX); anim->LeftLegX = -(Math_CosF(anim->WalkTime) * anim->Swing * ANIM_LEG_MAX);
anim->LeftLegZ = 0; anim->LeftLegZ = 0;
anim->RightLegX = -anim->LeftLegX; anim->RightLegZ = -anim->LeftLegZ; anim->RightLegX = -anim->LeftLegX; anim->RightLegZ = -anim->LeftLegZ;
anim->RightArmX = -anim->LeftArmX; anim->RightArmZ = -anim->LeftArmZ; anim->RightArmX = -anim->LeftArmX; anim->RightArmZ = -anim->LeftArmZ;
anim->BobbingHor = Math_Cos(anim->WalkTime) * anim->Swing * (2.5f / 16.0f); anim->BobbingHor = Math_CosF(anim->WalkTime) * anim->Swing * (2.5f / 16.0f);
anim->BobbingVer = Math_AbsF(Math_Sin(anim->WalkTime)) * anim->Swing * (2.5f / 16.0f); anim->BobbingVer = Math_AbsF(Math_SinF(anim->WalkTime)) * anim->Swing * (2.5f / 16.0f);
anim->BobbingModel = Math_AbsF(Math_Cos(anim->WalkTime)) * anim->Swing * (4.0f / 16.0f); anim->BobbingModel = Math_AbsF(Math_CosF(anim->WalkTime)) * anim->Swing * (4.0f / 16.0f);
if (calcHumanAnims && !Game_SimpleArmsAnim) { if (calcHumanAnims && !Game_SimpleArmsAnim) {
AnimatedComp_CalcHumanAnim(anim, idleXRot, idleZRot); AnimatedComp_CalcHumanAnim(anim, idleXRot, idleZRot);
@ -126,7 +126,7 @@ void TiltComp_Update(TiltComp* anim, Real64 delta) {
/* TODO: the Tilt code was designed for 60 ticks/second, fix it up for 20 ticks/second */ /* TODO: the Tilt code was designed for 60 ticks/second, fix it up for 20 ticks/second */
Int32 i; Int32 i;
for (i = 0; i < 3; i++) { for (i = 0; i < 3; i++) {
AnimatedComp_DoTilt(&anim->VelTiltStrengthN, p->Hacks.Noclip || p->Hacks.Flying); AnimatedComp_DoTilt(&anim->VelTiltStrengthN, p->Hacks.Floating);
} }
} }
@ -135,8 +135,8 @@ void TiltComp_GetCurrent(TiltComp* anim, Real32 t) {
anim->VelTiltStrength = Math_Lerp(anim->VelTiltStrengthO, anim->VelTiltStrengthN, t); anim->VelTiltStrength = Math_Lerp(anim->VelTiltStrengthO, anim->VelTiltStrengthN, t);
AnimatedComp* pAnim = &p->Base.Anim; AnimatedComp* pAnim = &p->Base.Anim;
anim->TiltX = Math_Cos(pAnim->WalkTime) * pAnim->Swing * (0.15f * MATH_DEG2RAD); anim->TiltX = Math_CosF(pAnim->WalkTime) * pAnim->Swing * (0.15f * MATH_DEG2RAD);
anim->TiltY = Math_Sin(pAnim->WalkTime) * pAnim->Swing * (0.15f * MATH_DEG2RAD); anim->TiltY = Math_SinF(pAnim->WalkTime) * pAnim->Swing * (0.15f * MATH_DEG2RAD);
} }
@ -665,29 +665,126 @@ void ShadowComponent_Draw(Entity* entity) {
} }
typedef struct CollisionsComponent_ { /*########################################################################################################################*
Entity* Entity; *---------------------------------------------------CollisionsComponent---------------------------------------------------*
bool HitXMin, HitYMin, HitZMin, HitXMax, HitYMax, HitZMax, WasOn; *#########################################################################################################################*/
} CollisionsComponent;
/* Whether a collision occurred with any horizontal sides of any blocks */ /* Whether a collision occurred with any horizontal sides of any blocks */
bool Collisions_HitHorizontal(CollisionsComponent* comp) { bool Collisions_HitHorizontal(CollisionsComp* comp) {
return comp->HitXMin || comp->HitXMax || comp->HitZMin || comp->HitZMax; return comp->HitXMin || comp->HitXMax || comp->HitZMin || comp->HitZMax;
} }
#define COLLISIONS_ADJ 0.001f
void Collisions_ClipX(Entity* entity, Vector3* size, AABB* entityBB, AABB* extentBB) {
/* TODO: test for corner cases, and refactor this */ entity->Velocity.X = 0.0f;
void Collisions_MoveAndWallSlide(CollisionsComponent* comp) { entityBB->Min.X = entity->Position.X - size->X / 2; extentBB->Min.X = entityBB->Min.X;
Vector3 zero = Vector3_Zero; entityBB->Max.X = entity->Position.X + size->X / 2; extentBB->Max.X = entityBB->Max.X;
Entity* entity = comp->Entity;
if (Vector3_Equals(&entity->Velocity, &zero)) return;
AABB entityBB, entityExtentBB;
UInt32 count = Searcher_FindReachableBlocks(entity, &entityBB, &entityExtentBB);
CollideWithReachableBlocks(comp, count, &entityBB, &entityExtentBB);
} }
void Collisions_CollideWithReachableBlocks(CollisionsComponent* comp, UInt32 count, AABB* entityBB, AABB* extentBB) { void Collisions_ClipY(Entity* entity, Vector3* size, AABB* entityBB, AABB* extentBB) {
entity->Velocity.Y = 0.0f;
entityBB->Min.Y = entity->Position.Y; extentBB->Min.Y = entityBB->Min.Y;
entityBB->Max.Y = entity->Position.Y + size->Y; extentBB->Max.Y = entityBB->Max.Y;
}
void Collisions_ClipZ(Entity* entity, Vector3* size, AABB* entityBB, AABB* extentBB) {
entity->Velocity.Z = 0.0f;
entityBB->Min.Z = entity->Position.Z - size->Z / 2; extentBB->Min.Z = entityBB->Min.Z;
entityBB->Max.Z = entity->Position.Z + size->Z / 2; extentBB->Max.Z = entityBB->Max.Z;
}
bool Collisions_CanSlideThrough(AABB* adjFinalBB) {
Vector3I bbMin; Vector3I_Floor(&bbMin, &adjFinalBB->Min);
Vector3I bbMax; Vector3I_Floor(&bbMax, &adjFinalBB->Max);
AABB blockBB;
Vector3 v;
Int32 x, y, z;
for (y = bbMin.Y; y <= bbMax.Y; y++) { v.Y = (Real32)y;
for (z = bbMin.Z; z <= bbMax.Z; z++) { v.Z = (Real32)z;
for (x = bbMin.X; x <= bbMax.X; x++) { v.X = (Real32)x;
BlockID block = World_GetPhysicsBlock(x, y, z);
Vector3_Add(&blockBB.Min, &v, &Block_MinBB[block]);
Vector3_Add(&blockBB.Max, &v, &Block_MaxBB[block]);
if (!AABB_Intersects(&blockBB, adjFinalBB)) continue;
if (Block_Collide[block] == COLLIDE_SOLID) return false;
}
}
}
return true;
}
bool Collisions_DidSlide(CollisionsComp* comp, AABB* blockBB, Vector3* size, AABB* finalBB, AABB* entityBB, AABB* extentBB) {
Real32 yDist = blockBB->Max.Y - entityBB->Min.Y;
if (yDist > 0.0f && yDist <= comp->Entity->StepSize + 0.01f) {
Real32 blockBB_MinX = max(blockBB->Min.X, blockBB->Max.X - size->X / 2);
Real32 blockBB_MaxX = min(blockBB->Max.X, blockBB->Min.X + size->X / 2);
Real32 blockBB_MinZ = max(blockBB->Min.Z, blockBB->Max.Z - size->Z / 2);
Real32 blockBB_MaxZ = min(blockBB->Max.Z, blockBB->Min.Z + size->Z / 2);
AABB adjBB;
adjBB.Min.X = min(finalBB->Min.X, blockBB_MinX + COLLISIONS_ADJ);
adjBB.Max.X = max(finalBB->Max.X, blockBB_MaxX - COLLISIONS_ADJ);
adjBB.Min.Y = blockBB->Max.Y + COLLISIONS_ADJ;
adjBB.Max.Y = adjBB.Min.Y + size->Y;
adjBB.Min.Z = min(finalBB->Min.Z, blockBB_MinZ + COLLISIONS_ADJ);
adjBB.Max.Z = max(finalBB->Max.Z, blockBB_MaxZ - COLLISIONS_ADJ);
if (!Collisions_CanSlideThrough(&adjBB)) return false;
comp->Entity->Position.Y = adjBB.Min.Y;
comp->Entity->OnGround = true;
Collisions_ClipY(comp->Entity, size, entityBB, extentBB);
return true;
}
return false;
}
void Collisions_ClipXMin(CollisionsComp* comp, AABB* blockBB, AABB* entityBB, bool wasOn, AABB* finalBB, AABB* extentBB, Vector3* size) {
if (!wasOn || !Collisions_DidSlide(comp, blockBB, size, finalBB, entityBB, extentBB)) {
comp->Entity->Position.X = blockBB->Min.X - size->X / 2 - COLLISIONS_ADJ;
Collisions_ClipX(comp->Entity, size, entityBB, extentBB);
comp->HitXMin = true;
}
}
void Collisions_ClipXMax(CollisionsComp* comp, AABB* blockBB, AABB* entityBB, bool wasOn, AABB* finalBB, AABB* extentBB, Vector3* size) {
if (!wasOn || !Collisions_DidSlide(comp, blockBB, size, finalBB, entityBB, extentBB)) {
comp->Entity->Position.X = blockBB->Max.X + size->X / 2 + COLLISIONS_ADJ;
Collisions_ClipX(comp->Entity, size, entityBB, extentBB);
comp->HitXMax = true;
}
}
void Collisions_ClipZMax(CollisionsComp* comp, AABB* blockBB, AABB* entityBB, bool wasOn, AABB* finalBB, AABB* extentBB, Vector3* size) {
if (!wasOn || !Collisions_DidSlide(comp, blockBB, size, finalBB, entityBB, extentBB)) {
comp->Entity->Position.Z = blockBB->Max.Z + size->Z / 2 + COLLISIONS_ADJ;
Collisions_ClipZ(comp->Entity, size, entityBB, extentBB);
comp->HitZMax = true;
}
}
void Collisions_ClipZMin(CollisionsComp* comp, AABB* blockBB, AABB* entityBB, bool wasOn, AABB* finalBB, AABB* extentBB, Vector3* size) {
if (!wasOn || !Collisions_DidSlide(comp, blockBB, size, finalBB, entityBB, extentBB)) {
comp->Entity->Position.Z = blockBB->Min.Z - size->Z / 2 - COLLISIONS_ADJ;
Collisions_ClipZ(comp->Entity, size, entityBB, extentBB);
comp->HitZMin = true;
}
}
void Collisions_ClipYMin(CollisionsComp* comp, AABB* blockBB, AABB* entityBB, AABB* extentBB, Vector3* size) {
comp->Entity->Position.Y = blockBB->Min.Y - size->Y - COLLISIONS_ADJ;
Collisions_ClipY(comp->Entity, size, entityBB, extentBB);
comp->HitYMin = true;
}
void Collisions_ClipYMax(CollisionsComp* comp, AABB* blockBB, AABB* entityBB, AABB* extentBB, Vector3* size) {
comp->Entity->Position.Y = blockBB->Max.Y + COLLISIONS_ADJ;
comp->Entity->OnGround = true;
Collisions_ClipY(comp->Entity, size, entityBB, extentBB);
comp->HitYMax = true;
}
void Collisions_CollideWithReachableBlocks(CollisionsComp* comp, UInt32 count, AABB* entityBB, AABB* extentBB) {
Entity* entity = comp->Entity; Entity* entity = comp->Entity;
/* Reset collision detection states */ /* Reset collision detection states */
bool wasOn = entity->OnGround; bool wasOn = entity->OnGround;
@ -712,7 +809,8 @@ void Collisions_CollideWithReachableBlocks(CollisionsComponent* comp, UInt32 cou
Real32 tx, ty, tz; Real32 tx, ty, tz;
Searcher_CalcTime(&entity->Velocity, entityBB, &blockBB, &tx, &ty, &tz); Searcher_CalcTime(&entity->Velocity, entityBB, &blockBB, &tx, &ty, &tz);
if (tx > 1.0f || ty > 1.0f || tz > 1.0f) { if (tx > 1.0f || ty > 1.0f || tz > 1.0f) {
Utils.LogDebug("t > 1 in physics calculation.. this shouldn't have happened."); String warn = String_FromConst("t > 1 in physics calculation.. this shouldn't have happened.");
Platform_Log(&warn);
} }
/* Calculate the location of the entity when it collides with this block */ /* Calculate the location of the entity when it collides with this block */
@ -722,148 +820,364 @@ void Collisions_CollideWithReachableBlocks(CollisionsComponent* comp, UInt32 cou
Vector3_Add(&finalBB.Min, &entityBB->Min, &v); Vector3_Add(&finalBB.Min, &entityBB->Min, &v);
Vector3_Add(&finalBB.Min, &entityBB->Max, &v); Vector3_Add(&finalBB.Min, &entityBB->Max, &v);
// if we have hit the bottom of a block, we need to change the axis we test first. /* if we have hit the bottom of a block, we need to change the axis we test first */
if (!hitYMin) { if (!comp->HitYMin) {
if (finalBB.Min.Y + Adjustment >= blockBB.Max.Y) { if (finalBB.Min.Y + COLLISIONS_ADJ >= blockBB.Max.Y) {
ClipYMax(&blockBB, entityBB, extentBB, size); Collisions_ClipYMax(comp, &blockBB, entityBB, extentBB, &size);
} else if (finalBB.Max.Y - Adjustment <= blockBB.Min.Y) { } else if (finalBB.Max.Y - COLLISIONS_ADJ <= blockBB.Min.Y) {
ClipYMin(&blockBB, entityBB, extentBB, size); Collisions_ClipYMin(comp, &blockBB, entityBB, extentBB, &size);
} else if (finalBB.Min.X + Adjustment >= blockBB.Max.X) { } else if (finalBB.Min.X + COLLISIONS_ADJ >= blockBB.Max.X) {
ClipXMax(&blockBB, entityBB, wasOn, finalBB, extentBB, size); Collisions_ClipXMax(comp, &blockBB, entityBB, wasOn, &finalBB, extentBB, &size);
} else if (finalBB.Max.X - Adjustment <= blockBB.Min.X) { } else if (finalBB.Max.X - COLLISIONS_ADJ <= blockBB.Min.X) {
ClipXMin(&blockBB, entityBB, wasOn, finalBB, extentBB, size); Collisions_ClipXMin(comp, &blockBB, entityBB, wasOn, &finalBB, extentBB, &size);
} else if (finalBB.Min.Z + Adjustment >= blockBB.Max.Z) { } else if (finalBB.Min.Z + COLLISIONS_ADJ >= blockBB.Max.Z) {
ClipZMax(&blockBB, entityBB, wasOn, finalBB, extentBB, size); Collisions_ClipZMax(comp, &blockBB, entityBB, wasOn, &finalBB, extentBB, &size);
} else if (finalBB.Max.Z - Adjustment <= blockBB.Min.Z) { } else if (finalBB.Max.Z - COLLISIONS_ADJ <= blockBB.Min.Z) {
ClipZMin(&blockBB, entityBB, wasOn, finalBB, extentBB, size); Collisions_ClipZMin(comp, &blockBB, entityBB, wasOn, &finalBB, extentBB, &size);
} }
continue; continue;
} }
// if flying or falling, test the horizontal axes first. /* if flying or falling, test the horizontal axes first */
if (finalBB.Min.X + Adjustment >= blockBB.Max.X) { if (finalBB.Min.X + COLLISIONS_ADJ >= blockBB.Max.X) {
ClipXMax(&blockBB, entityBB, wasOn, finalBB, extentBB, size); Collisions_ClipXMax(comp, &blockBB, entityBB, wasOn, &finalBB, extentBB, &size);
} else if (finalBB.Max.X - Adjustment <= blockBB.Min.X) { } else if (finalBB.Max.X - COLLISIONS_ADJ <= blockBB.Min.X) {
ClipXMin(&blockBB, entityBB, wasOn, finalBB, extentBB, size); Collisions_ClipXMin(comp, &blockBB, entityBB, wasOn, &finalBB, extentBB, &size);
} else if (finalBB.Min.Z + Adjustment >= blockBB.Max.Z) { } else if (finalBB.Min.Z + COLLISIONS_ADJ >= blockBB.Max.Z) {
ClipZMax(&blockBB, entityBB, wasOn, finalBB, extentBB, size); Collisions_ClipZMax(comp, &blockBB, entityBB, wasOn, &finalBB, extentBB, &size);
} else if (finalBB.Max.Z - Adjustment <= blockBB.Min.Z) { } else if (finalBB.Max.Z - COLLISIONS_ADJ <= blockBB.Min.Z) {
ClipZMin(&blockBB, entityBB, wasOn, finalBB, extentBB, size); Collisions_ClipZMin(comp, &blockBB, entityBB, wasOn, &finalBB, extentBB, &size);
} else if (finalBB.Min.Y + Adjustment >= blockBB.Max.Y) { } else if (finalBB.Min.Y + COLLISIONS_ADJ >= blockBB.Max.Y) {
ClipYMax(&blockBB, entityBB, extentBB, size); Collisions_ClipYMax(comp, &blockBB, entityBB, extentBB, &size);
} else if (finalBB.Max.Y - Adjustment <= blockBB.Min.Y) { } else if (finalBB.Max.Y - COLLISIONS_ADJ <= blockBB.Min.Y) {
ClipYMin(&blockBB, entityBB, extentBB, size); Collisions_ClipYMin(comp, &blockBB, entityBB, extentBB, &size);
} }
} }
} }
void Collisions_ClipXMin(AABB* blockBB, AABB* entityBB, bool wasOn, AABB* finalBB, AABB* extentBB, Vector3* size) { /* TODO: test for corner cases, and refactor this */
if (!wasOn || !DidSlide(blockBB, size, finalBB, entityBB, extentBB)) { void Collisions_MoveAndWallSlide(CollisionsComp* comp) {
entity.Position.X = blockBB.Min.X - size.X / 2 - Adjustment; Vector3 zero = Vector3_Zero;
ClipX(size, entityBB, extentBB); Entity* entity = comp->Entity;
hitXMin = true; if (Vector3_Equals(&entity->Velocity, &zero)) return;
AABB entityBB, entityExtentBB;
UInt32 count = Searcher_FindReachableBlocks(entity, &entityBB, &entityExtentBB);
Collisions_CollideWithReachableBlocks(comp, count, &entityBB, &entityExtentBB);
}
/*########################################################################################################################*
*----------------------------------------------------PhysicsComponent-----------------------------------------------------*
*#########################################################################################################################*/
void PhysicsComp_Init(PhysicsComp* comp, Entity* entity) {
Platform_MemSet(comp, 0, sizeof(PhysicsComp));
comp->CanLiquidJump = true;
comp->Entity = entity;
comp->JumpVel = 0.42f;
comp->UserJumpVel = 0.42f;
comp->ServerJumpVel = 0.42f;
}
bool PhysicsComp_TouchesLiquid(BlockID block) { return Block_Collide[block] == COLLIDE_LIQUID; }
void PhysicsComp_UpdateVelocityState(PhysicsComp* comp) {
Entity* entity = comp->Entity;
HacksComp* hacks = comp->Hacks;
if (hacks->Floating) {
entity->Velocity.Y = 0.0f; /* eliminate the effect of gravity */
Int32 dir = (hacks->FlyingUp || comp->Jumping) ? 1 : (hacks->FlyingDown ? -1 : 0);
entity->Velocity.Y += 0.12f * dir;
if (hacks->Speeding && hacks->CanSpeed) entity->Velocity.Y += 0.12f * dir;
if (hacks->HalfSpeeding && hacks->CanSpeed) entity->Velocity.Y += 0.06f * dir;
} else if (comp->Jumping && Entity_TouchesAnyRope(entity) && entity->Velocity.Y > 0.02f) {
entity->Velocity.Y = 0.02f;
}
if (!comp->Jumping) {
comp->CanLiquidJump = false; return;
}
bool touchWater = Entity_TouchesAnyWater(entity);
bool touchLava = Entity_TouchesAnyLava(entity);
if (touchWater || touchLava) {
AABB bounds; Entity_GetBounds(entity, &bounds);
Int32 feetY = Math_Floor(bounds.Min.Y), bodyY = feetY + 1;
Int32 headY = Math_Floor(bounds.Max.Y);
if (bodyY > headY) bodyY = headY;
bounds.Max.Y = bounds.Min.Y = feetY;
bool liquidFeet = Entity_TouchesAny(&bounds, PhysicsComp_TouchesLiquid);
bounds.Min.Y = min(bodyY, headY);
bounds.Max.Y = max(bodyY, headY);
bool liquidRest = Entity_TouchesAny(&bounds, PhysicsComp_TouchesLiquid);
bool pastJumpPoint = liquidFeet && !liquidRest && (Math_ModF(entity->Position.Y, 1.0f) >= 0.4f);
if (!pastJumpPoint) {
comp->CanLiquidJump = true;
entity->Velocity.Y += 0.04f;
if (hacks->Speeding && hacks->CanSpeed) entity->Velocity.Y += 0.04f;
if (hacks->HalfSpeeding && hacks->CanSpeed) entity->Velocity.Y += 0.02f;
} else if (pastJumpPoint) {
/* either A) climb up solid on side B) jump bob in water */
if (Collisions_HitHorizontal(comp->Collisions)) {
entity->Velocity.Y += touchLava ? 0.30f : 0.13f;
} else if (comp->CanLiquidJump) {
entity->Velocity.Y += touchLava ? 0.20f : 0.10f;
}
comp->CanLiquidJump = false;
}
} else if (comp->UseLiquidGravity) {
entity->Velocity.Y += 0.04f;
if (hacks->Speeding && hacks->CanSpeed) entity->Velocity.Y += 0.04f;
if (hacks->HalfSpeeding && hacks->CanSpeed) entity->Velocity.Y += 0.02f;
comp->CanLiquidJump = false;
} else if (Entity_TouchesAnyRope(entity)) {
entity->Velocity.Y += (hacks->Speeding && hacks->CanSpeed) ? 0.15f : 0.10f;
comp->CanLiquidJump = false;
} else if (entity->OnGround) {
PhysicsComp_DoNormalJump(comp);
} }
} }
void Collisions_ClipXMax(AABB* blockBB, AABB* entityBB, bool wasOn, AABB* finalBB, AABB* extentBB, Vector3* size) { void PhysicsComp_DoNormalJump(PhysicsComp* comp) {
if (!wasOn || !DidSlide(blockBB, size, finalBB, entityBB, extentBB)) { Entity* entity = comp->Entity;
entity.Position.X = blockBB.Max.X + size.X / 2 + Adjustment; HacksComp* hacks = comp->Hacks;
ClipX(size, entityBB, extentBB); if (comp->JumpVel == 0.0f || hacks->MaxJumps == 0) return;
hitXMax = true;
entity->Velocity.Y = comp->JumpVel;
if (hacks->Speeding && hacks->CanSpeed) entity->Velocity.Y += comp->JumpVel;
if (hacks->HalfSpeeding && hacks->CanSpeed) entity->Velocity.Y += comp->JumpVel / 2;
comp->CanLiquidJump = false;
}
bool PhysicsComp_TouchesSlipperyIce(BlockID b) { return Block_ExtendedCollide[b] == COLLIDE_SLIPPERY_ICE; }
bool PhysicsComp_OnIce(Entity* entity) {
Vector3 under = entity->Position; under.Y -= 0.01f;
Vector3I underCoords; Vector3I_Floor(&underCoords, &under);
BlockID blockUnder = World_SafeGetBlock_3I(underCoords);
if (Block_ExtendedCollide[blockUnder] == COLLIDE_ICE) return true;
AABB bounds; Entity_GetBounds(entity, &bounds);
bounds.Min.Y -= 0.01f; bounds.Max.Y = bounds.Min.Y;
return Entity_TouchesAny(&bounds, PhysicsComp_TouchesSlipperyIce);
}
void PhysicsComp_MoveHor(PhysicsComp* comp, Vector3 vel, Real32 factor) {
Real32 dist = Math_SqrtF(vel.X * vel.X + vel.Z * vel.Z);
if (dist < 0.00001f) return;
if (dist < 1.0f) dist = 1.0f;
/* entity.Velocity += vel * (factor / dist) */
Entity* entity = comp->Entity;
Vector3_Mul1By(&vel, factor / dist);
Vector3_AddBy(&entity->Velocity, &vel);
}
void PhysicsComp_Move(PhysicsComp* comp, Vector3 drag, Real32 gravity, Real32 yMul) {
Entity* entity = comp->Entity;
entity->Velocity.Y *= yMul;
if (!comp->Hacks->Noclip) {
Collisions_MoveAndWallSlide(comp->Collisions);
} }
Vector3_AddBy(&entity->Position, &entity->Velocity);
entity->Velocity.Y /= yMul;
Vector3_Mul3By(&entity->Velocity, &drag);
entity->Velocity.Y -= gravity;
} }
void Collisions_ClipZMax(AABB* blockBB, AABB* entityBB, bool wasOn, AABB* finalBB, AABB* extentBB, Vector3* size) { void PhysicsComp_MoveFlying(PhysicsComp* comp, Vector3 vel, Real32 factor, Vector3 drag, Real32 gravity, Real32 yMul) {
if (!wasOn || !DidSlide(blockBB, size, finalBB, entityBB, extentBB)) { Entity* entity = comp->Entity;
entity.Position.Z = blockBB.Max.Z + size.Z / 2 + Adjustment; HacksComp* hacks = comp->Hacks;
ClipZ(size, entityBB, extentBB);
hitZMax = true;
}
}
void Collisions_ClipZMin(AABB* blockBB, AABB* entityBB, bool wasOn, AABB* finalBB, AABB* extentBB, Vector3* size) { PhysicsComp_MoveHor(comp, vel, factor);
if (!wasOn || !DidSlide(blockBB, size, finalBB, entityBB, extentBB)) { Real32 yVel = Math_SqrtF(entity->Velocity.X * entity->Velocity.X + entity->Velocity.Z * entity->Velocity.Z);
entity.Position.Z = blockBB.Min.Z - size.Z / 2 - Adjustment; /* make horizontal speed the same as vertical speed */
ClipZ(size, entityBB, extentBB); if ((vel.X != 0.0f || vel.Z != 0.0f) && yVel > 0.001f) {
hitZMin = true;
}
}
void Collisions_ClipYMin(AABB* blockBB, AABB* entityBB, AABB* extentBB, Vector3* size) {
entity.Position.Y = blockBB.Min.Y - size.Y - Adjustment;
ClipY(size, entityBB, ref extentBB);
hitYMin = true;
}
void Collisions_ClipYMax(AABB* blockBB, AABB* entityBB, AABB* extentBB, Vector3* size) {
entity.Position.Y = blockBB.Max.Y + Adjustment;
entity.onGround = true;
ClipY(size, entityBB, ref extentBB);
hitYMax = true;
}
bool Collisions_DidSlide(AABB blockBB, Vector3* size, AABB* finalBB, AABB* entityBB, AABB* extentBB) {
Real32 yDist = blockBB.Max.Y - entityBB.Min.Y;
if (yDist > 0 && yDist <= entity.StepSize + 0.01f) {
float blockXMin = blockBB.Min.X, blockZMin = blockBB.Min.Z;
blockBB.Min.X = Math.Max(blockBB.Min.X, blockBB.Max.X - size.X / 2);
blockBB.Max.X = Math.Min(blockBB.Max.X, blockXMin + size.X / 2);
blockBB.Min.Z = Math.Max(blockBB.Min.Z, blockBB.Max.Z - size.Z / 2);
blockBB.Max.Z = Math.Min(blockBB.Max.Z, blockZMin + size.Z / 2);
AABB adjBB;
adjBB.Min.X = min(finalBB->Min.X, blockBB.Min.X + Adjustment);
adjBB.Max.X = max(finalBB->Max.X, blockBB.Max.X - Adjustment);
adjBB.Min.Y = blockBB.Max.Y + Adjustment;
adjBB.Max.Y = adjBB.Min.Y + size->Y;
adjBB.Min.Z = min(finalBB->Min.Z, blockBB.Min.Z + Adjustment);
adjBB.Max.Z = max(finalBB->Max.Z, blockBB.Max.Z - Adjustment);
if (!Collisions_CanSlideThrough(&adjBB)) return false;
entity.Position.Y = blockBB.Max.Y + Adjustment;
entity.onGround = true;
ClipY(size, entityBB, extentBB);
return true;
}
return false;
}
bool Collisions_CanSlideThrough(AABB* adjFinalBB) {
Vector3I bbMin; Vector3I_Floor(&bbMin, &adjFinalBB->Min);
Vector3I bbMax; Vector3I_Floor(&bbMax, &adjFinalBB->Max);
AABB blockBB;
Int32 x, y, z;
for (y = bbMin.Y; y <= bbMax.Y; y++) {
for (z = bbMin.Z; z <= bbMax.Z; z++) {
for (x = bbMin.X; x <= bbMax.X; x++) {
BlockID block = World_GetPhysicsBlock(x, y, z);
blockBB.Min = new Vector3(x, y, z) + Block_MinBB[block];
blockBB.Max = new Vector3(x, y, z) + Block_MaxBB[block];
if (!AABB_Intersects(&blockBB, adjFinalBB)) continue;
if (Block_Collide[block] == COLLIDE_SOLID) return false;
}
}
}
return true;
}
void Collisions_ClipX(Entity* entity, Vector3* size, AABB* entityBB, AABB* extentBB) {
entity->Velocity.X = 0.0f;
entityBB->Min.X = entity->Position.X - size->X / 2; extentBB->Min.X = entityBB->Min.X;
entityBB->Max.X = entity->Position.X + size->X / 2; extentBB->Max.X = entityBB->Max.X;
}
void Collisions_ClipY(Entity* entity, Vector3* size, AABB* entityBB, AABB* extentBB) {
entity->Velocity.Y = 0.0f; entity->Velocity.Y = 0.0f;
entityBB->Min.Y = entity->Position.Y; extentBB->Min.Y = entityBB->Min.Y; yMul = 1.0f;
entityBB->Max.Y = entity->Position.Y + size->Y; extentBB->Max.Y = entityBB->Max.Y; if (hacks->FlyingUp || comp->Jumping) entity->Velocity.Y += yVel;
if (hacks->FlyingDown) entity->Velocity.Y -= yVel;
}
PhysicsComp_Move(comp, drag, gravity, yMul);
} }
void Collisions_ClipZ(Entity* entity, Vector3* size, AABB* entityBB, AABB* extentBB) { void PhysicsComp_MoveNormal(PhysicsComp* comp, Vector3 vel, Real32 factor, Vector3 drag, Real32 gravity, Real32 yMul) {
entity->Velocity.Z = 0.0f; PhysicsComp_MoveHor(comp, vel, factor);
entityBB->Min.Z = entity->Position.Z - size->Z / 2; extentBB->Min.Z = entityBB->Min.Z; PhysicsComp_Move(comp, drag, gravity, yMul);
entityBB->Max.Z = entity->Position.Z + size->Z / 2; extentBB->Max.Z = entityBB->Max.Z; }
Real32 PhysicsComp_LowestModifier(PhysicsComp* comp, AABB* bounds, bool checkSolid) {
Vector3I bbMin, bbMax;
Vector3I_Floor(&bbMin, &bounds->Min);
Vector3I_Floor(&bbMax, &bounds->Max);
Real32 modifier = MATH_POS_INF;
bbMin.X = max(bbMin.X, 0); bbMax.X = min(bbMax.X, World_MaxX);
bbMin.Y = max(bbMin.Y, 0); bbMax.Y = min(bbMax.Y, World_MaxY);
bbMin.Z = max(bbMin.Z, 0); bbMax.Z = min(bbMax.Z, World_MaxZ);
AABB blockBB;
Vector3 v;
Int32 x, y, z;
for (y = bbMin.Y; y <= bbMax.Y; y++) { v.Y = (Real32)y;
for (z = bbMin.Z; z <= bbMax.Z; z++) { v.Z = (Real32)z;
for (x = bbMin.X; x <= bbMax.X; x++) { v.X = (Real32)x;
BlockID block = World_GetBlock(x, y, z);
if (block == BLOCK_AIR) continue;
UInt8 collide = Block_Collide[block];
if (collide == COLLIDE_SOLID && !checkSolid) continue;
Vector3_Add(&blockBB.Min, &v, &Block_MinBB[block]);
Vector3_Add(&blockBB.Max, &v, &Block_MaxBB[block]);
if (!AABB_Intersects(&blockBB, bounds)) continue;
modifier = min(modifier, Block_SpeedMultiplier[block]);
if (Block_ExtendedCollide[block] == COLLIDE_LIQUID) {
comp->UseLiquidGravity = true;
}
}
}
}
return modifier;
}
Real32 PhysicsComp_GetSpeed(HacksComp* hacks, Real32 speedMul) {
Real32 factor = hacks->Floating ? speedMul : 1.0f, speed = factor;
if (hacks->Speeding && hacks->CanSpeed) speed += factor * hacks->SpeedMultiplier;
if (hacks->HalfSpeeding && hacks->CanSpeed) speed += factor * hacks->SpeedMultiplier / 2;
return hacks->CanSpeed ? speed : min(speed, 1.0f);
}
Real32 PhysicsComp_GetBaseSpeed(PhysicsComp* comp) {
AABB bounds; Entity_GetBounds(comp->Entity, &bounds);
comp->UseLiquidGravity = false;
Real32 baseModifier = PhysicsComp_LowestModifier(comp, &bounds, false);
bounds.Min.Y -= 0.5f / 16.0f; /* also check block standing on */
Real32 solidModifier = PhysicsComp_LowestModifier(comp, &bounds, true);
if (baseModifier == MATH_POS_INF && solidModifier == MATH_POS_INF) return 1.0f;
return baseModifier == MATH_POS_INF ? solidModifier : baseModifier;
}
#define LIQUID_GRAVITY 0.02f
#define ROPE_GRAVITY 0.034f
void PhysicsComp_PhysicsTick(PhysicsComp* comp, Vector3 vel) {
Entity* entity = comp->Entity;
HacksComp* hacks = comp->Hacks;
if (hacks->Noclip) entity->OnGround = false;
Real32 baseSpeed = PhysicsComp_GetBaseSpeed(comp);
Real32 verSpeed = baseSpeed * (PhysicsComp_GetSpeed(hacks, 8.0f) / 5.0f);
Real32 horSpeed = baseSpeed * PhysicsComp_GetSpeed(hacks, 8.0f / 5.0f) * hacks->BaseHorSpeed;
/* previously horSpeed used to be multiplied by factor of 0.02 in last case */
/* it's now multiplied by 0.1, so need to divide by 5 so user speed modifier comes out same */
/* TODO: this is a temp fix to avoid crashing for high horizontal speed */
if (horSpeed > 75.0f) horSpeed = 75.0f;
/* vertical speed never goes below: base speed * 1.0 */
if (verSpeed < baseSpeed) verSpeed = baseSpeed;
bool womSpeedBoost = hacks->CanDoubleJump && hacks->WOMStyleHacks;
if (!hacks->Floating && womSpeedBoost) {
if (comp->MultiJumps == 1) { horSpeed *= 46.5f; verSpeed *= 7.5f; }
else if (comp->MultiJumps > 1) { horSpeed *= 93.0f; verSpeed *= 10.0f; }
}
if (Entity_TouchesAnyWater(entity) && !hacks->Floating) {
Vector3 waterDrag = VECTOR3_CONST(0.8f, 0.8f, 0.8f);
PhysicsComp_MoveNormal(comp, vel, 0.02f * horSpeed, waterDrag, LIQUID_GRAVITY, verSpeed);
} else if (Entity_TouchesAnyLava(entity) && !hacks->Floating) {
Vector3 lavaDrag = VECTOR3_CONST(0.5f, 0.5f, 0.5f);
PhysicsComp_MoveNormal(comp, vel, 0.02f * horSpeed, lavaDrag, LIQUID_GRAVITY, verSpeed);
} else if (Entity_TouchesAnyRope(entity) && !hacks->Floating) {
Vector3 ropeDrag = VECTOR3_CONST(0.5f, 0.85f, 0.5f);
PhysicsComp_MoveNormal(comp, vel, 0.02f * 1.7f, ropeDrag, ROPE_GRAVITY, verSpeed);
} else {
Real32 factor = hacks->Floating || entity->OnGround ? 0.1f : 0.02f;
Real32 gravity = comp->UseLiquidGravity ? LIQUID_GRAVITY : entity->Model->Gravity;
if (hacks->Floating) {
PhysicsComp_MoveFlying(comp, vel, factor * horSpeed, entity->Model->Drag, gravity, verSpeed);
} else {
PhysicsComp_MoveNormal(comp, vel, factor * horSpeed, entity->Model->Drag, gravity, verSpeed);
}
if (PhysicsComp_OnIce(entity) && !hacks->Floating) {
/* limit components to +-0.25f by rescaling vector to [-0.25, 0.25] */
if (Math_AbsF(entity->Velocity.X) > 0.25f || Math_AbsF(entity->Velocity.Z) > 0.25f) {
Real32 xScale = Math_AbsF(0.25f / entity->Velocity.X);
Real32 zScale = Math_AbsF(0.25f / entity->Velocity.Z);
Real32 scale = min(xScale, zScale);
entity->Velocity.X *= scale;
entity->Velocity.Z *= scale;
}
} else if (entity->OnGround || hacks->Flying) {
Vector3_Mul3By(&entity->Velocity, &entity->Model->GroundFriction); /* air drag or ground friction */
}
}
if (entity->OnGround) comp->MultiJumps = 0;
}
Real64 PhysicsComp_YPosAt(Int32 t, Real32 u) {
/* v(t, u) = (4 + u) * (0.98^t) - 4, where u = initial velocity */
/* x(t, u) = Σv(t, u) from 0 to t (since we work in discrete timesteps) */
/* plugging into Wolfram Alpha gives 1 equation as */
/* (0.98^t) * (-49u - 196) - 4t + 50u + 196 */
Real64 a = Math_Exp(-0.0202027 * t); /* ~0.98^t */
return a * (-49 * u - 196) - 4 * t + 50 * u + 196;
}
Real64 PhysicsComp_GetMaxHeight(Real32 u) {
/* equation below comes from solving diff(x(t, u))= 0 */
/* We only work in discrete timesteps, so test both rounded up and down */
Real64 t = 49.49831645 * Math_Log(0.247483075 * u + 0.9899323);
Real64 value_floor = PhysicsComp_YPosAt((Int32)t, u);
Real64 value_ceil = PhysicsComp_YPosAt((Int32)t + 1, u);
return max(value_floor, value_ceil);
}
/* Calculates the jump velocity required such that when a client presses
the jump binding they will be able to jump up to the given height. */
void PhysicsComp_CalculateJumpVelocity(PhysicsComp* comp, bool userVel, Real32 jumpHeight) {
comp->JumpVel = 0.0f;
if (jumpHeight == 0.0f) return;
if (jumpHeight >= 256.0f) comp->JumpVel = 10.0f;
if (jumpHeight >= 512.0f) comp->JumpVel = 16.5f;
if (jumpHeight >= 768.0f) comp->JumpVel = 22.5f;
while (PhysicsComp_GetMaxHeight(comp->JumpVel) <= jumpHeight) { comp->JumpVel += 0.001f; }
if (userVel) comp->UserJumpVel = comp->JumpVel;
}
void PhysicsComp_DoEntityPush(Entity* entity) {
Int32 id;
Vector3 dir; dir.Y = 0.0f;
for (id = 0; id < ENTITIES_MAX_COUNT; id++) {
Entity* other = Entities_List[id];
if (other == NULL || other == entity) continue;
if (!other->Model->Pushes) continue;
bool yIntersects =
entity->Position.Y <= (other->Position.Y + other->Size.Y) &&
other->Position.Y <= (entity->Position.Y + entity->Size.Y);
if (!yIntersects) continue;
dir.X = other->Position.X - entity->Position.X;
dir.Z = other->Position.Z - entity->Position.Z;
Real32 dist = dir.X * dir.X + dir.Z * dir.Z;
if (dist < 0.002f || dist > 1.0f) continue; /* TODO: range needs to be lower? */
Vector3_Normalize(&dir, &dir);
Real32 pushStrength = (1 - dist) / 32.0f; /* TODO: should be 24/25 */
/* entity.Velocity -= dir * pushStrength */
Vector3_Mul1By(&dir, pushStrength);
Vector3_SubBy(&entity->Velocity, &dir);
}
} }

View File

@ -9,7 +9,7 @@
typedef struct Entity_ Entity; typedef struct Entity_ Entity;
typedef struct LocationUpdate_ LocationUpdate; typedef struct LocationUpdate_ LocationUpdate;
/* Entity component that performs model animation depending on movement speed and time. */ /* Entity component that performs model animation depending on movement speed and time */
typedef struct AnimatedComp_ { typedef struct AnimatedComp_ {
Real32 BobbingHor, BobbingVer, BobbingModel; Real32 BobbingHor, BobbingVer, BobbingModel;
Real32 WalkTime, Swing, BobStrength; Real32 WalkTime, Swing, BobStrength;
@ -23,7 +23,7 @@ void AnimatedComp_Init(AnimatedComp* anim);
void AnimatedComp_Update(AnimatedComp* anim, Vector3 oldPos, Vector3 newPos, Real64 delta, bool onGround); void AnimatedComp_Update(AnimatedComp* anim, Vector3 oldPos, Vector3 newPos, Real64 delta, bool onGround);
void AnimatedComp_GetCurrent(AnimatedComp* anim, Real32 t, bool calcHumanAnims); void AnimatedComp_GetCurrent(AnimatedComp* anim, Real32 t, bool calcHumanAnims);
/* Entity component that performs tilt animation depending on movement speed and time. */ /* Entity component that performs tilt animation depending on movement speed and time */
typedef struct TiltComp_ { typedef struct TiltComp_ {
Real32 TiltX, TiltY, VelTiltStrength; Real32 TiltX, TiltY, VelTiltStrength;
Real32 VelTiltStrengthO, VelTiltStrengthN; Real32 VelTiltStrengthO, VelTiltStrengthN;
@ -33,33 +33,34 @@ void TiltComp_Init(TiltComp* anim);
void TiltComp_Update(TiltComp* anim, Real64 delta); void TiltComp_Update(TiltComp* anim, Real64 delta);
void TiltComp_GetCurrent(TiltComp* anim, Real32 t); void TiltComp_GetCurrent(TiltComp* anim, Real32 t);
/* Entity component that performs management of hack states. */ /* Entity component that performs management of hack states */
typedef struct HacksComponent_ { typedef struct HacksComponent_ {
UInt8 UserType; UInt8 UserType;
/* Speed player move at, relative to normal speed, when the 'speeding' key binding is held down. */ /* Speed player move at, relative to normal speed, when the 'speeding' key binding is held down */
Real32 SpeedMultiplier; Real32 SpeedMultiplier;
/* Whether blocks that the player places that intersect themselves, should cause the player to /* Whether blocks that the player places that intersect themselves, should cause the player to
be pushed back in the opposite direction of the placed block. */ be pushed back in the opposite direction of the placed block */
bool PushbackPlacing; bool PushbackPlacing;
/* Whether the player should be able to step up whole blocks, instead of just slabs. */ /* Whether the player should be able to step up whole blocks, instead of just slabs */
bool FullBlockStep; bool FullBlockStep;
/* Whether the player has allowed hacks usage as an option. Note 'can use X' set by the server override this. */ /* Whether the player has allowed hacks usage as an option. Note 'can use X' set by the server override this */
bool Enabled; bool Enabled;
bool CanAnyHacks, CanUseThirdPersonCamera, CanSpeed, CanFly; bool CanAnyHacks, CanUseThirdPersonCamera, CanSpeed, CanFly;
bool CanRespawn, CanNoclip, CanPushbackBlocks,CanSeeAllNames; bool CanRespawn, CanNoclip, CanPushbackBlocks,CanSeeAllNames;
bool CanDoubleJump, CanBePushed; bool CanDoubleJump, CanBePushed;
/* Maximum speed the entity can move at horizontally when CanSpeed is false. */ /* Maximum speed the entity can move at horizontally when CanSpeed is false */
Real32 BaseHorSpeed; Real32 BaseHorSpeed;
/* Max amount of jumps the player can perform. */ /* Max amount of jumps the player can perform */
Int32 MaxJumps; Int32 MaxJumps;
/* Whether the player should slide after letting go of movement buttons in noclip. */ /* Whether the player should slide after letting go of movement buttons in noclip */
bool NoclipSlide; bool NoclipSlide;
/* Whether the player has allowed the usage of fast double jumping abilities. */ /* Whether the player has allowed the usage of fast double jumping abilities */
bool WOMStyleHacks; bool WOMStyleHacks;
bool Noclip, Flying,FlyingUp, FlyingDown, Speeding, HalfSpeeding; bool Noclip, Flying, FlyingUp, FlyingDown, Speeding, HalfSpeeding;
bool Floating; /* true if NoClip or Flying */
UInt8 HacksFlagsBuffer[String_BufferSize(128)]; UInt8 HacksFlagsBuffer[String_BufferSize(128)];
String HacksFlags; String HacksFlags;
} HacksComp; } HacksComp;
@ -71,13 +72,13 @@ void HacksComp_SetUserType(HacksComp* hacks, UInt8 value, bool setBlockPerms);
void HacksComp_CheckConsistency(HacksComp* hacks); void HacksComp_CheckConsistency(HacksComp* hacks);
void HacksComp_UpdateState(HacksComp* hacks); void HacksComp_UpdateState(HacksComp* hacks);
/* Represents a position and orientation state. */ /* Represents a position and orientation state */
typedef struct InterpState_ { typedef struct InterpState_ {
Vector3 Pos; Vector3 Pos;
Real32 HeadX, HeadY, RotX, RotZ; Real32 HeadX, HeadY, RotX, RotZ;
} InterpState; } InterpState;
/* Base entity component that performs interpolation of position and orientation. */ /* Base entity component that performs interpolation of position and orientation */
typedef struct InterpComp_ { typedef struct InterpComp_ {
InterpState Prev, Next; InterpState Prev, Next;
Real32 PrevRotY, NextRotY; Real32 PrevRotY, NextRotY;
@ -91,10 +92,10 @@ void InterpComp_LerpAngles(InterpComp* interp, Entity* entity, Real32 t);
void LocalInterpComp_SetLocation(InterpComp* interp, LocationUpdate* update, bool interpolate); void LocalInterpComp_SetLocation(InterpComp* interp, LocationUpdate* update, bool interpolate);
void LocalInterpComp_AdvanceState(InterpComp* interp); void LocalInterpComp_AdvanceState(InterpComp* interp);
/* Entity component that performs interpolation for network players. */ /* Entity component that performs interpolation for network players */
typedef struct NetInterpComp_ { typedef struct NetInterpComp_ {
InterpComp Base; InterpComp Base;
/* Last known position and orientation sent by the server. */ /* Last known position and orientation sent by the server */
InterpState Cur; InterpState Cur;
Int32 StatesCount; Int32 StatesCount;
InterpState States[10]; InterpState States[10];
@ -103,10 +104,37 @@ typedef struct NetInterpComp_ {
void NetInterpComp_SetLocation(NetInterpComp* interp, LocationUpdate* update, bool interpolate); void NetInterpComp_SetLocation(NetInterpComp* interp, LocationUpdate* update, bool interpolate);
void NetInterpComp_AdvanceState(NetInterpComp* interp); void NetInterpComp_AdvanceState(NetInterpComp* interp);
/* Entity component that draws square and circle shadows beneath entities. */ /* Entity component that draws square and circle shadows beneath entities */
bool ShadowComponent_BoundShadowTex; bool ShadowComponent_BoundShadowTex;
GfxResourceID ShadowComponent_ShadowTex; GfxResourceID ShadowComponent_ShadowTex;
void ShadowComponent_Draw(Entity* entity); void ShadowComponent_Draw(Entity* entity);
/* Entity component that performs collision detection */
typedef struct CollisionsComp_ {
Entity* Entity;
bool HitXMin, HitYMin, HitZMin, HitXMax, HitYMax, HitZMax, WasOn;
} CollisionsComp;
bool Collisions_HitHorizontal(CollisionsComp* comp);
void Collisions_MoveAndWallSlide(CollisionsComp* comp);
/* Entity component that performs collisions */
typedef struct PhysicsComp_ {
bool UseLiquidGravity; /* used by BlockDefinitions */
bool CanLiquidJump, Jumping;
Int32 MultiJumps;
Entity* Entity;
Real32 JumpVel, UserJumpVel, ServerJumpVel;
HacksComp* Hacks;
CollisionsComp* Collisions;
} PhysicsComp;
void PhysicsComp_Init(PhysicsComp* comp, Entity* entity);
void PhysicsComp_UpdateVelocityState(PhysicsComp* comp);
void PhysicsComp_DoNormalJump(PhysicsComp* comp);
void PhysicsComp_PhysicsTick(PhysicsComp* comp, Vector3 vel);
void PhysicsComp_CalculateJumpVelocity(PhysicsComp* comp, bool userVel, Real32 jumpHeight);
Real64 PhysicsComp_GetMaxHeight(Real32 u);
void PhysicsComp_DoEntityPush(Entity* entity);
#endif #endif

View File

@ -18,11 +18,11 @@ GfxResourceID env_cloudsVb, env_skyVb, env_cloudsTex;
Int32 env_cloudVertices, env_skyVertices; Int32 env_cloudVertices, env_skyVertices;
Real32 EnvRenderer_BlendFactor(Real32 x) { Real32 EnvRenderer_BlendFactor(Real32 x) {
/* return -0.05 + 0.22 * (Math_LogE(x) * 0.25f); */ /* return -0.05 + 0.22 * (Math_Log(x) * 0.25f); */
Real32 blend = -0.13f + 0.28f * (Math_LogE(x) * 0.25f); Real64 blend = -0.13 + 0.28 * (Math_Log(x) * 0.25);
if (blend < 0.0f) blend = 0.0f; if (blend < 0.0) blend = 0.0;
if (blend > 1.0f) blend = 1.0f; if (blend > 1.0) blend = 1.0;
return blend; return (Real32)blend;
} }
void EnvRenderer_BlockOn(Real32* fogDensity, PackedCol* fogCol) { void EnvRenderer_BlockOn(Real32* fogDensity, PackedCol* fogCol) {
@ -59,8 +59,11 @@ void EnvRenderer_RenderMinimal(Real64 deltaTime) {
/* TODO: rewrite this to avoid raising the event? want to avoid recreating vbos too many times often */ /* TODO: rewrite this to avoid raising the event? want to avoid recreating vbos too many times often */
if (fogDensity != 0.0f) { if (fogDensity != 0.0f) {
/* Exp fog mode: f = e^(-density*coord) */ /* Exp fog mode: f = e^(-density*coord) */
/* Solve for f = 0.05 to figure out coord (good approx for fog end) */ /* Solve coord for f = 0.05 (good approx for fog end) */
Real32 dist = (Real32)Math_LogE(0.05f) / -fogDensity; /* i.e. log(0.05) = -density * coord */
#define LOG_005 -2.99573227355399
Real64 dist = LOG_005 / -fogDensity;
Game_SetViewDistance((Int32)dist, false); Game_SetViewDistance((Int32)dist, false);
} else { } else {
Game_SetViewDistance(Game_UserViewDistance, false); Game_SetViewDistance(Game_UserViewDistance, false);
@ -129,8 +132,10 @@ void EnvRenderer_UpdateFog(void) {
0.99=z/end --> z=end*0.99 0.99=z/end --> z=end*0.99
therefore therefore
d = -ln(0.01)/(end*0.99) */ d = -ln(0.01)/(end*0.99) */
Real32 density = -Math_LogE(0.01f) / (Game_ViewDistance * 0.99f);
Gfx_SetFogDensity(density); #define LOG_001 -4.60517018598809
Real64 density = -(LOG_001) / (Game_ViewDistance * 0.99);
Gfx_SetFogDensity((Real32)density);
} else { } else {
Gfx_SetFogMode(FOG_LINEAR); Gfx_SetFogMode(FOG_LINEAR);
Gfx_SetFogEnd(Game_ViewDistance); Gfx_SetFogEnd(Game_ViewDistance);

View File

@ -1,5 +1,21 @@
#include "ExtMath.h" #include "ExtMath.h"
#include <math.h>
/* TODO: Replace with own functions that don't rely on stdlib */
Real32 Math_AbsF(Real32 x) { return fabsf(x); }
Real32 Math_SinF(Real32 x) { return sinf(x); }
Real32 Math_CosF(Real32 x) { return cosf(x); }
Real32 Math_TanF(Real32 x) { return tanf(x); }
Real32 Math_SqrtF(Real32 x) { return sqrtf(x); }
Real32 Math_ModF(Real32 x, Real32 y) { return fmodf(x, y); }
Real64 Math_Log(Real64 x) { return log(x); }
Real64 Math_Exp(Real64 x) { return exp(x); }
Real64 Math_Asin(Real64 x) { return asin(x); }
Real64 Math_Atan2(Real64 y, Real64 x) { return atan2(y, x); }
Int32 Math_AbsI(Int32 x) { return abs(x); }
Int32 Math_Floor(Real32 value) { Int32 Math_Floor(Real32 value) {
Int32 valueI = (Int32)value; Int32 valueI = (Int32)value;
return valueI > value ? valueI - 1 : valueI; return valueI > value ? valueI - 1 : valueI;

View File

@ -1,6 +1,5 @@
#ifndef CC_MATH_H #ifndef CC_MATH_H
#define CC_MATH_H #define CC_MATH_H
#include <math.h>
#include "Typedefs.h" #include "Typedefs.h"
/* Simple math functions and constants. /* Simple math functions and constants.
Copyright 2017 ClassicalSharp | Licensed under BSD-3 Copyright 2017 ClassicalSharp | Licensed under BSD-3
@ -15,21 +14,19 @@
#define Math_Deg2Packed(x) ((UInt8)((x) * 256.0f / 360.0f)) #define Math_Deg2Packed(x) ((UInt8)((x) * 256.0f / 360.0f))
#define Math_Packed2Deg(x) ((x) * 360.0f / 256.0f) #define Math_Packed2Deg(x) ((x) * 360.0f / 256.0f)
#define Math_AbsF(x) fabsf(x) Real32 Math_AbsF(Real32 x);
#define Math_AbsI(x) abs(x) Real32 Math_SinF(Real32 x);
Real32 Math_CosF(Real32 x);
Real32 Math_TanF(Real32 x);
Real32 Math_SqrtF(Real32 x);
Real32 Math_ModF(Real32 x, Real32 y);
#define Math_LogE(x) logf(x) Real64 Math_Log(Real64 x);
#define Math_PowE(x) expf(x) Real64 Math_Exp(Real64 x);
Real64 Math_Asin(Real64 x);
#define Math_Sin(x) sinf(x) Real64 Math_Atan2(Real64 y, Real64 x);
#define Math_Cos(x) cosf(x)
#define Math_Tan(x) tanf(x)
#define Math_Asin(x) asinf(x)
#define Math_Atan2(y, x) atan2f(y, x)
#define Math_Sqrt(x) sqrtf(x)
#define Math_Mod(x, y) fmodf(x, y)
Int32 Math_AbsI(Int32 x);
Int32 Math_Floor(Real32 value); Int32 Math_Floor(Real32 value);
Int32 Math_Ceil(Real32 value); Int32 Math_Ceil(Real32 value);
Int32 Math_Log2(Int32 value); Int32 Math_Log2(Int32 value);

View File

@ -103,16 +103,16 @@ void HeldBlockRenderer_ProjectionChanged(void* obj) {
*/ */
void HeldBlockRenderer_DigAnimation(void) { void HeldBlockRenderer_DigAnimation(void) {
Real32 t = held_time / held_period; Real32 t = held_time / held_period;
Real32 sinHalfCircle = Math_Sin(t * MATH_PI); Real32 sinHalfCircle = Math_SinF(t * MATH_PI);
Real32 sqrtLerpPI = Math_Sqrt(t) * MATH_PI; Real32 sqrtLerpPI = Math_SqrtF(t) * MATH_PI;
held_entity.Position.X -= Math_Sin(sqrtLerpPI) * 0.4f; held_entity.Position.X -= Math_SinF(sqrtLerpPI) * 0.4f;
held_entity.Position.Y += Math_Sin((sqrtLerpPI * 2)) * 0.2f; held_entity.Position.Y += Math_SinF((sqrtLerpPI * 2)) * 0.2f;
held_entity.Position.Z -= sinHalfCircle * 0.2f; held_entity.Position.Z -= sinHalfCircle * 0.2f;
Real32 sinHalfCircleWeird = Math_Sin(t * t * MATH_PI); Real32 sinHalfCircleWeird = Math_SinF(t * t * MATH_PI);
held_entity.RotY -= Math_Sin(sqrtLerpPI) * 80.0f; held_entity.RotY -= Math_SinF(sqrtLerpPI) * 80.0f;
held_entity.HeadY -= Math_Sin(sqrtLerpPI) * 80.0f; held_entity.HeadY -= Math_SinF(sqrtLerpPI) * 80.0f;
held_entity.RotX += sinHalfCircleWeird * 20.0f; held_entity.RotX += sinHalfCircleWeird * 20.0f;
} }
@ -172,7 +172,7 @@ void HeldBlockRenderer_DoAnimation(Real64 delta, Real32 lastSwingY) {
if (held_swinging || !held_breaking) { if (held_swinging || !held_breaking) {
Real32 t = held_time / held_period; Real32 t = held_time / held_period;
held_swingY = -0.4f * Math_Sin(t * MATH_PI); held_swingY = -0.4f * Math_SinF(t * MATH_PI);
held_entity.Position.Y += held_swingY; held_entity.Position.Y += held_swingY;
if (held_swinging) { if (held_swinging) {

View File

@ -118,8 +118,8 @@ void IModel_SetupState(IModel* model, Entity* entity) {
IModel_Cols[5] = IModel_Cols[4]; IModel_Cols[5] = IModel_Cols[4];
Real32 yawDelta = entity->HeadY - entity->RotY; Real32 yawDelta = entity->HeadY - entity->RotY;
IModel_cosHead = Math_Cos(yawDelta * MATH_DEG2RAD); IModel_cosHead = Math_CosF(yawDelta * MATH_DEG2RAD);
IModel_sinHead = Math_Sin(yawDelta * MATH_DEG2RAD); IModel_sinHead = Math_SinF(yawDelta * MATH_DEG2RAD);
} }
void IModel_UpdateVB(void) { void IModel_UpdateVB(void) {
@ -158,9 +158,9 @@ void IModel_DrawPart(ModelPart part) {
void IModel_DrawRotate(Real32 angleX, Real32 angleY, Real32 angleZ, ModelPart part, bool head) { void IModel_DrawRotate(Real32 angleX, Real32 angleY, Real32 angleZ, ModelPart part, bool head) {
IModel* model = IModel_ActiveModel; IModel* model = IModel_ActiveModel;
Real32 cosX = Math_Cos(-angleX), sinX = Math_Sin(-angleX); Real32 cosX = Math_CosF(-angleX), sinX = Math_SinF(-angleX);
Real32 cosY = Math_Cos(-angleY), sinY = Math_Sin(-angleY); Real32 cosY = Math_CosF(-angleY), sinY = Math_SinF(-angleY);
Real32 cosZ = Math_Cos(-angleZ), sinZ = Math_Sin(-angleZ); Real32 cosZ = Math_CosF(-angleZ), sinZ = Math_SinF(-angleZ);
Real32 x = part.RotX, y = part.RotY, z = part.RotZ; Real32 x = part.RotX, y = part.RotY, z = part.RotZ;
ModelVertex* src = &model->vertices[part.Offset]; ModelVertex* src = &model->vertices[part.Offset];

View File

@ -386,7 +386,7 @@ void InputHandler_KeyDown(void* obj, Int32 key) {
Game_ScreenshotRequested = true; Game_ScreenshotRequested = true;
} else if (active->VTABLE->HandlesKeyDown(active, key)) { } else if (active->VTABLE->HandlesKeyDown(active, key)) {
} else if (InputHandler_HandleCoreKey(key)) { } else if (InputHandler_HandleCoreKey(key)) {
} else if (LocalPlayer_Instance.Input.Handles(key)) { } else if (LocalPlayer_HandlesKey(key)) {
} else { } else {
UInt8 textBuffer[String_BufferSize(STRING_SIZE)]; UInt8 textBuffer[String_BufferSize(STRING_SIZE)];
String text = String_InitAndClearArray(textBuffer); String text = String_InitAndClearArray(textBuffer);

View File

@ -44,10 +44,10 @@ void IsometricDrawer_InitCache(void) {
Matrix_RotateX(&rotX, -30.0f * MATH_DEG2RAD); Matrix_RotateX(&rotX, -30.0f * MATH_DEG2RAD);
Matrix_Mul(&iso_transform, &rotY, &rotX); Matrix_Mul(&iso_transform, &rotY, &rotX);
iso_cosX = Math_Cos(30.0f * MATH_DEG2RAD); iso_cosX = Math_CosF(30.0f * MATH_DEG2RAD);
iso_sinX = Math_Sin(30.0f * MATH_DEG2RAD); iso_sinX = Math_SinF(30.0f * MATH_DEG2RAD);
iso_cosY = Math_Cos(-45.0f * MATH_DEG2RAD); iso_cosY = Math_CosF(-45.0f * MATH_DEG2RAD);
iso_sinY = Math_Sin(-45.0f * MATH_DEG2RAD); iso_sinY = Math_SinF(-45.0f * MATH_DEG2RAD);
} }
void IsometricDrawer_Flush(void) { void IsometricDrawer_Flush(void) {

View File

@ -216,9 +216,9 @@ void NotchyGen_CarveCaves(void) {
Real32 caveRadius = Random_Float(&rnd) * Random_Float(&rnd); Real32 caveRadius = Random_Float(&rnd) * Random_Float(&rnd);
for (j = 0; j < caveLen; j++) { for (j = 0; j < caveLen; j++) {
caveX += Math_Sin(theta) * Math_Cos(phi); caveX += Math_SinF(theta) * Math_CosF(phi);
caveZ += Math_Cos(theta) * Math_Cos(phi); caveZ += Math_CosF(theta) * Math_CosF(phi);
caveY += Math_Sin(phi); caveY += Math_SinF(phi);
theta = theta + deltaTheta * 0.2f; theta = theta + deltaTheta * 0.2f;
deltaTheta = deltaTheta * 0.9f + Random_Float(&rnd) - Random_Float(&rnd); deltaTheta = deltaTheta * 0.9f + Random_Float(&rnd) - Random_Float(&rnd);
@ -232,7 +232,7 @@ void NotchyGen_CarveCaves(void) {
Real32 radius = (Gen_Height - cenY) / (Real32)Gen_Height; Real32 radius = (Gen_Height - cenY) / (Real32)Gen_Height;
radius = 1.2f + (radius * 3.5f + 1.0f) * caveRadius; radius = 1.2f + (radius * 3.5f + 1.0f) * caveRadius;
radius = radius * Math_Sin(j * MATH_PI / caveLen); radius = radius * Math_SinF(j * MATH_PI / caveLen);
NotchyGen_FillOblateSpheroid(cenX, cenY, cenZ, radius, BLOCK_AIR); NotchyGen_FillOblateSpheroid(cenX, cenY, cenZ, radius, BLOCK_AIR);
} }
} }
@ -254,16 +254,16 @@ void NotchyGen_CarveOreVeins(Real32 abundance, const UInt8* state, BlockID block
Real32 phi = Random_Float(&rnd) * 2.0f * MATH_PI, deltaPhi = 0.0f; Real32 phi = Random_Float(&rnd) * 2.0f * MATH_PI, deltaPhi = 0.0f;
for (j = 0; j < veinLen; j++) { for (j = 0; j < veinLen; j++) {
veinX += Math_Sin(theta) * Math_Cos(phi); veinX += Math_SinF(theta) * Math_CosF(phi);
veinZ += Math_Cos(theta) * Math_Cos(phi); veinZ += Math_CosF(theta) * Math_CosF(phi);
veinY += Math_Sin(phi); veinY += Math_SinF(phi);
theta = deltaTheta * 0.2f; theta = deltaTheta * 0.2f;
deltaTheta = deltaTheta * 0.9f + Random_Float(&rnd) - Random_Float(&rnd); deltaTheta = deltaTheta * 0.9f + Random_Float(&rnd) - Random_Float(&rnd);
phi = phi * 0.5f + deltaPhi * 0.25f; phi = phi * 0.5f + deltaPhi * 0.25f;
deltaPhi = deltaPhi * 0.9f + Random_Float(&rnd) - Random_Float(&rnd); deltaPhi = deltaPhi * 0.9f + Random_Float(&rnd) - Random_Float(&rnd);
Real32 radius = abundance * Math_Sin(j * MATH_PI / veinLen) + 1.0f; Real32 radius = abundance * Math_SinF(j * MATH_PI / veinLen) + 1.0f;
NotchyGen_FillOblateSpheroid((Int32)veinX, (Int32)veinY, (Int32)veinZ, radius, block); NotchyGen_FillOblateSpheroid((Int32)veinX, (Int32)veinY, (Int32)veinZ, radius, block);
} }
} }

View File

@ -2611,9 +2611,13 @@ void HacksSettingsScreen_SetClipping(STRING_PURE String* v) {
void HacksSettingsScreen_GetJump(STRING_TRANSIENT String* v) { String_AppendReal32(v, LocalPlayer_JumpHeight(), 3); } void HacksSettingsScreen_GetJump(STRING_TRANSIENT String* v) { String_AppendReal32(v, LocalPlayer_JumpHeight(), 3); }
void HacksSettingsScreen_SetJump(STRING_PURE String* v) { void HacksSettingsScreen_SetJump(STRING_PURE String* v) {
LocalPlayer_Instance.physics.CalculateJumpVelocity(true, Menu_Real32(v)); PhysicsComp* physics = &LocalPlayer_Instance.Physics;
Real32 jumpVel = LocalPlayer_Instance.physics.jumpVel; PhysicsComp_CalculateJumpVelocity(physics, true, Menu_Real32(v));
Options_Set(OPT_JUMP_VELOCITY, jumpVel.ToString());
UInt8 strBuffer[String_BufferSize(STRING_SIZE)];
String str = String_InitAndClearArray(strBuffer);
String_AppendReal32(&str, physics->JumpVel, 8);
Options_Set(OPT_JUMP_VELOCITY, &str);
} }
void HacksSettingsScreen_GetWOMHacks(STRING_TRANSIENT String* v) { Menu_GetBool(v, LocalPlayer_Instance.Hacks.WOMStyleHacks); } void HacksSettingsScreen_GetWOMHacks(STRING_TRANSIENT String* v) { Menu_GetBool(v, LocalPlayer_Instance.Hacks.WOMStyleHacks); }

View File

@ -572,9 +572,9 @@ void SpiderModel_DrawModel(Entity* entity) {
IModel_DrawPart(Spider_Link); IModel_DrawPart(Spider_Link);
IModel_DrawPart(Spider_End); IModel_DrawPart(Spider_End);
Real32 rotX = Math_Sin(entity->Anim.WalkTime) * entity->Anim.Swing * MATH_PI; Real32 rotX = Math_SinF(entity->Anim.WalkTime) * entity->Anim.Swing * MATH_PI;
Real32 rotZ = Math_Cos(entity->Anim.WalkTime * 2) * entity->Anim.Swing * MATH_PI / 16.0f; Real32 rotZ = Math_CosF(entity->Anim.WalkTime * 2) * entity->Anim.Swing * MATH_PI / 16.0f;
Real32 rotY = Math_Sin(entity->Anim.WalkTime * 2) * entity->Anim.Swing * MATH_PI / 32.0f; Real32 rotY = Math_SinF(entity->Anim.WalkTime * 2) * entity->Anim.Swing * MATH_PI / 32.0f;
IModel_Rotation = ROTATE_ORDER_XZY; IModel_Rotation = ROTATE_ORDER_XZY;
IModel_DrawRotate(rotX, quarterPi + rotY, eighthPi + rotZ, Spider_LeftLeg, false); IModel_DrawRotate(rotX, quarterPi + rotY, eighthPi + rotZ, Spider_LeftLeg, false);
@ -1120,10 +1120,10 @@ Real32 BlockModel_GetEyeY(Entity* entity) {
Vector3 BlockModel_GetCollisionSize(void) { Vector3 BlockModel_GetCollisionSize(void) {
Vector3 size; Vector3 size;
Vector3_Subtract(&size, &BlockModel_maxBB, &BlockModel_minBB); Vector3_Sub(&size, &BlockModel_maxBB, &BlockModel_minBB);
/* to fit slightly inside */ /* to fit slightly inside */
Vector3 sizeShrink = Vector3_Create1(0.75f / 16.0f); Vector3 sizeShrink = VECTOR3_CONST1(0.75f / 16.0f);
Vector3_Subtract(&size, &size, &sizeShrink); Vector3_SubBy(&size, &sizeShrink);
return size; return size;
} }

View File

@ -105,7 +105,7 @@ bool Particle_PhysicsTick(Particle* p, Real32 gravity, bool throughLiquids, Real
p->Velocity.Y -= gravity * (Real32)delta; p->Velocity.Y -= gravity * (Real32)delta;
Int32 startY = Math_Floor(p->NextPos.Y); Int32 startY = Math_Floor(p->NextPos.Y);
Vector3 velocity; Vector3 velocity;
Vector3_Multiply1(&velocity, &p->Velocity, (Real32)delta * 3.0f); Vector3_Mul1(&velocity, &p->Velocity, (Real32)delta * 3.0f);
Vector3_Add(&p->NextPos, &p->NextPos, &velocity); Vector3_Add(&p->NextPos, &p->NextPos, &velocity);
Int32 endY = Math_Floor(p->NextPos.Y); Int32 endY = Math_Floor(p->NextPos.Y);

View File

@ -71,7 +71,7 @@ bool Intersection_RayIntersectsRotatedBox(Vector3 origin, Vector3 dir, Entity* t
* / * /
/ /
*/ */
Vector3 delta; Vector3_Subtract(&delta, &origin, &target->Position); /* delta = origin - target.Position */ Vector3 delta; Vector3_Sub(&delta, &origin, &target->Position); /* delta = origin - target.Position */
delta = Intersection_InverseRotate(delta, target); /* delta = UndoRotation(delta) */ delta = Intersection_InverseRotate(delta, target); /* delta = UndoRotation(delta) */
Vector3_Add(&origin, &delta, &target->Position); /* origin = delta + target.Position */ Vector3_Add(&origin, &delta, &target->Position); /* origin = delta + target.Position */

View File

@ -71,7 +71,7 @@ void PickedPosRenderer_ZQuad(Real32 z, Real32 x1, Real32 y1, Real32 x2, Real32 y
void PickedPosRenderer_UpdateState(PickedPos* selected) { void PickedPosRenderer_UpdateState(PickedPos* selected) {
pickedPos_ptr = pickedPos_vertices; pickedPos_ptr = pickedPos_vertices;
Vector3 delta; Vector3 delta;
Vector3_Subtract(&delta, &Game_CurrentCameraPos, &selected->Min); Vector3_Sub(&delta, &Game_CurrentCameraPos, &selected->Min);
Real32 dist = Vector3_LengthSquared(&delta); Real32 dist = Vector3_LengthSquared(&delta);
Real32 offset = 0.01f; Real32 offset = 0.01f;

View File

@ -185,7 +185,7 @@ bool Picking_ClipBlock(PickedPos* pos) {
} }
Vector3 scaledDir, intersect; Vector3 scaledDir, intersect;
Vector3_Multiply1(&scaledDir, &tracer.Dir, t0); /* scaledDir = dir * t0 */ Vector3_Mul1(&scaledDir, &tracer.Dir, t0); /* scaledDir = dir * t0 */
Vector3_Add(&intersect, &tracer.Origin, &scaledDir); /* intersect = origin + scaledDir */ Vector3_Add(&intersect, &tracer.Origin, &scaledDir); /* intersect = origin + scaledDir */
/* Only pick the block if the block is precisely within reach distance. */ /* Only pick the block if the block is precisely within reach distance. */
Real32 lenSq = Vector3_LengthSquared(&scaledDir); Real32 lenSq = Vector3_LengthSquared(&scaledDir);
@ -210,7 +210,7 @@ bool Picking_ClipCamera(PickedPos* pos) {
} }
Vector3 intersect; Vector3 intersect;
Vector3_Multiply1(&intersect, &tracer.Dir, t0); /* intersect = dir * t0 */ Vector3_Mul1(&intersect, &tracer.Dir, t0); /* intersect = dir * t0 */
Vector3_Add(&intersect, &tracer.Origin, &intersect); /* intersect = origin + dir * t0 */ Vector3_Add(&intersect, &tracer.Origin, &intersect); /* intersect = origin + dir * t0 */
PickedPos_SetAsValid(pos, &tracer, intersect); PickedPos_SetAsValid(pos, &tracer, intersect);
@ -236,7 +236,7 @@ void Picking_ClipCameraPos(Vector3 origin, Vector3 dir, Real32 reach, PickedPos*
bool noClip = !Game_CameraClipping || LocalPlayer_Instance.Hacks.Noclip; bool noClip = !Game_CameraClipping || LocalPlayer_Instance.Hacks.Noclip;
if (noClip || !Picking_RayTrace(origin, dir, reach, pos, Picking_ClipCamera)) { if (noClip || !Picking_RayTrace(origin, dir, reach, pos, Picking_ClipCamera)) {
PickedPos_SetAsInvalid(pos); PickedPos_SetAsInvalid(pos);
Vector3_Multiply1(&pos->Intersect, &tracer.Dir, reach); /* intersect = dir * reach */ Vector3_Mul1(&pos->Intersect, &tracer.Dir, reach); /* intersect = dir * reach */
Vector3_Add(&pos->Intersect, &tracer.Origin, &pos->Intersect); /* intersect = origin + dir * reach */ Vector3_Add(&pos->Intersect, &tracer.Origin, &pos->Intersect); /* intersect = origin + dir * reach */
} }
} }

View File

@ -18,11 +18,6 @@ Vector3I Vector3I_Create3(Int32 x, Int32 y, Int32 z) {
Vector3I v; v.X = x; v.Y = y; v.Z = z; return v; Vector3I v; v.X = x; v.Y = y; v.Z = z; return v;
} }
Real32 Vector3_Length(Vector3* v) {
Real32 lenSquared = v->X * v->X + v->Y * v->Y + v->Z * v->Z;
return Math_Sqrt(lenSquared);
}
Real32 Vector3_LengthSquared(Vector3* v) { Real32 Vector3_LengthSquared(Vector3* v) {
return v->X * v->X + v->Y * v->Y + v->Z * v->Z; return v->X * v->X + v->Y * v->Y + v->Z * v->Z;
} }
@ -35,15 +30,15 @@ void Vector3_Add1(Vector3* result, Vector3* a, Real32 b) {
result->X = a->X + b; result->Y = a->Y + b; result->Z = a->Z + b; result->X = a->X + b; result->Y = a->Y + b; result->Z = a->Z + b;
} }
void Vector3_Subtract(Vector3* result, Vector3* a, Vector3* b) { void Vector3_Sub(Vector3* result, Vector3* a, Vector3* b) {
result->X = a->X - b->X; result->Y = a->Y - b->Y; result->Z = a->Z - b->Z; result->X = a->X - b->X; result->Y = a->Y - b->Y; result->Z = a->Z - b->Z;
} }
void Vector3_Multiply1(Vector3* result, Vector3* a, Real32 scale) { void Vector3_Mul1(Vector3* result, Vector3* a, Real32 scale) {
result->X = a->X * scale; result->Y = a->Y * scale; result->Z = a->Z * scale; result->X = a->X * scale; result->Y = a->Y * scale; result->Z = a->Z * scale;
} }
void Vector3_Multiply3(Vector3* result, Vector3* a, Vector3* scale) { void Vector3_Mul3(Vector3* result, Vector3* a, Vector3* scale) {
result->X = a->X * scale->X; result->Y = a->Y * scale->Y; result->Z = a->Z * scale->Z; result->X = a->X * scale->X; result->Y = a->Y * scale->Y; result->Z = a->Z * scale->Z;
} }
@ -70,7 +65,8 @@ void Vector3_Cross(Vector3* result, Vector3* a, Vector3* b) {
} }
void Vector3_Normalize(Vector3* result, Vector3* a) { void Vector3_Normalize(Vector3* result, Vector3* a) {
Real32 scale = 1.0f / Vector3_Length(a); Real32 lenSquared = a->X * a->X + a->Y * a->Y + a->Z * a->Z;
Real32 scale = 1.0f / Math_SqrtF(lenSquared);
result->X = a->X * scale; result->X = a->X * scale;
result->Y = a->Y * scale; result->Y = a->Y * scale;
result->Z = a->Z * scale; result->Z = a->Z * scale;
@ -103,22 +99,22 @@ void Vector3_TransformZ(Vector3* result, Real32 z, Matrix* mat) {
} }
Vector3 Vector3_RotateX(Vector3 v, Real32 angle) { Vector3 Vector3_RotateX(Vector3 v, Real32 angle) {
Real32 cosA = Math_Cos(angle), sinA = Math_Sin(angle); Real32 cosA = Math_CosF(angle), sinA = Math_SinF(angle);
return Vector3_Create3(v.X, cosA * v.Y + sinA * v.Z, -sinA * v.Y + cosA * v.Z); return Vector3_Create3(v.X, cosA * v.Y + sinA * v.Z, -sinA * v.Y + cosA * v.Z);
} }
Vector3 Vector3_RotateY(Vector3 v, Real32 angle) { Vector3 Vector3_RotateY(Vector3 v, Real32 angle) {
Real32 cosA = Math_Cos(angle), sinA = Math_Sin(angle); Real32 cosA = Math_CosF(angle), sinA = Math_SinF(angle);
return Vector3_Create3(cosA * v.X - sinA * v.Z, v.Y, sinA * v.X + cosA * v.Z); return Vector3_Create3(cosA * v.X - sinA * v.Z, v.Y, sinA * v.X + cosA * v.Z);
} }
Vector3 Vector3_RotateY3(Real32 x, Real32 y, Real32 z, Real32 angle) { Vector3 Vector3_RotateY3(Real32 x, Real32 y, Real32 z, Real32 angle) {
Real32 cosA = Math_Cos(angle), sinA = Math_Sin(angle); Real32 cosA = Math_CosF(angle), sinA = Math_SinF(angle);
return Vector3_Create3(cosA * x - sinA * z, y, sinA * x + cosA * z); return Vector3_Create3(cosA * x - sinA * z, y, sinA * x + cosA * z);
} }
Vector3 Vector3_RotateZ(Vector3 v, Real32 angle) { Vector3 Vector3_RotateZ(Vector3 v, Real32 angle) {
Real32 cosA = Math_Cos(angle), sinA = Math_Sin(angle); Real32 cosA = Math_CosF(angle), sinA = Math_SinF(angle);
return Vector3_Create3(cosA * v.X + sinA * v.Y, -sinA * v.X + cosA * v.Y, v.Z); return Vector3_Create3(cosA * v.X + sinA * v.Y, -sinA * v.X + cosA * v.Y, v.Z);
} }
@ -150,15 +146,15 @@ void Vector3I_Max(Vector3I* result, Vector3I* a, Vector3I* b) {
Vector3 Vector3_GetDirVector(Real32 yawRad, Real32 pitchRad) { Vector3 Vector3_GetDirVector(Real32 yawRad, Real32 pitchRad) {
Real32 x = -Math_Cos(pitchRad) * -Math_Sin(yawRad); Real32 x = -Math_CosF(pitchRad) * -Math_SinF(yawRad);
Real32 y = -Math_Sin(pitchRad); Real32 y = -Math_SinF(pitchRad);
Real32 z = -Math_Cos(pitchRad) * Math_Cos(yawRad); Real32 z = -Math_CosF(pitchRad) * Math_CosF(yawRad);
return Vector3_Create3(x, y, z); return Vector3_Create3(x, y, z);
} }
void Vector3_GetHeading(Vector3 dir, Real32* yaw, Real32* pitch) { void Vector3_GetHeading(Vector3 dir, Real32* yaw, Real32* pitch) {
*pitch = Math_Asin(-dir.Y); *pitch = (Real32)Math_Asin(-dir.Y);
*yaw = Math_Atan2(dir.X, -dir.Z); *yaw = (Real32)Math_Atan2(dir.X, -dir.Z);
} }
@ -172,21 +168,21 @@ Matrix Matrix_Identity = {
/* Transposed, source https://open.gl/transformations */ /* Transposed, source https://open.gl/transformations */
void Matrix_RotateX(Matrix* result, Real32 angle) { void Matrix_RotateX(Matrix* result, Real32 angle) {
Real32 cosA = Math_Cos(angle), sinA = Math_Sin(angle); Real32 cosA = Math_CosF(angle), sinA = Math_SinF(angle);
*result = Matrix_Identity; *result = Matrix_Identity;
result->Row1.Y = cosA; result->Row1.Z = sinA; result->Row1.Y = cosA; result->Row1.Z = sinA;
result->Row2.Y = -sinA; result->Row2.Z = cosA; result->Row2.Y = -sinA; result->Row2.Z = cosA;
} }
void Matrix_RotateY(Matrix* result, Real32 angle) { void Matrix_RotateY(Matrix* result, Real32 angle) {
Real32 cosA = Math_Cos(angle), sinA = Math_Sin(angle); Real32 cosA = Math_CosF(angle), sinA = Math_SinF(angle);
*result = Matrix_Identity; *result = Matrix_Identity;
result->Row1.X = cosA; result->Row1.Z = -sinA; result->Row1.X = cosA; result->Row1.Z = -sinA;
result->Row2.X = sinA; result->Row2.Z = cosA; result->Row2.X = sinA; result->Row2.Z = cosA;
} }
void Matrix_RotateZ(Matrix* result, Real32 angle) { void Matrix_RotateZ(Matrix* result, Real32 angle) {
Real32 cosA = Math_Cos(angle), sinA = Math_Sin(angle); Real32 cosA = Math_CosF(angle), sinA = Math_SinF(angle);
*result = Matrix_Identity; *result = Matrix_Identity;
result->Row1.X = cosA; result->Row1.Y = sinA; result->Row1.X = cosA; result->Row1.Y = sinA;
result->Row2.X = -sinA; result->Row2.Y = cosA; result->Row2.X = -sinA; result->Row2.Y = cosA;
@ -254,7 +250,7 @@ void Matrix_OrthographicOffCenter(Matrix* result, Real32 left, Real32 right, Rea
} }
void Matrix_PerspectiveFieldOfView(Matrix* result, Real32 fovy, Real32 aspect, Real32 zNear, Real32 zFar) { void Matrix_PerspectiveFieldOfView(Matrix* result, Real32 fovy, Real32 aspect, Real32 zNear, Real32 zFar) {
Real32 c = zNear * Math_Tan(0.5f * fovy); Real32 c = zNear * Math_TanF(0.5 * fovy);
Matrix_PerspectiveOffCenter(result, -c * aspect, c * aspect, -c, c, zNear, zFar); Matrix_PerspectiveOffCenter(result, -c * aspect, c * aspect, -c, c, zNear, zFar);
} }
@ -275,7 +271,7 @@ void Matrix_PerspectiveOffCenter(Matrix* result, Real32 left, Real32 right, Real
void Matrix_LookAt(Matrix* result, Vector3 eye, Vector3 target, Vector3 up) { void Matrix_LookAt(Matrix* result, Vector3 eye, Vector3 target, Vector3 up) {
/* Transposed, source https://msdn.microsoft.com/en-us/library/windows/desktop/bb281711(v=vs.85).aspx */ /* Transposed, source https://msdn.microsoft.com/en-us/library/windows/desktop/bb281711(v=vs.85).aspx */
Vector3 x, y, z; Vector3 x, y, z;
Vector3_Subtract(&z, &eye, &target); Vector3_Normalize(&z, &z); Vector3_Sub(&z, &eye, &target); Vector3_Normalize(&z, &z);
Vector3_Cross(&x, &up, &z); Vector3_Normalize(&x, &x); Vector3_Cross(&x, &up, &z); Vector3_Normalize(&x, &x);
Vector3_Cross(&y, &z, &x); Vector3_Normalize(&y, &y); Vector3_Cross(&y, &z, &x); Vector3_Normalize(&y, &y);
@ -298,7 +294,7 @@ frustum40, frustum41, frustum42, frustum43;
void FrustumCulling_Normalise(Real32* plane0, Real32* plane1, Real32* plane2, Real32* plane3) { void FrustumCulling_Normalise(Real32* plane0, Real32* plane1, Real32* plane2, Real32* plane3) {
Real32 val1 = *plane0, val2 = *plane1, val3 = *plane2; Real32 val1 = *plane0, val2 = *plane1, val3 = *plane2;
Real32 t = Math_Sqrt(val1 * val1 + val2 * val2 + val3 * val3); Real32 t = Math_SqrtF(val1 * val1 + val2 * val2 + val3 * val3);
*plane0 /= t; *plane1 /= t; *plane2 /= t; *plane3 /= t; *plane0 /= t; *plane1 /= t; *plane2 /= t; *plane3 /= t;
} }

View File

@ -17,10 +17,9 @@ Vector3 Vector3_Create1(Real32 value);
Vector3 Vector3_Create3(Real32 x, Real32 y, Real32 z); Vector3 Vector3_Create3(Real32 x, Real32 y, Real32 z);
Vector3I Vector3I_Create1(Int32 value); Vector3I Vector3I_Create1(Int32 value);
Vector3I Vector3I_Create3(Int32 x, Int32 y, Int32 z); Vector3I Vector3I_Create3(Int32 x, Int32 y, Int32 z);
Real32 Vector3_Length(Vector3* v);
Real32 Vector3_LengthSquared(Vector3* v); Real32 Vector3_LengthSquared(Vector3* v);
#define VECTOR3_CONST1(val) { val, val, val };
#define VECTOR3_CONST(x, y, z) { x, y, z }; #define VECTOR3_CONST(x, y, z) { x, y, z };
#define Vector3_UnitX VECTOR3_CONST(1.0f, 0.0f, 0.0f) #define Vector3_UnitX VECTOR3_CONST(1.0f, 0.0f, 0.0f)
#define Vector3_UnitY VECTOR3_CONST(0.0f, 1.0f, 0.0f) #define Vector3_UnitY VECTOR3_CONST(0.0f, 1.0f, 0.0f)
@ -30,11 +29,16 @@ Real32 Vector3_LengthSquared(Vector3* v);
void Vector3_Add(Vector3* result, Vector3* a, Vector3* b); void Vector3_Add(Vector3* result, Vector3* a, Vector3* b);
void Vector3_Add1(Vector3* result, Vector3* a, Real32 b); void Vector3_Add1(Vector3* result, Vector3* a, Real32 b);
void Vector3_Subtract(Vector3* result, Vector3* a, Vector3* b); void Vector3_Sub(Vector3* result, Vector3* a, Vector3* b);
void Vector3_Multiply1(Vector3* result, Vector3* a, Real32 scale); void Vector3_Mul1(Vector3* result, Vector3* a, Real32 scale);
void Vector3_Multiply3(Vector3* result, Vector3* a, Vector3* scale); void Vector3_Mul3(Vector3* result, Vector3* a, Vector3* scale);
void Vector3_Negate(Vector3* result, Vector3* a); void Vector3_Negate(Vector3* result, Vector3* a);
#define Vector3_AddBy(dst, value) Vector3_Add(dst, dst, value)
#define Vector3_SubBy(dst, value) Vector3_Sub(dst, dst, value)
#define Vector3_Mul1By(dst, value) Vector3_Mul1(dst, dst, value)
#define Vector3_Mul3By(dst, value) Vector3_Mul3(dst, dst, value)
void Vector3_Lerp(Vector3* result, Vector3* a, Vector3* b, Real32 blend); void Vector3_Lerp(Vector3* result, Vector3* a, Vector3* b, Real32 blend);
Real32 Vector3_Dot(Vector3* left, Vector3* right); Real32 Vector3_Dot(Vector3* left, Vector3* right);
void Vector3_Cross(Vector3* result, Vector3* a, Vector3* b); void Vector3_Cross(Vector3* result, Vector3* a, Vector3* b);

View File

@ -735,8 +735,8 @@ void TableWidget_Recreate(GuiElement* elem) {
void TableWidget_Reposition(GuiElement* elem) { void TableWidget_Reposition(GuiElement* elem) {
TableWidget* widget = (TableWidget*)elem; TableWidget* widget = (TableWidget*)elem;
Real32 scale = Game_GetInventoryScale(); Real32 scale = Game_GetInventoryScale();
widget->BlockSize = (Int32)(50 * Math_Sqrt(scale)); widget->BlockSize = (Int32)(50 * Math_SqrtF(scale));
widget->SelBlockExpand = 25.0f * Math_Sqrt(scale); widget->SelBlockExpand = 25.0f * Math_SqrtF(scale);
TableWidget_UpdatePos(widget); TableWidget_UpdatePos(widget);
TableWidget_UpdateScrollbarPos(widget); TableWidget_UpdateScrollbarPos(widget);
} }

View File

@ -208,13 +208,12 @@ void WorldEnv_SetShadowCol(PackedCol col) {
Event_RaiseInt32(&WorldEvents_EnvVarChanged, ENV_VAR_SHADOW_COL); Event_RaiseInt32(&WorldEvents_EnvVarChanged, ENV_VAR_SHADOW_COL);
} }
#define Respawn_NotFound -10000.0f
Real32 Respawn_HighestFreeY(AABB* bb) { Real32 Respawn_HighestFreeY(AABB* bb) {
Int32 minX = Math_Floor(bb->Min.X), maxX = Math_Floor(bb->Max.X); Int32 minX = Math_Floor(bb->Min.X), maxX = Math_Floor(bb->Max.X);
Int32 minY = Math_Floor(bb->Min.Y), maxY = Math_Floor(bb->Max.Y); Int32 minY = Math_Floor(bb->Min.Y), maxY = Math_Floor(bb->Max.Y);
Int32 minZ = Math_Floor(bb->Min.Z), maxZ = Math_Floor(bb->Max.Z); Int32 minZ = Math_Floor(bb->Min.Z), maxZ = Math_Floor(bb->Max.Z);
Real32 spawnY = Respawn_NotFound; Real32 spawnY = RESPAWN_NOT_FOUND;
AABB blockBB; AABB blockBB;
Int32 x, y, z; Int32 x, y, z;
Vector3 pos; Vector3 pos;
@ -248,7 +247,7 @@ Vector3 Respawn_FindSpawnPosition(Real32 x, Real32 z, Vector3 modelSize) {
Int32 y; Int32 y;
for (y = World_Height; y >= 0; y--) { for (y = World_Height; y >= 0; y--) {
Real32 highestY = Respawn_HighestFreeY(&bb); Real32 highestY = Respawn_HighestFreeY(&bb);
if (highestY != Respawn_NotFound) { if (highestY != RESPAWN_NOT_FOUND) {
spawn.Y = highestY; break; spawn.Y = highestY; break;
} }
bb.Min.Y -= 1.0f; bb.Max.Y -= 1.0f; bb.Min.Y -= 1.0f; bb.Max.Y -= 1.0f;

View File

@ -87,9 +87,10 @@ void WorldEnv_SetCloudsCol(PackedCol col);
void WorldEnv_SetSunCol(PackedCol col); void WorldEnv_SetSunCol(PackedCol col);
void WorldEnv_SetShadowCol(PackedCol col); void WorldEnv_SetShadowCol(PackedCol col);
/* Finds the highest free Y coordinate in the given bounding box.*/ #define RESPAWN_NOT_FOUND -100000.0f
/* Finds the highest free Y coordinate in the given bounding box */
Real32 Respawn_HighestFreeY(AABB* bb); Real32 Respawn_HighestFreeY(AABB* bb);
/* Finds a suitable spawn position for the entity, by iterating /* Finds a suitable spawn position for the entity, by iterating
downwards from top of the world until the ground is found. */ downwards from top of the world until the ground is found */
Vector3 Respawn_FindSpawnPosition(Real32 x, Real32 z, Vector3 modelSize); Vector3 Respawn_FindSpawnPosition(Real32 x, Real32 z, Vector3 modelSize);
#endif #endif