From a5e39efa049300e6d24544f76f4677299fded17a Mon Sep 17 00:00:00 2001 From: sylvessa <225480449+sylvessa@users.noreply.github.com> Date: Mon, 23 Mar 2026 08:03:45 -0500 Subject: [PATCH] add missing funcs to Player, add Velocity and Vectors --- Doxyfile | 4 +- Minecraft.Server.FourKit/Entity/Entity.cs | 36 ++ Minecraft.Server.FourKit/Entity/Player.cs | 36 ++ Minecraft.Server.FourKit/FourKitHost.cs | 24 +- Minecraft.Server.FourKit/NativeBridge.cs | 19 + Minecraft.Server.FourKit/Util/Vector.cs | 579 ++++++++++++++++++++++ Minecraft.Server/FourKitBridge.cpp | 66 ++- 7 files changed, 758 insertions(+), 6 deletions(-) create mode 100644 Minecraft.Server.FourKit/Util/Vector.cs diff --git a/Doxyfile b/Doxyfile index 960ebdafc..8e51d2101 100644 --- a/Doxyfile +++ b/Doxyfile @@ -48,7 +48,7 @@ PROJECT_NAME = FourKit # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 1469f90c +PROJECT_NUMBER = fac8269 # 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 @@ -1554,7 +1554,7 @@ HTML_COLORSTYLE_GAMMA = 80 # The default value is: 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 # documentation will contain sections that can be hidden and shown after the diff --git a/Minecraft.Server.FourKit/Entity/Entity.cs b/Minecraft.Server.FourKit/Entity/Entity.cs index 68ba258f1..586194496 100644 --- a/Minecraft.Server.FourKit/Entity/Entity.cs +++ b/Minecraft.Server.FourKit/Entity/Entity.cs @@ -1,5 +1,7 @@ namespace Minecraft.Server.FourKit.Entity; +using Minecraft.Server.FourKit.Util; + /// /// Represents a base entity in the world /// @@ -11,6 +13,8 @@ public abstract class Entity private int _dimensionId; private int _entityId; private EntityType _entityType = EntityType.UNKNOWN; + private bool _onGround; + private double _velocityX, _velocityY, _velocityZ; /// /// Gets the entity's current position. @@ -72,6 +76,31 @@ public abstract class Entity /// World containing this entity. public World getWorld() => FourKit.getWorld(_dimensionId); + /// + /// 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. + /// + /// True if entity is on ground. + public bool isOnGround() => _onGround; + + /// + /// Gets this entity's current velocity. + /// + /// Current travelling velocity of this entity. + public Vector getVelocity() => new Vector(_velocityX, _velocityY, _velocityZ); + + /// + /// Sets this entity's velocity. + /// + /// New velocity to travel with. + 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 void SetLocation(Location location) { @@ -88,4 +117,11 @@ public abstract class Entity internal void SetDimensionInternal(int dimensionId) => _dimensionId = dimensionId; internal void SetEntityIdInternal(int entityId) => _entityId = entityId; 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; + } } diff --git a/Minecraft.Server.FourKit/Entity/Player.cs b/Minecraft.Server.FourKit/Entity/Player.cs index 70f8670ff..c908f5fd1 100644 --- a/Minecraft.Server.FourKit/Entity/Player.cs +++ b/Minecraft.Server.FourKit/Entity/Player.cs @@ -14,6 +14,9 @@ public class Player : HumanEntity, OfflinePlayer, CommandSender private float _walkSpeed = 0.2f; private Guid _playerUniqueId; private string? _displayName; + private bool _sneaking; + private bool _sprinting; + private bool _allowFlight; internal bool IsOnline { get; set; } @@ -95,6 +98,36 @@ public class Player : HumanEntity, OfflinePlayer, CommandSender NativeBridge.SetWalkSpeed?.Invoke(getEntityId(), value); } + /// + /// Returns if the player is in sneak mode. + /// + /// True if player is in sneak mode. + public bool isSneaking() => _sneaking; + + /// + /// Gets whether the player is sprinting or not. + /// + /// True if player is sprinting. + public bool isSprinting() => _sprinting; + + /// + /// Determines if the Player is allowed to fly via jump key double-tap + /// like in creative mode. + /// + /// True if the player is allowed to fly. + public bool getAllowFlight() => _allowFlight; + + /// + /// Sets if the Player is allowed to fly via jump key double-tap like + /// in creative mode. + /// + /// If flight should be allowed. + public void setAllowFlight(bool flight) + { + _allowFlight = flight; + NativeBridge.SetAllowFlight?.Invoke(getEntityId(), flight ? 1 : 0); + } + /// public void sendMessage(string message) { @@ -206,4 +239,7 @@ public class Player : HumanEntity, OfflinePlayer, CommandSender internal void SetSaturationInternal(float saturation) => _saturation = saturation; internal void SetWalkSpeedInternal(float walkSpeed) => _walkSpeed = walkSpeed; 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; } diff --git a/Minecraft.Server.FourKit/FourKitHost.cs b/Minecraft.Server.FourKit/FourKitHost.cs index 7a4e48771..5d0776b39 100644 --- a/Minecraft.Server.FourKit/FourKitHost.cs +++ b/Minecraft.Server.FourKit/FourKitHost.cs @@ -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] public static long FirePlayerDropItem(int entityId, int itemId, int itemCount, int itemAux, 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) { if (NativeBridge.GetPlayerSnapshot == null) return; - double[] buf = new double[13]; + double[] buf = new double[20]; var gh = GCHandle.Alloc(buf, GCHandleType.Pinned); try { @@ -974,6 +989,11 @@ public static class FourKitHost player.SetWalkSpeedInternal((float)buf[7]); player.SetSleepingInternal(buf[11] != 0.0); 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) diff --git a/Minecraft.Server.FourKit/NativeBridge.cs b/Minecraft.Server.FourKit/NativeBridge.cs index ddad6c2f8..83e35988e 100644 --- a/Minecraft.Server.FourKit/NativeBridge.cs +++ b/Minecraft.Server.FourKit/NativeBridge.cs @@ -117,6 +117,15 @@ internal static class NativeBridge [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 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 NativeSetHealthDelegate? SetPlayerHealth; @@ -156,6 +165,9 @@ internal static class NativeBridge internal static NativeGetItemMetaDelegate? GetItemMeta; internal static NativeSetItemMetaDelegate? SetItemMeta; 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) { @@ -209,4 +221,11 @@ internal static class NativeBridge SetItemMeta = Marshal.GetDelegateForFunctionPointer(setItemMeta); SetHeldItemSlot = Marshal.GetDelegateForFunctionPointer(setHeldItemSlot); } + + internal static void SetEntityCallbacks(IntPtr setSneaking, IntPtr setVelocity, IntPtr setAllowFlight) + { + SetSneaking = Marshal.GetDelegateForFunctionPointer(setSneaking); + SetVelocity = Marshal.GetDelegateForFunctionPointer(setVelocity); + SetAllowFlight = Marshal.GetDelegateForFunctionPointer(setAllowFlight); + } } diff --git a/Minecraft.Server.FourKit/Util/Vector.cs b/Minecraft.Server.FourKit/Util/Vector.cs new file mode 100644 index 000000000..e6778f5e6 --- /dev/null +++ b/Minecraft.Server.FourKit/Util/Vector.cs @@ -0,0 +1,579 @@ +namespace Minecraft.Server.FourKit.Util; + +/// +/// 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 +/// in order to get a copy. +/// +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; + } + + /// + /// Construct the vector with provided integer components. + /// + /// X component. + /// Y component. + /// Z component. + public Vector(int x, int y, int z) + { + this.x = x; + this.y = y; + this.z = z; + } + + /// + /// Construct the vector with provided double components. + /// + /// X component. + /// Y component. + /// Z component. + public Vector(double x, double y, double z) + { + this.x = x; + this.y = y; + this.z = z; + } + + /// + /// Construct the vector with provided float components. + /// + /// X component. + /// Y component. + /// Z component. + public Vector(float x, float y, float z) + { + this.x = x; + this.y = y; + this.z = z; + } + + /// + /// Adds a vector to this one. + /// + /// The other vector. + /// The same vector. + public Vector add(Vector vec) + { + x += vec.x; + y += vec.y; + z += vec.z; + return this; + } + + /// + /// Subtracts a vector from this one. + /// + /// The other vector. + /// The same vector. + public Vector subtract(Vector vec) + { + x -= vec.x; + y -= vec.y; + z -= vec.z; + return this; + } + + /// + /// Multiplies the vector by another. + /// + /// The other vector. + /// The same vector. + public Vector multiply(Vector vec) + { + x *= vec.x; + y *= vec.y; + z *= vec.z; + return this; + } + + /// + /// Divides the vector by another. + /// + /// The other vector. + /// The same vector. + public Vector divide(Vector vec) + { + x /= vec.x; + y /= vec.y; + z /= vec.z; + return this; + } + + /// + /// Copies another vector. + /// + /// The other vector. + /// The same vector. + public Vector copy(Vector vec) + { + x = vec.x; + y = vec.y; + z = vec.z; + return this; + } + + /// + /// 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. + /// + /// The magnitude. + public double length() + { + return Math.Sqrt(x * x + y * y + z * z); + } + + /// + /// Gets the magnitude of the vector squared. + /// + /// The magnitude squared. + public double lengthSquared() + { + return x * x + y * y + z * z; + } + + /// + /// 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. + /// + /// The other vector. + /// The distance. + public double distance(Vector o) + { + return Math.Sqrt(distanceSquared(o)); + } + + /// + /// Get the squared distance between this vector and another. + /// + /// The other vector. + /// The distance squared. + 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; + } + + /// + /// Gets the angle between this vector and another in radians. + /// + /// The other vector. + /// Angle in radians. + public float angle(Vector other) + { + double dot = this.dot(other) / (length() * other.length()); + return (float)Math.Acos(dot); + } + + /// + /// Sets this vector to the midpoint between this vector and another. + /// + /// The other vector. + /// This same vector (now a midpoint). + 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; + } + + /// + /// Gets a new midpoint vector between this vector and another. + /// + /// The other vector. + /// A new midpoint vector. + 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); + } + + /// + /// Performs scalar multiplication, multiplying all components with a scalar. + /// + /// The factor. + /// The same vector. + public Vector multiply(int m) + { + x *= m; + y *= m; + z *= m; + return this; + } + + /// + /// Performs scalar multiplication, multiplying all components with a scalar. + /// + /// The factor. + /// The same vector. + public Vector multiply(double m) + { + x *= m; + y *= m; + z *= m; + return this; + } + + /// + /// Performs scalar multiplication, multiplying all components with a scalar. + /// + /// The factor. + /// The same vector. + public Vector multiply(float m) + { + x *= m; + y *= m; + z *= m; + return this; + } + + /// + /// 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. + /// + /// The other vector. + /// Dot product. + public double dot(Vector other) + { + return x * other.x + y * other.y + z * other.z; + } + + /// + /// Calculates the cross product of this vector with another. + /// The cross product is defined as: + /// + /// x = y1 * z2 - y2 * z1 + /// y = z1 * x2 - z2 * x1 + /// z = x1 * y2 - x2 * y1 + /// + /// + /// The other vector. + /// The same vector. + 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; + } + + /// + /// Converts this vector to a unit vector (a vector with length of 1). + /// + /// The same vector. + public Vector normalize() + { + double mag = length(); + x /= mag; + y /= mag; + z /= mag; + return this; + } + + /// + /// Zero this vector's components. + /// + /// The same vector. + public Vector zero() + { + x = 0; + y = 0; + z = 0; + return this; + } + + /// + /// 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. + /// + /// Minimum vector. + /// Maximum vector. + /// Whether this vector is in the AABB. + 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; + } + + /// + /// Returns whether this vector is within a sphere. + /// + /// Sphere origin. + /// Sphere radius. + /// Whether this vector is in the sphere. + public bool isInSphere(Vector origin, double radius) + { + return distanceSquared(origin) <= radius * radius; + } + + /// + /// Gets the X component. + /// + /// The X component. + public double getX() + { + return x; + } + + /// + /// Gets the floored value of the X component, indicating the block that + /// this vector is contained with. + /// + /// Block X. + public int getBlockX() + { + return (int)Math.Floor(x); + } + + /// + /// Gets the Y component. + /// + /// The Y component. + public double getY() + { + return y; + } + + /// + /// Gets the floored value of the Y component, indicating the block that + /// this vector is contained with. + /// + /// Block Y. + public int getBlockY() + { + return (int)Math.Floor(y); + } + + /// + /// Gets the Z component. + /// + /// The Z component. + public double getZ() + { + return z; + } + + /// + /// Gets the floored value of the Z component, indicating the block that + /// this vector is contained with. + /// + /// Block Z. + public int getBlockZ() + { + return (int)Math.Floor(z); + } + + /// + /// Set the X component. + /// + /// The new X component. + /// This vector. + public Vector setX(int x) + { + this.x = x; + return this; + } + + /// + /// Set the X component. + /// + /// The new X component. + /// This vector. + public Vector setX(double x) + { + this.x = x; + return this; + } + + /// + /// Set the X component. + /// + /// The new X component. + /// This vector. + public Vector setX(float x) + { + this.x = x; + return this; + } + + /// + /// Set the Y component. + /// + /// The new Y component. + /// This vector. + public Vector setY(int y) + { + this.y = y; + return this; + } + + /// + /// Set the Y component. + /// + /// The new Y component. + /// This vector. + public Vector setY(double y) + { + this.y = y; + return this; + } + + /// + /// Set the Y component. + /// + /// The new Y component. + /// This vector. + public Vector setY(float y) + { + this.y = y; + return this; + } + + /// + /// Set the Z component. + /// + /// The new Z component. + /// This vector. + public Vector setZ(int z) + { + this.z = z; + return this; + } + + /// + /// Set the Z component. + /// + /// The new Z component. + /// This vector. + public Vector setZ(double z) + { + this.z = z; + return this; + } + + /// + /// Set the Z component. + /// + /// The new Z component. + /// This vector. + public Vector setZ(float z) + { + this.z = z; + return this; + } + + /// + /// Get a new vector. + /// + /// A clone of this vector. + public Vector clone() + { + return new Vector(x, y, z); + } + + /// + /// Gets a Location version of this vector with yaw and pitch being 0. + /// + /// The world to link the location to. + /// The location. + public Location toLocation(World world) + { + return new Location(world, x, y, z); + } + + /// + /// Gets a Location version of this vector. + /// + /// The world to link the location to. + /// The desired yaw. + /// The desired pitch. + /// The location. + public Location toLocation(World world, float yaw, float pitch) + { + return new Location(world, x, y, z, yaw, pitch); + } + + /// + /// Get the threshold used for equals(). + /// + /// The epsilon. + public static double getEpsilon() + { + return EPSILON; + } + + /// + /// Gets the minimum components of two vectors. + /// + /// The first vector. + /// The second vector. + /// Minimum. + 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)); + } + + /// + /// Gets the maximum components of two vectors. + /// + /// The first vector. + /// The second vector. + /// Maximum. + 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)); + } + + /// + /// Gets a random vector with components having a random value between 0 and 1. + /// + /// A random vector. + public static Vector getRandom() + { + return new Vector(_random.NextDouble(), _random.NextDouble(), _random.NextDouble()); + } + + /// + 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; + } + + /// + public override string ToString() + { + return $"{x},{y},{z}"; + } +} diff --git a/Minecraft.Server/FourKitBridge.cpp b/Minecraft.Server/FourKitBridge.cpp index 34ba09ed6..321f3afbf 100644 --- a/Minecraft.Server/FourKitBridge.cpp +++ b/Minecraft.Server/FourKitBridge.cpp @@ -175,6 +175,7 @@ typedef int(__stdcall *fn_fire_inventory_click)(int entityId, const char *titleUtf8, int titleByteLen); 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_set_entity_callbacks)(void *setSneaking, void *setVelocity, void *setAllowFlight); 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_bed_enter s_managedFireBedEnter = nullptr; static fn_fire_bed_leave s_managedFireBedLeave = nullptr; +static fn_set_entity_callbacks s_managedSetEntityCallbacks = nullptr; 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) { auto player = FindPlayer(entityId); if (!player) { - memset(outData, 0, 13 * sizeof(double)); + memset(outData, 0, 20 * sizeof(double)); outData[3] = 20.0; outData[4] = 20.0; outData[7] = 0.1; @@ -352,6 +354,13 @@ static void __cdecl NativeGetPlayerSnapshot(int entityId, double *outData) outData[10] = (double)player->dimension; outData[11] = player->isSleeping() ? 1.0 : 0.0; 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) @@ -1276,6 +1285,53 @@ static void __cdecl NativeSetHeldItemSlot(int entityId, int slot) player->connection->queueSend(std::make_shared(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(&player->abilities)); + } + } +} + static std::wstring FindNet10SystemRoot() { // 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"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"SetEntityCallbacks", (void **)&s_managedSetEntityCallbacks); if (!ok) { @@ -1574,6 +1631,11 @@ void Initialize() (void *)&NativeSetItemMeta, (void *)&NativeSetHeldItemSlot); + s_managedSetEntityCallbacks( + (void *)&NativeSetSneaking, + (void *)&NativeSetVelocity, + (void *)&NativeSetAllowFlight); + LogInfo("fourkit", "FourKit initialized successfully."); }