Cuberite
A lightweight, fast and extensible game server for Minecraft
Villager.cpp
Go to the documentation of this file.
1 
2 #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
3 
4 #include "Villager.h"
5 #include "../World.h"
6 #include "../BlockArea.h"
7 #include "../Blocks/BlockHandler.h"
8 #include "../BlockInServerPluginInterface.h"
9 
10 
11 
12 
13 
15  Super("Villager", mtVillager, "entity.villager.hurt", "entity.villager.death", "entity.villager.ambient", 0.6f, 1.95f),
16  m_ActionCountDown(-1),
17  m_Type(VillagerType),
18  m_FarmerAction(faIdling),
19  m_Inventory(8, 1)
20 {
21 }
22 
23 
24 
25 
26 
28 {
29  if (!Super::DoTakeDamage(a_TDI))
30  {
31  return false;
32  }
33 
34  if ((a_TDI.Attacker != nullptr) && a_TDI.Attacker->IsPlayer())
35  {
36  if (GetRandomProvider().RandBool(1.0 / 6.0))
37  {
39  }
40  }
41 
42  if (a_TDI.DamageType == dtLightning)
43  {
44  Destroy();
45  m_World->SpawnMob(GetPosX(), GetPosY(), GetPosZ(), mtWitch, false);
46  return true;
47  }
48  return true;
49 }
50 
51 
52 
53 
54 
55 void cVillager::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
56 {
57  Super::Tick(a_Dt, a_Chunk);
58  if (!IsTicking())
59  {
60  // The base class tick destroyed us
61  return;
62  }
63 
64  switch (m_Type)
65  {
66  case vtFarmer:
67  {
68  TickFarmer();
69  break;
70  }
71  }
72 }
73 
74 
75 
76 
77 
79 {
80  Super::KilledBy(a_TDI);
81 
82  // TODO: 0% chance on Easy, 50% chance on Normal and 100% chance on Hard
83  if (GetRandomProvider().RandBool(0.5) && (a_TDI.Attacker != nullptr) && (a_TDI.Attacker->IsMob()))
84  {
85  eMonsterType MonsterType = (static_cast<cMonster *>(a_TDI.Attacker)->GetMobType());
86  if ((MonsterType == mtZombie) || (MonsterType == mtZombieVillager))
87  {
89  }
90  }
91 }
92 
93 
94 
95 
96 
98 // Farmer functions:
99 
101 {
102 
103  // Don't harvest crops if you must not
105  {
106  return;
107  }
108 
109  // This is to prevent undefined behaviors
110  if (m_FinalDestination.y <= 0)
111  {
112  return;
113  }
114 
115  if (!IsIdling())
116  {
117  // Forcing the farmer to go to work spots.
118  MoveToPosition(static_cast<Vector3d>(m_CropsPos) + Vector3d(0.5, 0, 0.5));
119 
120  // Forcing the farmer to look at the work spots.
121  Vector3d Direction = (m_FinalDestination - (GetPosition() + Vector3d(0, 1.6, 0))); // We get the direction from the eyes of the farmer to the work spot.
123  SetPitch(std::asin(-Direction.y) / M_PI * 180);
124  }
125 
126  // Updating the timer
127  if (m_ActionCountDown > -1)
128  {
130  }
131 
132  // Searching for work in blocks where the farmer goes.
134  {
138  return;
139  }
141  {
145  return;
146  }
147  else
148  {
149  m_FarmerAction = faIdling; // Returning to idling.
150  }
151 
152 
153  // Don't always try to do a special action. Each tick has 10% to do a special action.
155  {
156  ScanAreaForWork();
157  }
158 
159 }
160 
161 
162 
163 
164 
166 {
167 
168  auto Pos = GetPosition().Floor();
169  auto MinPos = Pos - FARMER_SCAN_CROPS_DIST;
170  auto MaxPos = Pos + FARMER_SCAN_CROPS_DIST;
171 
172  // Read area to be checked for crops.
173  cBlockArea Surrounding;
174  Surrounding.Read(
175  *m_World,
176  MinPos, MaxPos
177  );
178 
179  for (int I = 0; I < FARMER_RANDOM_TICK_SPEED; I++)
180  {
181  for (int Y = MinPos.y; Y <= MaxPos.y; Y++)
182  {
183  // Pick random coordinates and check for crops.
184  Vector3i CandidatePos(MinPos.x + m_World->GetTickRandomNumber(MaxPos.x - MinPos.x - 1), Y, MinPos.z + m_World->GetTickRandomNumber(MaxPos.z - MinPos.z - 1));
185 
186  // A villager can harvest this.
187  if (IsHarvestable(CandidatePos))
188  {
189  m_CropsPos = CandidatePos;
191  MoveToPosition(static_cast<Vector3d>(m_CropsPos) + Vector3d(0.5, 0, 0.5));
192  return;
193  }
194  // A villager can plant this.
195  else if (IsPlantable(CandidatePos) && CanPlantCrops())
196  {
197  m_CropsPos = CandidatePos;
199  MoveToPosition(static_cast<Vector3d>(m_CropsPos) + Vector3d(0.5, 0, 0.5));
200  return;
201  }
202 
203  } // for Y
204  } // Repeat the proccess according to the random tick speed.
205 }
206 
207 
208 
209 
210 
212 {
213  if (m_ActionCountDown > 0)
214  {
215  // The farmer is still on cooldown
216  return;
217  }
218 
219  // Harvest the crops if it is closer than 1 block.
220  if ((GetPosition() - m_CropsPos).Length() < 1)
221  {
222  // Check if the blocks didn't change while the villager was walking to the coordinates.
224  {
226  m_World->DropBlockAsPickups(m_CropsPos, this, nullptr);
227  // Applying 0.5 second cooldown.
228  m_ActionCountDown = 10;
229  }
230  }
231 }
232 
233 
234 
235 
236 
238 {
239 
240  // Search for adjacent crops
241 
242  constexpr std::array<Vector3i, 4> Directions = { Vector3i{0, 0, -1}, {0, 0, 1}, {1, 0, 0}, {-1, 0, 0} };
243 
244  for (Vector3i Direction : Directions)
245  {
247  {
250  MoveToPosition(static_cast<Vector3d>(m_CropsPos) + Vector3d(0.5, 0, 0.5));
251  return;
252  }
254  {
257  MoveToPosition(static_cast<Vector3d>(m_CropsPos) + Vector3d(0.5, 0, 0.5));
258  return;
259  }
260 
261  }
262 
263  // There is no more work to do around the previous crops.
265 }
266 
267 
268 
269 
270 
272 {
273 
274  if ((GetPosition() - m_CropsPos).Length() > 1)
275  {
276  // The farmer is still to far from the final destination
277  return;
278  }
279 
280  if (m_ActionCountDown > 0)
281  {
282  // The farmer is still on cooldown
283  return;
284  }
285 
286  // Check if there is still farmland at the spot where the crops were.
287  if (IsPlantable(m_CropsPos))
288  {
289  // Finding the item to use to plant a crop
290  int TargetSlot = -1;
291  BLOCKTYPE CropBlockType = E_BLOCK_AIR;
292 
293  for (int I = 0; I < m_Inventory.GetWidth() && TargetSlot < 0; I++)
294  {
295  const cItem & Slot = m_Inventory.GetSlot(I);
296  switch (Slot.m_ItemType)
297  {
298  case E_ITEM_SEEDS:
299  {
300  TargetSlot = I;
301  CropBlockType = E_BLOCK_CROPS;
302  break;
303  }
304 
306  {
307  TargetSlot = I;
308  CropBlockType = E_BLOCK_BEETROOTS;
309  break;
310  }
311 
312  case E_ITEM_POTATO:
313  {
314  TargetSlot = I;
315  CropBlockType = E_BLOCK_POTATOES;
316  break;
317  }
318 
319  case E_ITEM_CARROT:
320  {
321  TargetSlot = I;
322  CropBlockType = E_BLOCK_CARROTS;
323  break;
324  }
325 
326  default:
327  {
328  break;
329  }
330  }
331  }
332 
333  // Removing item from villager inventory
334  m_Inventory.RemoveOneItem(TargetSlot);
335 
336  // Placing crop block
337  m_World->SetBlock(m_CropsPos, CropBlockType, 0);
338 
339  // Applying 1 second cooldown
340  m_ActionCountDown = 20;
341 
342  // Try to do the same with adjacent crops.
344  }
345 }
346 
347 
348 
349 
350 
352 {
357 }
358 
359 
360 
361 
362 
363 bool cVillager::IsBlockFarmable(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
364 {
365  switch (a_BlockType)
366  {
367  case E_BLOCK_BEETROOTS:
368  {
369  // The crop must have fully grown up.
370  return a_BlockMeta == 0x03;
371  }
372  case E_BLOCK_CROPS:
373  case E_BLOCK_POTATOES:
374  case E_BLOCK_CARROTS:
375  {
376  // The crop must have fully grown up.
377  return a_BlockMeta == 0x07;
378  }
379  default: return false;
380  }
381 }
382 
383 
384 
385 
386 
388 {
389  return IsBlockFarmable(m_World->GetBlock(a_CropsPos), m_World->GetBlockMeta(a_CropsPos));
390 }
391 
392 
393 
394 
395 
397 {
398  return (m_World->GetBlock(a_CropsPos.addedY(-1)) == E_BLOCK_FARMLAND) && (m_World->GetBlock(a_CropsPos) == E_BLOCK_AIR);
399 }
400 
401 
402 
403 
404 
406 {
407  int Profession = GetRandomProvider().RandInt(cVillager::eVillagerType::vtMax - 1);
408 
409  return static_cast<cVillager::eVillagerType>(Profession);
410 }
@ E_BLOCK_CARROTS
Definition: BlockType.h:156
@ E_BLOCK_POTATOES
Definition: BlockType.h:157
@ E_BLOCK_FARMLAND
Definition: BlockType.h:72
@ E_BLOCK_AIR
Definition: BlockType.h:10
@ E_BLOCK_CROPS
Definition: BlockType.h:71
@ E_BLOCK_BEETROOTS
Definition: BlockType.h:226
@ E_ITEM_CARROT
Definition: BlockType.h:437
@ E_ITEM_BEETROOT_SEEDS
Definition: BlockType.h:482
@ E_ITEM_SEEDS
Definition: BlockType.h:339
@ E_ITEM_POTATO
Definition: BlockType.h:438
unsigned char NIBBLETYPE
The datatype used by nibbledata (meta, light, skylight)
Definition: ChunkDef.h:44
unsigned char BLOCKTYPE
The datatype used by blockdata.
Definition: ChunkDef.h:41
@ dtLightning
Definition: Defines.h:248
@ PARTICLE_BLOCK_BREAK
MTRand & GetRandomProvider()
Returns the current thread's random number source.
Definition: FastRandom.cpp:12
eMonsterType m_Type
Definition: Monster.cpp:35
eMonsterType
Identifies individual monster type.
Definition: MonsterTypes.h:11
@ mtZombieVillager
Definition: MonsterTypes.h:82
@ mtZombie
Definition: MonsterTypes.h:79
@ mtVillager
Definition: MonsterTypes.h:71
@ mtWitch
Definition: MonsterTypes.h:74
Direction
Vector3< double > Vector3d
Definition: Vector3.h:485
bool Read(cForEachChunkProvider &a_ForEachChunkProvider, int a_MinBlockX, int a_MaxBlockX, int a_MinBlockY, int a_MaxBlockY, int a_MinBlockZ, int a_MaxBlockZ, int a_DataTypes=baTypes|baMetas|baBlockEntities)
Reads an area of blocks specified.
Definition: BlockArea.cpp:445
Definition: Chunk.h:36
cEntity * Attacker
Definition: Entity.h:62
eDamageType DamageType
Definition: Entity.h:61
Definition: Entity.h:76
void SetPitch(double a_Pitch)
Definition: Entity.cpp:2136
bool IsPlayer(void) const
Definition: Entity.h:160
bool IsTicking(void) const
Returns true if the entity is valid and ticking.
Definition: Entity.cpp:2259
double GetPosX(void) const
Definition: Entity.h:195
cWorld * m_World
Definition: Entity.h:624
double GetPosZ(void) const
Definition: Entity.h:197
void Destroy()
Destroys the entity, schedules it for memory freeing and broadcasts the DestroyEntity packet.
Definition: Entity.cpp:243
double GetPosY(void) const
Definition: Entity.h:196
const Vector3d & GetPosition(void) const
Exported in ManualBindings.
Definition: Entity.h:297
bool IsMob(void) const
Definition: Entity.h:162
IntType RandInt(IntType a_Min, IntType a_Max)
Return a random IntType in the range [a_Min, a_Max].
Definition: FastRandom.h:78
Definition: Item.h:37
short m_ItemType
Definition: Item.h:163
const cItem & GetSlot(int a_X, int a_Y) const
Definition: ItemGrid.cpp:96
bool HasItems(const cItem &a_ItemStack)
Returns true if there are at least as many items of type a_ItemStack as in a_ItemStack.
Definition: ItemGrid.cpp:585
int GetWidth(void) const
Definition: ItemGrid.h:38
cItem RemoveOneItem(int a_SlotNum)
Removes one item from the stack in the specified slot, and returns it.
Definition: ItemGrid.cpp:516
Vector3d m_FinalDestination
Coordinates for the ultimate, final destination.
Definition: Monster.h:264
virtual void KilledBy(TakeDamageInfo &a_TDI) override
Called when the health drops below zero.
Definition: Monster.cpp:602
virtual void MoveToPosition(const Vector3d &a_Position)
Engage pathfinder and tell it to calculate a path to a given position, and move the mob accordingly.
Definition: Monster.cpp:245
eMonsterType GetMobType(void) const
Definition: Monster.h:70
virtual void Tick(std::chrono::milliseconds a_Dt, cChunk &a_Chunk) override
virtual bool DoTakeDamage(TakeDamageInfo &a_TDI) override
When hit by someone, run away.
void TickFarmer()
Tick function for farmers.
Definition: Villager.cpp:100
bool IsPlantable(Vector3i a_CropsPos)
Returns true if seeds can be planted at a given location.
Definition: Villager.cpp:396
eFarmerAction m_FarmerAction
Definition: Villager.h:101
Vector3i m_CropsPos
Definition: Villager.h:102
@ faIdling
Definition: Villager.h:58
@ faHarvesting
Definition: Villager.h:60
@ faPlanting
Definition: Villager.h:59
static eVillagerType GetRandomProfession()
Returns a random Profession.
Definition: Villager.cpp:405
static constexpr Vector3i FARMER_SCAN_CROPS_DIST
This distance from the Villager makes for a 31x3x31 area.
Definition: Villager.h:67
void HandleFarmerTryHarvestCrops()
Looks if the farmer has reached it's destination, and if it's still crops and the destination is clos...
Definition: Villager.cpp:211
int m_Type
Definition: Villager.h:100
bool IsHarvestable(Vector3i a_CropsPos)
Returns true if the block at the given location is a fully grown up crop.
Definition: Villager.cpp:387
void ScanAreaForWork()
Searches in a 31x3x31 area to harvest crops or spaces to plant crops.
Definition: Villager.cpp:165
static const int FARMER_RANDOM_TICK_SPEED
Definition: Villager.h:63
int m_ActionCountDown
Definition: Villager.h:99
bool IsBlockFarmable(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
Returns true if the given blocktype are: crops, potatoes or carrots and they have full grown up.
Definition: Villager.cpp:363
static constexpr double FARMER_SPECIAL_ACTION_CHANCE
With 10% chance, it takes about 20 seconds to find a spot.
Definition: Villager.h:65
bool CanPlantCrops()
Returns whether the farmer has crops in his inventory to plant.
Definition: Villager.cpp:351
cItemGrid m_Inventory
Definition: Villager.h:103
eVillagerType
Definition: Villager.h:19
@ vtFarmer
Definition: Villager.h:20
bool IsIdling()
Returns whether the farmer is not working.
Definition: Villager.h:88
void CheckForNearbyCrops()
Checking for harvesting or planting nearby crops.
Definition: Villager.cpp:237
void HandleFarmerTryPlaceCrops()
Looks if the farmer has reached it's destination, and if it's still non obstructed farmland and the d...
Definition: Villager.cpp:271
virtual bool DoTakeDamage(TakeDamageInfo &a_TDI) override
When hit by someone, run away.
Definition: Villager.cpp:27
cVillager(eVillagerType VillagerType)
Definition: Villager.cpp:14
virtual void Tick(std::chrono::milliseconds a_Dt, cChunk &a_Chunk) override
Definition: Villager.cpp:55
virtual void KilledBy(TakeDamageInfo &a_TDI) override
Called when the health drops below zero.
Definition: Villager.cpp:78
Vector3< T > addedY(T a_AddY) const
Returns a copy of this vector moved by the specified amount on the y axis.
Definition: Vector3.h:314
Vector3< int > Floor(void) const
Returns a new Vector3i with coords set to std::floor() of this vector's coords.
Definition: Vector3.h:177
T y
Definition: Vector3.h:17
void Normalize(void)
Definition: Vector3.h:49
bool DropBlockAsPickups(Vector3i a_BlockPos, const cEntity *a_Digger=nullptr, const cItem *a_Tool=nullptr)
Digs the specified block, and spawns the appropriate pickups for it.
Definition: World.cpp:2090
virtual UInt32 SpawnMob(double a_PosX, double a_PosY, double a_PosZ, eMonsterType a_MonsterType, bool a_Baby=false) override
Spawns a mob of the specified type.
Definition: World.cpp:2897
virtual void BroadcastEntityAnimation(const cEntity &a_Entity, EntityAnimation a_Animation, const cClientHandle *a_Exclude=nullptr) override
BLOCKTYPE GetBlock(Vector3i a_BlockPos) const
Returns the block type at the specified position.
Definition: World.h:363
int GetTickRandomNumber(int a_Range)
Returns a random number in range [0 .
Definition: World.cpp:2978
virtual void BroadcastSoundParticleEffect(const EffectID a_EffectID, Vector3i a_SrcPos, int a_Data, const cClientHandle *a_Exclude=nullptr) override
bool VillagersShouldHarvestCrops(void) const
Definition: World.h:131
NIBBLETYPE GetBlockMeta(Vector3i a_BlockPos) const
Returns the block meta at the specified position.
Definition: World.h:370
void SetBlock(Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
Sets the block at the specified coords to the specified value.
Definition: World.cpp:1743