playsound, sleep ignoring

This commit is contained in:
sylvessa 2026-03-23 17:25:46 -05:00
parent a5e39efa04
commit a0be612f48
7 changed files with 294 additions and 9 deletions

View file

@ -324,6 +324,8 @@ void ServerLevel::updateSleepingPlayerList()
for (auto& player : players)
{
if (player->fk_sleepingIgnored)
continue;
if (!player->isSleeping())
{
allPlayersSleeping = false;
@ -368,6 +370,8 @@ bool ServerLevel::allPlayersAreSleeping()
// all players are sleeping, but have they slept long enough?
for (auto& player : players)
{
if (player->fk_sleepingIgnored)
continue;
// System.out.println(player->entityId + ": " + player->getSleepTimer());
if (!player->isSleepingLongEnough())
{

View file

@ -17,6 +17,7 @@ public class Player : HumanEntity, OfflinePlayer, CommandSender
private bool _sneaking;
private bool _sprinting;
private bool _allowFlight;
private bool _sleepingIgnored;
internal bool IsOnline { get; set; }
@ -110,6 +111,40 @@ public class Player : HumanEntity, OfflinePlayer, CommandSender
/// <returns>True if player is sprinting.</returns>
public bool isSprinting() => _sprinting;
/// <summary>
/// Sets whether the player is ignored as not sleeping. If everyone is
/// either sleeping or has this flag set, then time will advance to the
/// next day. If everyone has this flag set but no one is actually in
/// bed, then nothing will happen.
/// </summary>
/// <param name="isSleeping">Whether to ignore.</param>
public void setSleepingIgnored(bool isSleeping)
{
_sleepingIgnored = isSleeping;
NativeBridge.SetSleepingIgnored?.Invoke(getEntityId(), isSleeping ? 1 : 0);
}
/// <summary>
/// Returns whether the player is sleeping ignored.
/// </summary>
/// <returns>Whether player is ignoring sleep.</returns>
public bool isSleepingIgnored() => _sleepingIgnored;
/// <summary>
/// Play a sound for a player at the location.
/// This function will fail silently if Location or Sound are null.
/// </summary>
/// <param name="location">The location to play the sound.</param>
/// <param name="sound">The sound to play.</param>
/// <param name="volume">The volume of the sound.</param>
/// <param name="pitch">The pitch of the sound.</param>
public void playSound(Location location, Sound sound, float volume, float pitch)
{
if (location == null)
return;
NativeBridge.PlaySound?.Invoke(getEntityId(), (int)sound, location.X, location.Y, location.Z, volume, pitch);
}
/// <summary>
/// Determines if the Player is allowed to fly via jump key double-tap
/// like in creative mode.
@ -242,4 +277,5 @@ public class Player : HumanEntity, OfflinePlayer, CommandSender
internal void SetSneakingInternal(bool sneaking) => _sneaking = sneaking;
internal void SetSprintingInternal(bool sprinting) => _sprinting = sprinting;
internal void SetAllowFlightInternal(bool allowFlight) => _allowFlight = allowFlight;
internal void SetSleepingIgnoredInternal(bool ignored) => _sleepingIgnored = ignored;
}

View file

@ -538,6 +538,9 @@ public static class FourKitHost
Marshal.Copy(lens, 0, ptr, 4);
}
// todo: rework callback funcs due to it being messy
[UnmanagedCallersOnly]
public static void SetNativeCallbacks(IntPtr damage, IntPtr setHealth, IntPtr teleport, IntPtr setGameMode, IntPtr broadcastMessage, IntPtr setFallDistance, IntPtr getPlayerSnapshot, IntPtr sendMessage, IntPtr setWalkSpeed, IntPtr teleportEntity)
{
@ -595,13 +598,13 @@ public static class FourKitHost
}
[UnmanagedCallersOnly]
public static void SetEntityCallbacks(IntPtr setSneaking, IntPtr setVelocity, IntPtr setAllowFlight)
public static void SetEntityCallbacks(IntPtr setSneaking, IntPtr setVelocity, IntPtr setAllowFlight, IntPtr playSound, IntPtr setSleepingIgnored)
{
// setsneaking and setallowflight here cuz i am lazy
// should be under player stuff ill do that later
try
{
NativeBridge.SetEntityCallbacks(setSneaking, setVelocity, setAllowFlight);
NativeBridge.SetEntityCallbacks(setSneaking, setVelocity, setAllowFlight, playSound, setSleepingIgnored);
}
catch (Exception ex)
{
@ -963,12 +966,12 @@ public static class FourKitHost
};
}
// double[20] = { x, y, z, health, maxHealth, fallDistance, gameMode, walkSpeed, yaw, pitch, dimension, isSleeping, sleepTimer, sneaking, sprinting, onGround, velocityX, velocityY, velocityZ, allowFlight }
// double[21] = { x, y, z, health, maxHealth, fallDistance, gameMode, walkSpeed, yaw, pitch, dimension, isSleeping, sleepTimer, sneaking, sprinting, onGround, velocityX, velocityY, velocityZ, allowFlight, sleepingIgnored }
private static void SyncPlayerFromNative(Player player)
{
if (NativeBridge.GetPlayerSnapshot == null)
return;
double[] buf = new double[20];
double[] buf = new double[21];
var gh = GCHandle.Alloc(buf, GCHandleType.Pinned);
try
{
@ -994,6 +997,7 @@ public static class FourKitHost
player.SetOnGroundInternal(buf[15] != 0.0);
player.SetVelocityInternal(buf[16], buf[17], buf[18]);
player.SetAllowFlightInternal(buf[19] != 0.0);
player.SetSleepingIgnoredInternal(buf[20] != 0.0);
}
private static void BroadcastNativeMessage(string message)

View file

@ -126,6 +126,12 @@ internal static class NativeBridge
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate void NativeSetAllowFlightDelegate(int entityId, int allowFlight);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate void NativePlaySoundDelegate(int entityId, int soundId, double x, double y, double z, float volume, float pitch);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate void NativeSetSleepingIgnoredDelegate(int entityId, int ignored);
internal static NativeDamageDelegate? DamagePlayer;
internal static NativeSetHealthDelegate? SetPlayerHealth;
@ -168,6 +174,8 @@ internal static class NativeBridge
internal static NativeSetSneakingDelegate? SetSneaking;
internal static NativeSetVelocityDelegate? SetVelocity;
internal static NativeSetAllowFlightDelegate? SetAllowFlight;
internal static NativePlaySoundDelegate? PlaySound;
internal static NativeSetSleepingIgnoredDelegate? SetSleepingIgnored;
internal static void SetCallbacks(IntPtr damage, IntPtr setHealth, IntPtr teleport, IntPtr setGameMode, IntPtr broadcastMessage, IntPtr setFallDistance, IntPtr getPlayerSnapshot, IntPtr sendMessage, IntPtr setWalkSpeed, IntPtr teleportEntity)
{
@ -222,10 +230,12 @@ internal static class NativeBridge
SetHeldItemSlot = Marshal.GetDelegateForFunctionPointer<NativeSetHeldItemSlotDelegate>(setHeldItemSlot);
}
internal static void SetEntityCallbacks(IntPtr setSneaking, IntPtr setVelocity, IntPtr setAllowFlight)
internal static void SetEntityCallbacks(IntPtr setSneaking, IntPtr setVelocity, IntPtr setAllowFlight, IntPtr playSound, IntPtr setSleepingIgnored)
{
SetSneaking = Marshal.GetDelegateForFunctionPointer<NativeSetSneakingDelegate>(setSneaking);
SetVelocity = Marshal.GetDelegateForFunctionPointer<NativeSetVelocityDelegate>(setVelocity);
SetAllowFlight = Marshal.GetDelegateForFunctionPointer<NativeSetAllowFlightDelegate>(setAllowFlight);
PlaySound = Marshal.GetDelegateForFunctionPointer<NativePlaySoundDelegate>(playSound);
SetSleepingIgnored = Marshal.GetDelegateForFunctionPointer<NativeSetSleepingIgnoredDelegate>(setSleepingIgnored);
}
}

View file

@ -0,0 +1,208 @@
namespace Minecraft.Server.FourKit;
/// <summary>
/// An Enum of Sounds the server is able to send to players.
/// </summary>
public enum Sound
{
AMBIENCE_CAVE = 75,
AMBIENCE_RAIN = 73,
AMBIENCE_THUNDER = 74,
ANVIL_BREAK = 110,
ANVIL_LAND = 111,
ANVIL_USE = 112,
ARROW_HIT = 56,
BAT_DEATH = 140,
BAT_HURT = 139,
BAT_IDLE = 138,
BAT_LOOP = 138,
BAT_TAKEOFF = 141,
BLAZE_BREATH = 15,
BLAZE_DEATH = 17,
BLAZE_HIT = 16,
BREATH = 81,
BURP = 63,
CAT_HISS = 54,
CAT_HIT = 54,
CAT_MEOW = 53,
CAT_PURR = 51,
CAT_PURREOW = 52,
CHEST_CLOSE = 70,
CHEST_OPEN = 69,
CHICKEN_EGG_POP = 2,
CHICKEN_HURT = 1,
CHICKEN_IDLE = 0,
CHICKEN_WALK = 148,
CLICK = 65,
COW_HURT = 4,
COW_IDLE = 3,
COW_WALK = 147,
CREEPER_DEATH = 42,
CREEPER_HISS = 41,
DIG_GRASS = 125,
DIG_GRAVEL = 126,
DIG_SAND = 127,
DIG_SNOW = 128,
DIG_STONE = 129,
DIG_WOOD = 130,
DIG_WOOL = 124,
DONKEY_ANGRY = 175,
DONKEY_DEATH = 165,
DONKEY_HIT = 169,
DONKEY_IDLE = 173,
DOOR_CLOSE = 72,
DOOR_OPEN = 71,
DRINK = 61,
EAT = 62,
ENDERDRAGON_DEATH = 101,
ENDERDRAGON_GROWL = 102,
ENDERDRAGON_HIT = 103,
ENDERDRAGON_WINGS = 104,
ENDERMAN_DEATH = 25,
ENDERMAN_HIT = 24,
ENDERMAN_IDLE = 23,
ENDERMAN_SCREAM = 151,
ENDERMAN_STARE = 150,
ENDERMAN_TELEPORT = 26,
EXPLODE = 57,
FALL_BIG = 83,
FALL_SMALL = 82,
FIRE = 80,
FIRE_IGNITE = 79,
FIREWORK_BLAST = 132,
FIREWORK_BLAST2 = 133,
FIREWORK_LARGE_BLAST = 134,
FIREWORK_LARGE_BLAST2 = 135,
FIREWORK_LAUNCH = 131,
FIREWORK_TWINKLE = 136,
FIREWORK_TWINKLE2 = 137,
FIZZ = 58,
FUSE = 60,
GHAST_CHARGE = 22,
GHAST_DEATH = 20,
GHAST_FIREBALL = 21,
GHAST_MOAN = 18,
GHAST_SCREAM = 19,
GHAST_SCREAM2 = 19,
GLASS = 66,
HORSE_ANGRY = 176,
HORSE_ARMOR = 161,
HORSE_BREATHE = 178,
HORSE_DEATH = 166,
HORSE_GALLOP = 177,
HORSE_HIT = 170,
HORSE_IDLE = 174,
HORSE_JUMP = 181,
HORSE_LAND = 160,
HORSE_SADDLE = 162,
HORSE_SKELETON_DEATH = 164,
HORSE_SKELETON_HIT = 168,
HORSE_SKELETON_IDLE = 172,
HORSE_SOFT = 180,
HORSE_WOOD = 179,
HORSE_ZOMBIE_DEATH = 163,
HORSE_ZOMBIE_HIT = 167,
HORSE_ZOMBIE_IDLE = 171,
HURT = 81,
HURT_FLESH = 81,
IRONGOLEM_DEATH = 107,
IRONGOLEM_HIT = 106,
IRONGOLEM_THROW = 105,
IRONGOLEM_WALK = 108,
ITEM_BREAK = 68,
ITEM_PICKUP = 59,
LAVA = 93,
LAVA_POP = 92,
LEVEL_UP = 188,
MAGMACUBE_JUMP = 49,
MAGMACUBE_WALK = 50,
MAGMACUBE_WALK2 = 49,
MINECART_BASE = 94,
MINECART_INSIDE = 95,
NOTE_BASS = 88,
NOTE_BASS_DRUM = 85,
NOTE_BASS_GUITAR = 88,
NOTE_PIANO = 84,
NOTE_PLING = 84,
NOTE_SNARE_DRUM = 86,
NOTE_STICKS = 87,
ORB_PICKUP = 67,
PIG_DEATH = 6,
PIG_IDLE = 5,
PIG_WALK = 149,
PISTON_EXTEND = 90,
PISTON_RETRACT = 89,
PORTAL = 76,
PORTAL_TRAVEL = 78,
PORTAL_TRIGGER = 77,
SHEEP_IDLE = 7,
SHEEP_SHEAR = 152,
SHEEP_WALK = 153,
SHOOT_ARROW = 55,
SILVERFISH_HIT = 32,
SILVERFISH_IDLE = 31,
SILVERFISH_KILL = 33,
SILVERFISH_WALK = 34,
SKELETON_DEATH = 154,
SKELETON_HURT = 36,
SKELETON_IDLE = 35,
SKELETON_WALK = 155,
SLIME_ATTACK = 40,
SLIME_WALK = 185,
SLIME_WALK2 = 186,
SPIDER_DEATH = 38,
SPIDER_IDLE = 37,
SPIDER_WALK = 156,
SPLASH = 64,
SPLASH2 = 64,
STEP_GRASS = 97,
STEP_GRAVEL = 96,
STEP_LADDER = 123,
STEP_SAND = 100,
STEP_SNOW = 122,
STEP_STONE = 94,
STEP_WOOD = 95,
STEP_WOOL = 99,
SUCCESSFUL_HIT = 56,
SWIM = 159,
THORNS = 109,
VILLAGER_DEATH = 116,
VILLAGER_HAGGLE = 113,
VILLAGER_HIT = 115,
VILLAGER_IDLE = 114,
VILLAGER_NO = 118,
VILLAGER_YES = 117,
WATER = 91,
WITCH_DEATH = 184,
WITCH_HURT = 183,
WITCH_IDLE = 182,
WITHER_DEATH = 145,
WITHER_HURT = 144,
WITHER_IDLE = 143,
WITHER_SHOOT = 146,
WITHER_SPAWN = 142,
WOLF_BARK = 11,
WOLF_DEATH = 13,
WOLF_GROWL = 8,
WOLF_HOWL = 8,
WOLF_HURT = 12,
WOLF_PANT = 10,
WOLF_SHAKE = 14,
WOLF_WALK = 157,
WOLF_WHINE = 9,
WOOD_CLICK = 65,
ZOMBIE_DEATH = 45,
ZOMBIE_HURT = 44,
ZOMBIE_IDLE = 43,
ZOMBIE_INFECT = 119,
ZOMBIE_METAL = 48,
ZOMBIE_PIG_ANGRY = 30,
ZOMBIE_PIG_DEATH = 29,
ZOMBIE_PIG_HURT = 28,
ZOMBIE_PIG_IDLE = 27,
ZOMBIE_REMEDY = 121,
ZOMBIE_STEP = 158,
ZOMBIE_UNFECT = 120,
ZOMBIE_WOOD = 46,
ZOMBIE_WOODBREAK = 47,
}

View file

@ -36,6 +36,7 @@
#include "..\Minecraft.World\Player.h"
#include "..\Minecraft.World\PlayerAbilitiesPacket.h"
#include "..\Minecraft.World\SetCarriedItemPacket.h"
#include "..\Minecraft.World\LevelSoundPacket.h"
#include "..\Minecraft.World\SimpleContainer.h"
#include "..\Minecraft.World\Slot.h"
#include "..\Minecraft.World\Tile.h"
@ -175,7 +176,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);
typedef void(__stdcall *fn_set_entity_callbacks)(void *setSneaking, void *setVelocity, void *setAllowFlight, void *playSound, void *setSleepingIgnored);
struct OpenContainerInfo
{
@ -328,13 +329,13 @@ static void __cdecl NativeSetFallDistance(int entityId, float distance)
}
}
// double[20] = { x, y, z, health, maxHealth, fallDistance, gameMode, walkSpeed, yaw, pitch, dimension, isSleeping, sleepTimer, sneaking, sprinting, onGround, velocityX, velocityY, velocityZ, allowFlight }
// double[21] = { x, y, z, health, maxHealth, fallDistance, gameMode, walkSpeed, yaw, pitch, dimension, isSleeping, sleepTimer, sneaking, sprinting, onGround, velocityX, velocityY, velocityZ, allowFlight, sleepingIgnored }
static void __cdecl NativeGetPlayerSnapshot(int entityId, double *outData)
{
auto player = FindPlayer(entityId);
if (!player)
{
memset(outData, 0, 20 * sizeof(double));
memset(outData, 0, 21 * sizeof(double));
outData[3] = 20.0;
outData[4] = 20.0;
outData[7] = 0.1;
@ -361,6 +362,7 @@ static void __cdecl NativeGetPlayerSnapshot(int entityId, double *outData)
outData[17] = player->yd;
outData[18] = player->zd;
outData[19] = player->abilities.mayfly ? 1.0 : 0.0;
outData[20] = player->fk_sleepingIgnored ? 1.0 : 0.0;
}
static void __cdecl NativeBroadcastMessage(const char *utf8, int len)
@ -1332,6 +1334,24 @@ static void __cdecl NativeSetAllowFlight(int entityId, int allowFlight)
}
}
static void __cdecl NativePlaySound(int entityId, int soundId, double x, double y, double z, float volume, float pitch)
{
auto player = FindPlayer(entityId);
if (player && player->connection)
{
player->connection->send(std::make_shared<LevelSoundPacket>(soundId, x, y, z, volume, pitch));
}
}
static void __cdecl NativeSetSleepingIgnored(int entityId, int ignored)
{
auto player = FindPlayer(entityId);
if (player)
{
player->fk_sleepingIgnored = (ignored != 0);
}
}
static std::wstring FindNet10SystemRoot()
{
// overengineered
@ -1634,7 +1654,9 @@ void Initialize()
s_managedSetEntityCallbacks(
(void *)&NativeSetSneaking,
(void *)&NativeSetVelocity,
(void *)&NativeSetAllowFlight);
(void *)&NativeSetAllowFlight,
(void *)&NativePlaySound,
(void *)&NativeSetSleepingIgnored);
LogInfo("fourkit", "FourKit initialized successfully.");
}

View file

@ -126,6 +126,7 @@ public:
bool fk_deathKeepLevel = false;
int fk_deathNewExp = 0;
int fk_deathNewLevel = 0;
bool fk_sleepingIgnored = false;
// 4J Stu - Made protected so that we can access it from MultiPlayerLocalPlayer
protected: