From d8da9af7fe2f2bb8778b808f5a7738283bfa337c Mon Sep 17 00:00:00 2001 From: Logan Gibson Date: Sun, 12 Apr 2026 04:18:03 -0700 Subject: [PATCH 1/8] Add particles when fishing (#1) Co-authored-by: Lord_Cambion --- Minecraft.Client/LevelRenderer.cpp | 6 +- Minecraft.Client/ParticleEngine.cpp | 2 +- Minecraft.Client/WaterWakeParticle.cpp | 47 ++++ Minecraft.Client/WaterWakeParticle.h | 10 + Minecraft.Client/cmake/sources/Common.cmake | 2 + Minecraft.Server/cmake/sources/Common.cmake | 5 +- Minecraft.World/Class.h | 4 + Minecraft.World/FishingHook.cpp | 278 +++++++++++++++----- Minecraft.World/FishingHook.h | 18 +- Minecraft.World/ParticleTypes.h | 1 + configure_cmake.bat | 4 + 11 files changed, 301 insertions(+), 76 deletions(-) create mode 100644 Minecraft.Client/WaterWakeParticle.cpp create mode 100644 Minecraft.Client/WaterWakeParticle.h create mode 100644 configure_cmake.bat diff --git a/Minecraft.Client/LevelRenderer.cpp b/Minecraft.Client/LevelRenderer.cpp index 0a18d936..9639012c 100644 --- a/Minecraft.Client/LevelRenderer.cpp +++ b/Minecraft.Client/LevelRenderer.cpp @@ -21,6 +21,7 @@ #include "LavaParticle.h" #include "FootstepParticle.h" #include "SplashParticle.h" +#include "WaterWakeParticle.h" #include "SmokeParticle.h" #include "RedDustParticle.h" #include "BreakingItemParticle.h" @@ -2709,7 +2710,7 @@ shared_ptr LevelRenderer::addParticleInternal(ePARTICLE_TYPE eParticle // 4J - the java code doesn't distance cull these two particle types, we need to implement this behaviour differently as our distance check is // mixed up with other things bool distCull = true; - if ( (eParticleType == eParticleType_hugeexplosion) || (eParticleType == eParticleType_largeexplode) || (eParticleType == eParticleType_dragonbreath) ) + if ( (eParticleType == eParticleType_hugeexplosion) || (eParticleType == eParticleType_largeexplode) || (eParticleType == eParticleType_dragonbreath) || (eParticleType == eParticleType_wake)) { distCull = false; } @@ -2882,6 +2883,9 @@ shared_ptr LevelRenderer::addParticleInternal(ePARTICLE_TYPE eParticle case eParticleType_splash: particle = std::make_shared(lev, x, y, z, xa, ya, za); break; + case eParticleType_wake: + particle = std::make_shared(lev, x, y, z, xa, ya, za); + break; case eParticleType_largesmoke: particle = std::make_shared(lev, x, y, z, xa, ya, za, 2.5f); break; diff --git a/Minecraft.Client/ParticleEngine.cpp b/Minecraft.Client/ParticleEngine.cpp index 7cb051cd..a5385347 100644 --- a/Minecraft.Client/ParticleEngine.cpp +++ b/Minecraft.Client/ParticleEngine.cpp @@ -12,6 +12,7 @@ #include "../Minecraft.World/net.minecraft.world.level.h" #include "../Minecraft.World/StringHelpers.h" #include "../Minecraft.World/net.minecraft.world.level.dimension.h" +#include "../Minecraft.World/InputOutputStream.h" ResourceLocation ParticleEngine::PARTICLES_LOCATION = ResourceLocation(TN_PARTICLES); @@ -49,7 +50,6 @@ void ParticleEngine::add(shared_ptr p) break; } int list = p->getAlpha() != 1.0f ? TRANSLUCENT_LIST : OPAQUE_LIST; // 4J - Brought forward from Java 1.8 - if( particles[l][t][list].size() >= maxParticles) { particles[l][t][list].pop_front(); diff --git a/Minecraft.Client/WaterWakeParticle.cpp b/Minecraft.Client/WaterWakeParticle.cpp new file mode 100644 index 00000000..aedb628f --- /dev/null +++ b/Minecraft.Client/WaterWakeParticle.cpp @@ -0,0 +1,47 @@ +#include "stdafx.h" +#include "WaterWakeParticle.h" +#include "../Minecraft.World/Random.h" +#include "../Minecraft.World/Mth.h" +#include "../Minecraft.World/JavaMath.h" +#include "../Minecraft.World/net.minecraft.world.level.h" +#include "../Minecraft.World/net.minecraft.world.level.material.h" +#include "../Minecraft.World/net.minecraft.world.level.tile.h" + +WaterWakeParticle::WaterWakeParticle(Level *level, double x, double y, double z, double xa, double ya, double za) : Particle(level, x, y, z, 0, 0, 0) +{ + xd *= 0.30000001192092896; + yd = random->nextDouble() * 0.2 + 0.1; + zd *= 0.30000001192092896; + rCol = 1.0f; + gCol = 1.0f; + bCol = 1.0f; + setMiscTex(19); + setSize(0.01f, 0.01f); + lifetime = (int)(8.0 / (random->nextDouble() * 0.8 + 0.2)); + gravity = 0.0F; + xd = xa; + yd = ya; + zd = za; +} + +void WaterWakeParticle::tick() +{ + xo = x; + yo = y; + zo = z; + + move(xd, yd, zd); + xd *= 0.9800000190734863; + yd *= 0.9800000190734863; + zd *= 0.9800000190734863; + + int i = 60 - lifetime; + float f = (float)i * 0.001f; + this->setSize(f, f); + this->setMiscTex(19 + i % 4); + + if (lifetime-- <= 0) + { + this->remove(); + } +} \ No newline at end of file diff --git a/Minecraft.Client/WaterWakeParticle.h b/Minecraft.Client/WaterWakeParticle.h new file mode 100644 index 00000000..2e6a32af --- /dev/null +++ b/Minecraft.Client/WaterWakeParticle.h @@ -0,0 +1,10 @@ +#pragma once +#include "Particle.h" + +class WaterWakeParticle : public Particle +{ +public: + virtual eINSTANCEOF GetType() { return eType_WAKEPARTICLE; } + WaterWakeParticle(Level *level, double x, double y, double z, double xa, double ya, double za); + virtual void tick(); +}; \ No newline at end of file diff --git a/Minecraft.Client/cmake/sources/Common.cmake b/Minecraft.Client/cmake/sources/Common.cmake index b5024e9a..26cae6c5 100644 --- a/Minecraft.Client/cmake/sources/Common.cmake +++ b/Minecraft.Client/cmake/sources/Common.cmake @@ -715,6 +715,8 @@ set(_MINECRAFT_CLIENT_COMMON_NET_MINECRAFT_CLIENT_PARTICLE "${CMAKE_CURRENT_SOURCE_DIR}/SpellParticle.h" "${CMAKE_CURRENT_SOURCE_DIR}/SplashParticle.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/SplashParticle.h" + "${CMAKE_CURRENT_SOURCE_DIR}/WaterWakeParticle.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/WaterWakeParticle.h" "${CMAKE_CURRENT_SOURCE_DIR}/SuspendedParticle.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/SuspendedParticle.h" "${CMAKE_CURRENT_SOURCE_DIR}/SuspendedTownParticle.cpp" diff --git a/Minecraft.Server/cmake/sources/Common.cmake b/Minecraft.Server/cmake/sources/Common.cmake index 5f3bd7f1..c966fa12 100644 --- a/Minecraft.Server/cmake/sources/Common.cmake +++ b/Minecraft.Server/cmake/sources/Common.cmake @@ -17,7 +17,8 @@ set(_MINECRAFT_SERVER_COMMON_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/../Minecraft.Client/BookModel.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/../Minecraft.Client/BossMobGuiInfo.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/../Minecraft.Client/BreakingItemParticle.cpp" - "${CMAKE_CURRENT_SOURCE_DIR}/../Minecraft.Client/BubbleParticle.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/../Minecraft.Client/BubbleParticle.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/../Minecraft.Client/WaterWakeParticle.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/../Minecraft.Client/BufferedImage.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/../Minecraft.Client/Button.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/../Minecraft.Client/Camera.cpp" @@ -499,6 +500,8 @@ set(_MINECRAFT_SERVER_COMMON_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/../Minecraft.Client/Xbox/Network/NetworkPlayerXbox.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/../Minecraft.Client/ZombieModel.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/../Minecraft.Client/ZombieRenderer.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/../Minecraft.Client/GuardianModel.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/../Minecraft.Client/GuardianRenderer.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/../Minecraft.Client/compat_shims.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/../Minecraft.Client/glWrapper.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/../Minecraft.Client/iob_shim.asm" diff --git a/Minecraft.World/Class.h b/Minecraft.World/Class.h index 058cffd9..71b9df55 100644 --- a/Minecraft.World/Class.h +++ b/Minecraft.World/Class.h @@ -292,6 +292,9 @@ enum eINSTANCEOF eType_FIREWORKSSPARKPARTICLE, eType_FIREWORKSOVERLAYPARTICLE, + //TU 31 + eType_WAKEPARTICLE, + // === Tile Entities === // eTYPE_TILEENTITY = BIT_TILE_ENTITY, @@ -503,6 +506,7 @@ public: classes->push_back( SUBCLASS(eType_SMOKEPARTICLE)->addParent(eTYPE_ENTITY) ); classes->push_back( SUBCLASS(eType_SNOWSHOVELPARTICLE)->addParent(eTYPE_ENTITY) ); classes->push_back( SUBCLASS(eType_SPLASHPARTICLE)->addParent(eTYPE_ENTITY) ); + classes->push_back( SUBCLASS(eType_WAKEPARTICLE)->addParent(eTYPE_ENTITY) ); classes->push_back( SUBCLASS(eType_TAKEANIMATIONPARTICLE)->addParent(eTYPE_ENTITY) ); classes->push_back( SUBCLASS(eType_TERRAINPARTICLE)->addParent(eTYPE_ENTITY) ); classes->push_back( SUBCLASS(eType_WATERDROPPARTICLE)->addParent(eTYPE_ENTITY) ); diff --git a/Minecraft.World/FishingHook.cpp b/Minecraft.World/FishingHook.cpp index 1d2de0ad..a95fd8d9 100644 --- a/Minecraft.World/FishingHook.cpp +++ b/Minecraft.World/FishingHook.cpp @@ -15,9 +15,18 @@ #include "../Minecraft.World/EnchantmentHelper.h" #include "../Minecraft.World/Enchantment.h" #include "../Minecraft.World/ItemInstance.h" +#include "SynchedEntityData.h" #include -// 4J - added common ctor code. + +const int FishingHook::DATA_FLAG_RENDER_CLIENT_FX = 20; +const int FishingHook::DATA_FISH_APPROACH_ANGLE = 21; +const int FishingHook::DATA_WAKE_TIMER = 22; +const int FishingHook::DATA_NIBBLE_TIMER = 23; +const int FishingHook::DATA_FLAG_NIBBLE = 24; + + +// 4J - added common ctor code. void FishingHook::_init() { // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that @@ -31,14 +40,16 @@ void FishingHook::_init() inGround = false; shakeTime = 0; flightTime = 0; - nibble = 0; // TU 31: Fishing rod now has a random nibble timer between 5 and 30 seconds, instead of a 1/500 chance every tick (plus modifiers). Source: https://minecraft.wiki/w/Fishing - nibbleTimer = random->nextInt(801) + 100; - lureTime = 0; hookedIn = nullptr; previousItem = nullptr; + fishApproachAngle = 0.0f; + wakeTimer = 0; + nibble = 0; + nibbleTimer = 0; + lureLevel = 0; luckLevel = 0; @@ -113,6 +124,11 @@ void FishingHook::getEnchantLevels() { void FishingHook::defineSynchedData() { + entityData->define(FishingHook::DATA_FLAG_RENDER_CLIENT_FX, (short)0); + entityData->define(FishingHook::DATA_FISH_APPROACH_ANGLE, 0.0f); + entityData->define(FishingHook::DATA_WAKE_TIMER, (short)0); + entityData->define(FishingHook::DATA_NIBBLE_TIMER, (short)0); + entityData->define(FishingHook::DATA_FLAG_NIBBLE, (short)0); } bool FishingHook::shouldRenderAtSqrDistance(double distance) @@ -336,7 +352,7 @@ void FishingHook::tick() inertia = 0.5f; } - int steps = 5; + int steps = 10; double waterPercentage = 0; for (int i = 0; i < steps; i++) { @@ -351,72 +367,19 @@ void FishingHook::tick() if (waterPercentage > 0) { - if (nibble > 0) - { - - nibble--; - } - else - { - - if (!(level->canSeeSky(Mth::floor(x), Mth::floor(y) + 1, Mth::floor(z)))) { - // Don't minus the nibbleTimer if the hook obstructed from the sky. - } - // TU 31: Raining affects the nibble timer by random chance rather than being a fixed rate. Source: https://minecraft.wiki/w/Fishing - else if (!(level->isRainingAt( Mth::floor(x), Mth::floor(y) + 1, Mth::floor(z)))) { - nibbleTimer--; - } - - else { - if (random->nextInt(4) == 0) { - nibbleTimer -= 2; - } - else { - nibbleTimer--; - } - } - - // Only calculate the effect of lure if it hasn't been calculated already. - if (lureTime == 0 && owner != nullptr) - { - lureTime = this->lureLevel * 100; - nibbleTimer -= lureTime; - // if the lure effect causes the nibble timer to go below 0, reset the timer and lure time to recalculate next tick. Source: https://minecraft.wiki/w/Fishing - if (nibbleTimer < 0) - { - nibbleTimer = random->nextInt(801) + 100; - lureTime = 0; - } - } - - // Checks if the nibble timer has ran out. Edge case for if it's raining and the nibble timer goes - // below 0 due to the random chance of the rain decreasing the timer by 2 instead of 1. - if (nibbleTimer == 0 || nibbleTimer == -1) - { - nibble = random->nextInt(11) + 30; - nibbleTimer = random->nextInt(801) + 100; - lureTime = 0; - yd -= 0.2f; - playSound(eSoundType_RANDOM_SPLASH, 0.25f, 1 + (random->nextFloat() - random->nextFloat()) * 0.4f); - float yt = static_cast(Mth::floor(bb->y0)); - for (int i = 0; i < 1 + bbWidth * 20; i++) - { - float xo = (random->nextFloat() * 2 - 1) * bbWidth; - float zo = (random->nextFloat() * 2 - 1) * bbWidth; - level->addParticle(eParticleType_bubble, x + xo, yt + 1, z + zo, xd, yd - random->nextFloat() * 0.2f, zd); - } - for (int i = 0; i < 1 + bbWidth * 20; i++) - { - float xo = (random->nextFloat() * 2 - 1) * bbWidth; - float zo = (random->nextFloat() * 2 - 1) * bbWidth; - level->addParticle(eParticleType_splash, x + xo, yt + 1, z + zo, xd, yd, zd); - } - } + if (!level->isClientSide) { + catchingFish(); + } - } - - if (nibble > 0) + if (level->isClientSide) { + applyClientFX(); + if (entityData->getShort(FishingHook::DATA_FLAG_NIBBLE) != 0) + { + yd -= random->nextFloat() * random->nextFloat() * random->nextFloat() * 0.2; + } + } + else if (nibble > 0) { yd -= random->nextFloat() * random->nextFloat() * random->nextFloat() * 0.2; } @@ -444,6 +407,177 @@ void FishingHook::addAdditonalSaveData(CompoundTag *tag) tag->putByte(L"inTile", static_cast(lastTile)); tag->putByte(L"shake", static_cast(shakeTime)); tag->putByte(L"inGround", static_cast(inGround ? 1 : 0)); + tag->putFloat(L"fishApproachAngle", fishApproachAngle); + tag->putShort(L"wakeTimer", static_cast(wakeTimer)); + tag->putShort(L"nibbleTimer", static_cast(nibbleTimer)); + tag->putShort(L"nibble", static_cast(nibble)); +} + +void FishingHook::catchingFish() { + int timerSubtractor = 1; + // Being under roof increases fishing time + if (!(level->canSeeSky(Mth::floor(x), Mth::floor(y) + 1, Mth::floor(z)) && random->nextInt(2) == 0)) { + timerSubtractor--; + } + // TU 31: Raining affects the nibble timer by random chance rather than being a fixed rate. Source: https://minecraft.wiki/w/Fishing + if (level->isRainingAt( Mth::floor(x), Mth::floor(y) + 1, Mth::floor(z)) && random->nextInt(4) == 0) { + timerSubtractor++; + } + + if (nibble > 0) + { + nibble -= 1; + if (nibble <= 0) + { + nibbleTimer = 0; + wakeTimer = 0; + } + } + + else + { + if (wakeTimer > 0) + { + wakeTimer -= timerSubtractor; + + if (wakeTimer <= 0) + { + yd -= 0.2f; + playSound(eSoundType_RANDOM_SPLASH, 0.25f, 1.0f + (random->nextFloat() - random->nextFloat()) * 0.4f); + nibble = random->nextInt(11) + 30; + } + else + { + fishApproachAngle += (float)(random->nextGaussian() * 4.0); + } + } + else if ( nibbleTimer>0 ) { + nibbleTimer -= timerSubtractor; + if (nibbleTimer <= 0) + { + fishApproachAngle = random->nextFloat() * 360.0f; + wakeTimer = random->nextInt(61) + 20; + } + } + else + { + nibbleTimer = random->nextInt(801) + 100 - lureLevel * 100; + } + } + updateSynchedData(); +} + +// I guess I have to use UK spelling :( +void FishingHook::updateSynchedData() { + short nibbleFlag = (nibble > 0) ? 1 : 0; + if (nibble > 0 && entityData->getShort(FishingHook::DATA_FLAG_RENDER_CLIENT_FX) != 1) { + entityData->set(FishingHook::DATA_FLAG_RENDER_CLIENT_FX, 1); // Render Nibble FX + } + // Flags and synced data are only updated if they have changed. + else if (wakeTimer > 0 && entityData->getShort(FishingHook::DATA_FLAG_RENDER_CLIENT_FX) != 2) { + entityData->set(FishingHook::DATA_FLAG_RENDER_CLIENT_FX, 2); // Render Wake FX + } + + else if (nibbleTimer > 0 && entityData->getShort(FishingHook::DATA_FLAG_RENDER_CLIENT_FX) != 3) { + entityData->set(FishingHook::DATA_FLAG_RENDER_CLIENT_FX, 3); // Render Fishing FX + } + + else if (entityData->getShort(FishingHook::DATA_FLAG_RENDER_CLIENT_FX) != 0){ + entityData->set(FishingHook::DATA_FLAG_RENDER_CLIENT_FX, 0); // Render Nothing + } + + if (entityData->getFloat(FishingHook::DATA_FISH_APPROACH_ANGLE) != fishApproachAngle) { + entityData->set(FishingHook::DATA_FISH_APPROACH_ANGLE, fishApproachAngle); + } + if (entityData->getShort(FishingHook::DATA_NIBBLE_TIMER) != nibbleTimer) { + entityData->set(FishingHook::DATA_NIBBLE_TIMER, nibbleTimer); + } + if (entityData->getShort(FishingHook::DATA_WAKE_TIMER) != wakeTimer) { + entityData->set(FishingHook::DATA_WAKE_TIMER, wakeTimer); + } + + // Nibble flag is only updated if it has changed. + if (entityData->getShort(FishingHook::DATA_FLAG_NIBBLE) != nibbleFlag) { + entityData->set(FishingHook::DATA_FLAG_NIBBLE, nibbleFlag); + } +} + +void FishingHook::applyClientFX() { + float f; + float particleY; + float particleZ; + float particleX; + float xDir; + float zDir; + float xVel; + float zVel; + float yt = static_cast(Mth::floor(bb->y0) + 1.0); + int clientWakeTimer; + int clientNibbleTimer; + + + switch (entityData->getShort(FishingHook::DATA_FLAG_RENDER_CLIENT_FX)) { + case 1: + yd -= 0.2f; + playSound(eSoundType_RANDOM_SPLASH, 0.25f, 1.0f + (random->nextFloat() - random->nextFloat()) * 0.4f); + for (int i = 0; i < 1 + bbWidth * 20; i++) + { + level->addParticle(eParticleType_bubble, x, yt, z, bbWidth, 0, bbWidth); + } + for (int i = 0; i < 1 + bbWidth * 20; i++) + { + level->addParticle(eParticleType_wake, x, yt, z, bbWidth, 0, bbWidth); + } + break; + case 2: + f = entityData->getFloat(FishingHook::DATA_FISH_APPROACH_ANGLE) * 0.017453292f; + xDir = Mth::sin(f); + zDir = Mth::cos(f); + clientWakeTimer = entityData->getShort(FishingHook::DATA_WAKE_TIMER); + particleX = x + (xDir * (float)clientWakeTimer * 0.1f); + particleZ = z+ (zDir * (float)clientWakeTimer * 0.1f); + + if (random->nextFloat() < 0.15f) + { + level->addParticle(eParticleType_bubble, particleX, yt - 0.10000000149011612, particleZ, xDir, 0.1, zDir); + } + + zVel = xDir * 0.04F; + xVel = zDir * 0.04F; + + level->addParticle(eParticleType_wake, particleX, yt, particleZ, xVel, 0.01, (-zVel)); + level->addParticle(eParticleType_wake, particleX, yt, particleZ, (-xVel), 0.01, zVel); + break; + case 3: + f = 0.15F; + clientNibbleTimer = entityData->getShort(FishingHook::DATA_NIBBLE_TIMER); + if (clientNibbleTimer < 20) + { + f = f + (float)(20 - clientNibbleTimer) * 0.05f; + } + else if (clientNibbleTimer < 40) + { + f = (float)(40 - clientNibbleTimer) * 0.02f; + } + else if (clientNibbleTimer < 60) + { + f = (float)(60 - clientNibbleTimer) * 0.01f; + } + + if (random->nextFloat() < f) + { + xDir = random->nextFloat() * 360.0f * 0.017453292f; + zDir = (random->nextFloat() * 45.0f) + 25.0f; + particleX = x + (Mth::sin(xDir) * zDir * 0.1f); + particleY = Mth::floor(bb->y0) + 1.0; + particleZ = z + (Mth::cos(xDir) * zDir * 0.1f); + for (int i = 0; i < 2 + random->nextInt(2); i++) + { + level->addParticle(eParticleType_splash, particleX, particleY, particleZ, 0.10000000149011612, 0.0, 0.10000000149011612); + } + } + break; + } } void FishingHook::readAdditionalSaveData(CompoundTag *tag) @@ -454,6 +588,11 @@ void FishingHook::readAdditionalSaveData(CompoundTag *tag) lastTile = tag->getByte(L"inTile") & 0xff; shakeTime = tag->getByte(L"shake") & 0xff; inGround = tag->getByte(L"inGround") == 1; + fishApproachAngle = tag->getFloat(L"fishApproachAngle"); + wakeTimer = tag->getShort(L"wakeTimer"); + nibbleTimer = tag->getShort(L"nibbleTimer"); + nibble = tag->getShort(L"nibble"); + entityData->set(FishingHook::DATA_FLAG_NIBBLE, (nibble > 0) ? 1 : 0); } float FishingHook::getShadowHeightOffs() @@ -500,7 +639,6 @@ int FishingHook::retrieve() if (inGround) dmg = 2; remove(); - owner->fishing = nullptr; return dmg; } diff --git a/Minecraft.World/FishingHook.h b/Minecraft.World/FishingHook.h index 23af71ab..a7c3f2c9 100644 --- a/Minecraft.World/FishingHook.h +++ b/Minecraft.World/FishingHook.h @@ -25,14 +25,23 @@ public: private: int life; int flightTime; - int nibble; - int nibbleTimer; - int lureTime; int lureLevel; int luckLevel; shared_ptr previousItem; + int wakeTimer; + int nibbleTimer; + int nibble; + float fishApproachAngle; + +private: + static const int DATA_FLAG_RENDER_CLIENT_FX; + static const int DATA_FISH_APPROACH_ANGLE; + static const int DATA_WAKE_TIMER; + static const int DATA_NIBBLE_TIMER; + static const int DATA_FLAG_NIBBLE; + public: shared_ptr hookedIn; @@ -61,6 +70,9 @@ public: virtual void lerpMotion(double xd, double yd, double zd); virtual void tick(); virtual void addAdditonalSaveData(CompoundTag *tag); + void catchingFish(); + void updateSynchedData(); + void applyClientFX(); virtual void readAdditionalSaveData(CompoundTag *tag); virtual float getShadowHeightOffs(); virtual void getEnchantLevels(); diff --git a/Minecraft.World/ParticleTypes.h b/Minecraft.World/ParticleTypes.h index ecc2ab96..4bb3e360 100644 --- a/Minecraft.World/ParticleTypes.h +++ b/Minecraft.World/ParticleTypes.h @@ -13,6 +13,7 @@ enum ePARTICLE_TYPE eParticleType_lava, eParticleType_footstep, eParticleType_splash, + eParticleType_wake, eParticleType_largesmoke, eParticleType_reddust, eParticleType_snowballpoof, diff --git a/configure_cmake.bat b/configure_cmake.bat new file mode 100644 index 00000000..f4942dd2 --- /dev/null +++ b/configure_cmake.bat @@ -0,0 +1,4 @@ +"C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\Tools\VsDevCmd.bat" +"C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat" +cd C:\Users\logat\OneDrive\Documents\GitHub\LegacyEvolved +cmake --preset windows64 \ No newline at end of file From e0700871c7d503db55cdae036dc0b573e0afca79 Mon Sep 17 00:00:00 2001 From: /home/neo <158327205+neoapps-dev@users.noreply.github.com> Date: Sun, 12 Apr 2026 14:32:46 +0300 Subject: [PATCH 2/8] fix: CI --- .github/workflows/nightly.yml | 53 +++++++++++++---------------------- 1 file changed, 20 insertions(+), 33 deletions(-) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 73db0173..b74ddf78 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -1,6 +1,9 @@ name: Nightly Release on: + push: + branches: + - main workflow_dispatch: permissions: @@ -40,8 +43,8 @@ jobs: shell: pwsh run: | $source = "./build/windows64/Minecraft.Client/Release" - $zip = "LCREWindows64.zip" - $topLevel = "LCREWindows64" + $zip = "neoLegacyWindows64.zip" + $topLevel = "neoLegacyWindows64" # Collect files, excluding unwanted extensions $files = Get-ChildItem -Path $source -Recurse -File | @@ -78,7 +81,7 @@ jobs: shell: pwsh run: | New-Item -ItemType Directory -Force -Path staging - Copy-Item LCREWindows64.zip staging/ + Copy-Item neoLegacyWindows64.zip staging/ Copy-Item ./build/windows64/Minecraft.Client/Release/Minecraft.Client.exe staging/ - name: Upload artifacts @@ -114,8 +117,8 @@ jobs: shell: pwsh run: | $source = "./build/windows64/Minecraft.Server/Release" - $zip = "LCREServerWindows64.zip" - $topLevel = "LCREServerWindows64" + $zip = "neoLegacyServerWindows64.zip" + $topLevel = "neoLegacyServerWindows64" $files = Get-ChildItem -Path $source -Recurse -File | Where-Object { $_.Extension -notin '.pch', '.zip', '.ipdb', '.iobj' } @@ -149,7 +152,7 @@ jobs: shell: pwsh run: | New-Item -ItemType Directory -Force -Path staging - Copy-Item LCREServerWindows64.zip staging/ + Copy-Item neoLegacyServerWindows64.zip staging/ - name: Upload artifacts uses: actions/upload-artifact@v6 @@ -176,7 +179,7 @@ jobs: uses: actions/attest-build-provenance@v2 with: subject-path: | - artifacts/LCREServerWindows64.zip + artifacts/neoLegacyServerWindows64.zip - name: Get short SHA id: sha @@ -192,17 +195,9 @@ jobs: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: gh api repos/${{ github.repository }}/git/refs/tags/Nightly-Dedicated-Server --method DELETE || true - - name: Import GPG key - uses: crazy-max/ghaction-import-gpg@v6 - with: - gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }} - passphrase: ${{ secrets.GPG_PASSPHRASE }} - git_user_signingkey: true - git_tag_gpgsign: true - - - name: Create signed tag + - name: Create tag run: | - git tag -s -f Nightly-Dedicated-Server -m "Nightly server release ${{ steps.sha.outputs.short }}" + git tag -f Nightly-Dedicated-Server -m "Nightly server release ${{ steps.sha.outputs.short }}" git push origin Nightly-Dedicated-Server --force - name: Create release @@ -213,7 +208,7 @@ jobs: --title "Server: ${{ steps.sha.outputs.short }}" \ --notes "Dedicated Server runtime for Windows64. - Download \`LCREServerWindows64.zip\` and extract it to a folder where you'd like to keep the server runtime." \ + Download \`neoLegacyServerWindows64.zip\` and extract it to a folder where you'd like to keep the server runtime." \ --latest=false release-client: @@ -235,7 +230,7 @@ jobs: uses: actions/attest-build-provenance@v2 with: subject-path: | - artifacts/LCREWindows64.zip + artifacts/neoLegacyWindows64.zip artifacts/Minecraft.Client.exe - name: Get short SHA @@ -252,17 +247,9 @@ jobs: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: gh api repos/${{ github.repository }}/git/refs/tags/Nightly --method DELETE || true - - name: Import GPG key - uses: crazy-max/ghaction-import-gpg@v6 - with: - gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }} - passphrase: ${{ secrets.GPG_PASSPHRASE }} - git_user_signingkey: true - git_tag_gpgsign: true - - name: Create signed tag run: | - git tag -s -f Nightly -m "Nightly release ${{ steps.sha.outputs.short }}" + git tag -f Nightly -m "Nightly release ${{ steps.sha.outputs.short }}" git push origin Nightly --force - name: Write release notes @@ -270,15 +257,15 @@ jobs: cat > notes.md <<'NOTES' # Instructions: **Newcomers:** - - If this is your first time, download `LCREWindows64.zip` and extract it wherever you would like to keep it. + - If this is your first time, download `neoLegacyWindows64.zip` and extract it wherever you would like to keep it. - I would recommend to set your username prior to launch (create a file called `username.txt`, put your desired username into the file, and save). - To play, simply run `Minecraft.Client.exe`. **For those that wish to update their existing installation with the latest build:** - - Download `Minecraft.Client.exe` and `Minecraft.Client.pdb` and copy them over to your existing LCREWindows64 build (overwrite your old version of Minecraft.Client.exe and Minecraft.Client.pdb). + - Download `Minecraft.Client.exe` and `Minecraft.Client.pdb` and copy them over to your existing neoLegacyWindows64 build (overwrite your old version of Minecraft.Client.exe and Minecraft.Client.pdb). **Steam Deck & Linux:** - - Y'all know the drill. Download the `LCREWindows64.zip`, extract it, add the `Minecraft.Client.exe` as a "Non-Steam Game" within the Steam library, turn on compatibility mode with Proton Experimental, and then run it! + - Y'all know the drill. Download the `neoLegacyWindows64.zip`, extract it, add the `Minecraft.Client.exe` as a "Non-Steam Game" within the Steam library, turn on compatibility mode with Proton Experimental, and then run it! # Multiplayer instructions: LAN games are natively supported, and any LAN games will appear automatically on the right. However, if you'd like to play with your friends online (and if you don't want to require them to setup a vpn, and/or if you don't want to port forward), I would recommend the following setup. Please keep in mind, you do NOT need to do this to enjoy the game. This is just how I have it setup for me so my friends can join without any hassle: @@ -289,7 +276,7 @@ jobs: How-to: - Ensure your playit.gg agent is connected to your playit.gg account - - On the playit.gg website, setup a new tunnel (choose TCP). Ensure the configurable settings are set to the below values, assuming your agent is installed on the same computer as your online LCREMinecraft game is hosted from. + - On the playit.gg website, setup a new tunnel (choose TCP). Ensure the configurable settings are set to the below values, assuming your agent is installed on the same computer as your online neoLegacyMinecraft game is hosted from. - Configurable settings: - Local IP: `127.0.0.1` - Local Port: `25565` @@ -321,4 +308,4 @@ jobs: with: name: | client-build - server-build \ No newline at end of file + server-build From 53e50647e0a20ed31f5898f10828bcefa4892114 Mon Sep 17 00:00:00 2001 From: /home/neo <158327205+neoapps-dev@users.noreply.github.com> Date: Sun, 12 Apr 2026 14:44:53 +0300 Subject: [PATCH 3/8] fix: CI part 2 --- .github/workflows/nightly.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index b74ddf78..6a0d9ee5 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -197,6 +197,8 @@ jobs: - name: Create tag run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" git tag -f Nightly-Dedicated-Server -m "Nightly server release ${{ steps.sha.outputs.short }}" git push origin Nightly-Dedicated-Server --force @@ -249,6 +251,8 @@ jobs: - name: Create signed tag run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" git tag -f Nightly -m "Nightly release ${{ steps.sha.outputs.short }}" git push origin Nightly --force From 5be165439208e0c1d576d401a07222bc9ea587a4 Mon Sep 17 00:00:00 2001 From: piebot Date: Sun, 12 Apr 2026 14:48:05 +0300 Subject: [PATCH 4/8] chore: update emerald launcher url --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index aaf80952..07726fc5 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ This project aims to backport the newer title updates back to Legacy Console Edition (which is based on TU19). [![Discord](https://img.shields.io/badge/Discord-Join%20Server-5865F2?logo=discord&logoColor=white)](https://discord.gg/D6hEPNYeyn) -[![Discord](https://img.shields.io/badge/Get_it_on-Emerald_Launcher-3fc724)](https://discord.gg/D6hEPNYeyn) +[![Emerald Launcher](https://img.shields.io/badge/Get_it_on-Emerald_Launcher-3fc724)](https://github.com/LCE-Hub/LCE-Emerald-Launcher) # Our roadmap: ![Roadmap](.gitea/roadmap.png) From e45d5dd7cdbc60b4fc732733203b0ca3ee3b51e3 Mon Sep 17 00:00:00 2001 From: Lord_Cambion Date: Sun, 12 Apr 2026 16:10:56 +0200 Subject: [PATCH 5/8] fix: Monument Entry + room Generation --- Minecraft.World/OceanMonumentPieces.cpp | 83 ++++++++++++------------- 1 file changed, 41 insertions(+), 42 deletions(-) diff --git a/Minecraft.World/OceanMonumentPieces.cpp b/Minecraft.World/OceanMonumentPieces.cpp index 8882c073..4cb9f536 100644 --- a/Minecraft.World/OceanMonumentPieces.cpp +++ b/Minecraft.World/OceanMonumentPieces.cpp @@ -381,44 +381,43 @@ std::vector OceanMonumentPieces::MonumentB entryRoom = grid[ENTRY_INDEX]; - for (int x = 0; x < 5; ++x) - for (int y = 0; y < 3; ++y) - for (int z = 0; z < 5; ++z) - { - int idx = Piece::roomIndex(x, y, z); - if (grid[idx] == nullptr) continue; - - - static const int dx[6] = { 0, 0, 0, 0,-1, 1 }; - static const int dy[6] = {-1, 1, 0, 0, 0, 0 }; - static const int dz[6] = { 0, 0,-1, 1, 0, 0 }; - static const int oppFacing[6] = { 1, 0, 3, 2, 5, 4 }; - - for (int f = 0; f < 6; ++f) + for (int x = 0; x < 5; ++x) + for (int y = 0; y < 3; ++y) + for (int z = 0; z < 5; ++z) { - int nx = x + dx[f]; - int ny = y + dy[f]; - int nz = z + dz[f]; - if (nx < 0 || nx >= 5 || ny < 0 || ny >= 3 || nz < 0 || nz >= 5) continue; - int nidx = Piece::roomIndex(nx, ny, nz); - if (grid[nidx] == nullptr) continue; + int idx = Piece::roomIndex(x, y, z); + if (grid[idx] == nullptr) continue; - - if (nidx <= idx) continue; + for (int f = 0; f < 6; ++f) + { + int nx = x + Facing::STEP_X[f]; + int ny = y + Facing::STEP_Y[f]; + int nz = z + Facing::STEP_Z[f]; + if (nx < 0 || nx >= 5 || ny < 0 || ny >= 3 || nz < 0 || nz >= 5) continue; + int nidx = Piece::roomIndex(nx, ny, nz); + if (grid[nidx] == nullptr) continue; + //if (nidx <= idx) continue; - if (nz != z) - { - - int opp = (f % 2 == 0) ? f + 1 : f - 1; - grid[idx]->connectTo(opp, grid[nidx]); - } - else - { - grid[idx]->connectTo(f, grid[nidx]); + + if (nz != z) + { + + + + + + + + + int opp = Facing::OPPOSITE_FACING[f]; + grid[idx]->connectTo(opp, grid[nidx]); + } + else + { + grid[idx]->connectTo(f, grid[nidx]); + } } } - } - RoomDefinition* specialUp = new RoomDefinition(1003); RoomDefinition* specialWing1 = new RoomDefinition(1001); @@ -1482,15 +1481,15 @@ OceanMonumentPieces::EntryRoom::EntryRoom(int facing, RoomDefinition* room) bool OceanMonumentPieces::EntryRoom::postProcess(Level* level, Random* random, BoundingBox* chunkBB) { - generateBox(level, chunkBB, 0, 1, 0, 2, 1, 2, Tile::prismarine_Id, blockPrismarineBricks(),Tile::prismarine_Id, blockPrismarineBricks(), false); - generateBox(level, chunkBB, 5, 3, 0, 7, 3, 7, Tile::prismarine_Id, blockPrismarineBricks(),Tile::prismarine_Id, blockPrismarineBricks(), false); - generateBox(level, chunkBB, 6, 2, 0, 7, 2, 7, Tile::prismarine_Id, blockPrismarineBricks(),Tile::prismarine_Id, blockPrismarineBricks(), false); - generateBox(level, chunkBB, 0, 2, 0, 1, 2, 7, Tile::prismarine_Id, blockPrismarineBricks(),Tile::prismarine_Id, blockPrismarineBricks(), false); - generateBox(level, chunkBB, 0, 1, 0, 0, 1, 7, Tile::prismarine_Id, blockPrismarineBricks(),Tile::prismarine_Id, blockPrismarineBricks(), false); - generateBox(level, chunkBB, 7, 1, 0, 7, 1, 7, Tile::prismarine_Id, blockPrismarineBricks(),Tile::prismarine_Id, blockPrismarineBricks(), false); - generateBox(level, chunkBB, 0, 1, 7, 7, 3, 7, Tile::prismarine_Id, blockPrismarineBricks(),Tile::prismarine_Id, blockPrismarineBricks(), false); - generateBox(level, chunkBB, 1, 1, 0, 2, 3, 0, Tile::prismarine_Id, blockPrismarineBricks(),Tile::prismarine_Id, blockPrismarineBricks(), false); - generateBox(level, chunkBB, 5, 1, 0, 6, 3, 0, Tile::prismarine_Id, blockPrismarineBricks(),Tile::prismarine_Id, blockPrismarineBricks(), false); + generateBox(level, chunkBB, 0, 3, 0, 2, 3, 7, Tile::prismarine_Id, blockPrismarineBricks(), Tile::prismarine_Id, blockPrismarineBricks(), false); + generateBox(level, chunkBB, 5, 3, 0, 7, 3, 7, Tile::prismarine_Id, blockPrismarineBricks(), Tile::prismarine_Id, blockPrismarineBricks(), false); + generateBox(level, chunkBB, 0, 2, 0, 1, 2, 7, Tile::prismarine_Id, blockPrismarineBricks(), Tile::prismarine_Id, blockPrismarineBricks(), false); + generateBox(level, chunkBB, 6, 2, 0, 7, 2, 7, Tile::prismarine_Id, blockPrismarineBricks(), Tile::prismarine_Id, blockPrismarineBricks(), false); + generateBox(level, chunkBB, 0, 1, 0, 0, 1, 7, Tile::prismarine_Id, blockPrismarineBricks(), Tile::prismarine_Id, blockPrismarineBricks(), false); + generateBox(level, chunkBB, 7, 1, 0, 7, 1, 7, Tile::prismarine_Id, blockPrismarineBricks(), Tile::prismarine_Id, blockPrismarineBricks(), false); + generateBox(level, chunkBB, 0, 1, 7, 7, 3, 7, Tile::prismarine_Id, blockPrismarineBricks(), Tile::prismarine_Id, blockPrismarineBricks(), false); + generateBox(level, chunkBB, 1, 1, 0, 2, 3, 0, Tile::prismarine_Id, blockPrismarineBricks(), Tile::prismarine_Id, blockPrismarineBricks(), false); + generateBox(level, chunkBB, 5, 1, 0, 6, 3, 0, Tile::prismarine_Id, blockPrismarineBricks(), Tile::prismarine_Id, blockPrismarineBricks(), false); if (roomDef->hasOpening[F_NORTH]) fillWithAirOrWater(level, chunkBB, 3, 1, 7, 4, 2, 7, false); if (roomDef->hasOpening[F_WEST]) fillWithAirOrWater(level, chunkBB, 0, 1, 3, 1, 2, 4, false); From 48ce29a28eeeaceb6cb4755c04eac30d47648541 Mon Sep 17 00:00:00 2001 From: SevenToaster509 Date: Sun, 12 Apr 2026 18:25:27 +0100 Subject: [PATCH 6/8] Fix: Clicking book while signing removes signing text, Clicking book when book is signed allows text editing, Added default resolution to not crash on smaller screens (720p and less) --- .../Common/Media/MediaWindows64.arc | Bin 28631560 -> 28661186 bytes .../Common/UI/UIScene_BookAndQuillMenu.cpp | 8 +++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Minecraft.Client/Common/Media/MediaWindows64.arc b/Minecraft.Client/Common/Media/MediaWindows64.arc index 05dce97574ef4b3a86c254c54c8fc952f7168f35..9eb8ea28313cd09df480481d454aa1bd135b066b 100644 GIT binary patch delta 6415 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 delta 6375 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 O8f%Aq3tN^vvg3c6cKUq) diff --git a/Minecraft.Client/Common/UI/UIScene_BookAndQuillMenu.cpp b/Minecraft.Client/Common/UI/UIScene_BookAndQuillMenu.cpp index 4fac0f54..17109584 100644 --- a/Minecraft.Client/Common/UI/UIScene_BookAndQuillMenu.cpp +++ b/Minecraft.Client/Common/UI/UIScene_BookAndQuillMenu.cpp @@ -287,6 +287,9 @@ void UIScene_BookAndQuillMenu::handleInput(int iPad, int key, bool repeat, bool navigateBack(); } } + else { + navigateBack(); + } } else { @@ -471,10 +474,13 @@ void UIScene_BookAndQuillMenu::handlePress(F64 controlId, F64 childId) #endif break; case eControl_Book: + if (signedBook == true) { + break; + } if (g_KBMInput.IsKBMActive()) { //This does not work when using controller. Why? God knows... this->SetFocusToElement(eControl_Type); - m_typeText.beginDirectEdit(1023, false, L""); + m_typeText.beginDirectEdit(1023, signing, data->player->getDisplayName()); } else { if (signedBook == true) { From e0cc846be5440914caee64438a06b6d5a204094f Mon Sep 17 00:00:00 2001 From: SevenToaster509 Date: Sun, 12 Apr 2026 18:42:59 +0100 Subject: [PATCH 7/8] Fix: Lapis Slot for Enchanting takes and consumes any item --- .../Common/UI/UIScene_EnchantingMenu.cpp | 4 ---- Minecraft.World/EnchantmentMenu.cpp | 1 - Minecraft.World/EnchantmentSlot.h | 15 ++++++++++++--- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/Minecraft.Client/Common/UI/UIScene_EnchantingMenu.cpp b/Minecraft.Client/Common/UI/UIScene_EnchantingMenu.cpp index ced8b5fe..7d1cea3f 100644 --- a/Minecraft.Client/Common/UI/UIScene_EnchantingMenu.cpp +++ b/Minecraft.Client/Common/UI/UIScene_EnchantingMenu.cpp @@ -18,10 +18,6 @@ UIScene_EnchantingMenu::UIScene_EnchantingMenu(int iPad, void *_initData, UILaye m_enchantButton[1].init(1); m_enchantButton[2].init(2); - - - - EnchantingScreenInput *initData = static_cast(_initData); m_labelEnchant.init( initData->name.empty() ? app.GetString(IDS_ENCHANT) : initData->name ); diff --git a/Minecraft.World/EnchantmentMenu.cpp b/Minecraft.World/EnchantmentMenu.cpp index f468907c..64875812 100644 --- a/Minecraft.World/EnchantmentMenu.cpp +++ b/Minecraft.World/EnchantmentMenu.cpp @@ -106,7 +106,6 @@ void EnchantmentMenu::slotsChanged(int a) // 4J used to take a shared_ptr container, int id, int x, int y) : Slot(container,id, x, y) {} - virtual bool mayPlace(shared_ptr item) {return true;} + int slotNum; + //stack->getItem()->id == 351 && stack->getItem()->getMaterial() == 11 + EnchantmentSlot(shared_ptr container, int id, int x, int y) : Slot(container, id, x, y) { slotNum = id; } + virtual bool mayPlace(shared_ptr item) { + if (slotNum == 0 || (item->id == 351 && Item::items[item->id]->getMaterial() == 11)) { + return true; + } + else { + return false; + } + } virtual bool mayCombine(shared_ptr item) {return false;} // 4J Added }; \ No newline at end of file From 3d57609e129e7cb08d7b606f25c7fd0d8bfad086 Mon Sep 17 00:00:00 2001 From: SevenToaster509 Date: Sun, 12 Apr 2026 20:43:55 +0100 Subject: [PATCH 8/8] Chore: Disable track debugging Hope no-one needs it, it was pissing me off --- Minecraft.Client/Common/Audio/SoundEngine.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Minecraft.Client/Common/Audio/SoundEngine.cpp b/Minecraft.Client/Common/Audio/SoundEngine.cpp index 31804e6b..69948636 100644 --- a/Minecraft.Client/Common/Audio/SoundEngine.cpp +++ b/Minecraft.Client/Common/Audio/SoundEngine.cpp @@ -770,14 +770,14 @@ int SoundEngine::GetRandomishTrack(int iStart,int iEnd) if(m_bHeardTrackA[i]==false) { bAllTracksHeard=false; - app.DebugPrintf("Not heard all tracks yet\n"); + //app.DebugPrintf("Not heard all tracks yet\n"); break; } } if(bAllTracksHeard) { - app.DebugPrintf("Heard all tracks - resetting the tracking array\n"); + //app.DebugPrintf("Heard all tracks - resetting the tracking array\n"); for(size_t i=iStart;i<=iEnd;i++) { @@ -793,17 +793,17 @@ int SoundEngine::GetRandomishTrack(int iStart,int iEnd) if(m_bHeardTrackA[iVal]==false) { // not heard this - app.DebugPrintf("(%d) Not heard track %d yet, so playing it now\n",i,iVal); + //app.DebugPrintf("(%d) Not heard track %d yet, so playing it now\n",i,iVal); m_bHeardTrackA[iVal]=true; break; } else { - app.DebugPrintf("(%d) Skipping track %d already heard it recently\n",i,iVal); + //app.DebugPrintf("(%d) Skipping track %d already heard it recently\n",i,iVal); } } - app.DebugPrintf("Select track %d\n",iVal); + //app.DebugPrintf("Select track %d\n",iVal); return iVal; } /////////////////////////////////////////////