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

View file

@ -17,6 +17,7 @@ public class Player : HumanEntity, OfflinePlayer, CommandSender
private bool _sneaking; private bool _sneaking;
private bool _sprinting; private bool _sprinting;
private bool _allowFlight; private bool _allowFlight;
private bool _sleepingIgnored;
internal bool IsOnline { get; set; } internal bool IsOnline { get; set; }
@ -110,6 +111,40 @@ public class Player : HumanEntity, OfflinePlayer, CommandSender
/// <returns>True if player is sprinting.</returns> /// <returns>True if player is sprinting.</returns>
public bool isSprinting() => _sprinting; 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> /// <summary>
/// Determines if the Player is allowed to fly via jump key double-tap /// Determines if the Player is allowed to fly via jump key double-tap
/// like in creative mode. /// like in creative mode.
@ -242,4 +277,5 @@ public class Player : HumanEntity, OfflinePlayer, CommandSender
internal void SetSneakingInternal(bool sneaking) => _sneaking = sneaking; internal void SetSneakingInternal(bool sneaking) => _sneaking = sneaking;
internal void SetSprintingInternal(bool sprinting) => _sprinting = sprinting; internal void SetSprintingInternal(bool sprinting) => _sprinting = sprinting;
internal void SetAllowFlightInternal(bool allowFlight) => _allowFlight = allowFlight; 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); Marshal.Copy(lens, 0, ptr, 4);
} }
// todo: rework callback funcs due to it being messy
[UnmanagedCallersOnly] [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) 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] [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 // setsneaking and setallowflight here cuz i am lazy
// should be under player stuff ill do that later // should be under player stuff ill do that later
try try
{ {
NativeBridge.SetEntityCallbacks(setSneaking, setVelocity, setAllowFlight); NativeBridge.SetEntityCallbacks(setSneaking, setVelocity, setAllowFlight, playSound, setSleepingIgnored);
} }
catch (Exception ex) 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) private static void SyncPlayerFromNative(Player player)
{ {
if (NativeBridge.GetPlayerSnapshot == null) if (NativeBridge.GetPlayerSnapshot == null)
return; return;
double[] buf = new double[20]; double[] buf = new double[21];
var gh = GCHandle.Alloc(buf, GCHandleType.Pinned); var gh = GCHandle.Alloc(buf, GCHandleType.Pinned);
try try
{ {
@ -994,6 +997,7 @@ public static class FourKitHost
player.SetOnGroundInternal(buf[15] != 0.0); player.SetOnGroundInternal(buf[15] != 0.0);
player.SetVelocityInternal(buf[16], buf[17], buf[18]); player.SetVelocityInternal(buf[16], buf[17], buf[18]);
player.SetAllowFlightInternal(buf[19] != 0.0); player.SetAllowFlightInternal(buf[19] != 0.0);
player.SetSleepingIgnoredInternal(buf[20] != 0.0);
} }
private static void BroadcastNativeMessage(string message) private static void BroadcastNativeMessage(string message)

View file

@ -126,6 +126,12 @@ internal static class NativeBridge
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate void NativeSetAllowFlightDelegate(int entityId, int allowFlight); 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 NativeDamageDelegate? DamagePlayer;
internal static NativeSetHealthDelegate? SetPlayerHealth; internal static NativeSetHealthDelegate? SetPlayerHealth;
@ -168,6 +174,8 @@ internal static class NativeBridge
internal static NativeSetSneakingDelegate? SetSneaking; internal static NativeSetSneakingDelegate? SetSneaking;
internal static NativeSetVelocityDelegate? SetVelocity; internal static NativeSetVelocityDelegate? SetVelocity;
internal static NativeSetAllowFlightDelegate? SetAllowFlight; 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) 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); 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); SetSneaking = Marshal.GetDelegateForFunctionPointer<NativeSetSneakingDelegate>(setSneaking);
SetVelocity = Marshal.GetDelegateForFunctionPointer<NativeSetVelocityDelegate>(setVelocity); SetVelocity = Marshal.GetDelegateForFunctionPointer<NativeSetVelocityDelegate>(setVelocity);
SetAllowFlight = Marshal.GetDelegateForFunctionPointer<NativeSetAllowFlightDelegate>(setAllowFlight); 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\Player.h"
#include "..\Minecraft.World\PlayerAbilitiesPacket.h" #include "..\Minecraft.World\PlayerAbilitiesPacket.h"
#include "..\Minecraft.World\SetCarriedItemPacket.h" #include "..\Minecraft.World\SetCarriedItemPacket.h"
#include "..\Minecraft.World\LevelSoundPacket.h"
#include "..\Minecraft.World\SimpleContainer.h" #include "..\Minecraft.World\SimpleContainer.h"
#include "..\Minecraft.World\Slot.h" #include "..\Minecraft.World\Slot.h"
#include "..\Minecraft.World\Tile.h" #include "..\Minecraft.World\Tile.h"
@ -175,7 +176,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); typedef void(__stdcall *fn_set_entity_callbacks)(void *setSneaking, void *setVelocity, void *setAllowFlight, void *playSound, void *setSleepingIgnored);
struct OpenContainerInfo 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) static void __cdecl NativeGetPlayerSnapshot(int entityId, double *outData)
{ {
auto player = FindPlayer(entityId); auto player = FindPlayer(entityId);
if (!player) if (!player)
{ {
memset(outData, 0, 20 * sizeof(double)); memset(outData, 0, 21 * 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;
@ -361,6 +362,7 @@ static void __cdecl NativeGetPlayerSnapshot(int entityId, double *outData)
outData[17] = player->yd; outData[17] = player->yd;
outData[18] = player->zd; outData[18] = player->zd;
outData[19] = player->abilities.mayfly ? 1.0 : 0.0; 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) 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() static std::wstring FindNet10SystemRoot()
{ {
// overengineered // overengineered
@ -1634,7 +1654,9 @@ void Initialize()
s_managedSetEntityCallbacks( s_managedSetEntityCallbacks(
(void *)&NativeSetSneaking, (void *)&NativeSetSneaking,
(void *)&NativeSetVelocity, (void *)&NativeSetVelocity,
(void *)&NativeSetAllowFlight); (void *)&NativeSetAllowFlight,
(void *)&NativePlaySound,
(void *)&NativeSetSleepingIgnored);
LogInfo("fourkit", "FourKit initialized successfully."); LogInfo("fourkit", "FourKit initialized successfully.");
} }

View file

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