From a0be612f48032a8f340e7eee2d2b751fba92c74e Mon Sep 17 00:00:00 2001 From: sylvessa <225480449+sylvessa@users.noreply.github.com> Date: Mon, 23 Mar 2026 17:25:46 -0500 Subject: [PATCH] playsound, sleep ignoring --- Minecraft.Client/ServerLevel.cpp | 4 + Minecraft.Server.FourKit/Entity/Player.cs | 36 ++++ Minecraft.Server.FourKit/FourKitHost.cs | 12 +- Minecraft.Server.FourKit/NativeBridge.cs | 12 +- Minecraft.Server.FourKit/Sound.cs | 208 ++++++++++++++++++++++ Minecraft.Server/FourKitBridge.cpp | 30 +++- Minecraft.World/Player.h | 1 + 7 files changed, 294 insertions(+), 9 deletions(-) create mode 100644 Minecraft.Server.FourKit/Sound.cs diff --git a/Minecraft.Client/ServerLevel.cpp b/Minecraft.Client/ServerLevel.cpp index a2596911..37a2234e 100644 --- a/Minecraft.Client/ServerLevel.cpp +++ b/Minecraft.Client/ServerLevel.cpp @@ -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()) { diff --git a/Minecraft.Server.FourKit/Entity/Player.cs b/Minecraft.Server.FourKit/Entity/Player.cs index c908f5fd..85c7529b 100644 --- a/Minecraft.Server.FourKit/Entity/Player.cs +++ b/Minecraft.Server.FourKit/Entity/Player.cs @@ -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 /// True if player is sprinting. public bool isSprinting() => _sprinting; + /// + /// 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. + /// + /// Whether to ignore. + public void setSleepingIgnored(bool isSleeping) + { + _sleepingIgnored = isSleeping; + NativeBridge.SetSleepingIgnored?.Invoke(getEntityId(), isSleeping ? 1 : 0); + } + + /// + /// Returns whether the player is sleeping ignored. + /// + /// Whether player is ignoring sleep. + public bool isSleepingIgnored() => _sleepingIgnored; + + /// + /// Play a sound for a player at the location. + /// This function will fail silently if Location or Sound are null. + /// + /// The location to play the sound. + /// The sound to play. + /// The volume of the sound. + /// The pitch of the sound. + 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); + } + /// /// 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; } diff --git a/Minecraft.Server.FourKit/FourKitHost.cs b/Minecraft.Server.FourKit/FourKitHost.cs index 5d0776b3..9a8c28a8 100644 --- a/Minecraft.Server.FourKit/FourKitHost.cs +++ b/Minecraft.Server.FourKit/FourKitHost.cs @@ -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) diff --git a/Minecraft.Server.FourKit/NativeBridge.cs b/Minecraft.Server.FourKit/NativeBridge.cs index 83e35988..425892a1 100644 --- a/Minecraft.Server.FourKit/NativeBridge.cs +++ b/Minecraft.Server.FourKit/NativeBridge.cs @@ -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(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(setSneaking); SetVelocity = Marshal.GetDelegateForFunctionPointer(setVelocity); SetAllowFlight = Marshal.GetDelegateForFunctionPointer(setAllowFlight); + PlaySound = Marshal.GetDelegateForFunctionPointer(playSound); + SetSleepingIgnored = Marshal.GetDelegateForFunctionPointer(setSleepingIgnored); } } diff --git a/Minecraft.Server.FourKit/Sound.cs b/Minecraft.Server.FourKit/Sound.cs new file mode 100644 index 00000000..ea0698e4 --- /dev/null +++ b/Minecraft.Server.FourKit/Sound.cs @@ -0,0 +1,208 @@ +namespace Minecraft.Server.FourKit; + +/// +/// An Enum of Sounds the server is able to send to players. +/// +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, +} diff --git a/Minecraft.Server/FourKitBridge.cpp b/Minecraft.Server/FourKitBridge.cpp index 321f3afb..245fdcc2 100644 --- a/Minecraft.Server/FourKitBridge.cpp +++ b/Minecraft.Server/FourKitBridge.cpp @@ -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(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."); } diff --git a/Minecraft.World/Player.h b/Minecraft.World/Player.h index 74f03920..c8ca1b27 100644 --- a/Minecraft.World/Player.h +++ b/Minecraft.World/Player.h @@ -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: