summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTycho Bickerstaff <work.tycho@gmail.com>2013-12-21 14:32:40 +0100
committerTycho Bickerstaff <work.tycho@gmail.com>2013-12-21 14:32:40 +0100
commit779aca60511055832e776ab4a6299a2b7e049a16 (patch)
treedfb031e9bd01b25ab0199286cf6e660f26489817
parentMerge branch 'master' into cmake (diff)
parentMerge branch 'master', remote-tracking branch 'upstream/master' (diff)
downloadcuberite-779aca60511055832e776ab4a6299a2b7e049a16.tar
cuberite-779aca60511055832e776ab4a6299a2b7e049a16.tar.gz
cuberite-779aca60511055832e776ab4a6299a2b7e049a16.tar.bz2
cuberite-779aca60511055832e776ab4a6299a2b7e049a16.tar.lz
cuberite-779aca60511055832e776ab4a6299a2b7e049a16.tar.xz
cuberite-779aca60511055832e776ab4a6299a2b7e049a16.tar.zst
cuberite-779aca60511055832e776ab4a6299a2b7e049a16.zip
Diffstat (limited to '')
-rw-r--r--MCServer/Plugins/APIDump/Static/.gitignore1
-rw-r--r--MCServer/Plugins/APIDump/main_APIDump.lua8
-rw-r--r--Nightbuild2008.cmd15
-rw-r--r--src/BlockArea.cpp3
-rw-r--r--src/BlockID.cpp3
-rw-r--r--src/Chunk.cpp41
-rw-r--r--src/ChunkSender.cpp4
-rw-r--r--src/ClientHandle.cpp41
-rw-r--r--src/ClientHandle.h9
-rw-r--r--src/Entities/Entity.cpp12
-rw-r--r--src/Entities/Entity.h2
-rw-r--r--src/Entities/Floater.cpp21
-rw-r--r--src/Entities/Player.cpp43
-rw-r--r--src/Entities/Player.h9
-rw-r--r--src/Entities/ProjectileEntity.cpp8
-rw-r--r--src/Items/ItemFishingRod.h9
-rw-r--r--src/MobCensus.cpp8
-rw-r--r--src/Mobs/Monster.cpp14
-rw-r--r--src/Mobs/Monster.h2
-rw-r--r--src/Mobs/Wolf.cpp4
-rw-r--r--src/Mobs/Zombie.cpp9
-rw-r--r--src/Mobs/Zombie.h9
-rw-r--r--src/OSSupport/IsThread.cpp4
-rw-r--r--src/Protocol/Protocol132.cpp4
-rw-r--r--src/Root.cpp72
-rw-r--r--src/Simulator/RedstoneSimulator.cpp41
-rw-r--r--src/Simulator/RedstoneSimulator.h9
-rw-r--r--src/World.cpp12
-rw-r--r--src/World.h2
29 files changed, 238 insertions, 181 deletions
diff --git a/MCServer/Plugins/APIDump/Static/.gitignore b/MCServer/Plugins/APIDump/Static/.gitignore
new file mode 100644
index 000000000..8d1c8b69c
--- /dev/null
+++ b/MCServer/Plugins/APIDump/Static/.gitignore
@@ -0,0 +1 @@
+
diff --git a/MCServer/Plugins/APIDump/main_APIDump.lua b/MCServer/Plugins/APIDump/main_APIDump.lua
index ec5569f55..e5c8b9c30 100644
--- a/MCServer/Plugins/APIDump/main_APIDump.lua
+++ b/MCServer/Plugins/APIDump/main_APIDump.lua
@@ -1,4 +1,3 @@
-
-- main.lua
-- Implements the plugin entrypoint (in this case the entire plugin)
@@ -232,6 +231,13 @@ end
function DumpAPIHtml()
LOG("Dumping all available functions and constants to API subfolder...");
+
+ LOG("Moving static files..");
+ cFile:CreateFolder("API/Static");
+ local localFolder = g_Plugin:GetLocalFolder();
+ for k, v in cFile:GetFolderContents(localFolder .. "/Static") do
+ cFile:Copy(localFolder .. "/Static/" .. v, "API/Static/" .. v);
+ end
LOG("Creating API tables...");
local API, Globals = CreateAPITables();
diff --git a/Nightbuild2008.cmd b/Nightbuild2008.cmd
index ad0b415ba..cbd23692b 100644
--- a/Nightbuild2008.cmd
+++ b/Nightbuild2008.cmd
@@ -1,17 +1,20 @@
@echo off
:: Nightbbuild2008.cmd
:: This script is run every night to produce a new version of MCServer, backup its PDB files and upload the packages to web.
-:: These sub-scripts are used:
-:: - UploadVersion.ftp FTP command template for uploading the version to the web
:: When run without parameters, this script pauses at the end and waits for a keypress.
:: To run in an automated scheduler, add any parameter to disable waiting for a keystroke
::
+:: The sript creates a symbol store (a database of PDB files) that can be used as a single entry in MSVC's symbol path,
+:: then any executable / crashdump built by this script can be debugged and its symbols will be found automatically by MSVC,
+:: without the users needing to specify the build version or anything.
+:: In order to support pruning the symstore, a per-month store is created, so that old months can be removed when no longer needed.
+::
:: This script expects a few tools on specific paths, you can pass the correct paths for your system as env vars "zip" and "vc"
:: This script assumes that "git", "symstore" and "touch" are available on PATH.
:: git comes from msysgit
:: symstore comes from Microsoft's Debugging Tools for Windows
:: touch comes from unxtools
-:: This script is locale-dependent
+:: This script is locale-dependent, because it parses the output of "time" and "date" shell commands
:: 7-zip executable (by default it should be on PATH):
@@ -45,9 +48,9 @@ echo Performing nightbuild of MC-Server
set DONOTPAUSE=y
:: Update the sources to the latest revision:
-del src\Bindings.cpp
-del src\Bindings.h
-git checkout -- src\Bindings.*
+del src\Bindings\Bindings.cpp
+del src\Bindings\Bindings.h
+git checkout -- src\Bindings\Bindings.*
git pull
if errorlevel 1 goto haderror
diff --git a/src/BlockArea.cpp b/src/BlockArea.cpp
index c9443c702..a5309f995 100644
--- a/src/BlockArea.cpp
+++ b/src/BlockArea.cpp
@@ -131,7 +131,7 @@ static void MergeCombinatorLake(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBB
case E_BLOCK_STATIONARY_LAVA:
{
a_DstType = a_SrcType;
- a_DstMeta = a_DstMeta;
+ a_DstMeta = a_SrcMeta;
return;
}
}
@@ -820,7 +820,6 @@ void cBlockArea::RelLine(int a_RelX1, int a_RelY1, int a_RelZ1, int a_RelX2, int
int sx = (a_RelX1 < a_RelX2) ? 1 : -1;
int sy = (a_RelY1 < a_RelY2) ? 1 : -1;
int sz = (a_RelZ1 < a_RelZ2) ? 1 : -1;
- int err = dx - dz;
if (dx >= std::max(dy, dz)) // x dominant
{
diff --git a/src/BlockID.cpp b/src/BlockID.cpp
index 2ca9dc49a..05d4c6595 100644
--- a/src/BlockID.cpp
+++ b/src/BlockID.cpp
@@ -662,6 +662,7 @@ public:
g_BlockTransparent[E_BLOCK_CROPS] = true;
g_BlockTransparent[E_BLOCK_DANDELION] = true;
g_BlockTransparent[E_BLOCK_DETECTOR_RAIL] = true;
+ g_BlockTransparent[E_BLOCK_ENDER_CHEST] = true;
g_BlockTransparent[E_BLOCK_FENCE] = true;
g_BlockTransparent[E_BLOCK_FENCE_GATE] = true;
g_BlockTransparent[E_BLOCK_FIRE] = true;
@@ -691,12 +692,14 @@ public:
g_BlockTransparent[E_BLOCK_STAINED_GLASS_PANE] = true;
g_BlockTransparent[E_BLOCK_STATIONARY_LAVA] = true;
g_BlockTransparent[E_BLOCK_STATIONARY_WATER] = true;
+ g_BlockTransparent[E_BLOCK_STONE_BUTTON] = true;
g_BlockTransparent[E_BLOCK_STONE_PRESSURE_PLATE] = true;
g_BlockTransparent[E_BLOCK_TALL_GRASS] = true;
g_BlockTransparent[E_BLOCK_TORCH] = true;
g_BlockTransparent[E_BLOCK_VINES] = true;
g_BlockTransparent[E_BLOCK_WALLSIGN] = true;
g_BlockTransparent[E_BLOCK_WATER] = true;
+ g_BlockTransparent[E_BLOCK_WOODEN_BUTTON] = true;
g_BlockTransparent[E_BLOCK_WOODEN_DOOR] = true;
g_BlockTransparent[E_BLOCK_WOODEN_PRESSURE_PLATE] = true;
diff --git a/src/Chunk.cpp b/src/Chunk.cpp
index 3ae4e36be..3c44b91d0 100644
--- a/src/Chunk.cpp
+++ b/src/Chunk.cpp
@@ -63,26 +63,27 @@ cChunk::cChunk(
int a_ChunkX, int a_ChunkY, int a_ChunkZ,
cChunkMap * a_ChunkMap, cWorld * a_World,
cChunk * a_NeighborXM, cChunk * a_NeighborXP, cChunk * a_NeighborZM, cChunk * a_NeighborZP
-)
- : m_PosX( a_ChunkX )
- , m_PosY( a_ChunkY )
- , m_PosZ( a_ChunkZ )
- , m_BlockTickX( 0 )
- , m_BlockTickY( 0 )
- , m_BlockTickZ( 0 )
- , m_World( a_World )
- , m_ChunkMap(a_ChunkMap)
- , m_IsValid(false)
- , m_IsLightValid(false)
- , m_IsDirty(false)
- , m_IsSaving(false)
- , m_StayCount(0)
- , m_NeighborXM(a_NeighborXM)
- , m_NeighborXP(a_NeighborXP)
- , m_NeighborZM(a_NeighborZM)
- , m_NeighborZP(a_NeighborZP)
- , m_WaterSimulatorData(a_World->GetWaterSimulator()->CreateChunkData())
- , m_LavaSimulatorData (a_World->GetLavaSimulator ()->CreateChunkData())
+) :
+ m_IsValid(false),
+ m_IsLightValid(false),
+ m_IsDirty(false),
+ m_IsSaving(false),
+ m_HasLoadFailed(false),
+ m_StayCount(0),
+ m_PosX(a_ChunkX),
+ m_PosY(a_ChunkY),
+ m_PosZ(a_ChunkZ),
+ m_World(a_World),
+ m_ChunkMap(a_ChunkMap),
+ m_BlockTickX(0),
+ m_BlockTickY(0),
+ m_BlockTickZ(0),
+ m_NeighborXM(a_NeighborXM),
+ m_NeighborXP(a_NeighborXP),
+ m_NeighborZM(a_NeighborZM),
+ m_NeighborZP(a_NeighborZP),
+ m_WaterSimulatorData(a_World->GetWaterSimulator()->CreateChunkData()),
+ m_LavaSimulatorData (a_World->GetLavaSimulator ()->CreateChunkData())
{
if (a_NeighborXM != NULL)
{
diff --git a/src/ChunkSender.cpp b/src/ChunkSender.cpp
index 7d1ef73a0..fe3ee9b42 100644
--- a/src/ChunkSender.cpp
+++ b/src/ChunkSender.cpp
@@ -35,8 +35,8 @@ void cNotifyChunkSender::Call(int a_ChunkX, int a_ChunkZ)
cChunkSender::cChunkSender(void) :
super("ChunkSender"),
m_World(NULL),
- m_Notify(NULL),
- m_RemoveCount(0)
+ m_RemoveCount(0),
+ m_Notify(NULL)
{
m_Notify.SetChunkSender(this);
}
diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index 837f88e61..65b376d38 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -77,27 +77,26 @@ int cClientHandle::s_ClientCount = 0;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cClientHandle:
-cClientHandle::cClientHandle(const cSocket * a_Socket, int a_ViewDistance)
- : m_ViewDistance(a_ViewDistance)
- , m_IPString(a_Socket->GetIPString())
- , m_OutgoingData(64 KiB)
- , m_Player(NULL)
- , m_HasSentDC(false)
- , m_TimeSinceLastPacket(0)
- , m_bKeepThreadGoing(true)
- , m_Ping(1000)
- , m_PingID(1)
- , m_TicksSinceDestruction(0)
- , m_State(csConnected)
- , m_LastStreamedChunkX(0x7fffffff) // bogus chunk coords to force streaming upon login
- , m_LastStreamedChunkZ(0x7fffffff)
- , m_ShouldCheckDownloaded(false)
- , m_UniqueID(0)
- , m_BlockDigAnimStage(-1)
- , m_HasStartedDigging(false)
- , m_CurrentExplosionTick(0)
- , m_RunningSumExplosions(0)
- , m_HasSentPlayerChunk(false)
+cClientHandle::cClientHandle(const cSocket * a_Socket, int a_ViewDistance) :
+ m_ViewDistance(a_ViewDistance),
+ m_IPString(a_Socket->GetIPString()),
+ m_OutgoingData(64 KiB),
+ m_Player(NULL),
+ m_HasSentDC(false),
+ m_LastStreamedChunkX(0x7fffffff), // bogus chunk coords to force streaming upon login
+ m_LastStreamedChunkZ(0x7fffffff),
+ m_TimeSinceLastPacket(0),
+ m_Ping(1000),
+ m_PingID(1),
+ m_BlockDigAnimStage(-1),
+ m_HasStartedDigging(false),
+ m_TicksSinceDestruction(0),
+ m_State(csConnected),
+ m_ShouldCheckDownloaded(false),
+ m_CurrentExplosionTick(0),
+ m_RunningSumExplosions(0),
+ m_UniqueID(0),
+ m_HasSentPlayerChunk(false)
{
m_Protocol = new cProtocolRecognizer(this);
diff --git a/src/ClientHandle.h b/src/ClientHandle.h
index b426153b9..6f82d5d46 100644
--- a/src/ClientHandle.h
+++ b/src/ClientHandle.h
@@ -42,12 +42,6 @@ class cClientHandle : // tolua_export
public cSocketThreads::cCallback
{ // tolua_export
public:
- enum ENUM_PRIORITY
- {
- E_PRIORITY_LOW,
- E_PRIORITY_NORMAL
- };
-
static const int MAXBLOCKCHANGEINTERACTIONS = 20; // 5 didn't help, 10 still doesn't work in Creative, 20 seems to have done the trick
#if defined(ANDROID_NDK)
@@ -219,7 +213,6 @@ private:
AString m_IPString;
- int m_ProtocolVersion;
AString m_Username;
AString m_Password;
@@ -291,8 +284,6 @@ private:
/// m_State needs to be locked in the Destroy() function so that the destruction code doesn't run twice on two different threads
cCriticalSection m_CSDestroyingState;
- bool m_bKeepThreadGoing;
-
/// If set to true during csDownloadingWorld, the tick thread calls CheckIfWorldDownloaded()
bool m_ShouldCheckDownloaded;
diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp
index 32ee7f2bd..8fcdcc82f 100644
--- a/src/Entities/Entity.cpp
+++ b/src/Entities/Entity.cpp
@@ -33,31 +33,31 @@ cEntity::cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, d
, m_Attachee(NULL)
, m_Referencers(new cReferenceManager(cReferenceManager::RFMNGR_REFERENCERS))
, m_References(new cReferenceManager(cReferenceManager::RFMNGR_REFERENCES))
- , m_HeadYaw( 0.0 )
- , m_Rot(0.0, 0.0, 0.0)
- , m_Pos(a_X, a_Y, a_Z)
- , m_Mass (0.001) //Default 1g
, m_bDirtyHead(true)
, m_bDirtyOrientation(true)
, m_bDirtyPosition(true)
, m_bDirtySpeed(true)
, m_bOnGround( false )
, m_Gravity( -9.81f )
- , m_IsInitialized(false)
, m_LastPosX( 0.0 )
, m_LastPosY( 0.0 )
, m_LastPosZ( 0.0 )
, m_TimeLastTeleportPacket(0)
, m_TimeLastMoveReltPacket(0)
, m_TimeLastSpeedPacket(0)
+ , m_IsInitialized(false)
, m_EntityType(a_EntityType)
, m_World(NULL)
, m_TicksSinceLastBurnDamage(0)
, m_TicksSinceLastLavaDamage(0)
, m_TicksSinceLastFireDamage(0)
- , m_TicksSinceLastVoidDamage(0)
, m_TicksLeftBurning(0)
+ , m_TicksSinceLastVoidDamage(0)
+ , m_HeadYaw( 0.0 )
+ , m_Rot(0.0, 0.0, 0.0)
+ , m_Pos(a_X, a_Y, a_Z)
, m_WaterSpeed(0, 0, 0)
+ , m_Mass (0.001) // Default 1g
, m_Width(a_Width)
, m_Height(a_Height)
{
diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h
index 7107a4a13..9cb36eb14 100644
--- a/src/Entities/Entity.h
+++ b/src/Entities/Entity.h
@@ -387,7 +387,7 @@ protected:
double m_LastPosX, m_LastPosY, m_LastPosZ;
// This variables keep track of the last time a packet was sent
- Int64 m_TimeLastTeleportPacket,m_TimeLastMoveReltPacket,m_TimeLastSpeedPacket; // In ticks
+ Int64 m_TimeLastTeleportPacket, m_TimeLastMoveReltPacket, m_TimeLastSpeedPacket; // In ticks
bool m_IsInitialized; // Is set to true when it's initialized, until it's destroyed (Initialize() till Destroy() )
diff --git a/src/Entities/Floater.cpp b/src/Entities/Floater.cpp
index 1aa0413d9..ac7a82f91 100644
--- a/src/Entities/Floater.cpp
+++ b/src/Entities/Floater.cpp
@@ -1,14 +1,19 @@
+
#include "Globals.h"
#include "Floater.h"
#include "Player.h"
#include "../ClientHandle.h"
+
+
+
+
cFloater::cFloater(double a_X, double a_Y, double a_Z, Vector3d a_Speed, int a_PlayerID) :
cEntity(etFloater, a_X, a_Y, a_Z, 0.98, 0.98),
+ m_PickupCountDown(0),
m_PlayerID(a_PlayerID),
- m_CanPickupItem(false),
- m_PickupCountDown(0)
+ m_CanPickupItem(false)
{
SetSpeed(a_Speed);
}
@@ -29,9 +34,9 @@ void cFloater::SpawnOn(cClientHandle & a_Client)
void cFloater::Tick(float a_Dt, cChunk & a_Chunk)
{
HandlePhysics(a_Dt, a_Chunk);
- if (IsBlockWater(m_World->GetBlock((int) GetPosX(), (int) GetPosY(), (int) GetPosZ())))
+ if (IsBlockWater(m_World->GetBlock((int) GetPosX(), (int) GetPosY(), (int) GetPosZ())) && m_World->GetBlockMeta((int) GetPosX(), (int) GetPosY(), (int) GetPosZ()) == 0)
{
- if (m_World->GetTickRandomNumber(100) == 0)
+ if ((!m_CanPickupItem) && (m_World->GetTickRandomNumber(100) == 0))
{
SetPosY(GetPosY() - 1);
m_CanPickupItem = true;
@@ -40,7 +45,7 @@ void cFloater::Tick(float a_Dt, cChunk & a_Chunk)
}
else
{
- SetSpeedY(1);
+ SetSpeedY(0.7);
}
}
SetSpeedX(GetSpeedX() * 0.95);
@@ -55,4 +60,8 @@ void cFloater::Tick(float a_Dt, cChunk & a_Chunk)
}
}
BroadcastMovementUpdate();
-} \ No newline at end of file
+}
+
+
+
+
diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp
index ca0d625e2..8f30cd4cc 100644
--- a/src/Entities/Player.cpp
+++ b/src/Entities/Player.cpp
@@ -36,43 +36,44 @@
cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName)
: super(etPlayer, 0.6, 1.8)
- , m_GameMode(eGameMode_NotSet)
- , m_IP("")
- , m_LastBlockActionTime( 0 )
- , m_LastBlockActionCnt( 0 )
, m_AirLevel( MAX_AIR_LEVEL )
- , m_AirTickTimer( DROWNING_TICKS )
- , m_bVisible( true )
- , m_LastGroundHeight( 0 )
- , m_bTouchGround( false )
- , m_Stance( 0.0 )
- , m_Inventory(*this)
- , m_CurrentWindow(NULL)
- , m_InventoryWindow(NULL)
- , m_TimeLastPickupCheck( 0.f )
- , m_Color('-')
- , m_ClientHandle( a_Client )
+ , m_AirTickTimer(DROWNING_TICKS)
+ , m_bVisible(true)
, m_FoodLevel(MAX_FOOD_LEVEL)
, m_FoodSaturationLevel(5)
, m_FoodTickTimer(0)
, m_FoodExhaustionLevel(0)
, m_FoodPoisonedTicksRemaining(0)
+ , m_LastJumpHeight(0)
+ , m_LastGroundHeight(0)
+ , m_bTouchGround(false)
+ , m_Stance(0.0)
+ , m_Inventory(*this)
+ , m_CurrentWindow(NULL)
+ , m_InventoryWindow(NULL)
+ , m_TimeLastPickupCheck(0.f)
+ , m_Color('-')
+ , m_LastBlockActionTime(0)
+ , m_LastBlockActionCnt(0)
+ , m_GameMode(eGameMode_NotSet)
+ , m_IP("")
+ , m_ClientHandle(a_Client)
, m_NormalMaxSpeed(0.1)
, m_SprintingMaxSpeed(0.13)
, m_IsCrouched(false)
, m_IsSprinting(false)
+ , m_IsFlying(false)
, m_IsSwimming(false)
, m_IsSubmerged(false)
- , m_IsFlying(false)
- , m_CanFly(false)
, m_IsFishing(false)
- , m_FloaterID(-1)
+ , m_CanFly(false)
, m_EatingFinishTick(-1)
- , m_IsChargingBow(false)
- , m_BowCharge(0)
- , m_CurrentXp(0)
, m_LifetimeTotalXp(0)
+ , m_CurrentXp(0)
, m_bDirtyExperience(false)
+ , m_IsChargingBow(false)
+ , m_BowCharge(0)
+ , m_FloaterID(-1)
{
LOGD("Created a player object for \"%s\" @ \"%s\" at %p, ID %d",
a_PlayerName.c_str(), a_Client->GetIPString().c_str(),
diff --git a/src/Entities/Player.h b/src/Entities/Player.h
index 74da857e8..c0ad9eeac 100644
--- a/src/Entities/Player.h
+++ b/src/Entities/Player.h
@@ -407,9 +407,6 @@ protected:
float m_TimeLastPickupCheck;
- void ResolvePermissions();
-
- void ResolveGroups();
char m_Color;
float m_LastBlockActionTime;
@@ -417,6 +414,7 @@ protected:
eGameMode m_GameMode;
std::string m_IP;
+ /// The item being dragged by the cursor while in a UI window
cItem m_DraggingItem;
long long m_LastPlayerListTime;
@@ -456,6 +454,11 @@ protected:
int m_FloaterID;
+
+
+ void ResolvePermissions(void);
+ void ResolveGroups(void);
+
virtual void Destroyed(void);
/// Filters out damage for creative mode
diff --git a/src/Entities/ProjectileEntity.cpp b/src/Entities/ProjectileEntity.cpp
index 1d49c2445..9e5069ba6 100644
--- a/src/Entities/ProjectileEntity.cpp
+++ b/src/Entities/ProjectileEntity.cpp
@@ -396,9 +396,9 @@ cArrowEntity::cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a
m_DamageCoeff(2),
m_IsCritical(false),
m_Timer(0),
+ m_HitGroundTimer(0),
m_bIsCollected(false),
- m_HitBlockPos(Vector3i(0, 0, 0)),
- m_HitGroundTimer(0)
+ m_HitBlockPos(Vector3i(0, 0, 0))
{
SetSpeed(a_Speed);
SetMass(0.1);
@@ -420,9 +420,9 @@ cArrowEntity::cArrowEntity(cPlayer & a_Player, double a_Force) :
m_DamageCoeff(2),
m_IsCritical((a_Force >= 1)),
m_Timer(0),
+ m_HitGroundTimer(0),
m_bIsCollected(false),
- m_HitBlockPos(0, 0, 0),
- m_HitGroundTimer(0)
+ m_HitBlockPos(0, 0, 0)
{
}
diff --git a/src/Items/ItemFishingRod.h b/src/Items/ItemFishingRod.h
index 91c0e9638..87021fbd2 100644
--- a/src/Items/ItemFishingRod.h
+++ b/src/Items/ItemFishingRod.h
@@ -29,6 +29,11 @@ public:
virtual bool OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Dir) override
{
+ if (a_Dir != BLOCK_FACE_NONE)
+ {
+ return false;
+ }
+
if (a_Player->IsFishing())
{
class cFloaterCallback :
@@ -63,13 +68,13 @@ public:
Drops.Add(cItem(E_ITEM_RAW_FISH));
Vector3d FloaterPos(Callbacks.GetPos());
Vector3d FlyDirection(a_Player->GetPosition() - FloaterPos);
- a_World->SpawnItemPickups(Drops, FloaterPos.x, FloaterPos.y, FloaterPos.z, FlyDirection.x, FlyDirection.y, FlyDirection.z);
+ a_World->SpawnItemPickups(Drops, FloaterPos.x, FloaterPos.y, FloaterPos.z, FlyDirection.x, FlyDirection.Length() / (FlyDirection.y * 2), FlyDirection.z);
// TODO: More types of pickups.
}
}
else
{
- cFloater * Floater = new cFloater(a_Player->GetPosX(), a_Player->GetStance(), a_Player->GetPosZ(), a_Player->GetLookVector() * 7, a_Player->GetUniqueID());
+ cFloater * Floater = new cFloater(a_Player->GetPosX(), a_Player->GetStance(), a_Player->GetPosZ(), a_Player->GetLookVector() * 15, a_Player->GetUniqueID());
Floater->Initialize(a_World);
a_Player->SetIsFishing(true, Floater->GetUniqueID());
}
diff --git a/src/MobCensus.cpp b/src/MobCensus.cpp
index 66b5932bc..9c32bf695 100644
--- a/src/MobCensus.cpp
+++ b/src/MobCensus.cpp
@@ -19,7 +19,6 @@ void cMobCensus::CollectMob(cMonster & a_Monster, cChunk & a_Chunk, double a_Dis
bool cMobCensus::IsCapped(cMonster::eFamily a_MobFamily)
{
- bool toReturn = true;
const int ratio = 319; // this should be 256 as we are only supposed to take account from chunks that are in 17x17 from a player
// but for now, we use all chunks loaded by players. that means 19 x 19 chunks. That's why we use 256 * (19*19) / (17*17) = 319
// MG TODO : code the correct count
@@ -42,9 +41,12 @@ int cMobCensus::GetCapMultiplier(cMonster::eFamily a_MobFamily)
case cMonster::mfPassive: return 11;
case cMonster::mfAmbient: return 16;
case cMonster::mfWater: return 5;
+ default:
+ {
+ ASSERT(!"Unhandled mob family");
+ return -1;
+ }
}
- ASSERT(!"Unhandled mob family");
- return -1;
}
diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp
index 606e93408..e5d21b2f2 100644
--- a/src/Mobs/Monster.cpp
+++ b/src/Mobs/Monster.cpp
@@ -68,9 +68,12 @@ static const struct
cMonster::cMonster(const AString & a_ConfigName, eType a_MobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height)
: super(etMonster, a_Width, a_Height)
+ , m_EMState(IDLE)
+ , m_EMPersonality(AGGRESSIVE)
+ , m_SightDistance(25)
, m_Target(NULL)
, m_AttackRate(3)
- , idle_interval(0)
+ , m_IdleInterval(0)
, m_bMovingToDestination(false)
, m_DestinationTime( 0 )
, m_DestroyTimer( 0 )
@@ -78,10 +81,7 @@ cMonster::cMonster(const AString & a_ConfigName, eType a_MobType, const AString
, m_MobType(a_MobType)
, m_SoundHurt(a_SoundHurt)
, m_SoundDeath(a_SoundDeath)
- , m_EMState(IDLE)
- , m_SightDistance(25)
, m_SeePlayerInterval (0)
- , m_EMPersonality(AGGRESSIVE)
, m_AttackDamage(1.0f)
, m_AttackRange(2.0f)
, m_AttackInterval(0)
@@ -435,13 +435,13 @@ void cMonster::EventLosePlayer(void)
// What to do if in Idle State
void cMonster::InStateIdle(float a_Dt)
{
- idle_interval += a_Dt;
- if (idle_interval > 1)
+ m_IdleInterval += a_Dt;
+ if (m_IdleInterval > 1)
{
// at this interval the results are predictable
int rem = m_World->GetTickRandomNumber(6) + 1;
// LOGD("Moving: int: %3.3f rem: %i",idle_interval,rem);
- idle_interval -= 1; // So nothing gets dropped when the server hangs for a few seconds
+ m_IdleInterval -= 1; // So nothing gets dropped when the server hangs for a few seconds
Vector3f Dist;
Dist.x = (float)(m_World->GetTickRandomNumber(10) - 5);
Dist.z = (float)(m_World->GetTickRandomNumber(10) - 5);
diff --git a/src/Mobs/Monster.h b/src/Mobs/Monster.h
index 29a705d11..dafb33574 100644
--- a/src/Mobs/Monster.h
+++ b/src/Mobs/Monster.h
@@ -161,7 +161,7 @@ protected:
cEntity * m_Target;
float m_AttackRate;
- float idle_interval;
+ float m_IdleInterval;
Vector3f m_Destination;
bool m_bMovingToDestination;
diff --git a/src/Mobs/Wolf.cpp b/src/Mobs/Wolf.cpp
index c86250142..3d4e97c80 100644
--- a/src/Mobs/Wolf.cpp
+++ b/src/Mobs/Wolf.cpp
@@ -11,10 +11,10 @@
cWolf::cWolf(void) :
super("Wolf", mtWolf, "mob.wolf.hurt", "mob.wolf.death", 0.6, 0.8),
- m_IsAngry(false),
- m_IsTame(false),
m_IsSitting(false),
+ m_IsTame(false),
m_IsBegging(false),
+ m_IsAngry(false),
m_OwnerName(""),
m_CollarColor(14)
{
diff --git a/src/Mobs/Zombie.cpp b/src/Mobs/Zombie.cpp
index a485d2b55..a046fcc92 100644
--- a/src/Mobs/Zombie.cpp
+++ b/src/Mobs/Zombie.cpp
@@ -8,10 +8,11 @@
-cZombie::cZombie(bool IsVillagerZombie) :
+
+cZombie::cZombie(bool a_IsVillagerZombie) :
super("Zombie", mtZombie, "mob.zombie.hurt", "mob.zombie.death", 0.6, 1.8),
- m_bIsConverting(false),
- m_bIsVillagerZombie(IsVillagerZombie)
+ m_IsVillagerZombie(a_IsVillagerZombie),
+ m_IsConverting(false)
{
SetBurnsInDaylight(true);
}
@@ -45,3 +46,5 @@ void cZombie::MoveToPosition(const Vector3f & a_Position)
}
+
+
diff --git a/src/Mobs/Zombie.h b/src/Mobs/Zombie.h
index 7e14fe42f..1ba368f9c 100644
--- a/src/Mobs/Zombie.h
+++ b/src/Mobs/Zombie.h
@@ -12,19 +12,20 @@ class cZombie :
typedef cAggressiveMonster super;
public:
- cZombie(bool IsVillagerZombie);
+ cZombie(bool a_IsVillagerZombie);
CLASS_PROTODEF(cZombie);
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
virtual void MoveToPosition(const Vector3f & a_Position) override;
- bool IsVillagerZombie(void) const {return m_bIsVillagerZombie; }
- bool IsConverting(void) const {return m_bIsConverting; }
+ bool IsVillagerZombie(void) const {return m_IsVillagerZombie; }
+ bool IsConverting (void) const {return m_IsConverting; }
private:
- bool m_bIsVillagerZombie, m_bIsConverting;
+ bool m_IsVillagerZombie;
+ bool m_IsConverting;
} ;
diff --git a/src/OSSupport/IsThread.cpp b/src/OSSupport/IsThread.cpp
index 7eb114a82..36205bcf1 100644
--- a/src/OSSupport/IsThread.cpp
+++ b/src/OSSupport/IsThread.cpp
@@ -51,8 +51,8 @@ static void SetThreadName( DWORD dwThreadID, LPCSTR szThreadName)
// cIsThread:
cIsThread::cIsThread(const AString & iThreadName) :
- m_ThreadName(iThreadName),
m_ShouldTerminate(false),
+ m_ThreadName(iThreadName),
m_Handle(NULL_HANDLE)
{
}
@@ -144,7 +144,7 @@ bool cIsThread::Wait(void)
return (res == WAIT_OBJECT_0);
#else // _WIN32
int res = pthread_join(m_Handle, NULL);
- m_Handle = NULL;
+ m_Handle = NULL_HANDLE;
#ifdef LOGD // ProtoProxy doesn't have LOGD
LOGD("Thread %s finished", m_ThreadName.c_str());
diff --git a/src/Protocol/Protocol132.cpp b/src/Protocol/Protocol132.cpp
index d8f450588..346607b79 100644
--- a/src/Protocol/Protocol132.cpp
+++ b/src/Protocol/Protocol132.cpp
@@ -188,7 +188,7 @@ void cProtocol132::DataReceived(const char * a_Data, int a_Size)
byte Decrypted[512];
while (a_Size > 0)
{
- int NumBytes = (a_Size > sizeof(Decrypted)) ? sizeof(Decrypted) : a_Size;
+ int NumBytes = (a_Size > (int)sizeof(Decrypted)) ? (int)sizeof(Decrypted) : a_Size;
m_Decryptor.ProcessData(Decrypted, (byte *)a_Data, NumBytes);
super::DataReceived((const char *)Decrypted, NumBytes);
a_Size -= NumBytes;
@@ -705,7 +705,7 @@ void cProtocol132::Flush(void)
byte Encrypted[8192]; // Larger buffer, we may be sending lots of data (chunks)
while (a_Size > 0)
{
- int NumBytes = (a_Size > sizeof(Encrypted)) ? sizeof(Encrypted) : a_Size;
+ int NumBytes = (a_Size > (int)sizeof(Encrypted)) ? (int)sizeof(Encrypted) : a_Size;
m_Encryptor.ProcessData(Encrypted, (byte *)a_Data, NumBytes);
super::SendData((const char *)Encrypted, NumBytes);
a_Size -= NumBytes;
diff --git a/src/Root.cpp b/src/Root.cpp
index fb1e96426..fffd8fb47 100644
--- a/src/Root.cpp
+++ b/src/Root.cpp
@@ -39,19 +39,20 @@ cRoot* cRoot::s_Root = NULL;
-cRoot::cRoot()
- : m_Server( NULL )
- , m_MonsterConfig( NULL )
- , m_GroupManager( NULL )
- , m_CraftingRecipes(NULL)
- , m_FurnaceRecipe( NULL )
- , m_WebAdmin( NULL )
- , m_PluginManager( NULL )
- , m_Log( NULL )
- , m_bStop( false )
- , m_bRestart( false )
- , m_InputThread( NULL )
- , m_pDefaultWorld( NULL )
+cRoot::cRoot(void) :
+ m_PrimaryServerVersion(cProtocolRecognizer::PROTO_VERSION_LATEST),
+ m_pDefaultWorld(NULL),
+ m_InputThread(NULL),
+ m_Server(NULL),
+ m_MonsterConfig(NULL),
+ m_GroupManager(NULL),
+ m_CraftingRecipes(NULL),
+ m_FurnaceRecipe(NULL),
+ m_WebAdmin(NULL),
+ m_PluginManager(NULL),
+ m_Log(NULL),
+ m_bStop(false),
+ m_bRestart(false)
{
s_Root = this;
}
@@ -552,22 +553,25 @@ bool cRoot::FindAndDoWithPlayer(const AString & a_PlayerName, cPlayerListCallbac
{
class cCallback : public cPlayerListCallback
{
- unsigned int BestRating;
- unsigned int NameLength;
- const AString PlayerName;
+ unsigned m_BestRating;
+ unsigned m_NameLength;
+ const AString m_PlayerName;
cPlayerListCallback & m_Callback;
virtual bool Item (cPlayer * a_pPlayer)
{
- unsigned int Rating = RateCompareString (PlayerName, a_pPlayer->GetName());
- if (Rating > 0 && Rating >= BestRating)
+ unsigned int Rating = RateCompareString (m_PlayerName, a_pPlayer->GetName());
+ if ((Rating > 0) && (Rating >= m_BestRating))
{
- BestMatch = a_pPlayer;
- if( Rating > BestRating ) NumMatches = 0;
- BestRating = Rating;
- ++NumMatches;
+ m_BestMatch = a_pPlayer;
+ if (Rating > m_BestRating)
+ {
+ m_NumMatches = 0;
+ }
+ m_BestRating = Rating;
+ ++m_NumMatches;
}
- if (Rating == NameLength) // Perfect match
+ if (Rating == m_NameLength) // Perfect match
{
return true;
}
@@ -575,23 +579,23 @@ bool cRoot::FindAndDoWithPlayer(const AString & a_PlayerName, cPlayerListCallbac
}
public:
- cCallback (const AString & a_PlayerName, cPlayerListCallback & a_Callback)
- : m_Callback( a_Callback )
- , BestMatch( NULL )
- , BestRating( 0 )
- , NumMatches( 0 )
- , NameLength( a_PlayerName.length() )
- , PlayerName( a_PlayerName )
+ cCallback (const AString & a_PlayerName, cPlayerListCallback & a_Callback) :
+ m_Callback(a_Callback),
+ m_BestRating(0),
+ m_NameLength(a_PlayerName.length()),
+ m_PlayerName(a_PlayerName),
+ m_BestMatch(NULL),
+ m_NumMatches(0)
{}
- cPlayer * BestMatch;
- unsigned int NumMatches;
+ cPlayer * m_BestMatch;
+ unsigned m_NumMatches;
} Callback (a_PlayerName, a_Callback);
ForEachPlayer( Callback );
- if (Callback.NumMatches == 1)
+ if (Callback.m_NumMatches == 1)
{
- return a_Callback.Item (Callback.BestMatch);
+ return a_Callback.Item(Callback.m_BestMatch);
}
return false;
}
diff --git a/src/Simulator/RedstoneSimulator.cpp b/src/Simulator/RedstoneSimulator.cpp
index 92aeda29a..e53c7c172 100644
--- a/src/Simulator/RedstoneSimulator.cpp
+++ b/src/Simulator/RedstoneSimulator.cpp
@@ -228,12 +228,13 @@ void cRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, c
int a_Z = BaseZ + dataitr->z;
switch (BlockType)
{
- case E_BLOCK_BLOCK_OF_REDSTONE: HandleRedstoneBlock(a_X, dataitr->y, a_Z); break;
- case E_BLOCK_LEVER: HandleRedstoneLever(a_X, dataitr->y, a_Z); break;
- case E_BLOCK_TNT: HandleTNT(a_X, dataitr->y, a_Z); break;
+ case E_BLOCK_BLOCK_OF_REDSTONE: HandleRedstoneBlock(a_X, dataitr->y, a_Z); break;
+ case E_BLOCK_LEVER: HandleRedstoneLever(a_X, dataitr->y, a_Z); break;
+ case E_BLOCK_TNT: HandleTNT(a_X, dataitr->y, a_Z); break;
case E_BLOCK_TRAPDOOR: HandleTrapdoor(a_X, dataitr->y, a_Z); break;
- case E_BLOCK_REDSTONE_WIRE: HandleRedstoneWire(a_X, dataitr->y, a_Z); break;
+ case E_BLOCK_REDSTONE_WIRE: HandleRedstoneWire(a_X, dataitr->y, a_Z); break;
case E_BLOCK_NOTE_BLOCK: HandleNoteBlock(a_X, dataitr->y, a_Z); break;
+ case E_BLOCK_DAYLIGHT_SENSOR: HandleDaylightSensor(a_X, dataitr->y, a_Z); break;
case E_BLOCK_REDSTONE_TORCH_OFF:
case E_BLOCK_REDSTONE_TORCH_ON:
@@ -611,7 +612,10 @@ void cRedstoneSimulator::HandleRedstoneRepeater(int a_BlockX, int a_BlockY, int
{
if (itr->ShouldPowerOn)
{
- m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_REPEATER_ON, a_Meta);
+ if (!IsOn)
+ {
+ m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_REPEATER_ON, a_Meta); // For performance
+ }
switch (a_Meta & 0x3) // We only want the direction (bottom) bits
{
@@ -647,7 +651,10 @@ void cRedstoneSimulator::HandleRedstoneRepeater(int a_BlockX, int a_BlockY, int
}
else
{
- m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_REPEATER_OFF, a_Meta);
+ if (IsOn)
+ {
+ m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_REPEATER_OFF, a_Meta);
+ }
m_RepeatersDelayList.erase(itr); // We can remove off repeaters which don't need further updating
return;
}
@@ -814,6 +821,7 @@ void cRedstoneSimulator::HandleRail(int a_BlockX, int a_BlockY, int a_BlockZ, BL
}
break;
}
+ default: LOGD("Unhandled type of rail in %s", __FUNCTION__);
}
}
@@ -887,6 +895,18 @@ void cRedstoneSimulator::HandleNoteBlock(int a_BlockX, int a_BlockY, int a_Block
+void cRedstoneSimulator::HandleDaylightSensor(int a_BlockX, int a_BlockY, int a_BlockZ)
+{
+ if (m_World.GetBlockSkyLight(a_BlockX, a_BlockY + 1, a_BlockZ) > 10)
+ {
+ SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_DAYLIGHT_SENSOR);
+ }
+}
+
+
+
+
+
bool cRedstoneSimulator::AreCoordsDirectlyPowered(int a_BlockX, int a_BlockY, int a_BlockZ)
{
for (PoweredBlocksList::const_iterator itr = m_PoweredBlocks.begin(); itr != m_PoweredBlocks.end(); ++itr) // Check powered list
@@ -1298,7 +1318,7 @@ void cRedstoneSimulator::QueueRepeaterPowerChange(int a_BlockX, int a_BlockY, in
}
// Already in here (normal to allow repeater to continue on powering and updating blocks in front) - just update info and quit
- itr->a_DelayTicks = ((a_Meta & 0xC) >> 0x2) + 1;
+ itr->a_DelayTicks = (((a_Meta & 0xC) >> 0x2) + 1) * 2; // See below for description
itr->a_ElapsedTicks = 0;
itr->ShouldPowerOn = ShouldPowerOn;
return;
@@ -1308,7 +1328,12 @@ void cRedstoneSimulator::QueueRepeaterPowerChange(int a_BlockX, int a_BlockY, in
// Self not in list, add self to list
sRepeatersDelayList RC;
RC.a_BlockPos = Vector3i(a_BlockX, a_BlockY, a_BlockZ);
- RC.a_DelayTicks = ((a_Meta & 0xC) >> 0x2) + 1; // Gets the top two bits (delay time), shifts them into the lower two bits, and adds one (meta 0 = 1 tick; 1 = 2 etc.)
+
+ // Gets the top two bits (delay time), shifts them into the lower two bits, and adds one (meta 0 = 1 tick; 1 = 2 etc.)
+ // * 2 because apparently, MCS ticks are way faster than vanilla ticks, so repeater aren't noticeably delayed
+ RC.a_DelayTicks = (((a_Meta & 0xC) >> 0x2) + 1) * 2;
+
+
RC.a_ElapsedTicks = 0;
RC.ShouldPowerOn = ShouldPowerOn;
m_RepeatersDelayList.push_back(RC);
diff --git a/src/Simulator/RedstoneSimulator.h b/src/Simulator/RedstoneSimulator.h
index d40d88342..309135497 100644
--- a/src/Simulator/RedstoneSimulator.h
+++ b/src/Simulator/RedstoneSimulator.h
@@ -115,6 +115,8 @@ private:
void HandleTrapdoor(int a_BlockX, int a_BlockY, int a_BlockZ);
/// <summary>Handles noteblocks</summary>
void HandleNoteBlock(int a_BlockX, int a_BlockY, int a_BlockZ);
+ /// <summary>Handles noteblocks</summary>
+ void HandleDaylightSensor(int a_BlockX, int a_BlockY, int a_BlockZ);
/* ===================== */
/* ====== Helper functions ====== */
@@ -164,13 +166,11 @@ private:
case E_BLOCK_STICKY_PISTON:
case E_BLOCK_REDSTONE_REPEATER_ON:
case E_BLOCK_REDSTONE_REPEATER_OFF:
+ case E_BLOCK_DAYLIGHT_SENSOR:
{
return false;
}
- default:
- {
- return true;
- }
+ default: return true;
}
}
@@ -208,6 +208,7 @@ private:
{
switch (Block)
{
+ case E_BLOCK_DAYLIGHT_SENSOR:
case E_BLOCK_WOODEN_BUTTON:
case E_BLOCK_STONE_BUTTON:
case E_BLOCK_REDSTONE_WIRE:
diff --git a/src/World.cpp b/src/World.cpp
index f81456334..976af671d 100644
--- a/src/World.cpp
+++ b/src/World.cpp
@@ -229,16 +229,16 @@ cWorld::cWorld(const AString & a_WorldName) :
m_WorldName(a_WorldName),
m_IniFileName(m_WorldName + "/world.ini"),
m_StorageSchema("Default"),
+ m_IsSpawnExplicitlySet(false),
m_WorldAgeSecs(0),
m_TimeOfDaySecs(0),
m_WorldAge(0),
m_TimeOfDay(0),
m_LastTimeUpdate(0),
+ m_SkyDarkness(0),
m_Weather(eWeather_Sunny),
m_WeatherInterval(24000), // Guaranteed 1 day of sunshine at server start :)
- m_TickThread(*this),
- m_SkyDarkness(0),
- m_bSpawnExplicitlySet(false)
+ m_TickThread(*this)
{
LOGD("cWorld::cWorld(\"%s\")", a_WorldName.c_str());
@@ -329,7 +329,7 @@ void cWorld::SetNextBlockTick(int a_BlockX, int a_BlockY, int a_BlockZ)
void cWorld::InitializeSpawn(void)
{
- if (!m_bSpawnExplicitlySet) // Check if spawn position was already explicitly set or not
+ if (!m_IsSpawnExplicitlySet) // Check if spawn position was already explicitly set or not
{
GenerateRandomSpawn(); // Generate random solid-land coordinate and then write it to the world configuration
@@ -487,7 +487,7 @@ void cWorld::Start(void)
// Try to find the "SpawnPosition" key and coord values in the world configuration, set the flag if found
int KeyNum = IniFile.FindKey("SpawnPosition");
- m_bSpawnExplicitlySet =
+ m_IsSpawnExplicitlySet =
(
(KeyNum >= 0) &&
(
@@ -497,7 +497,7 @@ void cWorld::Start(void)
)
);
- if (m_bSpawnExplicitlySet)
+ if (m_IsSpawnExplicitlySet)
{
LOGD("Spawnpoint explicitly set!");
m_SpawnX = IniFile.GetValueF("SpawnPosition", "X", m_SpawnX);
diff --git a/src/World.h b/src/World.h
index 2d9e8b551..1effc5d5d 100644
--- a/src/World.h
+++ b/src/World.h
@@ -647,7 +647,7 @@ private:
/// This random generator is to be used only in the Tick() method, and thus only in the World-Tick-thread (MTRand is not exactly thread-safe)
MTRand m_TickRand;
- bool m_bSpawnExplicitlySet;
+ bool m_IsSpawnExplicitlySet;
double m_SpawnX;
double m_SpawnY;
double m_SpawnZ;