Implement farmland trampling (#5401)
* Add DarkoGNU to CONTRIBUTORS * HandleFarmlandTrampling function & its docs * Fix decimal separators (, -> .) * Fix style. Adjust thresholds. Make function non-virtual * Adjust thresholds again. Prepare for fixing #5402 * Trying to fix falling through farmlands * Another style fix * Add FarmlandTramplingEnabled to world.ini * Docs for IsFarmlandTramplingEnabled * Style * Farmland trampling - handling the random chance * Trampling kinda works, very buggy * Trying to fix clang-tidy * Fix trampling * Trying to fix the 'undocumented API symbol' * Implement bearbin's suggestions * Calculate volume properly * Don't use std::pow for squaring * Improved comments * Really, should comments' style be checked?
This commit is contained in:
parent
844a339330
commit
4f554e91ab
@ -17,6 +17,7 @@ birkett (Anthony Birkett)
|
||||
Bond_009
|
||||
changyongGuo
|
||||
Cocosushi6
|
||||
DarkoGNU
|
||||
derouinw
|
||||
dImrich (Damian Imrich)
|
||||
Diusrex
|
||||
|
@ -2245,6 +2245,16 @@ function OnAllChunksAvailable()</pre> All return values from the callbacks are i
|
||||
},
|
||||
Notes = "Returns whether the configuration has DeepSnow enabled.",
|
||||
},
|
||||
IsFarmlandTramplingEnabled =
|
||||
{
|
||||
Returns =
|
||||
{
|
||||
{
|
||||
Type = "boolean",
|
||||
},
|
||||
},
|
||||
Notes = "Returns true if farmland trampling is enabled.",
|
||||
},
|
||||
IsGameModeAdventure =
|
||||
{
|
||||
Returns =
|
||||
|
@ -1164,6 +1164,7 @@ float cBlockInfo::GetBlockHeight(const BLOCKTYPE Block)
|
||||
case E_BLOCK_DARK_OAK_FENCE: return 1.5;
|
||||
case E_BLOCK_DARK_OAK_FENCE_GATE: return 1.5;
|
||||
case E_BLOCK_ENCHANTMENT_TABLE: return 0.75; // 12 pixels
|
||||
case E_BLOCK_FARMLAND: return 0.9375; // 15 pixels
|
||||
case E_BLOCK_FENCE: return 1.5;
|
||||
case E_BLOCK_JUNGLE_FENCE: return 1.5;
|
||||
case E_BLOCK_JUNGLE_FENCE_GATE: return 1.5;
|
||||
|
@ -10,7 +10,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "BlockHandler.h"
|
||||
#include "ChunkInterface.h"
|
||||
#include "../BlockArea.h"
|
||||
#include "../Chunk.h"
|
||||
#include "../ClientHandle.h"
|
||||
|
||||
|
||||
|
||||
@ -25,6 +28,58 @@ public:
|
||||
|
||||
using Super::Super;
|
||||
|
||||
/** Turns farmland into dirt.
|
||||
Will first check for any colliding entities and teleport them to a higher position.
|
||||
*/
|
||||
static void TurnToDirt(cChunk & a_Chunk, Vector3i a_AbsPos)
|
||||
{
|
||||
auto RelPos = cChunkDef::AbsoluteToRelative(a_AbsPos);
|
||||
TurnToDirt(a_Chunk, a_AbsPos, RelPos);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** Turns farmland into dirt.
|
||||
Will first check for any colliding entities and teleport them to a higher position.
|
||||
*/
|
||||
static void TurnToDirt(cChunk & a_Chunk, Vector3i a_AbsPos, Vector3i a_RelPos)
|
||||
{
|
||||
static const auto FarmlandHeight = cBlockInfo::GetBlockHeight(E_BLOCK_FARMLAND);
|
||||
static const auto FullHeightDelta = 1 - FarmlandHeight;
|
||||
|
||||
a_Chunk.ForEachEntityInBox(
|
||||
cBoundingBox(Vector3d(0.5, FarmlandHeight, 0.5) + a_AbsPos, 0.5, FullHeightDelta),
|
||||
[&](cEntity & Entity)
|
||||
{
|
||||
if (!Entity.IsOnGround())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
Entity.AddPosY(FullHeightDelta);
|
||||
|
||||
// Players need a packet that will update their position
|
||||
if (Entity.IsPlayer())
|
||||
{
|
||||
auto Player = static_cast<cPlayer *>(&Entity);
|
||||
// This works, but it's much worse than Vanilla.
|
||||
// This can be easily improved by implementing relative
|
||||
// "Player Position And Look" packets! See
|
||||
// https://wiki.vg/Protocol#Player_Position_And_Look_.28clientbound.29
|
||||
Player->GetClientHandle()->SendPlayerMoveLook();
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
a_Chunk.SetBlock(a_RelPos, E_BLOCK_DIRT, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private:
|
||||
|
||||
virtual cItems ConvertToPickups(const NIBBLETYPE a_BlockMeta, const cItem * const a_Tool) const override
|
||||
@ -76,7 +131,8 @@ private:
|
||||
}
|
||||
default:
|
||||
{
|
||||
a_Chunk.SetBlock(a_RelPos, E_BLOCK_DIRT, 0);
|
||||
auto AbsPos = a_Chunk.RelativeToAbsolute(a_RelPos);
|
||||
TurnToDirt(a_Chunk, AbsPos, a_RelPos);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -101,10 +157,17 @@ private:
|
||||
}
|
||||
|
||||
// Check whether we should revert to dirt:
|
||||
// TODO: fix for signs and slabs (possibly more blocks) - they should destroy farmland
|
||||
auto upperBlock = a_ChunkInterface.GetBlock(a_BlockPos.addedY(1));
|
||||
if (cBlockInfo::FullyOccupiesVoxel(upperBlock))
|
||||
{
|
||||
a_ChunkInterface.SetBlock(a_BlockPos, E_BLOCK_DIRT, 0);
|
||||
// Until the fix above is done, this line should also suffice:
|
||||
// a_ChunkInterface.SetBlock(a_BlockPos, E_BLOCK_DIRT, 0);
|
||||
a_ChunkInterface.DoWithChunkAt(a_BlockPos, [&](cChunk & Chunk)
|
||||
{
|
||||
TurnToDirt(Chunk, a_BlockPos);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "../Bindings/PluginManager.h"
|
||||
#include "../BoundingBox.h"
|
||||
#include "../Blocks/BlockHandler.h"
|
||||
#include "../Blocks/BlockFarmland.h"
|
||||
#include "../EffectID.h"
|
||||
#include "../Mobs/Monster.h"
|
||||
|
||||
@ -430,7 +431,9 @@ void cPawn::HandleFalling(void)
|
||||
|
||||
if (OnGround)
|
||||
{
|
||||
auto Damage = static_cast<int>(m_LastGroundHeight - GetPosY() - 3.0);
|
||||
auto FallHeight = m_LastGroundHeight - GetPosY();
|
||||
auto Damage = static_cast<int>(FallHeight - 3.0);
|
||||
|
||||
if ((Damage > 0) && !FallDamageAbsorbed)
|
||||
{
|
||||
if (IsElytraFlying())
|
||||
@ -438,7 +441,6 @@ void cPawn::HandleFalling(void)
|
||||
Damage = static_cast<int>(static_cast<float>(Damage) * 0.33);
|
||||
}
|
||||
|
||||
// Fall particles:
|
||||
if (const auto Below = POS_TOINT.addedY(-1); Below.y >= 0)
|
||||
{
|
||||
const auto BlockBelow = GetWorld()->GetBlock(Below);
|
||||
@ -448,6 +450,7 @@ void cPawn::HandleFalling(void)
|
||||
Damage = std::clamp(static_cast<int>(static_cast<float>(Damage) * 0.2), 1, 20);
|
||||
}
|
||||
|
||||
// Fall particles
|
||||
GetWorld()->BroadcastParticleEffect(
|
||||
"blockdust",
|
||||
GetPosition(),
|
||||
@ -463,6 +466,15 @@ void cPawn::HandleFalling(void)
|
||||
|
||||
m_bTouchGround = true;
|
||||
m_LastGroundHeight = GetPosY();
|
||||
|
||||
// Farmland trampling. Mobs smaller than 0.512 cubic blocks won't trample (Java Edition's behavior)
|
||||
// We only have width and height, so we have to calculate Width^2
|
||||
if (GetWorld()->IsFarmlandTramplingEnabled() &&
|
||||
(BlockAtFoot == E_BLOCK_FARMLAND) &&
|
||||
(GetWidth() * GetWidth() * GetHeight() >= 0.512))
|
||||
{
|
||||
HandleFarmlandTrampling(FallHeight);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -478,6 +490,42 @@ void cPawn::HandleFalling(void)
|
||||
|
||||
|
||||
|
||||
void cPawn::HandleFarmlandTrampling(double a_FallHeight)
|
||||
{
|
||||
bool ShouldTrample = true;
|
||||
auto & Random = GetRandomProvider();
|
||||
|
||||
// No trampling if FallHeight <= 0.6875
|
||||
if (a_FallHeight <= 0.6875)
|
||||
{
|
||||
ShouldTrample = false;
|
||||
}
|
||||
// For FallHeight <= 1.5625 we need to get a random bool
|
||||
else if (a_FallHeight <= 1.0625)
|
||||
{
|
||||
ShouldTrample = Random.RandBool(0.25);
|
||||
}
|
||||
else if (a_FallHeight <= 1.5625)
|
||||
{
|
||||
ShouldTrample = Random.RandBool(0.66);
|
||||
}
|
||||
// For FallHeight > 1.5625 we always trample - ShouldTrample remains true
|
||||
|
||||
if (ShouldTrample)
|
||||
{
|
||||
auto AbsPos = GetPosition().Floor();
|
||||
GetWorld()->DoWithChunkAt(AbsPos, [&](cChunk & Chunk)
|
||||
{
|
||||
cBlockFarmlandHandler::TurnToDirt(Chunk, AbsPos);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cPawn::OnRemoveFromWorld(cWorld & a_World)
|
||||
{
|
||||
StopEveryoneFromTargetingMe();
|
||||
|
@ -33,6 +33,16 @@ public:
|
||||
virtual void HandleFalling(void);
|
||||
virtual void OnRemoveFromWorld(cWorld & a_World) override;
|
||||
|
||||
/** Handles farmland trampling when hitting the ground.
|
||||
Algorithm:
|
||||
fall height <= 0.6875 blocks: no trampling
|
||||
fall height > 0.6875 and <= 1.0625: 25% chance of trampling
|
||||
fall height > 1.0625 and <= 1.5625: 66% chance of trampling
|
||||
fall height > 1.5625: always trample
|
||||
The values may differ from vanilla, they were determined experimentally.
|
||||
*/
|
||||
void HandleFarmlandTrampling(double a_FallHeight);
|
||||
|
||||
/** Tells all pawns which are targeting us to stop targeting us. */
|
||||
void StopEveryoneFromTargetingMe();
|
||||
|
||||
|
@ -166,6 +166,7 @@ cWorld::cWorld(
|
||||
m_SkyDarkness(0),
|
||||
m_GameMode(gmSurvival),
|
||||
m_bEnabledPVP(false),
|
||||
m_bFarmlandTramplingEnabled(false),
|
||||
m_IsDeepSnowEnabled(false),
|
||||
m_ShouldLavaSpawnFire(true),
|
||||
m_VillagersShouldHarvestCrops(true),
|
||||
@ -300,6 +301,7 @@ cWorld::cWorld(
|
||||
int TNTShrapnelLevel = IniFile.GetValueSetI("Physics", "TNTShrapnelLevel", static_cast<int>(slAll));
|
||||
m_bCommandBlocksEnabled = IniFile.GetValueSetB("Mechanics", "CommandBlocksEnabled", false);
|
||||
m_bEnabledPVP = IniFile.GetValueSetB("Mechanics", "PVPEnabled", true);
|
||||
m_bFarmlandTramplingEnabled = IniFile.GetValueSetB("Mechanics", "FarmlandTramplingEnabled", true);
|
||||
m_bUseChatPrefixes = IniFile.GetValueSetB("Mechanics", "UseChatPrefixes", true);
|
||||
m_MinNetherPortalWidth = IniFile.GetValueSetI("Mechanics", "MinNetherPortalWidth", 2);
|
||||
m_MaxNetherPortalWidth = IniFile.GetValueSetI("Mechanics", "MaxNetherPortalWidth", 21);
|
||||
|
@ -121,6 +121,9 @@ public:
|
||||
|
||||
bool IsPVPEnabled(void) const { return m_bEnabledPVP; }
|
||||
|
||||
/** Returns true if farmland trampling is enabled */
|
||||
bool IsFarmlandTramplingEnabled(void) const { return m_bFarmlandTramplingEnabled; }
|
||||
|
||||
bool IsDeepSnowEnabled(void) const { return m_IsDeepSnowEnabled; }
|
||||
|
||||
bool ShouldLavaSpawnFire(void) const { return m_ShouldLavaSpawnFire; }
|
||||
@ -997,6 +1000,7 @@ private:
|
||||
|
||||
eGameMode m_GameMode;
|
||||
bool m_bEnabledPVP;
|
||||
bool m_bFarmlandTramplingEnabled;
|
||||
bool m_IsDeepSnowEnabled;
|
||||
bool m_ShouldLavaSpawnFire;
|
||||
bool m_VillagersShouldHarvestCrops;
|
||||
|
Loading…
x
Reference in New Issue
Block a user