Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
15bee41a36
@ -1188,7 +1188,7 @@ These ItemGrids are available in the API and can be manipulated by the plugins,
|
|||||||
constructor =
|
constructor =
|
||||||
{
|
{
|
||||||
{ Params = "", Return = "cItem", Notes = "Creates a new empty cItem object" },
|
{ Params = "", Return = "cItem", Notes = "Creates a new empty cItem object" },
|
||||||
{ Params = "ItemType, Count, Damage, EnchantmentString", Return = "cItem", Notes = "Creates a new cItem object of the specified type, count (1 by default), damage (0 by default) and enchantments (non-enchanted by default)" },
|
{ Params = "ItemType, Count, Damage, EnchantmentString, CustomName, Lore", Return = "cItem", Notes = "Creates a new cItem object of the specified type, count (1 by default), damage (0 by default), enchantments (non-enchanted by default), CustomName (empty by default) and Lore (string, empty by default)" },
|
||||||
{ Params = "cItem", Return = "cItem", Notes = "Creates an exact copy of the cItem object in the parameter" },
|
{ Params = "cItem", Return = "cItem", Notes = "Creates an exact copy of the cItem object in the parameter" },
|
||||||
} ,
|
} ,
|
||||||
AddCount = { Params = "AmountToAdd", Return = "cItem", Notes = "Adds the specified amount to the item count. Returns self (useful for chaining)." },
|
AddCount = { Params = "AmountToAdd", Return = "cItem", Notes = "Adds the specified amount to the item count. Returns self (useful for chaining)." },
|
||||||
@ -1201,12 +1201,14 @@ These ItemGrids are available in the API and can be manipulated by the plugins,
|
|||||||
IsDamageable = { Params = "", Return = "bool", Notes = "Returns true if this item does account for its damage" },
|
IsDamageable = { Params = "", Return = "bool", Notes = "Returns true if this item does account for its damage" },
|
||||||
IsEmpty = { Params = "", Return = "bool", Notes = "Returns true if this object represents an empty item (zero count or invalid ID)" },
|
IsEmpty = { Params = "", Return = "bool", Notes = "Returns true if this object represents an empty item (zero count or invalid ID)" },
|
||||||
IsEqual = { Params = "cItem", Return = "bool", Notes = "Returns true if the item in the parameter is the same as the one stored in the object (type, damage, lore, name and enchantments)" },
|
IsEqual = { Params = "cItem", Return = "bool", Notes = "Returns true if the item in the parameter is the same as the one stored in the object (type, damage, lore, name and enchantments)" },
|
||||||
IsEnchantable = { Params = "", Return = "bool", Notes = "Returns true if the item is enchantable" },
|
|
||||||
IsFullStack = { Params = "", Return = "bool", Notes = "Returns true if the item is stacked up to its maximum stacking" },
|
IsFullStack = { Params = "", Return = "bool", Notes = "Returns true if the item is stacked up to its maximum stacking" },
|
||||||
IsSameType = { Params = "cItem", Return = "bool", Notes = "Returns true if the item in the parameter is of the same ItemType as the one stored in the object. This is true even if the two items have different enchantments" },
|
IsSameType = { Params = "cItem", Return = "bool", Notes = "Returns true if the item in the parameter is of the same ItemType as the one stored in the object. This is true even if the two items have different enchantments" },
|
||||||
IsBothNameAndLoreEmpty = { Params = "", Return = "bool", Notes = "Returns if both the custom name and lore are not set." },
|
IsBothNameAndLoreEmpty = { Params = "", Return = "bool", Notes = "Returns if both the custom name and lore are not set." },
|
||||||
IsCustomNameEmpty = { Params = "", Return = "bool", Notes = "Returns if the custom name of the cItem is empty." },
|
IsCustomNameEmpty = { Params = "", Return = "bool", Notes = "Returns if the custom name of the cItem is empty." },
|
||||||
IsLoreEmpty = { Params = "", Return = "", Notes = "Returns if the lore of the cItem is empty." },
|
IsLoreEmpty = { Params = "", Return = "", Notes = "Returns if the lore of the cItem is empty." },
|
||||||
|
GetEnchantability = { Params = "", Return = "number", Notes = "Returns the enchantability of the item. When the item hasn't a enchantability, it will returns 0" },
|
||||||
|
EnchantByXPLevels = { Params = "NumXPLevels", Return = "bool", Notes = "Enchants the item using the specified number of XP levels. Returns true if item enchanted, false if not." },
|
||||||
|
IsEnchantable = { Params = "ItemType, WithBook", Return = "bool", Notes = "(STATIC) Returns true if the specified item type is enchantable. If WithBook is true, the function is used in the anvil inventory with book enchantments. So it checks the \"only book enchantments\" too. Example: You can only enchant a hoe with a book." },
|
||||||
},
|
},
|
||||||
Variables =
|
Variables =
|
||||||
{
|
{
|
||||||
@ -1214,8 +1216,10 @@ These ItemGrids are available in the API and can be manipulated by the plugins,
|
|||||||
m_ItemCount = { Type = "number", Notes = "Number of items in this stack" },
|
m_ItemCount = { Type = "number", Notes = "Number of items in this stack" },
|
||||||
m_ItemDamage = { Type = "number", Notes = "The damage of the item. Zero means no damage. Maximum damage can be queried with GetMaxDamage()" },
|
m_ItemDamage = { Type = "number", Notes = "The damage of the item. Zero means no damage. Maximum damage can be queried with GetMaxDamage()" },
|
||||||
m_ItemType = { Type = "number", Notes = "The item type. One of E_ITEM_ or E_BLOCK_ constants" },
|
m_ItemType = { Type = "number", Notes = "The item type. One of E_ITEM_ or E_BLOCK_ constants" },
|
||||||
m_CustomName = { Type = "string", Notes = "The custom name for an item." },
|
m_CustomName = { Type = "string", Notes = "The custom name for an item." },
|
||||||
m_Lore = { Type = "string", Notes = "The lore for an item. Line breaks are represented by the ` character." },
|
m_Lore = { Type = "string", Notes = "The lore for an item. Line breaks are represented by the ` character." },
|
||||||
|
m_RepairCost = { Type = "number", Notes = "The repair cost of the item. The anvil need this value" },
|
||||||
|
m_Enchantments = { Type = "{{cEnchantments|cEnchantments}}}", Notes = "The enchantments of the item." },
|
||||||
},
|
},
|
||||||
AdditionalInfo =
|
AdditionalInfo =
|
||||||
{
|
{
|
||||||
@ -2340,6 +2344,7 @@ end
|
|||||||
ForEachBlockEntityInChunk = { Params = "ChunkX, ChunkZ, CallbackFunction, [CallbackData]", Return = "bool", Notes = "Calls the specified callback for each block entity in the chunk. Returns true if all block entities in the chunk have been processed (including when there are zero block entities), or false if the callback has aborted the enumeration by returning true. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cBlockEntity|BlockEntity}}, [CallbackData])</pre> The callback should return false or no value to continue with the next block entity, or true to abort the enumeration. Use {{tolua}}.cast() to cast the Callback's BlockEntity parameter to the correct {{cBlockEntity}} descendant." },
|
ForEachBlockEntityInChunk = { Params = "ChunkX, ChunkZ, CallbackFunction, [CallbackData]", Return = "bool", Notes = "Calls the specified callback for each block entity in the chunk. Returns true if all block entities in the chunk have been processed (including when there are zero block entities), or false if the callback has aborted the enumeration by returning true. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cBlockEntity|BlockEntity}}, [CallbackData])</pre> The callback should return false or no value to continue with the next block entity, or true to abort the enumeration. Use {{tolua}}.cast() to cast the Callback's BlockEntity parameter to the correct {{cBlockEntity}} descendant." },
|
||||||
ForEachChestInChunk = { Params = "ChunkX, ChunkZ, CallbackFunction, [CallbackData]", Return = "bool", Notes = "Calls the specified callback for each chest in the chunk. Returns true if all chests in the chunk have been processed (including when there are zero chests), or false if the callback has aborted the enumeration by returning true. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cChestEntity|ChestEntity}}, [CallbackData])</pre> The callback should return false or no value to continue with the next chest, or true to abort the enumeration." },
|
ForEachChestInChunk = { Params = "ChunkX, ChunkZ, CallbackFunction, [CallbackData]", Return = "bool", Notes = "Calls the specified callback for each chest in the chunk. Returns true if all chests in the chunk have been processed (including when there are zero chests), or false if the callback has aborted the enumeration by returning true. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cChestEntity|ChestEntity}}, [CallbackData])</pre> The callback should return false or no value to continue with the next chest, or true to abort the enumeration." },
|
||||||
ForEachEntity = { Params = "CallbackFunction, [CallbackData]", Return = "bool", Notes = "Calls the specified callback for each entity in the loaded world. Returns true if all the entities have been processed (including when there are zero entities), or false if the callback function has aborted the enumeration by returning true. The callback function has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cEntity|Entity}}, [CallbackData])</pre> The callback should return false or no value to continue with the next entity, or true to abort the enumeration." },
|
ForEachEntity = { Params = "CallbackFunction, [CallbackData]", Return = "bool", Notes = "Calls the specified callback for each entity in the loaded world. Returns true if all the entities have been processed (including when there are zero entities), or false if the callback function has aborted the enumeration by returning true. The callback function has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cEntity|Entity}}, [CallbackData])</pre> The callback should return false or no value to continue with the next entity, or true to abort the enumeration." },
|
||||||
|
ForEachEntityInBox = { Params = "{{cBoundingBox|Box}}, CallbackFunction", Return = "bool", Notes = "Calls the specified callback for each entity in the specified bounding box. Returns true if all the entities have been processed (including when there are zero entities), or false if the callback function has aborted the enumeration by returning true. If any chunk within the bounding box is not valid, it is silently skipped without any notification. The callback function has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cEntity|Entity}})</pre> The callback should return false or no value to continue with the next entity, or true to abort the enumeration." },
|
||||||
ForEachEntityInChunk = { Params = "ChunkX, ChunkZ, CallbackFunction, [CallbackData]", Return = "bool", Notes = "Calls the specified callback for each entity in the specified chunk. Returns true if all the entities have been processed (including when there are zero entities), or false if the chunk is not loaded or the callback function has aborted the enumeration by returning true. The callback function has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cEntity|Entity}}, [CallbackData])</pre> The callback should return false or no value to continue with the next entity, or true to abort the enumeration." },
|
ForEachEntityInChunk = { Params = "ChunkX, ChunkZ, CallbackFunction, [CallbackData]", Return = "bool", Notes = "Calls the specified callback for each entity in the specified chunk. Returns true if all the entities have been processed (including when there are zero entities), or false if the chunk is not loaded or the callback function has aborted the enumeration by returning true. The callback function has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cEntity|Entity}}, [CallbackData])</pre> The callback should return false or no value to continue with the next entity, or true to abort the enumeration." },
|
||||||
ForEachFurnaceInChunk = { Params = "ChunkX, ChunkZ, CallbackFunction, [CallbackData]", Return = "bool", Notes = "Calls the specified callback for each furnace in the chunk. Returns true if all furnaces in the chunk have been processed (including when there are zero furnaces), or false if the callback has aborted the enumeration by returning true. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cFurnaceEntity|FurnaceEntity}}, [CallbackData])</pre> The callback should return false or no value to continue with the next furnace, or true to abort the enumeration." },
|
ForEachFurnaceInChunk = { Params = "ChunkX, ChunkZ, CallbackFunction, [CallbackData]", Return = "bool", Notes = "Calls the specified callback for each furnace in the chunk. Returns true if all furnaces in the chunk have been processed (including when there are zero furnaces), or false if the callback has aborted the enumeration by returning true. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cFurnaceEntity|FurnaceEntity}}, [CallbackData])</pre> The callback should return false or no value to continue with the next furnace, or true to abort the enumeration." },
|
||||||
ForEachPlayer = { Params = "CallbackFunction, [CallbackData]", Return = "bool", Notes = "Calls the specified callback for each player in the loaded world. Returns true if all the players have been processed (including when there are zero players), or false if the callback function has aborted the enumeration by returning true. The callback function has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cPlayer|Player}}, [CallbackData])</pre> The callback should return false or no value to continue with the next player, or true to abort the enumeration." },
|
ForEachPlayer = { Params = "CallbackFunction, [CallbackData]", Return = "bool", Notes = "Calls the specified callback for each player in the loaded world. Returns true if all the players have been processed (including when there are zero players), or false if the callback function has aborted the enumeration by returning true. The callback function has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cPlayer|Player}}, [CallbackData])</pre> The callback should return false or no value to continue with the next player, or true to abort the enumeration." },
|
||||||
|
@ -65,6 +65,8 @@ function Initialize(Plugin)
|
|||||||
PM:BindCommand("/sb", "debuggers", HandleSetBiome, "- Sets the biome around you to the specified one");
|
PM:BindCommand("/sb", "debuggers", HandleSetBiome, "- Sets the biome around you to the specified one");
|
||||||
PM:BindCommand("/wesel", "debuggers", HandleWESel, "- Expands the current WE selection by 1 block in X/Z");
|
PM:BindCommand("/wesel", "debuggers", HandleWESel, "- Expands the current WE selection by 1 block in X/Z");
|
||||||
PM:BindCommand("/rmitem", "debuggers", HandleRMItem, "- Remove the specified item from the inventory.");
|
PM:BindCommand("/rmitem", "debuggers", HandleRMItem, "- Remove the specified item from the inventory.");
|
||||||
|
PM:BindCommand("/pickups", "debuggers", HandlePickups, "- Spawns random pickups around you");
|
||||||
|
PM:BindCommand("/poof", "debuggers", HandlePoof, "- Nudges pickups close to you away from you");
|
||||||
|
|
||||||
Plugin:AddWebTab("Debuggers", HandleRequest_Debuggers)
|
Plugin:AddWebTab("Debuggers", HandleRequest_Debuggers)
|
||||||
Plugin:AddWebTab("StressTest", HandleRequest_StressTest)
|
Plugin:AddWebTab("StressTest", HandleRequest_StressTest)
|
||||||
@ -1558,3 +1560,57 @@ end
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
local PossibleItems =
|
||||||
|
{
|
||||||
|
cItem(E_ITEM_DIAMOND),
|
||||||
|
cItem(E_ITEM_GOLD),
|
||||||
|
cItem(E_ITEM_IRON),
|
||||||
|
cItem(E_ITEM_DYE, 1, E_META_DYE_BLUE), -- Lapis lazuli
|
||||||
|
cItem(E_ITEM_COAL),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function HandlePickups(a_Split, a_Player)
|
||||||
|
local PlayerX = a_Player:GetPosX()
|
||||||
|
local PlayerY = a_Player:GetPosY()
|
||||||
|
local PlayerZ = a_Player:GetPosZ()
|
||||||
|
local World = a_Player:GetWorld()
|
||||||
|
local Range = 12
|
||||||
|
for x = 0, Range do for z = 0, Range do
|
||||||
|
local px = PlayerX + x - Range / 2
|
||||||
|
local pz = PlayerZ + z - Range / 2
|
||||||
|
local Items = cItems()
|
||||||
|
Items:Add(PossibleItems[math.random(#PossibleItems)])
|
||||||
|
World:SpawnItemPickups(Items, px, PlayerY, pz, 0)
|
||||||
|
end end -- for z, for x
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function HandlePoof(a_Split, a_Player)
|
||||||
|
local PlayerPos = Vector3d(a_Player:GetPosition()) -- Create a copy of the position
|
||||||
|
PlayerPos.y = PlayerPos.y - 1
|
||||||
|
local Box = cBoundingBox(PlayerPos, 4, 2)
|
||||||
|
local NumEntities = 0
|
||||||
|
a_Player:GetWorld():ForEachEntityInBox(Box,
|
||||||
|
function (a_Entity)
|
||||||
|
if not(a_Entity:IsPlayer()) then
|
||||||
|
local AddSpeed = a_Entity:GetPosition() - PlayerPos -- Speed away from the player
|
||||||
|
a_Entity:AddSpeed(AddSpeed * 32 / (AddSpeed:SqrLength() + 1)) -- The further away, the less speed to add
|
||||||
|
NumEntities = NumEntities + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
)
|
||||||
|
a_Player:SendMessage("Poof! (" .. NumEntities .. " entities)")
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit 27b9d111818af3b05bcf4153bb6e380fe1dd6816
|
Subproject commit 203c2fb68bbf871eaf4ca98756a113d74d620dea
|
@ -668,6 +668,24 @@ void cIniFile::Clear(void)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool cIniFile::HasValue(const AString & a_KeyName, const AString & a_ValueName)
|
||||||
|
{
|
||||||
|
// Find the key:
|
||||||
|
int keyID = FindKey(a_KeyName);
|
||||||
|
if (keyID == noID)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the value:
|
||||||
|
int valueID = FindValue(keyID, a_ValueName);
|
||||||
|
return (valueID != noID);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cIniFile::AddHeaderComment(const AString & comment)
|
void cIniFile::AddHeaderComment(const AString & comment)
|
||||||
{
|
{
|
||||||
comments.push_back(comment);
|
comments.push_back(comment);
|
||||||
|
@ -53,7 +53,9 @@ private:
|
|||||||
|
|
||||||
/// Removes the UTF-8 BOMs (Byte order makers), if present.
|
/// Removes the UTF-8 BOMs (Byte order makers), if present.
|
||||||
void RemoveBom(AString & a_line) const;
|
void RemoveBom(AString & a_line) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
enum errors
|
enum errors
|
||||||
{
|
{
|
||||||
noID = -1,
|
noID = -1,
|
||||||
@ -80,6 +82,9 @@ public:
|
|||||||
/// Deletes all stored ini data (but doesn't touch the file)
|
/// Deletes all stored ini data (but doesn't touch the file)
|
||||||
void Clear(void);
|
void Clear(void);
|
||||||
|
|
||||||
|
/** Returns true iff the specified value exists. */
|
||||||
|
bool HasValue(const AString & a_KeyName, const AString & a_ValueName);
|
||||||
|
|
||||||
/// Returns index of specified key, or noID if not found
|
/// Returns index of specified key, or noID if not found
|
||||||
int FindKey(const AString & keyname) const;
|
int FindKey(const AString & keyname) const;
|
||||||
|
|
||||||
|
@ -36,7 +36,9 @@ extern "C" {
|
|||||||
#define TEMPLATE_BIND(p)
|
#define TEMPLATE_BIND(p)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define TOLUA_TEMPLATE_BIND(p)
|
#ifndef TOLUA_TEMPLATE_BIND
|
||||||
|
#define TOLUA_TEMPLATE_BIND(p)
|
||||||
|
#endif
|
||||||
|
|
||||||
#define TOLUA_PROTECTED_DESTRUCTOR
|
#define TOLUA_PROTECTED_DESTRUCTOR
|
||||||
#define TOLUA_PROPERTY_TYPE(p)
|
#define TOLUA_PROPERTY_TYPE(p)
|
||||||
|
@ -107,7 +107,7 @@ void cLuaChunkStay::AddChunkCoord(cLuaState & L, int a_Index)
|
|||||||
}
|
}
|
||||||
} // for itr - m_Chunks[]
|
} // for itr - m_Chunks[]
|
||||||
|
|
||||||
m_Chunks.push_back(cChunkCoords(ChunkX, ZERO_CHUNK_Y, ChunkZ));
|
m_Chunks.push_back(cChunkCoords(ChunkX, ChunkZ));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -859,6 +859,32 @@ void cLuaState::GetStackValue(int a_StackPos, eWeather & a_ReturnedVal)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cLuaState::GetStackValue(int a_StackPos, pBoundingBox & a_ReturnedVal)
|
||||||
|
{
|
||||||
|
tolua_Error err;
|
||||||
|
if (tolua_isusertype(m_LuaState, a_StackPos, "cBoundingBox", false, &err))
|
||||||
|
{
|
||||||
|
a_ReturnedVal = *((cBoundingBox **)lua_touserdata(m_LuaState, a_StackPos));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cLuaState::GetStackValue(int a_StackPos, pWorld & a_ReturnedVal)
|
||||||
|
{
|
||||||
|
tolua_Error err;
|
||||||
|
if (tolua_isusertype(m_LuaState, a_StackPos, "cWorld", false, &err))
|
||||||
|
{
|
||||||
|
a_ReturnedVal = *((cWorld **)lua_touserdata(m_LuaState, a_StackPos));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cLuaState::CallFunction(int a_NumResults)
|
bool cLuaState::CallFunction(int a_NumResults)
|
||||||
{
|
{
|
||||||
ASSERT (m_NumCurrentFunctionArgs >= 0); // A function must be pushed to stack first
|
ASSERT (m_NumCurrentFunctionArgs >= 0); // A function must be pushed to stack first
|
||||||
|
@ -59,6 +59,10 @@ class cTNTEntity;
|
|||||||
class cCreeper;
|
class cCreeper;
|
||||||
class cHopperEntity;
|
class cHopperEntity;
|
||||||
class cBlockEntity;
|
class cBlockEntity;
|
||||||
|
class cBoundingBox;
|
||||||
|
|
||||||
|
typedef cBoundingBox * pBoundingBox;
|
||||||
|
typedef cWorld * pWorld;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -231,6 +235,12 @@ public:
|
|||||||
If not, a_Value is unchanged. */
|
If not, a_Value is unchanged. */
|
||||||
void GetStackValue(int a_StackPos, eWeather & a_Value);
|
void GetStackValue(int a_StackPos, eWeather & a_Value);
|
||||||
|
|
||||||
|
/** Retrieve value at a_StackPos, if it is a valid cBoundingBox class. If not, a_Value is unchanged */
|
||||||
|
void GetStackValue(int a_StackPos, pBoundingBox & a_Value);
|
||||||
|
|
||||||
|
/** Retrieve value at a_StackPos, if it is a valid cWorld class. If not, a_Value is unchanged */
|
||||||
|
void GetStackValue(int a_StackPos, pWorld & a_Value);
|
||||||
|
|
||||||
|
|
||||||
// Include the cLuaState::Call() overload implementation that is generated by the gen_LuaState_Call.lua script:
|
// Include the cLuaState::Call() overload implementation that is generated by the gen_LuaState_Call.lua script:
|
||||||
#include "LuaState_Call.inc"
|
#include "LuaState_Call.inc"
|
||||||
@ -328,6 +338,14 @@ protected:
|
|||||||
*/
|
*/
|
||||||
bool PushFunction(int a_FnRef);
|
bool PushFunction(int a_FnRef);
|
||||||
|
|
||||||
|
/** Pushes a function that has been saved as a reference.
|
||||||
|
Returns true if successful. Logs a warning on failure
|
||||||
|
*/
|
||||||
|
bool PushFunction(const cRef & a_FnRef)
|
||||||
|
{
|
||||||
|
return PushFunction((int)a_FnRef);
|
||||||
|
}
|
||||||
|
|
||||||
/** Pushes a function that is stored in a referenced table by name
|
/** Pushes a function that is stored in a referenced table by name
|
||||||
Returns true if successful. Logs a warning on failure
|
Returns true if successful. Logs a warning on failure
|
||||||
*/
|
*/
|
||||||
|
@ -676,6 +676,75 @@ static int tolua_ForEachInChunk(lua_State * tolua_S)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
template <
|
||||||
|
class Ty1,
|
||||||
|
class Ty2,
|
||||||
|
bool (Ty1::*Func1)(const cBoundingBox &, cItemCallback<Ty2> &)
|
||||||
|
>
|
||||||
|
static int tolua_ForEachInBox(lua_State * tolua_S)
|
||||||
|
{
|
||||||
|
// Check params:
|
||||||
|
cLuaState L(tolua_S);
|
||||||
|
if (
|
||||||
|
!L.CheckParamUserType(1, "cWorld") ||
|
||||||
|
!L.CheckParamUserType(2, "cBoundingBox") ||
|
||||||
|
!L.CheckParamFunction(3) ||
|
||||||
|
!L.CheckParamEnd(4)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the params:
|
||||||
|
Ty1 * Self = NULL;
|
||||||
|
cBoundingBox * Box = NULL;
|
||||||
|
L.GetStackValues(1, Self, Box);
|
||||||
|
ASSERT(Self != NULL); // We have verified the type at the top, so we should get valid objects here
|
||||||
|
ASSERT(Box != NULL);
|
||||||
|
|
||||||
|
// Create a reference for the function:
|
||||||
|
cLuaState::cRef FnRef(L, 3);
|
||||||
|
|
||||||
|
// Callback wrapper for the Lua function:
|
||||||
|
class cLuaCallback : public cItemCallback<Ty2>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
cLuaCallback(cLuaState & a_LuaState, cLuaState::cRef & a_FuncRef) :
|
||||||
|
m_LuaState(a_LuaState),
|
||||||
|
m_FnRef(a_FuncRef)
|
||||||
|
{}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// cItemCallback<Ty2> overrides:
|
||||||
|
virtual bool Item(Ty2 * a_Item) override
|
||||||
|
{
|
||||||
|
bool res = false;
|
||||||
|
if (!m_LuaState.Call(m_FnRef, a_Item, cLuaState::Return, res))
|
||||||
|
{
|
||||||
|
LOGWARNING("Failed to call Lua callback");
|
||||||
|
m_LuaState.LogStackTrace();
|
||||||
|
return true; // Abort enumeration
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
cLuaState & m_LuaState;
|
||||||
|
cLuaState::cRef & m_FnRef;
|
||||||
|
} Callback(L, FnRef);
|
||||||
|
|
||||||
|
bool bRetVal = (Self->*Func1)(*Box, Callback);
|
||||||
|
|
||||||
|
FnRef.UnRef();
|
||||||
|
|
||||||
|
/* Push return value on stack */
|
||||||
|
tolua_pushboolean(tolua_S, bRetVal);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
template <
|
template <
|
||||||
class Ty1,
|
class Ty1,
|
||||||
class Ty2,
|
class Ty2,
|
||||||
@ -3327,6 +3396,7 @@ void ManualBindings::Bind(lua_State * tolua_S)
|
|||||||
tolua_function(tolua_S, "ForEachBlockEntityInChunk", tolua_ForEachInChunk<cWorld, cBlockEntity, &cWorld::ForEachBlockEntityInChunk>);
|
tolua_function(tolua_S, "ForEachBlockEntityInChunk", tolua_ForEachInChunk<cWorld, cBlockEntity, &cWorld::ForEachBlockEntityInChunk>);
|
||||||
tolua_function(tolua_S, "ForEachChestInChunk", tolua_ForEachInChunk<cWorld, cChestEntity, &cWorld::ForEachChestInChunk>);
|
tolua_function(tolua_S, "ForEachChestInChunk", tolua_ForEachInChunk<cWorld, cChestEntity, &cWorld::ForEachChestInChunk>);
|
||||||
tolua_function(tolua_S, "ForEachEntity", tolua_ForEach< cWorld, cEntity, &cWorld::ForEachEntity>);
|
tolua_function(tolua_S, "ForEachEntity", tolua_ForEach< cWorld, cEntity, &cWorld::ForEachEntity>);
|
||||||
|
tolua_function(tolua_S, "ForEachEntityInBox", tolua_ForEachInBox< cWorld, cEntity, &cWorld::ForEachEntityInBox>);
|
||||||
tolua_function(tolua_S, "ForEachEntityInChunk", tolua_ForEachInChunk<cWorld, cEntity, &cWorld::ForEachEntityInChunk>);
|
tolua_function(tolua_S, "ForEachEntityInChunk", tolua_ForEachInChunk<cWorld, cEntity, &cWorld::ForEachEntityInChunk>);
|
||||||
tolua_function(tolua_S, "ForEachFurnaceInChunk", tolua_ForEachInChunk<cWorld, cFurnaceEntity, &cWorld::ForEachFurnaceInChunk>);
|
tolua_function(tolua_S, "ForEachFurnaceInChunk", tolua_ForEachInChunk<cWorld, cFurnaceEntity, &cWorld::ForEachFurnaceInChunk>);
|
||||||
tolua_function(tolua_S, "ForEachPlayer", tolua_ForEach< cWorld, cPlayer, &cWorld::ForEachPlayer>);
|
tolua_function(tolua_S, "ForEachPlayer", tolua_ForEach< cWorld, cPlayer, &cWorld::ForEachPlayer>);
|
||||||
|
@ -109,7 +109,7 @@ local function WriteOverload(f, a_NumParams, a_NumReturns)
|
|||||||
|
|
||||||
-- Write the function signature:
|
-- Write the function signature:
|
||||||
f:write("bool Call(")
|
f:write("bool Call(")
|
||||||
f:write("FnT a_Function")
|
f:write("const FnT & a_Function")
|
||||||
for i = 1, a_NumParams do
|
for i = 1, a_NumParams do
|
||||||
f:write(", ParamT", i, " a_Param", i)
|
f:write(", ParamT", i, " a_Param", i)
|
||||||
end
|
end
|
||||||
|
@ -362,6 +362,8 @@ enum ENUM_ITEM_ID
|
|||||||
E_ITEM_LEAD = 420,
|
E_ITEM_LEAD = 420,
|
||||||
E_ITEM_NAME_TAG = 421,
|
E_ITEM_NAME_TAG = 421,
|
||||||
E_ITEM_MINECART_WITH_COMMAND_BLOCK = 422,
|
E_ITEM_MINECART_WITH_COMMAND_BLOCK = 422,
|
||||||
|
E_ITEM_RAW_MUTTON = 423,
|
||||||
|
E_ITEM_MUTTON = 424,
|
||||||
|
|
||||||
// Keep these two as the last values of the consecutive list, without a number - they will get their correct number assigned automagically by C++
|
// Keep these two as the last values of the consecutive list, without a number - they will get their correct number assigned automagically by C++
|
||||||
// IsValidItem() depends on this!
|
// IsValidItem() depends on this!
|
||||||
|
@ -80,6 +80,17 @@ public:
|
|||||||
/// Calculates the intersection of the two bounding boxes; returns true if nonempty
|
/// Calculates the intersection of the two bounding boxes; returns true if nonempty
|
||||||
bool Intersect(const cBoundingBox & a_Other, cBoundingBox & a_Intersection);
|
bool Intersect(const cBoundingBox & a_Other, cBoundingBox & a_Intersection);
|
||||||
|
|
||||||
|
double GetMinX(void) const { return m_Min.x; }
|
||||||
|
double GetMinY(void) const { return m_Min.y; }
|
||||||
|
double GetMinZ(void) const { return m_Min.z; }
|
||||||
|
|
||||||
|
double GetMaxX(void) const { return m_Max.x; }
|
||||||
|
double GetMaxY(void) const { return m_Max.y; }
|
||||||
|
double GetMaxZ(void) const { return m_Max.z; }
|
||||||
|
|
||||||
|
const Vector3d & GetMin(void) const { return m_Min; }
|
||||||
|
const Vector3d & GetMax(void) const { return m_Max; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Vector3d m_Min;
|
Vector3d m_Min;
|
||||||
Vector3d m_Max;
|
Vector3d m_Max;
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
#include "MobSpawner.h"
|
#include "MobSpawner.h"
|
||||||
#include "BlockInServerPluginInterface.h"
|
#include "BlockInServerPluginInterface.h"
|
||||||
#include "SetChunkData.h"
|
#include "SetChunkData.h"
|
||||||
|
#include "BoundingBox.h"
|
||||||
|
|
||||||
#include "json/json.h"
|
#include "json/json.h"
|
||||||
|
|
||||||
@ -65,7 +66,7 @@ sSetBlock::sSetBlock( int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_Bloc
|
|||||||
// cChunk:
|
// cChunk:
|
||||||
|
|
||||||
cChunk::cChunk(
|
cChunk::cChunk(
|
||||||
int a_ChunkX, int a_ChunkY, int a_ChunkZ,
|
int a_ChunkX, int a_ChunkZ,
|
||||||
cChunkMap * a_ChunkMap, cWorld * a_World,
|
cChunkMap * a_ChunkMap, cWorld * a_World,
|
||||||
cChunk * a_NeighborXM, cChunk * a_NeighborXP, cChunk * a_NeighborZM, cChunk * a_NeighborZP,
|
cChunk * a_NeighborXM, cChunk * a_NeighborXP, cChunk * a_NeighborZM, cChunk * a_NeighborZP,
|
||||||
cAllocationPool<cChunkData::sChunkSection> & a_Pool
|
cAllocationPool<cChunkData::sChunkSection> & a_Pool
|
||||||
@ -77,7 +78,6 @@ cChunk::cChunk(
|
|||||||
m_HasLoadFailed(false),
|
m_HasLoadFailed(false),
|
||||||
m_StayCount(0),
|
m_StayCount(0),
|
||||||
m_PosX(a_ChunkX),
|
m_PosX(a_ChunkX),
|
||||||
m_PosY(a_ChunkY),
|
|
||||||
m_PosZ(a_ChunkZ),
|
m_PosZ(a_ChunkZ),
|
||||||
m_World(a_World),
|
m_World(a_World),
|
||||||
m_ChunkMap(a_ChunkMap),
|
m_ChunkMap(a_ChunkMap),
|
||||||
@ -653,7 +653,7 @@ void cChunk::MoveEntityToNewChunk(cEntity * a_Entity)
|
|||||||
cChunk * Neighbor = GetNeighborChunk(a_Entity->GetChunkX() * cChunkDef::Width, a_Entity->GetChunkZ() * cChunkDef::Width);
|
cChunk * Neighbor = GetNeighborChunk(a_Entity->GetChunkX() * cChunkDef::Width, a_Entity->GetChunkZ() * cChunkDef::Width);
|
||||||
if (Neighbor == NULL)
|
if (Neighbor == NULL)
|
||||||
{
|
{
|
||||||
Neighbor = m_ChunkMap->GetChunkNoLoad(a_Entity->GetChunkX(), ZERO_CHUNK_Y, a_Entity->GetChunkZ());
|
Neighbor = m_ChunkMap->GetChunkNoLoad(a_Entity->GetChunkX(), a_Entity->GetChunkZ());
|
||||||
if (Neighbor == NULL)
|
if (Neighbor == NULL)
|
||||||
{
|
{
|
||||||
// TODO: What to do with this?
|
// TODO: What to do with this?
|
||||||
@ -1960,6 +1960,30 @@ bool cChunk::ForEachEntity(cEntityCallback & a_Callback)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool cChunk::ForEachEntityInBox(const cBoundingBox & a_Box, cEntityCallback & a_Callback)
|
||||||
|
{
|
||||||
|
// The entity list is locked by the parent chunkmap's CS
|
||||||
|
for (cEntityList::iterator itr = m_Entities.begin(), itr2 = itr; itr != m_Entities.end(); itr = itr2)
|
||||||
|
{
|
||||||
|
++itr2;
|
||||||
|
cBoundingBox EntBox((*itr)->GetPosition(), (*itr)->GetWidth() / 2, (*itr)->GetHeight());
|
||||||
|
if (!EntBox.DoesIntersect(a_Box))
|
||||||
|
{
|
||||||
|
// The entity is not in the specified box
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (a_Callback.Item(*itr))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} // for itr - m_Entitites[]
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cChunk::DoWithEntityByID(int a_EntityID, cEntityCallback & a_Callback, bool & a_CallbackResult)
|
bool cChunk::DoWithEntityByID(int a_EntityID, cEntityCallback & a_Callback, bool & a_CallbackResult)
|
||||||
{
|
{
|
||||||
// The entity list is locked by the parent chunkmap's CS
|
// The entity list is locked by the parent chunkmap's CS
|
||||||
@ -2603,7 +2627,7 @@ cChunk * cChunk::GetRelNeighborChunk(int a_RelX, int a_RelZ)
|
|||||||
int BlockZ = m_PosZ * cChunkDef::Width + a_RelZ;
|
int BlockZ = m_PosZ * cChunkDef::Width + a_RelZ;
|
||||||
int ChunkX, ChunkZ;
|
int ChunkX, ChunkZ;
|
||||||
BlockToChunk(BlockX, BlockZ, ChunkX, ChunkZ);
|
BlockToChunk(BlockX, BlockZ, ChunkX, ChunkZ);
|
||||||
return m_ChunkMap->GetChunkNoLoad(ChunkX, ZERO_CHUNK_Y, ChunkZ);
|
return m_ChunkMap->GetChunkNoLoad(ChunkX, ChunkZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Walk the neighbors:
|
// Walk the neighbors:
|
||||||
|
@ -67,7 +67,7 @@ class cChunk :
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
cChunk(
|
cChunk(
|
||||||
int a_ChunkX, int a_ChunkY, int a_ChunkZ, // Chunk coords
|
int a_ChunkX, int a_ChunkZ, // Chunk coords
|
||||||
cChunkMap * a_ChunkMap, cWorld * a_World, // Parent objects
|
cChunkMap * a_ChunkMap, cWorld * a_World, // Parent objects
|
||||||
cChunk * a_NeighborXM, cChunk * a_NeighborXP, cChunk * a_NeighborZM, cChunk * a_NeighborZP, // Neighbor chunks
|
cChunk * a_NeighborXM, cChunk * a_NeighborXP, cChunk * a_NeighborZM, cChunk * a_NeighborZP, // Neighbor chunks
|
||||||
cAllocationPool<cChunkData::sChunkSection> & a_Pool
|
cAllocationPool<cChunkData::sChunkSection> & a_Pool
|
||||||
@ -216,6 +216,10 @@ public:
|
|||||||
/** Calls the callback for each entity; returns true if all entities processed, false if the callback aborted by returning true */
|
/** Calls the callback for each entity; returns true if all entities processed, false if the callback aborted by returning true */
|
||||||
bool ForEachEntity(cEntityCallback & a_Callback); // Lua-accessible
|
bool ForEachEntity(cEntityCallback & a_Callback); // Lua-accessible
|
||||||
|
|
||||||
|
/** Calls the callback for each entity that has a nonempty intersection with the specified boundingbox.
|
||||||
|
Returns true if all entities processed, false if the callback aborted by returning true. */
|
||||||
|
bool ForEachEntityInBox(const cBoundingBox & a_Box, cEntityCallback & a_Callback); // Lua-accessible
|
||||||
|
|
||||||
/** Calls the callback if the entity with the specified ID is found, with the entity object as the callback param. Returns true if entity found. */
|
/** Calls the callback if the entity with the specified ID is found, with the entity object as the callback param. Returns true if entity found. */
|
||||||
bool DoWithEntityByID(int a_EntityID, cEntityCallback & a_Callback, bool & a_CallbackResult); // Lua-accessible
|
bool DoWithEntityByID(int a_EntityID, cEntityCallback & a_Callback, bool & a_CallbackResult); // Lua-accessible
|
||||||
|
|
||||||
|
@ -16,11 +16,6 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** This is really only a placeholder to be used in places where we need to "make up" a chunk's Y coord.
|
|
||||||
It will help us when the new chunk format comes out and we need to patch everything up for compatibility.
|
|
||||||
*/
|
|
||||||
#define ZERO_CHUNK_Y 0
|
|
||||||
|
|
||||||
// Used to smoothly convert to new axis ordering. One will be removed when deemed stable.
|
// Used to smoothly convert to new axis ordering. One will be removed when deemed stable.
|
||||||
#define AXIS_ORDER_YZX 1 // Original (1.1-)
|
#define AXIS_ORDER_YZX 1 // Original (1.1-)
|
||||||
#define AXIS_ORDER_XZY 2 // New (1.2+)
|
#define AXIS_ORDER_XZY 2 // New (1.2+)
|
||||||
@ -377,14 +372,13 @@ class cChunkCoords
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
int m_ChunkX;
|
int m_ChunkX;
|
||||||
int m_ChunkY;
|
|
||||||
int m_ChunkZ;
|
int m_ChunkZ;
|
||||||
|
|
||||||
cChunkCoords(int a_ChunkX, int a_ChunkY, int a_ChunkZ) : m_ChunkX(a_ChunkX), m_ChunkY(a_ChunkY), m_ChunkZ(a_ChunkZ) {}
|
cChunkCoords(int a_ChunkX, int a_ChunkZ) : m_ChunkX(a_ChunkX), m_ChunkZ(a_ChunkZ) {}
|
||||||
|
|
||||||
bool operator == (const cChunkCoords & a_Other) const
|
bool operator == (const cChunkCoords & a_Other) const
|
||||||
{
|
{
|
||||||
return ((m_ChunkX == a_Other.m_ChunkX) && (m_ChunkY == a_Other.m_ChunkY) && (m_ChunkZ == a_Other.m_ChunkZ));
|
return ((m_ChunkX == a_Other.m_ChunkX) && (m_ChunkZ == a_Other.m_ChunkZ));
|
||||||
}
|
}
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
@ -395,6 +389,27 @@ typedef std::vector<cChunkCoords> cChunkCoordsVector;
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class cChunkCoordsWithBool
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int m_ChunkX;
|
||||||
|
int m_ChunkZ;
|
||||||
|
bool m_ForceGenerate;
|
||||||
|
|
||||||
|
cChunkCoordsWithBool(int a_ChunkX, int a_ChunkZ, bool a_ForceGenerate) : m_ChunkX(a_ChunkX), m_ChunkZ(a_ChunkZ), m_ForceGenerate(a_ForceGenerate){}
|
||||||
|
|
||||||
|
bool operator == (const cChunkCoordsWithBool & a_Other) const
|
||||||
|
{
|
||||||
|
return ((m_ChunkX == a_Other.m_ChunkX) && (m_ChunkZ == a_Other.m_ChunkZ) && (m_ForceGenerate == a_Other.m_ForceGenerate));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::list<cChunkCoordsWithBool> cChunkCoordsWithBoolList;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// Interface class used as a callback for operations that involve chunk coords
|
/// Interface class used as a callback for operations that involve chunk coords
|
||||||
class cChunkCoordCallback
|
class cChunkCoordCallback
|
||||||
{
|
{
|
||||||
|
290
src/ChunkMap.cpp
290
src/ChunkMap.cpp
File diff suppressed because it is too large
Load Diff
@ -36,6 +36,7 @@ class cBlockArea;
|
|||||||
class cMobCensus;
|
class cMobCensus;
|
||||||
class cMobSpawner;
|
class cMobSpawner;
|
||||||
class cSetChunkData;
|
class cSetChunkData;
|
||||||
|
class cBoundingBox;
|
||||||
|
|
||||||
typedef std::list<cClientHandle *> cClientHandleList;
|
typedef std::list<cClientHandle *> cClientHandleList;
|
||||||
typedef cChunk * cChunkPtr;
|
typedef cChunk * cChunkPtr;
|
||||||
@ -209,6 +210,11 @@ public:
|
|||||||
/** Calls the callback for each entity in the specified chunk; returns true if all entities processed, false if the callback aborted by returning true */
|
/** Calls the callback for each entity in the specified chunk; returns true if all entities processed, false if the callback aborted by returning true */
|
||||||
bool ForEachEntityInChunk(int a_ChunkX, int a_ChunkZ, cEntityCallback & a_Callback); // Lua-accessible
|
bool ForEachEntityInChunk(int a_ChunkX, int a_ChunkZ, cEntityCallback & a_Callback); // Lua-accessible
|
||||||
|
|
||||||
|
/** Calls the callback for each entity that has a nonempty intersection with the specified boundingbox.
|
||||||
|
Returns true if all entities processed, false if the callback aborted by returning true.
|
||||||
|
If any chunk in the box is missing, ignores the entities in that chunk silently. */
|
||||||
|
bool ForEachEntityInBox(const cBoundingBox & a_Box, cEntityCallback & a_Callback); // Lua-accessible
|
||||||
|
|
||||||
/** Destroys and returns a list of blocks destroyed in the explosion at the specified coordinates */
|
/** Destroys and returns a list of blocks destroyed in the explosion at the specified coordinates */
|
||||||
void DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_BlockY, double a_BlockZ, cVector3iArray & a_BlockAffected);
|
void DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_BlockY, double a_BlockZ, cVector3iArray & a_BlockAffected);
|
||||||
|
|
||||||
@ -270,16 +276,16 @@ public:
|
|||||||
bool GetSignLines (int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4); // Lua-accessible
|
bool GetSignLines (int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4); // Lua-accessible
|
||||||
|
|
||||||
/** Touches the chunk, causing it to be loaded or generated */
|
/** Touches the chunk, causing it to be loaded or generated */
|
||||||
void TouchChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ);
|
void TouchChunk(int a_ChunkX, int a_ChunkZ);
|
||||||
|
|
||||||
/** Loads the chunk, if not already loaded. Doesn't generate. Returns true if chunk valid (even if already loaded before) */
|
/** Loads the chunk, if not already loaded. Doesn't generate. Returns true if chunk valid (even if already loaded before) */
|
||||||
bool LoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ);
|
bool LoadChunk(int a_ChunkX, int a_ChunkZ);
|
||||||
|
|
||||||
/** Loads the chunks specified. Doesn't report failure, other than chunks being !IsValid() */
|
/** Loads the chunks specified. Doesn't report failure, other than chunks being !IsValid() */
|
||||||
void LoadChunks(const cChunkCoordsList & a_Chunks);
|
void LoadChunks(const cChunkCoordsList & a_Chunks);
|
||||||
|
|
||||||
/** Marks the chunk as failed-to-load */
|
/** Marks the chunk as failed-to-load */
|
||||||
void ChunkLoadFailed(int a_ChunkX, int a_ChunkY, int a_ChunkZ);
|
void ChunkLoadFailed(int a_ChunkX, int a_ChunkZ);
|
||||||
|
|
||||||
/** Sets the sign text. Returns true if sign text changed. */
|
/** Sets the sign text. Returns true if sign text changed. */
|
||||||
bool SetSignLines(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);
|
bool SetSignLines(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);
|
||||||
@ -363,7 +369,7 @@ private:
|
|||||||
~cChunkLayer();
|
~cChunkLayer();
|
||||||
|
|
||||||
/** Always returns an assigned chunkptr, but the chunk needn't be valid (loaded / generated) - callers must check */
|
/** Always returns an assigned chunkptr, but the chunk needn't be valid (loaded / generated) - callers must check */
|
||||||
cChunkPtr GetChunk( int a_ChunkX, int a_ChunkY, int a_ChunkZ);
|
cChunkPtr GetChunk( int a_ChunkX, int a_ChunkZ);
|
||||||
|
|
||||||
/** Returns the specified chunk, or NULL if not created yet */
|
/** Returns the specified chunk, or NULL if not created yet */
|
||||||
cChunk * FindChunk(int a_ChunkX, int a_ChunkZ);
|
cChunk * FindChunk(int a_ChunkX, int a_ChunkZ);
|
||||||
@ -456,9 +462,9 @@ private:
|
|||||||
|
|
||||||
std::auto_ptr<cAllocationPool<cChunkData::sChunkSection> > m_Pool;
|
std::auto_ptr<cAllocationPool<cChunkData::sChunkSection> > m_Pool;
|
||||||
|
|
||||||
cChunkPtr GetChunk (int a_ChunkX, int a_ChunkY, int a_ChunkZ); // Also queues the chunk for loading / generating if not valid
|
cChunkPtr GetChunk (int a_ChunkX, int a_ChunkZ); // Also queues the chunk for loading / generating if not valid
|
||||||
cChunkPtr GetChunkNoGen (int a_ChunkX, int a_ChunkY, int a_ChunkZ); // Also queues the chunk for loading if not valid; doesn't generate
|
cChunkPtr GetChunkNoGen (int a_ChunkX, int a_ChunkZ); // Also queues the chunk for loading if not valid; doesn't generate
|
||||||
cChunkPtr GetChunkNoLoad(int a_ChunkX, int a_ChunkY, int a_ChunkZ); // Doesn't load, doesn't generate
|
cChunkPtr GetChunkNoLoad(int a_ChunkX, int a_ChunkZ); // Doesn't load, doesn't generate
|
||||||
|
|
||||||
/** Gets a block in any chunk while in the cChunk's Tick() method; returns true if successful, false if chunk not loaded (doesn't queue load) */
|
/** Gets a block in any chunk while in the cChunk's Tick() method; returns true if successful, false if chunk not loaded (doesn't queue load) */
|
||||||
bool LockedGetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta);
|
bool LockedGetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta);
|
||||||
|
@ -81,7 +81,7 @@ void cChunkSender::ChunkReady(int a_ChunkX, int a_ChunkZ)
|
|||||||
// This is probably never gonna be called twice for the same chunk, and if it is, we don't mind, so we don't check
|
// This is probably never gonna be called twice for the same chunk, and if it is, we don't mind, so we don't check
|
||||||
{
|
{
|
||||||
cCSLock Lock(m_CS);
|
cCSLock Lock(m_CS);
|
||||||
m_ChunksReady.push_back(cChunkCoords(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ));
|
m_ChunksReady.push_back(cChunkCoords(a_ChunkX, a_ChunkZ));
|
||||||
}
|
}
|
||||||
m_evtQueue.Set();
|
m_evtQueue.Set();
|
||||||
}
|
}
|
||||||
@ -95,12 +95,12 @@ void cChunkSender::QueueSendChunkTo(int a_ChunkX, int a_ChunkZ, cClientHandle *
|
|||||||
ASSERT(a_Client != NULL);
|
ASSERT(a_Client != NULL);
|
||||||
{
|
{
|
||||||
cCSLock Lock(m_CS);
|
cCSLock Lock(m_CS);
|
||||||
if (std::find(m_SendChunks.begin(), m_SendChunks.end(), sSendChunk(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ, a_Client)) != m_SendChunks.end())
|
if (std::find(m_SendChunks.begin(), m_SendChunks.end(), sSendChunk(a_ChunkX, a_ChunkZ, a_Client)) != m_SendChunks.end())
|
||||||
{
|
{
|
||||||
// Already queued, bail out
|
// Already queued, bail out
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_SendChunks.push_back(sSendChunk(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ, a_Client));
|
m_SendChunks.push_back(sSendChunk(a_ChunkX, a_ChunkZ, a_Client));
|
||||||
}
|
}
|
||||||
m_evtQueue.Set();
|
m_evtQueue.Set();
|
||||||
}
|
}
|
||||||
@ -160,7 +160,7 @@ void cChunkSender::Execute(void)
|
|||||||
m_ChunksReady.pop_front();
|
m_ChunksReady.pop_front();
|
||||||
Lock.Unlock();
|
Lock.Unlock();
|
||||||
|
|
||||||
SendChunk(Coords.m_ChunkX, Coords.m_ChunkY, Coords.m_ChunkZ, NULL);
|
SendChunk(Coords.m_ChunkX, Coords.m_ChunkZ, NULL);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -169,7 +169,7 @@ void cChunkSender::Execute(void)
|
|||||||
m_SendChunks.pop_front();
|
m_SendChunks.pop_front();
|
||||||
Lock.Unlock();
|
Lock.Unlock();
|
||||||
|
|
||||||
SendChunk(Chunk.m_ChunkX, Chunk.m_ChunkY, Chunk.m_ChunkZ, Chunk.m_Client);
|
SendChunk(Chunk.m_ChunkX, Chunk.m_ChunkZ, Chunk.m_Client);
|
||||||
}
|
}
|
||||||
Lock.Lock();
|
Lock.Lock();
|
||||||
int RemoveCount = m_RemoveCount;
|
int RemoveCount = m_RemoveCount;
|
||||||
@ -186,14 +186,14 @@ void cChunkSender::Execute(void)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cChunkSender::SendChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHandle * a_Client)
|
void cChunkSender::SendChunk(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client)
|
||||||
{
|
{
|
||||||
ASSERT(m_World != NULL);
|
ASSERT(m_World != NULL);
|
||||||
|
|
||||||
// Ask the client if it still wants the chunk:
|
// Ask the client if it still wants the chunk:
|
||||||
if (a_Client != NULL)
|
if (a_Client != NULL)
|
||||||
{
|
{
|
||||||
if (!a_Client->WantsSendChunk(a_ChunkX, a_ChunkY, a_ChunkZ))
|
if (!a_Client->WantsSendChunk(a_ChunkX, a_ChunkZ))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -95,13 +95,11 @@ protected:
|
|||||||
struct sSendChunk
|
struct sSendChunk
|
||||||
{
|
{
|
||||||
int m_ChunkX;
|
int m_ChunkX;
|
||||||
int m_ChunkY;
|
|
||||||
int m_ChunkZ;
|
int m_ChunkZ;
|
||||||
cClientHandle * m_Client;
|
cClientHandle * m_Client;
|
||||||
|
|
||||||
sSendChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHandle * a_Client) :
|
sSendChunk(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client) :
|
||||||
m_ChunkX(a_ChunkX),
|
m_ChunkX(a_ChunkX),
|
||||||
m_ChunkY(a_ChunkY),
|
|
||||||
m_ChunkZ(a_ChunkZ),
|
m_ChunkZ(a_ChunkZ),
|
||||||
m_Client(a_Client)
|
m_Client(a_Client)
|
||||||
{
|
{
|
||||||
@ -111,7 +109,6 @@ protected:
|
|||||||
{
|
{
|
||||||
return (
|
return (
|
||||||
(a_Other.m_ChunkX == m_ChunkX) &&
|
(a_Other.m_ChunkX == m_ChunkX) &&
|
||||||
(a_Other.m_ChunkY == m_ChunkY) &&
|
|
||||||
(a_Other.m_ChunkZ == m_ChunkZ) &&
|
(a_Other.m_ChunkZ == m_ChunkZ) &&
|
||||||
(a_Other.m_Client == m_Client)
|
(a_Other.m_Client == m_Client)
|
||||||
);
|
);
|
||||||
@ -162,7 +159,7 @@ protected:
|
|||||||
virtual void BlockEntity (cBlockEntity * a_Entity) override;
|
virtual void BlockEntity (cBlockEntity * a_Entity) override;
|
||||||
|
|
||||||
/// Sends the specified chunk to a_Client, or to all chunk clients if a_Client == NULL
|
/// Sends the specified chunk to a_Client, or to all chunk clients if a_Client == NULL
|
||||||
void SendChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHandle * a_Client);
|
void SendChunk(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client);
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ void cChunkStay::Add(int a_ChunkX, int a_ChunkZ)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} // for itr - Chunks[]
|
} // for itr - Chunks[]
|
||||||
m_Chunks.push_back(cChunkCoords(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ));
|
m_Chunks.push_back(cChunkCoords(a_ChunkX, a_ChunkZ));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -472,13 +472,13 @@ void cClientHandle::StreamChunks(void)
|
|||||||
// For each distance touch chunks in a hollow square centered around current position:
|
// For each distance touch chunks in a hollow square centered around current position:
|
||||||
for (int i = -d; i <= d; ++i)
|
for (int i = -d; i <= d; ++i)
|
||||||
{
|
{
|
||||||
World->TouchChunk(ChunkPosX + d, ZERO_CHUNK_Y, ChunkPosZ + i);
|
World->TouchChunk(ChunkPosX + d, ChunkPosZ + i);
|
||||||
World->TouchChunk(ChunkPosX - d, ZERO_CHUNK_Y, ChunkPosZ + i);
|
World->TouchChunk(ChunkPosX - d, ChunkPosZ + i);
|
||||||
} // for i
|
} // for i
|
||||||
for (int i = -d + 1; i < d; ++i)
|
for (int i = -d + 1; i < d; ++i)
|
||||||
{
|
{
|
||||||
World->TouchChunk(ChunkPosX + i, ZERO_CHUNK_Y, ChunkPosZ + d);
|
World->TouchChunk(ChunkPosX + i, ChunkPosZ + d);
|
||||||
World->TouchChunk(ChunkPosX + i, ZERO_CHUNK_Y, ChunkPosZ - d);
|
World->TouchChunk(ChunkPosX + i, ChunkPosZ - d);
|
||||||
} // for i
|
} // for i
|
||||||
} // for d
|
} // for d
|
||||||
}
|
}
|
||||||
@ -501,8 +501,8 @@ void cClientHandle::StreamChunk(int a_ChunkX, int a_ChunkZ)
|
|||||||
{
|
{
|
||||||
{
|
{
|
||||||
cCSLock Lock(m_CSChunkLists);
|
cCSLock Lock(m_CSChunkLists);
|
||||||
m_LoadedChunks.push_back(cChunkCoords(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ));
|
m_LoadedChunks.push_back(cChunkCoords(a_ChunkX, a_ChunkZ));
|
||||||
m_ChunksToSend.push_back(cChunkCoords(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ));
|
m_ChunksToSend.push_back(cChunkCoords(a_ChunkX, a_ChunkZ));
|
||||||
}
|
}
|
||||||
World->SendChunkTo(a_ChunkX, a_ChunkZ, this);
|
World->SendChunkTo(a_ChunkX, a_ChunkZ, this);
|
||||||
}
|
}
|
||||||
@ -2734,7 +2734,7 @@ bool cClientHandle::HasPluginChannel(const AString & a_PluginChannel)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cClientHandle::WantsSendChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ)
|
bool cClientHandle::WantsSendChunk(int a_ChunkX, int a_ChunkZ)
|
||||||
{
|
{
|
||||||
if (m_State >= csDestroying)
|
if (m_State >= csDestroying)
|
||||||
{
|
{
|
||||||
@ -2742,7 +2742,7 @@ bool cClientHandle::WantsSendChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ)
|
|||||||
}
|
}
|
||||||
|
|
||||||
cCSLock Lock(m_CSChunkLists);
|
cCSLock Lock(m_CSChunkLists);
|
||||||
return (std::find(m_ChunksToSend.begin(), m_ChunksToSend.end(), cChunkCoords(a_ChunkX, a_ChunkY, a_ChunkZ)) != m_ChunksToSend.end());
|
return (std::find(m_ChunksToSend.begin(), m_ChunksToSend.end(), cChunkCoords(a_ChunkX, a_ChunkZ)) != m_ChunksToSend.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2758,9 +2758,9 @@ void cClientHandle::AddWantedChunk(int a_ChunkX, int a_ChunkZ)
|
|||||||
|
|
||||||
LOGD("Adding chunk [%d, %d] to wanted chunks for client %p", a_ChunkX, a_ChunkZ, this);
|
LOGD("Adding chunk [%d, %d] to wanted chunks for client %p", a_ChunkX, a_ChunkZ, this);
|
||||||
cCSLock Lock(m_CSChunkLists);
|
cCSLock Lock(m_CSChunkLists);
|
||||||
if (std::find(m_ChunksToSend.begin(), m_ChunksToSend.end(), cChunkCoords(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ)) == m_ChunksToSend.end())
|
if (std::find(m_ChunksToSend.begin(), m_ChunksToSend.end(), cChunkCoords(a_ChunkX, a_ChunkZ)) == m_ChunksToSend.end())
|
||||||
{
|
{
|
||||||
m_ChunksToSend.push_back(cChunkCoords(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ));
|
m_ChunksToSend.push_back(cChunkCoords(a_ChunkX, a_ChunkZ));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2858,11 +2858,27 @@ void cClientHandle::SocketClosed(void)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cClientHandle::HandleEnchantItem(Byte & WindowID, Byte & Enchantment)
|
void cClientHandle::HandleEnchantItem(Byte & a_WindowID, Byte & a_Enchantment)
|
||||||
{
|
{
|
||||||
cEnchantingWindow * Window = (cEnchantingWindow*)m_Player->GetWindow();
|
if (a_Enchantment > 2)
|
||||||
|
{
|
||||||
|
LOGWARNING("%s attempt to crash the server with invalid enchanting selection!", GetUsername().c_str());
|
||||||
|
Kick("Invalid enchanting!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
(m_Player->GetWindow() == NULL) ||
|
||||||
|
(m_Player->GetWindow()->GetWindowID() != a_WindowID) ||
|
||||||
|
(m_Player->GetWindow()->GetWindowType() != cWindow::wtEnchantment)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cEnchantingWindow * Window = (cEnchantingWindow*) m_Player->GetWindow();
|
||||||
cItem Item = *Window->m_SlotArea->GetSlot(0, *m_Player);
|
cItem Item = *Window->m_SlotArea->GetSlot(0, *m_Player);
|
||||||
int BaseEnchantmentLevel = Window->GetPropertyValue(Enchantment);
|
int BaseEnchantmentLevel = Window->GetPropertyValue(a_Enchantment);
|
||||||
|
|
||||||
if (Item.EnchantByXPLevels(BaseEnchantmentLevel))
|
if (Item.EnchantByXPLevels(BaseEnchantmentLevel))
|
||||||
{
|
{
|
||||||
|
@ -209,7 +209,7 @@ public:
|
|||||||
// tolua_end
|
// tolua_end
|
||||||
|
|
||||||
/** Returns true if the client wants the chunk specified to be sent (in m_ChunksToSend) */
|
/** Returns true if the client wants the chunk specified to be sent (in m_ChunksToSend) */
|
||||||
bool WantsSendChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ);
|
bool WantsSendChunk(int a_ChunkX, int a_ChunkZ);
|
||||||
|
|
||||||
/** Adds the chunk specified to the list of chunks wanted for sending (m_ChunksToSend) */
|
/** Adds the chunk specified to the list of chunks wanted for sending (m_ChunksToSend) */
|
||||||
void AddWantedChunk(int a_ChunkX, int a_ChunkZ);
|
void AddWantedChunk(int a_ChunkX, int a_ChunkZ);
|
||||||
@ -269,7 +269,7 @@ public:
|
|||||||
void RemoveFromWorld(void);
|
void RemoveFromWorld(void);
|
||||||
|
|
||||||
/** Called when the player will enchant a Item */
|
/** Called when the player will enchant a Item */
|
||||||
void HandleEnchantItem(Byte & WindowID, Byte & Enchantment);
|
void HandleEnchantItem(Byte & a_WindowID, Byte & a_Enchantment);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -34,6 +34,7 @@ cEntityEffect::eType cEntityEffect::GetPotionEffectType(short a_ItemDamage)
|
|||||||
case 0x08: return cEntityEffect::effWeakness;
|
case 0x08: return cEntityEffect::effWeakness;
|
||||||
case 0x09: return cEntityEffect::effStrength;
|
case 0x09: return cEntityEffect::effStrength;
|
||||||
case 0x0a: return cEntityEffect::effSlowness;
|
case 0x0a: return cEntityEffect::effSlowness;
|
||||||
|
case 0x0b: return cEntityEffect::effJumpBoost;
|
||||||
case 0x0c: return cEntityEffect::effInstantDamage;
|
case 0x0c: return cEntityEffect::effInstantDamage;
|
||||||
case 0x0d: return cEntityEffect::effWaterBreathing;
|
case 0x0d: return cEntityEffect::effWaterBreathing;
|
||||||
case 0x0e: return cEntityEffect::effInvisibility;
|
case 0x0e: return cEntityEffect::effInvisibility;
|
||||||
@ -41,7 +42,6 @@ cEntityEffect::eType cEntityEffect::GetPotionEffectType(short a_ItemDamage)
|
|||||||
// No effect potions
|
// No effect potions
|
||||||
case 0x00:
|
case 0x00:
|
||||||
case 0x07:
|
case 0x07:
|
||||||
case 0x0b: // Will be potion of leaping in 1.8
|
|
||||||
case 0x0f:
|
case 0x0f:
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
|
@ -208,6 +208,59 @@ void cBioGenCache::InitializeBiomeGen(cIniFile & a_IniFile)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// cBioGenMulticache:
|
||||||
|
|
||||||
|
cBioGenMulticache::cBioGenMulticache(cBiomeGen * a_BioGenToCache, size_t a_CacheSize, size_t a_CachesLength) :
|
||||||
|
m_CachesLength(a_CachesLength)
|
||||||
|
{
|
||||||
|
m_Caches.reserve(a_CachesLength);
|
||||||
|
for (size_t i = 0; i < a_CachesLength; i++)
|
||||||
|
{
|
||||||
|
m_Caches.push_back(new cBioGenCache(a_BioGenToCache, a_CacheSize));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cBioGenMulticache::~cBioGenMulticache()
|
||||||
|
{
|
||||||
|
for (std::vector<cBiomeGen*>::iterator it = m_Caches.begin(); it != m_Caches.end(); it++)
|
||||||
|
{
|
||||||
|
delete *it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cBioGenMulticache::GenBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap)
|
||||||
|
{
|
||||||
|
const size_t coefficient = 3;
|
||||||
|
const size_t cacheIdx = ((size_t)a_ChunkX + coefficient * (size_t)a_ChunkZ) % m_CachesLength;
|
||||||
|
|
||||||
|
m_Caches[cacheIdx]->GenBiomes(a_ChunkX, a_ChunkZ, a_BiomeMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cBioGenMulticache::InitializeBiomeGen(cIniFile & a_IniFile)
|
||||||
|
{
|
||||||
|
for (std::vector<cBiomeGen*>::iterator it = m_Caches.begin(); it != m_Caches.end(); it++)
|
||||||
|
{
|
||||||
|
cBiomeGen * tmp = *it;
|
||||||
|
tmp->InitializeBiomeGen(a_IniFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// cBiomeGenList:
|
// cBiomeGenList:
|
||||||
|
@ -80,6 +80,32 @@ protected:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class cBioGenMulticache :
|
||||||
|
public cBiomeGen
|
||||||
|
{
|
||||||
|
|
||||||
|
typedef cBiomeGen super;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*
|
||||||
|
a_CacheSize defines the size of each singular cache
|
||||||
|
a_CachesLength defines how many caches are used for the multicache
|
||||||
|
*/
|
||||||
|
cBioGenMulticache(cBiomeGen * a_BioGenToCache, size_t a_CacheSize, size_t a_CachesLength); // Doesn't take ownership of a_BioGenToCache
|
||||||
|
~cBioGenMulticache();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
size_t m_CachesLength;
|
||||||
|
std::vector<cBiomeGen*> m_Caches;
|
||||||
|
|
||||||
|
virtual void GenBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap) override;
|
||||||
|
virtual void InitializeBiomeGen(cIniFile & a_IniFile) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// Base class for generators that use a list of available biomes. This class takes care of the list.
|
/// Base class for generators that use a list of available biomes. This class takes care of the list.
|
||||||
class cBiomeGenList :
|
class cBiomeGenList :
|
||||||
public cBiomeGen
|
public cBiomeGen
|
||||||
|
@ -52,10 +52,21 @@ bool cChunkGenerator::Start(cPluginInterface & a_PluginInterface, cChunkSink & a
|
|||||||
m_PluginInterface = &a_PluginInterface;
|
m_PluginInterface = &a_PluginInterface;
|
||||||
m_ChunkSink = &a_ChunkSink;
|
m_ChunkSink = &a_ChunkSink;
|
||||||
|
|
||||||
MTRand rnd;
|
// Get the seed; create a new one and log it if not found in the INI file:
|
||||||
m_Seed = a_IniFile.GetValueSetI("Seed", "Seed", (int)rnd.randInt());
|
if (a_IniFile.HasValue("Seed", "Seed"))
|
||||||
AString GeneratorName = a_IniFile.GetValueSet("Generator", "Generator", "Composable");
|
{
|
||||||
|
m_Seed = a_IniFile.GetValueI("Seed", "Seed");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MTRand rnd;
|
||||||
|
m_Seed = rnd.randInt();
|
||||||
|
LOGINFO("Chosen a new random seed for world: %d", m_Seed);
|
||||||
|
a_IniFile.SetValueI("Seed", "Seed", m_Seed);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the generator engine based on the INI file settings:
|
||||||
|
AString GeneratorName = a_IniFile.GetValueSet("Generator", "Generator", "Composable");
|
||||||
if (NoCaseCompare(GeneratorName, "Noise3D") == 0)
|
if (NoCaseCompare(GeneratorName, "Noise3D") == 0)
|
||||||
{
|
{
|
||||||
m_Generator = new cNoise3DGenerator(*this);
|
m_Generator = new cNoise3DGenerator(*this);
|
||||||
@ -99,15 +110,15 @@ void cChunkGenerator::Stop(void)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cChunkGenerator::QueueGenerateChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ)
|
void cChunkGenerator::QueueGenerateChunk(int a_ChunkX, int a_ChunkZ, bool a_ForceGenerate)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
cCSLock Lock(m_CS);
|
cCSLock Lock(m_CS);
|
||||||
|
|
||||||
// Check if it is already in the queue:
|
// Check if it is already in the queue:
|
||||||
for (cChunkCoordsList::iterator itr = m_Queue.begin(); itr != m_Queue.end(); ++itr)
|
for (cChunkCoordsWithBoolList::iterator itr = m_Queue.begin(); itr != m_Queue.end(); ++itr)
|
||||||
{
|
{
|
||||||
if ((itr->m_ChunkX == a_ChunkX) && (itr->m_ChunkY == a_ChunkY) && (itr->m_ChunkZ == a_ChunkZ))
|
if ((itr->m_ChunkX == a_ChunkX) && (itr->m_ChunkZ == a_ChunkZ))
|
||||||
{
|
{
|
||||||
// Already in the queue, bail out
|
// Already in the queue, bail out
|
||||||
return;
|
return;
|
||||||
@ -119,7 +130,7 @@ void cChunkGenerator::QueueGenerateChunk(int a_ChunkX, int a_ChunkY, int a_Chunk
|
|||||||
{
|
{
|
||||||
LOGWARN("WARNING: Adding chunk [%i, %i] to generation queue; Queue is too big! (" SIZE_T_FMT ")", a_ChunkX, a_ChunkZ, m_Queue.size());
|
LOGWARN("WARNING: Adding chunk [%i, %i] to generation queue; Queue is too big! (" SIZE_T_FMT ")", a_ChunkX, a_ChunkZ, m_Queue.size());
|
||||||
}
|
}
|
||||||
m_Queue.push_back(cChunkCoords(a_ChunkX, a_ChunkY, a_ChunkZ));
|
m_Queue.push_back(cChunkCoordsWithBool(a_ChunkX, a_ChunkZ, a_ForceGenerate));
|
||||||
}
|
}
|
||||||
|
|
||||||
m_Event.Set();
|
m_Event.Set();
|
||||||
@ -229,9 +240,9 @@ void cChunkGenerator::Execute(void)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
cChunkCoords coords = m_Queue.front(); // Get next coord from queue
|
cChunkCoordsWithBool coords = m_Queue.front(); // Get next coord from queue
|
||||||
m_Queue.erase( m_Queue.begin()); // Remove coordinate from queue
|
|
||||||
bool SkipEnabled = (m_Queue.size() > QUEUE_SKIP_LIMIT);
|
bool SkipEnabled = (m_Queue.size() > QUEUE_SKIP_LIMIT);
|
||||||
|
m_Queue.erase(m_Queue.begin()); // Remove coordinate from queue
|
||||||
Lock.Unlock(); // Unlock ASAP
|
Lock.Unlock(); // Unlock ASAP
|
||||||
m_evtRemoved.Set();
|
m_evtRemoved.Set();
|
||||||
|
|
||||||
@ -245,8 +256,7 @@ void cChunkGenerator::Execute(void)
|
|||||||
LastReportTick = clock();
|
LastReportTick = clock();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hack for regenerating chunks: if Y != 0, the chunk is considered invalid, even if it has its data set
|
if (!coords.m_ForceGenerate && m_ChunkSink->IsChunkValid(coords.m_ChunkX, coords.m_ChunkZ))
|
||||||
if ((coords.m_ChunkY == 0) && m_ChunkSink->IsChunkValid(coords.m_ChunkX, coords.m_ChunkZ))
|
|
||||||
{
|
{
|
||||||
LOGD("Chunk [%d, %d] already generated, skipping generation", coords.m_ChunkX, coords.m_ChunkZ);
|
LOGD("Chunk [%d, %d] already generated, skipping generation", coords.m_ChunkX, coords.m_ChunkZ);
|
||||||
// Already generated, ignore request
|
// Already generated, ignore request
|
||||||
@ -259,8 +269,8 @@ void cChunkGenerator::Execute(void)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGD("Generating chunk [%d, %d, %d]", coords.m_ChunkX, coords.m_ChunkY, coords.m_ChunkZ);
|
LOGD("Generating chunk [%d, %d]", coords.m_ChunkX, coords.m_ChunkZ);
|
||||||
DoGenerate(coords.m_ChunkX, coords.m_ChunkY, coords.m_ChunkZ);
|
DoGenerate(coords.m_ChunkX, coords.m_ChunkZ);
|
||||||
|
|
||||||
NumChunksGenerated++;
|
NumChunksGenerated++;
|
||||||
} // while (!bStop)
|
} // while (!bStop)
|
||||||
@ -269,7 +279,7 @@ void cChunkGenerator::Execute(void)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cChunkGenerator::DoGenerate(int a_ChunkX, int a_ChunkY, int a_ChunkZ)
|
void cChunkGenerator::DoGenerate(int a_ChunkX, int a_ChunkZ)
|
||||||
{
|
{
|
||||||
ASSERT(m_PluginInterface != NULL);
|
ASSERT(m_PluginInterface != NULL);
|
||||||
ASSERT(m_ChunkSink != NULL);
|
ASSERT(m_ChunkSink != NULL);
|
||||||
|
@ -116,7 +116,7 @@ public:
|
|||||||
void Stop(void);
|
void Stop(void);
|
||||||
|
|
||||||
/// Queues the chunk for generation; removes duplicate requests
|
/// Queues the chunk for generation; removes duplicate requests
|
||||||
void QueueGenerateChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ);
|
void QueueGenerateChunk(int a_ChunkX, int a_ChunkZ, bool a_ForceGenerate);
|
||||||
|
|
||||||
/// Generates the biomes for the specified chunk (directly, not in a separate thread). Used by the world loader if biomes failed loading.
|
/// Generates the biomes for the specified chunk (directly, not in a separate thread). Used by the world loader if biomes failed loading.
|
||||||
void GenerateBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap);
|
void GenerateBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap);
|
||||||
@ -137,10 +137,10 @@ private:
|
|||||||
|
|
||||||
int m_Seed;
|
int m_Seed;
|
||||||
|
|
||||||
cCriticalSection m_CS;
|
cCriticalSection m_CS;
|
||||||
cChunkCoordsList m_Queue;
|
cChunkCoordsWithBoolList m_Queue;
|
||||||
cEvent m_Event; ///< Set when an item is added to the queue or the thread should terminate
|
cEvent m_Event; ///< Set when an item is added to the queue or the thread should terminate
|
||||||
cEvent m_evtRemoved; ///< Set when an item is removed from the queue
|
cEvent m_evtRemoved; ///< Set when an item is removed from the queue
|
||||||
|
|
||||||
cGenerator * m_Generator; ///< The actual generator engine used to generate chunks
|
cGenerator * m_Generator; ///< The actual generator engine used to generate chunks
|
||||||
|
|
||||||
@ -154,7 +154,7 @@ private:
|
|||||||
// cIsThread override:
|
// cIsThread override:
|
||||||
virtual void Execute(void) override;
|
virtual void Execute(void) override;
|
||||||
|
|
||||||
void DoGenerate(int a_ChunkX, int a_ChunkY, int a_ChunkZ);
|
void DoGenerate(int a_ChunkX, int a_ChunkZ);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -230,6 +230,8 @@ void cComposableGenerator::InitBiomeGen(cIniFile & a_IniFile)
|
|||||||
|
|
||||||
// Add a cache, if requested:
|
// Add a cache, if requested:
|
||||||
int CacheSize = a_IniFile.GetValueSetI("Generator", "BiomeGenCacheSize", CacheOffByDefault ? 0 : 64);
|
int CacheSize = a_IniFile.GetValueSetI("Generator", "BiomeGenCacheSize", CacheOffByDefault ? 0 : 64);
|
||||||
|
int MultiCacheLength = a_IniFile.GetValueSetI("Generator", "BiomeGenMultiCacheLength", 4);
|
||||||
|
|
||||||
if (CacheSize > 0)
|
if (CacheSize > 0)
|
||||||
{
|
{
|
||||||
if (CacheSize < 4)
|
if (CacheSize < 4)
|
||||||
@ -241,7 +243,16 @@ void cComposableGenerator::InitBiomeGen(cIniFile & a_IniFile)
|
|||||||
}
|
}
|
||||||
LOGD("Using a cache for biomegen of size %d.", CacheSize);
|
LOGD("Using a cache for biomegen of size %d.", CacheSize);
|
||||||
m_UnderlyingBiomeGen = m_BiomeGen;
|
m_UnderlyingBiomeGen = m_BiomeGen;
|
||||||
m_BiomeGen = new cBioGenCache(m_UnderlyingBiomeGen, CacheSize);
|
if (MultiCacheLength > 0)
|
||||||
|
{
|
||||||
|
LOGD("Enabling multicache for biomegen of length %d.", MultiCacheLength);
|
||||||
|
m_BiomeGen = new cBioGenMulticache(m_UnderlyingBiomeGen, CacheSize, MultiCacheLength);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_BiomeGen = new cBioGenCache(m_UnderlyingBiomeGen, CacheSize);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
80
src/Item.cpp
80
src/Item.cpp
@ -190,31 +190,35 @@ void cItem::FromJson(const Json::Value & a_Value)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cItem::IsEnchantable(short item)
|
bool cItem::IsEnchantable(short a_ItemType, bool a_WithBook)
|
||||||
{
|
{
|
||||||
if ((item >= 256) && (item <= 259))
|
if (
|
||||||
|
ItemCategory::IsAxe(a_ItemType) ||
|
||||||
|
ItemCategory::IsSword(a_ItemType) ||
|
||||||
|
ItemCategory::IsShovel(a_ItemType) ||
|
||||||
|
ItemCategory::IsPickaxe(a_ItemType) ||
|
||||||
|
(a_WithBook && ItemCategory::IsHoe(a_ItemType)) ||
|
||||||
|
ItemCategory::IsArmor(a_ItemType)
|
||||||
|
)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if ((item >= 267) && (item <= 279))
|
|
||||||
|
switch (a_ItemType)
|
||||||
{
|
{
|
||||||
return true;
|
case E_ITEM_BOOK:
|
||||||
}
|
case E_ITEM_BOW:
|
||||||
if ((item >= 283) && (item <= 286))
|
case E_ITEM_FISHING_ROD:
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if ((item >= 290) && (item <= 294))
|
|
||||||
{
|
case E_ITEM_CARROT_ON_STICK:
|
||||||
return true;
|
case E_ITEM_SHEARS:
|
||||||
}
|
case E_ITEM_FLINT_AND_STEEL:
|
||||||
if ((item >= 298) && (item <= 317))
|
{
|
||||||
{
|
return a_WithBook;
|
||||||
return true;
|
}
|
||||||
}
|
|
||||||
if ((item == 346) || (item == 359) || (item == 261))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -299,73 +303,77 @@ int cItem::GetEnchantability()
|
|||||||
|
|
||||||
bool cItem::EnchantByXPLevels(int a_NumXPLevels)
|
bool cItem::EnchantByXPLevels(int a_NumXPLevels)
|
||||||
{
|
{
|
||||||
if (!cItem::IsEnchantable(m_ItemType) && (m_ItemType != E_ITEM_BOOK))
|
if (!cItem::IsEnchantable(m_ItemType))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Enchantability = GetEnchantability();
|
int Enchantability = GetEnchantability();
|
||||||
|
if (Enchantability == 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
cFastRandom Random;
|
cFastRandom Random;
|
||||||
int ModifiedEnchantmentLevel = a_NumXPLevels + (int)Random.NextFloat((float)Enchantability / 4) + (int)Random.NextFloat((float)Enchantability / 4) + 1;
|
int ModifiedEnchantmentLevel = a_NumXPLevels + (int)Random.NextFloat((float)Enchantability / 4) + (int)Random.NextFloat((float)Enchantability / 4) + 1;
|
||||||
float RandomBonus = 1.0F + (Random.NextFloat(1) + Random.NextFloat(1) - 1.0F) * 0.15F;
|
float RandomBonus = 1.0F + (Random.NextFloat(1) + Random.NextFloat(1) - 1.0F) * 0.15F;
|
||||||
int FinalEnchantmentLevel = (int)(ModifiedEnchantmentLevel * RandomBonus + 0.5F);
|
int FinalEnchantmentLevel = (int)(ModifiedEnchantmentLevel * RandomBonus + 0.5F);
|
||||||
|
|
||||||
cWeightedEnchantments enchantments;
|
cWeightedEnchantments Enchantments;
|
||||||
cEnchantments::AddItemEnchantmentWeights(enchantments, m_ItemType, FinalEnchantmentLevel);
|
cEnchantments::AddItemEnchantmentWeights(Enchantments, m_ItemType, FinalEnchantmentLevel);
|
||||||
|
|
||||||
if (m_ItemType == E_ITEM_BOOK)
|
if (m_ItemType == E_ITEM_BOOK)
|
||||||
{
|
{
|
||||||
m_ItemType = E_ITEM_ENCHANTED_BOOK;
|
m_ItemType = E_ITEM_ENCHANTED_BOOK;
|
||||||
}
|
}
|
||||||
|
|
||||||
cEnchantments Enchantment1 = cEnchantments::GetRandomEnchantmentFromVector(enchantments);
|
cEnchantments Enchantment1 = cEnchantments::GetRandomEnchantmentFromVector(Enchantments);
|
||||||
m_Enchantments.AddFromString(Enchantment1.ToString());
|
m_Enchantments.AddFromString(Enchantment1.ToString());
|
||||||
cEnchantments::RemoveEnchantmentWeightFromVector(enchantments, Enchantment1);
|
cEnchantments::RemoveEnchantmentWeightFromVector(Enchantments, Enchantment1);
|
||||||
|
|
||||||
// Checking for conflicting enchantments
|
// Checking for conflicting enchantments
|
||||||
cEnchantments::CheckEnchantmentConflictsFromVector(enchantments, Enchantment1);
|
cEnchantments::CheckEnchantmentConflictsFromVector(Enchantments, Enchantment1);
|
||||||
|
|
||||||
float NewEnchantmentLevel = (float)a_NumXPLevels;
|
float NewEnchantmentLevel = (float)a_NumXPLevels;
|
||||||
|
|
||||||
// Next Enchantment (Second)
|
// Next Enchantment (Second)
|
||||||
NewEnchantmentLevel = NewEnchantmentLevel / 2;
|
NewEnchantmentLevel = NewEnchantmentLevel / 2;
|
||||||
float SecondEnchantmentChance = (NewEnchantmentLevel + 1) / 50 * 100;
|
float SecondEnchantmentChance = (NewEnchantmentLevel + 1) / 50 * 100;
|
||||||
if (enchantments.empty() || (Random.NextFloat(100) > SecondEnchantmentChance))
|
if (Enchantments.empty() || (Random.NextFloat(100) > SecondEnchantmentChance))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
cEnchantments Enchantment2 = cEnchantments::GetRandomEnchantmentFromVector(enchantments);
|
cEnchantments Enchantment2 = cEnchantments::GetRandomEnchantmentFromVector(Enchantments);
|
||||||
m_Enchantments.AddFromString(Enchantment2.ToString());
|
m_Enchantments.AddFromString(Enchantment2.ToString());
|
||||||
cEnchantments::RemoveEnchantmentWeightFromVector(enchantments, Enchantment2);
|
cEnchantments::RemoveEnchantmentWeightFromVector(Enchantments, Enchantment2);
|
||||||
|
|
||||||
// Checking for conflicting enchantments
|
// Checking for conflicting enchantments
|
||||||
cEnchantments::CheckEnchantmentConflictsFromVector(enchantments, Enchantment2);
|
cEnchantments::CheckEnchantmentConflictsFromVector(Enchantments, Enchantment2);
|
||||||
|
|
||||||
// Next Enchantment (Third)
|
// Next Enchantment (Third)
|
||||||
NewEnchantmentLevel = NewEnchantmentLevel / 2;
|
NewEnchantmentLevel = NewEnchantmentLevel / 2;
|
||||||
float ThirdEnchantmentChance = (NewEnchantmentLevel + 1) / 50 * 100;
|
float ThirdEnchantmentChance = (NewEnchantmentLevel + 1) / 50 * 100;
|
||||||
if (enchantments.empty() || (Random.NextFloat(100) > ThirdEnchantmentChance))
|
if (Enchantments.empty() || (Random.NextFloat(100) > ThirdEnchantmentChance))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
cEnchantments Enchantment3 = cEnchantments::GetRandomEnchantmentFromVector(enchantments);
|
cEnchantments Enchantment3 = cEnchantments::GetRandomEnchantmentFromVector(Enchantments);
|
||||||
m_Enchantments.AddFromString(Enchantment3.ToString());
|
m_Enchantments.AddFromString(Enchantment3.ToString());
|
||||||
cEnchantments::RemoveEnchantmentWeightFromVector(enchantments, Enchantment3);
|
cEnchantments::RemoveEnchantmentWeightFromVector(Enchantments, Enchantment3);
|
||||||
|
|
||||||
// Checking for conflicting enchantments
|
// Checking for conflicting enchantments
|
||||||
cEnchantments::CheckEnchantmentConflictsFromVector(enchantments, Enchantment3);
|
cEnchantments::CheckEnchantmentConflictsFromVector(Enchantments, Enchantment3);
|
||||||
|
|
||||||
// Next Enchantment (Fourth)
|
// Next Enchantment (Fourth)
|
||||||
NewEnchantmentLevel = NewEnchantmentLevel / 2;
|
NewEnchantmentLevel = NewEnchantmentLevel / 2;
|
||||||
float FourthEnchantmentChance = (NewEnchantmentLevel + 1) / 50 * 100;
|
float FourthEnchantmentChance = (NewEnchantmentLevel + 1) / 50 * 100;
|
||||||
if (enchantments.empty() || (Random.NextFloat(100) > FourthEnchantmentChance))
|
if (Enchantments.empty() || (Random.NextFloat(100) > FourthEnchantmentChance))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
cEnchantments Enchantment4 = cEnchantments::GetRandomEnchantmentFromVector(enchantments);
|
cEnchantments Enchantment4 = cEnchantments::GetRandomEnchantmentFromVector(Enchantments);
|
||||||
m_Enchantments.AddFromString(Enchantment4.ToString());
|
m_Enchantments.AddFromString(Enchantment4.ToString());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -183,8 +183,10 @@ public:
|
|||||||
/** Loads the item data from JSON representation */
|
/** Loads the item data from JSON representation */
|
||||||
void FromJson(const Json::Value & a_Value);
|
void FromJson(const Json::Value & a_Value);
|
||||||
|
|
||||||
/** Returns true if the specified item type is enchantable (as per 1.2.5 protocol requirements) */
|
/** Returns true if the specified item type is enchantable.
|
||||||
static bool IsEnchantable(short a_ItemType); // tolua_export
|
If WithBook is true, the function is used in the anvil inventory with book enchantments.
|
||||||
|
So it checks the "only book enchantments" too. Example: You can only enchant a hoe with a book. */
|
||||||
|
static bool IsEnchantable(short a_ItemType, bool a_WithBook = false); // tolua_export
|
||||||
|
|
||||||
/** Returns the enchantability of the item. When the item hasn't a enchantability, it will returns 0 */
|
/** Returns the enchantability of the item. When the item hasn't a enchantability, it will returns 0 */
|
||||||
int GetEnchantability(); // tolua_export
|
int GetEnchantability(); // tolua_export
|
||||||
|
@ -29,7 +29,7 @@ public:
|
|||||||
switch (m_ItemType)
|
switch (m_ItemType)
|
||||||
{
|
{
|
||||||
// Please keep alpha-sorted.
|
// Please keep alpha-sorted.
|
||||||
case E_ITEM_BAKED_POTATO: return FoodInfo(6, 7.2);
|
case E_ITEM_BAKED_POTATO: return FoodInfo(5, 7.2);
|
||||||
case E_ITEM_BREAD: return FoodInfo(5, 6);
|
case E_ITEM_BREAD: return FoodInfo(5, 6);
|
||||||
// Carrots handled in ItemSeeds
|
// Carrots handled in ItemSeeds
|
||||||
case E_ITEM_COOKED_CHICKEN: return FoodInfo(6, 7.2);
|
case E_ITEM_COOKED_CHICKEN: return FoodInfo(6, 7.2);
|
||||||
@ -43,14 +43,16 @@ public:
|
|||||||
case E_ITEM_POISONOUS_POTATO: return FoodInfo(2, 1.2);
|
case E_ITEM_POISONOUS_POTATO: return FoodInfo(2, 1.2);
|
||||||
// Potatoes handled in ItemSeeds
|
// Potatoes handled in ItemSeeds
|
||||||
case E_ITEM_PUMPKIN_PIE: return FoodInfo(8, 4.8);
|
case E_ITEM_PUMPKIN_PIE: return FoodInfo(8, 4.8);
|
||||||
|
case E_ITEM_RED_APPLE: return FoodInfo(4, 2.4);
|
||||||
case E_ITEM_RAW_BEEF: return FoodInfo(3, 1.8);
|
case E_ITEM_RAW_BEEF: return FoodInfo(3, 1.8);
|
||||||
case E_ITEM_RAW_CHICKEN: return FoodInfo(2, 1.2);
|
case E_ITEM_RAW_CHICKEN: return FoodInfo(2, 1.2);
|
||||||
case E_ITEM_RAW_FISH: return FoodInfo(2, 1.2);
|
case E_ITEM_RAW_FISH: return FoodInfo(2, 1.2);
|
||||||
|
case E_ITEM_RAW_MUTTON: return FoodInfo(2, 1.2);
|
||||||
case E_ITEM_RAW_PORKCHOP: return FoodInfo(3, 1.8);
|
case E_ITEM_RAW_PORKCHOP: return FoodInfo(3, 1.8);
|
||||||
case E_ITEM_RED_APPLE: return FoodInfo(4, 2.4);
|
|
||||||
case E_ITEM_ROTTEN_FLESH: return FoodInfo(4, 0.8);
|
case E_ITEM_ROTTEN_FLESH: return FoodInfo(4, 0.8);
|
||||||
case E_ITEM_SPIDER_EYE: return FoodInfo(2, 3.2);
|
case E_ITEM_SPIDER_EYE: return FoodInfo(2, 3.2);
|
||||||
case E_ITEM_STEAK: return FoodInfo(8, 12.8);
|
case E_ITEM_STEAK: return FoodInfo(8, 12.8);
|
||||||
|
case E_ITEM_MUTTON: return FoodInfo(6, 9.6);
|
||||||
}
|
}
|
||||||
LOGWARNING("%s: Unknown food item (%d), returning zero nutrition", __FUNCTION__, m_ItemType);
|
LOGWARNING("%s: Unknown food item (%d), returning zero nutrition", __FUNCTION__, m_ItemType);
|
||||||
return FoodInfo(0, 0.f);
|
return FoodInfo(0, 0.f);
|
||||||
|
@ -207,7 +207,7 @@ cItemHandler *cItemHandler::CreateItemHandler(int a_ItemType)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Food (please keep alpha-sorted):
|
// Food (please keep alpha-sorted):
|
||||||
// (carrots and potatoes handled in SeedHandler as both seed and food
|
// (carrots and potatoes handled separately in SeedHandler as they're both seed and food)
|
||||||
case E_ITEM_BAKED_POTATO:
|
case E_ITEM_BAKED_POTATO:
|
||||||
case E_ITEM_BREAD:
|
case E_ITEM_BREAD:
|
||||||
case E_ITEM_COOKED_CHICKEN:
|
case E_ITEM_COOKED_CHICKEN:
|
||||||
@ -217,13 +217,15 @@ cItemHandler *cItemHandler::CreateItemHandler(int a_ItemType)
|
|||||||
case E_ITEM_GOLDEN_CARROT:
|
case E_ITEM_GOLDEN_CARROT:
|
||||||
case E_ITEM_MELON_SLICE:
|
case E_ITEM_MELON_SLICE:
|
||||||
case E_ITEM_MUSHROOM_SOUP:
|
case E_ITEM_MUSHROOM_SOUP:
|
||||||
|
case E_ITEM_MUTTON:
|
||||||
case E_ITEM_POISONOUS_POTATO:
|
case E_ITEM_POISONOUS_POTATO:
|
||||||
case E_ITEM_PUMPKIN_PIE:
|
case E_ITEM_PUMPKIN_PIE:
|
||||||
|
case E_ITEM_RED_APPLE:
|
||||||
case E_ITEM_RAW_BEEF:
|
case E_ITEM_RAW_BEEF:
|
||||||
case E_ITEM_RAW_CHICKEN:
|
case E_ITEM_RAW_CHICKEN:
|
||||||
case E_ITEM_RAW_FISH:
|
case E_ITEM_RAW_FISH:
|
||||||
|
case E_ITEM_RAW_MUTTON:
|
||||||
case E_ITEM_RAW_PORKCHOP:
|
case E_ITEM_RAW_PORKCHOP:
|
||||||
case E_ITEM_RED_APPLE:
|
|
||||||
case E_ITEM_ROTTEN_FLESH:
|
case E_ITEM_ROTTEN_FLESH:
|
||||||
case E_ITEM_SPIDER_EYE:
|
case E_ITEM_SPIDER_EYE:
|
||||||
case E_ITEM_STEAK:
|
case E_ITEM_STEAK:
|
||||||
|
@ -37,7 +37,7 @@ public:
|
|||||||
{
|
{
|
||||||
switch (m_ItemType)
|
switch (m_ItemType)
|
||||||
{
|
{
|
||||||
case E_ITEM_CARROT: return FoodInfo(4, 4.8);
|
case E_ITEM_CARROT: return FoodInfo(3, 4.8);
|
||||||
case E_ITEM_POTATO: return FoodInfo(1, 0.6);
|
case E_ITEM_POTATO: return FoodInfo(1, 0.6);
|
||||||
default: return FoodInfo(0, 0);
|
default: return FoodInfo(0, 0);
|
||||||
}
|
}
|
||||||
|
@ -39,6 +39,13 @@ void cSheep::GetDrops(cItems & a_Drops, cEntity * a_Killer)
|
|||||||
{
|
{
|
||||||
a_Drops.push_back(cItem(E_BLOCK_WOOL, 1, m_WoolColor));
|
a_Drops.push_back(cItem(E_BLOCK_WOOL, 1, m_WoolColor));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int LootingLevel = 0;
|
||||||
|
if (a_Killer != NULL)
|
||||||
|
{
|
||||||
|
LootingLevel = a_Killer->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchLooting);
|
||||||
|
}
|
||||||
|
AddRandomDropItem(a_Drops, 1, 3 + LootingLevel, IsOnFire() ? E_ITEM_MUTTON : E_ITEM_RAW_MUTTON);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -180,3 +180,65 @@ extern int UncompressStringGZIP(const char * a_Data, size_t a_Length, AString &
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
extern int InflateString(const char * a_Data, size_t a_Length, AString & a_Uncompressed)
|
||||||
|
{
|
||||||
|
a_Uncompressed.reserve(a_Length);
|
||||||
|
|
||||||
|
char Buffer[64 KiB];
|
||||||
|
z_stream strm;
|
||||||
|
memset(&strm, 0, sizeof(strm));
|
||||||
|
strm.next_in = (Bytef *)a_Data;
|
||||||
|
strm.avail_in = (uInt)a_Length;
|
||||||
|
strm.next_out = (Bytef *)Buffer;
|
||||||
|
strm.avail_out = sizeof(Buffer);
|
||||||
|
|
||||||
|
int res = inflateInit(&strm); // Force GZIP decoding
|
||||||
|
if (res != Z_OK)
|
||||||
|
{
|
||||||
|
LOG("%s: inflation initialization failed: %d (\"%s\").", __FUNCTION__, res, strm.msg);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
res = inflate(&strm, Z_NO_FLUSH);
|
||||||
|
switch (res)
|
||||||
|
{
|
||||||
|
case Z_OK:
|
||||||
|
{
|
||||||
|
// Some data has been uncompressed. Consume the buffer and continue uncompressing
|
||||||
|
a_Uncompressed.append(Buffer, sizeof(Buffer) - strm.avail_out);
|
||||||
|
strm.next_out = (Bytef *)Buffer;
|
||||||
|
strm.avail_out = sizeof(Buffer);
|
||||||
|
if (strm.avail_in == 0)
|
||||||
|
{
|
||||||
|
// All data has been uncompressed
|
||||||
|
inflateEnd(&strm);
|
||||||
|
return Z_OK;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Z_STREAM_END:
|
||||||
|
{
|
||||||
|
// Finished uncompressing. Consume the rest of the buffer and return
|
||||||
|
a_Uncompressed.append(Buffer, sizeof(Buffer) - strm.avail_out);
|
||||||
|
inflateEnd(&strm);
|
||||||
|
return Z_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
// An error has occurred, log it and return the error value
|
||||||
|
LOG("%s: inflation failed: %d (\"%s\").", __FUNCTION__, res, strm.msg);
|
||||||
|
inflateEnd(&strm);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
} // switch (res)
|
||||||
|
} // while (true)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -21,5 +21,7 @@ extern int CompressStringGZIP(const char * a_Data, size_t a_Length, AString & a_
|
|||||||
/// Uncompresses a_Data into a_Uncompressed using GZIP; returns Z_OK for success or Z_XXX error constants same as zlib
|
/// Uncompresses a_Data into a_Uncompressed using GZIP; returns Z_OK for success or Z_XXX error constants same as zlib
|
||||||
extern int UncompressStringGZIP(const char * a_Data, size_t a_Length, AString & a_Uncompressed);
|
extern int UncompressStringGZIP(const char * a_Data, size_t a_Length, AString & a_Uncompressed);
|
||||||
|
|
||||||
|
/** Uncompresses a_Data into a_Uncompressed using Inflate; returns Z_OK for success or Z_XXX error constants same as zlib */
|
||||||
|
extern int InflateString(const char * a_Data, size_t a_Length, AString & a_Uncompressed);
|
||||||
|
|
||||||
|
|
||||||
|
@ -207,7 +207,7 @@ void cSlotArea::ShiftClicked(cPlayer & a_Player, int a_SlotNum, const cItem & a_
|
|||||||
m_ParentWindow.DistributeStack(Slot, a_Player, this, true);
|
m_ParentWindow.DistributeStack(Slot, a_Player, this, true);
|
||||||
if (Slot.IsEmpty())
|
if (Slot.IsEmpty())
|
||||||
{
|
{
|
||||||
// Empty the slot completely, the cilent doesn't like left-over ItemType with zero count
|
// Empty the slot completely, the client doesn't like left-over ItemType with zero count
|
||||||
Slot.Empty();
|
Slot.Empty();
|
||||||
}
|
}
|
||||||
SetSlot(a_SlotNum, a_Player, Slot);
|
SetSlot(a_SlotNum, a_Player, Slot);
|
||||||
@ -1389,8 +1389,11 @@ void cSlotAreaBeacon::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum)
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// cSlotAreaEnchanting:
|
// cSlotAreaEnchanting:
|
||||||
|
|
||||||
cSlotAreaEnchanting::cSlotAreaEnchanting(cEnchantingWindow & a_ParentWindow) :
|
cSlotAreaEnchanting::cSlotAreaEnchanting(cEnchantingWindow & a_ParentWindow, int a_BlockX, int a_BlockY, int a_BlockZ) :
|
||||||
cSlotAreaTemporary(1, a_ParentWindow)
|
cSlotAreaTemporary(1, a_ParentWindow),
|
||||||
|
m_BlockX(a_BlockX),
|
||||||
|
m_BlockY(a_BlockY),
|
||||||
|
m_BlockZ(a_BlockZ)
|
||||||
{
|
{
|
||||||
a_ParentWindow.m_SlotArea = this;
|
a_ParentWindow.m_SlotArea = this;
|
||||||
}
|
}
|
||||||
@ -1428,6 +1431,25 @@ void cSlotAreaEnchanting::Clicked(cPlayer & a_Player, int a_SlotNum, eClickActio
|
|||||||
MiddleClicked(a_Player, a_SlotNum);
|
MiddleClicked(a_Player, a_SlotNum);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
case caDropKey:
|
||||||
|
case caCtrlDropKey:
|
||||||
|
{
|
||||||
|
DropClicked(a_Player, a_SlotNum, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case caNumber1:
|
||||||
|
case caNumber2:
|
||||||
|
case caNumber3:
|
||||||
|
case caNumber4:
|
||||||
|
case caNumber5:
|
||||||
|
case caNumber6:
|
||||||
|
case caNumber7:
|
||||||
|
case caNumber8:
|
||||||
|
case caNumber9:
|
||||||
|
{
|
||||||
|
NumberClicked(a_Player, a_SlotNum, a_ClickAction);
|
||||||
|
return;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
@ -1443,107 +1465,37 @@ void cSlotAreaEnchanting::Clicked(cPlayer & a_Player, int a_SlotNum, eClickActio
|
|||||||
bAsync = true;
|
bAsync = true;
|
||||||
}
|
}
|
||||||
cItem & DraggingItem = a_Player.GetDraggingItem();
|
cItem & DraggingItem = a_Player.GetDraggingItem();
|
||||||
switch (a_ClickAction)
|
|
||||||
|
if (DraggingItem.IsEmpty())
|
||||||
{
|
{
|
||||||
case caRightClick:
|
// DraggingItem is empty -> Switch draggingitem and slot
|
||||||
|
if (!Slot.IsEmpty())
|
||||||
{
|
{
|
||||||
// Right-clicked
|
std::swap(DraggingItem, Slot);
|
||||||
if (DraggingItem.IsEmpty())
|
|
||||||
{
|
|
||||||
DraggingItem = Slot.CopyOne();
|
|
||||||
Slot.Empty();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Slot.IsEmpty())
|
|
||||||
{
|
|
||||||
Slot = DraggingItem.CopyOne();
|
|
||||||
DraggingItem.m_ItemCount -= 1;
|
|
||||||
if (DraggingItem.m_ItemCount <= 0)
|
|
||||||
{
|
|
||||||
DraggingItem.Empty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if ((!DraggingItem.IsEqual(Slot)) && (DraggingItem.m_ItemCount == 1))
|
|
||||||
{
|
|
||||||
// Swap contents
|
|
||||||
cItem tmp(DraggingItem);
|
|
||||||
DraggingItem = Slot;
|
|
||||||
Slot = tmp;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else if (Slot.IsEmpty())
|
||||||
|
{
|
||||||
|
// DraggingItem isn't empty and slot is empty -> Set one dragging item in the slot
|
||||||
|
Slot = DraggingItem.CopyOne();
|
||||||
|
DraggingItem.m_ItemCount -= 1;
|
||||||
|
|
||||||
case caLeftClick:
|
if (DraggingItem.m_ItemCount <= 0)
|
||||||
{
|
{
|
||||||
// Left-clicked
|
DraggingItem.Empty();
|
||||||
if (DraggingItem.IsEmpty())
|
|
||||||
{
|
|
||||||
DraggingItem = Slot.CopyOne();
|
|
||||||
Slot.Empty();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (DraggingItem.IsEqual(Slot))
|
|
||||||
{
|
|
||||||
// Do nothing
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Slot.IsEmpty())
|
|
||||||
{
|
|
||||||
if (DraggingItem.m_ItemCount == 1)
|
|
||||||
{
|
|
||||||
// Swap contents
|
|
||||||
cItem tmp(DraggingItem);
|
|
||||||
DraggingItem = Slot;
|
|
||||||
Slot = tmp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Slot = DraggingItem.CopyOne();
|
|
||||||
DraggingItem.m_ItemCount -= 1;
|
|
||||||
if (DraggingItem.m_ItemCount <= 0)
|
|
||||||
{
|
|
||||||
DraggingItem.Empty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
default:
|
}
|
||||||
{
|
else if ((DraggingItem.m_ItemCount == 1) && !DraggingItem.IsEqual(Slot))
|
||||||
LOGWARNING("SlotArea: Unhandled click action: %d (%s)", a_ClickAction, ClickActionToString(a_ClickAction));
|
{
|
||||||
m_ParentWindow.BroadcastWholeWindow();
|
// DraggingItem and slot aren't empty -> Switch items
|
||||||
return;
|
std::swap(DraggingItem, Slot);
|
||||||
}
|
}
|
||||||
} // switch (a_ClickAction
|
|
||||||
|
|
||||||
SetSlot(a_SlotNum, a_Player, Slot);
|
SetSlot(a_SlotNum, a_Player, Slot);
|
||||||
if (bAsync)
|
if (bAsync)
|
||||||
{
|
{
|
||||||
m_ParentWindow.BroadcastWholeWindow();
|
m_ParentWindow.BroadcastWholeWindow();
|
||||||
}
|
}
|
||||||
UpdateResult(a_Player);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cSlotAreaEnchanting::DblClicked(cPlayer & a_Player, int a_SlotNum)
|
|
||||||
{
|
|
||||||
cItem & Dragging = a_Player.GetDraggingItem();
|
|
||||||
if ((!Dragging.IsEmpty()) || (a_SlotNum != 0))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
cItem Item = *GetSlot(0, a_Player);
|
|
||||||
if (!m_ParentWindow.CollectItemsToHand(Item, *this, a_Player, false))
|
|
||||||
{
|
|
||||||
m_ParentWindow.CollectItemsToHand(Item, *this, a_Player, true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1567,7 +1519,15 @@ void cSlotAreaEnchanting::DistributeStack(cItem & a_ItemStack, cPlayer & a_Playe
|
|||||||
{
|
{
|
||||||
a_ItemStack.Empty();
|
a_ItemStack.Empty();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cSlotAreaEnchanting::OnPlayerAdded(cPlayer & a_Player)
|
||||||
|
{
|
||||||
|
super::OnPlayerAdded(a_Player);
|
||||||
UpdateResult(a_Player);
|
UpdateResult(a_Player);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1587,29 +1547,33 @@ void cSlotAreaEnchanting::OnPlayerRemoved(cPlayer & a_Player)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cSlotAreaEnchanting::SetSlot(int a_SlotNum, cPlayer & a_Player, const cItem & a_Item)
|
||||||
|
{
|
||||||
|
super::SetSlot(a_SlotNum, a_Player, a_Item);
|
||||||
|
UpdateResult(a_Player);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cSlotAreaEnchanting::UpdateResult(cPlayer & a_Player)
|
void cSlotAreaEnchanting::UpdateResult(cPlayer & a_Player)
|
||||||
{
|
{
|
||||||
cItem Item = *GetSlot(0, a_Player);
|
cItem Item = *GetSlot(0, a_Player);
|
||||||
|
|
||||||
if (Item.IsEmpty() || !Item.m_Enchantments.IsEmpty())
|
if (cItem::IsEnchantable(Item.m_ItemType) && Item.m_Enchantments.IsEmpty())
|
||||||
{
|
|
||||||
m_ParentWindow.SetProperty(0, 0, a_Player);
|
|
||||||
m_ParentWindow.SetProperty(1, 0, a_Player);
|
|
||||||
m_ParentWindow.SetProperty(2, 0, a_Player);
|
|
||||||
}
|
|
||||||
else if (cItem::IsEnchantable(Item.m_ItemType) || Item.m_ItemType == E_ITEM_BOOK)
|
|
||||||
{
|
{
|
||||||
int Bookshelves = std::min(GetBookshelvesCount(a_Player.GetWorld()), 15);
|
int Bookshelves = std::min(GetBookshelvesCount(a_Player.GetWorld()), 15);
|
||||||
|
|
||||||
cFastRandom Random;
|
cFastRandom Random;
|
||||||
int base = (Random.GenerateRandomInteger(1, 8) + (int)floor((float)Bookshelves / 2) + Random.GenerateRandomInteger(0, Bookshelves));
|
int Base = (Random.GenerateRandomInteger(1, 8) + (int)floor((float)Bookshelves / 2) + Random.GenerateRandomInteger(0, Bookshelves));
|
||||||
int topSlot = std::max(base / 3, 1);
|
int TopSlot = std::max(Base / 3, 1);
|
||||||
int middleSlot = (base * 2) / 3 + 1;
|
int MiddleSlot = (Base * 2) / 3 + 1;
|
||||||
int bottomSlot = std::max(base, Bookshelves * 2);
|
int BottomSlot = std::max(Base, Bookshelves * 2);
|
||||||
|
|
||||||
m_ParentWindow.SetProperty(0, topSlot, a_Player);
|
m_ParentWindow.SetProperty(0, TopSlot, a_Player);
|
||||||
m_ParentWindow.SetProperty(1, middleSlot, a_Player);
|
m_ParentWindow.SetProperty(1, MiddleSlot, a_Player);
|
||||||
m_ParentWindow.SetProperty(2, bottomSlot, a_Player);
|
m_ParentWindow.SetProperty(2, BottomSlot, a_Player);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1625,12 +1589,9 @@ void cSlotAreaEnchanting::UpdateResult(cPlayer & a_Player)
|
|||||||
|
|
||||||
int cSlotAreaEnchanting::GetBookshelvesCount(cWorld * a_World)
|
int cSlotAreaEnchanting::GetBookshelvesCount(cWorld * a_World)
|
||||||
{
|
{
|
||||||
int PosX, PosY, PosZ;
|
|
||||||
((cEnchantingWindow*)&m_ParentWindow)->GetBlockPos(PosX, PosY, PosZ);
|
|
||||||
|
|
||||||
int Bookshelves = 0;
|
int Bookshelves = 0;
|
||||||
cBlockArea Area;
|
cBlockArea Area;
|
||||||
Area.Read(a_World, PosX - 2, PosX + 2, PosY, PosY + 1, PosZ - 2, PosZ + 2);
|
Area.Read(a_World, m_BlockX - 2, m_BlockX + 2, m_BlockY, m_BlockY + 1, m_BlockZ - 2, m_BlockZ + 2);
|
||||||
|
|
||||||
static const struct
|
static const struct
|
||||||
{
|
{
|
||||||
@ -1678,7 +1639,7 @@ int cSlotAreaEnchanting::GetBookshelvesCount(cWorld * a_World)
|
|||||||
if (
|
if (
|
||||||
(Area.GetRelBlockType(CheckCoords[i].m_AirX, CheckCoords[i].m_AirY, CheckCoords[i].m_AirZ) == E_BLOCK_AIR) && // There's air in the checkspot
|
(Area.GetRelBlockType(CheckCoords[i].m_AirX, CheckCoords[i].m_AirY, CheckCoords[i].m_AirZ) == E_BLOCK_AIR) && // There's air in the checkspot
|
||||||
(Area.GetRelBlockType(CheckCoords[i].m_BookX, CheckCoords[i].m_BookY, CheckCoords[i].m_BookZ) == E_BLOCK_BOOKCASE) // There's bookcase in the wanted place
|
(Area.GetRelBlockType(CheckCoords[i].m_BookX, CheckCoords[i].m_BookY, CheckCoords[i].m_BookZ) == E_BLOCK_BOOKCASE) // There's bookcase in the wanted place
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
Bookshelves++;
|
Bookshelves++;
|
||||||
}
|
}
|
||||||
|
@ -349,14 +349,15 @@ class cSlotAreaEnchanting :
|
|||||||
typedef cSlotAreaTemporary super;
|
typedef cSlotAreaTemporary super;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
cSlotAreaEnchanting(cEnchantingWindow & a_ParentWindow);
|
cSlotAreaEnchanting(cEnchantingWindow & a_ParentWindow, int a_BlockX, int a_BlockY, int a_BlockZ);
|
||||||
|
|
||||||
// cSlotArea overrides:
|
// cSlotArea overrides:
|
||||||
virtual void Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) override;
|
virtual void Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) override;
|
||||||
virtual void DblClicked(cPlayer & a_Player, int a_SlotNum) override;
|
|
||||||
virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) override;
|
virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) override;
|
||||||
|
virtual void SetSlot(int a_SlotNum, cPlayer & a_Player, const cItem & a_Item) override;
|
||||||
|
|
||||||
// cSlotAreaTemporary overrides:
|
// cSlotAreaTemporary overrides:
|
||||||
|
virtual void OnPlayerAdded (cPlayer & a_Player) override;
|
||||||
virtual void OnPlayerRemoved(cPlayer & a_Player) override;
|
virtual void OnPlayerRemoved(cPlayer & a_Player) override;
|
||||||
|
|
||||||
/* Get the count of bookshelves who stand in the near of the enchanting table */
|
/* Get the count of bookshelves who stand in the near of the enchanting table */
|
||||||
@ -365,6 +366,8 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
/** Handles a click in the item slot. */
|
/** Handles a click in the item slot. */
|
||||||
void UpdateResult(cPlayer & a_Player);
|
void UpdateResult(cPlayer & a_Player);
|
||||||
|
|
||||||
|
int m_BlockX, m_BlockY, m_BlockZ;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -881,7 +881,7 @@ cEnchantingWindow::cEnchantingWindow(int a_BlockX, int a_BlockY, int a_BlockZ) :
|
|||||||
m_BlockY(a_BlockY),
|
m_BlockY(a_BlockY),
|
||||||
m_BlockZ(a_BlockZ)
|
m_BlockZ(a_BlockZ)
|
||||||
{
|
{
|
||||||
m_SlotAreas.push_back(new cSlotAreaEnchanting(*this));
|
m_SlotAreas.push_back(new cSlotAreaEnchanting(*this, m_BlockX, m_BlockY, m_BlockZ));
|
||||||
m_SlotAreas.push_back(new cSlotAreaInventory(*this));
|
m_SlotAreas.push_back(new cSlotAreaInventory(*this));
|
||||||
m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
|
m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
|
||||||
}
|
}
|
||||||
@ -892,8 +892,13 @@ cEnchantingWindow::cEnchantingWindow(int a_BlockX, int a_BlockY, int a_BlockZ) :
|
|||||||
|
|
||||||
void cEnchantingWindow::SetProperty(int a_Property, int a_Value)
|
void cEnchantingWindow::SetProperty(int a_Property, int a_Value)
|
||||||
{
|
{
|
||||||
m_PropertyValue[a_Property] = a_Value;
|
if ((a_Property < 0) || ((size_t)a_Property >= ARRAYCOUNT(m_PropertyValue)))
|
||||||
|
{
|
||||||
|
ASSERT(!"a_Property is invalid");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_PropertyValue[a_Property] = a_Value;
|
||||||
super::SetProperty(a_Property, a_Value);
|
super::SetProperty(a_Property, a_Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -903,8 +908,13 @@ void cEnchantingWindow::SetProperty(int a_Property, int a_Value)
|
|||||||
|
|
||||||
void cEnchantingWindow::SetProperty(int a_Property, int a_Value, cPlayer & a_Player)
|
void cEnchantingWindow::SetProperty(int a_Property, int a_Value, cPlayer & a_Player)
|
||||||
{
|
{
|
||||||
m_PropertyValue[a_Property] = a_Value;
|
if ((a_Property < 0) || ((size_t)a_Property >= ARRAYCOUNT(m_PropertyValue)))
|
||||||
|
{
|
||||||
|
ASSERT(!"a_Property is invalid");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_PropertyValue[a_Property] = a_Value;
|
||||||
super::SetProperty(a_Property, a_Value, a_Player);
|
super::SetProperty(a_Property, a_Value, a_Player);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -914,6 +924,12 @@ void cEnchantingWindow::SetProperty(int a_Property, int a_Value, cPlayer & a_Pla
|
|||||||
|
|
||||||
int cEnchantingWindow::GetPropertyValue(int a_Property)
|
int cEnchantingWindow::GetPropertyValue(int a_Property)
|
||||||
{
|
{
|
||||||
|
if ((a_Property < 0) || ((size_t)a_Property >= ARRAYCOUNT(m_PropertyValue)))
|
||||||
|
{
|
||||||
|
ASSERT(!"a_Property is invalid");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return m_PropertyValue[a_Property];
|
return m_PropertyValue[a_Property];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -921,17 +937,6 @@ int cEnchantingWindow::GetPropertyValue(int a_Property)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cEnchantingWindow::GetBlockPos(int & a_PosX, int & a_PosY, int & a_PosZ)
|
|
||||||
{
|
|
||||||
a_PosX = m_BlockX;
|
|
||||||
a_PosY = m_BlockY;
|
|
||||||
a_PosZ = m_BlockZ;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// cChestWindow:
|
// cChestWindow:
|
||||||
|
|
||||||
|
@ -291,9 +291,6 @@ public:
|
|||||||
/** Return the Value of a Property */
|
/** Return the Value of a Property */
|
||||||
int GetPropertyValue(int a_Property);
|
int GetPropertyValue(int a_Property);
|
||||||
|
|
||||||
/** Get the Position from the Enchantment Table */
|
|
||||||
void GetBlockPos(int & a_PosX, int & a_PosY, int & a_PosZ);
|
|
||||||
|
|
||||||
cSlotArea * m_SlotArea;
|
cSlotArea * m_SlotArea;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -442,7 +442,7 @@ void cWorld::InitializeSpawn(void)
|
|||||||
{
|
{
|
||||||
for (int z = 0; z < ViewDist; z++)
|
for (int z = 0; z < ViewDist; z++)
|
||||||
{
|
{
|
||||||
m_ChunkMap->TouchChunk(x + ChunkX-(ViewDist - 1) / 2, ZERO_CHUNK_Y, z + ChunkZ-(ViewDist - 1) / 2); // Queue the chunk in the generator / loader
|
m_ChunkMap->TouchChunk(x + ChunkX-(ViewDist - 1) / 2, z + ChunkZ-(ViewDist - 1) / 2); // Queue the chunk in the generator / loader
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2424,7 +2424,7 @@ void cWorld::SetChunkData(cSetChunkData & a_SetChunkData)
|
|||||||
// Save the chunk right after generating, so that we don't have to generate it again on next run
|
// Save the chunk right after generating, so that we don't have to generate it again on next run
|
||||||
if (a_SetChunkData.ShouldMarkDirty())
|
if (a_SetChunkData.ShouldMarkDirty())
|
||||||
{
|
{
|
||||||
m_Storage.QueueSaveChunk(ChunkX, 0, ChunkZ);
|
m_Storage.QueueSaveChunk(ChunkX, ChunkZ);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2696,6 +2696,15 @@ bool cWorld::ForEachEntityInChunk(int a_ChunkX, int a_ChunkZ, cEntityCallback &
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool cWorld::ForEachEntityInBox(const cBoundingBox & a_Box, cEntityCallback & a_Callback)
|
||||||
|
{
|
||||||
|
return m_ChunkMap->ForEachEntityInBox(a_Box, a_Callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cWorld::DoWithEntityByID(int a_UniqueID, cEntityCallback & a_Callback)
|
bool cWorld::DoWithEntityByID(int a_UniqueID, cEntityCallback & a_Callback)
|
||||||
{
|
{
|
||||||
return m_ChunkMap->DoWithEntityByID(a_UniqueID, a_Callback);
|
return m_ChunkMap->DoWithEntityByID(a_UniqueID, a_Callback);
|
||||||
@ -2769,18 +2778,18 @@ void cWorld::RemoveClientFromChunkSender(cClientHandle * a_Client)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cWorld::TouchChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ)
|
void cWorld::TouchChunk(int a_ChunkX, int a_ChunkZ)
|
||||||
{
|
{
|
||||||
m_ChunkMap->TouchChunk(a_ChunkX, a_ChunkY, a_ChunkZ);
|
m_ChunkMap->TouchChunk(a_ChunkX, a_ChunkZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cWorld::LoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ)
|
bool cWorld::LoadChunk(int a_ChunkX, int a_ChunkZ)
|
||||||
{
|
{
|
||||||
return m_ChunkMap->LoadChunk(a_ChunkX, a_ChunkY, a_ChunkZ);
|
return m_ChunkMap->LoadChunk(a_ChunkX, a_ChunkZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2796,9 +2805,9 @@ void cWorld::LoadChunks(const cChunkCoordsList & a_Chunks)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cWorld::ChunkLoadFailed(int a_ChunkX, int a_ChunkY, int a_ChunkZ)
|
void cWorld::ChunkLoadFailed(int a_ChunkX, int a_ChunkZ)
|
||||||
{
|
{
|
||||||
m_ChunkMap->ChunkLoadFailed(a_ChunkX, a_ChunkY, a_ChunkZ);
|
m_ChunkMap->ChunkLoadFailed(a_ChunkX, a_ChunkZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2903,8 +2912,7 @@ void cWorld::RegenerateChunk(int a_ChunkX, int a_ChunkZ)
|
|||||||
{
|
{
|
||||||
m_ChunkMap->MarkChunkRegenerating(a_ChunkX, a_ChunkZ);
|
m_ChunkMap->MarkChunkRegenerating(a_ChunkX, a_ChunkZ);
|
||||||
|
|
||||||
// Trick: use Y=1 to force the chunk generation even though the chunk data is already present
|
m_Generator.QueueGenerateChunk(a_ChunkX, a_ChunkZ, true);
|
||||||
m_Generator.QueueGenerateChunk(a_ChunkX, 1, a_ChunkZ);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2913,7 +2921,7 @@ void cWorld::RegenerateChunk(int a_ChunkX, int a_ChunkZ)
|
|||||||
|
|
||||||
void cWorld::GenerateChunk(int a_ChunkX, int a_ChunkZ)
|
void cWorld::GenerateChunk(int a_ChunkX, int a_ChunkZ)
|
||||||
{
|
{
|
||||||
m_Generator.QueueGenerateChunk(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ);
|
m_Generator.QueueGenerateChunk(a_ChunkX, a_ChunkZ, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
13
src/World.h
13
src/World.h
@ -324,6 +324,11 @@ public:
|
|||||||
/** Calls the callback for each entity in the specified chunk; returns true if all entities processed, false if the callback aborted by returning true */
|
/** Calls the callback for each entity in the specified chunk; returns true if all entities processed, false if the callback aborted by returning true */
|
||||||
bool ForEachEntityInChunk(int a_ChunkX, int a_ChunkZ, cEntityCallback & a_Callback); // Exported in ManualBindings.cpp
|
bool ForEachEntityInChunk(int a_ChunkX, int a_ChunkZ, cEntityCallback & a_Callback); // Exported in ManualBindings.cpp
|
||||||
|
|
||||||
|
/** Calls the callback for each entity that has a nonempty intersection with the specified boundingbox.
|
||||||
|
Returns true if all entities processed, false if the callback aborted by returning true.
|
||||||
|
If any chunk in the box is missing, ignores the entities in that chunk silently. */
|
||||||
|
bool ForEachEntityInBox(const cBoundingBox & a_Box, cEntityCallback & a_Callback); // Exported in ManualBindings.cpp
|
||||||
|
|
||||||
/** Calls the callback if the entity with the specified ID is found, with the entity object as the callback param. Returns true if entity found and callback returned false. */
|
/** Calls the callback if the entity with the specified ID is found, with the entity object as the callback param. Returns true if entity found and callback returned false. */
|
||||||
bool DoWithEntityByID(int a_UniqueID, cEntityCallback & a_Callback); // Exported in ManualBindings.cpp
|
bool DoWithEntityByID(int a_UniqueID, cEntityCallback & a_Callback); // Exported in ManualBindings.cpp
|
||||||
|
|
||||||
@ -351,16 +356,16 @@ public:
|
|||||||
void RemoveClientFromChunkSender(cClientHandle * a_Client);
|
void RemoveClientFromChunkSender(cClientHandle * a_Client);
|
||||||
|
|
||||||
/** Touches the chunk, causing it to be loaded or generated */
|
/** Touches the chunk, causing it to be loaded or generated */
|
||||||
void TouchChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ);
|
void TouchChunk(int a_ChunkX, int a_ChunkZ);
|
||||||
|
|
||||||
/** Loads the chunk, if not already loaded. Doesn't generate. Returns true if chunk valid (even if already loaded before) */
|
/** Loads the chunk, if not already loaded. Doesn't generate. Returns true if chunk valid (even if already loaded before) */
|
||||||
bool LoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ);
|
bool LoadChunk(int a_ChunkX, int a_ChunkZ);
|
||||||
|
|
||||||
/** Loads the chunks specified. Doesn't report failure, other than chunks being !IsValid() */
|
/** Loads the chunks specified. Doesn't report failure, other than chunks being !IsValid() */
|
||||||
void LoadChunks(const cChunkCoordsList & a_Chunks);
|
void LoadChunks(const cChunkCoordsList & a_Chunks);
|
||||||
|
|
||||||
/** Marks the chunk as failed-to-load: */
|
/** Marks the chunk as failed-to-load: */
|
||||||
void ChunkLoadFailed(int a_ChunkX, int a_ChunkY, int a_ChunkZ);
|
void ChunkLoadFailed(int a_ChunkX, int a_ChunkZ);
|
||||||
|
|
||||||
/** Sets the sign text, asking plugins for permission first. a_Player is the player who this change belongs to, may be NULL. Returns true if sign text changed. Same as UpdateSign() */
|
/** Sets the sign text, asking plugins for permission first. a_Player is the player who this change belongs to, may be NULL. Returns true if sign text changed. Same as UpdateSign() */
|
||||||
bool SetSignLines(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, cPlayer * a_Player = NULL); // Exported in ManualBindings.cpp
|
bool SetSignLines(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, cPlayer * a_Player = NULL); // Exported in ManualBindings.cpp
|
||||||
@ -380,7 +385,7 @@ public:
|
|||||||
/** Regenerate the given chunk: */
|
/** Regenerate the given chunk: */
|
||||||
void RegenerateChunk(int a_ChunkX, int a_ChunkZ); // tolua_export
|
void RegenerateChunk(int a_ChunkX, int a_ChunkZ); // tolua_export
|
||||||
|
|
||||||
/** Generates the given chunk, if not already generated */
|
/** Generates the given chunk */
|
||||||
void GenerateChunk(int a_ChunkX, int a_ChunkZ); // tolua_export
|
void GenerateChunk(int a_ChunkX, int a_ChunkZ); // tolua_export
|
||||||
|
|
||||||
/** Queues a chunk for lighting; a_Callback is called after the chunk is lighted */
|
/** Queues a chunk for lighting; a_Callback is called after the chunk is lighted */
|
||||||
|
@ -66,8 +66,17 @@ Since only the header is actually in the memory, this number can be high, but st
|
|||||||
*/
|
*/
|
||||||
#define MAX_MCA_FILES 32
|
#define MAX_MCA_FILES 32
|
||||||
|
|
||||||
/// The maximum size of an inflated chunk; raw chunk data is 192 KiB, allow 64 KiB more of entities
|
#define LOAD_FAILED(CHX, CHZ) \
|
||||||
#define CHUNK_INFLATE_MAX 256 KiB
|
{ \
|
||||||
|
const int RegionX = FAST_FLOOR_DIV(CHX, 32); \
|
||||||
|
const int RegionZ = FAST_FLOOR_DIV(CHZ, 32); \
|
||||||
|
LOGERROR("%s (%d): Loading chunk [%d, %d] from file r.%d.%d.mca failed. " \
|
||||||
|
"The server will now abort in order to avoid further data loss. " \
|
||||||
|
"Please add the reported file and this message to the issue report.", \
|
||||||
|
__FUNCTION__, __LINE__, CHX, CHZ, RegionX, RegionZ \
|
||||||
|
); \
|
||||||
|
*((volatile int *)0) = 0; /* Crash intentionally */ \
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -248,29 +257,22 @@ cWSSAnvil::cMCAFile * cWSSAnvil::LoadMCAFile(const cChunkCoords & a_Chunk)
|
|||||||
|
|
||||||
bool cWSSAnvil::LoadChunkFromData(const cChunkCoords & a_Chunk, const AString & a_Data)
|
bool cWSSAnvil::LoadChunkFromData(const cChunkCoords & a_Chunk, const AString & a_Data)
|
||||||
{
|
{
|
||||||
// Decompress the data:
|
// Uncompress the data:
|
||||||
char Uncompressed[CHUNK_INFLATE_MAX];
|
AString Uncompressed;
|
||||||
z_stream strm;
|
int res = InflateString(a_Data.data(), a_Data.size(), Uncompressed);
|
||||||
strm.zalloc = (alloc_func)NULL;
|
if (res != Z_OK)
|
||||||
strm.zfree = (free_func)NULL;
|
|
||||||
strm.opaque = NULL;
|
|
||||||
inflateInit(&strm);
|
|
||||||
strm.next_out = (Bytef *)Uncompressed;
|
|
||||||
strm.avail_out = sizeof(Uncompressed);
|
|
||||||
strm.next_in = (Bytef *)a_Data.data();
|
|
||||||
strm.avail_in = (uInt)a_Data.size();
|
|
||||||
int res = inflate(&strm, Z_FINISH);
|
|
||||||
inflateEnd(&strm);
|
|
||||||
if (res != Z_STREAM_END)
|
|
||||||
{
|
{
|
||||||
|
LOGWARNING("Uncompressing chunk [%d, %d] failed: %d", a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, res);
|
||||||
|
LOAD_FAILED(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse the NBT data:
|
// Parse the NBT data:
|
||||||
cParsedNBT NBT(Uncompressed, strm.total_out);
|
cParsedNBT NBT(Uncompressed.data(), Uncompressed.size());
|
||||||
if (!NBT.IsValid())
|
if (!NBT.IsValid())
|
||||||
{
|
{
|
||||||
// NBT Parsing failed
|
// NBT Parsing failed
|
||||||
|
LOAD_FAILED(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -317,11 +319,13 @@ bool cWSSAnvil::LoadChunkFromNBT(const cChunkCoords & a_Chunk, const cParsedNBT
|
|||||||
int Level = a_NBT.FindChildByName(0, "Level");
|
int Level = a_NBT.FindChildByName(0, "Level");
|
||||||
if (Level < 0)
|
if (Level < 0)
|
||||||
{
|
{
|
||||||
|
LOAD_FAILED(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
int Sections = a_NBT.FindChildByName(Level, "Sections");
|
int Sections = a_NBT.FindChildByName(Level, "Sections");
|
||||||
if ((Sections < 0) || (a_NBT.GetType(Sections) != TAG_List) || (a_NBT.GetChildrenType(Sections) != TAG_Compound))
|
if ((Sections < 0) || (a_NBT.GetType(Sections) != TAG_List) || (a_NBT.GetChildrenType(Sections) != TAG_Compound))
|
||||||
{
|
{
|
||||||
|
LOAD_FAILED(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (int Child = a_NBT.GetFirstChild(Sections); Child >= 0; Child = a_NBT.GetNextSibling(Child))
|
for (int Child = a_NBT.GetFirstChild(Sections); Child >= 0; Child = a_NBT.GetNextSibling(Child))
|
||||||
@ -2811,30 +2815,42 @@ bool cWSSAnvil::cMCAFile::GetChunkData(const cChunkCoords & a_Chunk, AString & a
|
|||||||
}
|
}
|
||||||
unsigned ChunkLocation = ntohl(m_Header[LocalX + 32 * LocalZ]);
|
unsigned ChunkLocation = ntohl(m_Header[LocalX + 32 * LocalZ]);
|
||||||
unsigned ChunkOffset = ChunkLocation >> 8;
|
unsigned ChunkOffset = ChunkLocation >> 8;
|
||||||
|
if (ChunkOffset <= 2)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
m_File.Seek((int)ChunkOffset * 4096);
|
m_File.Seek((int)ChunkOffset * 4096);
|
||||||
|
|
||||||
int ChunkSize = 0;
|
int ChunkSize = 0;
|
||||||
if (m_File.Read(&ChunkSize, 4) != 4)
|
if (m_File.Read(&ChunkSize, 4) != 4)
|
||||||
{
|
{
|
||||||
|
LOAD_FAILED(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ChunkSize = ntohl((u_long)ChunkSize);
|
ChunkSize = ntohl((u_long)ChunkSize);
|
||||||
char CompressionType = 0;
|
char CompressionType = 0;
|
||||||
if (m_File.Read(&CompressionType, 1) != 1)
|
if (m_File.Read(&CompressionType, 1) != 1)
|
||||||
{
|
{
|
||||||
|
LOAD_FAILED(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (CompressionType != 2)
|
if (CompressionType != 2)
|
||||||
{
|
{
|
||||||
// Chunk is in an unknown compression
|
// Chunk is in an unknown compression
|
||||||
|
LOAD_FAILED(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ChunkSize--;
|
ChunkSize--;
|
||||||
|
|
||||||
// HACK: This depends on the internal knowledge that AString's data() function returns the internal buffer directly
|
// HACK: This depends on the internal knowledge that AString's data() function returns the internal buffer directly
|
||||||
a_Data.assign(ChunkSize, '\0');
|
a_Data.assign(ChunkSize, '\0');
|
||||||
return (m_File.Read((void *)a_Data.data(), ChunkSize) == ChunkSize);
|
if (m_File.Read((void *)a_Data.data(), ChunkSize) == ChunkSize)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
LOAD_FAILED(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2889,7 +2905,13 @@ bool cWSSAnvil::cMCAFile::SetChunkData(const cChunkCoords & a_Chunk, const AStri
|
|||||||
|
|
||||||
// Store the header:
|
// Store the header:
|
||||||
ChunkSize = ((u_long)a_Data.size() + MCA_CHUNK_HEADER_LENGTH + 4095) / 4096; // Round data size *up* to nearest 4KB sector, make it a sector number
|
ChunkSize = ((u_long)a_Data.size() + MCA_CHUNK_HEADER_LENGTH + 4095) / 4096; // Round data size *up* to nearest 4KB sector, make it a sector number
|
||||||
ASSERT(ChunkSize < 256);
|
if (ChunkSize > 255)
|
||||||
|
{
|
||||||
|
LOGWARNING("Cannot save chunk [%d, %d], the data is too large (%u KiB, maximum is 1024 KiB). Remove some entities and retry.",
|
||||||
|
a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, (unsigned)(ChunkSize * 4)
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
m_Header[LocalX + 32 * LocalZ] = htonl((ChunkSector << 8) | ChunkSize);
|
m_Header[LocalX + 32 * LocalZ] = htonl((ChunkSector << 8) | ChunkSize);
|
||||||
if (m_File.Seek(0) < 0)
|
if (m_File.Seek(0) < 0)
|
||||||
{
|
{
|
||||||
|
@ -980,7 +980,7 @@ bool cWSSCompact::cPAKFile::SaveChunkToData(const cChunkCoords & a_Chunk, cWorld
|
|||||||
if (!a_World->GetChunkData(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, Serializer))
|
if (!a_World->GetChunkData(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, Serializer))
|
||||||
{
|
{
|
||||||
// Chunk not valid
|
// Chunk not valid
|
||||||
LOG("cWSSCompact: Trying to save chunk [%d, %d, %d] that has no data, ignoring request.", a_Chunk.m_ChunkX, a_Chunk.m_ChunkY, a_Chunk.m_ChunkZ);
|
LOG("cWSSCompact: Trying to save chunk [%d, %d] that has no data, ignoring request.", a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -999,7 +999,7 @@ bool cWSSCompact::cPAKFile::SaveChunkToData(const cChunkCoords & a_Chunk, cWorld
|
|||||||
int errorcode = CompressString(Data.data(), Data.size(), CompressedData, m_CompressionFactor);
|
int errorcode = CompressString(Data.data(), Data.size(), CompressedData, m_CompressionFactor);
|
||||||
if (errorcode != Z_OK)
|
if (errorcode != Z_OK)
|
||||||
{
|
{
|
||||||
LOGERROR("Error %i compressing data for chunk [%d, %d, %d]", errorcode, a_Chunk.m_ChunkX, a_Chunk.m_ChunkY, a_Chunk.m_ChunkZ);
|
LOGERROR("Error %i compressing data for chunk [%d, %d]", errorcode, a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1010,7 +1010,7 @@ bool cWSSCompact::cPAKFile::SaveChunkToData(const cChunkCoords & a_Chunk, cWorld
|
|||||||
sChunkHeader * Header = new sChunkHeader;
|
sChunkHeader * Header = new sChunkHeader;
|
||||||
if (Header == NULL)
|
if (Header == NULL)
|
||||||
{
|
{
|
||||||
LOGWARNING("Cannot create a new chunk header to save chunk [%d, %d, %d]", a_Chunk.m_ChunkX, a_Chunk.m_ChunkY, a_Chunk.m_ChunkZ);
|
LOGWARNING("Cannot create a new chunk header to save chunk [%d, %d]", a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Header->m_CompressedSize = (int)CompressedData.size();
|
Header->m_CompressedSize = (int)CompressedData.size();
|
||||||
|
@ -141,9 +141,9 @@ size_t cWorldStorage::GetSaveQueueLength(void)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cWorldStorage::QueueLoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, bool a_Generate)
|
void cWorldStorage::QueueLoadChunk(int a_ChunkX, int a_ChunkZ, bool a_Generate)
|
||||||
{
|
{
|
||||||
m_LoadQueue.EnqueueItem(sChunkLoad(a_ChunkX, a_ChunkY, a_ChunkZ, a_Generate));
|
m_LoadQueue.EnqueueItem(sChunkLoad(a_ChunkX, a_ChunkZ, a_Generate));
|
||||||
m_Event.Set();
|
m_Event.Set();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,9 +151,9 @@ void cWorldStorage::QueueLoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, boo
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cWorldStorage::QueueSaveChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ)
|
void cWorldStorage::QueueSaveChunk(int a_ChunkX, int a_ChunkZ)
|
||||||
{
|
{
|
||||||
m_SaveQueue.EnqueueItemIfNotPresent(cChunkCoords(a_ChunkX, a_ChunkY, a_ChunkZ));
|
m_SaveQueue.EnqueueItemIfNotPresent(cChunkCoords(a_ChunkX, a_ChunkZ));
|
||||||
m_Event.Set();
|
m_Event.Set();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,9 +161,9 @@ void cWorldStorage::QueueSaveChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cWorldStorage::UnqueueLoad(int a_ChunkX, int a_ChunkY, int a_ChunkZ)
|
void cWorldStorage::UnqueueLoad(int a_ChunkX, int a_ChunkZ)
|
||||||
{
|
{
|
||||||
m_LoadQueue.Remove(sChunkLoad(a_ChunkX, a_ChunkY, a_ChunkZ, true));
|
m_LoadQueue.Remove(sChunkLoad(a_ChunkX, a_ChunkZ, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -242,19 +242,19 @@ void cWorldStorage::Execute(void)
|
|||||||
|
|
||||||
bool cWorldStorage::LoadOneChunk(void)
|
bool cWorldStorage::LoadOneChunk(void)
|
||||||
{
|
{
|
||||||
sChunkLoad ToLoad(0, 0, 0, false);
|
sChunkLoad ToLoad(0, 0, false);
|
||||||
bool ShouldLoad = m_LoadQueue.TryDequeueItem(ToLoad);
|
bool ShouldLoad = m_LoadQueue.TryDequeueItem(ToLoad);
|
||||||
if (ShouldLoad && !LoadChunk(ToLoad.m_ChunkX, ToLoad.m_ChunkY, ToLoad.m_ChunkZ))
|
if (ShouldLoad && !LoadChunk(ToLoad.m_ChunkX, ToLoad.m_ChunkZ))
|
||||||
{
|
{
|
||||||
if (ToLoad.m_Generate)
|
if (ToLoad.m_Generate)
|
||||||
{
|
{
|
||||||
// The chunk couldn't be loaded, generate it:
|
// The chunk couldn't be loaded, generate it:
|
||||||
m_World->GetGenerator().QueueGenerateChunk(ToLoad.m_ChunkX, ToLoad.m_ChunkY, ToLoad.m_ChunkZ);
|
m_World->GetGenerator().QueueGenerateChunk(ToLoad.m_ChunkX, ToLoad.m_ChunkZ, false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// TODO: Notify the world that the load has failed:
|
// TODO: Notify the world that the load has failed:
|
||||||
// m_World->ChunkLoadFailed(ToLoad.m_ChunkX, ToLoad.m_ChunkY, ToLoad.m_ChunkZ);
|
// m_World->ChunkLoadFailed(ToLoad.m_ChunkX, ToLoad.m_ChunkZ);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ShouldLoad;
|
return ShouldLoad;
|
||||||
@ -266,7 +266,7 @@ bool cWorldStorage::LoadOneChunk(void)
|
|||||||
|
|
||||||
bool cWorldStorage::SaveOneChunk(void)
|
bool cWorldStorage::SaveOneChunk(void)
|
||||||
{
|
{
|
||||||
cChunkCoords ToSave(0, 0, 0);
|
cChunkCoords ToSave(0, 0);
|
||||||
bool ShouldSave = m_SaveQueue.TryDequeueItem(ToSave);
|
bool ShouldSave = m_SaveQueue.TryDequeueItem(ToSave);
|
||||||
if (ShouldSave && m_World->IsChunkValid(ToSave.m_ChunkX, ToSave.m_ChunkZ))
|
if (ShouldSave && m_World->IsChunkValid(ToSave.m_ChunkX, ToSave.m_ChunkZ))
|
||||||
{
|
{
|
||||||
@ -283,7 +283,7 @@ bool cWorldStorage::SaveOneChunk(void)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cWorldStorage::LoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ)
|
bool cWorldStorage::LoadChunk(int a_ChunkX, int a_ChunkZ)
|
||||||
{
|
{
|
||||||
if (m_World->IsChunkValid(a_ChunkX, a_ChunkZ))
|
if (m_World->IsChunkValid(a_ChunkX, a_ChunkZ))
|
||||||
{
|
{
|
||||||
@ -291,7 +291,7 @@ bool cWorldStorage::LoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
cChunkCoords Coords(a_ChunkX, a_ChunkY, a_ChunkZ);
|
cChunkCoords Coords(a_ChunkX, a_ChunkZ);
|
||||||
|
|
||||||
// First try the schema that is used for saving
|
// First try the schema that is used for saving
|
||||||
if (m_SaveSchema->LoadChunk(Coords))
|
if (m_SaveSchema->LoadChunk(Coords))
|
||||||
@ -309,7 +309,7 @@ bool cWorldStorage::LoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Notify the chunk owner that the chunk failed to load (sets cChunk::m_HasLoadFailed to true):
|
// Notify the chunk owner that the chunk failed to load (sets cChunk::m_HasLoadFailed to true):
|
||||||
m_World->ChunkLoadFailed(a_ChunkX, a_ChunkY, a_ChunkZ);
|
m_World->ChunkLoadFailed(a_ChunkX, a_ChunkZ);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -64,13 +64,13 @@ public:
|
|||||||
cWorldStorage(void);
|
cWorldStorage(void);
|
||||||
~cWorldStorage();
|
~cWorldStorage();
|
||||||
|
|
||||||
void QueueLoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, bool a_Generate); // Queues the chunk for loading; if not loaded, the chunk will be generated if a_Generate is true
|
void QueueLoadChunk(int a_ChunkX, int a_ChunkZ, bool a_Generate); // Queues the chunk for loading; if not loaded, the chunk will be generated if a_Generate is true
|
||||||
void QueueSaveChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ);
|
void QueueSaveChunk(int a_ChunkX, int a_ChunkZ);
|
||||||
|
|
||||||
/// Loads the chunk specified; returns true on success, false on failure
|
/// Loads the chunk specified; returns true on success, false on failure
|
||||||
bool LoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ);
|
bool LoadChunk(int a_ChunkX, int a_ChunkZ);
|
||||||
|
|
||||||
void UnqueueLoad(int a_ChunkX, int a_ChunkY, int a_ChunkZ);
|
void UnqueueLoad(int a_ChunkX, int a_ChunkZ);
|
||||||
void UnqueueSave(const cChunkCoords & a_Chunk);
|
void UnqueueSave(const cChunkCoords & a_Chunk);
|
||||||
|
|
||||||
bool Start(cWorld * a_World, const AString & a_StorageSchemaName, int a_StorageCompressionFactor); // Hide the cIsThread's Start() method, we need to provide args
|
bool Start(cWorld * a_World, const AString & a_StorageSchemaName, int a_StorageCompressionFactor); // Hide the cIsThread's Start() method, we need to provide args
|
||||||
@ -87,17 +87,15 @@ protected:
|
|||||||
struct sChunkLoad
|
struct sChunkLoad
|
||||||
{
|
{
|
||||||
int m_ChunkX;
|
int m_ChunkX;
|
||||||
int m_ChunkY;
|
|
||||||
int m_ChunkZ;
|
int m_ChunkZ;
|
||||||
bool m_Generate; // If true, the chunk will be generated if it cannot be loaded
|
bool m_Generate; // If true, the chunk will be generated if it cannot be loaded
|
||||||
|
|
||||||
sChunkLoad(int a_ChunkX, int a_ChunkY, int a_ChunkZ, bool a_Generate) : m_ChunkX(a_ChunkX), m_ChunkY(a_ChunkY), m_ChunkZ(a_ChunkZ), m_Generate(a_Generate) {}
|
sChunkLoad(int a_ChunkX, int a_ChunkZ, bool a_Generate) : m_ChunkX(a_ChunkX), m_ChunkZ(a_ChunkZ), m_Generate(a_Generate) {}
|
||||||
|
|
||||||
bool operator ==(const sChunkLoad other) const
|
bool operator ==(const sChunkLoad other) const
|
||||||
{
|
{
|
||||||
return (
|
return (
|
||||||
(this->m_ChunkX == other.m_ChunkX) &&
|
(this->m_ChunkX == other.m_ChunkX) &&
|
||||||
(this->m_ChunkY == other.m_ChunkY) &&
|
|
||||||
(this->m_ChunkZ == other.m_ChunkZ)
|
(this->m_ChunkZ == other.m_ChunkZ)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user