add missing funcs to Player, add Velocity and Vectors

This commit is contained in:
sylvessa 2026-03-23 08:03:45 -05:00
parent fac8269fed
commit a5e39efa04
7 changed files with 758 additions and 6 deletions

View file

@ -48,7 +48,7 @@ PROJECT_NAME = FourKit
# could be handy for archiving the generated documentation or if some version # could be handy for archiving the generated documentation or if some version
# control system is used. # control system is used.
PROJECT_NUMBER = 1469f90c PROJECT_NUMBER = fac8269
# Using the PROJECT_BRIEF tag one can provide an optional one line description # Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewers a # for a project that appears at the top of each page and should give viewers a
@ -1554,7 +1554,7 @@ HTML_COLORSTYLE_GAMMA = 80
# The default value is: YES. # The default value is: YES.
# This tag requires that the tag GENERATE_HTML is set to YES. # This tag requires that the tag GENERATE_HTML is set to YES.
HTML_DYNAMIC_MENUS = YES HTML_DYNAMIC_MENUS = NO
# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
# documentation will contain sections that can be hidden and shown after the # documentation will contain sections that can be hidden and shown after the

View file

@ -1,5 +1,7 @@
namespace Minecraft.Server.FourKit.Entity; namespace Minecraft.Server.FourKit.Entity;
using Minecraft.Server.FourKit.Util;
/// <summary> /// <summary>
/// Represents a base entity in the world /// Represents a base entity in the world
/// </summary> /// </summary>
@ -11,6 +13,8 @@ public abstract class Entity
private int _dimensionId; private int _dimensionId;
private int _entityId; private int _entityId;
private EntityType _entityType = EntityType.UNKNOWN; private EntityType _entityType = EntityType.UNKNOWN;
private bool _onGround;
private double _velocityX, _velocityY, _velocityZ;
/// <summary> /// <summary>
/// Gets the entity's current position. /// Gets the entity's current position.
@ -72,6 +76,31 @@ public abstract class Entity
/// <returns>World containing this entity.</returns> /// <returns>World containing this entity.</returns>
public World getWorld() => FourKit.getWorld(_dimensionId); public World getWorld() => FourKit.getWorld(_dimensionId);
/// <summary>
/// Returns true if the entity is supported by a block. This value is a
/// state updated by the server and is not recalculated unless the entity moves.
/// </summary>
/// <returns>True if entity is on ground.</returns>
public bool isOnGround() => _onGround;
/// <summary>
/// Gets this entity's current velocity.
/// </summary>
/// <returns>Current travelling velocity of this entity.</returns>
public Vector getVelocity() => new Vector(_velocityX, _velocityY, _velocityZ);
/// <summary>
/// Sets this entity's velocity.
/// </summary>
/// <param name="velocity">New velocity to travel with.</param>
public void setVelocity(Vector velocity)
{
_velocityX = velocity.getX();
_velocityY = velocity.getY();
_velocityZ = velocity.getZ();
NativeBridge.SetVelocity?.Invoke(getEntityId(), velocity.getX(), velocity.getY(), velocity.getZ());
}
// INTERNAL // INTERNAL
internal void SetLocation(Location location) internal void SetLocation(Location location)
{ {
@ -88,4 +117,11 @@ public abstract class Entity
internal void SetDimensionInternal(int dimensionId) => _dimensionId = dimensionId; internal void SetDimensionInternal(int dimensionId) => _dimensionId = dimensionId;
internal void SetEntityIdInternal(int entityId) => _entityId = entityId; internal void SetEntityIdInternal(int entityId) => _entityId = entityId;
internal void SetEntityTypeInternal(EntityType entityType) => _entityType = entityType; internal void SetEntityTypeInternal(EntityType entityType) => _entityType = entityType;
internal void SetOnGroundInternal(bool onGround) => _onGround = onGround;
internal void SetVelocityInternal(double x, double y, double z)
{
_velocityX = x;
_velocityY = y;
_velocityZ = z;
}
} }

View file

@ -14,6 +14,9 @@ public class Player : HumanEntity, OfflinePlayer, CommandSender
private float _walkSpeed = 0.2f; private float _walkSpeed = 0.2f;
private Guid _playerUniqueId; private Guid _playerUniqueId;
private string? _displayName; private string? _displayName;
private bool _sneaking;
private bool _sprinting;
private bool _allowFlight;
internal bool IsOnline { get; set; } internal bool IsOnline { get; set; }
@ -95,6 +98,36 @@ public class Player : HumanEntity, OfflinePlayer, CommandSender
NativeBridge.SetWalkSpeed?.Invoke(getEntityId(), value); NativeBridge.SetWalkSpeed?.Invoke(getEntityId(), value);
} }
/// <summary>
/// Returns if the player is in sneak mode.
/// </summary>
/// <returns>True if player is in sneak mode.</returns>
public bool isSneaking() => _sneaking;
/// <summary>
/// Gets whether the player is sprinting or not.
/// </summary>
/// <returns>True if player is sprinting.</returns>
public bool isSprinting() => _sprinting;
/// <summary>
/// Determines if the Player is allowed to fly via jump key double-tap
/// like in creative mode.
/// </summary>
/// <returns>True if the player is allowed to fly.</returns>
public bool getAllowFlight() => _allowFlight;
/// <summary>
/// Sets if the Player is allowed to fly via jump key double-tap like
/// in creative mode.
/// </summary>
/// <param name="flight">If flight should be allowed.</param>
public void setAllowFlight(bool flight)
{
_allowFlight = flight;
NativeBridge.SetAllowFlight?.Invoke(getEntityId(), flight ? 1 : 0);
}
/// <inheritdoc/> /// <inheritdoc/>
public void sendMessage(string message) public void sendMessage(string message)
{ {
@ -206,4 +239,7 @@ public class Player : HumanEntity, OfflinePlayer, CommandSender
internal void SetSaturationInternal(float saturation) => _saturation = saturation; internal void SetSaturationInternal(float saturation) => _saturation = saturation;
internal void SetWalkSpeedInternal(float walkSpeed) => _walkSpeed = walkSpeed; internal void SetWalkSpeedInternal(float walkSpeed) => _walkSpeed = walkSpeed;
internal void SetPlayerUniqueIdInternal(Guid id) => _playerUniqueId = id; internal void SetPlayerUniqueIdInternal(Guid id) => _playerUniqueId = id;
internal void SetSneakingInternal(bool sneaking) => _sneaking = sneaking;
internal void SetSprintingInternal(bool sprinting) => _sprinting = sprinting;
internal void SetAllowFlightInternal(bool allowFlight) => _allowFlight = allowFlight;
} }

View file

@ -594,6 +594,21 @@ public static class FourKitHost
} }
} }
[UnmanagedCallersOnly]
public static void SetEntityCallbacks(IntPtr setSneaking, IntPtr setVelocity, IntPtr setAllowFlight)
{
// setsneaking and setallowflight here cuz i am lazy
// should be under player stuff ill do that later
try
{
NativeBridge.SetEntityCallbacks(setSneaking, setVelocity, setAllowFlight);
}
catch (Exception ex)
{
ServerLog.Error("fourkit", $"SetEntityCallbacks error: {ex}");
}
}
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
public static long FirePlayerDropItem(int entityId, int itemId, int itemCount, int itemAux, public static long FirePlayerDropItem(int entityId, int itemId, int itemCount, int itemAux,
IntPtr outItemIdPtr, IntPtr outItemCountPtr, IntPtr outItemAuxPtr) IntPtr outItemIdPtr, IntPtr outItemCountPtr, IntPtr outItemAuxPtr)
@ -948,12 +963,12 @@ public static class FourKitHost
}; };
} }
// double[13] = { x, y, z, health, maxHealth, fallDistance, gameMode, walkSpeed, yaw, pitch, dimension, isSleeping, sleepTimer } // double[20] = { x, y, z, health, maxHealth, fallDistance, gameMode, walkSpeed, yaw, pitch, dimension, isSleeping, sleepTimer, sneaking, sprinting, onGround, velocityX, velocityY, velocityZ, allowFlight }
private static void SyncPlayerFromNative(Player player) private static void SyncPlayerFromNative(Player player)
{ {
if (NativeBridge.GetPlayerSnapshot == null) if (NativeBridge.GetPlayerSnapshot == null)
return; return;
double[] buf = new double[13]; double[] buf = new double[20];
var gh = GCHandle.Alloc(buf, GCHandleType.Pinned); var gh = GCHandle.Alloc(buf, GCHandleType.Pinned);
try try
{ {
@ -974,6 +989,11 @@ public static class FourKitHost
player.SetWalkSpeedInternal((float)buf[7]); player.SetWalkSpeedInternal((float)buf[7]);
player.SetSleepingInternal(buf[11] != 0.0); player.SetSleepingInternal(buf[11] != 0.0);
player.SetSleepTicksInternal((int)buf[12]); player.SetSleepTicksInternal((int)buf[12]);
player.SetSneakingInternal(buf[13] != 0.0);
player.SetSprintingInternal(buf[14] != 0.0);
player.SetOnGroundInternal(buf[15] != 0.0);
player.SetVelocityInternal(buf[16], buf[17], buf[18]);
player.SetAllowFlightInternal(buf[19] != 0.0);
} }
private static void BroadcastNativeMessage(string message) private static void BroadcastNativeMessage(string message)

View file

@ -117,6 +117,15 @@ internal static class NativeBridge
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate void NativeSetHeldItemSlotDelegate(int entityId, int slot); internal delegate void NativeSetHeldItemSlotDelegate(int entityId, int slot);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate void NativeSetSneakingDelegate(int entityId, int sneak);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate void NativeSetVelocityDelegate(int entityId, double x, double y, double z);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate void NativeSetAllowFlightDelegate(int entityId, int allowFlight);
internal static NativeDamageDelegate? DamagePlayer; internal static NativeDamageDelegate? DamagePlayer;
internal static NativeSetHealthDelegate? SetPlayerHealth; internal static NativeSetHealthDelegate? SetPlayerHealth;
@ -156,6 +165,9 @@ internal static class NativeBridge
internal static NativeGetItemMetaDelegate? GetItemMeta; internal static NativeGetItemMetaDelegate? GetItemMeta;
internal static NativeSetItemMetaDelegate? SetItemMeta; internal static NativeSetItemMetaDelegate? SetItemMeta;
internal static NativeSetHeldItemSlotDelegate? SetHeldItemSlot; internal static NativeSetHeldItemSlotDelegate? SetHeldItemSlot;
internal static NativeSetSneakingDelegate? SetSneaking;
internal static NativeSetVelocityDelegate? SetVelocity;
internal static NativeSetAllowFlightDelegate? SetAllowFlight;
internal static void SetCallbacks(IntPtr damage, IntPtr setHealth, IntPtr teleport, IntPtr setGameMode, IntPtr broadcastMessage, IntPtr setFallDistance, IntPtr getPlayerSnapshot, IntPtr sendMessage, IntPtr setWalkSpeed, IntPtr teleportEntity) internal static void SetCallbacks(IntPtr damage, IntPtr setHealth, IntPtr teleport, IntPtr setGameMode, IntPtr broadcastMessage, IntPtr setFallDistance, IntPtr getPlayerSnapshot, IntPtr sendMessage, IntPtr setWalkSpeed, IntPtr teleportEntity)
{ {
@ -209,4 +221,11 @@ internal static class NativeBridge
SetItemMeta = Marshal.GetDelegateForFunctionPointer<NativeSetItemMetaDelegate>(setItemMeta); SetItemMeta = Marshal.GetDelegateForFunctionPointer<NativeSetItemMetaDelegate>(setItemMeta);
SetHeldItemSlot = Marshal.GetDelegateForFunctionPointer<NativeSetHeldItemSlotDelegate>(setHeldItemSlot); SetHeldItemSlot = Marshal.GetDelegateForFunctionPointer<NativeSetHeldItemSlotDelegate>(setHeldItemSlot);
} }
internal static void SetEntityCallbacks(IntPtr setSneaking, IntPtr setVelocity, IntPtr setAllowFlight)
{
SetSneaking = Marshal.GetDelegateForFunctionPointer<NativeSetSneakingDelegate>(setSneaking);
SetVelocity = Marshal.GetDelegateForFunctionPointer<NativeSetVelocityDelegate>(setVelocity);
SetAllowFlight = Marshal.GetDelegateForFunctionPointer<NativeSetAllowFlightDelegate>(setAllowFlight);
}
} }

View file

@ -0,0 +1,579 @@
namespace Minecraft.Server.FourKit.Util;
/// <summary>
/// Represents a mutable vector. Because the components of Vectors are mutable,
/// storing Vectors long term may be dangerous if passing code modifies the
/// Vector later. If you want to keep around a Vector, it may be wise to call
/// <see cref="clone"/> in order to get a copy.
/// </summary>
public class Vector
{
private static readonly double EPSILON = 0.000001;
private static readonly Random _random = new();
protected double x;
protected double y;
protected double z;
public Vector()
{
x = 0;
y = 0;
z = 0;
}
/// <summary>
/// Construct the vector with provided integer components.
/// </summary>
/// <param name="x">X component.</param>
/// <param name="y">Y component.</param>
/// <param name="z">Z component.</param>
public Vector(int x, int y, int z)
{
this.x = x;
this.y = y;
this.z = z;
}
/// <summary>
/// Construct the vector with provided double components.
/// </summary>
/// <param name="x">X component.</param>
/// <param name="y">Y component.</param>
/// <param name="z">Z component.</param>
public Vector(double x, double y, double z)
{
this.x = x;
this.y = y;
this.z = z;
}
/// <summary>
/// Construct the vector with provided float components.
/// </summary>
/// <param name="x">X component.</param>
/// <param name="y">Y component.</param>
/// <param name="z">Z component.</param>
public Vector(float x, float y, float z)
{
this.x = x;
this.y = y;
this.z = z;
}
/// <summary>
/// Adds a vector to this one.
/// </summary>
/// <param name="vec">The other vector.</param>
/// <returns>The same vector.</returns>
public Vector add(Vector vec)
{
x += vec.x;
y += vec.y;
z += vec.z;
return this;
}
/// <summary>
/// Subtracts a vector from this one.
/// </summary>
/// <param name="vec">The other vector.</param>
/// <returns>The same vector.</returns>
public Vector subtract(Vector vec)
{
x -= vec.x;
y -= vec.y;
z -= vec.z;
return this;
}
/// <summary>
/// Multiplies the vector by another.
/// </summary>
/// <param name="vec">The other vector.</param>
/// <returns>The same vector.</returns>
public Vector multiply(Vector vec)
{
x *= vec.x;
y *= vec.y;
z *= vec.z;
return this;
}
/// <summary>
/// Divides the vector by another.
/// </summary>
/// <param name="vec">The other vector.</param>
/// <returns>The same vector.</returns>
public Vector divide(Vector vec)
{
x /= vec.x;
y /= vec.y;
z /= vec.z;
return this;
}
/// <summary>
/// Copies another vector.
/// </summary>
/// <param name="vec">The other vector.</param>
/// <returns>The same vector.</returns>
public Vector copy(Vector vec)
{
x = vec.x;
y = vec.y;
z = vec.z;
return this;
}
/// <summary>
/// Gets the magnitude of the vector, defined as sqrt(x^2+y^2+z^2).
/// The value of this method is not cached and uses a costly square-root
/// function, so do not repeatedly call this method to get the vector's
/// magnitude. NaN will be returned if the inner result of the sqrt()
/// function overflows, which will be caused if the length is too long.
/// </summary>
/// <returns>The magnitude.</returns>
public double length()
{
return Math.Sqrt(x * x + y * y + z * z);
}
/// <summary>
/// Gets the magnitude of the vector squared.
/// </summary>
/// <returns>The magnitude squared.</returns>
public double lengthSquared()
{
return x * x + y * y + z * z;
}
/// <summary>
/// Get the distance between this vector and another. The value of this
/// method is not cached and uses a costly square-root function, so do not
/// repeatedly call this method to get the vector's magnitude. NaN will be
/// returned if the inner result of the sqrt() function overflows, which
/// will be caused if the distance is too long.
/// </summary>
/// <param name="o">The other vector.</param>
/// <returns>The distance.</returns>
public double distance(Vector o)
{
return Math.Sqrt(distanceSquared(o));
}
/// <summary>
/// Get the squared distance between this vector and another.
/// </summary>
/// <param name="o">The other vector.</param>
/// <returns>The distance squared.</returns>
public double distanceSquared(Vector o)
{
double dx = x - o.x;
double dy = y - o.y;
double dz = z - o.z;
return dx * dx + dy * dy + dz * dz;
}
/// <summary>
/// Gets the angle between this vector and another in radians.
/// </summary>
/// <param name="other">The other vector.</param>
/// <returns>Angle in radians.</returns>
public float angle(Vector other)
{
double dot = this.dot(other) / (length() * other.length());
return (float)Math.Acos(dot);
}
/// <summary>
/// Sets this vector to the midpoint between this vector and another.
/// </summary>
/// <param name="other">The other vector.</param>
/// <returns>This same vector (now a midpoint).</returns>
public Vector midpoint(Vector other)
{
x = (x + other.x) / 2.0;
y = (y + other.y) / 2.0;
z = (z + other.z) / 2.0;
return this;
}
/// <summary>
/// Gets a new midpoint vector between this vector and another.
/// </summary>
/// <param name="other">The other vector.</param>
/// <returns>A new midpoint vector.</returns>
public Vector getMidpoint(Vector other)
{
double mx = (x + other.x) / 2.0;
double my = (y + other.y) / 2.0;
double mz = (z + other.z) / 2.0;
return new Vector(mx, my, mz);
}
/// <summary>
/// Performs scalar multiplication, multiplying all components with a scalar.
/// </summary>
/// <param name="m">The factor.</param>
/// <returns>The same vector.</returns>
public Vector multiply(int m)
{
x *= m;
y *= m;
z *= m;
return this;
}
/// <summary>
/// Performs scalar multiplication, multiplying all components with a scalar.
/// </summary>
/// <param name="m">The factor.</param>
/// <returns>The same vector.</returns>
public Vector multiply(double m)
{
x *= m;
y *= m;
z *= m;
return this;
}
/// <summary>
/// Performs scalar multiplication, multiplying all components with a scalar.
/// </summary>
/// <param name="m">The factor.</param>
/// <returns>The same vector.</returns>
public Vector multiply(float m)
{
x *= m;
y *= m;
z *= m;
return this;
}
/// <summary>
/// Calculates the dot product of this vector with another. The dot product
/// is defined as x1*x2+y1*y2+z1*z2. The returned value is a scalar.
/// </summary>
/// <param name="other">The other vector.</param>
/// <returns>Dot product.</returns>
public double dot(Vector other)
{
return x * other.x + y * other.y + z * other.z;
}
/// <summary>
/// Calculates the cross product of this vector with another.
/// The cross product is defined as:
/// <code>
/// x = y1 * z2 - y2 * z1
/// y = z1 * x2 - z2 * x1
/// z = x1 * y2 - x2 * y1
/// </code>
/// </summary>
/// <param name="o">The other vector.</param>
/// <returns>The same vector.</returns>
public Vector crossProduct(Vector o)
{
double newX = y * o.z - o.y * z;
double newY = z * o.x - o.z * x;
double newZ = x * o.y - o.x * y;
x = newX;
y = newY;
z = newZ;
return this;
}
/// <summary>
/// Converts this vector to a unit vector (a vector with length of 1).
/// </summary>
/// <returns>The same vector.</returns>
public Vector normalize()
{
double mag = length();
x /= mag;
y /= mag;
z /= mag;
return this;
}
/// <summary>
/// Zero this vector's components.
/// </summary>
/// <returns>The same vector.</returns>
public Vector zero()
{
x = 0;
y = 0;
z = 0;
return this;
}
/// <summary>
/// Returns whether this vector is in an axis-aligned bounding box.
/// The minimum and maximum vectors given must be truly the minimum and
/// maximum X, Y and Z components.
/// </summary>
/// <param name="min">Minimum vector.</param>
/// <param name="max">Maximum vector.</param>
/// <returns>Whether this vector is in the AABB.</returns>
public bool isInAABB(Vector min, Vector max)
{
return x >= min.x && x <= max.x &&
y >= min.y && y <= max.y &&
z >= min.z && z <= max.z;
}
/// <summary>
/// Returns whether this vector is within a sphere.
/// </summary>
/// <param name="origin">Sphere origin.</param>
/// <param name="radius">Sphere radius.</param>
/// <returns>Whether this vector is in the sphere.</returns>
public bool isInSphere(Vector origin, double radius)
{
return distanceSquared(origin) <= radius * radius;
}
/// <summary>
/// Gets the X component.
/// </summary>
/// <returns>The X component.</returns>
public double getX()
{
return x;
}
/// <summary>
/// Gets the floored value of the X component, indicating the block that
/// this vector is contained with.
/// </summary>
/// <returns>Block X.</returns>
public int getBlockX()
{
return (int)Math.Floor(x);
}
/// <summary>
/// Gets the Y component.
/// </summary>
/// <returns>The Y component.</returns>
public double getY()
{
return y;
}
/// <summary>
/// Gets the floored value of the Y component, indicating the block that
/// this vector is contained with.
/// </summary>
/// <returns>Block Y.</returns>
public int getBlockY()
{
return (int)Math.Floor(y);
}
/// <summary>
/// Gets the Z component.
/// </summary>
/// <returns>The Z component.</returns>
public double getZ()
{
return z;
}
/// <summary>
/// Gets the floored value of the Z component, indicating the block that
/// this vector is contained with.
/// </summary>
/// <returns>Block Z.</returns>
public int getBlockZ()
{
return (int)Math.Floor(z);
}
/// <summary>
/// Set the X component.
/// </summary>
/// <param name="x">The new X component.</param>
/// <returns>This vector.</returns>
public Vector setX(int x)
{
this.x = x;
return this;
}
/// <summary>
/// Set the X component.
/// </summary>
/// <param name="x">The new X component.</param>
/// <returns>This vector.</returns>
public Vector setX(double x)
{
this.x = x;
return this;
}
/// <summary>
/// Set the X component.
/// </summary>
/// <param name="x">The new X component.</param>
/// <returns>This vector.</returns>
public Vector setX(float x)
{
this.x = x;
return this;
}
/// <summary>
/// Set the Y component.
/// </summary>
/// <param name="y">The new Y component.</param>
/// <returns>This vector.</returns>
public Vector setY(int y)
{
this.y = y;
return this;
}
/// <summary>
/// Set the Y component.
/// </summary>
/// <param name="y">The new Y component.</param>
/// <returns>This vector.</returns>
public Vector setY(double y)
{
this.y = y;
return this;
}
/// <summary>
/// Set the Y component.
/// </summary>
/// <param name="y">The new Y component.</param>
/// <returns>This vector.</returns>
public Vector setY(float y)
{
this.y = y;
return this;
}
/// <summary>
/// Set the Z component.
/// </summary>
/// <param name="z">The new Z component.</param>
/// <returns>This vector.</returns>
public Vector setZ(int z)
{
this.z = z;
return this;
}
/// <summary>
/// Set the Z component.
/// </summary>
/// <param name="z">The new Z component.</param>
/// <returns>This vector.</returns>
public Vector setZ(double z)
{
this.z = z;
return this;
}
/// <summary>
/// Set the Z component.
/// </summary>
/// <param name="z">The new Z component.</param>
/// <returns>This vector.</returns>
public Vector setZ(float z)
{
this.z = z;
return this;
}
/// <summary>
/// Get a new vector.
/// </summary>
/// <returns>A clone of this vector.</returns>
public Vector clone()
{
return new Vector(x, y, z);
}
/// <summary>
/// Gets a Location version of this vector with yaw and pitch being 0.
/// </summary>
/// <param name="world">The world to link the location to.</param>
/// <returns>The location.</returns>
public Location toLocation(World world)
{
return new Location(world, x, y, z);
}
/// <summary>
/// Gets a Location version of this vector.
/// </summary>
/// <param name="world">The world to link the location to.</param>
/// <param name="yaw">The desired yaw.</param>
/// <param name="pitch">The desired pitch.</param>
/// <returns>The location.</returns>
public Location toLocation(World world, float yaw, float pitch)
{
return new Location(world, x, y, z, yaw, pitch);
}
/// <summary>
/// Get the threshold used for equals().
/// </summary>
/// <returns>The epsilon.</returns>
public static double getEpsilon()
{
return EPSILON;
}
/// <summary>
/// Gets the minimum components of two vectors.
/// </summary>
/// <param name="v1">The first vector.</param>
/// <param name="v2">The second vector.</param>
/// <returns>Minimum.</returns>
public static Vector getMinimum(Vector v1, Vector v2)
{
return new Vector(Math.Min(v1.x, v2.x), Math.Min(v1.y, v2.y), Math.Min(v1.z, v2.z));
}
/// <summary>
/// Gets the maximum components of two vectors.
/// </summary>
/// <param name="v1">The first vector.</param>
/// <param name="v2">The second vector.</param>
/// <returns>Maximum.</returns>
public static Vector getMaximum(Vector v1, Vector v2)
{
return new Vector(Math.Max(v1.x, v2.x), Math.Max(v1.y, v2.y), Math.Max(v1.z, v2.z));
}
/// <summary>
/// Gets a random vector with components having a random value between 0 and 1.
/// </summary>
/// <returns>A random vector.</returns>
public static Vector getRandom()
{
return new Vector(_random.NextDouble(), _random.NextDouble(), _random.NextDouble());
}
/// <inheritdoc/>
public override bool Equals(object? obj)
{
if (obj is not Vector other) return false;
return Math.Abs(x - other.x) < EPSILON &&
Math.Abs(y - other.y) < EPSILON &&
Math.Abs(z - other.z) < EPSILON;
}
/// <inheritdoc/>
public override string ToString()
{
return $"{x},{y},{z}";
}
}

View file

@ -175,6 +175,7 @@ typedef int(__stdcall *fn_fire_inventory_click)(int entityId,
const char *titleUtf8, int titleByteLen); const char *titleUtf8, int titleByteLen);
typedef int(__stdcall *fn_fire_bed_enter)(int entityId, int dimId, int bedX, int bedY, int bedZ); typedef int(__stdcall *fn_fire_bed_enter)(int entityId, int dimId, int bedX, int bedY, int bedZ);
typedef void(__stdcall *fn_fire_bed_leave)(int entityId, int dimId, int bedX, int bedY, int bedZ); typedef void(__stdcall *fn_fire_bed_leave)(int entityId, int dimId, int bedX, int bedY, int bedZ);
typedef void(__stdcall *fn_set_entity_callbacks)(void *setSneaking, void *setVelocity, void *setAllowFlight);
struct OpenContainerInfo struct OpenContainerInfo
{ {
@ -215,6 +216,7 @@ static fn_fire_player_portal s_managedFirePlayerPortal = nullptr;
static fn_fire_inventory_click s_managedFireInventoryClick = nullptr; static fn_fire_inventory_click s_managedFireInventoryClick = nullptr;
static fn_fire_bed_enter s_managedFireBedEnter = nullptr; static fn_fire_bed_enter s_managedFireBedEnter = nullptr;
static fn_fire_bed_leave s_managedFireBedLeave = nullptr; static fn_fire_bed_leave s_managedFireBedLeave = nullptr;
static fn_set_entity_callbacks s_managedSetEntityCallbacks = nullptr;
static bool s_initialized = false; static bool s_initialized = false;
@ -326,13 +328,13 @@ static void __cdecl NativeSetFallDistance(int entityId, float distance)
} }
} }
// double[13] = { x, y, z, health, maxHealth, fallDistance, gameMode, walkSpeed, yaw, pitch, dimension, isSleeping, sleepTimer } // double[20] = { x, y, z, health, maxHealth, fallDistance, gameMode, walkSpeed, yaw, pitch, dimension, isSleeping, sleepTimer, sneaking, sprinting, onGround, velocityX, velocityY, velocityZ, allowFlight }
static void __cdecl NativeGetPlayerSnapshot(int entityId, double *outData) static void __cdecl NativeGetPlayerSnapshot(int entityId, double *outData)
{ {
auto player = FindPlayer(entityId); auto player = FindPlayer(entityId);
if (!player) if (!player)
{ {
memset(outData, 0, 13 * sizeof(double)); memset(outData, 0, 20 * sizeof(double));
outData[3] = 20.0; outData[3] = 20.0;
outData[4] = 20.0; outData[4] = 20.0;
outData[7] = 0.1; outData[7] = 0.1;
@ -352,6 +354,13 @@ static void __cdecl NativeGetPlayerSnapshot(int entityId, double *outData)
outData[10] = (double)player->dimension; outData[10] = (double)player->dimension;
outData[11] = player->isSleeping() ? 1.0 : 0.0; outData[11] = player->isSleeping() ? 1.0 : 0.0;
outData[12] = (double)player->getSleepTimer(); outData[12] = (double)player->getSleepTimer();
outData[13] = player->isSneaking() ? 1.0 : 0.0;
outData[14] = player->isSprinting() ? 1.0 : 0.0;
outData[15] = player->onGround ? 1.0 : 0.0;
outData[16] = player->xd;
outData[17] = player->yd;
outData[18] = player->zd;
outData[19] = player->abilities.mayfly ? 1.0 : 0.0;
} }
static void __cdecl NativeBroadcastMessage(const char *utf8, int len) static void __cdecl NativeBroadcastMessage(const char *utf8, int len)
@ -1276,6 +1285,53 @@ static void __cdecl NativeSetHeldItemSlot(int entityId, int slot)
player->connection->queueSend(std::make_shared<SetCarriedItemPacket>(slot)); player->connection->queueSend(std::make_shared<SetCarriedItemPacket>(slot));
} }
static void __cdecl NativeSetSneaking(int entityId, int sneak)
{
auto player = FindPlayer(entityId);
if (player)
{
player->setSneaking(sneak != 0);
}
}
static void __cdecl NativeSetVelocity(int entityId, double x, double y, double z)
{
auto player = FindPlayer(entityId);
if (player)
{
player->xd = x;
player->yd = y;
player->zd = z;
player->hurtMarked = true;
return;
}
auto entity = FindEntity(entityId);
if (entity)
{
entity->xd = x;
entity->yd = y;
entity->zd = z;
entity->hurtMarked = true;
}
}
static void __cdecl NativeSetAllowFlight(int entityId, int allowFlight)
{
auto player = FindPlayer(entityId);
if (player)
{
player->abilities.mayfly = (allowFlight != 0);
if (!player->abilities.mayfly)
{
player->abilities.flying = false;
}
if (player->connection)
{
player->connection->send(std::make_shared<PlayerAbilitiesPacket>(&player->abilities));
}
}
}
static std::wstring FindNet10SystemRoot() static std::wstring FindNet10SystemRoot()
{ {
// overengineered // overengineered
@ -1518,6 +1574,7 @@ void Initialize()
ok = ok && GetManagedEntryPoint(loadAssembly, assemblyPath.c_str(), typeName, L"FireInventoryClick", (void **)&s_managedFireInventoryClick); ok = ok && GetManagedEntryPoint(loadAssembly, assemblyPath.c_str(), typeName, L"FireInventoryClick", (void **)&s_managedFireInventoryClick);
ok = ok && GetManagedEntryPoint(loadAssembly, assemblyPath.c_str(), typeName, L"FireBedEnter", (void **)&s_managedFireBedEnter); ok = ok && GetManagedEntryPoint(loadAssembly, assemblyPath.c_str(), typeName, L"FireBedEnter", (void **)&s_managedFireBedEnter);
ok = ok && GetManagedEntryPoint(loadAssembly, assemblyPath.c_str(), typeName, L"FireBedLeave", (void **)&s_managedFireBedLeave); ok = ok && GetManagedEntryPoint(loadAssembly, assemblyPath.c_str(), typeName, L"FireBedLeave", (void **)&s_managedFireBedLeave);
ok = ok && GetManagedEntryPoint(loadAssembly, assemblyPath.c_str(), typeName, L"SetEntityCallbacks", (void **)&s_managedSetEntityCallbacks);
if (!ok) if (!ok)
{ {
@ -1574,6 +1631,11 @@ void Initialize()
(void *)&NativeSetItemMeta, (void *)&NativeSetItemMeta,
(void *)&NativeSetHeldItemSlot); (void *)&NativeSetHeldItemSlot);
s_managedSetEntityCallbacks(
(void *)&NativeSetSneaking,
(void *)&NativeSetVelocity,
(void *)&NativeSetAllowFlight);
LogInfo("fourkit", "FourKit initialized successfully."); LogInfo("fourkit", "FourKit initialized successfully.");
} }