View

Large diffs are not rendered by default.

Oops, something went wrong.
View
@@ -13,7 +13,6 @@
class cGroup;
class cWindow;
class cClientHandle;
class cTeam;
@@ -29,12 +28,13 @@ class cPlayer :
typedef cPawn super;
public:
enum
{
MAX_HEALTH = 20,
MAX_FOOD_LEVEL = 20,
EATING_TICKS = 30, ///< Number of ticks it takes to eat an item
} ;
static const int MAX_HEALTH;
static const int MAX_FOOD_LEVEL;
/** Number of ticks it takes to eat an item */
static const int EATING_TICKS;
// tolua_end
CLASS_PROTODEF(cPlayer)
@@ -235,24 +235,20 @@ class cPlayer :
// tolua_end
typedef std::list< cGroup* > GroupList;
typedef std::list< std::string > StringList;
bool HasPermission(const AString & a_Permission); // tolua_export
/** Adds a player to existing group or creates a new group when it doesn't exist */
void AddToGroup( const AString & a_GroupName); // tolua_export
/** Removes a player from the group, resolves permissions and group inheritance (case sensitive) */
void RemoveFromGroup( const AString & a_GroupName); // tolua_export
bool HasPermission( const AString & a_Permission); // tolua_export
const GroupList & GetGroups() { return m_Groups; } // >> EXPORTED IN MANUALBINDINGS <<
StringList GetResolvedPermissions(); // >> EXPORTED IN MANUALBINDINGS <<
bool IsInGroup( const AString & a_Group); // tolua_export
/** Returns true iff a_Permission matches the a_Template.
A match is defined by either being exactly the same, or each sub-item matches until there's a wildcard in a_Template.
Ie. {"a", "b", "c"} matches {"a", "b", "*"} but doesn't match {"a", "b"} */
static bool PermissionMatches(const AStringVector & a_Permission, const AStringVector & a_Template); // Exported in ManualBindings with AString params
/** Returns all the permissions that the player has assigned to them. */
const AStringVector & GetPermissions(void) { return m_Permissions; } // Exported in ManualBindings.cpp
// tolua_begin
/** Returns the full color code to use for this player, based on their primary group or set in m_Color.
The returned value includes the cChatColor::Delimiter. */
/** Returns the full color code to use for this player, based on their rank.
The returned value either is empty, or includes the cChatColor::Delimiter. */
AString GetColor(void) const;
/** tosses the item in the selected hotbar slot */
@@ -346,8 +342,6 @@ class cPlayer :
*/
bool LoadFromFile(const AString & a_FileName, cWorldPtr & a_World);
void LoadPermissionsFromDisk(void); // tolua_export
const AString & GetLoadedWorldName() { return m_LoadedWorldName; }
void UseEquippedItem(int a_Amount = 1);
@@ -421,6 +415,11 @@ class cPlayer :
/** Returns the UUID (short format) that has been read from the client, or empty string if not available. */
const AString & GetUUID(void) const { return m_UUID; }
/** (Re)loads the rank and permissions from the cRankManager.
Expects the m_UUID member to be valid.
Loads the m_Rank, m_Permissions, m_MsgPrefix, m_MsgSuffix and m_MsgNameColorCode members. */
void LoadRank(void);
// tolua_end
// cEntity overrides:
@@ -431,12 +430,22 @@ class cPlayer :
virtual void Detach(void);
protected:
typedef std::map< std::string, bool > PermissionMap;
PermissionMap m_ResolvedPermissions;
PermissionMap m_Permissions;
GroupList m_ResolvedGroups;
GroupList m_Groups;
typedef std::vector<std::vector<AString> > AStringVectorVector;
/** The name of the rank assigned to this player. */
AString m_Rank;
/** All the permissions that this player has, based on their rank. */
AStringVector m_Permissions;
/** All the permissions that this player has, based on their rank, split into individual dot-delimited parts.
This is used mainly by the HasPermission() function to optimize the lookup. */
AStringVectorVector m_SplitPermissions;
// Message visuals:
AString m_MsgPrefix, m_MsgSuffix;
AString m_MsgNameColorCode;
AString m_PlayerName;
AString m_LoadedWorldName;
@@ -481,8 +490,6 @@ class cPlayer :
/** The player's last saved bed position */
Vector3i m_LastBedPos;
char m_Color;
eGameMode m_GameMode;
AString m_IP;
View
@@ -45,7 +45,7 @@ class cFastRandom
float NextFloat(float a_Range, int a_Salt);
/** Returns a random float between 0 and 1. */
float NextFloat(void) { return NextFloat(1); };
float NextFloat(void) { return NextFloat(1); }
/** Returns a random int in the range [a_Begin .. a_End] */
int GenerateRandomInteger(int a_Begin, int a_End);
View
@@ -12,6 +12,7 @@ SET (SRCS
CompoGen.cpp
ComposableGenerator.cpp
DistortedHeightmap.cpp
DungeonRoomsFinisher.cpp
EndGen.cpp
FinishGen.cpp
GridStructGen.cpp
@@ -40,6 +41,7 @@ SET (HDRS
CompoGen.h
ComposableGenerator.h
DistortedHeightmap.h
DungeonRoomsFinisher.h
EndGen.h
FinishGen.h
GridStructGen.h
View
@@ -166,6 +166,9 @@ cCaveTunnel::cCaveTunnel(
if ((a_BlockStartY <= 0) && (a_BlockEndY <= 0))
{
// Don't bother detailing this cave, it's under the world anyway
m_MinBlockX = m_MaxBlockX = 0;
m_MinBlockY = m_MaxBlockY = -1;
m_MinBlockZ = m_MaxBlockZ = 0;
return;
}
View
@@ -27,6 +27,7 @@ const unsigned int QUEUE_SKIP_LIMIT = 500;
cChunkGenerator::cChunkGenerator(void) :
super("cChunkGenerator"),
m_Seed(0), // Will be overwritten by the actual generator
m_Generator(NULL),
m_PluginInterface(NULL),
m_ChunkSink(NULL)
View
@@ -19,6 +19,7 @@
#include "Caves.h"
#include "DistortedHeightmap.h"
#include "DungeonRoomsFinisher.h"
#include "EndGen.h"
#include "MineShafts.h"
#include "NetherFortGen.h"
@@ -343,6 +344,14 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
float Threshold = (float)a_IniFile.GetValueSetF("Generator", "DualRidgeCavesThreshold", 0.3);
m_FinishGens.push_back(new cStructGenDualRidgeCaves(Seed, Threshold));
}
else if (NoCaseCompare(*itr, "DungeonRooms") == 0)
{
int GridSize = a_IniFile.GetValueSetI("Generator", "DungeonRoomsGridSize", 48);
int MaxSize = a_IniFile.GetValueSetI("Generator", "DungeonRoomsMaxSize", 7);
int MinSize = a_IniFile.GetValueSetI("Generator", "DungeonRoomsMinSize", 5);
AString HeightDistrib = a_IniFile.GetValueSet ("Generator", "DungeonRoomsHeightDistrib", "0, 0; 10, 10; 11, 500; 40, 500; 60, 40; 90, 1");
m_FinishGens.push_back(new cDungeonRoomsFinisher(*m_HeightGen, Seed, GridSize, MaxSize, MinSize, HeightDistrib));
}
else if (NoCaseCompare(*itr, "Ice") == 0)
{
m_FinishGens.push_back(new cFinishGenIce);
@@ -387,6 +396,28 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
m_FinishGens.push_back(new cFinishGenSingleTopBlock(Seed, E_BLOCK_LILY_PAD, AllowedBiomes, 4, AllowedBlocks));
}
else if (NoCaseCompare(*itr, "NaturalPatches") == 0)
{
cStructGenOreNests::OreList Ores;
// Dirt vein
cStructGenOreNests::OreInfo DirtVein;
DirtVein.BlockType = E_BLOCK_DIRT;
DirtVein.MaxHeight = 127;
DirtVein.NumNests = 20;
DirtVein.NestSize = 32;
Ores.push_back(DirtVein);
// Gravel vein
cStructGenOreNests::OreInfo GravelVein;
GravelVein.BlockType = E_BLOCK_DIRT;
GravelVein.MaxHeight = 127;
GravelVein.NumNests = 20;
GravelVein.NestSize = 32;
Ores.push_back(GravelVein);
m_FinishGens.push_back(new cStructGenOreNests(Seed, Ores, E_BLOCK_STONE));
}
else if (NoCaseCompare(*itr, "NetherClumpFoliage") == 0)
{
m_FinishGens.push_back(new cFinishGenNetherClumpFoliage(Seed));
@@ -398,9 +429,74 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
int MaxDepth = a_IniFile.GetValueSetI("Generator", "NetherFortsMaxDepth", 12);
m_FinishGens.push_back(new cNetherFortGen(Seed, GridSize, MaxOffset, MaxDepth));
}
else if (NoCaseCompare(*itr, "NetherOreNests") == 0)
{
cStructGenOreNests::OreList Ores;
// Quartz vein
cStructGenOreNests::OreInfo QuartzVein;
QuartzVein.BlockType = E_BLOCK_NETHER_QUARTZ_ORE;
QuartzVein.MaxHeight = 255;
QuartzVein.NumNests = 80;
QuartzVein.NestSize = 8;
Ores.push_back(QuartzVein);
m_FinishGens.push_back(new cStructGenOreNests(Seed, Ores, E_BLOCK_NETHERRACK));
}
else if (NoCaseCompare(*itr, "OreNests") == 0)
{
m_FinishGens.push_back(new cStructGenOreNests(Seed));
cStructGenOreNests::OreList Ores;
// Coal vein
cStructGenOreNests::OreInfo CoalVein;
CoalVein.BlockType = E_BLOCK_COAL_ORE;
CoalVein.MaxHeight = 127;
CoalVein.NumNests = 50;
CoalVein.NestSize = 10;
Ores.push_back(CoalVein);
// Iron vein
cStructGenOreNests::OreInfo IronVein;
IronVein.BlockType = E_BLOCK_IRON_ORE;
IronVein.MaxHeight = 64;
IronVein.NumNests = 14;
IronVein.NestSize = 6;
Ores.push_back(IronVein);
// Gold vein
cStructGenOreNests::OreInfo GoldVein;
GoldVein.BlockType = E_BLOCK_GOLD_ORE;
GoldVein.MaxHeight = 32;
GoldVein.NumNests = 2;
GoldVein.NestSize = 6;
Ores.push_back(GoldVein);
// Redstone vein
cStructGenOreNests::OreInfo RedstoneVein;
RedstoneVein.BlockType = E_BLOCK_REDSTONE_ORE;
RedstoneVein.MaxHeight = 16;
RedstoneVein.NumNests = 4;
RedstoneVein.NestSize = 6;
Ores.push_back(RedstoneVein);
// Lapis vein
cStructGenOreNests::OreInfo LapisVein;
LapisVein.BlockType = E_BLOCK_LAPIS_ORE;
LapisVein.MaxHeight = 30;
LapisVein.NumNests = 2;
LapisVein.NestSize = 5;
Ores.push_back(LapisVein);
// Diamond vein
cStructGenOreNests::OreInfo DiamondVein;
DiamondVein.BlockType = E_BLOCK_DIAMOND_ORE;
DiamondVein.MaxHeight = 15;
DiamondVein.NumNests = 1;
DiamondVein.NestSize = 4;
Ores.push_back(DiamondVein);
m_FinishGens.push_back(new cStructGenOreNests(Seed, Ores, E_BLOCK_STONE));
}
else if (NoCaseCompare(*itr, "POCPieces") == 0)
{
View
@@ -0,0 +1,279 @@
// DungeonRoomsFinisher.cpp
// Declares the cDungeonRoomsFinisher class representing the finisher that generates dungeon rooms
#include "Globals.h"
#include "DungeonRoomsFinisher.h"
#include "../FastRandom.h"
/** Height, in blocks, of the internal dungeon room open space. This many air blocks Y-wise. */
static const int ROOM_HEIGHT = 4;
////////////////////////////////////////////////////////////////////////////////
// cDungeonRoom:
class cDungeonRoom :
public cGridStructGen::cStructure
{
typedef cGridStructGen::cStructure super;
public:
cDungeonRoom(
int a_GridX, int a_GridZ,
int a_OriginX, int a_OriginZ,
int a_HalfSizeX, int a_HalfSizeZ,
int a_FloorHeight,
cNoise & a_Noise
) :
super(a_GridX, a_GridZ, a_OriginX, a_OriginZ),
m_StartX(a_OriginX - a_HalfSizeX),
m_EndX(a_OriginX + a_HalfSizeX),
m_StartZ(a_OriginZ - a_HalfSizeZ),
m_EndZ(a_OriginZ + a_HalfSizeZ),
m_FloorHeight(a_FloorHeight)
{
/*
Pick coords next to the wall for the chests.
This is done by indexing the possible coords, picking any one for the first chest
and then picking another position for the second chest that is not adjacent to the first pos
*/
int rnd = a_Noise.IntNoise2DInt(a_OriginX, a_OriginZ) / 7;
int SizeX = m_EndX - m_StartX - 1;
int SizeZ = m_EndZ - m_StartZ - 1;
int NumPositions = 2 * SizeX + 2 * SizeZ;
int FirstChestPos = rnd % NumPositions; // The corner positions are a bit more likely, but we don't mind
rnd = rnd / 512;
int SecondChestPos = (FirstChestPos + 2 + (rnd % (NumPositions - 3))) % NumPositions;
m_Chest1 = DecodeChestCoords(FirstChestPos, SizeX, SizeZ);
m_Chest2 = DecodeChestCoords(SecondChestPos, SizeX, SizeZ);
}
protected:
// The X range of the room, start inclusive, end exclusive:
int m_StartX, m_EndX;
// The Z range of the room, start inclusive, end exclusive:
int m_StartZ, m_EndZ;
/** The Y coord of the floor of the room */
int m_FloorHeight;
/** The (absolute) coords of the first chest. The Y coord represents the chest's Meta value (facing). */
Vector3i m_Chest1;
/** The (absolute) coords of the second chest. The Y coord represents the chest's Meta value (facing). */
Vector3i m_Chest2;
/** Decodes the position index along the room walls into a proper 2D position for a chest. */
Vector3i DecodeChestCoords(int a_PosIdx, int a_SizeX, int a_SizeZ)
{
if (a_PosIdx < a_SizeX)
{
// Return a coord on the ZM side of the room:
return Vector3i(m_StartX + a_PosIdx + 1, E_META_CHEST_FACING_ZP, m_StartZ + 1);
}
a_PosIdx -= a_SizeX;
if (a_PosIdx < a_SizeZ)
{
// Return a coord on the XP side of the room:
return Vector3i(m_EndX - 1, E_META_CHEST_FACING_XM, m_StartZ + a_PosIdx + 1);
}
a_PosIdx -= a_SizeZ;
if (a_PosIdx < a_SizeX)
{
// Return a coord on the ZP side of the room:
return Vector3i(m_StartX + a_PosIdx + 1, E_META_CHEST_FACING_ZM, m_StartZ + 1);
}
a_PosIdx -= a_SizeX;
// Return a coord on the XM side of the room:
return Vector3i(m_StartX + 1, E_META_CHEST_FACING_XP, m_StartZ + a_PosIdx + 1);
}
/** Fills the specified area of blocks in the chunk with the specified blocktype if they are one of the overwritten block types.
The coords are absolute, start coords are inclusive, end coords are exclusive. */
void ReplaceCuboid(cChunkDesc & a_ChunkDesc, int a_StartX, int a_StartY, int a_StartZ, int a_EndX, int a_EndY, int a_EndZ, BLOCKTYPE a_DstBlockType)
{
int BlockX = a_ChunkDesc.GetChunkX() * cChunkDef::Width;
int BlockZ = a_ChunkDesc.GetChunkZ() * cChunkDef::Width;
int RelStartX = Clamp(a_StartX - BlockX, 0, cChunkDef::Width - 1);
int RelStartZ = Clamp(a_StartZ - BlockZ, 0, cChunkDef::Width - 1);
int RelEndX = Clamp(a_EndX - BlockX, 0, cChunkDef::Width);
int RelEndZ = Clamp(a_EndZ - BlockZ, 0, cChunkDef::Width);
for (int y = a_StartY; y < a_EndY; y++)
{
for (int z = RelStartZ; z < RelEndZ; z++)
{
for (int x = RelStartX; x < RelEndX; x++)
{
if (cBlockInfo::CanBeTerraformed(a_ChunkDesc.GetBlockType(x, y, z)))
{
a_ChunkDesc.SetBlockType(x, y, z, a_DstBlockType);
}
} // for x
} // for z
} // for z
}
/** Fills the specified area of blocks in the chunk with a random pattern of the specified blocktypes, if they are one of the overwritten block types.
The coords are absolute, start coords are inclusive, end coords are exclusive. The first blocktype uses 75% chance, the second 25% chance. */
void ReplaceCuboidRandom(cChunkDesc & a_ChunkDesc, int a_StartX, int a_StartY, int a_StartZ, int a_EndX, int a_EndY, int a_EndZ, BLOCKTYPE a_DstBlockType1, BLOCKTYPE a_DstBlockType2)
{
int BlockX = a_ChunkDesc.GetChunkX() * cChunkDef::Width;
int BlockZ = a_ChunkDesc.GetChunkZ() * cChunkDef::Width;
int RelStartX = Clamp(a_StartX - BlockX, 0, cChunkDef::Width - 1);
int RelStartZ = Clamp(a_StartZ - BlockZ, 0, cChunkDef::Width - 1);
int RelEndX = Clamp(a_EndX - BlockX, 0, cChunkDef::Width);
int RelEndZ = Clamp(a_EndZ - BlockZ, 0, cChunkDef::Width);
cFastRandom rnd;
for (int y = a_StartY; y < a_EndY; y++)
{
for (int z = RelStartZ; z < RelEndZ; z++)
{
for (int x = RelStartX; x < RelEndX; x++)
{
if (cBlockInfo::CanBeTerraformed(a_ChunkDesc.GetBlockType(x, y, z)))
{
BLOCKTYPE BlockType = (rnd.NextInt(101) < 75) ? a_DstBlockType1 : a_DstBlockType2;
a_ChunkDesc.SetBlockType(x, y, z, BlockType);
}
} // for x
} // for z
} // for z
}
/** Tries to place a chest at the specified (absolute) coords.
Does nothing if the coords are outside the chunk. */
void TryPlaceChest(cChunkDesc & a_ChunkDesc, const Vector3i & a_Chest)
{
int RelX = a_Chest.x - a_ChunkDesc.GetChunkX() * cChunkDef::Width;
int RelZ = a_Chest.z - a_ChunkDesc.GetChunkZ() * cChunkDef::Width;
if (
(RelX < 0) || (RelX >= cChunkDef::Width) || // The X coord is not in this chunk
(RelZ < 0) || (RelZ >= cChunkDef::Width) // The Z coord is not in this chunk
)
{
return;
}
a_ChunkDesc.SetBlockTypeMeta(RelX, m_FloorHeight + 1, RelZ, E_BLOCK_CHEST, (NIBBLETYPE)a_Chest.y);
// TODO: Fill the chest with random loot
}
// cGridStructGen::cStructure override:
virtual void DrawIntoChunk(cChunkDesc & a_ChunkDesc) override
{
if (
(m_EndX < a_ChunkDesc.GetChunkX() * cChunkDef::Width) ||
(m_StartX >= a_ChunkDesc.GetChunkX() * cChunkDef::Width + cChunkDef::Width) ||
(m_EndZ < a_ChunkDesc.GetChunkZ() * cChunkDef::Width) ||
(m_StartZ >= a_ChunkDesc.GetChunkZ() * cChunkDef::Width + cChunkDef::Width)
)
{
// The chunk is not intersecting the room at all, bail out
return;
}
int b = m_FloorHeight + 1; // Bottom
int t = m_FloorHeight + 1 + ROOM_HEIGHT; // Top
ReplaceCuboidRandom(a_ChunkDesc, m_StartX, m_FloorHeight, m_StartZ, m_EndX + 1, b, m_EndZ + 1, E_BLOCK_MOSSY_COBBLESTONE, E_BLOCK_COBBLESTONE); // Floor
ReplaceCuboid(a_ChunkDesc, m_StartX + 1, b, m_StartZ + 1, m_EndX, t, m_EndZ, E_BLOCK_AIR); // Insides
// Walls:
ReplaceCuboid(a_ChunkDesc, m_StartX, b, m_StartZ, m_StartX + 1, t, m_EndZ, E_BLOCK_COBBLESTONE); // XM wall
ReplaceCuboid(a_ChunkDesc, m_EndX, b, m_StartZ, m_EndX + 1, t, m_EndZ, E_BLOCK_COBBLESTONE); // XP wall
ReplaceCuboid(a_ChunkDesc, m_StartX, b, m_StartZ, m_EndX + 1, t, m_StartZ + 1, E_BLOCK_COBBLESTONE); // ZM wall
ReplaceCuboid(a_ChunkDesc, m_StartX, b, m_EndZ, m_EndX + 1, t, m_EndZ + 1, E_BLOCK_COBBLESTONE); // ZP wall
// Place chests:
TryPlaceChest(a_ChunkDesc, m_Chest1);
TryPlaceChest(a_ChunkDesc, m_Chest2);
// Place the spawner:
int CenterX = (m_StartX + m_EndX) / 2 - a_ChunkDesc.GetChunkX() * cChunkDef::Width;
int CenterZ = (m_StartZ + m_EndZ) / 2 - a_ChunkDesc.GetChunkZ() * cChunkDef::Width;
if (
(CenterX >= 0) && (CenterX < cChunkDef::Width) &&
(CenterZ >= 0) && (CenterZ < cChunkDef::Width)
)
{
a_ChunkDesc.SetBlockTypeMeta(CenterX, b, CenterZ, E_BLOCK_MOB_SPAWNER, 0);
// TODO: Set the spawned mob
}
}
} ;
////////////////////////////////////////////////////////////////////////////////
// cDungeonRoomsFinisher:
cDungeonRoomsFinisher::cDungeonRoomsFinisher(cTerrainHeightGen & a_HeightGen, int a_Seed, int a_GridSize, int a_MaxSize, int a_MinSize, const AString & a_HeightDistrib) :
super(a_Seed + 100, a_GridSize, a_GridSize, a_GridSize, a_GridSize, a_MaxSize, a_MaxSize, 1024),
m_HeightGen(a_HeightGen),
m_MaxHalfSize((a_MaxSize + 1) / 2),
m_MinHalfSize((a_MinSize + 1) / 2),
m_HeightProbability(cChunkDef::Height)
{
// Initialize the height probability distribution:
m_HeightProbability.SetDefString(a_HeightDistrib);
// Normalize the min and max size:
if (m_MinHalfSize > m_MaxHalfSize)
{
std::swap(m_MinHalfSize, m_MaxHalfSize);
}
}
cDungeonRoomsFinisher::cStructurePtr cDungeonRoomsFinisher::CreateStructure(int a_GridX, int a_GridZ, int a_OriginX, int a_OriginZ)
{
// Select a random room size in each direction:
int rnd = m_Noise.IntNoise2DInt(a_OriginX, a_OriginZ) / 7;
int HalfSizeX = m_MinHalfSize + (rnd % (m_MaxHalfSize - m_MinHalfSize + 1));
rnd = rnd / 32;
int HalfSizeZ = m_MinHalfSize + (rnd % (m_MaxHalfSize - m_MinHalfSize + 1));
rnd = rnd / 32;
// Select a random floor height for the room, based on the height generator:
int ChunkX, ChunkZ;
int RelX = a_OriginX, RelY = 0, RelZ = a_OriginZ;
cChunkDef::AbsoluteToRelative(RelX, RelY, RelZ, ChunkX, ChunkZ);
cChunkDef::HeightMap HeightMap;
m_HeightGen.GenHeightMap(ChunkX, ChunkZ, HeightMap);
int Height = cChunkDef::GetHeight(HeightMap, RelX, RelZ); // Max room height at {a_OriginX, a_OriginZ}
Height = Clamp(m_HeightProbability.MapValue(rnd % m_HeightProbability.GetSum()), 10, Height - 5);
// Create the dungeon room descriptor:
return cStructurePtr(new cDungeonRoom(a_GridX, a_GridZ, a_OriginX, a_OriginZ, HalfSizeX, HalfSizeZ, Height, m_Noise));
}
View
@@ -0,0 +1,52 @@
// DungeonRoomsFinisher.h
// Declares the cDungeonRoomsFinisher class representing the finisher that generates dungeon rooms
#pragma once
#include "GridStructGen.h"
#include "../ProbabDistrib.h"
class cDungeonRoomsFinisher :
public cGridStructGen
{
typedef cGridStructGen super;
public:
/** Creates a new dungeon room finisher.
a_HeightGen is the underlying height generator, so that the rooms can always be placed under the terrain.
a_MaxSize and a_MinSize are the maximum and minimum sizes of the room's internal (air) area, in blocks across.
a_HeightDistrib is the string defining the height distribution for the rooms (cProbabDistrib format). */
cDungeonRoomsFinisher(cTerrainHeightGen & a_HeightGen, int a_Seed, int a_GridSize, int a_MaxSize, int a_MinSize, const AString & a_HeightDistrib);
protected:
/** The height gen that is used for limiting the rooms' Y coords */
cTerrainHeightGen & m_HeightGen;
/** Maximum half-size (from center to wall) of the dungeon room's inner (air) area. Default is 3 (vanilla). */
int m_MaxHalfSize;
/** Minimum half-size (from center to wall) of the dungeon room's inner (air) area. Default is 2 (vanilla). */
int m_MinHalfSize;
/** The height probability distribution to make the spawners more common in layers 10 - 40, less common outside this range. */
cProbabDistrib m_HeightProbability;
// cGridStructGen overrides:
virtual cStructurePtr CreateStructure(int a_GridX, int a_GridZ, int a_OriginX, int a_OriginZ) override;
} ;
View
@@ -484,8 +484,6 @@ int cFinishGenSingleTopBlock::GetNumToGen(const cChunkDef::BiomeMap & a_BiomeMap
void cFinishGenSingleTopBlock::GenFinish(cChunkDesc & a_ChunkDesc)
{
// Add Lilypads on top of water surface in Swampland
int NumToGen = GetNumToGen(a_ChunkDesc.GetBiomeMap());
int ChunkX = a_ChunkDesc.GetChunkX();
int ChunkZ = a_ChunkDesc.GetChunkZ();
View
@@ -239,7 +239,13 @@ bool cHeiGenCache::GetHeightAt(int a_ChunkX, int a_ChunkZ, int a_RelX, int a_Rel
cHeiGenClassic::cHeiGenClassic(int a_Seed) :
m_Seed(a_Seed),
m_Noise(a_Seed)
m_Noise(a_Seed),
m_HeightFreq1(1.0f),
m_HeightAmp1(1.0f),
m_HeightFreq2(0.5f),
m_HeightAmp2(0.5f),
m_HeightFreq3(0.1f),
m_HeightAmp3(0.1f)
{
}
@@ -432,7 +438,7 @@ const cHeiGenBiomal::sGenParam cHeiGenBiomal::m_GenParam[256] =
/* biExtremeHillsM */ { 0.1f, 2.0f, 0.05f, 12.0f, 0.01f, 10.0f, 40}, // 131
/* biFlowerForest */ { 0.1f, 2.0f, 0.05f, 12.0f, 0.01f, 10.0f, 40}, // 132
/* biTaigaM */ { 0.1f, 2.0f, 0.05f, 12.0f, 0.01f, 10.0f, 40}, // 133
/* biSwamplandM */ { 1.0f, 2.0f, 1.10f, 5.0f, 0.01f, 8.0f, 60}, // 134
/* biSwamplandM */ { 1.0f, 3.0f, 1.10f, 7.0f, 0.01f, 0.01f, 60}, // 134
// Biomes 135 .. 139 unused, 5 empty placeholders here:
{}, {}, {}, {}, {}, // 135 .. 139
View
@@ -12,45 +12,6 @@
////////////////////////////////////////////////////////////////////////////////
// cStructGenOreNests configuration:
const int MAX_HEIGHT_COAL = 127;
const int NUM_NESTS_COAL = 50;
const int NEST_SIZE_COAL = 10;
const int MAX_HEIGHT_IRON = 64;
const int NUM_NESTS_IRON = 14;
const int NEST_SIZE_IRON = 6;
const int MAX_HEIGHT_REDSTONE = 16;
const int NUM_NESTS_REDSTONE = 4;
const int NEST_SIZE_REDSTONE = 6;
const int MAX_HEIGHT_GOLD = 32;
const int NUM_NESTS_GOLD = 2;
const int NEST_SIZE_GOLD = 6;
const int MAX_HEIGHT_DIAMOND = 15;
const int NUM_NESTS_DIAMOND = 1;
const int NEST_SIZE_DIAMOND = 4;
const int MAX_HEIGHT_LAPIS = 30;
const int NUM_NESTS_LAPIS = 2;
const int NEST_SIZE_LAPIS = 5;
const int MAX_HEIGHT_DIRT = 127;
const int NUM_NESTS_DIRT = 20;
const int NEST_SIZE_DIRT = 32;
const int MAX_HEIGHT_GRAVEL = 70;
const int NUM_NESTS_GRAVEL = 15;
const int NEST_SIZE_GRAVEL = 32;
////////////////////////////////////////////////////////////////////////////////
// cStructGenTrees:
@@ -311,14 +272,15 @@ void cStructGenOreNests::GenFinish(cChunkDesc & a_ChunkDesc)
int ChunkX = a_ChunkDesc.GetChunkX();
int ChunkZ = a_ChunkDesc.GetChunkZ();
cChunkDef::BlockTypes & BlockTypes = a_ChunkDesc.GetBlockTypes();
GenerateOre(ChunkX, ChunkZ, E_BLOCK_COAL_ORE, MAX_HEIGHT_COAL, NUM_NESTS_COAL, NEST_SIZE_COAL, BlockTypes, 1);
GenerateOre(ChunkX, ChunkZ, E_BLOCK_IRON_ORE, MAX_HEIGHT_IRON, NUM_NESTS_IRON, NEST_SIZE_IRON, BlockTypes, 2);
GenerateOre(ChunkX, ChunkZ, E_BLOCK_REDSTONE_ORE, MAX_HEIGHT_REDSTONE, NUM_NESTS_REDSTONE, NEST_SIZE_REDSTONE, BlockTypes, 3);
GenerateOre(ChunkX, ChunkZ, E_BLOCK_GOLD_ORE, MAX_HEIGHT_GOLD, NUM_NESTS_GOLD, NEST_SIZE_GOLD, BlockTypes, 4);
GenerateOre(ChunkX, ChunkZ, E_BLOCK_DIAMOND_ORE, MAX_HEIGHT_DIAMOND, NUM_NESTS_DIAMOND, NEST_SIZE_DIAMOND, BlockTypes, 5);
GenerateOre(ChunkX, ChunkZ, E_BLOCK_LAPIS_ORE, MAX_HEIGHT_LAPIS, NUM_NESTS_LAPIS, NEST_SIZE_LAPIS, BlockTypes, 6);
GenerateOre(ChunkX, ChunkZ, E_BLOCK_DIRT, MAX_HEIGHT_DIRT, NUM_NESTS_DIRT, NEST_SIZE_DIRT, BlockTypes, 10);
GenerateOre(ChunkX, ChunkZ, E_BLOCK_GRAVEL, MAX_HEIGHT_GRAVEL, NUM_NESTS_GRAVEL, NEST_SIZE_GRAVEL, BlockTypes, 11);
int seq = 1;
// Generate the ores from the ore list.
for (OreList::const_iterator itr = m_OreList.begin(); itr != m_OreList.end(); ++itr)
{
GenerateOre(ChunkX, ChunkZ, itr->BlockType, itr->MaxHeight, itr->NumNests, itr->NestSize, BlockTypes, seq);
seq++;
}
}
@@ -376,7 +338,7 @@ void cStructGenOreNests::GenerateOre(int a_ChunkX, int a_ChunkZ, BLOCKTYPE a_Ore
}
int Index = cChunkDef::MakeIndexNoCheck(BlockX, BlockY, BlockZ);
if (a_BlockTypes[Index] == E_BLOCK_STONE)
if (a_BlockTypes[Index] == m_ToReplace)
{
a_BlockTypes[Index] = a_OreType;
}
View
@@ -76,11 +76,29 @@ class cStructGenOreNests :
public cFinishGen
{
public:
cStructGenOreNests(int a_Seed) : m_Noise(a_Seed), m_Seed(a_Seed) {}
struct OreInfo
{
BLOCKTYPE BlockType; // The type of the nest.
int MaxHeight; // The highest possible a nest can occur
int NumNests; // How many nests per chunk
int NestSize; // The amount of blocks a nest can have.
};
typedef std::vector<OreInfo> OreList;
cStructGenOreNests(int a_Seed, OreList a_OreList, BLOCKTYPE a_ToReplace) :
m_Noise(a_Seed),
m_Seed(a_Seed),
m_OreList(a_OreList),
m_ToReplace(a_ToReplace)
{}
protected:
cNoise m_Noise;
int m_Seed;
cNoise m_Noise;
int m_Seed;
OreList m_OreList; // A list of possible ores.
BLOCKTYPE m_ToReplace;
// cFinishGen override:
virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
View
@@ -249,7 +249,7 @@ template class SizeChecker<UInt16, 2>;
#include "OSSupport/Event.h"
#include "OSSupport/Thread.h"
#include "OSSupport/File.h"
#include "MCLogger.h"
#include "Logger.h"
#else
// Logging functions
void inline LOGERROR(const char* a_Format, ...) FORMATSTRING(1, 2);
View

This file was deleted.

Oops, something went wrong.
View

This file was deleted.

Oops, something went wrong.
View

This file was deleted.

Oops, something went wrong.
View

This file was deleted.

Oops, something went wrong.
View
@@ -15,7 +15,8 @@
cHTTPConnection::cHTTPConnection(cHTTPServer & a_HTTPServer) :
m_HTTPServer(a_HTTPServer),
m_State(wcsRecvHeaders),
m_CurrentRequest(NULL)
m_CurrentRequest(NULL),
m_CurrentRequestBodyRemaining(0)
{
// LOGD("HTTP: New connection at %p", this);
}
View
@@ -15,7 +15,9 @@
cHTTPFormParser::cHTTPFormParser(cHTTPRequest & a_Request, cCallbacks & a_Callbacks) :
m_Callbacks(a_Callbacks),
m_IsValid(true)
m_IsValid(true),
m_IsCurrentPartFile(false),
m_FileHasBeenAnnounced(false)
{
if (a_Request.GetMethod() == "GET")
{
@@ -55,7 +57,9 @@ cHTTPFormParser::cHTTPFormParser(cHTTPRequest & a_Request, cCallbacks & a_Callba
cHTTPFormParser::cHTTPFormParser(eKind a_Kind, const char * a_Data, size_t a_Size, cCallbacks & a_Callbacks) :
m_Callbacks(a_Callbacks),
m_Kind(a_Kind),
m_IsValid(true)
m_IsValid(true),
m_IsCurrentPartFile(false),
m_FileHasBeenAnnounced(false)
{
Parse(a_Data, a_Size);
}
View
@@ -18,7 +18,7 @@
class cHTTPMessage
{
public:
enum
enum eStatus
{
HTTP_OK = 200,
HTTP_BAD_REQUEST = 400,
View
@@ -106,7 +106,7 @@ int cInventory::AddItem(const cItem & a_Item, bool a_AllowNewStacks, bool a_tryT
// When the item is a armor, try to set it directly to the armor slot.
if (ItemCategory::IsArmor(a_Item.m_ItemType))
{
for (size_t i = 0; i < (size_t)m_ArmorSlots.GetNumSlots(); i++)
for (int i = 0; i < m_ArmorSlots.GetNumSlots(); i++)
{
if (m_ArmorSlots.GetSlot(i).IsEmpty() && cSlotAreaArmor::CanPlaceArmorInSlot(i, a_Item))
{
View
@@ -39,8 +39,8 @@ class cInventory :
enum
{
invArmorCount = 4,
invInventoryCount = 9 * 3,
invHotbarCount = 9,
invInventoryCount = 9 * 3,
invHotbarCount = 9,
invArmorOffset = 0,
invInventoryOffset = invArmorOffset + invArmorCount,
View
@@ -57,6 +57,12 @@ class cItemBowHandler :
}
Force = std::min(Force, 1.0);
// Does the player have an arrow?
if (!a_Player->IsGameModeCreative() && !a_Player->GetInventory().HasItems(cItem(E_ITEM_ARROW)))
{
return;
}
// Create the arrow entity:
cArrowEntity * Arrow = new cArrowEntity(*a_Player, Force * 2);
if (Arrow == NULL)
@@ -73,6 +79,10 @@ class cItemBowHandler :
a_Player->GetWorld()->BroadcastSoundEffect("random.bow", a_Player->GetPosX(), a_Player->GetPosY(), a_Player->GetPosZ(), 0.5, (float)Force);
if (!a_Player->IsGameModeCreative())
{
if (a_Player->GetEquippedItem().m_Enchantments.GetLevel(cEnchantments::enchInfinity) == 0)
{
a_Player->GetInventory().RemoveItem(cItem(E_ITEM_ARROW));
}
a_Player->UseEquippedItem();
}
}
View
@@ -29,7 +29,7 @@ class cItemGoldenAppleHandler :
a_Player->AddEntityEffect(cEntityEffect::effRegeneration, 100, 1);
// When the apple is a 'notch apple', give extra effects:
if (a_Item->m_ItemDamage > 0)
if (a_Item->m_ItemDamage >= E_META_GOLDEN_APPLE_ENCHANTED)
{
a_Player->AddEntityEffect(cEntityEffect::effRegeneration, 600, 4);
a_Player->AddEntityEffect(cEntityEffect::effResistance, 6000, 0);
View
@@ -66,7 +66,7 @@ cItemHandler * cItemHandler::m_ItemHandler[2268];
cItemHandler * cItemHandler::GetItemHandler(int a_ItemType)
{
if ((a_ItemType < 0) || ((unsigned long)a_ItemType >= ARRAYCOUNT(m_ItemHandler)))
if ((a_ItemType < 0) || ((size_t)a_ItemType >= ARRAYCOUNT(m_ItemHandler)))
{
// Either nothing (-1), or bad value, both cases should return the air handler
if (a_ItemType < -1)
View
@@ -75,7 +75,7 @@ class cItemHandler
int FoodLevel;
double Saturation;
FoodInfo(int a_FoodLevel, double a_Saturation, int a_PoisonChance = 0) :
FoodInfo(int a_FoodLevel, double a_Saturation) :
FoodLevel(a_FoodLevel),
Saturation(a_Saturation)
{
View
@@ -19,7 +19,6 @@ class cItemShovelHandler : public cItemHandler
cItemShovelHandler(int a_ItemType)
: cItemHandler(a_ItemType)
{
}
virtual bool OnDiggingBlock(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Dir) override
View
@@ -73,6 +73,8 @@ class cReader :
HEIGHTTYPE * m_HeightMap; // 3x3 chunks of height map, organized as a single XZY blob of data (instead of 3x3 XZY blobs)
cReader(BLOCKTYPE * a_BlockTypes, HEIGHTTYPE * a_HeightMap) :
m_ReadingChunkX(0),
m_ReadingChunkZ(0),
m_MaxHeight(0),
m_BlockTypes(a_BlockTypes),
m_HeightMap(a_HeightMap)
@@ -89,7 +91,9 @@ class cReader :
cLightingThread::cLightingThread(void) :
super("cLightingThread"),
m_World(NULL)
m_World(NULL),
m_MaxHeight(0),
m_NumSeeds(0)
{
}
View
@@ -31,7 +31,7 @@ Linearly interpolates values in the array between the equidistant anchor points
Works in-place (input is already present at the correct output coords)
Uses templates to make it possible for the compiler to further optimizer the loops
*/
template<
template <
int SizeX, int SizeY, // Dimensions of the array
int AnchorStepX, int AnchorStepY,
typename TYPE
@@ -83,7 +83,7 @@ void LinearUpscale2DArrayInPlace(TYPE * a_Array)
Linearly interpolates values in the array between the equidistant anchor points (upscales).
Works on two arrays, input is packed and output is to be completely constructed.
*/
template<typename TYPE> void LinearUpscale2DArray(
template <typename TYPE> void LinearUpscale2DArray(
TYPE * a_Src, ///< Source array of size a_SrcSizeX x a_SrcSizeY
int a_SrcSizeX, int a_SrcSizeY, ///< Dimensions of the src array
TYPE * a_Dst, ///< Dest array, of size (a_SrcSizeX * a_UpscaleX + 1) x (a_SrcSizeY * a_UpscaleY + 1)
@@ -153,7 +153,7 @@ template<typename TYPE> void LinearUpscale2DArray(
Linearly interpolates values in the array between the equidistant anchor points (upscales).
Works on two arrays, input is packed and output is to be completely constructed.
*/
template<typename TYPE> void LinearUpscale3DArray(
template <typename TYPE> void LinearUpscale3DArray(
TYPE * a_Src, ///< Source array of size a_SrcSizeX x a_SrcSizeY x a_SrcSizeZ
int a_SrcSizeX, int a_SrcSizeY, int a_SrcSizeZ, ///< Dimensions of the src array
TYPE * a_Dst, ///< Dest array, of size (a_SrcSizeX * a_UpscaleX + 1) x (a_SrcSizeY * a_UpscaleY + 1) x (a_SrcSizeZ * a_UpscaleZ + 1)
View

This file was deleted.

Oops, something went wrong.
View

This file was deleted.

Oops, something went wrong.
View
@@ -0,0 +1,145 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "OSSupport/IsThread.h"
#ifdef _WIN32
#include <time.h>
#endif
cLogger & cLogger::GetInstance(void)
{
static cLogger Instance;
return Instance;
}
void cLogger::InitiateMultithreading()
{
GetInstance();
}
void cLogger::LogSimple(AString a_Message, eLogLevel a_LogLevel)
{
time_t rawtime;
time(&rawtime);
struct tm * timeinfo;
#ifdef _MSC_VER
struct tm timeinforeal;
timeinfo = &timeinforeal;
localtime_s(timeinfo, &rawtime);
#else
timeinfo = localtime(&rawtime);
#endif
AString Line;
#ifdef _DEBUG
Printf(Line, "[%04lx|%02d:%02d:%02d] %s\n", cIsThread::GetCurrentID(), timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec, a_Message.c_str());
#else
Printf(Line, "[%02d:%02d:%02d] %s\n", timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec, a_Message.c_str());
#endif
cCSLock Lock(m_CriticalSection);
for (size_t i = 0; i < m_LogListeners.size(); i++)
{
m_LogListeners[i]->Log(Line, a_LogLevel);
}
}
void cLogger::Log(const char * a_Format, eLogLevel a_LogLevel, va_list a_ArgList)
{
AString Message;
AppendVPrintf(Message, a_Format, a_ArgList);
LogSimple(Message, a_LogLevel);
}
void cLogger::AttachListener(cListener * a_Listener)
{
cCSLock Lock(m_CriticalSection);
m_LogListeners.push_back(a_Listener);
}
void cLogger::DetachListener(cListener * a_Listener)
{
cCSLock Lock(m_CriticalSection);
m_LogListeners.erase(std::remove(m_LogListeners.begin(), m_LogListeners.end(), a_Listener));
}
////////////////////////////////////////////////////////////////////////////////
// Global functions
void LOG(const char * a_Format, ...)
{
va_list argList;
va_start(argList, a_Format);
cLogger::GetInstance().Log(a_Format, cLogger::llRegular, argList);
va_end(argList);
}
void LOGINFO(const char * a_Format, ...)
{
va_list argList;
va_start(argList, a_Format);
cLogger::GetInstance().Log( a_Format, cLogger::llInfo, argList);
va_end(argList);
}
void LOGWARN(const char * a_Format, ...)
{
va_list argList;
va_start(argList, a_Format);
cLogger::GetInstance().Log( a_Format, cLogger::llWarning, argList);
va_end(argList);
}
void LOGERROR(const char * a_Format, ...)
{
va_list argList;
va_start(argList, a_Format);
cLogger::GetInstance().Log( a_Format, cLogger::llError, argList);
va_end(argList);
}
View
@@ -0,0 +1,73 @@
#pragma once
class cLogger
{
public:
enum eLogLevel
{
llRegular,
llInfo,
llWarning,
llError,
};
class cListener
{
public:
virtual void Log(AString a_Message, eLogLevel a_LogLevel) = 0;
virtual ~cListener(){}
};
void Log (const char * a_Format, eLogLevel a_LogLevel, va_list a_ArgList) FORMATSTRING(2, 0);
/** Logs the simple text message at the specified log level. */
void LogSimple(AString a_Message, eLogLevel a_LogLevel = llRegular);
void AttachListener(cListener * a_Listener);
void DetachListener(cListener * a_Listener);
static cLogger & GetInstance(void);
// Must be called before calling GetInstance in a multithreaded context
static void InitiateMultithreading();
private:
cCriticalSection m_CriticalSection;
std::vector<cListener *> m_LogListeners;
};
extern void LOG(const char* a_Format, ...) FORMATSTRING(1, 2);
extern void LOGINFO(const char* a_Format, ...) FORMATSTRING(1, 2);
extern void LOGWARN(const char* a_Format, ...) FORMATSTRING(1, 2);
extern void LOGERROR(const char* a_Format, ...) FORMATSTRING(1, 2);
// In debug builds, translate LOGD to LOG, otherwise leave it out altogether:
#ifdef _DEBUG
#define LOGD LOG
#else
#define LOGD(...)
#endif // _DEBUG
#define LOGWARNING LOGWARN
View
@@ -0,0 +1,322 @@
#include "Globals.h"
#include "LoggerListeners.h"
#if defined(_WIN32)
#include <io.h> // Needed for _isatty(), not available on Linux
#include <time.h>
#elif defined(__linux) && !defined(ANDROID_NDK)
#include <unistd.h> // Needed for isatty() on Linux
#elif defined(ANDROID_NDK)
#include <android/log.h>
#endif
#if defined(_WIN32) || (defined (__linux) && !defined(ANDROID_NDK))
class cColouredConsoleListener
: public cLogger::cListener
{
protected:
virtual void SetLogColour(cLogger::eLogLevel a_LogLevel) = 0;
virtual void SetDefaultLogColour() = 0;
virtual void Log(AString a_Message, cLogger::eLogLevel a_LogLevel) override
{
SetLogColour(a_LogLevel);
fputs(a_Message.c_str(), stdout);
SetDefaultLogColour();
}
};
#endif
#ifdef _WIN32
class cWindowsConsoleListener
: public cColouredConsoleListener
{
typedef cColouredConsoleListener super;
public:
cWindowsConsoleListener(HANDLE a_Console, WORD a_DefaultConsoleAttrib) :
m_Console(a_Console),
m_DefaultConsoleAttrib(a_DefaultConsoleAttrib)
{
}
#ifdef _DEBUG
virtual void Log(AString a_Message, cLogger::eLogLevel a_LogLevel) override
{
super::Log(a_Message, a_LogLevel);
// In a Windows Debug build, output the log to debug console as well:
OutputDebugStringA(a_Message.c_str());
}
#endif
virtual void SetLogColour(cLogger::eLogLevel a_LogLevel) override
{
// by default, gray on black
WORD Attrib = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
switch (a_LogLevel)
{
case cLogger::llRegular:
{
// Gray on black
Attrib = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
break;
}
case cLogger::llInfo:
{
// Yellow on black
Attrib = FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY;
break;
}
case cLogger::llWarning:
{
// Red on black
Attrib = FOREGROUND_RED | FOREGROUND_INTENSITY;
break;
}
case cLogger::llError:
{
// Black on red
Attrib = BACKGROUND_RED | BACKGROUND_INTENSITY;
break;
}
}
SetConsoleTextAttribute(m_Console, Attrib);
}
virtual void SetDefaultLogColour() override
{
SetConsoleTextAttribute(m_Console, m_DefaultConsoleAttrib);
}
private:
HANDLE m_Console;
WORD m_DefaultConsoleAttrib;
};
#elif defined (__linux) && !defined(ANDROID_NDK)
class cLinuxConsoleListener
: public cColouredConsoleListener
{
public:
virtual void SetLogColour(cLogger::eLogLevel a_LogLevel) override
{
switch (a_LogLevel)
{
case cLogger::llRegular:
{
// Whatever the console default is
printf("\x1b[0m");
break;
}
case cLogger::llInfo:
{
// Yellow on black
printf("\x1b[33;1m");
break;
}
case cLogger::llWarning:
{
// Red on black
printf("\x1b[31;1m");
break;
}
case cLogger::llError:
{
// Yellow on red
printf("\x1b[1;33;41;1m");
break;
}
}
}
virtual void SetDefaultLogColour() override
{
// Whatever the console default is
printf("\x1b[0m");
}
};
#elif defined(ANDROID_NDK)
class cAndroidConsoleListener
: public cLogger::cListener
{
public:
virtual void Log(AString a_Message, cLogger::eLogLevel a_LogLevel) override
{
android_LogPriority AndroidLogLevel;
switch (a_LogLevel)
{
case cLogger::llRegular:
{
AndroidLogLevel = ANDROID_LOG_VERBOSE;
break;
}
case cLogger::llInfo:
{
AndroidLogLevel = ANDROID_LOG_INFO;
break;
}
case cLogger::llWarning:
{
AndroidLogLevel = ANDROID_LOG_WARNING;
break;
}
case cLogger::llError:
{
AndroidLogLevel = ANDROID_LOG_ERROR;
break;
}
}
__android_log_print(AndroidLogLevel, "MCServer", "%s", a_Message.c_str());
}
};
#endif
class cVanillaCPPConsoleListener
: public cLogger::cListener
{
public:
virtual void Log(AString a_Message, cLogger::eLogLevel a_LogLevel) override
{
AString LogLevelString;
switch (a_LogLevel)
{
case cLogger::llRegular:
{
LogLevelString = "Log";
break;
}
case cLogger::llInfo:
{
LogLevelString = "Info";
break;
}
case cLogger::llWarning:
{
LogLevelString = "Warning";
break;
}
case cLogger::llError:
{
LogLevelString = "Error";
break;
}
}
printf("%s: %s", LogLevelString.c_str(), a_Message.c_str());
}
};
cLogger::cListener * MakeConsoleListener(void)
{
#ifdef _WIN32
// See whether we are writing to a console the default console attrib:
bool ShouldColorOutput = (_isatty(_fileno(stdin)) != 0);
if (ShouldColorOutput)
{
CONSOLE_SCREEN_BUFFER_INFO sbi;
HANDLE Console = GetStdHandle(STD_OUTPUT_HANDLE);
GetConsoleScreenBufferInfo(Console, &sbi);
WORD DefaultConsoleAttrib = sbi.wAttributes;
return new cWindowsConsoleListener(Console, DefaultConsoleAttrib);
}
else
{
return new cVanillaCPPConsoleListener;
}
#elif defined (__linux) && !defined(ANDROID_NDK)
// TODO: lookup terminal in terminfo
if (isatty(fileno(stdout)))
{
return new cLinuxConsoleListener();
}
else
{
return new cVanillaCPPConsoleListener();
}
#else
return new cVanillaCPPConsoleListener();
#endif
}
////////////////////////////////////////////////////////////////////////////////
// cFileListener:
cFileListener::cFileListener(void)
{
cFile::CreateFolder(FILE_IO_PREFIX + AString("logs"));
AString FileName;
FileName = Printf("%s%sLOG_%d.txt", FILE_IO_PREFIX, "logs/", (int)time(NULL));
m_File.Open(FileName, cFile::fmAppend);
}
void cFileListener::Log(AString a_Message, cLogger::eLogLevel a_LogLevel)
{
const char * LogLevelPrefix = "Unkn ";
switch (a_LogLevel)
{
case cLogger::llRegular:
{
LogLevelPrefix = " ";
break;
}
case cLogger::llInfo:
{
LogLevelPrefix = "info ";
break;
}
case cLogger::llWarning:
{
LogLevelPrefix = "Warn ";
break;
}
case cLogger::llError:
{
LogLevelPrefix = "Err ";
break;
}
}
m_File.Printf("%s%s", LogLevelPrefix, a_Message.c_str());
}
View
@@ -0,0 +1,31 @@
#include "Logger.h"
class cFileListener
: public cLogger::cListener
{
public:
cFileListener();
cFileListener(AString a_Filename);
virtual void Log(AString a_Message, cLogger::eLogLevel a_LogLevel) override;
private:
cFile m_File;
};
cLogger::cListener * MakeConsoleListener();
View

This file was deleted.

Oops, something went wrong.
View

This file was deleted.

Oops, something went wrong.
View
@@ -1024,7 +1024,7 @@ void cMonster::HandleDaylightBurning(cChunk & a_Chunk)
(a_Chunk.GetBlock(RelX, RelY, RelZ) != E_BLOCK_SOULSAND) && // Not on soulsand
(GetWorld()->GetTimeOfDay() < (12000 + 1000)) && // It is nighttime
!IsOnFire() && // Not already burning
GetWorld()->IsWeatherWetAt(POSX_TOINT, POSZ_TOINT) // Not raining
GetWorld()->IsWeatherSunnyAt(POSX_TOINT, POSZ_TOINT) // Not raining
)
{
// Burn for 100 ticks, then decide again
View
@@ -146,6 +146,8 @@ cCubicCell2D::cCubicCell2D(
) :
m_Noise(a_Noise),
m_WorkRnds(&m_Workspace1),
m_CurFloorX(0),
m_CurFloorY(0),
m_Array(a_Array),
m_SizeX(a_SizeX),
m_SizeY(a_SizeY),
@@ -300,6 +302,9 @@ cCubicCell3D::cCubicCell3D(
) :
m_Noise(a_Noise),
m_WorkRnds(&m_Workspace1),
m_CurFloorX(0),
m_CurFloorY(0),
m_CurFloorZ(0),
m_Array(a_Array),
m_SizeX(a_SizeX),
m_SizeY(a_SizeY),
View
@@ -70,6 +70,7 @@ bool cFile::Open(const AString & iFileName, eMode iMode)
case fmRead: Mode = "rb"; break;
case fmWrite: Mode = "wb"; break;
case fmReadWrite: Mode = "rb+"; break;
case fmAppend: Mode = "a+"; break;
}
if (Mode == NULL)
{
@@ -255,10 +256,10 @@ int cFile::ReadRestOfFile(AString & a_Contents)
return -1;
}
int DataSize = GetSize() - Tell();
size_t DataSize = GetSize() - Tell();
// HACK: This depends on the internal knowledge that AString's data() function returns the internal buffer directly
a_Contents.assign((size_t)DataSize, '\0');
a_Contents.assign(DataSize, '\0');
return Read((void *)a_Contents.data(), DataSize);
}
@@ -459,7 +460,7 @@ int cFile::Printf(const char * a_Fmt, ...)
va_start(args, a_Fmt);
AppendVPrintf(buf, a_Fmt, args);
va_end(args);
return Write(buf.c_str(), (int)buf.length());
return Write(buf.c_str(), buf.length());
}
View
@@ -60,9 +60,10 @@ class cFile
/** The mode in which to open the file */
enum eMode
{
fmRead, // Read-only. If the file doesn't exist, object will not be valid
fmWrite, // Write-only. If the file already exists, it will be overwritten
fmReadWrite // Read/write. If the file already exists, it will be left intact; writing will overwrite the data from the beginning
fmRead, // Read-only. If the file doesn't exist, object will not be valid
fmWrite, // Write-only. If the file already exists, it will be overwritten
fmReadWrite, // Read/write. If the file already exists, it will be left intact; writing will overwrite the data from the beginning
fmAppend // Write-only. If the file already exists cursor will be moved to the end of the file
} ;
/** Simple constructor - creates an unopened file object, use Open() to open / create a real file */
View
@@ -20,7 +20,7 @@ cQueueFuncs and is used as the default behavior.
*/
/// This empty struct allows for the callback functions to be inlined
template<class T>
template <class T>
struct cQueueFuncs
{
public:
View
@@ -16,6 +16,7 @@ cSslContext::cSslContext(void) :
m_IsValid(false),
m_HasHandshaken(false)
{
memset(&m_Ssl, 0, sizeof(m_Ssl));
}
View
@@ -10,6 +10,7 @@
#include "inifile/iniFile.h"
#include "json/json.h"
#include "PolarSSL++/BlockingSslClientSocket.h"
#include "../RankManager.h"
@@ -208,7 +209,7 @@ AString cMojangAPI::GetUUIDFromPlayerName(const AString & a_PlayerName, bool a_U
// No UUID found
return "";
}
return itr->second.m_PlayerName;
return itr->second.m_UUID;
}
@@ -300,6 +301,7 @@ void cMojangAPI::AddPlayerNameToUUIDMapping(const AString & a_PlayerName, const
cCSLock Lock(m_CSUUIDToName);
m_UUIDToName[UUID] = sProfile(a_PlayerName, UUID, "", "", Now);
}
NotifyNameUUID(a_PlayerName, a_UUID);
}
@@ -322,6 +324,7 @@ void cMojangAPI::AddPlayerProfile(const AString & a_PlayerName, const AString &
cCSLock Lock(m_CSUUIDToProfile);
m_UUIDToProfile[UUID] = sProfile(a_PlayerName, UUID, a_Properties, Now);
}
NotifyNameUUID(a_PlayerName, a_UUID);
}
@@ -655,11 +658,11 @@ void cMojangAPI::CacheNamesToUUIDs(const AStringVector & a_PlayerNames)
}
// Store the returned results into cache:
size_t JsonCount = root.size();
Json::Value::UInt JsonCount = root.size();
Int64 Now = time(NULL);
{
cCSLock Lock(m_CSNameToUUID);
for (size_t idx = 0; idx < JsonCount; ++idx)
for (Json::Value::UInt idx = 0; idx < JsonCount; ++idx)
{
Json::Value & Val = root[idx];
AString JsonName = Val.get("name", "").asString();
@@ -669,13 +672,14 @@ void cMojangAPI::CacheNamesToUUIDs(const AStringVector & a_PlayerNames)
continue;
}
m_NameToUUID[StrToLower(JsonName)] = sProfile(JsonName, JsonUUID, "", "", Now);
NotifyNameUUID(JsonName, JsonUUID);
} // for idx - root[]
} // cCSLock (m_CSNameToUUID)
// Also cache the UUIDToName:
{
cCSLock Lock(m_CSUUIDToName);
for (size_t idx = 0; idx < JsonCount; ++idx)
for (Json::Value::UInt idx = 0; idx < JsonCount; ++idx)
{
Json::Value & Val = root[idx];
AString JsonName = Val.get("name", "").asString();
@@ -792,6 +796,21 @@ void cMojangAPI::CacheUUIDToProfile(const AString & a_UUID)
cCSLock Lock(m_CSNameToUUID);
m_NameToUUID[StrToLower(PlayerName)] = sProfile(PlayerName, a_UUID, Properties, Now);
}
NotifyNameUUID(PlayerName, a_UUID);
}
void cMojangAPI::NotifyNameUUID(const AString & a_PlayerName, const AString & a_UUID)
{
// Notify the rank manager:
cCSLock Lock(m_CSRankMgr);
if (m_RankMgr != NULL)
{
m_RankMgr->NotifyNameUUID(a_PlayerName, a_UUID);
}
}
View
@@ -11,6 +11,13 @@
#include <time.h>
// fwd: ../RankManager.h"
class cRankManager;
namespace Json
{
class Value;
@@ -38,8 +45,6 @@ class cMojangAPI
Returns true if all was successful, false on failure. */
static bool SecureRequest(const AString & a_ServerName, const AString & a_Request, AString & a_Response);
// tolua_begin
/** Normalizes the given UUID to its short form (32 bytes, no dashes, lowercase).
Logs a warning and returns empty string if not a UUID.
Note: only checks the string's length, not the actual content. */
@@ -50,8 +55,6 @@ class cMojangAPI
Note: only checks the string's length, not the actual content. */
static AString MakeUUIDDashed(const AString & a_UUID);
// tolua_end
/** Converts a player name into a UUID.
The UUID will be empty on error.
If a_UseOnlyCached is true, the function only consults the cached values.
@@ -85,7 +88,10 @@ class cMojangAPI
/** Called by the Authenticator to add a profile that it has received from authenticating a user. Adds
the profile to the respective mapping caches and updtes their datetime stamp to now. */
void AddPlayerProfile(const AString & a_PlayerName, const AString & a_UUID, const Json::Value & a_Properties);
/** Sets the m_RankMgr that is used for name-uuid notifications. Accepts NULL to remove the binding. */
void SetRankManager(cRankManager * a_RankManager) { m_RankMgr = a_RankManager; }
protected:
/** Holds data for a single player profile. */
struct sProfile
@@ -165,6 +171,12 @@ class cMojangAPI
/** Protects m_UUIDToProfile against simultaneous multi-threaded access. */
cCriticalSection m_CSUUIDToProfile;
/** The rank manager that is notified of the name-uuid pairings. May be NULL. Protected by m_CSRankMgr. */
cRankManager * m_RankMgr;
/** Protects m_RankMgr agains simultaneous multi-threaded access. */
cCriticalSection m_CSRankMgr;
/** Loads the caches from a disk storage. */
@@ -182,6 +194,10 @@ class cMojangAPI
UUIDs that are not valid will not be added into the cache.
ASSUMEs that a_UUID is a lowercased short UUID. */
void CacheUUIDToProfile(const AString & a_UUID);
/** Called for each name-uuid pairing that is discovered.
If assigned, notifies the m_RankManager of the event. */
void NotifyNameUUID(const AString & a_PlayerName, const AString & a_PlayerUUID);
} ; // tolua_export
View
@@ -116,7 +116,7 @@ class cProtocol
virtual void SendTabCompletionResults(const AStringVector & a_Results) = 0;
virtual void SendTeleportEntity (const cEntity & a_Entity) = 0;
virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) = 0;
virtual void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay) = 0;
virtual void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_DoDaylightCycle) = 0;
virtual void SendUnloadChunk (int a_ChunkX, int a_ChunkZ) = 0;
virtual void SendUpdateBlockEntity (cBlockEntity & a_BlockEntity) = 0;
virtual void SendUpdateSign (int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4) = 0;
View
@@ -1072,8 +1072,11 @@ void cProtocol125::SendThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ)
void cProtocol125::SendTimeUpdate(Int64 a_WorldAge, Int64 a_TimeOfDay)
void cProtocol125::SendTimeUpdate(Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_DoDaylightCycle)
{
// This protocol doesn't support a_DoDaylightCycle on false.
UNUSED(a_DoDaylightCycle);
cCSLock Lock(m_CSPacket);
WriteByte (PACKET_UPDATE_TIME);
// Use a_WorldAge for daycount, and a_TimeOfDay for the proper time of day:
View
@@ -88,7 +88,7 @@ class cProtocol125 :
virtual void SendTabCompletionResults(const AStringVector & a_Results) override;
virtual void SendTeleportEntity (const cEntity & a_Entity) override;
virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) override;
virtual void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay) override;
virtual void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_DoDaylightCycle) override;
virtual void SendUnloadChunk (int a_ChunkX, int a_ChunkZ) override;
virtual void SendUpdateBlockEntity (cBlockEntity & a_BlockEntity) override {}
virtual void SendUpdateSign (int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4) override;
@@ -103,7 +103,7 @@ class cProtocol125 :
protected:
/// Results of packet-parsing:
enum
enum eParseResult
{
PARSE_OK = 1,
PARSE_ERROR = -1,
View
@@ -130,8 +130,14 @@ void cProtocol142::SendSoundParticleEffect(int a_EffectID, int a_SrcX, int a_Src
void cProtocol142::SendTimeUpdate(Int64 a_WorldAge, Int64 a_TimeOfDay)
void cProtocol142::SendTimeUpdate(Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_DoDaylightCycle)
{
if (!a_DoDaylightCycle)
{
// When writing a "-" before the number the client ignores it but it will stop the client-side time expiration.
a_TimeOfDay = std::min(-a_TimeOfDay, -1LL);
}
cCSLock Lock(m_CSPacket);
WriteByte (PACKET_UPDATE_TIME);
WriteInt64(a_WorldAge);
View
@@ -34,7 +34,7 @@ class cProtocol142 :
// Sending commands (alphabetically sorted):
virtual void SendPickupSpawn (const cPickup & a_Pickup) override;
virtual void SendSoundParticleEffect(int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) override;
virtual void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay) override;
virtual void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_DoDaylightCycle) override;
// Specific packet parsers:
virtual int ParseLocaleViewDistance(void) override;
View
@@ -41,14 +41,18 @@ Implements the 1.7.x protocol classes:
#include "../BlockEntities/CommandBlockEntity.h"
#include "../BlockEntities/MobHeadEntity.h"
#include "../BlockEntities/FlowerPotEntity.h"
#include "Bindings/PluginManager.h"
#define HANDLE_READ(ByteBuf, Proc, Type, Var) \
Type Var; \
ByteBuf.Proc(Var);
if (!ByteBuf.Proc(Var))\
{\
return;\
}
@@ -1286,9 +1290,14 @@ void cProtocol172::SendThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ)
void cProtocol172::SendTimeUpdate(Int64 a_WorldAge, Int64 a_TimeOfDay)
void cProtocol172::SendTimeUpdate(Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_DoDaylightCycle)
{
ASSERT(m_State == 3); // In game mode?
if (!a_DoDaylightCycle)
{
// When writing a "-" before the number the client ignores it but it will stop the client-side time expiration.
a_TimeOfDay = std::min(-a_TimeOfDay, -1LL);
}
cPacketizer Pkt(*this, 0x03);
Pkt.WriteInt64(a_WorldAge);
@@ -1700,8 +1709,7 @@ bool cProtocol172::HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketType)
void cProtocol172::HandlePacketStatusPing(cByteBuffer & a_ByteBuffer)
{
Int64 Timestamp;
a_ByteBuffer.ReadBEInt64(Timestamp);
HANDLE_READ(a_ByteBuffer, ReadBEInt64, Int64, Timestamp);
cPacketizer Pkt(*this, 0x01); // Ping packet
Pkt.WriteInt64(Timestamp);
@@ -1713,21 +1721,41 @@ void cProtocol172::HandlePacketStatusPing(cByteBuffer & a_ByteBuffer)
void cProtocol172::HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer)
{
// Send the response:
AString Response = "{\"version\":{\"name\":\"1.7.2\", \"protocol\":4}, \"players\":{";
cServer * Server = cRoot::Get()->GetServer();
AppendPrintf(Response, "\"max\":%u, \"online\":%u, \"sample\":[]},",
Server->GetMaxPlayers(),
Server->GetNumPlayers()
);
AppendPrintf(Response, "\"description\":{\"text\":\"%s\"},",
Server->GetDescription().c_str()
);
AppendPrintf(Response, "\"favicon\": \"data:image/png;base64,%s\"",
Server->GetFaviconData().c_str()
);
Response.append("}");
AString ServerDescription = Server->GetDescription();
int NumPlayers = Server->GetNumPlayers();
int MaxPlayers = Server->GetMaxPlayers();
AString Favicon = Server->GetFaviconData();
cRoot::Get()->GetPluginManager()->CallHookServerPing(*m_Client, ServerDescription, NumPlayers, MaxPlayers, Favicon);
// Version:
Json::Value Version;
Version["name"] = "1.7.2";
Version["protocol"] = 4;
// Players:
Json::Value Players;
Players["online"] = NumPlayers;
Players["max"] = MaxPlayers;
// TODO: Add "sample"
// Description:
Json::Value Description;
Description["text"] = ServerDescription.c_str();
// Create the response:
Json::Value ResponseValue;
ResponseValue["version"] = Version;
ResponseValue["players"] = Players;
ResponseValue["description"] = Description;
if (!Favicon.empty())
{
ResponseValue["favicon"] = Printf("data:image/png;base64,%s", Favicon.c_str());
}
Json::StyledWriter Writer;
AString Response = Writer.write(ResponseValue);
cPacketizer Pkt(*this, 0x00); // Response packet
Pkt.WriteString(Response);
}
@@ -1796,7 +1824,11 @@ void cProtocol172::HandlePacketLoginEncryptionResponse(cByteBuffer & a_ByteBuffe
void cProtocol172::HandlePacketLoginStart(cByteBuffer & a_ByteBuffer)
{
AString Username;
a_ByteBuffer.ReadVarUTF8String(Username);
if (!a_ByteBuffer.ReadVarUTF8String(Username))
{
m_Client->Kick("Bad username");
return;
}
if (!m_Client->HandleHandshake(Username))
{
@@ -2054,7 +2086,10 @@ void cProtocol172::HandlePacketPluginMessage(cByteBuffer & a_ByteBuffer)
HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Channel);
HANDLE_READ(a_ByteBuffer, ReadBEShort, short, Length);
AString Data;
a_ByteBuffer.ReadString(Data, Length);
if (!a_ByteBuffer.ReadString(Data, Length))
{
return;
}
m_Client->HandlePluginMessage(Channel, Data);
}
@@ -3060,20 +3095,41 @@ void cProtocol176::SendPlayerSpawn(const cPlayer & a_Player)
void cProtocol176::HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer)
{
// Send the response:
AString Response = "{\"version\": {\"name\": \"1.7.6\", \"protocol\":5}, \"players\": {";
AppendPrintf(Response, "\"max\": %u, \"online\": %u, \"sample\": []},",
cRoot::Get()->GetServer()->GetMaxPlayers(),
cRoot::Get()->GetServer()->GetNumPlayers()
);
AppendPrintf(Response, "\"description\": {\"text\": \"%s\"},",
cRoot::Get()->GetServer()->GetDescription().c_str()
);
AppendPrintf(Response, "\"favicon\": \"data:image/png;base64,%s\"",
cRoot::Get()->GetServer()->GetFaviconData().c_str()
);
Response.append("}");
cServer * Server = cRoot::Get()->GetServer();
AString Motd = Server->GetDescription();
int NumPlayers = Server->GetNumPlayers();
int MaxPlayers = Server->GetMaxPlayers();
AString Favicon = Server->GetFaviconData();
cRoot::Get()->GetPluginManager()->CallHookServerPing(*m_Client, Motd, NumPlayers, MaxPlayers, Favicon);
// Version:
Json::Value Version;
Version["name"] = "1.7.6";
Version["protocol"] = 5;
// Players:
Json::Value Players;
Players["online"] = NumPlayers;
Players["max"] = MaxPlayers;
// TODO: Add "sample"
// Description:
Json::Value Description;
Description["text"] = Motd.c_str();
// Create the response:
Json::Value ResponseValue;
ResponseValue["version"] = Version;
ResponseValue["players"] = Players;
ResponseValue["description"] = Description;
if (!Favicon.empty())
{
ResponseValue["favicon"] = Printf("data:image/png;base64,%s", Favicon.c_str());
}
Json::StyledWriter Writer;
AString Response = Writer.write(ResponseValue);
cPacketizer Pkt(*this, 0x00); // Response packet
Pkt.WriteString(Response);
}
View
@@ -120,7 +120,7 @@ class cProtocol172 :
virtual void SendTabCompletionResults(const AStringVector & a_Results) override;
virtual void SendTeleportEntity (const cEntity & a_Entity) override;
virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) override;
virtual void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay) override;
virtual void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_DoDaylightCycle) override;
virtual void SendUnloadChunk (int a_ChunkX, int a_ChunkZ) override;
virtual void SendUpdateBlockEntity (cBlockEntity & a_BlockEntity) override;
virtual void SendUpdateSign (int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4) override;
Oops, something went wrong.