add more missing useful funcs

This commit is contained in:
sylvessa 2026-03-23 19:10:35 -05:00
parent f60d75dabb
commit a91abed6a1
4 changed files with 260 additions and 4 deletions

View file

@ -12,6 +12,11 @@ public class Player : HumanEntity, OfflinePlayer, CommandSender
{
private float _saturation = 5.0f;
private float _walkSpeed = 0.2f;
private float _exhaustion;
private int _foodLevel = 20;
private int _level;
private float _exp;
private int _totalExperience;
private Guid _playerUniqueId;
private string? _displayName;
private bool _sneaking;
@ -270,6 +275,104 @@ public class Player : HumanEntity, OfflinePlayer, CommandSender
}
}
/// <summary>
/// Gets the players current experience level.
/// </summary>
/// <returns>Current experience level.</returns>
public int getLevel() => _level;
/// <summary>
/// Sets the players current experience level.
/// </summary>
/// <param name="level">New experience level.</param>
public void setLevel(int level)
{
_level = level;
NativeBridge.SetLevel?.Invoke(getEntityId(), level);
}
/// <summary>
/// Gets the players current experience points towards the next level.
/// This is a percentage value. 0 is "no progress" and 1 is "next level".
/// </summary>
/// <returns>Current experience points.</returns>
public float getExp() => _exp;
/// <summary>
/// Sets the players current experience points towards the next level.
/// This is a percentage value. 0 is "no progress" and 1 is "next level".
/// </summary>
/// <param name="exp">New experience points.</param>
public void setExp(float exp)
{
_exp = exp;
NativeBridge.SetExp?.Invoke(getEntityId(), exp);
}
/// <summary>
/// Gives the player the amount of experience specified.
/// </summary>
/// <param name="amount">Exp amount to give.</param>
public void giveExp(int amount)
{
NativeBridge.GiveExp?.Invoke(getEntityId(), amount);
}
/// <summary>
/// Gives the player the amount of experience levels specified.
/// Levels can be taken by specifying a negative amount.
/// </summary>
/// <param name="amount">Amount of experience levels to give or take.</param>
public void giveExpLevels(int amount)
{
NativeBridge.GiveExpLevels?.Invoke(getEntityId(), amount);
}
/// <summary>
/// Gets the players current exhaustion level.
/// Exhaustion controls how fast the food level drops. While you have a
/// certain amount of exhaustion, your saturation will drop to zero, and
/// then your food will drop to zero.
/// </summary>
/// <returns>Exhaustion level.</returns>
public float getExhaustion() => _exhaustion;
/// <summary>
/// Sets the players current exhaustion level.
/// </summary>
/// <param name="value">Exhaustion level.</param>
public void setExhaustion(float value)
{
_exhaustion = value;
NativeBridge.SetExhaustion?.Invoke(getEntityId(), value);
}
/// <summary>
/// Sets the players current saturation level.
/// </summary>
/// <param name="value">Saturation level.</param>
public void setSaturation(float value)
{
_saturation = value;
NativeBridge.SetSaturation?.Invoke(getEntityId(), value);
}
/// <summary>
/// Gets the players current food level.
/// </summary>
/// <returns>Food level.</returns>
public int getFoodLevel() => _foodLevel;
/// <summary>
/// Sets the players current food level.
/// </summary>
/// <param name="value">New food level.</param>
public void setFoodLevel(int value)
{
_foodLevel = value;
NativeBridge.SetFoodLevel?.Invoke(getEntityId(), value);
}
// INTERNAL
internal void SetSaturationInternal(float saturation) => _saturation = saturation;
internal void SetWalkSpeedInternal(float walkSpeed) => _walkSpeed = walkSpeed;
@ -278,4 +381,9 @@ public class Player : HumanEntity, OfflinePlayer, CommandSender
internal void SetSprintingInternal(bool sprinting) => _sprinting = sprinting;
internal void SetAllowFlightInternal(bool allowFlight) => _allowFlight = allowFlight;
internal void SetSleepingIgnoredInternal(bool ignored) => _sleepingIgnored = ignored;
internal void SetLevelInternal(int level) => _level = level;
internal void SetExpInternal(float exp) => _exp = exp;
internal void SetTotalExperienceInternal(int totalExp) => _totalExperience = totalExp;
internal void SetFoodLevelInternal(int foodLevel) => _foodLevel = foodLevel;
internal void SetExhaustionInternal(float exhaustion) => _exhaustion = exhaustion;
}

View file

@ -612,6 +612,19 @@ public static class FourKitHost
}
}
[UnmanagedCallersOnly]
public static void SetExperienceCallbacks(IntPtr setLevel, IntPtr setExp, IntPtr giveExp, IntPtr giveExpLevels, IntPtr setFoodLevel, IntPtr setSaturation, IntPtr setExhaustion)
{
try
{
NativeBridge.SetExperienceCallbacks(setLevel, setExp, giveExp, giveExpLevels, setFoodLevel, setSaturation, setExhaustion);
}
catch (Exception ex)
{
ServerLog.Error("fourkit", $"SetExperienceCallbacks error: {ex}");
}
}
[UnmanagedCallersOnly]
public static long FirePlayerDropItem(int entityId, int itemId, int itemCount, int itemAux,
IntPtr outItemIdPtr, IntPtr outItemCountPtr, IntPtr outItemAuxPtr)
@ -966,12 +979,12 @@ public static class FourKitHost
};
}
// double[21] = { x, y, z, health, maxHealth, fallDistance, gameMode, walkSpeed, yaw, pitch, dimension, isSleeping, sleepTimer, sneaking, sprinting, onGround, velocityX, velocityY, velocityZ, allowFlight, sleepingIgnored }
// double[27] = { x, y, z, health, maxHealth, fallDistance, gameMode, walkSpeed, yaw, pitch, dimension, isSleeping, sleepTimer, sneaking, sprinting, onGround, velocityX, velocityY, velocityZ, allowFlight, sleepingIgnored, experienceLevel, experienceProgress, totalExperience, foodLevel, saturation, exhaustion }
private static void SyncPlayerFromNative(Player player)
{
if (NativeBridge.GetPlayerSnapshot == null)
return;
double[] buf = new double[21];
double[] buf = new double[27];
var gh = GCHandle.Alloc(buf, GCHandleType.Pinned);
try
{
@ -998,6 +1011,12 @@ public static class FourKitHost
player.SetVelocityInternal(buf[16], buf[17], buf[18]);
player.SetAllowFlightInternal(buf[19] != 0.0);
player.SetSleepingIgnoredInternal(buf[20] != 0.0);
player.SetLevelInternal((int)buf[21]);
player.SetExpInternal((float)buf[22]);
player.SetTotalExperienceInternal((int)buf[23]);
player.SetFoodLevelInternal((int)buf[24]);
player.SetSaturationInternal((float)buf[25]);
player.SetExhaustionInternal((float)buf[26]);
}
private static void BroadcastNativeMessage(string message)

View file

@ -132,6 +132,27 @@ internal static class NativeBridge
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate void NativeSetSleepingIgnoredDelegate(int entityId, int ignored);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate void NativeSetLevelDelegate(int entityId, int level);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate void NativeSetExpDelegate(int entityId, float exp);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate void NativeGiveExpDelegate(int entityId, int amount);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate void NativeGiveExpLevelsDelegate(int entityId, int amount);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate void NativeSetFoodLevelDelegate(int entityId, int foodLevel);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate void NativeSetSaturationDelegate(int entityId, float saturation);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate void NativeSetExhaustionDelegate(int entityId, float exhaustion);
internal static NativeDamageDelegate? DamagePlayer;
internal static NativeSetHealthDelegate? SetPlayerHealth;
@ -176,6 +197,13 @@ internal static class NativeBridge
internal static NativeSetAllowFlightDelegate? SetAllowFlight;
internal static NativePlaySoundDelegate? PlaySound;
internal static NativeSetSleepingIgnoredDelegate? SetSleepingIgnored;
internal static NativeSetLevelDelegate? SetLevel;
internal static NativeSetExpDelegate? SetExp;
internal static NativeGiveExpDelegate? GiveExp;
internal static NativeGiveExpLevelsDelegate? GiveExpLevels;
internal static NativeSetFoodLevelDelegate? SetFoodLevel;
internal static NativeSetSaturationDelegate? SetSaturation;
internal static NativeSetExhaustionDelegate? SetExhaustion;
internal static void SetCallbacks(IntPtr damage, IntPtr setHealth, IntPtr teleport, IntPtr setGameMode, IntPtr broadcastMessage, IntPtr setFallDistance, IntPtr getPlayerSnapshot, IntPtr sendMessage, IntPtr setWalkSpeed, IntPtr teleportEntity)
{
@ -238,4 +266,15 @@ internal static class NativeBridge
PlaySound = Marshal.GetDelegateForFunctionPointer<NativePlaySoundDelegate>(playSound);
SetSleepingIgnored = Marshal.GetDelegateForFunctionPointer<NativeSetSleepingIgnoredDelegate>(setSleepingIgnored);
}
internal static void SetExperienceCallbacks(IntPtr setLevel, IntPtr setExp, IntPtr giveExp, IntPtr giveExpLevels, IntPtr setFoodLevel, IntPtr setSaturation, IntPtr setExhaustion)
{
SetLevel = Marshal.GetDelegateForFunctionPointer<NativeSetLevelDelegate>(setLevel);
SetExp = Marshal.GetDelegateForFunctionPointer<NativeSetExpDelegate>(setExp);
GiveExp = Marshal.GetDelegateForFunctionPointer<NativeGiveExpDelegate>(giveExp);
GiveExpLevels = Marshal.GetDelegateForFunctionPointer<NativeGiveExpLevelsDelegate>(giveExpLevels);
SetFoodLevel = Marshal.GetDelegateForFunctionPointer<NativeSetFoodLevelDelegate>(setFoodLevel);
SetSaturation = Marshal.GetDelegateForFunctionPointer<NativeSetSaturationDelegate>(setSaturation);
SetExhaustion = Marshal.GetDelegateForFunctionPointer<NativeSetExhaustionDelegate>(setExhaustion);
}
}

View file

@ -36,6 +36,8 @@
#include "..\Minecraft.World\Player.h"
#include "..\Minecraft.World\PlayerAbilitiesPacket.h"
#include "..\Minecraft.World\SetCarriedItemPacket.h"
#include "..\Minecraft.World\SetExperiencePacket.h"
#include "..\Minecraft.World\SetHealthPacket.h"
#include "..\Minecraft.World\LevelSoundPacket.h"
#include "..\Minecraft.World\SimpleContainer.h"
#include "..\Minecraft.World\Slot.h"
@ -177,6 +179,7 @@ typedef int(__stdcall *fn_fire_inventory_click)(int entityId,
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, 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);
struct OpenContainerInfo
{
@ -218,6 +221,7 @@ 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 fn_set_experience_callbacks s_managedSetExperienceCallbacks = nullptr;
static bool s_initialized = false;
@ -329,16 +333,18 @@ static void __cdecl NativeSetFallDistance(int entityId, float distance)
}
}
// double[21] = { x, y, z, health, maxHealth, fallDistance, gameMode, walkSpeed, yaw, pitch, dimension, isSleeping, sleepTimer, sneaking, sprinting, onGround, velocityX, velocityY, velocityZ, allowFlight, sleepingIgnored }
// double[27] = { x, y, z, health, maxHealth, fallDistance, gameMode, walkSpeed, yaw, pitch, dimension, isSleeping, sleepTimer, sneaking, sprinting, onGround, velocityX, velocityY, velocityZ, allowFlight, sleepingIgnored, experienceLevel, experienceProgress, totalExperience, foodLevel, saturation, exhaustion }
static void __cdecl NativeGetPlayerSnapshot(int entityId, double *outData)
{
auto player = FindPlayer(entityId);
if (!player)
{
memset(outData, 0, 21 * sizeof(double));
memset(outData, 0, 27 * sizeof(double));
outData[3] = 20.0;
outData[4] = 20.0;
outData[7] = 0.1;
outData[24] = 20.0;
outData[25] = 5.0;
return;
}
outData[0] = player->x;
@ -363,6 +369,13 @@ static void __cdecl NativeGetPlayerSnapshot(int entityId, double *outData)
outData[18] = player->zd;
outData[19] = player->abilities.mayfly ? 1.0 : 0.0;
outData[20] = player->fk_sleepingIgnored ? 1.0 : 0.0;
outData[21] = (double)player->experienceLevel;
outData[22] = (double)player->experienceProgress;
outData[23] = (double)player->totalExperience;
FoodData *fd = player->getFoodData();
outData[24] = fd ? (double)fd->getFoodLevel() : 20.0;
outData[25] = fd ? (double)fd->getSaturationLevel() : 5.0;
outData[26] = fd ? (double)fd->getExhaustionLevel() : 0.0;
}
static void __cdecl NativeBroadcastMessage(const char *utf8, int len)
@ -1352,6 +1365,73 @@ static void __cdecl NativeSetSleepingIgnored(int entityId, int ignored)
}
}
static void __cdecl NativeSetLevel(int entityId, int level)
{
auto player = FindPlayer(entityId);
if (!player) return;
player->experienceLevel = level;
if (player->connection)
player->connection->send(std::make_shared<SetExperiencePacket>(player->experienceProgress, player->totalExperience, player->experienceLevel));
}
static void __cdecl NativeSetExp(int entityId, float exp)
{
auto player = FindPlayer(entityId);
if (!player) return;
player->experienceProgress = exp;
if (player->connection)
player->connection->send(std::make_shared<SetExperiencePacket>(player->experienceProgress, player->totalExperience, player->experienceLevel));
}
static void __cdecl NativeGiveExp(int entityId, int amount)
{
auto player = FindPlayer(entityId);
if (!player) return;
player->increaseXp(amount);
if (player->connection)
player->connection->send(std::make_shared<SetExperiencePacket>(player->experienceProgress, player->totalExperience, player->experienceLevel));
}
static void __cdecl NativeGiveExpLevels(int entityId, int amount)
{
auto player = FindPlayer(entityId);
if (!player) return;
player->giveExperienceLevels(amount);
if (player->connection)
player->connection->send(std::make_shared<SetExperiencePacket>(player->experienceProgress, player->totalExperience, player->experienceLevel));
}
static void __cdecl NativeSetFoodLevel(int entityId, int foodLevel)
{
auto player = FindPlayer(entityId);
if (!player) return;
FoodData *fd = player->getFoodData();
if (!fd) return;
fd->setFoodLevel(foodLevel);
if (player->connection)
player->connection->send(std::make_shared<SetHealthPacket>(player->getHealth(), fd->getFoodLevel(), fd->getSaturationLevel(), eTelemetryChallenges_Unknown));
}
static void __cdecl NativeSetSaturation(int entityId, float saturation)
{
auto player = FindPlayer(entityId);
if (!player) return;
FoodData *fd = player->getFoodData();
if (!fd) return;
fd->setSaturation(saturation);
if (player->connection)
player->connection->send(std::make_shared<SetHealthPacket>(player->getHealth(), fd->getFoodLevel(), fd->getSaturationLevel(), eTelemetryChallenges_Unknown));
}
static void __cdecl NativeSetExhaustion(int entityId, float exhaustion)
{
auto player = FindPlayer(entityId);
if (!player) return;
FoodData *fd = player->getFoodData();
if (!fd) return;
fd->setExhaustion(exhaustion);
}
static std::wstring FindNet10SystemRoot()
{
// overengineered
@ -1595,6 +1675,7 @@ void Initialize()
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);
ok = ok && GetManagedEntryPoint(loadAssembly, assemblyPath.c_str(), typeName, L"SetExperienceCallbacks", (void **)&s_managedSetExperienceCallbacks);
if (!ok)
{
@ -1658,6 +1739,15 @@ void Initialize()
(void *)&NativePlaySound,
(void *)&NativeSetSleepingIgnored);
s_managedSetExperienceCallbacks(
(void *)&NativeSetLevel,
(void *)&NativeSetExp,
(void *)&NativeGiveExp,
(void *)&NativeGiveExpLevels,
(void *)&NativeSetFoodLevel,
(void *)&NativeSetSaturation,
(void *)&NativeSetExhaustion);
LogInfo("fourkit", "FourKit initialized successfully.");
}