void CTurtle::Update(float fElapsedTime) { m_vAnimations[m_nCurrAnimation].Update(fElapsedTime); if(GetExperience() >= (100 * GetLevel())) { CBattleMap::GetInstance()->PlaySFX(CAssets::GetInstance()->aBMcowabungaSnd); SetExperience(0/*GetExperience()-(100* GetLevel())*/); SetLevel(GetLevel() + 1); SetHealthMax((int)((float)GetMaxHealth() * 1.25f)); SetHealth((int)((float)GetMaxHealth())); SetBaseAP(GetBaseAP()+2); SetStrength( (int)( (float)GetStrength() * 1.2f ) ); SetDefense( (int) ( (float)GetDefense() * 1.2f ) ); SetAccuracy( (int) ( (float)GetAccuracy() * 1.2f ) ); SetSpeed( (int) ( (float)GetSpeed() * 1.2f ) ); } if( GetHealth() <= 0) { if(GetAlive() == true) { CBattleMap::GetInstance()->DecrementNumChars(); CBattleMap::GetInstance()->DecrementNumTurtles(); CBattleMap::GetInstance()->SetTurtleDead(); SetAlive(false); if(GetCurrAnimNum() != 9) SetCurrAnim(9); SetPosZ(0.9f); } } }
void CTurtle::Render() { if(!m_bIsAlive) { if(GetCurrAnimNum() != 9) SetCurrAnim(9); SetPosZ(0.9f); } m_vAnimations[m_nCurrAnimation].Render((int)GetPosX()+m_vAnimations[0].GetFrames()[0].nAnchorX,(int)GetPosY()+m_vAnimations[0].GetFrames()[0].nAnchorY, GetPosZ(), 1.0f, m_dwColor); }
bool cMinecart::TestBlockCollision(NIBBLETYPE a_RailMeta) { switch (a_RailMeta) { case E_META_RAIL_ZM_ZP: { if (GetSpeedZ() > 0) { BLOCKTYPE Block = m_World->GetBlock(POSX_TOINT, POSY_TOINT, (int)ceil(GetPosZ())); if (!IsBlockRail(Block) && cBlockInfo::IsSolid(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(POSX_TOINT, POSY_TOINT, (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 if (GetSpeedZ() < 0) { BLOCKTYPE Block = m_World->GetBlock(POSX_TOINT, POSY_TOINT, POSZ_TOINT - 1); if (!IsBlockRail(Block) && cBlockInfo::IsSolid(Block)) { cBoundingBox bbBlock(Vector3d(POSX_TOINT, POSY_TOINT, POSZ_TOINT - 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()), POSY_TOINT, POSZ_TOINT); if (!IsBlockRail(Block) && cBlockInfo::IsSolid(Block)) { cBoundingBox bbBlock(Vector3d((int)ceil(GetPosX()), POSY_TOINT, POSZ_TOINT), 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 if (GetSpeedX() < 0) { BLOCKTYPE Block = m_World->GetBlock(POSX_TOINT - 1, POSY_TOINT, POSZ_TOINT); if (!IsBlockRail(Block) && cBlockInfo::IsSolid(Block)) { cBoundingBox bbBlock(Vector3d(POSX_TOINT - 1, POSY_TOINT, POSZ_TOINT), 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(POSX_TOINT - 1, POSY_TOINT, POSZ_TOINT); BLOCKTYPE BlockXP = m_World->GetBlock(POSX_TOINT + 1, POSY_TOINT, POSZ_TOINT); BLOCKTYPE BlockZM = m_World->GetBlock(POSX_TOINT, POSY_TOINT, POSZ_TOINT - 1); BLOCKTYPE BlockZP = m_World->GetBlock(POSX_TOINT, POSY_TOINT, POSZ_TOINT + 1); if ( (!IsBlockRail(BlockXM) && cBlockInfo::IsSolid(BlockXM)) || (!IsBlockRail(BlockXP) && cBlockInfo::IsSolid(BlockXP)) || (!IsBlockRail(BlockZM) && cBlockInfo::IsSolid(BlockZM)) || (!IsBlockRail(BlockZP) && cBlockInfo::IsSolid(BlockZP)) ) { SetSpeed(0, 0, 0); SetPosition(POSX_TOINT + 0.5, GetPosY(), POSZ_TOINT + 0.5); return true; } break; } default: break; } return false; }
void cMinecart::SnapToRail(NIBBLETYPE a_RailMeta) { switch (a_RailMeta) { case E_META_RAIL_ASCEND_XM: case E_META_RAIL_ASCEND_XP: case E_META_RAIL_XM_XP: { SetSpeedZ(0); SetPosZ(floor(GetPosZ()) + 0.5); break; } case E_META_RAIL_ASCEND_ZM: case E_META_RAIL_ASCEND_ZP: case E_META_RAIL_ZM_ZP: { SetSpeedX(0); SetPosX(floor(GetPosX()) + 0.5); break; } // Curved rail physics: once minecart has reached more than half of the block in the direction that it is travelling in, jerk it in the direction of curvature case E_META_RAIL_CURVED_ZM_XM: { if (GetPosZ() > floor(GetPosZ()) + 0.5) { if (GetSpeedZ() > 0) { SetSpeedX(-GetSpeedZ() * 0.7); } SetSpeedZ(0); SetPosZ(floor(GetPosZ()) + 0.5); } else if (GetPosX() > floor(GetPosX()) + 0.5) { if (GetSpeedX() > 0) { SetSpeedZ(-GetSpeedX() * 0.7); } SetSpeedX(0); SetPosX(floor(GetPosX()) + 0.5); } SetSpeedY(0); break; } case E_META_RAIL_CURVED_ZM_XP: { if (GetPosZ() > floor(GetPosZ()) + 0.5) { if (GetSpeedZ() > 0) { SetSpeedX(GetSpeedZ() * 0.7); } SetSpeedZ(0); SetPosZ(floor(GetPosZ()) + 0.5); } else if (GetPosX() < floor(GetPosX()) + 0.5) { if (GetSpeedX() < 0) { SetSpeedZ(GetSpeedX() * 0.7); } SetSpeedX(0); SetPosX(floor(GetPosX()) + 0.5); } SetSpeedY(0); break; } case E_META_RAIL_CURVED_ZP_XM: { if (GetPosZ() < floor(GetPosZ()) + 0.5) { if (GetSpeedZ() < 0) { SetSpeedX(GetSpeedZ() * 0.7); } SetSpeedZ(0); SetPosZ(floor(GetPosZ()) + 0.5); } else if (GetPosX() > floor(GetPosX()) + 0.5) { if (GetSpeedX() > 0) { SetSpeedZ(GetSpeedX() * 0.7); } SetSpeedX(0); SetPosX(floor(GetPosX()) + 0.5); } SetSpeedY(0); break; } case E_META_RAIL_CURVED_ZP_XP: { if (GetPosZ() < floor(GetPosZ()) + 0.5) { if (GetSpeedZ() < 0) { SetSpeedX(-GetSpeedZ() * 0.7); } SetSpeedZ(0); SetPosZ(floor(GetPosZ()) + 0.5); } else if (GetPosX() < floor(GetPosX()) + 0.5) { if (GetSpeedX() < 0) { SetSpeedZ(-GetSpeedX() * 0.7); } SetSpeedX(0); SetPosX(floor(GetPosX()) + 0.5); } SetSpeedY(0); break; } default: break; } }
cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName) : super(etPlayer, 0.6, 1.8) , 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_Color('-') , m_GameMode(eGameMode_NotSet) , m_IP("") , m_ClientHandle(a_Client) , m_NormalMaxSpeed(1.0) , m_SprintingMaxSpeed(1.3) , m_FlyingMaxSpeed(1.0) , m_IsCrouched(false) , m_IsSprinting(false) , m_IsFlying(false) , m_IsSwimming(false) , m_IsSubmerged(false) , m_IsFishing(false) , m_CanFly(false) , m_EatingFinishTick(-1) , m_LifetimeTotalXp(0) , m_CurrentXp(0) , m_bDirtyExperience(false) , m_IsChargingBow(false) , m_BowCharge(0) , m_FloaterID(-1) , m_Team(NULL) { LOGD("Created a player object for \"%s\" @ \"%s\" at %p, ID %d", a_PlayerName.c_str(), a_Client->GetIPString().c_str(), this, GetUniqueID() ); m_InventoryWindow = new cInventoryWindow(*this); m_CurrentWindow = m_InventoryWindow; m_InventoryWindow->OpenedByPlayer(*this); SetMaxHealth(MAX_HEALTH); m_Health = MAX_HEALTH; cTimer t1; m_LastPlayerListTime = t1.GetNowTime(); m_PlayerName = a_PlayerName; if (!LoadFromDisk()) { m_Inventory.Clear(); cWorld * DefaultWorld = cRoot::Get()->GetDefaultWorld(); SetPosX(DefaultWorld->GetSpawnX()); SetPosY(DefaultWorld->GetSpawnY()); SetPosZ(DefaultWorld->GetSpawnZ()); LOGD("Player \"%s\" is connecting for the first time, spawning at default world spawn {%.2f, %.2f, %.2f}", a_PlayerName.c_str(), GetPosX(), GetPosY(), GetPosZ() ); } m_LastJumpHeight = (float)(GetPosY()); m_LastGroundHeight = (float)(GetPosY()); m_Stance = GetPosY() + 1.62; if (m_GameMode == gmNotSet) { cWorld * World = cRoot::Get()->GetWorld(GetLoadedWorldName()); if (World == NULL) { World = cRoot::Get()->GetDefaultWorld(); } if (World->IsGameModeCreative()) { m_CanFly = true; } } cRoot::Get()->GetServer()->PlayerCreated(this); }
bool cPlayer::LoadFromDisk() { LoadPermissionsFromDisk(); AString SourceFile; Printf(SourceFile, "players/%s.json", GetName().c_str() ); cFile f; if (!f.Open(SourceFile, cFile::fmRead)) { // This is a new player whom we haven't seen yet, bail out, let them have the defaults return false; } AString buffer; if (f.ReadRestOfFile(buffer) != f.GetSize()) { LOGWARNING("Cannot read player data from file \"%s\"", SourceFile.c_str()); return false; } f.Close(); //cool kids play nice Json::Value root; Json::Reader reader; if (!reader.parse(buffer, root, false)) { LOGWARNING("Cannot parse player data in file \"%s\", player will be reset", SourceFile.c_str()); } Json::Value & JSON_PlayerPosition = root["position"]; if (JSON_PlayerPosition.size() == 3) { SetPosX(JSON_PlayerPosition[(unsigned int)0].asDouble()); SetPosY(JSON_PlayerPosition[(unsigned int)1].asDouble()); SetPosZ(JSON_PlayerPosition[(unsigned int)2].asDouble()); m_LastPos = GetPosition(); } Json::Value & JSON_PlayerRotation = root["rotation"]; if (JSON_PlayerRotation.size() == 3) { SetYaw ((float)JSON_PlayerRotation[(unsigned int)0].asDouble()); SetPitch ((float)JSON_PlayerRotation[(unsigned int)1].asDouble()); SetRoll ((float)JSON_PlayerRotation[(unsigned int)2].asDouble()); } m_Health = root.get("health", 0).asInt(); m_AirLevel = root.get("air", MAX_AIR_LEVEL).asInt(); m_FoodLevel = root.get("food", MAX_FOOD_LEVEL).asInt(); m_FoodSaturationLevel = root.get("foodSaturation", MAX_FOOD_LEVEL).asDouble(); m_FoodTickTimer = root.get("foodTickTimer", 0).asInt(); m_FoodExhaustionLevel = root.get("foodExhaustion", 0).asDouble(); m_LifetimeTotalXp = (short) root.get("xpTotal", 0).asInt(); m_CurrentXp = (short) root.get("xpCurrent", 0).asInt(); m_IsFlying = root.get("isflying", 0).asBool(); m_GameMode = (eGameMode) root.get("gamemode", eGameMode_NotSet).asInt(); if (m_GameMode == eGameMode_Creative) { m_CanFly = true; } m_Inventory.LoadFromJson(root["inventory"]); m_LoadedWorldName = root.get("world", "world").asString(); // Load the player stats. // We use the default world name (like bukkit) because stats are shared between dimensions/worlds. cStatSerializer StatSerializer(cRoot::Get()->GetDefaultWorld()->GetName(), GetName(), &m_Stats); StatSerializer.Load(); LOGD("Player \"%s\" was read from file, spawning at {%.2f, %.2f, %.2f} in world \"%s\"", GetName().c_str(), GetPosX(), GetPosY(), GetPosZ(), m_LoadedWorldName.c_str() ); return true; }
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_FoodLevel(MAX_FOOD_LEVEL) , m_FoodSaturationLevel(5) , m_FoodTickTimer(0) , m_FoodExhaustionLevel(0) , m_FoodPoisonedTicksRemaining(0) , m_NormalMaxSpeed(0.1) , m_SprintingMaxSpeed(0.13) , m_IsCrouched(false) , m_IsSprinting(false) , m_IsSwimming(false) , m_IsSubmerged(false) , m_EatingFinishTick(-1) , m_IsChargingBow(false) , m_BowCharge(0) , m_CurrentXp(0) , m_LifetimeTotalXp(0) , m_bDirtyExperience(false) { LOGD("Created a player object for \"%s\" @ \"%s\" at %p, ID %d", a_PlayerName.c_str(), a_Client->GetIPString().c_str(), this, GetUniqueID() ); m_InventoryWindow = new cInventoryWindow(*this); m_CurrentWindow = m_InventoryWindow; m_InventoryWindow->OpenedByPlayer(*this); SetMaxHealth(MAX_HEALTH); m_Health = MAX_HEALTH; cTimer t1; m_LastPlayerListTime = t1.GetNowTime(); m_TimeLastTeleportPacket = 0; m_TimeLastPickupCheck = 0; m_PlayerName = a_PlayerName; m_bDirtyPosition = true; // So chunks are streamed to player at spawn if (!LoadFromDisk()) { m_Inventory.Clear(); SetPosX(cRoot::Get()->GetDefaultWorld()->GetSpawnX()); SetPosY(cRoot::Get()->GetDefaultWorld()->GetSpawnY()); SetPosZ(cRoot::Get()->GetDefaultWorld()->GetSpawnZ()); LOGD("Player \"%s\" is connecting for the first time, spawning at default world spawn {%.2f, %.2f, %.2f}", a_PlayerName.c_str(), GetPosX(), GetPosY(), GetPosZ() ); } m_LastJumpHeight = (float)(GetPosY()); m_LastGroundHeight = (float)(GetPosY()); m_Stance = GetPosY() + 1.62; cRoot::Get()->GetServer()->PlayerCreated(this); }
bool cPlayer::LoadFromDisk() { LoadPermissionsFromDisk(); // Log player permissions, cause it's what the cool kids do LOGINFO("Player %s has permissions:", m_PlayerName.c_str() ); for( PermissionMap::iterator itr = m_ResolvedPermissions.begin(); itr != m_ResolvedPermissions.end(); ++itr ) { if( itr->second ) LOGINFO("%s", itr->first.c_str() ); } AString SourceFile; Printf(SourceFile, "players/%s.json", m_PlayerName.c_str() ); cFile f; if (!f.Open(SourceFile, cFile::fmRead)) { // This is a new player whom we haven't seen yet, bail out, let them have the defaults return false; } AString buffer; if (f.ReadRestOfFile(buffer) != f.GetSize()) { LOGWARNING("Cannot read player data from file \"%s\"", SourceFile.c_str()); return false; } f.Close(); //cool kids play nice Json::Value root; Json::Reader reader; if (!reader.parse(buffer, root, false)) { LOGWARNING("Cannot parse player data in file \"%s\", player will be reset", SourceFile.c_str()); } Json::Value & JSON_PlayerPosition = root["position"]; if (JSON_PlayerPosition.size() == 3) { SetPosX(JSON_PlayerPosition[(unsigned int)0].asDouble()); SetPosY(JSON_PlayerPosition[(unsigned int)1].asDouble()); SetPosZ(JSON_PlayerPosition[(unsigned int)2].asDouble()); m_LastPosX = GetPosX(); m_LastPosY = GetPosY(); m_LastPosZ = GetPosZ(); m_LastFoodPos = GetPosition(); } Json::Value & JSON_PlayerRotation = root["rotation"]; if (JSON_PlayerRotation.size() == 3) { SetRotation ((float)JSON_PlayerRotation[(unsigned int)0].asDouble()); SetPitch ((float)JSON_PlayerRotation[(unsigned int)1].asDouble()); SetRoll ((float)JSON_PlayerRotation[(unsigned int)2].asDouble()); } m_Health = root.get("health", 0).asInt(); m_AirLevel = root.get("air", MAX_AIR_LEVEL).asInt(); m_FoodLevel = root.get("food", MAX_FOOD_LEVEL).asInt(); m_FoodSaturationLevel = root.get("foodSaturation", MAX_FOOD_LEVEL).asDouble(); m_FoodTickTimer = root.get("foodTickTimer", 0).asInt(); m_FoodExhaustionLevel = root.get("foodExhaustion", 0).asDouble(); m_LifetimeTotalXp = (short) root.get("xpTotal", 0).asInt(); m_CurrentXp = (short) root.get("xpCurrent", 0).asInt(); //SetExperience(root.get("experience", 0).asInt()); m_GameMode = (eGameMode) root.get("gamemode", eGameMode_NotSet).asInt(); m_Inventory.LoadFromJson(root["inventory"]); m_LoadedWorldName = root.get("world", "world").asString(); LOGD("Player \"%s\" was read from file, spawning at {%.2f, %.2f, %.2f} in world \"%s\"", m_PlayerName.c_str(), GetPosX(), GetPosY(), GetPosZ(), m_LoadedWorldName.c_str() ); return true; }
cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName) : super(etPlayer, 0.6, 1.8), m_bVisible(true), m_FoodLevel(MAX_FOOD_LEVEL), m_FoodSaturationLevel(5.0), m_FoodTickTimer(0), m_FoodExhaustionLevel(0.0), m_LastJumpHeight(0), m_LastGroundHeight(0), m_bTouchGround(false), m_Stance(0.0), m_Inventory(*this), m_EnderChestContents(9, 3), m_CurrentWindow(NULL), m_InventoryWindow(NULL), m_GameMode(eGameMode_NotSet), m_IP(""), m_ClientHandle(a_Client), m_NormalMaxSpeed(1.0), m_SprintingMaxSpeed(1.3), m_FlyingMaxSpeed(1.0), m_IsCrouched(false), m_IsSprinting(false), m_IsFlying(false), m_IsSwimming(false), m_IsSubmerged(false), m_IsFishing(false), m_CanFly(false), m_EatingFinishTick(-1), m_LifetimeTotalXp(0), m_CurrentXp(0), m_bDirtyExperience(false), m_IsChargingBow(false), m_BowCharge(0), m_FloaterID(-1), m_Team(NULL), m_TicksUntilNextSave(PLAYER_INVENTORY_SAVE_INTERVAL), m_bIsTeleporting(false), m_UUID((a_Client != NULL) ? a_Client->GetUUID() : "") { m_InventoryWindow = new cInventoryWindow(*this); m_CurrentWindow = m_InventoryWindow; m_InventoryWindow->OpenedByPlayer(*this); SetMaxHealth(MAX_HEALTH); m_Health = MAX_HEALTH; cTimer t1; m_LastPlayerListTime = t1.GetNowTime(); m_PlayerName = a_PlayerName; cWorld * World = NULL; if (!LoadFromDisk(World)) { m_Inventory.Clear(); SetPosX(World->GetSpawnX()); SetPosY(World->GetSpawnY()); SetPosZ(World->GetSpawnZ()); SetBedPos(Vector3i((int)World->GetSpawnX(), (int)World->GetSpawnY(), (int)World->GetSpawnZ())); LOGD("Player \"%s\" is connecting for the first time, spawning at default world spawn {%.2f, %.2f, %.2f}", a_PlayerName.c_str(), GetPosX(), GetPosY(), GetPosZ() ); } m_LastJumpHeight = (float)(GetPosY()); m_LastGroundHeight = (float)(GetPosY()); m_Stance = GetPosY() + 1.62; if (m_GameMode == gmNotSet) { if (World->IsGameModeCreative()) { m_CanFly = true; } } cRoot::Get()->GetServer()->PlayerCreated(this); }
bool cPlayer::LoadFromFile(const AString & a_FileName, cWorldPtr & a_World) { // Load the data from the file: cFile f; if (!f.Open(a_FileName, cFile::fmRead)) { // This is a new player whom we haven't seen yet, bail out, let them have the defaults return false; } AString buffer; if (f.ReadRestOfFile(buffer) != f.GetSize()) { LOGWARNING("Cannot read player data from file \"%s\"", a_FileName.c_str()); return false; } f.Close(); // Parse the JSON format: Json::Value root; Json::Reader reader; if (!reader.parse(buffer, root, false)) { LOGWARNING("Cannot parse player data in file \"%s\"", a_FileName.c_str()); return false; } // Load the player data: Json::Value & JSON_PlayerPosition = root["position"]; if (JSON_PlayerPosition.size() == 3) { SetPosX(JSON_PlayerPosition[(unsigned)0].asDouble()); SetPosY(JSON_PlayerPosition[(unsigned)1].asDouble()); SetPosZ(JSON_PlayerPosition[(unsigned)2].asDouble()); m_LastPos = GetPosition(); } Json::Value & JSON_PlayerRotation = root["rotation"]; if (JSON_PlayerRotation.size() == 3) { SetYaw ((float)JSON_PlayerRotation[(unsigned)0].asDouble()); SetPitch ((float)JSON_PlayerRotation[(unsigned)1].asDouble()); SetRoll ((float)JSON_PlayerRotation[(unsigned)2].asDouble()); } m_Health = root.get("health", 0).asInt(); m_AirLevel = root.get("air", MAX_AIR_LEVEL).asInt(); m_FoodLevel = root.get("food", MAX_FOOD_LEVEL).asInt(); m_FoodSaturationLevel = root.get("foodSaturation", MAX_FOOD_LEVEL).asDouble(); m_FoodTickTimer = root.get("foodTickTimer", 0).asInt(); m_FoodExhaustionLevel = root.get("foodExhaustion", 0).asDouble(); m_LifetimeTotalXp = (short) root.get("xpTotal", 0).asInt(); m_CurrentXp = (short) root.get("xpCurrent", 0).asInt(); m_IsFlying = root.get("isflying", 0).asBool(); m_GameMode = (eGameMode) root.get("gamemode", eGameMode_NotSet).asInt(); if (m_GameMode == eGameMode_Creative) { m_CanFly = true; } m_Inventory.LoadFromJson(root["inventory"]); cEnderChestEntity::LoadFromJson(root["enderchestinventory"], m_EnderChestContents); m_LoadedWorldName = root.get("world", "world").asString(); a_World = cRoot::Get()->GetWorld(GetLoadedWorldName(), false); if (a_World == NULL) { a_World = cRoot::Get()->GetDefaultWorld(); } m_LastBedPos.x = root.get("SpawnX", a_World->GetSpawnX()).asInt(); m_LastBedPos.y = root.get("SpawnY", a_World->GetSpawnY()).asInt(); m_LastBedPos.z = root.get("SpawnZ", a_World->GetSpawnZ()).asInt(); // Load the player stats. // We use the default world name (like bukkit) because stats are shared between dimensions/worlds. cStatSerializer StatSerializer(cRoot::Get()->GetDefaultWorld()->GetName(), GetName(), &m_Stats); StatSerializer.Load(); LOGD("Player %s was read from file \"%s\", spawning at {%.2f, %.2f, %.2f} in world \"%s\"", GetName().c_str(), a_FileName.c_str(), GetPosX(), GetPosY(), GetPosZ(), a_World->GetName().c_str() ); return true; }
void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) { // TODO Add collision detection with entities. a_Dt /= 1000; Vector3d NextPos = Vector3d(GetPosX(),GetPosY(),GetPosZ()); Vector3d NextSpeed = Vector3d(GetSpeedX(),GetSpeedY(),GetSpeedZ()); int BlockX = (int) floor(NextPos.x); int BlockY = (int) floor(NextPos.y); int BlockZ = (int) floor(NextPos.z); if ((BlockY >= cChunkDef::Height) || (BlockY < 0)) { // Outside of the world // TODO: Current speed should still be added to the entity position // Otherwise TNT explosions in the void will still effect the bottommost layers of the world return; } // Make sure we got the correct chunk and a valid one. No one ever knows... cChunk * NextChunk = a_Chunk.GetNeighborChunk(BlockX,BlockZ); if (NextChunk != NULL) { int RelBlockX = BlockX - (NextChunk->GetPosX() * cChunkDef::Width); int RelBlockZ = BlockZ - (NextChunk->GetPosZ() * cChunkDef::Width); BLOCKTYPE BlockIn = NextChunk->GetBlock( RelBlockX, BlockY, RelBlockZ ); if (!g_BlockIsSolid[BlockIn]) // Making sure we are not inside a solid block { if (m_bOnGround) // check if it's still on the ground { BLOCKTYPE BlockBelow = NextChunk->GetBlock( RelBlockX, BlockY - 1, RelBlockZ ); if (!g_BlockIsSolid[BlockBelow]) // Check if block below is air or water. { m_bOnGround = false; } } } else { //Push out entity. m_bOnGround = true; NextPos.y += 0.2; LOGD("Entity #%d (%s) is inside a block at {%d,%d,%d}", m_UniqueID, GetClass(), BlockX, BlockY, BlockZ); } if (!m_bOnGround) { float fallspeed; if (IsBlockWater(BlockIn)) { fallspeed = -3.0f * a_Dt; //Fall slower in water. } else if (BlockIn == E_BLOCK_COBWEB) { NextSpeed.y *= 0.05; //Reduce overall falling speed fallspeed = 0; //No falling. } else { //Normal gravity fallspeed = m_Gravity * a_Dt; } NextSpeed.y += fallspeed; } else { //Friction 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; } } //Adjust X and Z speed for COBWEB temporary. This speed modification should be handled inside block handlers since we //might have different speed modifiers according to terrain. if (BlockIn == E_BLOCK_COBWEB) { NextSpeed.x *= 0.25; NextSpeed.z *= 0.25; } //Get water direction Direction WaterDir = m_World->GetWaterSimulator()->GetFlowingDirection(BlockX, BlockY, BlockZ); m_WaterSpeed *= 0.9f; //Reduce speed each tick switch(WaterDir) { case X_PLUS: m_WaterSpeed.x = 1.f; m_bOnGround = false; break; case X_MINUS: m_WaterSpeed.x = -1.f; m_bOnGround = false; break; case Z_PLUS: m_WaterSpeed.z = 1.f; m_bOnGround = false; break; case Z_MINUS: m_WaterSpeed.z = -1.f; m_bOnGround = false; break; default: break; } if (fabs(m_WaterSpeed.x) < 0.05) { m_WaterSpeed.x = 0; } if (fabs(m_WaterSpeed.z) < 0.05) { m_WaterSpeed.z = 0; } NextSpeed += m_WaterSpeed; if( NextSpeed.SqrLength() > 0.f ) { cTracer Tracer( GetWorld() ); int Ret = Tracer.Trace( NextPos, NextSpeed, 2 ); if( Ret ) // Oh noez! we hit something { // Set to hit position if( (Tracer.RealHit - NextPos).SqrLength() <= ( NextSpeed * a_Dt ).SqrLength() ) { if( Ret == 1 ) { if( Tracer.HitNormal.x != 0.f ) NextSpeed.x = 0.f; if( Tracer.HitNormal.y != 0.f ) NextSpeed.y = 0.f; if( Tracer.HitNormal.z != 0.f ) NextSpeed.z = 0.f; if( Tracer.HitNormal.y > 0 ) // means on ground { m_bOnGround = true; } } NextPos.Set(Tracer.RealHit.x,Tracer.RealHit.y,Tracer.RealHit.z); NextPos.x += Tracer.HitNormal.x * 0.5f; NextPos.z += Tracer.HitNormal.z * 0.5f; } else NextPos += (NextSpeed * a_Dt); } else { // We didn't hit anything, so move =] NextPos += (NextSpeed * a_Dt); } } BlockX = (int) floor(NextPos.x); BlockZ = (int) floor(NextPos.z); NextChunk = NextChunk->GetNeighborChunk(BlockX,BlockZ); // See if we can commit our changes. If not, we will discard them. if (NextChunk != NULL) { if (NextPos.x != GetPosX()) SetPosX(NextPos.x); if (NextPos.y != GetPosY()) SetPosY(NextPos.y); if (NextPos.z != GetPosZ()) SetPosZ(NextPos.z); if (NextSpeed.x != GetSpeedX()) SetSpeedX(NextSpeed.x); if (NextSpeed.y != GetSpeedY()) SetSpeedY(NextSpeed.y); if (NextSpeed.z != GetSpeedZ()) SetSpeedZ(NextSpeed.z); } } }
void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) { // TODO Add collision detection with entities. a_Dt /= 1000; // Convert from msec to sec Vector3d NextPos = Vector3d(GetPosX(),GetPosY(),GetPosZ()); Vector3d NextSpeed = Vector3d(GetSpeedX(),GetSpeedY(),GetSpeedZ()); int BlockX = (int) floor(NextPos.x); int BlockY = (int) floor(NextPos.y); int BlockZ = (int) floor(NextPos.z); if ((BlockY >= cChunkDef::Height) || (BlockY < 0)) { // Outside of the world cChunk * NextChunk = a_Chunk.GetNeighborChunk(BlockX, BlockZ); // See if we can commit our changes. If not, we will discard them. if (NextChunk != NULL) { SetSpeed(NextSpeed); NextPos += (NextSpeed * a_Dt); SetPosition(NextPos); } return; } // Make sure we got the correct chunk and a valid one. No one ever knows... cChunk * NextChunk = a_Chunk.GetNeighborChunk(BlockX, BlockZ); if (NextChunk != NULL) { int RelBlockX = BlockX - (NextChunk->GetPosX() * cChunkDef::Width); int RelBlockZ = BlockZ - (NextChunk->GetPosZ() * cChunkDef::Width); BLOCKTYPE BlockIn = NextChunk->GetBlock( RelBlockX, BlockY, RelBlockZ ); BLOCKTYPE BlockBelow = (BlockY > 0) ? NextChunk->GetBlock(RelBlockX, BlockY - 1, RelBlockZ) : E_BLOCK_AIR; if (!g_BlockIsSolid[BlockIn]) // Making sure we are not inside a solid block { if (m_bOnGround) // check if it's still on the ground { if (!g_BlockIsSolid[BlockBelow]) // Check if block below is air or water. { m_bOnGround = false; } } } else { // Push out entity. BLOCKTYPE GotBlock; static const struct { int x, y, z; } gCrossCoords[] = { { 1, 0, 0}, {-1, 0, 0}, { 0, 0, 1}, { 0, 0, -1}, } ; bool IsNoAirSurrounding = true; for (int i = 0; i < ARRAYCOUNT(gCrossCoords); i++) { if (!NextChunk->UnboundedRelGetBlockType(RelBlockX + gCrossCoords[i].x, BlockY, RelBlockZ + gCrossCoords[i].z, GotBlock)) { // The pickup is too close to an unloaded chunk, bail out of any physics handling return; } if (!g_BlockIsSolid[GotBlock]) { NextPos.x += gCrossCoords[i].x; NextPos.z += gCrossCoords[i].z; IsNoAirSurrounding = false; break; } } // for i - gCrossCoords[] if (IsNoAirSurrounding) { NextPos.y += 0.5; } m_bOnGround = true; LOGD("Entity #%d (%s) is inside a block at {%d, %d, %d}", m_UniqueID, GetClass(), BlockX, BlockY, BlockZ ); } if (!m_bOnGround) { float fallspeed; if (IsBlockWater(BlockIn)) { 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 fallspeed = 0; // No falling. } else { // Normal gravity fallspeed = m_Gravity * a_Dt; } NextSpeed.y += fallspeed; } else { if (IsMinecart()) { if (!IsBlockRail(BlockBelow)) { // 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; } } } } else { // Friction for non-minecarts 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; } } } } // Adjust X and Z speed for COBWEB temporary. This speed modification should be handled inside block handlers since we // might have different speed modifiers according to terrain. if (BlockIn == E_BLOCK_COBWEB) { NextSpeed.x *= 0.25; NextSpeed.z *= 0.25; } //Get water direction Direction WaterDir = m_World->GetWaterSimulator()->GetFlowingDirection(BlockX, BlockY, BlockZ); m_WaterSpeed *= 0.9f; //Reduce speed each tick switch(WaterDir) { case X_PLUS: m_WaterSpeed.x = 0.2f; m_bOnGround = false; break; case X_MINUS: m_WaterSpeed.x = -0.2f; m_bOnGround = false; break; case Z_PLUS: m_WaterSpeed.z = 0.2f; m_bOnGround = false; break; case Z_MINUS: m_WaterSpeed.z = -0.2f; m_bOnGround = false; break; default: break; } if (fabs(m_WaterSpeed.x) < 0.05) { m_WaterSpeed.x = 0; } if (fabs(m_WaterSpeed.z) < 0.05) { m_WaterSpeed.z = 0; } NextSpeed += m_WaterSpeed; if( NextSpeed.SqrLength() > 0.f ) { cTracer Tracer( GetWorld() ); int Ret = Tracer.Trace( NextPos, NextSpeed, 2 ); if( Ret ) // Oh noez! we hit something { // Set to hit position if( (Tracer.RealHit - NextPos).SqrLength() <= ( NextSpeed * a_Dt ).SqrLength() ) { if( Ret == 1 ) { if( Tracer.HitNormal.x != 0.f ) NextSpeed.x = 0.f; if( Tracer.HitNormal.y != 0.f ) NextSpeed.y = 0.f; if( Tracer.HitNormal.z != 0.f ) NextSpeed.z = 0.f; if( Tracer.HitNormal.y > 0 ) // means on ground { m_bOnGround = true; } } NextPos.Set(Tracer.RealHit.x,Tracer.RealHit.y,Tracer.RealHit.z); NextPos.x += Tracer.HitNormal.x * 0.3f; NextPos.y += Tracer.HitNormal.y * 0.05f; // Any larger produces entity vibration-upon-the-spot NextPos.z += Tracer.HitNormal.z * 0.3f; } else { NextPos += (NextSpeed * a_Dt); } } else { // We didn't hit anything, so move =] NextPos += (NextSpeed * a_Dt); } } BlockX = (int) floor(NextPos.x); BlockZ = (int) floor(NextPos.z); NextChunk = NextChunk->GetNeighborChunk(BlockX,BlockZ); // See if we can commit our changes. If not, we will discard them. if (NextChunk != NULL) { if (NextPos.x != GetPosX()) SetPosX(NextPos.x); if (NextPos.y != GetPosY()) SetPosY(NextPos.y); if (NextPos.z != GetPosZ()) SetPosZ(NextPos.z); if (NextSpeed.x != GetSpeedX()) SetSpeedX(NextSpeed.x); if (NextSpeed.y != GetSpeedY()) SetSpeedY(NextSpeed.y); if (NextSpeed.z != GetSpeedZ()) SetSpeedZ(NextSpeed.z); } } }