1
0

Merge pull request #538 from mc-server/minecarts

Minecarts
This commit is contained in:
Mattes D 2014-01-15 02:42:24 -08:00
commit 457e93f1ed
13 changed files with 631 additions and 336 deletions

@ -1 +1 @@
Subproject commit c65b56767a5e59ca387a05be72ef18791baa9aed
Subproject commit 944b0e95303a17200e52699c3bc7c349424be581

View File

@ -2,15 +2,15 @@
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{3c30caed-20a3-4bd8-b12e-fdd1e13455e5}</UniqueIdentifier>
<UniqueIdentifier>{59bfc075-705c-42cd-adf7-40cef1aed8e1}</UniqueIdentifier>
<Extensions>.cpp</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{770573d2-b90d-43f4-ac1c-464ab10c46ec}</UniqueIdentifier>
<UniqueIdentifier>{407d7f02-df9e-485b-a95f-2f1dad08cbed}</UniqueIdentifier>
<Extensions>.;.h</Extensions>
</Filter>
<Filter Include="Miscellaneous">
<UniqueIdentifier>{1ac058bb-f217-4ac3-a14b-9c6ba021e030}</UniqueIdentifier>
<UniqueIdentifier>{293a01a6-81d1-4272-a7ff-310526bbc77f}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>

View File

@ -226,6 +226,7 @@
<ItemGroup>
<ClInclude Include="..\src\Resources\resource_MCServer.h" />
<ClInclude Include="..\src\Authenticator.h" />
<ClInclude Include="..\src\BiomeDef.h" />
<ClInclude Include="..\src\BlockArea.h" />
<ClInclude Include="..\src\BlockID.h" />
<ClInclude Include="..\src\BlockTracer.h" />
@ -234,8 +235,6 @@
<ClInclude Include="..\src\ChatColor.h" />
<ClInclude Include="..\src\Chunk.h" />
<ClInclude Include="..\src\ChunkDef.h" />
<ClInclude Include="..\src\BiomeDef.h" />
<ClInclude Include="..\src\BiomeDef.cpp" />
<ClInclude Include="..\src\ChunkMap.h" />
<ClInclude Include="..\src\ChunkSender.h" />
<ClInclude Include="..\src\ClientHandle.h" />
@ -374,7 +373,6 @@
<ClInclude Include="..\src\Bindings\Plugin.h" />
<ClInclude Include="..\src\Bindings\PluginLua.h" />
<ClInclude Include="..\src\Bindings\PluginManager.h" />
<ClInclude Include="..\src\Bindings\tolua_base.h" />
<ClInclude Include="..\src\Bindings\WebPlugin.h" />
<ClInclude Include="..\lib\inifile\iniFile.h" />
<ClInclude Include="..\lib\md5\md5.h" />
@ -618,6 +616,7 @@
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\src\Authenticator.cpp" />
<ClCompile Include="..\src\BiomeDef.cpp" />
<ClCompile Include="..\src\BlockArea.cpp" />
<ClCompile Include="..\src\BlockID.cpp" />
<ClCompile Include="..\src\BoundingBox.cpp" />

View File

@ -10,73 +10,73 @@
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Source Files\Mobs">
<UniqueIdentifier>{813698c3-b2c1-4f3d-a89c-7ac6239fff97}</UniqueIdentifier>
<UniqueIdentifier>{46ffa881-c36b-41b0-85df-90e0f78c6285}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\Entities">
<UniqueIdentifier>{b120a538-d8b9-4576-8675-36cf01fd69fc}</UniqueIdentifier>
<UniqueIdentifier>{5eb3c155-b618-4232-92a5-52b3ae70ec96}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\UI">
<UniqueIdentifier>{85037cf1-81a5-47c7-8c2e-899ea706b8e7}</UniqueIdentifier>
<UniqueIdentifier>{5f745788-b9aa-4dde-9763-cdfaddb3dfdf}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\Simulator">
<UniqueIdentifier>{46c9cb22-7c7f-4589-b9b2-1fc79d2bdbdf}</UniqueIdentifier>
<UniqueIdentifier>{acb44271-df18-41b2-8a50-656a49c39d3c}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\OSSupport">
<UniqueIdentifier>{f12178cb-2ecb-4e48-9a8d-ba3e2e73cfbc}</UniqueIdentifier>
<UniqueIdentifier>{1091cb9f-3d9d-4ed5-9359-fc762be21759}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\OSSupport\Android Specific">
<UniqueIdentifier>{488bc224-735f-405c-83de-870373cb52cb}</UniqueIdentifier>
<UniqueIdentifier>{c40bec86-f173-440a-b07e-bab15c8ce965}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\Bindings">
<UniqueIdentifier>{41c0d7c9-43b5-4d17-b50e-3c8ac3aa2905}</UniqueIdentifier>
<UniqueIdentifier>{4180990c-1257-4d07-9009-08535fedfbf8}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\External">
<UniqueIdentifier>{2c71a15a-8c65-4be7-bdfb-e083f4841c4a}</UniqueIdentifier>
<UniqueIdentifier>{ffc2297f-c790-4190-a56f-ac6a1f97a30c}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\WorldStorage">
<UniqueIdentifier>{2227f719-f0ac-444e-af14-230853017c45}</UniqueIdentifier>
<UniqueIdentifier>{011ff757-845a-4342-862e-44207ec46a94}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\Generating">
<UniqueIdentifier>{eb070b55-ba10-4bce-ba06-5d785a055e54}</UniqueIdentifier>
<UniqueIdentifier>{7f7a0b8c-4ee6-4a3a-92d6-5ba242a565f3}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\Blocks">
<UniqueIdentifier>{779dac55-c718-4fe1-8b67-547d431b9ebc}</UniqueIdentifier>
<UniqueIdentifier>{07157169-9da7-4998-9f00-4580641cf811}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\Items">
<UniqueIdentifier>{89847a5d-608a-4137-a766-1557276b4fcf}</UniqueIdentifier>
<UniqueIdentifier>{5b92b198-0a58-4399-9c8e-662bd5062b6c}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\Protocol">
<UniqueIdentifier>{e159d08d-daec-46de-9b60-9f8e660da91d}</UniqueIdentifier>
<UniqueIdentifier>{16a88457-3862-4ff0-a591-a7160ea956f5}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\SQLite">
<UniqueIdentifier>{0278092b-abe5-4276-81cf-59e4079e5bc7}</UniqueIdentifier>
<UniqueIdentifier>{a3561ecf-a501-4c76-b176-1f214b7a5523}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\LuaExpat">
<UniqueIdentifier>{e4879cf2-e769-4e1d-8905-0f6c40ee5bc1}</UniqueIdentifier>
<UniqueIdentifier>{a35eb320-d10b-4592-92ed-2d2f242dbed7}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\BlockEntities">
<UniqueIdentifier>{d641a9d4-f5dc-4808-bee6-194306505244}</UniqueIdentifier>
<UniqueIdentifier>{1c271d11-30ce-4aef-b8a9-7c8ee560d5d6}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\HTTPServer">
<UniqueIdentifier>{a1e39415-2aca-4779-a558-2567a9de304f}</UniqueIdentifier>
<UniqueIdentifier>{223bdf26-d107-498f-8c42-00c19ef80348}</UniqueIdentifier>
</Filter>
<Filter Include="Config files">
<UniqueIdentifier>{eb5f3060-03ed-4548-8bde-340454d3d23a}</UniqueIdentifier>
<UniqueIdentifier>{99140e5f-0287-4601-ad28-bad2533d8876}</UniqueIdentifier>
</Filter>
<Filter Include="Plugins">
<UniqueIdentifier>{7c681450-041a-4846-acf6-951c1f4e32a4}</UniqueIdentifier>
<UniqueIdentifier>{beb25b3b-31f3-468e-a721-6d0dc297e4b5}</UniqueIdentifier>
</Filter>
<Filter Include="Plugins\Core">
<UniqueIdentifier>{e961964c-9fb7-4513-89fa-05e0b760e0f1}</UniqueIdentifier>
<UniqueIdentifier>{f848f39d-680d-4f9c-8dcb-da9a0bb871f5}</UniqueIdentifier>
</Filter>
<Filter Include="Plugins\ChatLog">
<UniqueIdentifier>{70696c83-2307-43c6-8851-81aa3baa8523}</UniqueIdentifier>
<UniqueIdentifier>{7c735e41-f3b2-4500-856b-54845f834eb2}</UniqueIdentifier>
</Filter>
<Filter Include="Plugins\Debuggers">
<UniqueIdentifier>{d3b692db-0684-4b89-9d38-2e5af12e9a6e}</UniqueIdentifier>
<UniqueIdentifier>{83d5aac9-2975-4334-9acc-b48e96a16b23}</UniqueIdentifier>
</Filter>
<Filter Include="Plugins\APIDump">
<UniqueIdentifier>{6eee304c-f055-4758-a248-a125e1af7e73}</UniqueIdentifier>
<UniqueIdentifier>{e5167107-9cc8-4e03-b519-c3a13b9b7955}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
@ -96,6 +96,9 @@
<ClInclude Include="..\src\Authenticator.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="..\src\BiomeDef.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="..\src\BlockArea.h">
<Filter>Source Files</Filter>
</ClInclude>
@ -513,9 +516,6 @@
<ClInclude Include="..\src\Bindings\PluginManager.h">
<Filter>Source Files\Bindings</Filter>
</ClInclude>
<ClInclude Include="..\src\Bindings\tolua_base.h">
<Filter>Source Files\Bindings</Filter>
</ClInclude>
<ClInclude Include="..\src\Bindings\WebPlugin.h">
<Filter>Source Files\Bindings</Filter>
</ClInclude>
@ -1114,6 +1114,9 @@
<ClCompile Include="..\src\Authenticator.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\BiomeDef.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\BlockArea.cpp">
<Filter>Source Files</Filter>
</ClCompile>

View File

@ -169,9 +169,9 @@ void cPluginManager::InsertDefaultPlugins(cIniFile & a_SettingsIni)
a_SettingsIni.AddKeyComment("Plugins", " Plugin=HookNotify");
a_SettingsIni.AddKeyComment("Plugins", " Plugin=ChunkWorx");
a_SettingsIni.AddKeyComment("Plugins", " Plugin=APIDump");
a_SettingsIni.SetValue("Plugins", "Plugin", "Core");
a_SettingsIni.SetValue("Plugins", "Plugin", "TransAPI");
a_SettingsIni.SetValue("Plugins", "Plugin", "ChatLog");
a_SettingsIni.AddValue("Plugins", "Plugin", "Core");
a_SettingsIni.AddValue("Plugins", "Plugin", "TransAPI");
a_SettingsIni.AddValue("Plugins", "Plugin", "ChatLog");
}

View File

@ -767,6 +767,7 @@ public:
g_BlockIsSolid[E_BLOCK_MELON_STEM] = false;
g_BlockIsSolid[E_BLOCK_NETHER_PORTAL] = false;
g_BlockIsSolid[E_BLOCK_PISTON_EXTENSION] = false;
g_BlockIsSolid[E_BLOCK_POWERED_RAIL] = false;
g_BlockIsSolid[E_BLOCK_RAIL] = false;
g_BlockIsSolid[E_BLOCK_REDSTONE_TORCH_OFF] = false;
g_BlockIsSolid[E_BLOCK_REDSTONE_TORCH_ON] = false;

View File

@ -321,7 +321,10 @@ void cEntity::DoTakeDamage(TakeDamageInfo & a_TDI)
m_Health = 0;
}
AddSpeed(a_TDI.Knockback * 2);
if (IsMob() || IsPlayer()) // Knockback for only players and mobs
{
AddSpeed(a_TDI.Knockback * 2);
}
m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_HURT);
@ -626,11 +629,6 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
{
fallspeed = m_Gravity * a_Dt / 3; // Fall 3x slower in water.
}
else if (IsBlockRail(BlockBelow) && IsMinecart()) // Rails aren't solid, except for Minecarts
{
fallspeed = 0;
m_bOnGround = true;
}
else if (BlockIn == E_BLOCK_COBWEB)
{
NextSpeed.y *= 0.05; // Reduce overall falling speed
@ -645,41 +643,18 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
}
else
{
if (IsMinecart())
// Friction
if (NextSpeed.SqrLength() > 0.0004f)
{
if (!IsBlockRail(BlockBelow))
NextSpeed.x *= 0.7f / (1 + a_Dt);
if (fabs(NextSpeed.x) < 0.05)
{
// Friction if minecart is off track, otherwise, Minecart.cpp handles this
if (NextSpeed.SqrLength() > 0.0004f)
{
NextSpeed.x *= 0.7f / (1 + a_Dt);
if (fabs(NextSpeed.x) < 0.05)
{
NextSpeed.x = 0;
}
NextSpeed.z *= 0.7f / (1 + a_Dt);
if (fabs(NextSpeed.z) < 0.05)
{
NextSpeed.z = 0;
}
}
NextSpeed.x = 0;
}
}
else
{
// Friction for non-minecarts
if (NextSpeed.SqrLength() > 0.0004f)
NextSpeed.z *= 0.7f / (1 + a_Dt);
if (fabs(NextSpeed.z) < 0.05)
{
NextSpeed.x *= 0.7f / (1 + a_Dt);
if (fabs(NextSpeed.x) < 0.05)
{
NextSpeed.x = 0;
}
NextSpeed.z *= 0.7f / (1 + a_Dt);
if (fabs(NextSpeed.z) < 0.05)
{
NextSpeed.z = 0;
}
NextSpeed.z = 0;
}
}
}
@ -1104,9 +1079,11 @@ void cEntity::AttachTo(cEntity * a_AttachTo)
// Already attached to that entity, nothing to do here
return;
}
// Detach from any previous entity:
Detach();
if (m_AttachedTo != NULL)
{
// Detach from any previous entity:
Detach();
}
// Attach to the new entity:
m_AttachedTo = a_AttachTo;

View File

@ -327,7 +327,7 @@ public:
void AttachTo(cEntity * a_AttachTo);
/// Detaches from the currently attached entity, if any
void Detach(void);
virtual void Detach(void);
/// Makes sure head yaw is not over the specified range.
void WrapHeadYaw();

View File

@ -2,6 +2,7 @@
// Minecart.cpp
// Implements the cMinecart class representing a minecart in the world
// Handles physics when a minecart is on any type of rail (overrides simulator in Entity.cpp)
// Indiana Jones!
#include "Globals.h"
@ -10,6 +11,10 @@
#include "../ClientHandle.h"
#include "../Chunk.h"
#include "Player.h"
#include "../BoundingBox.h"
#define MAX_SPEED 8
#define MAX_SPEED_NEGATIVE -MAX_SPEED
@ -18,11 +23,15 @@
cMinecart::cMinecart(ePayload a_Payload, double a_X, double a_Y, double a_Z) :
super(etMinecart, a_X, a_Y, a_Z, 0.98, 0.7),
m_Payload(a_Payload),
m_LastDamage(0)
m_LastDamage(0),
m_DetectorRailPosition(0, 0, 0),
m_bIsOnDetectorRail(false)
{
SetMass(20.f);
SetMaxHealth(6);
SetHealth(6);
SetWidth(1.2);
SetHeight(0.9);
}
@ -53,6 +62,11 @@ void cMinecart::SpawnOn(cClientHandle & a_ClientHandle)
void cMinecart::HandlePhysics(float a_Dt, cChunk & a_Chunk)
{
if (IsDestroyed()) // Mainly to stop detector rails triggering again after minecart is dead
{
return;
}
int PosY = (int)floor(GetPosY());
if ((PosY <= 0) || (PosY >= cChunkDef::Height))
{
@ -70,24 +84,361 @@ void cMinecart::HandlePhysics(float a_Dt, cChunk & a_Chunk)
// Inside an unloaded chunk, bail out all processing
return;
}
BLOCKTYPE BelowType = Chunk->GetBlock(RelPosX, PosY - 1, RelPosZ);
BLOCKTYPE InsideType = Chunk->GetBlock(RelPosX, PosY, RelPosZ);
if (IsBlockRail(BelowType))
BLOCKTYPE InsideType;
NIBBLETYPE InsideMeta;
Chunk->GetBlockTypeMeta(RelPosX, PosY, RelPosZ, InsideType, InsideMeta);
if (!IsBlockRail(InsideType))
{
HandleRailPhysics(a_Dt, *Chunk);
Chunk->GetBlockTypeMeta(RelPosX, PosY + 1, RelPosZ, InsideType, InsideMeta); // When an descending minecart hits a flat rail, it goes through the ground; check for this
if (IsBlockRail(InsideType)) AddPosY(1); // Push cart upwards
}
if (IsBlockRail(InsideType))
{
bool WasDetectorRail = false;
SnapToRail(InsideMeta);
switch (InsideType)
{
case E_BLOCK_RAIL: HandleRailPhysics(InsideMeta, a_Dt); break;
case E_BLOCK_ACTIVATOR_RAIL: break;
case E_BLOCK_POWERED_RAIL: HandlePoweredRailPhysics(InsideMeta); break;
case E_BLOCK_DETECTOR_RAIL:
{
HandleDetectorRailPhysics(InsideMeta, a_Dt);
WasDetectorRail = true;
break;
}
default: VERIFY(!"Unhandled rail type despite checking if block was rail!"); break;
}
AddPosition(GetSpeed() * (a_Dt / 1000)); // Commit changes; as we use our own engine when on rails, this needs to be done, whereas it is normally in Entity.cpp
if (m_bIsOnDetectorRail && !WasDetectorRail)
{
m_World->SetBlock(m_DetectorRailPosition.x, m_DetectorRailPosition.y, m_DetectorRailPosition.z, E_BLOCK_DETECTOR_RAIL, m_World->GetBlockMeta(m_DetectorRailPosition) & 0x07);
m_bIsOnDetectorRail = false;
}
}
else
{
if (IsBlockRail(InsideType))
// Not on rail, default physics
SetPosY(floor(GetPosY()) + 0.35); // HandlePhysics overrides this if minecart can fall, else, it is to stop ground clipping minecart bottom when off-rail
super::HandlePhysics(a_Dt, *Chunk);
}
// Broadcast positioning changes to client
BroadcastMovementUpdate();
}
void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt)
{
/*
NOTE: Please bear in mind that taking away from negatives make them even more negative,
adding to negatives make them positive, etc.
*/
switch (a_RailMeta)
{
case E_META_RAIL_ZM_ZP: // NORTHSOUTH
{
SetPosY(PosY + 1);
HandleRailPhysics(a_Dt, *Chunk);
SetRotation(270);
SetPosY(floor(GetPosY()) + 0.55);
SetSpeedY(0); // Don't move vertically as on ground
SetSpeedX(0); // Correct diagonal movement from curved rails
if (TestBlockCollision(a_RailMeta)) return;
if (GetSpeedZ() != 0) // Don't do anything if cart is stationary
{
if (GetSpeedZ() > 0)
{
// Going SOUTH, slow down
AddSpeedZ(-0.1);
}
else
{
// Going NORTH, slow down
AddSpeedZ(0.1);
}
}
break;
}
else
case E_META_RAIL_XM_XP: // EASTWEST
{
super::HandlePhysics(a_Dt, *Chunk);
BroadcastMovementUpdate();
SetRotation(180);
SetPosY(floor(GetPosY()) + 0.55);
SetSpeedY(0);
SetSpeedZ(0);
if (TestBlockCollision(a_RailMeta)) return;
if (GetSpeedX() != 0)
{
if (GetSpeedX() > 0)
{
AddSpeedX(-0.1);
}
else
{
AddSpeedX(0.1);
}
}
break;
}
case E_META_RAIL_ASCEND_ZM: // ASCEND NORTH
{
SetRotation(270);
SetSpeedX(0);
if (GetSpeedZ() >= 0)
{
// SpeedZ POSITIVE, going SOUTH
if (GetSpeedZ() <= MAX_SPEED) // Speed limit
{
AddSpeedZ(0.5); // Speed up
SetSpeedY(-GetSpeedZ()); // Downward movement is negative (0 minus positive numbers is negative)
}
}
else
{
// SpeedZ NEGATIVE, going NORTH
AddSpeedZ(1); // Slow down
SetSpeedY(-GetSpeedZ()); // Upward movement is positive (0 minus negative number is positive number)
}
break;
}
case E_META_RAIL_ASCEND_ZP: // ASCEND SOUTH
{
SetRotation(270);
SetSpeedX(0);
if (GetSpeedZ() > 0)
{
// SpeedZ POSITIVE, going SOUTH
AddSpeedZ(-1); // Slow down
SetSpeedY(GetSpeedZ()); // Upward movement positive
}
else
{
if (GetSpeedZ() >= MAX_SPEED_NEGATIVE) // Speed limit
{
// SpeedZ NEGATIVE, going NORTH
AddSpeedZ(-0.5); // Speed up
SetSpeedY(GetSpeedZ()); // Downward movement negative
}
}
break;
}
case E_META_RAIL_ASCEND_XM: // ASCEND EAST
{
SetRotation(180);
SetSpeedZ(0);
if (GetSpeedX() >= 0)
{
if (GetSpeedX() <= MAX_SPEED)
{
AddSpeedX(0.5);
SetSpeedY(-GetSpeedX());
}
}
else
{
AddSpeedX(1);
SetSpeedY(-GetSpeedX());
}
break;
}
case E_META_RAIL_ASCEND_XP: // ASCEND WEST
{
SetRotation(180);
SetSpeedZ(0);
if (GetSpeedX() > 0)
{
AddSpeedX(-1);
SetSpeedY(GetSpeedX());
}
else
{
if (GetSpeedX() >= MAX_SPEED_NEGATIVE)
{
AddSpeedX(-0.5);
SetSpeedY(GetSpeedX());
}
}
break;
}
case E_META_RAIL_CURVED_ZM_XM: // Ends pointing NORTH and WEST
{
SetRotation(315); // Set correct rotation server side
SetPosY(floor(GetPosY()) + 0.55); // Levitate dat cart
if (TestBlockCollision(a_RailMeta)) return;
if (GetSpeedZ() > 0) // Cart moving south
{
int OldX = (int)floor(GetPosX());
AddSpeedX(-GetSpeedZ() + 0.5); // See below
AddPosX(-GetSpeedZ() * (a_Dt / 1000)); // Diagonally move southwest (which will make cart hit a southwest rail)
// If we are already at southwest rail, set Z speed to zero as we can be moving so fast, MCS doesn't tick fast enough to active the handle for the rail...
// ...and so we derail unexpectedly.
if (GetPosX() <= OldX - 1) SetSpeedZ(0);
}
else if (GetSpeedX() > 0) // Cart moving east
{
int OldZ = (int)floor(GetPosZ());
AddSpeedZ(-GetSpeedX() + 0.5);
AddPosZ(-GetSpeedX() * (a_Dt / 1000)); // Diagonally move northeast
if (GetPosZ() <= OldZ - 1) SetSpeedX(0);
}
break;
}
case E_META_RAIL_CURVED_ZM_XP: // Curved NORTH EAST
{
SetRotation(225);
SetPosY(floor(GetPosY()) + 0.55);
if (TestBlockCollision(a_RailMeta)) return;
if (GetSpeedZ() > 0)
{
int OldX = (int)floor(GetPosX());
AddSpeedX(GetSpeedZ() - 0.5);
AddPosX(GetSpeedZ() * (a_Dt / 1000));
if (GetPosX() >= OldX + 1) SetSpeedZ(0);
}
else if (GetSpeedX() < 0)
{
int OldZ = (int)floor(GetPosZ());
AddSpeedZ(GetSpeedX() + 0.5);
AddPosZ(GetSpeedX() * (a_Dt / 1000));
if (GetPosZ() <= OldZ - 1) SetSpeedX(0);
}
break;
}
case E_META_RAIL_CURVED_ZP_XM: // Curved SOUTH WEST
{
SetRotation(135);
SetPosY(floor(GetPosY()) + 0.55);
if (TestBlockCollision(a_RailMeta)) return;
if (GetSpeedZ() < 0)
{
int OldX = (int)floor(GetPosX());
AddSpeedX(GetSpeedZ() + 0.5);
AddPosX(GetSpeedZ() * (a_Dt / 1000));
if (GetPosX() <= OldX - 1) SetSpeedZ(0);
}
else if (GetSpeedX() > 0)
{
int OldZ = (int)floor(GetPosZ());
AddSpeedZ(GetSpeedX() - 0.5);
AddPosZ(GetSpeedX() * (a_Dt / 1000));
if (GetPosZ() >= OldZ + 1) SetSpeedX(0);
}
break;
}
case E_META_RAIL_CURVED_ZP_XP: // Curved SOUTH EAST
{
SetRotation(45);
SetPosY(floor(GetPosY()) + 0.55);
if (TestBlockCollision(a_RailMeta)) return;
if (GetSpeedZ() < 0)
{
int OldX = (int)floor(GetPosX());
AddSpeedX(-GetSpeedZ() - 0.5);
AddPosX(-GetSpeedZ() * (a_Dt / 1000));
if (GetPosX() >= OldX + 1) SetSpeedZ(0);
}
else if (GetSpeedX() < 0)
{
int OldZ = (int)floor(GetPosZ());
AddSpeedZ(-GetSpeedX() - 0.5);
AddPosZ(-GetSpeedX() * (a_Dt / 1000));
if (GetPosZ() >= OldZ + 1) SetSpeedX(0);
}
break;
}
default:
{
ASSERT(!"Unhandled rail meta!"); // Dun dun DUN!
break;
}
}
}
void cMinecart::HandlePoweredRailPhysics(NIBBLETYPE a_RailMeta)
{
// Initialise to 'slow down' values
int AccelDecelSpeed = -1;
int AccelDecelNegSpeed = 1;
if ((a_RailMeta & 0x8) == 0x8)
{
// Rail powered - set variables to 'speed up' values
AccelDecelSpeed = 1;
AccelDecelNegSpeed = -1;
}
switch (a_RailMeta & 0x07)
{
case E_META_RAIL_ZM_ZP: // NORTHSOUTH
{
SetRotation(270);
SetPosY(floor(GetPosY()) + 0.55);
SetSpeedY(0);
SetSpeedX(0);
if (TestBlockCollision(a_RailMeta)) return;
if (GetSpeedZ() != 0)
{
if (GetSpeedZ() > 0)
{
AddSpeedZ(AccelDecelNegSpeed);
}
else
{
AddSpeedZ(AccelDecelSpeed);
}
}
break;
}
case E_META_RAIL_XM_XP: // EASTWEST
{
SetRotation(180);
SetPosY(floor(GetPosY()) + 0.55);
SetSpeedY(0);
SetSpeedZ(0);
if (TestBlockCollision(a_RailMeta)) return;
if (GetSpeedX() != 0)
{
if (GetSpeedX() > 0)
{
AddSpeedX(AccelDecelSpeed);
}
else
{
AddSpeedX(AccelDecelNegSpeed);
}
}
break;
}
}
}
@ -96,260 +447,150 @@ void cMinecart::HandlePhysics(float a_Dt, cChunk & a_Chunk)
static const double MAX_SPEED = 8;
static const double MAX_SPEED_NEGATIVE = (0 - MAX_SPEED);
void cMinecart::HandleRailPhysics(float a_Dt, cChunk & a_Chunk)
void cMinecart::HandleDetectorRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt)
{
super::HandlePhysics(a_Dt, a_Chunk); // Main physics handling
m_bIsOnDetectorRail = true;
m_DetectorRailPosition = Vector3i((int)floor(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ()));
/*
NOTE: Please bear in mind that taking away from negatives make them even more negative,
adding to negatives make them positive, etc.
*/
// Get block meta below the cart
int RelPosX = (int)floor(GetPosX()) - a_Chunk.GetPosX() * cChunkDef::Width;
int RelPosZ = (int)floor(GetPosZ()) - a_Chunk.GetPosZ() * cChunkDef::Width;
NIBBLETYPE BelowMeta = a_Chunk.GetMeta(RelPosX, (int)floor(GetPosY() - 1), RelPosZ);
double SpeedX = GetSpeedX(), SpeedY = GetSpeedY(), SpeedZ = GetSpeedZ(); // Get current speed
switch (BelowMeta)
m_World->SetBlockMeta(m_DetectorRailPosition, a_RailMeta | 0x08);
HandleRailPhysics(a_RailMeta & 0x07, a_Dt);
}
void cMinecart::SnapToRail(NIBBLETYPE a_RailMeta)
{
switch (a_RailMeta)
{
case E_META_RAIL_ZM_ZP: // NORTHSOUTH
case E_META_RAIL_ASCEND_XM:
case E_META_RAIL_ASCEND_XP:
case E_META_RAIL_XM_XP:
{
SetRotation(270);
SpeedY = 0; // Don't move vertically as on ground
SpeedX = 0; // Correct diagonal movement from curved rails
if (SpeedZ != 0) // Don't do anything if cart is stationary
{
if (SpeedZ > 0)
{
// Going SOUTH, slow down
SpeedZ = SpeedZ - 0.1;
}
else
{
// Going NORTH, slow down
SpeedZ = SpeedZ + 0.1;
}
}
SetSpeedZ(0);
SetPosZ(floor(GetPosZ()) + 0.5);
break;
}
case E_META_RAIL_XM_XP: // EASTWEST
case E_META_RAIL_ASCEND_ZM:
case E_META_RAIL_ASCEND_ZP:
case E_META_RAIL_ZM_ZP:
{
SetRotation(180);
SpeedY = 0;
SpeedZ = 0;
if (SpeedX != 0)
{
if (SpeedX > 0)
{
SpeedX = SpeedX - 0.1;
}
else
{
SpeedX = SpeedX + 0.1;
}
}
break;
}
case E_META_RAIL_ASCEND_ZM: // ASCEND NORTH
{
SetRotation(270);
SetPosY(floor(GetPosY()) + 0.2); // It seems it doesn't work without levitation :/
SpeedX = 0;
if (SpeedZ >= 0)
{
// SpeedZ POSITIVE, going SOUTH
if (SpeedZ <= MAX_SPEED) // Speed limit
{
SpeedZ = SpeedZ + 0.5; // Speed up
SpeedY = (0 - SpeedZ); // Downward movement is negative (0 minus positive numbers is negative)
}
else
{
SpeedZ = MAX_SPEED; // Enforce speed limit
SpeedY = (0 - SpeedZ);
}
}
else
{
// SpeedZ NEGATIVE, going NORTH
SpeedZ = SpeedZ + 0.4; // Slow down
SpeedY = (0 - SpeedZ); // Upward movement is positive (0 minus negative number is positive number)
}
break;
}
case E_META_RAIL_ASCEND_ZP: // ASCEND SOUTH
{
SetRotation(270);
SetPosY(floor(GetPosY()) + 0.2);
SpeedX = 0;
if (SpeedZ > 0)
{
// SpeedZ POSITIVE, going SOUTH
SpeedZ = SpeedZ - 0.4; // Slow down
SpeedY = SpeedZ; // Upward movement positive
}
else
{
if (SpeedZ >= MAX_SPEED_NEGATIVE) // Speed limit
{
// SpeedZ NEGATIVE, going NORTH
SpeedZ = SpeedZ - 0.5; // Speed up
SpeedY = SpeedZ; // Downward movement negative
}
else
{
SpeedZ = MAX_SPEED_NEGATIVE; // Enforce speed limit
SpeedY = SpeedZ;
}
}
break;
}
case E_META_RAIL_ASCEND_XM: // ASCEND EAST
{
SetRotation(180);
SetPosY(floor(GetPosY()) + 0.2);
SpeedZ = 0;
if (SpeedX >= 0)
{
if (SpeedX <= MAX_SPEED)
{
SpeedX = SpeedX + 0.5;
SpeedY = (0 - SpeedX);
}
else
{
SpeedX = MAX_SPEED;
SpeedY = (0 - SpeedX);
}
}
else
{
SpeedX = SpeedX + 0.4;
SpeedY = (0 - SpeedX);
}
break;
}
case E_META_RAIL_ASCEND_XP: // ASCEND WEST
{
SetRotation(180);
SetPosY(floor(GetPosY()) + 0.2);
SpeedZ = 0;
if (SpeedX > 0)
{
SpeedX = SpeedX - 0.4;
SpeedY = SpeedX;
}
else
{
if (SpeedX >= MAX_SPEED_NEGATIVE)
{
SpeedX = SpeedX - 0.5;
SpeedY = SpeedX;
}
else
{
SpeedX = MAX_SPEED_NEGATIVE;
SpeedY = SpeedX;
}
}
break;
}
case E_META_RAIL_CURVED_ZM_XM: // Ends pointing NORTH and WEST
{
SetRotation(315); // Set correct rotation server side
SetPosY(floor(GetPosY()) + 0.2); // Levitate dat cart
if (SpeedZ > 0) // Cart moving south
{
SpeedX = (0 - SpeedZ); // Diagonally move southwest (which will make cart hit a southwest rail)
}
else if (SpeedX > 0) // Cart moving east
{
SpeedZ = (0 - SpeedX); // Diagonally move northeast
}
break;
}
case E_META_RAIL_CURVED_ZM_XP: // Curved NORTH EAST
{
SetRotation(225);
SetPosY(floor(GetPosY()) + 0.2);
if (SpeedZ > 0)
{
SpeedX = SpeedZ;
}
else if (SpeedX < 0)
{
SpeedZ = SpeedX;
}
break;
}
case E_META_RAIL_CURVED_ZP_XM: // Curved SOUTH WEST
{
SetRotation(135);
SetPosY(floor(GetPosY()) + 0.2);
if (SpeedZ < 0)
{
SpeedX = SpeedZ;
}
else if (SpeedX > 0)
{
SpeedZ = SpeedX;
}
break;
}
case E_META_RAIL_CURVED_ZP_XP: // Curved SOUTH EAST
{
SetRotation(45);
SetPosY(floor(GetPosY()) + 0.2);
if (SpeedZ < 0)
{
SpeedX = (0 - SpeedZ);
}
else if (SpeedX < 0)
{
SpeedZ = (0 - SpeedX);
}
break;
}
default:
{
ASSERT(!"Unhandled rail meta!"); // Dun dun DUN!
SetSpeedX(0);
SetPosX(floor(GetPosX()) + 0.5);
break;
}
default: break;
}
// Set speed to speed variables
SetSpeedX(SpeedX);
SetSpeedY(SpeedY);
SetSpeedZ(SpeedZ);
}
// Broadcast position to client
BroadcastMovementUpdate();
bool cMinecart::TestBlockCollision(NIBBLETYPE a_RailMeta)
{
switch (a_RailMeta)
{
case E_META_RAIL_ZM_ZP:
{
if (GetSpeedZ() > 0)
{
BLOCKTYPE Block = m_World->GetBlock((int)floor(GetPosX()), (int)floor(GetPosY()), (int)ceil(GetPosZ()));
if (!IsBlockRail(Block) && g_BlockIsSolid[Block])
{
// We could try to detect a block in front based purely on coordinates, but xoft made a bounding box system - why not use? :P
cBoundingBox bbBlock(Vector3d((int)floor(GetPosX()), (int)floor(GetPosY()), (int)ceil(GetPosZ())), 0.5, 1);
cBoundingBox bbMinecart(Vector3d(GetPosX(), floor(GetPosY()), GetPosZ()), GetWidth() / 2, GetHeight());
if (bbBlock.DoesIntersect(bbMinecart))
{
SetSpeed(0, 0, 0);
SetPosZ(floor(GetPosZ()) + 0.4);
return true;
}
}
}
else
{
BLOCKTYPE Block = m_World->GetBlock((int)floor(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ()) - 1);
if (!IsBlockRail(Block) && g_BlockIsSolid[Block])
{
cBoundingBox bbBlock(Vector3d((int)floor(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ()) - 1), 0.5, 1);
cBoundingBox bbMinecart(Vector3d(GetPosX(), floor(GetPosY()), GetPosZ() - 1), GetWidth() / 2, GetHeight());
if (bbBlock.DoesIntersect(bbMinecart))
{
SetSpeed(0, 0, 0);
SetPosZ(floor(GetPosZ()) + 0.65);
return true;
}
}
}
break;
}
case E_META_RAIL_XM_XP:
{
if (GetSpeedX() > 0)
{
BLOCKTYPE Block = m_World->GetBlock((int)ceil(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ()));
if (!IsBlockRail(Block) && g_BlockIsSolid[Block])
{
cBoundingBox bbBlock(Vector3d((int)ceil(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ())), 0.5, 1);
cBoundingBox bbMinecart(Vector3d(GetPosX(), floor(GetPosY()), GetPosZ()), GetWidth() / 2, GetHeight());
if (bbBlock.DoesIntersect(bbMinecart))
{
SetSpeed(0, 0, 0);
SetPosX(floor(GetPosX()) + 0.4);
return true;
}
}
}
else
{
BLOCKTYPE Block = m_World->GetBlock((int)floor(GetPosX()) - 1, (int)floor(GetPosY()), (int)floor(GetPosZ()));
if (!IsBlockRail(Block) && g_BlockIsSolid[Block])
{
cBoundingBox bbBlock(Vector3d((int)floor(GetPosX()) - 1, (int)floor(GetPosY()), (int)floor(GetPosZ())), 0.5, 1);
cBoundingBox bbMinecart(Vector3d(GetPosX() - 1, floor(GetPosY()), GetPosZ()), GetWidth() / 2, GetHeight());
if (bbBlock.DoesIntersect(bbMinecart))
{
SetSpeed(0, 0, 0);
SetPosX(floor(GetPosX()) + 0.65);
return true;
}
}
}
break;
}
case E_META_RAIL_CURVED_ZM_XM:
case E_META_RAIL_CURVED_ZM_XP:
case E_META_RAIL_CURVED_ZP_XM:
case E_META_RAIL_CURVED_ZP_XP:
{
BLOCKTYPE BlockXM = m_World->GetBlock((int)floor(GetPosX()) - 1, (int)floor(GetPosY()), (int)floor(GetPosZ()));
BLOCKTYPE BlockXP = m_World->GetBlock((int)floor(GetPosX()) + 1, (int)floor(GetPosY()), (int)floor(GetPosZ()));
BLOCKTYPE BlockZM = m_World->GetBlock((int)floor(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ()) + 1);
BLOCKTYPE BlockZP = m_World->GetBlock((int)floor(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ()) + 1);
if (
(!IsBlockRail(BlockXM) && g_BlockIsSolid[BlockXM]) ||
(!IsBlockRail(BlockXP) && g_BlockIsSolid[BlockXP]) ||
(!IsBlockRail(BlockZM) && g_BlockIsSolid[BlockZM]) ||
(!IsBlockRail(BlockZP) && g_BlockIsSolid[BlockZP])
)
{
SetSpeed(0, 0, 0);
SetPosition((int)floor(GetPosX()) + 0.5, GetPosY(), (int)floor(GetPosZ()) + 0.5);
return true;
}
break;
}
default: break;
}
return false;
}
@ -358,6 +599,14 @@ void cMinecart::HandleRailPhysics(float a_Dt, cChunk & a_Chunk)
void cMinecart::DoTakeDamage(TakeDamageInfo & TDI)
{
if (TDI.Attacker->IsPlayer() && ((cPlayer *)TDI.Attacker)->IsGameModeCreative())
{
Destroy();
TDI.FinalDamage = GetMaxHealth(); // Instant hit for creative
super::DoTakeDamage(TDI);
return; // No drops for creative
}
m_LastDamage = TDI.FinalDamage;
super::DoTakeDamage(TDI);
@ -365,7 +614,7 @@ void cMinecart::DoTakeDamage(TakeDamageInfo & TDI)
if (GetHealth() <= 0)
{
Destroy(true);
Destroy();
cItems Drops;
switch (m_Payload)
@ -410,6 +659,18 @@ void cMinecart::DoTakeDamage(TakeDamageInfo & TDI)
void cMinecart::Destroyed()
{
if (m_bIsOnDetectorRail)
{
m_World->SetBlock(m_DetectorRailPosition.x, m_DetectorRailPosition.y, m_DetectorRailPosition.z, E_BLOCK_DETECTOR_RAIL, m_World->GetBlockMeta(m_DetectorRailPosition) & 0x07);
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cEmptyMinecart:

View File

@ -51,17 +51,38 @@ public:
virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override;
virtual void DoTakeDamage(TakeDamageInfo & TDI) override;
virtual void Destroyed() override;
int LastDamage(void) const { return m_LastDamage; }
void HandleRailPhysics(float a_Dt, cChunk & a_Chunk);
ePayload GetPayload(void) const { return m_Payload; }
protected:
ePayload m_Payload;
int m_LastDamage;
Vector3i m_DetectorRailPosition;
bool m_bIsOnDetectorRail;
cMinecart(ePayload a_Payload, double a_X, double a_Y, double a_Z);
int m_LastDamage;
/** Handles physics on normal rails
For each tick, slow down on flat rails, speed up or slow down on ascending/descending rails (depending on direction), and turn on curved rails
*/
void HandleRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt);
/** Handles powered rail physics
Each tick, speed up or slow down cart, depending on metadata of rail (powered or not)
*/
void HandlePoweredRailPhysics(NIBBLETYPE a_RailMeta);
/** Handles detector rail activation
Activates detector rails when a minecart is on them. Calls HandleRailPhysics() for physics simulations
*/
void HandleDetectorRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt);
/** Snaps a minecart to a rail's axis, resetting its speed */
void SnapToRail(NIBBLETYPE a_RailMeta);
/** Tests is a solid block is in front of a cart, and stops the cart (and returns true) if so; returns false if no obstruction*/
bool TestBlockCollision(NIBBLETYPE a_RailMeta);
} ;

View File

@ -1884,3 +1884,33 @@ void cPlayer::ApplyFoodExhaustionFromMovement()
void cPlayer::Detach()
{
super::Detach();
int PosX = (int)floor(GetPosX());
int PosY = (int)floor(GetPosY());
int PosZ = (int)floor(GetPosZ());
// Search for a position within an area to teleport player after detachment
// Position must be solid land, and occupied by a nonsolid block
// If nothing found, player remains where they are
for (int x = PosX - 2; x <= (PosX + 2); ++x)
{
for (int y = PosY; y <= (PosY + 3); ++y)
{
for (int z = PosZ - 2; z <= (PosZ + 2); ++z)
{
if (!g_BlockIsSolid[m_World->GetBlock(x, y, z)] && g_BlockIsSolid[m_World->GetBlock(x, y - 1, z)])
{
TeleportToCoords(x, y, z);
return;
}
}
}
}
}

View File

@ -350,6 +350,8 @@ public:
virtual bool IsCrouched (void) const { return m_IsCrouched; }
virtual bool IsSprinting(void) const { return m_IsSprinting; }
virtual bool IsRclking (void) const { return IsEating(); }
virtual void Detach(void);
protected:
typedef std::map< std::string, bool > PermissionMap;

View File

@ -69,7 +69,7 @@ void cRedstoneSimulator::AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChu
// Changeable sources
((Block == E_BLOCK_REDSTONE_WIRE) && (Meta == 0)) ||
((Block == E_BLOCK_LEVER) && !IsLeverOn(Meta)) ||
((Block == E_BLOCK_DETECTOR_RAIL) && (Meta & 0x08) == 0x08) ||
((Block == E_BLOCK_DETECTOR_RAIL) && (Meta & 0x08) == 0) ||
(((Block == E_BLOCK_STONE_BUTTON) || (Block == E_BLOCK_WOODEN_BUTTON)) && (!IsButtonOn(Meta))) ||
(((Block == E_BLOCK_STONE_PRESSURE_PLATE) || (Block == E_BLOCK_WOODEN_PRESSURE_PLATE)) && (Meta == 0))
)
@ -505,8 +505,7 @@ void cRedstoneSimulator::HandleRedstoneWire(int a_BlockX, int a_BlockY, int a_Bl
// transferring power to other wires around.
// However, self not directly powered anymore, so source must have been removed,
// therefore, self must be set to meta zero
m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0);
m_World.WakeUpSimulators(a_BlockX, a_BlockY, a_BlockZ);
m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE, 0); // SetMeta & WakeUpSims doesn't seem to work here, so SetBlock
return; // No need to process block power sets because self not powered
}
else
@ -903,6 +902,7 @@ void cRedstoneSimulator::HandlePressurePlate(int a_BlockX, int a_BlockY, int a_B
else
{
m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0x0);
m_World.WakeUpSimulators(a_BlockX, a_BlockY, a_BlockZ);
}
break;
}
@ -965,6 +965,7 @@ void cRedstoneSimulator::HandlePressurePlate(int a_BlockX, int a_BlockY, int a_B
else
{
m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0x0);
m_World.WakeUpSimulators(a_BlockX, a_BlockY, a_BlockZ);
}
break;
}