add some vehicle related funcs, fix entity getting (temp)

This commit is contained in:
sylvessa 2026-03-23 22:29:23 -05:00
parent 32f058d078
commit d6c4500c75
6 changed files with 231 additions and 1 deletions

View file

@ -5,7 +5,7 @@ using Minecraft.Server.FourKit.Util;
/// <summary>
/// Represents a base entity in the world
/// </summary>
public abstract class Entity
public class Entity
{
private Location _location = new();
private Guid _uniqueId = Guid.NewGuid();
@ -101,6 +101,70 @@ public abstract class Entity
NativeBridge.SetVelocity?.Invoke(getEntityId(), velocity.getX(), velocity.getY(), velocity.getZ());
}
/// <summary>
/// Returns whether this entity is inside a vehicle.
/// </summary>
/// <returns><c>true</c> if the entity is in a vehicle.</returns>
public bool isInsideVehicle()
{
return (NativeBridge.GetVehicleId?.Invoke(getEntityId()) ?? -1) >= 0;
}
/// <summary>
/// Leave the current vehicle. If the entity is currently in a vehicle
/// (and is removed from it), <c>true</c> will be returned, otherwise
/// <c>false</c> will be returned.
/// </summary>
/// <returns><c>true</c> if the entity was in a vehicle.</returns>
public bool leaveVehicle()
{
return NativeBridge.LeaveVehicle?.Invoke(getEntityId()) != 0;
}
/// <summary>
/// Get the vehicle that this entity is inside. If there is no vehicle,
/// <c>null</c> will be returned.
/// </summary>
/// <returns>The current vehicle, or <c>null</c>.</returns>
public Entity? getVehicle()
{
int vehicleId = NativeBridge.GetVehicleId?.Invoke(getEntityId()) ?? -1;
if (vehicleId < 0) return null;
return FourKit.GetEntityByEntityId(vehicleId);
}
/// <summary>
/// Eject any passenger.
/// </summary>
/// <returns><c>true</c> if there was a passenger.</returns>
public bool eject()
{
return NativeBridge.Eject?.Invoke(getEntityId()) != 0;
}
/// <summary>
/// Gets the primary passenger of a vehicle. For vehicles that could
/// have multiple passengers, this will only return the primary passenger.
/// </summary>
/// <returns>The passenger entity, or <c>null</c>.</returns>
public Entity? getPassenger()
{
int passengerId = NativeBridge.GetPassengerId?.Invoke(getEntityId()) ?? -1;
if (passengerId < 0) return null;
return FourKit.GetEntityByEntityId(passengerId);
}
/// <summary>
/// Set the passenger of a vehicle.
/// </summary>
/// <param name="passenger">The new passenger.</param>
/// <returns><c>false</c> if it could not be done for whatever reason.</returns>
public bool setPassenger(Entity passenger)
{
if (passenger == null || NativeBridge.SetPassenger == null) return false;
return NativeBridge.SetPassenger(getEntityId(), passenger.getEntityId()) != 0;
}
// INTERNAL
internal void SetLocation(Location location)
{

View file

@ -6,6 +6,7 @@ using Minecraft.Server.FourKit.Inventory;
/// <summary>
/// An abstract base class for events that describe an interaction between a
/// <see cref="HumanEntity"/> and the contents of an <see cref="Inventory"/>.
/// This is currently not emitted anywhere, use <see cref="InventoryClickEvent"/> instead.
/// </summary>
public abstract class InventoryInteractEvent : InventoryEvent, Cancellable
{

View file

@ -97,6 +97,41 @@ public static class FourKit
}
}
internal static Entity.Entity? GetEntityByEntityId(int entityId)
{
var player = GetPlayerByEntityId(entityId);
if (player != null) return player;
if (NativeBridge.GetEntityInfo == null) return null;
IntPtr buf = System.Runtime.InteropServices.Marshal.AllocHGlobal(5 * sizeof(double));
try
{
NativeBridge.GetEntityInfo(entityId, buf);
double[] data = new double[5];
System.Runtime.InteropServices.Marshal.Copy(buf, data, 0, 5);
int typeId = (int)data[0];
if (typeId < 0) return null;
var entityType = Enum.IsDefined(typeof(Entity.EntityType), typeId)
? (Entity.EntityType)typeId
: Entity.EntityType.UNKNOWN;
int dimId = (int)data[4];
var entity = new Entity.Entity();
entity.SetEntityIdInternal(entityId);
entity.SetEntityTypeInternal(entityType);
entity.SetDimensionInternal(dimId);
entity.SetLocation(new Location(getWorld(dimId), data[1], data[2], data[3]));
return entity;
}
finally
{
System.Runtime.InteropServices.Marshal.FreeHGlobal(buf);
}
}
internal static Player TrackPlayer(int entityId, string name)
{
lock (_playerLock)

View file

@ -638,6 +638,19 @@ public static class FourKitHost
}
}
[UnmanagedCallersOnly]
public static void SetVehicleCallbacks(IntPtr setPassenger, IntPtr leaveVehicle, IntPtr eject, IntPtr getVehicleId, IntPtr getPassengerId, IntPtr getEntityInfo)
{
try
{
NativeBridge.SetVehicleCallbacks(setPassenger, leaveVehicle, eject, getVehicleId, getPassengerId, getEntityInfo);
}
catch (Exception ex)
{
ServerLog.Error("fourkit", $"SetVehicleCallbacks error: {ex}");
}
}
[UnmanagedCallersOnly]
public static long FirePlayerDropItem(int entityId, int itemId, int itemCount, int itemAux,
IntPtr outItemIdPtr, IntPtr outItemCountPtr, IntPtr outItemAuxPtr)

View file

@ -156,6 +156,24 @@ internal static class NativeBridge
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate void NativeSpawnParticleDelegate(int entityId, int particleId, float x, float y, float z, float offsetX, float offsetY, float offsetZ, float speed, int count);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate int NativeSetPassengerDelegate(int entityId, int passengerEntityId);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate int NativeLeaveVehicleDelegate(int entityId);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate int NativeEjectDelegate(int entityId);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate int NativeGetVehicleIdDelegate(int entityId);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate int NativeGetPassengerIdDelegate(int entityId);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate void NativeGetEntityInfoDelegate(int entityId, IntPtr outBuf);
internal static NativeDamageDelegate? DamagePlayer;
internal static NativeSetHealthDelegate? SetPlayerHealth;
@ -208,6 +226,12 @@ internal static class NativeBridge
internal static NativeSetSaturationDelegate? SetSaturation;
internal static NativeSetExhaustionDelegate? SetExhaustion;
internal static NativeSpawnParticleDelegate? SpawnParticle;
internal static NativeSetPassengerDelegate? SetPassenger;
internal static NativeLeaveVehicleDelegate? LeaveVehicle;
internal static NativeEjectDelegate? Eject;
internal static NativeGetVehicleIdDelegate? GetVehicleId;
internal static NativeGetPassengerIdDelegate? GetPassengerId;
internal static NativeGetEntityInfoDelegate? GetEntityInfo;
internal static void SetCallbacks(IntPtr damage, IntPtr setHealth, IntPtr teleport, IntPtr setGameMode, IntPtr broadcastMessage, IntPtr setFallDistance, IntPtr getPlayerSnapshot, IntPtr sendMessage, IntPtr setWalkSpeed, IntPtr teleportEntity)
{
@ -286,4 +310,14 @@ internal static class NativeBridge
{
SpawnParticle = Marshal.GetDelegateForFunctionPointer<NativeSpawnParticleDelegate>(spawnParticle);
}
internal static void SetVehicleCallbacks(IntPtr setPassenger, IntPtr leaveVehicle, IntPtr eject, IntPtr getVehicleId, IntPtr getPassengerId, IntPtr getEntityInfo)
{
SetPassenger = Marshal.GetDelegateForFunctionPointer<NativeSetPassengerDelegate>(setPassenger);
LeaveVehicle = Marshal.GetDelegateForFunctionPointer<NativeLeaveVehicleDelegate>(leaveVehicle);
Eject = Marshal.GetDelegateForFunctionPointer<NativeEjectDelegate>(eject);
GetVehicleId = Marshal.GetDelegateForFunctionPointer<NativeGetVehicleIdDelegate>(getVehicleId);
GetPassengerId = Marshal.GetDelegateForFunctionPointer<NativeGetPassengerIdDelegate>(getPassengerId);
GetEntityInfo = Marshal.GetDelegateForFunctionPointer<NativeGetEntityInfoDelegate>(getEntityInfo);
}
}

View file

@ -1,4 +1,5 @@
// todo: split into files for better readability
// todo: this needs to be made way more neat and less duplicate stuff
#include "FourKitBridge.h"
#include "Common/StringUtils.h"
@ -40,6 +41,7 @@
#include "..\Minecraft.World\SetHealthPacket.h"
#include "..\Minecraft.World\LevelSoundPacket.h"
#include "..\Minecraft.World\LevelParticlesPacket.h"
#include "..\Minecraft.World\SetEntityLinkPacket.h"
#include "..\Minecraft.World\SimpleContainer.h"
#include "..\Minecraft.World\Slot.h"
#include "..\Minecraft.World\Tile.h"
@ -182,6 +184,7 @@ typedef void(__stdcall *fn_fire_bed_leave)(int entityId, int dimId, int bedX, in
typedef void(__stdcall *fn_set_entity_callbacks)(void *setSneaking, void *setVelocity, void *setAllowFlight, void *playSound, void *setSleepingIgnored);
typedef void(__stdcall *fn_set_experience_callbacks)(void *setLevel, void *setExp, void *giveExp, void *giveExpLevels, void *setFoodLevel, void *setSaturation, void *setExhaustion);
typedef void(__stdcall *fn_set_particle_callbacks)(void *spawnParticle);
typedef void(__stdcall *fn_set_vehicle_callbacks)(void *setPassenger, void *leaveVehicle, void *eject, void *getVehicleId, void *getPassengerId, void *getEntityInfo);
struct OpenContainerInfo
{
@ -225,6 +228,7 @@ static fn_fire_bed_leave s_managedFireBedLeave = nullptr;
static fn_set_entity_callbacks s_managedSetEntityCallbacks = nullptr;
static fn_set_experience_callbacks s_managedSetExperienceCallbacks = nullptr;
static fn_set_particle_callbacks s_managedSetParticleCallbacks = nullptr;
static fn_set_vehicle_callbacks s_managedSetVehicleCallbacks = nullptr;
static bool s_initialized = false;
@ -1445,6 +1449,76 @@ static void __cdecl NativeSpawnParticle(int entityId, int particleId, float x, f
player->connection->send(std::make_shared<LevelParticlesPacket>(std::wstring(buf), x, y, z, offsetX, offsetY, offsetZ, speed, count));
}
static int __cdecl NativeSetPassenger(int entityId, int passengerEntityId)
{
auto entity = FindEntity(entityId);
auto passenger = FindEntity(passengerEntityId);
if (!entity || !passenger) return 0;
passenger->ride(entity);
PlayerList *list = MinecraftServer::getPlayerList();
if (list)
list->broadcastAll(std::make_shared<SetEntityLinkPacket>(SetEntityLinkPacket::RIDING, passenger, entity), entity->dimension);
return 1;
}
static int __cdecl NativeLeaveVehicle(int entityId)
{
auto entity = FindEntity(entityId);
if (!entity || !entity->riding) return 0;
int dim = entity->riding->dimension;
entity->ride(nullptr);
PlayerList *list = MinecraftServer::getPlayerList();
if (list)
list->broadcastAll(std::make_shared<SetEntityLinkPacket>(SetEntityLinkPacket::RIDING, entity, nullptr), dim);
return 1;
}
static int __cdecl NativeEject(int entityId)
{
auto entity = FindEntity(entityId);
if (!entity) return 0;
auto riderPtr = entity->rider.lock();
if (!riderPtr) return 0;
riderPtr->ride(nullptr);
PlayerList *list = MinecraftServer::getPlayerList();
if (list)
list->broadcastAll(std::make_shared<SetEntityLinkPacket>(SetEntityLinkPacket::RIDING, riderPtr, nullptr), entity->dimension);
return 1;
}
static int __cdecl NativeGetVehicleId(int entityId)
{
auto entity = FindEntity(entityId);
if (!entity || !entity->riding) return -1;
return entity->riding->entityId;
}
static int __cdecl NativeGetPassengerId(int entityId)
{
auto entity = FindEntity(entityId);
if (!entity) return -1;
auto riderPtr = entity->rider.lock();
if (!riderPtr) return -1;
return riderPtr->entityId;
}
static void __cdecl NativeGetEntityInfo(int entityId, double *outData)
{
// this stinks iof shit and more shit
outData[0] = -1;
outData[1] = 0;
outData[2] = 0;
outData[3] = 0;
outData[4] = 0;
auto entity = FindEntity(entityId);
if (!entity) return;
outData[0] = (double)MapEntityType((int)entity->GetType());
outData[1] = entity->x;
outData[2] = entity->y;
outData[3] = entity->z;
outData[4] = (double)entity->dimension;
}
static std::wstring FindNet10SystemRoot()
{
// overengineered
@ -1690,6 +1764,7 @@ void Initialize()
ok = ok && GetManagedEntryPoint(loadAssembly, assemblyPath.c_str(), typeName, L"SetEntityCallbacks", (void **)&s_managedSetEntityCallbacks);
ok = ok && GetManagedEntryPoint(loadAssembly, assemblyPath.c_str(), typeName, L"SetExperienceCallbacks", (void **)&s_managedSetExperienceCallbacks);
ok = ok && GetManagedEntryPoint(loadAssembly, assemblyPath.c_str(), typeName, L"SetParticleCallbacks", (void **)&s_managedSetParticleCallbacks);
ok = ok && GetManagedEntryPoint(loadAssembly, assemblyPath.c_str(), typeName, L"SetVehicleCallbacks", (void **)&s_managedSetVehicleCallbacks);
if (!ok)
{
@ -1765,6 +1840,14 @@ void Initialize()
s_managedSetParticleCallbacks(
(void *)&NativeSpawnParticle);
s_managedSetVehicleCallbacks(
(void *)&NativeSetPassenger,
(void *)&NativeLeaveVehicle,
(void *)&NativeEject,
(void *)&NativeGetVehicleId,
(void *)&NativeGetPassengerId,
(void *)&NativeGetEntityInfo);
LogInfo("fourkit", "FourKit initialized successfully.");
}