Merge branch 'master' into PreventNewWarnings
This commit is contained in:
24
.travis.yml
24
.travis.yml
@@ -1,39 +1,27 @@
|
||||
language: cpp
|
||||
compiler: clang
|
||||
|
||||
compiler:
|
||||
- clang
|
||||
- gcc
|
||||
|
||||
before_install:
|
||||
# - if [ "$TRAVIS_MCSERVER_BUILD_TYPE" == "COVERAGE" ]; then sudo pip install cpp_coveralls; fi
|
||||
|
||||
# g++4.8
|
||||
- sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
||||
- sudo apt-get update -qq
|
||||
|
||||
install:
|
||||
# g++4.8 and clang
|
||||
- sudo apt-get install -qq g++-4.8
|
||||
- sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 90
|
||||
- sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 90
|
||||
|
||||
# lua, needed for style checking and possibly later on for bindings generation
|
||||
- sudo apt-get install -qq lua5.1
|
||||
|
||||
# g++4.8
|
||||
- if [ "$CXX" == "g++" ]; then export CXX="g++-4.8"; export CC="gcc-4.8"; fi
|
||||
|
||||
# Build MCServer
|
||||
script: ./CIbuild.sh
|
||||
|
||||
#after_success:
|
||||
# - ./uploadCoverage.sh
|
||||
|
||||
env:
|
||||
- TRAVIS_MCSERVER_BUILD_TYPE=RELEASE MCSERVER_PATH=./MCServer
|
||||
- TRAVIS_MCSERVER_BUILD_TYPE=DEBUG MCSERVER_PATH=./MCServer_debug
|
||||
|
||||
#matrix:
|
||||
# include:
|
||||
# - compiler: gcc
|
||||
# env: TRAVIS_MCSERVER_BUILD_TYPE=COVERAGE MCSERVER_PATH=./MCServer
|
||||
|
||||
# Notification Settings
|
||||
notifications:
|
||||
email:
|
||||
on_success: change
|
||||
|
||||
@@ -24,9 +24,10 @@ p-mcgowan
|
||||
rs2k
|
||||
SafwatHalaby (Safwat Halaby)
|
||||
SamJBarney
|
||||
Seadragon91 (Lukas Pioch)
|
||||
Sofapriester
|
||||
SphinxC0re
|
||||
STR_Warrior
|
||||
NiLSPACE (formerly STR_Warrior)
|
||||
structinf (xdot)
|
||||
Sxw1212
|
||||
Taugeshtu
|
||||
@@ -35,7 +36,7 @@ tonibm19
|
||||
UltraCoderRU
|
||||
WebFreak001
|
||||
worktycho
|
||||
xoft
|
||||
xoft (Mattes Dolak/madmaxoft on GH)
|
||||
Yeeeeezus (Donated AlchemistVillage prefabs)
|
||||
|
||||
Please add yourself to this list if you contribute to MCServer.
|
||||
|
||||
@@ -815,7 +815,7 @@ rawrabbit=411
|
||||
cookedrabbit=412
|
||||
rabbitstew=413
|
||||
rabbitsoup=413
|
||||
rabbitsfood=414
|
||||
rabbitsfoot=414
|
||||
rabbithide=415
|
||||
armorstand=416
|
||||
ironhorsearmor=417
|
||||
|
||||
@@ -22,7 +22,11 @@ For Windows, you just need to download a file and extract it:
|
||||
- [Windows 32 bit](http://builds.cuberite.org/job/MCServer%20Windows%20x86/lastSuccessfulBuild/artifact/Install/MCServer.zip)
|
||||
- [Windows 64 bit](http://builds.cuberite.org/job/MCServer%20Windows%20x64/lastSuccessfulBuild/artifact/Install/MCServer.zip)
|
||||
|
||||
For other operating systems you need to download and compile yourself. There is also an archive of binary builds on the buildserver: http://builds.cuberite.org
|
||||
For other operating systems you need to download and compile yourself. This can be done either manually, or with this automatic script:
|
||||
|
||||
bash -c "$(wget -O - https://raw.githubusercontent.com/mc-server/MCServer/master/compile.sh)"
|
||||
|
||||
There is also an archive of binary builds on the buildserver: http://builds.cuberite.org
|
||||
|
||||
Compiling the server yourself has other benefits: you may get better performance performance (1.5-3x as fast) and it supports more operating systems. See the [COMPILING.md](https://github.com/mc-server/MCServer/blob/master/COMPILING.md) file for more details.
|
||||
|
||||
|
||||
199
compile.sh
Executable file
199
compile.sh
Executable file
@@ -0,0 +1,199 @@
|
||||
#|| goto :windows_detected
|
||||
|
||||
# Do we already have a repo?
|
||||
if [[ -d .git && -f easyinstall.sh && -f MakeLuaAPI.cmd ]]; then # A good enough indicator that we're in the MCServer git repo.
|
||||
cd ../
|
||||
echo "MCServer repository detected. This should make the process faster, especially if you compiled before."
|
||||
fi
|
||||
|
||||
# Error functions.
|
||||
function error
|
||||
{
|
||||
echo
|
||||
echo "-----------------"
|
||||
echo "Script aborted, reason:"
|
||||
echo $1
|
||||
exit -1
|
||||
}
|
||||
|
||||
function missingDepsExit
|
||||
{
|
||||
echo
|
||||
echo "Please install the dependencies, then come back."
|
||||
echo
|
||||
exit -2
|
||||
}
|
||||
|
||||
|
||||
# Echo: Greetings.
|
||||
echo
|
||||
echo "Hello, this script will download and compile Cuberite/MCServer."
|
||||
echo "On subsequent runs, it will update your MCServer."
|
||||
echo "The compilation and download will occur in the current directory."
|
||||
echo "If you're updating, you should run <Path to MCServer>/MCServer/compile.sh"
|
||||
echo "Compiling from source takes time, but it usually generates better executables."
|
||||
echo "If you prefer ready-to-use binaries or if you want more info, please visit:"
|
||||
echo "http://cuberite.org/"
|
||||
echo "http://mc-server.org/"
|
||||
|
||||
MISSING_PROGRAMS=""
|
||||
|
||||
# Compiler check.
|
||||
GCC_EXISTS=0
|
||||
CLANG_EXISTS=0
|
||||
g++ --help > /dev/null 2> /dev/null && GCC_EXISTS=1
|
||||
clang --help > /dev/null 2> /dev/null && CLANG_EXISTS=1
|
||||
if [[ $GCC_EXISTS == 0 && $CLANG_EXISTS == 0 ]]; then
|
||||
MISSING_PROGRAMS="gcc g++"
|
||||
fi
|
||||
|
||||
# Depdendency check.
|
||||
while read program; do
|
||||
$program --help > /dev/null 2> /dev/null || MISSING_PROGRAMS="$MISSING_PROGRAMS $program"
|
||||
done <<"EOF"
|
||||
git
|
||||
make
|
||||
cmake
|
||||
EOF
|
||||
if [[ $MISSING_PROGRAMS != "" ]]; then
|
||||
echo
|
||||
echo "-----------------"
|
||||
echo "You have missing compilation dependencies:"
|
||||
echo $MISSING_PROGRAMS
|
||||
echo
|
||||
|
||||
# apt-get guide.
|
||||
apt-get --help > /dev/null 2> /dev/null && \
|
||||
echo "You can install the missing depndencies via:" && \
|
||||
echo -n "sudo apt-get install " && echo $MISSING_PROGRAMS && missingDepsExit
|
||||
|
||||
# yum guide.
|
||||
yum --help > /dev/null 2> /dev/null && \
|
||||
echo "You can install the missing depndencies via:" && \
|
||||
echo -n "sudo yum install " && echo $MISSING_PROGRAMS && missingDepsExit
|
||||
|
||||
# rpm guide.
|
||||
rpm --help > /dev/null 2> /dev/null && \
|
||||
echo "You can install the missing depndencies via:" && \
|
||||
echo -n "sudo rpm -i " && echo $MISSING_PROGRAMS && missingDepsExit
|
||||
|
||||
# pacman guide.
|
||||
pacman --help > /dev/null 2> /dev/null && \
|
||||
echo "You can install the missing depndencies via:" && \
|
||||
echo -n "sudo pacman -S " && echo $MISSING_PROGRAMS && missingDepsExit
|
||||
|
||||
missingDepsExit
|
||||
fi
|
||||
|
||||
exit
|
||||
# Echo: Branch choice.
|
||||
echo
|
||||
echo "You can choose between 2 branches:"
|
||||
echo "* (S)Stable: (Coming soon) Choose the stable branch if you want the most reliable server."
|
||||
echo " As of now, Stable is not yet available, please use testing instead."
|
||||
echo
|
||||
echo "* (T)Testing: The testing branch is less stable,"
|
||||
echo " but using it and finding and reporting bugs helps us a lot!"
|
||||
echo
|
||||
echo "* (D)Dev: The least stable of the three. (Master branch)"
|
||||
echo " Choose the development branch if you are feeling adventurous and"
|
||||
echo " want to try new, bleeding edge features."
|
||||
echo
|
||||
|
||||
|
||||
# Input: Branch choice.
|
||||
echo -n "Choose the branch (s/t/d): "
|
||||
read BRANCH
|
||||
if [[ ($BRANCH == "s") || ($BRANCH == "S" ) ]]; then
|
||||
#BRANCH="stable"
|
||||
error "We don't have a stable branch yet, please use testing, sorry."
|
||||
elif [[ ($BRANCH == "t") || ($BRANCH == "T" ) ]]; then
|
||||
BRANCH="testing"
|
||||
elif [[ ($BRANCH == "d") || ($BRANCH == "D" ) ]]; then
|
||||
BRANCH="master"
|
||||
else
|
||||
error "Unrecognized user input."
|
||||
fi
|
||||
|
||||
# Echo: Compile mode choice.
|
||||
echo
|
||||
echo "Choose compile mode:"
|
||||
echo "* (N)Normal: Compiles normally."
|
||||
echo
|
||||
echo "* (D)Debug: Compiles in debug mode. Makes your console and crashes much more verbose."
|
||||
echo " But it costs performance."
|
||||
echo
|
||||
echo "Note that the script will connect to the internet in order to fetch code after this step."
|
||||
echo "It will then compile your program."
|
||||
echo
|
||||
|
||||
# Input: Compile mode choice.
|
||||
echo -n "Choose compile mode: (n/d): "
|
||||
read BUILDTYPE
|
||||
if [[ ($BUILDTYPE == "d") || ($BUILDTYPE == "D") ]]; then
|
||||
BUILDTYPE="Debug"
|
||||
elif [[ ($BUILDTYPE == "n") || ($BUILDTYPE == "N") ]]; then
|
||||
BUILDTYPE="Release"
|
||||
else
|
||||
error "Unrecognized user input."
|
||||
fi
|
||||
|
||||
|
||||
# Echo: Downloading began.
|
||||
echo
|
||||
echo " --- Downloading MCServer's source code from the $BRANCH branch..."
|
||||
|
||||
|
||||
# Git: Clone.
|
||||
if [ ! -d MCServer ]; then
|
||||
echo " --- Looks like your first run, cloning the whole code..."
|
||||
git clone https://github.com/mc-server/MCServer.git
|
||||
fi
|
||||
|
||||
|
||||
# Git: Fetch.
|
||||
pushd MCServer
|
||||
echo " --- Updating the $BRANCH branch..."
|
||||
git fetch origin $BRANCH || error "git fetch failed"
|
||||
git checkout $BRANCH || error "git checkout failed"
|
||||
git merge origin/$BRANCH || error "git merge failed"
|
||||
|
||||
|
||||
# Git: Submodules.
|
||||
echo " --- Updating submodules..."
|
||||
git submodule init
|
||||
git submodule update
|
||||
|
||||
|
||||
# Cmake.
|
||||
echo " --- Running cmake..."
|
||||
popd
|
||||
if [ ! -d build-mcserver ]; then mkdir build-mcserver; fi
|
||||
pushd build-mcserver
|
||||
cmake ../MCServer/ -DCMAKE_BUILD_TYPE=$BUILDTYPE || error "cmake failed"
|
||||
|
||||
|
||||
# Make.
|
||||
echo " --- Compiling..."
|
||||
make -j`nproc` || error "Compiling failed"
|
||||
echo
|
||||
|
||||
|
||||
# Echo: Compilation complete.
|
||||
popd
|
||||
pushd MCServer/MCServer
|
||||
echo
|
||||
echo "-----------------"
|
||||
echo "Compilation done!"
|
||||
echo
|
||||
echo "Cuberite awaits you at:"
|
||||
echo "`pwd`/MCServer"
|
||||
echo
|
||||
echo "Enjoy :)"
|
||||
popd
|
||||
exit 0
|
||||
|
||||
:windows_detected
|
||||
echo "This script is not available for Windows yet, sorry."
|
||||
echo "You can still download the Windows binaries from: http://mc-server.org"
|
||||
|
||||
@@ -94,7 +94,7 @@ cPlayer::cPlayer(cClientHandlePtr a_Client, const AString & a_PlayerName) :
|
||||
|
||||
SetMaxHealth(MAX_HEALTH);
|
||||
m_Health = MAX_HEALTH;
|
||||
|
||||
|
||||
m_LastPlayerListTime = std::chrono::steady_clock::now();
|
||||
m_PlayerName = a_PlayerName;
|
||||
|
||||
@@ -106,7 +106,7 @@ cPlayer::cPlayer(cClientHandlePtr a_Client, const AString & a_PlayerName) :
|
||||
SetPosY(World->GetSpawnY());
|
||||
SetPosZ(World->GetSpawnZ());
|
||||
SetBedPos(Vector3i(static_cast<int>(World->GetSpawnX()), static_cast<int>(World->GetSpawnY()), static_cast<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()
|
||||
);
|
||||
@@ -135,7 +135,7 @@ cPlayer::cPlayer(cClientHandlePtr a_Client, const AString & a_PlayerName) :
|
||||
m_IsFlying = true;
|
||||
m_bVisible = false;
|
||||
}
|
||||
|
||||
|
||||
cRoot::Get()->GetServer()->PlayerCreated(this);
|
||||
}
|
||||
|
||||
@@ -152,17 +152,17 @@ cPlayer::~cPlayer(void)
|
||||
}
|
||||
|
||||
LOGD("Deleting cPlayer \"%s\" at %p, ID %d", GetName().c_str(), this, GetUniqueID());
|
||||
|
||||
|
||||
// Notify the server that the player is being destroyed
|
||||
cRoot::Get()->GetServer()->PlayerDestroying(this);
|
||||
|
||||
SaveToDisk();
|
||||
|
||||
m_ClientHandle = nullptr;
|
||||
|
||||
|
||||
delete m_InventoryWindow;
|
||||
m_InventoryWindow = nullptr;
|
||||
|
||||
|
||||
LOGD("Player %p deleted", this);
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@ void cPlayer::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
|
||||
m_ClientHandle = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (!m_ClientHandle->IsPlaying())
|
||||
{
|
||||
// We're not yet in the game, ignore everything
|
||||
@@ -217,21 +217,21 @@ void cPlayer::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
|
||||
}
|
||||
|
||||
m_Stats.AddValue(statMinutesPlayed, 1);
|
||||
|
||||
|
||||
if (!a_Chunk.IsValid())
|
||||
{
|
||||
// This may happen if the cPlayer is created before the chunks have the chance of being loaded / generated (#83)
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
super::Tick(a_Dt, a_Chunk);
|
||||
|
||||
|
||||
// Handle charging the bow:
|
||||
if (m_IsChargingBow)
|
||||
{
|
||||
m_BowCharge += 1;
|
||||
}
|
||||
|
||||
|
||||
// Handle updating experience
|
||||
if (m_bDirtyExperience)
|
||||
{
|
||||
@@ -243,7 +243,7 @@ void cPlayer::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
|
||||
{
|
||||
// Apply food exhaustion from movement:
|
||||
ApplyFoodExhaustionFromMovement();
|
||||
|
||||
|
||||
if (cRoot::Get()->GetPluginManager()->CallHookPlayerMoving(*this, m_LastPos, GetPosition()))
|
||||
{
|
||||
CanMove = false;
|
||||
@@ -264,10 +264,10 @@ void cPlayer::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
|
||||
{
|
||||
FinishEating();
|
||||
}
|
||||
|
||||
|
||||
HandleFood();
|
||||
}
|
||||
|
||||
|
||||
if (m_IsFishing)
|
||||
{
|
||||
HandleFloater();
|
||||
@@ -467,7 +467,7 @@ void cPlayer::SetTouchGround(bool a_bTouchGround)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
m_bTouchGround = a_bTouchGround;
|
||||
|
||||
if (!m_bTouchGround)
|
||||
@@ -516,7 +516,7 @@ void cPlayer::SetTouchGround(bool a_bTouchGround)
|
||||
{
|
||||
// cPlayer makes sure damage isn't applied in creative, no need to check here
|
||||
TakeDamage(dtFalling, nullptr, Damage, Damage, 0);
|
||||
|
||||
|
||||
// Fall particles
|
||||
GetWorld()->BroadcastSoundParticleEffect(2006, POSX_TOINT, static_cast<int>(GetPosY()) - 1, POSZ_TOINT, Damage /* Used as particle effect speed modifier */);
|
||||
}
|
||||
@@ -548,7 +548,7 @@ void cPlayer::SetFoodLevel(int a_FoodLevel)
|
||||
m_FoodSaturationLevel = 5.0;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
m_FoodLevel = FoodLevel;
|
||||
SendHealth();
|
||||
}
|
||||
@@ -616,7 +616,7 @@ void cPlayer::StartEating(void)
|
||||
{
|
||||
// Set the timer:
|
||||
m_EatingFinishTick = m_World->GetWorldAge() + EATING_TICKS;
|
||||
|
||||
|
||||
// Send the packets:
|
||||
m_World->BroadcastEntityAnimation(*this, 3);
|
||||
m_World->BroadcastEntityMetadata(*this);
|
||||
@@ -630,7 +630,7 @@ void cPlayer::FinishEating(void)
|
||||
{
|
||||
// Reset the timer:
|
||||
m_EatingFinishTick = -1;
|
||||
|
||||
|
||||
// Send the packets:
|
||||
m_ClientHandle->SendEntityStatus(*this, esPlayerEatingAccepted);
|
||||
m_World->BroadcastEntityMetadata(*this);
|
||||
@@ -764,7 +764,7 @@ void cPlayer::SetSprintingMaxSpeed(double a_Speed)
|
||||
void cPlayer::SetFlyingMaxSpeed(double a_Speed)
|
||||
{
|
||||
m_FlyingMaxSpeed = a_Speed;
|
||||
|
||||
|
||||
// Update the flying speed, always:
|
||||
m_ClientHandle->SendPlayerAbilities();
|
||||
}
|
||||
@@ -776,7 +776,7 @@ void cPlayer::SetFlyingMaxSpeed(double a_Speed)
|
||||
void cPlayer::SetCrouch(bool a_IsCrouched)
|
||||
{
|
||||
// Set the crouch status, broadcast to all visible players
|
||||
|
||||
|
||||
if (a_IsCrouched == m_IsCrouched)
|
||||
{
|
||||
// No change
|
||||
@@ -797,7 +797,7 @@ void cPlayer::SetSprint(bool a_IsSprinting)
|
||||
// No change
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
m_IsSprinting = a_IsSprinting;
|
||||
m_ClientHandle->SendPlayerMaxSpeed();
|
||||
}
|
||||
@@ -883,7 +883,7 @@ bool cPlayer::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (super::DoTakeDamage(a_TDI))
|
||||
{
|
||||
// Any kind of damage adds food exhaustion
|
||||
@@ -1012,7 +1012,7 @@ void cPlayer::Respawn(void)
|
||||
|
||||
m_Health = GetMaxHealth();
|
||||
SetInvulnerableTicks(20);
|
||||
|
||||
|
||||
// Reset food level:
|
||||
m_FoodLevel = MAX_FOOD_LEVEL;
|
||||
m_FoodSaturationLevel = 5.0;
|
||||
@@ -1024,7 +1024,7 @@ void cPlayer::Respawn(void)
|
||||
// ToDo: send score to client? How?
|
||||
|
||||
m_ClientHandle->SendRespawn(GetWorld()->GetDimension(), true);
|
||||
|
||||
|
||||
// Extinguish the fire:
|
||||
StopBurning();
|
||||
|
||||
@@ -1158,7 +1158,7 @@ void cPlayer::CloseWindow(bool a_CanRefuse)
|
||||
m_CurrentWindow = m_InventoryWindow;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (m_CurrentWindow->ClosedByPlayer(*this, a_CanRefuse) || !a_CanRefuse)
|
||||
{
|
||||
// Close accepted, go back to inventory window (the default):
|
||||
@@ -1196,30 +1196,17 @@ void cPlayer::SetGameMode(eGameMode a_GameMode)
|
||||
LOGWARNING("%s: Setting invalid gamemode: %d", GetName().c_str(), a_GameMode);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (m_GameMode == a_GameMode)
|
||||
{
|
||||
// Gamemode already set
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
m_GameMode = a_GameMode;
|
||||
m_ClientHandle->SendGameMode(a_GameMode);
|
||||
|
||||
if (!(IsGameModeCreative() || IsGameModeSpectator()))
|
||||
{
|
||||
SetFlying(false);
|
||||
SetCanFly(false);
|
||||
}
|
||||
|
||||
if (IsGameModeSpectator() && IsVisible())
|
||||
{
|
||||
SetVisible(false);
|
||||
}
|
||||
else if (!IsVisible())
|
||||
{
|
||||
SetVisible(true);
|
||||
}
|
||||
SetCapabilities();
|
||||
|
||||
m_World->BroadcastPlayerListUpdateGameMode(*this);
|
||||
}
|
||||
@@ -1231,6 +1218,30 @@ void cPlayer::SetGameMode(eGameMode a_GameMode)
|
||||
void cPlayer::LoginSetGameMode( eGameMode a_GameMode)
|
||||
{
|
||||
m_GameMode = a_GameMode;
|
||||
|
||||
SetCapabilities();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cPlayer::SetCapabilities()
|
||||
{
|
||||
if (!IsGameModeCreative() || IsGameModeSpectator())
|
||||
{
|
||||
SetFlying(false);
|
||||
SetCanFly(false);
|
||||
}
|
||||
|
||||
if (IsGameModeSpectator())
|
||||
{
|
||||
SetVisible(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetVisible(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1322,12 +1333,12 @@ void cPlayer::SendRotation(double a_YawDegrees, double a_PitchDegrees)
|
||||
Vector3d cPlayer::GetThrowStartPos(void) const
|
||||
{
|
||||
Vector3d res = GetEyePosition();
|
||||
|
||||
|
||||
// Adjust the position to be just outside the player's bounding box:
|
||||
res.x += 0.16 * cos(GetPitch());
|
||||
res.y += -0.1;
|
||||
res.z += 0.16 * sin(GetPitch());
|
||||
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -1339,9 +1350,9 @@ Vector3d cPlayer::GetThrowSpeed(double a_SpeedCoeff) const
|
||||
{
|
||||
Vector3d res = GetLookVector();
|
||||
res.Normalize();
|
||||
|
||||
|
||||
// TODO: Add a slight random change (+-0.0075 in each direction)
|
||||
|
||||
|
||||
return res * a_SpeedCoeff;
|
||||
}
|
||||
|
||||
@@ -1386,13 +1397,13 @@ void cPlayer::MoveTo( const Vector3d & a_NewPos)
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// TODO: should do some checks to see if player is not moving through terrain
|
||||
// TODO: Official server refuses position packets too far away from each other, kicking "hacked" clients; we should, too
|
||||
|
||||
Vector3d DeltaPos = a_NewPos - GetPosition();
|
||||
UpdateMovementStats(DeltaPos);
|
||||
|
||||
|
||||
SetPosition( a_NewPos);
|
||||
SetStance(a_NewPos.y + 1.62);
|
||||
}
|
||||
@@ -1427,7 +1438,7 @@ bool cPlayer::HasPermission(const AString & a_Permission)
|
||||
// Empty permission request is always granted
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
AStringVector Split = StringSplit(a_Permission, ".");
|
||||
|
||||
// Iterate over all restrictions; if any matches, then return failure:
|
||||
@@ -1599,7 +1610,7 @@ void cPlayer::TossItems(const cItems & a_Items)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
m_Stats.AddValue(statItemsDropped, (StatValue)a_Items.Size());
|
||||
|
||||
double vX = 0, vY = 0, vZ = 0;
|
||||
@@ -1621,7 +1632,7 @@ bool cPlayer::DoMoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn)
|
||||
// Don't move to same world
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Ask the plugins if the player is allowed to changing the world
|
||||
if (cRoot::Get()->GetPluginManager()->CallHookEntityChangingWorld(*this, *a_World))
|
||||
{
|
||||
@@ -1658,7 +1669,7 @@ bool cPlayer::DoMoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn)
|
||||
|
||||
// Broadcast the player into the new world.
|
||||
a_World->BroadcastSpawnEntity(*this);
|
||||
|
||||
|
||||
// Player changed the world, call the hook
|
||||
cRoot::Get()->GetPluginManager()->CallHookEntityChangedWorld(*this, *OldWorld);
|
||||
|
||||
@@ -1678,7 +1689,7 @@ bool cPlayer::LoadFromDisk(cWorldPtr & a_World)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Load from the offline UUID file, if allowed:
|
||||
AString OfflineUUID = cClientHandle::GenerateOfflineUUID(GetName());
|
||||
const char * OfflineUsage = " (unused)";
|
||||
@@ -1690,7 +1701,7 @@ bool cPlayer::LoadFromDisk(cWorldPtr & a_World)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Load from the old-style name-based file, if allowed:
|
||||
if (cRoot::Get()->GetServer()->ShouldLoadNamedPlayerData())
|
||||
{
|
||||
@@ -1705,7 +1716,7 @@ bool cPlayer::LoadFromDisk(cWorldPtr & a_World)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// None of the files loaded successfully
|
||||
LOG("Player data file not found for %s (%s, offline %s%s), will be reset to defaults.",
|
||||
GetName().c_str(), m_UUID.c_str(), OfflineUUID.c_str(), OfflineUsage
|
||||
@@ -1782,7 +1793,7 @@ bool cPlayer::LoadFromFile(const AString & a_FileName, cWorldPtr & a_World)
|
||||
{
|
||||
m_CanFly = true;
|
||||
}
|
||||
|
||||
|
||||
m_Inventory.LoadFromJson(root["inventory"]);
|
||||
cEnderChestEntity::LoadFromJson(root["enderchestinventory"], m_EnderChestContents);
|
||||
|
||||
@@ -1801,11 +1812,11 @@ bool cPlayer::LoadFromFile(const AString & a_FileName, cWorldPtr & a_World)
|
||||
// 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;
|
||||
}
|
||||
|
||||
@@ -2161,7 +2172,7 @@ void cPlayer::ApplyFoodExhaustionFromMovement()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Calculate the distance travelled, update the last pos:
|
||||
Vector3d Movement(GetPosition() - m_LastPos);
|
||||
Movement.y = 0; // Only take XZ movement into account
|
||||
@@ -2364,7 +2375,7 @@ AString cPlayer::GetUUIDFileName(const AString & a_UUID)
|
||||
{
|
||||
AString UUID = cMojangAPI::MakeUUIDDashed(a_UUID);
|
||||
ASSERT(UUID.length() == 36);
|
||||
|
||||
|
||||
AString res("players/");
|
||||
res.append(UUID, 0, 2);
|
||||
res.push_back('/');
|
||||
@@ -2372,7 +2383,3 @@ AString cPlayer::GetUUIDFileName(const AString & a_UUID)
|
||||
res.append(".json");
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -26,42 +26,42 @@ class cPlayer :
|
||||
public cPawn
|
||||
{
|
||||
typedef cPawn super;
|
||||
|
||||
|
||||
public:
|
||||
static const int MAX_HEALTH;
|
||||
|
||||
|
||||
static const int MAX_FOOD_LEVEL;
|
||||
|
||||
|
||||
/** Number of ticks it takes to eat an item */
|
||||
static const int EATING_TICKS;
|
||||
|
||||
|
||||
// tolua_end
|
||||
|
||||
|
||||
CLASS_PROTODEF(cPlayer)
|
||||
|
||||
|
||||
|
||||
cPlayer(cClientHandlePtr a_Client, const AString & a_PlayerName);
|
||||
|
||||
|
||||
virtual ~cPlayer();
|
||||
|
||||
virtual void SpawnOn(cClientHandle & a_Client) override;
|
||||
|
||||
|
||||
virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
|
||||
|
||||
virtual void HandlePhysics(std::chrono::milliseconds a_Dt, cChunk &) override { UNUSED(a_Dt); }
|
||||
|
||||
/** Returns the curently equipped weapon; empty item if none */
|
||||
virtual cItem GetEquippedWeapon(void) const override { return m_Inventory.GetEquippedItem(); }
|
||||
|
||||
|
||||
/** Returns the currently equipped helmet; empty item if none */
|
||||
virtual cItem GetEquippedHelmet(void) const override { return m_Inventory.GetEquippedHelmet(); }
|
||||
|
||||
|
||||
/** Returns the currently equipped chestplate; empty item if none */
|
||||
virtual cItem GetEquippedChestplate(void) const override { return m_Inventory.GetEquippedChestplate(); }
|
||||
|
||||
/** Returns the currently equipped leggings; empty item if none */
|
||||
virtual cItem GetEquippedLeggings(void) const override { return m_Inventory.GetEquippedLeggings(); }
|
||||
|
||||
|
||||
/** Returns the currently equipped boots; empty item if none */
|
||||
virtual cItem GetEquippedBoots(void) const override { return m_Inventory.GetEquippedBoots(); }
|
||||
|
||||
@@ -104,16 +104,16 @@ public:
|
||||
static int CalcLevelFromXp(int a_CurrentXp);
|
||||
|
||||
// tolua_end
|
||||
|
||||
|
||||
/** Starts charging the equipped bow */
|
||||
void StartChargingBow(void);
|
||||
|
||||
|
||||
/** Finishes charging the current bow. Returns the number of ticks for which the bow has been charged */
|
||||
int FinishChargingBow(void);
|
||||
|
||||
|
||||
/** Cancels the current bow charging */
|
||||
void CancelChargingBow(void);
|
||||
|
||||
|
||||
/** Returns true if the player is currently charging the bow */
|
||||
bool IsChargingBow(void) const { return m_IsChargingBow; }
|
||||
|
||||
@@ -128,7 +128,7 @@ public:
|
||||
|
||||
/** Gets the contents of the player's associated enderchest */
|
||||
cItemGrid & GetEnderChestContents(void) { return m_EnderChestContents; }
|
||||
|
||||
|
||||
inline const cItem & GetEquippedItem(void) const { return GetInventory().GetEquippedItem(); } // tolua_export
|
||||
|
||||
/** Returns whether the player is climbing (ladders, vines etc.) */
|
||||
@@ -137,43 +137,49 @@ public:
|
||||
virtual void TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ) override;
|
||||
|
||||
// tolua_begin
|
||||
|
||||
|
||||
/** Sends the "look" packet to the player, forcing them to set their rotation to the specified values.
|
||||
a_YawDegrees is clipped to range [-180, +180),
|
||||
a_PitchDegrees is clipped to range [-180, +180) but the client only uses [-90, +90]
|
||||
*/
|
||||
void SendRotation(double a_YawDegrees, double a_PitchDegrees);
|
||||
|
||||
|
||||
/** Returns the position where projectiles thrown by this player should start, player eye position + adjustment */
|
||||
Vector3d GetThrowStartPos(void) const;
|
||||
|
||||
|
||||
/** Returns the initial speed vector of a throw, with a 3D length of a_SpeedCoeff. */
|
||||
Vector3d GetThrowSpeed(double a_SpeedCoeff) const;
|
||||
|
||||
|
||||
/** Returns the current gamemode. Partly OBSOLETE, you should use IsGameModeXXX() functions wherever applicable */
|
||||
eGameMode GetGameMode(void) const { return m_GameMode; }
|
||||
|
||||
|
||||
/** Returns the current effective gamemode (inherited gamemode is resolved before returning) */
|
||||
eGameMode GetEffectiveGameMode(void) const { return (m_GameMode == gmNotSet) ? m_World->GetGameMode() : m_GameMode; }
|
||||
|
||||
|
||||
/** Sets the gamemode for the player.
|
||||
The gamemode may be gmNotSet, in that case the player inherits the world's gamemode.
|
||||
Updates the gamemode on the client (sends the packet)
|
||||
*/
|
||||
void SetGameMode(eGameMode a_GameMode);
|
||||
|
||||
// Sets the current gamemode, doesn't check validity, doesn't send update packets to client
|
||||
void LoginSetGameMode(eGameMode a_GameMode);
|
||||
|
||||
// Updates player's capabilities - flying, visibility, etc. from their gamemode.
|
||||
void SetCapabilities();
|
||||
|
||||
/** Returns true if the player is in Creative mode, either explicitly, or by inheriting from current world */
|
||||
bool IsGameModeCreative(void) const;
|
||||
|
||||
|
||||
/** Returns true if the player is in Survival mode, either explicitly, or by inheriting from current world */
|
||||
bool IsGameModeSurvival(void) const;
|
||||
|
||||
|
||||
/** Returns true if the player is in Adventure mode, either explicitly, or by inheriting from current world */
|
||||
bool IsGameModeAdventure(void) const;
|
||||
|
||||
|
||||
/** Returns true if the player is in Spectator mode, either explicitly, or by inheriting from current world */
|
||||
bool IsGameModeSpectator(void) const;
|
||||
|
||||
|
||||
AString GetIP(void) const { return m_IP; } // tolua_export
|
||||
|
||||
/** Returns the associated team, nullptr if none */
|
||||
@@ -195,11 +201,8 @@ public:
|
||||
If the achievement has been already awarded to the player, this method will just increment the stat counter.
|
||||
Returns the _new_ stat value. (0 = Could not award achievement) */
|
||||
unsigned int AwardAchievement(const eStatistic a_Ach);
|
||||
|
||||
|
||||
void SetIP(const AString & a_IP);
|
||||
|
||||
// Sets the current gamemode, doesn't check validity, doesn't send update packets to client
|
||||
void LoginSetGameMode(eGameMode a_GameMode);
|
||||
|
||||
/** Forces the player to move in the given direction.
|
||||
@deprecated Use SetSpeed instead. */
|
||||
@@ -210,15 +213,15 @@ public:
|
||||
|
||||
cWindow * GetWindow(void) { return m_CurrentWindow; } // tolua_export
|
||||
const cWindow * GetWindow(void) const { return m_CurrentWindow; }
|
||||
|
||||
|
||||
/** Opens the specified window; closes the current one first using CloseWindow() */
|
||||
void OpenWindow(cWindow * a_Window); // Exported in ManualBindings.cpp
|
||||
|
||||
|
||||
// tolua_begin
|
||||
|
||||
|
||||
/** Closes the current window, resets current window to m_InventoryWindow. A plugin may refuse the closing if a_CanRefuse is true */
|
||||
void CloseWindow(bool a_CanRefuse = true);
|
||||
|
||||
|
||||
/** Closes the current window if it matches the specified ID, resets current window to m_InventoryWindow */
|
||||
void CloseWindowIfID(char a_WindowID, bool a_CanRefuse = true);
|
||||
|
||||
@@ -243,7 +246,7 @@ public:
|
||||
|
||||
const AString & GetName(void) const { return m_PlayerName; }
|
||||
void SetName(const AString & a_Name) { m_PlayerName = a_Name; }
|
||||
|
||||
|
||||
// tolua_end
|
||||
|
||||
bool HasPermission(const AString & a_Permission); // tolua_export
|
||||
@@ -260,7 +263,7 @@ public:
|
||||
const AStringVector & GetRestrictions(void) const { return m_Restrictions; } // Exported in ManualBindings.cpp
|
||||
|
||||
// tolua_begin
|
||||
|
||||
|
||||
/** Returns the full color code to use for this player, based on their rank.
|
||||
The returned value either is empty, or includes the cChatColor::Delimiter. */
|
||||
AString GetColor(void) const;
|
||||
@@ -279,15 +282,15 @@ public:
|
||||
|
||||
/** Heals the player by the specified amount of HPs (positive only); sends health update */
|
||||
virtual void Heal(int a_Health) override;
|
||||
|
||||
|
||||
int GetFoodLevel (void) const { return m_FoodLevel; }
|
||||
double GetFoodSaturationLevel (void) const { return m_FoodSaturationLevel; }
|
||||
int GetFoodTickTimer (void) const { return m_FoodTickTimer; }
|
||||
double GetFoodExhaustionLevel (void) const { return m_FoodExhaustionLevel; }
|
||||
|
||||
|
||||
/** Returns true if the player is satiated, i. e. their foodlevel is at the max and they cannot eat anymore */
|
||||
bool IsSatiated(void) const { return (m_FoodLevel >= MAX_FOOD_LEVEL); }
|
||||
|
||||
|
||||
void SetFoodLevel (int a_FoodLevel);
|
||||
void SetFoodSaturationLevel (double a_FoodSaturationLevel);
|
||||
void SetFoodTickTimer (int a_FoodTickTimer);
|
||||
@@ -298,10 +301,10 @@ public:
|
||||
|
||||
/** Adds the specified exhaustion to m_FoodExhaustion. Expects only positive values. */
|
||||
void AddFoodExhaustion(double a_Exhaustion);
|
||||
|
||||
|
||||
/** Returns true if the player is currently in the process of eating the currently equipped item */
|
||||
bool IsEating(void) const { return (m_EatingFinishTick >= 0); }
|
||||
|
||||
|
||||
/** Returns true if the player is currently flying. */
|
||||
bool IsFlying(void) const { return m_IsFlying; }
|
||||
|
||||
@@ -329,16 +332,16 @@ public:
|
||||
GetWorld()->BroadcastEntityAnimation(*this, 2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Starts eating the currently equipped item. Resets the eating timer and sends the proper animation packet */
|
||||
void StartEating(void);
|
||||
|
||||
|
||||
/** Finishes eating the currently equipped item. Consumes the item, updates health and broadcasts the packets */
|
||||
void FinishEating(void);
|
||||
|
||||
|
||||
/** Aborts the current eating operation */
|
||||
void AbortEating(void);
|
||||
|
||||
|
||||
virtual void KilledBy(TakeDamageInfo & a_TDI) override;
|
||||
|
||||
virtual void Killed(cEntity * a_Victim) override;
|
||||
@@ -356,69 +359,69 @@ public:
|
||||
bool SaveToDisk(void);
|
||||
|
||||
typedef cWorld * cWorldPtr;
|
||||
|
||||
|
||||
/** Loads the player data from the disk file
|
||||
Sets a_World to the world where the player will spawn, based on the stored world name or the default world by calling LoadFromFile()
|
||||
Returns true on success, false on failure
|
||||
*/
|
||||
bool LoadFromDisk(cWorldPtr & a_World);
|
||||
|
||||
|
||||
/** Loads the player data from the specified file
|
||||
Sets a_World to the world where the player will spawn, based on the stored world name or the default world
|
||||
Returns true on success, false on failure
|
||||
*/
|
||||
bool LoadFromFile(const AString & a_FileName, cWorldPtr & a_World);
|
||||
|
||||
|
||||
const AString & GetLoadedWorldName() { return m_LoadedWorldName; }
|
||||
|
||||
void UseEquippedItem(int a_Amount = 1);
|
||||
|
||||
|
||||
void SendHealth(void);
|
||||
|
||||
void SendExperience(void);
|
||||
|
||||
|
||||
/** In UI windows, get the item that the player is dragging */
|
||||
cItem & GetDraggingItem(void) {return m_DraggingItem; }
|
||||
|
||||
|
||||
// In UI windows, when inventory-painting:
|
||||
/** Clears the list of slots that are being inventory-painted. To be used by cWindow only */
|
||||
void ClearInventoryPaintSlots(void);
|
||||
|
||||
|
||||
/** Adds a slot to the list for inventory painting. To be used by cWindow only */
|
||||
void AddInventoryPaintSlot(int a_SlotNum);
|
||||
|
||||
|
||||
/** Returns the list of slots currently stored for inventory painting. To be used by cWindow only */
|
||||
const cSlotNums & GetInventoryPaintSlots(void) const;
|
||||
|
||||
|
||||
// tolua_begin
|
||||
|
||||
|
||||
/** Returns the current relative maximum speed (takes current sprinting / flying state into account) */
|
||||
double GetMaxSpeed(void) const;
|
||||
|
||||
|
||||
/** Gets the normal relative maximum speed */
|
||||
double GetNormalMaxSpeed(void) const { return m_NormalMaxSpeed; }
|
||||
|
||||
|
||||
/** Gets the sprinting relative maximum speed */
|
||||
double GetSprintingMaxSpeed(void) const { return m_SprintingMaxSpeed; }
|
||||
|
||||
|
||||
/** Gets the flying relative maximum speed */
|
||||
double GetFlyingMaxSpeed(void) const { return m_FlyingMaxSpeed; }
|
||||
|
||||
|
||||
/** Sets the normal relative maximum speed. Sends the update to player, if needed. */
|
||||
void SetNormalMaxSpeed(double a_Speed);
|
||||
|
||||
|
||||
/** Sets the sprinting relative maximum speed. Sends the update to player, if needed. */
|
||||
void SetSprintingMaxSpeed(double a_Speed);
|
||||
|
||||
|
||||
/** Sets the flying relative maximum speed. Sends the update to player, if needed. */
|
||||
void SetFlyingMaxSpeed(double a_Speed);
|
||||
|
||||
|
||||
/** Sets the crouch status, broadcasts to all visible players */
|
||||
void SetCrouch(bool a_IsCrouched);
|
||||
|
||||
|
||||
/** Starts or stops sprinting, sends the max speed update to the client, if needed */
|
||||
void SetSprint(bool a_IsSprinting);
|
||||
|
||||
|
||||
/** Flags the player as flying */
|
||||
void SetFlying(bool a_IsFlying);
|
||||
|
||||
@@ -442,17 +445,17 @@ public:
|
||||
|
||||
/** Sets the player's bed (home) position */
|
||||
void SetBedPos(const Vector3i & a_Pos) { m_LastBedPos = a_Pos; }
|
||||
|
||||
|
||||
// tolua_end
|
||||
|
||||
/** Update movement-related statistics. */
|
||||
void UpdateMovementStats(const Vector3d & a_DeltaPos);
|
||||
|
||||
|
||||
// tolua_begin
|
||||
|
||||
/** Returns wheter the player can fly or not. */
|
||||
virtual bool CanFly(void) const { return m_CanFly; }
|
||||
|
||||
|
||||
/** Returns the UUID (short format) that has been read from the client, or empty string if not available. */
|
||||
const AString & GetUUID(void) const { return m_UUID; }
|
||||
|
||||
@@ -492,7 +495,7 @@ public:
|
||||
/** Called by cClientHandle when the client is being destroyed.
|
||||
The player removes its m_ClientHandle ownership so that the ClientHandle gets deleted. */
|
||||
void RemoveClientHandle(void);
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
typedef std::vector<std::vector<AString> > AStringVectorVector;
|
||||
@@ -535,16 +538,16 @@ protected:
|
||||
// Food-related variables:
|
||||
/** Represents the food bar, one point equals half a "drumstick" */
|
||||
int m_FoodLevel;
|
||||
|
||||
|
||||
/** "Overcharge" for the m_FoodLevel; is depleted before m_FoodLevel */
|
||||
double m_FoodSaturationLevel;
|
||||
|
||||
|
||||
/** Count-up to the healing or damaging action, based on m_FoodLevel */
|
||||
int m_FoodTickTimer;
|
||||
|
||||
|
||||
/** A "buffer" which adds up hunger before it is substracted from m_FoodSaturationLevel or m_FoodLevel. Each action adds a little */
|
||||
double m_FoodExhaustionLevel;
|
||||
|
||||
|
||||
float m_LastJumpHeight;
|
||||
float m_LastGroundHeight;
|
||||
bool m_bTouchGround;
|
||||
@@ -564,31 +567,31 @@ protected:
|
||||
|
||||
eGameMode m_GameMode;
|
||||
AString m_IP;
|
||||
|
||||
|
||||
/** The item being dragged by the cursor while in a UI window */
|
||||
cItem m_DraggingItem;
|
||||
|
||||
std::chrono::steady_clock::time_point m_LastPlayerListTime;
|
||||
|
||||
cClientHandlePtr m_ClientHandle;
|
||||
|
||||
|
||||
cSlotNums m_InventoryPaintSlots;
|
||||
|
||||
|
||||
/** Max speed, relative to the game default.
|
||||
1 means regular speed, 2 means twice as fast, 0.5 means half-speed.
|
||||
Default value is 1. */
|
||||
double m_NormalMaxSpeed;
|
||||
|
||||
|
||||
/** Max speed, relative to the game default max speed, when sprinting.
|
||||
1 means regular speed, 2 means twice as fast, 0.5 means half-speed.
|
||||
Default value is 1.3. */
|
||||
double m_SprintingMaxSpeed;
|
||||
|
||||
|
||||
/** Max speed, relative to the game default flying max speed, when flying.
|
||||
1 means regular speed, 2 means twice as fast, 0.5 means half-speed.
|
||||
Default value is 1. */
|
||||
double m_FlyingMaxSpeed;
|
||||
|
||||
|
||||
bool m_IsCrouched;
|
||||
bool m_IsSprinting;
|
||||
bool m_IsFlying;
|
||||
@@ -629,7 +632,7 @@ protected:
|
||||
Will not apply food penalties if found to be true; will set to false after processing
|
||||
*/
|
||||
bool m_bIsTeleporting;
|
||||
|
||||
|
||||
/** The short UUID (no dashes) of the player, as read from the ClientHandle.
|
||||
If no ClientHandle is given, the UUID is initialized to empty. */
|
||||
AString m_UUID;
|
||||
@@ -649,7 +652,7 @@ protected:
|
||||
|
||||
/** Stops players from burning in creative mode */
|
||||
virtual void TickBurning(cChunk & a_Chunk) override;
|
||||
|
||||
|
||||
/** Called in each tick to handle food-related processing */
|
||||
void HandleFood(void);
|
||||
|
||||
@@ -666,7 +669,3 @@ protected:
|
||||
This can be used both for online and offline UUIDs. */
|
||||
AString GetUUIDFileName(const AString & a_UUID);
|
||||
} ; // tolua_export
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1259,7 +1259,7 @@ bool cFinishGenPassiveMobs::TrySpawnAnimals(cChunkDesc & a_ChunkDesc, int a_RelX
|
||||
}
|
||||
if (
|
||||
(BlockUnderFeet != E_BLOCK_GRASS) &&
|
||||
((AnimalToSpawn == mtSheep) || (AnimalToSpawn == mtChicken) || (AnimalToSpawn == mtPig))
|
||||
((AnimalToSpawn == mtWolf) || (AnimalToSpawn == mtRabbit) || (AnimalToSpawn == mtCow) || (AnimalToSpawn == mtSheep) || (AnimalToSpawn == mtChicken) || (AnimalToSpawn == mtPig))
|
||||
)
|
||||
{
|
||||
return false;
|
||||
|
||||
@@ -80,6 +80,13 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check to see if destination block is too far away
|
||||
// Reach Distance Multiplayer = 5 Blocks
|
||||
if ((BlockPos.x - a_Player->GetPosX() > 5) || (BlockPos.z - a_Player->GetPosZ() > 5))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remove water / lava block (unless plugins disagree)
|
||||
if (!a_Player->PlaceBlock(BlockPos.x, BlockPos.y, BlockPos.z, E_BLOCK_AIR, 0))
|
||||
{
|
||||
@@ -126,6 +133,13 @@ public:
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check to see if destination block is too far away
|
||||
// Reach Distance Multiplayer = 5 Blocks
|
||||
if ((BlockPos.x - a_Player->GetPosX() > 5) || (BlockPos.z - a_Player->GetPosZ() > 5))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (a_Player->GetGameMode() != gmCreative)
|
||||
{
|
||||
|
||||
@@ -169,7 +169,7 @@ bool cMonster::TickPathFinding(cChunk & a_Chunk)
|
||||
m_NoPathToTarget = false;
|
||||
m_NoMoreWayPoints = false;
|
||||
m_PathFinderDestination = m_FinalDestination;
|
||||
m_Path = new cPath(a_Chunk, GetPosition().Floor(), m_PathFinderDestination.Floor(), 20);
|
||||
m_Path = new cPath(a_Chunk, GetPosition(), m_PathFinderDestination, 20, GetWidth(), GetHeight());
|
||||
}
|
||||
|
||||
switch (m_Path->Step(a_Chunk))
|
||||
@@ -183,7 +183,7 @@ bool cMonster::TickPathFinding(cChunk & a_Chunk)
|
||||
|
||||
case ePathFinderStatus::PATH_NOT_FOUND:
|
||||
{
|
||||
ResetPathFinding(); // Try to calculate a path again.
|
||||
StopMovingToPosition(); // Try to calculate a path again.
|
||||
// Note that the next time may succeed, e.g. if a player breaks a barrier.
|
||||
break;
|
||||
}
|
||||
@@ -203,7 +203,7 @@ bool cMonster::TickPathFinding(cChunk & a_Chunk)
|
||||
{
|
||||
if ((m_Path->IsFirstPoint() || ReachedNextWaypoint()))
|
||||
{
|
||||
m_NextWayPointPosition = Vector3d(0.5, 0, 0.5) + m_Path->GetNextPoint();
|
||||
m_NextWayPointPosition = m_Path->GetNextPoint();
|
||||
m_GiveUpCounter = 40; // Give up after 40 ticks (2 seconds) if failed to reach m_NextWayPointPosition.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "Path.h"
|
||||
#include "../Chunk.h"
|
||||
|
||||
#define JUMP_G_COST 20
|
||||
|
||||
#define DISTANCE_MANHATTAN 0 // 1: More speed, a bit less accuracy 0: Max accuracy, less speed.
|
||||
#define HEURISTICS_ONLY 0 // 1: Much more speed, much less accurate.
|
||||
@@ -31,12 +32,11 @@ bool compareHeuristics::operator()(cPathCell * & a_Cell1, cPathCell * & a_Cell2)
|
||||
/* cPath implementation */
|
||||
cPath::cPath(
|
||||
cChunk & a_Chunk,
|
||||
const Vector3i & a_StartingPoint, const Vector3i & a_EndingPoint, int a_MaxSteps,
|
||||
const Vector3d & a_StartingPoint, const Vector3d & a_EndingPoint, int a_MaxSteps,
|
||||
double a_BoundingBoxWidth, double a_BoundingBoxHeight,
|
||||
int a_MaxUp, int a_MaxDown
|
||||
) :
|
||||
m_Destination(a_EndingPoint.Floor()),
|
||||
m_Source(a_StartingPoint.Floor()),
|
||||
|
||||
m_CurrentPoint(0), // GetNextPoint increments this to 1, but that's fine, since the first cell is always a_StartingPoint
|
||||
m_Chunk(&a_Chunk),
|
||||
m_BadChunkFound(false)
|
||||
@@ -44,6 +44,21 @@ cPath::cPath(
|
||||
// TODO: if src not walkable OR dest not walkable, then abort.
|
||||
// Borrow a new "isWalkable" from ProcessIfWalkable, make ProcessIfWalkable also call isWalkable
|
||||
|
||||
a_BoundingBoxWidth = 1; // Until we improve physics, if ever.
|
||||
|
||||
m_BoundingBoxWidth = ceil(a_BoundingBoxWidth);
|
||||
m_BoundingBoxHeight = ceil(a_BoundingBoxHeight);
|
||||
m_HalfWidth = a_BoundingBoxWidth / 2;
|
||||
|
||||
int HalfWidthInt = a_BoundingBoxWidth / 2;
|
||||
m_Source.x = floor(a_StartingPoint.x - HalfWidthInt);
|
||||
m_Source.y = floor(a_StartingPoint.y);
|
||||
m_Source.z = floor(a_StartingPoint.z - HalfWidthInt);
|
||||
|
||||
m_Destination.x = floor(a_EndingPoint.x - HalfWidthInt);
|
||||
m_Destination.y = floor(a_EndingPoint.y);
|
||||
m_Destination.z = floor(a_EndingPoint.z - HalfWidthInt);
|
||||
|
||||
if (GetCell(m_Source)->m_IsSolid || GetCell(m_Destination)->m_IsSolid)
|
||||
{
|
||||
m_Status = ePathFinderStatus::PATH_NOT_FOUND;
|
||||
@@ -148,7 +163,7 @@ bool cPath::IsSolid(const Vector3i & a_Location)
|
||||
}
|
||||
if (BlockType == E_BLOCK_STATIONARY_WATER)
|
||||
{
|
||||
GetCell(a_Location + Vector3i(0, -1, 0))->m_IsSolid = true; // Mobs will always think that the fence is 2 blocks high and therefore won't jump over.
|
||||
GetCell(a_Location + Vector3i(0, -1, 0))->m_IsSolid = true;
|
||||
}
|
||||
|
||||
return cBlockInfo::IsSolid(BlockType);
|
||||
@@ -179,7 +194,7 @@ bool cPath::Step_Internal()
|
||||
|
||||
// Calculation not finished yet.
|
||||
// Check if we have a new NearestPoint.
|
||||
|
||||
// TODO I don't like this that much, there should be a smarter way.
|
||||
if ((m_Destination - CurrentCell->m_Location).Length() < 5)
|
||||
{
|
||||
if (m_Rand.NextInt(4) == 0)
|
||||
@@ -193,21 +208,43 @@ bool cPath::Step_Internal()
|
||||
}
|
||||
// process a currentCell by inspecting all neighbors.
|
||||
|
||||
// Check North, South, East, West on all 3 different heights.
|
||||
int i;
|
||||
for (i = -1; i <= 1; ++i)
|
||||
|
||||
// Check North, South, East, West on our height.
|
||||
ProcessIfWalkable(CurrentCell->m_Location + Vector3i(1, 0, 0), CurrentCell, 10);
|
||||
ProcessIfWalkable(CurrentCell->m_Location + Vector3i(-1, 0, 0), CurrentCell, 10);
|
||||
ProcessIfWalkable(CurrentCell->m_Location + Vector3i(0, 0, 1), CurrentCell, 10);
|
||||
ProcessIfWalkable(CurrentCell->m_Location + Vector3i(0, 0, -1), CurrentCell, 10);
|
||||
|
||||
// Check diagonals on XY plane.
|
||||
for (int x = -1; x <= 1; x += 2)
|
||||
{
|
||||
ProcessIfWalkable(CurrentCell->m_Location + Vector3i(1, i, 0), CurrentCell, 10);
|
||||
ProcessIfWalkable(CurrentCell->m_Location + Vector3i(-1, i, 0), CurrentCell, 10);
|
||||
ProcessIfWalkable(CurrentCell->m_Location + Vector3i(0, i, 1), CurrentCell, 10);
|
||||
ProcessIfWalkable(CurrentCell->m_Location + Vector3i(0, i, -1), CurrentCell, 10);
|
||||
if (GetCell(CurrentCell->m_Location + Vector3i(x, 0, 0))->m_IsSolid) // If there's a solid our east / west.
|
||||
{
|
||||
ProcessIfWalkable(CurrentCell->m_Location + Vector3i(x, 1, 0), CurrentCell, JUMP_G_COST); // Check east / west-up.
|
||||
}
|
||||
else
|
||||
{
|
||||
ProcessIfWalkable(CurrentCell->m_Location + Vector3i(x, -1, 0), CurrentCell, 14); // Else check east / west-down.
|
||||
}
|
||||
}
|
||||
|
||||
// Check diagonals on mob's height only.
|
||||
int x, z;
|
||||
for (x = -1; x <= 1; x += 2)
|
||||
// Check diagonals on the YZ plane.
|
||||
for (int z = -1; z <= 1; z += 2)
|
||||
{
|
||||
for (z = -1; z <= 1; z += 2)
|
||||
if (GetCell(CurrentCell->m_Location + Vector3i(0, 0, z))->m_IsSolid) // If there's a solid our east / west.
|
||||
{
|
||||
ProcessIfWalkable(CurrentCell->m_Location + Vector3i(0, 1, z), CurrentCell, JUMP_G_COST); // Check east / west-up.
|
||||
}
|
||||
else
|
||||
{
|
||||
ProcessIfWalkable(CurrentCell->m_Location + Vector3i(0, -1, z), CurrentCell, 14); // Else check east / west-down.
|
||||
}
|
||||
}
|
||||
|
||||
// Check diagonals on the XZ plane. (Normal diagonals, this plane is special because of gravity, etc)
|
||||
for (int x = -1; x <= 1; x += 2)
|
||||
{
|
||||
for (int z = -1; z <= 1; z += 2)
|
||||
{
|
||||
// This condition prevents diagonal corner cutting.
|
||||
if (!GetCell(CurrentCell->m_Location + Vector3i(x, 0, 0))->m_IsSolid && !GetCell(CurrentCell->m_Location + Vector3i(0, 0, z))->m_IsSolid)
|
||||
@@ -320,7 +357,53 @@ si::setBlock((Ret)->m_Location.x, (Ret)->m_Location.y, (Ret)->m_Location.z, debu
|
||||
void cPath::ProcessIfWalkable(const Vector3i & a_Location, cPathCell * a_Parent, int a_Cost)
|
||||
{
|
||||
cPathCell * cell = GetCell(a_Location);
|
||||
if (!cell->m_IsSolid && GetCell(a_Location + Vector3i(0, -1, 0))->m_IsSolid && !GetCell(a_Location + Vector3i(0, 1, 0))->m_IsSolid)
|
||||
int x, y, z;
|
||||
|
||||
// Make sure we fit in the position.
|
||||
for (y = 0; y < m_BoundingBoxHeight; ++y)
|
||||
{
|
||||
for (x = 0; x < m_BoundingBoxWidth; ++x)
|
||||
{
|
||||
for (z = 0; z < m_BoundingBoxWidth; ++z)
|
||||
{
|
||||
if (GetCell(a_Location + Vector3i(x, y, z))->m_IsSolid)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*y =-1;
|
||||
for (x = 0; x < m_BoundingBoxWidth; ++x)
|
||||
{
|
||||
for (z = 0; z < m_BoundingBoxWidth; ++z)
|
||||
{
|
||||
if (!GetCell(a_Location + Vector3i(x, y, z))->m_IsSolid)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
ProcessCell(cell, a_Parent, a_Cost);*/
|
||||
|
||||
// Make sure there's at least 1 piece of solid below us.
|
||||
|
||||
bool GroundFlag = false;
|
||||
y =-1;
|
||||
for (x = 0; x < m_BoundingBoxWidth; ++x)
|
||||
{
|
||||
for (z = 0; z < m_BoundingBoxWidth; ++z)
|
||||
{
|
||||
if (GetCell(a_Location + Vector3i(x, y, z))->m_IsSolid)
|
||||
{
|
||||
GroundFlag = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (GroundFlag)
|
||||
{
|
||||
ProcessCell(cell, a_Parent, a_Cost);
|
||||
}
|
||||
|
||||
@@ -68,8 +68,8 @@ public:
|
||||
@param a_MaxSteps The maximum steps before giving up. */
|
||||
cPath(
|
||||
cChunk & a_Chunk,
|
||||
const Vector3i & a_StartingPoint, const Vector3i & a_EndingPoint, int a_MaxSteps,
|
||||
double a_BoundingBoxWidth = 1, double a_BoundingBoxHeight = 2,
|
||||
const Vector3d & a_StartingPoint, const Vector3d & a_EndingPoint, int a_MaxSteps,
|
||||
double a_BoundingBoxWidth, double a_BoundingBoxHeight,
|
||||
int a_MaxUp = 1, int a_MaxDown = 1
|
||||
);
|
||||
|
||||
@@ -89,10 +89,11 @@ public:
|
||||
|
||||
/* Point retrieval functions, inlined for performance. */
|
||||
/** Returns the next point in the path. */
|
||||
inline Vector3i GetNextPoint()
|
||||
inline Vector3d GetNextPoint()
|
||||
{
|
||||
ASSERT(m_Status == ePathFinderStatus::PATH_FOUND);
|
||||
return m_PathPoints[m_PathPoints.size() - 1 - (++m_CurrentPoint)];
|
||||
Vector3i Point = m_PathPoints[m_PathPoints.size() - 1 - (++m_CurrentPoint)];
|
||||
return Vector3d(Point.x + m_HalfWidth, Point.y, Point.z + m_HalfWidth);
|
||||
}
|
||||
/** Checks whether this is the last point or not. Never call getnextPoint when this is true. */
|
||||
inline bool IsLastPoint()
|
||||
@@ -106,11 +107,12 @@ public:
|
||||
return (m_CurrentPoint == 0);
|
||||
}
|
||||
/** Get the point at a_index. Remark: Internally, the indexes are reversed. */
|
||||
inline Vector3i GetPoint(size_t a_index)
|
||||
inline Vector3d GetPoint(size_t a_index)
|
||||
{
|
||||
ASSERT(m_Status == ePathFinderStatus::PATH_FOUND);
|
||||
ASSERT(a_index < m_PathPoints.size());
|
||||
return m_PathPoints[m_PathPoints.size() - 1 - a_index];
|
||||
Vector3i Point = m_PathPoints[m_PathPoints.size() - 1 - a_index];
|
||||
return Vector3d(Point.x + m_HalfWidth, Point.y, Point.z + m_HalfWidth);
|
||||
}
|
||||
/** Returns the total number of points this path has. */
|
||||
inline size_t GetPointCount()
|
||||
@@ -161,6 +163,9 @@ private:
|
||||
std::unordered_map<Vector3i, cPathCell, VectorHasher> m_Map;
|
||||
Vector3i m_Destination;
|
||||
Vector3i m_Source;
|
||||
int m_BoundingBoxWidth;
|
||||
int m_BoundingBoxHeight;
|
||||
double m_HalfWidth;
|
||||
int m_StepsLeft;
|
||||
cPathCell * m_NearestPointToTarget;
|
||||
cFastRandom m_Rand;
|
||||
|
||||
Reference in New Issue
Block a user