diff options
-rw-r--r-- | .gitignore | 6 | ||||
-rw-r--r-- | .gitmodules | 6 | ||||
-rw-r--r-- | .travis.yml | 12 | ||||
-rw-r--r-- | COMPILING | 1 | ||||
-rw-r--r-- | CONTRIBUTING.md | 4 | ||||
-rw-r--r-- | README.md | 2 | ||||
-rw-r--r-- | VC2008/MCServer.vcproj | 12 | ||||
-rw-r--r-- | src/Bindings/PluginManager.cpp | 25 | ||||
-rw-r--r-- | src/Bindings/PluginManager.h | 7 | ||||
-rw-r--r-- | src/ClientHandle.cpp | 23 | ||||
-rw-r--r-- | src/Entities/Entity.h | 3 | ||||
-rw-r--r-- | src/Entities/Floater.cpp | 58 | ||||
-rw-r--r-- | src/Entities/Floater.h | 29 | ||||
-rw-r--r-- | src/Entities/Player.cpp | 2 | ||||
-rw-r--r-- | src/Entities/Player.h | 10 | ||||
-rw-r--r-- | src/Items/ItemFishingRod.h | 78 | ||||
-rw-r--r-- | src/Items/ItemHandler.cpp | 2 |
17 files changed, 261 insertions, 19 deletions
diff --git a/.gitignore b/.gitignore index b0ad11d53..c65e6b8f6 100644 --- a/.gitignore +++ b/.gitignore @@ -11,9 +11,11 @@ cloc.xsl *.user *.suo /EveryNight.cmd -*.sublime-* -# emacs stuff +# IDE Stuff +## Sublime Text +*.sublime-* +## emacs *.*~ # world inside source diff --git a/.gitmodules b/.gitmodules index 088271457..028471319 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,9 +1,9 @@ [submodule "MCServer/Plugins/Core"] path = MCServer/Plugins/Core - url = git@github.com:mc-server/Core.git + url = git://github.com/mc-server/Core.git [submodule "MCServer/Plugins/ProtectionAreas"] path = MCServer/Plugins/ProtectionAreas - url = git@github.com:mc-server/ProtectionAreas.git + url = git://github.com/mc-server/ProtectionAreas.git [submodule "MCServer/Plugins/TransAPI"] path = MCServer/Plugins/TransAPI - url = git@github.com:bearbin/transapi.git + url = git://github.com/bearbin/transapi.git diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..229f55ebf --- /dev/null +++ b/.travis.yml @@ -0,0 +1,12 @@ +language: cpp +compiler: + - gcc + - clang +# Build MCServer +script: make release=1 -j 2 + +# Notification Settings +notifications: + email: + on_success: change + on_failure: always @@ -5,3 +5,4 @@ To compile MCServer on *nix, you need a GNUmake-compatible make that reads GNUma Run "make" to build a debug version (slow, but gives more info on crash) Run "make release=1" to build a release version (fast, less info on crash) Add addm32=1 to compile in 32-bit mode on 64-bit systems. +Add `-j 4` to use 4 threads and speed up compilation on multi-core devices. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9ce4c9ff3..5aba6ac9e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,10 @@ + Code Stuff ---------- + * Because some devs use MSVC2008, we use C++03 - no C++11 magic for now at least :( + * Use the provided wrappers for OS stuff: + - Threading is done by inheriting from cIsThread, thread synchronization through cCriticalSection, cSemaphore and cEvent, file access and filesystem operations through the cFile class, high-precision timers through cTimer, high-precision sleep through cSleep * No magic numbers, use named constants: - E_ITEM_XXX, E_BLOCK_XXX and E_META_XXX for items and blocks - E_ENTITY_TYPE_XXX for mob types @@ -29,3 +29,5 @@ Other Stuff For other stuff, including plugins and discussion, check the [forums](http://forum.mc-server.org) and [wiki](http://mc-server.org/wiki/). Earn bitcoins for commits or donate to reward the MCServer developers: [![tip for next commit](http://tip4commit.com/projects/74.svg)](http://tip4commit.com/projects/74) + +Travis CI: [![Build Status](https://travis-ci.org/mc-server/MCServer.png?branch=master)](https://travis-ci.org/mc-server/MCServer) diff --git a/VC2008/MCServer.vcproj b/VC2008/MCServer.vcproj index 5b756f3b6..cb9867450 100644 --- a/VC2008/MCServer.vcproj +++ b/VC2008/MCServer.vcproj @@ -1359,6 +1359,14 @@ > </File> <File + RelativePath="..\src\Entities\Floater.cpp" + > + </File> + <File + RelativePath="..\src\Entities\Floater.h" + > + </File> + <File RelativePath="..\src\Entities\Minecart.cpp" > </File> @@ -2567,6 +2575,10 @@ > </File> <File + RelativePath="..\src\Items\ItemFishingRod.h" + > + </File> + <File RelativePath="..\src\Items\ItemFlowerPot.h" > </File> diff --git a/src/Bindings/PluginManager.cpp b/src/Bindings/PluginManager.cpp index 732da24fa..832dc4249 100644 --- a/src/Bindings/PluginManager.cpp +++ b/src/Bindings/PluginManager.cpp @@ -9,6 +9,7 @@ #include "../Root.h" #include "../Server.h" #include "../CommandOutput.h" +#include "../ChatColor.h" #include "inifile/iniFile.h" #include "../Entities/Player.h" @@ -230,19 +231,25 @@ bool cPluginManager::CallHookBlockToPickups( bool cPluginManager::CallHookChat(cPlayer * a_Player, AString & a_Message) { - if (ExecuteCommand(a_Player, a_Message)) + bool WasCommandForbidden = false; + if (HandleCommand(a_Player, a_Message, true, WasCommandForbidden)) // We use HandleCommand as opposed to ExecuteCommand to accomodate the need to the WasCommandForbidden bool { - return true; + return true; // Chat message was handled as command + } + else if (WasCommandForbidden) // Couldn't be handled as command, was it because of insufficient permissions? + { + return true; // Yes - message was sent in HandleCommand, abort } // Check if it was a standard command (starts with a slash) + // If it was, we know that it was completely unrecognised (WasCommandForbidden == false) if (!a_Message.empty() && (a_Message[0] == '/')) { AStringVector Split(StringSplit(a_Message, " ")); ASSERT(!Split.empty()); // This should not happen - we know there's at least one char in the message so the split needs to be at least one item long - a_Player->SendMessage(Printf("Unknown Command: \"%s\"", Split[0].c_str())); - LOGINFO("Player \"%s\" issued an unknown command: \"%s\"", a_Player->GetName().c_str(), a_Message.c_str()); - return true; // Cancel sending + a_Player->SendMessage(Printf("%s[INFO] %sUnknown command: \"%s\"", cChatColor::Yellow.c_str(), cChatColor::White.c_str(), Split[0].c_str())); + LOGINFO("Player %s issued an unknown command: \"%s\"", a_Player->GetName().c_str(), a_Message.c_str()); + return true; // Cancel sending } HookMap::iterator Plugins = m_Hooks.find(HOOK_CHAT); @@ -1251,7 +1258,7 @@ bool cPluginManager::CallHookWorldTick(cWorld & a_World, float a_Dt, int a_LastT -bool cPluginManager::HandleCommand(cPlayer * a_Player, const AString & a_Command, bool a_ShouldCheckPermissions) +bool cPluginManager::HandleCommand(cPlayer * a_Player, const AString & a_Command, bool a_ShouldCheckPermissions, bool & a_WasCommandForbidden) { ASSERT(a_Player != NULL); @@ -1271,7 +1278,7 @@ bool cPluginManager::HandleCommand(cPlayer * a_Player, const AString & a_Command // Ask plugins first if a command is okay to execute the command: if (CallHookExecuteCommand(a_Player, Split)) { - LOGINFO("Player \"%s\" tried executing command \"%s\" that was stopped by the HOOK_EXECUTE_COMMAND hook", a_Player->GetName().c_str(), Split[0].c_str()); + LOGINFO("Player %s tried executing command \"%s\" that was stopped by the HOOK_EXECUTE_COMMAND hook", a_Player->GetName().c_str(), Split[0].c_str()); return false; } @@ -1281,7 +1288,9 @@ bool cPluginManager::HandleCommand(cPlayer * a_Player, const AString & a_Command !a_Player->HasPermission(cmd->second.m_Permission) ) { - LOGINFO("Player \"%s\" tried to execute forbidden command \"%s\".", a_Player->GetName().c_str(), Split[0].c_str()); + a_Player->SendMessage(Printf("%s[INFO] %sForbidden command; insufficient privileges: \"%s\"", cChatColor::Rose.c_str(), cChatColor::White.c_str(), Split[0].c_str())); + LOGINFO("Player %s tried to execute forbidden command: \"%s\"", a_Player->GetName().c_str(), Split[0].c_str()); + a_WasCommandForbidden = true; return false; } diff --git a/src/Bindings/PluginManager.h b/src/Bindings/PluginManager.h index b69f402c0..04d6470c7 100644 --- a/src/Bindings/PluginManager.h +++ b/src/Bindings/PluginManager.h @@ -289,7 +289,12 @@ private: bool AddPlugin(cPlugin * a_Plugin); /// Tries to match a_Command to the internal table of commands, if a match is found, the corresponding plugin is called. Returns true if the command is handled. - bool HandleCommand(cPlayer * a_Player, const AString & a_Command, bool a_ShouldCheckPermissions); + bool HandleCommand(cPlayer * a_Player, const AString & a_Command, bool a_ShouldCheckPermissions, bool & a_WasCommandForbidden); + bool HandleCommand(cPlayer * a_Player, const AString & a_Command, bool a_ShouldCheckPermissions) + { + bool DummyBoolean = false; + return HandleCommand(a_Player, a_Command, a_ShouldCheckPermissions, DummyBoolean); + } } ; // tolua_export diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index 1e63e2ba1..837f88e61 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -998,7 +998,7 @@ void cClientHandle::HandleChat(const AString & a_Message) // Not a command, broadcast as a simple message: AString Msg; - Printf(Msg, "<%s%s%s> %s", + Printf(Msg, "%s<%s>%s %s", m_Player->GetColor().c_str(), m_Player->GetName().c_str(), cChatColor::White.c_str(), @@ -1238,12 +1238,13 @@ void cClientHandle::HandleRespawn(void) void cClientHandle::HandleDisconnect(const AString & a_Reason) { - LOGD("Received d/c packet from \"%s\" with reason \"%s\"", m_Username.c_str(), a_Reason.c_str()); + LOGD("Received d/c packet from %s with reason \"%s\"", m_Username.c_str(), a_Reason.c_str()); if (!cRoot::Get()->GetPluginManager()->CallHookDisconnect(m_Player, a_Reason)) { AString DisconnectMessage; - Printf(DisconnectMessage, "%s disconnected: %s", m_Username.c_str(), a_Reason.c_str()); - m_Player->GetWorld()->BroadcastChat(DisconnectMessage, this); + Printf(DisconnectMessage, "%s[LEAVE] %s%s has left the game", cChatColor::Yellow.c_str(), cChatColor::White.c_str(), m_Username.c_str()); + cRoot::Get()->BroadcastChat(DisconnectMessage); + LOGINFO("Player %s has left the game.", m_Username.c_str()); } m_HasSentDC = true; Destroy(); @@ -2309,7 +2310,19 @@ void cClientHandle::SocketClosed(void) { // The socket has been closed for any reason - LOGD("Client \"%s\" @ %s disconnected", m_Username.c_str(), m_IPString.c_str()); + LOGD("Player %s @ %s disconnected", m_Username.c_str(), m_IPString.c_str()); + + if (m_Username != "") // Ignore client pings + { + if (!cRoot::Get()->GetPluginManager()->CallHookDisconnect(m_Player, "Player disconnected")) + { + AString DisconnectMessage; + Printf(DisconnectMessage, "%s[LEAVE] %s%s has left the game", cChatColor::Yellow.c_str(), cChatColor::White.c_str(), m_Username.c_str()); + cRoot::Get()->BroadcastChat(DisconnectMessage); + LOGINFO("Player %s has left the game.", m_Username.c_str()); + } + } + Destroy(); } diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h index 8d1692c98..7107a4a13 100644 --- a/src/Entities/Entity.h +++ b/src/Entities/Entity.h @@ -75,6 +75,7 @@ public: etTNT, etProjectile, etExpOrb, + etFloater, // Common variations etMob = etMonster, // DEPRECATED, use etMonster instead! @@ -129,6 +130,8 @@ public: bool IsBoat (void) const { return (m_EntityType == etBoat); } bool IsTNT (void) const { return (m_EntityType == etTNT); } bool IsProjectile (void) const { return (m_EntityType == etProjectile); } + bool IsExpOrb (void) const { return (m_EntityType == etExpOrb); } + bool IsFloater (void) const { return (m_EntityType == etFloater); } /// Returns true if the entity is of the specified class or a subclass (cPawn's IsA("cEntity") returns true) virtual bool IsA(const char * a_ClassName) const; diff --git a/src/Entities/Floater.cpp b/src/Entities/Floater.cpp new file mode 100644 index 000000000..1aa0413d9 --- /dev/null +++ b/src/Entities/Floater.cpp @@ -0,0 +1,58 @@ +#include "Globals.h" + +#include "Floater.h" +#include "Player.h" +#include "../ClientHandle.h" + +cFloater::cFloater(double a_X, double a_Y, double a_Z, Vector3d a_Speed, int a_PlayerID) : + cEntity(etFloater, a_X, a_Y, a_Z, 0.98, 0.98), + m_PlayerID(a_PlayerID), + m_CanPickupItem(false), + m_PickupCountDown(0) +{ + SetSpeed(a_Speed); +} + + + + + +void cFloater::SpawnOn(cClientHandle & a_Client) +{ + a_Client.SendSpawnObject(*this, 90, m_PlayerID, 0, 0); +} + + + + + +void cFloater::Tick(float a_Dt, cChunk & a_Chunk) +{ + HandlePhysics(a_Dt, a_Chunk); + if (IsBlockWater(m_World->GetBlock((int) GetPosX(), (int) GetPosY(), (int) GetPosZ()))) + { + if (m_World->GetTickRandomNumber(100) == 0) + { + SetPosY(GetPosY() - 1); + m_CanPickupItem = true; + m_PickupCountDown = 20; + LOGD("Floater %i can be picked up", GetUniqueID()); + } + else + { + SetSpeedY(1); + } + } + SetSpeedX(GetSpeedX() * 0.95); + SetSpeedZ(GetSpeedZ() * 0.95); + if (CanPickup()) + { + m_PickupCountDown--; + if (m_PickupCountDown == 0) + { + m_CanPickupItem = false; + LOGD("The fish is gone. Floater %i can not pick an item up.", GetUniqueID()); + } + } + BroadcastMovementUpdate(); +}
\ No newline at end of file diff --git a/src/Entities/Floater.h b/src/Entities/Floater.h new file mode 100644 index 000000000..9bc5039f8 --- /dev/null +++ b/src/Entities/Floater.h @@ -0,0 +1,29 @@ + +#pragma once + +#include "Entity.h" + + + + + +class cFloater : + public cEntity +{ + typedef cFloater super; + +public: + + cFloater(double a_X, double a_Y, double a_Z, Vector3d a_Speed, int a_PlayerID); + + virtual void SpawnOn(cClientHandle & a_Client) override; + virtual void Tick(float a_Dt, cChunk & a_Chunk) override; + + bool CanPickup(void) const { return m_CanPickupItem; } + +protected: + Vector3d m_Speed; + int m_PickupCountDown; + int m_PlayerID; + bool m_CanPickupItem; +} ;
\ No newline at end of file diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index bb19bcce9..ca0d625e2 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -65,6 +65,8 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName) , m_IsSubmerged(false) , m_IsFlying(false) , m_CanFly(false) + , m_IsFishing(false) + , m_FloaterID(-1) , m_EatingFinishTick(-1) , m_IsChargingBow(false) , m_BowCharge(0) diff --git a/src/Entities/Player.h b/src/Entities/Player.h index 59e941040..74da857e8 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -253,6 +253,14 @@ public: /// Returns true if the player is currently flying. bool IsFlying(void) const { return m_IsFlying; } + + /// returns true if the player has thrown out a floater. + bool IsFishing(void) const { return m_IsFishing; } + + void SetIsFishing(bool a_IsFishing, int a_FloaterID = -1) { m_IsFishing = a_IsFishing; m_FloaterID = a_FloaterID; } + + int GetFloaterID(void) const { return m_FloaterID; } + // tolua_end /// Starts eating the currently equipped item. Resets the eating timer and sends the proper animation packet @@ -429,6 +437,7 @@ protected: bool m_IsFlying; bool m_IsSwimming; bool m_IsSubmerged; + bool m_IsFishing; bool m_CanFly; // If this is true the player can fly. Even if he is not in creative. @@ -445,6 +454,7 @@ protected: bool m_IsChargingBow; int m_BowCharge; + int m_FloaterID; virtual void Destroyed(void); diff --git a/src/Items/ItemFishingRod.h b/src/Items/ItemFishingRod.h new file mode 100644 index 000000000..91c0e9638 --- /dev/null +++ b/src/Items/ItemFishingRod.h @@ -0,0 +1,78 @@ + +// ItemFishingRod.h + +// Declares the various fishing rod ItemHandlers + + + + + +#pragma once + +#include "../Entities/Floater.h" +#include "../Entities/Entity.h" +#include "../Item.h" + + + + +class cItemFishingRodHandler : + public cItemHandler +{ + typedef cItemHandler super; + +public: + cItemFishingRodHandler(int a_ItemType) : + super(a_ItemType) + { + } + + virtual bool OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Dir) override + { + if (a_Player->IsFishing()) + { + class cFloaterCallback : + public cEntityCallback + { + public: + cFloaterCallback(void) : + m_CanPickup(false) + { + } + + bool CanPickup(void) const { return m_CanPickup; } + Vector3d GetPos(void) const { return m_Pos; } + + virtual bool Item(cEntity * a_Entity) override + { + m_CanPickup = ((cFloater *)a_Entity)->CanPickup(); + m_Pos = Vector3d(a_Entity->GetPosX(), a_Entity->GetPosY(), a_Entity->GetPosZ()); + a_Entity->Destroy(true); + return true; + } + protected: + bool m_CanPickup; + Vector3d m_Pos; + } Callbacks; + a_World->DoWithEntityByID(a_Player->GetFloaterID(), Callbacks); + a_Player->SetIsFishing(false); + + if (Callbacks.CanPickup()) + { + cItems Drops; + Drops.Add(cItem(E_ITEM_RAW_FISH)); + Vector3d FloaterPos(Callbacks.GetPos()); + Vector3d FlyDirection(a_Player->GetPosition() - FloaterPos); + a_World->SpawnItemPickups(Drops, FloaterPos.x, FloaterPos.y, FloaterPos.z, FlyDirection.x, FlyDirection.y, FlyDirection.z); + // TODO: More types of pickups. + } + } + else + { + cFloater * Floater = new cFloater(a_Player->GetPosX(), a_Player->GetStance(), a_Player->GetPosZ(), a_Player->GetLookVector() * 7, a_Player->GetUniqueID()); + Floater->Initialize(a_World); + a_Player->SetIsFishing(true, Floater->GetUniqueID()); + } + return true; + } +} ;
\ No newline at end of file diff --git a/src/Items/ItemHandler.cpp b/src/Items/ItemHandler.cpp index 23b9a86d4..250e21dc4 100644 --- a/src/Items/ItemHandler.cpp +++ b/src/Items/ItemHandler.cpp @@ -17,6 +17,7 @@ #include "ItemComparator.h" #include "ItemDoor.h" #include "ItemDye.h" +#include "ItemFishingRod.h" #include "ItemFlowerPot.h" #include "ItemFood.h" #include "ItemHoe.h" @@ -100,6 +101,7 @@ cItemHandler *cItemHandler::CreateItemHandler(int a_ItemType) case E_ITEM_EGG: return new cItemEggHandler(); case E_ITEM_ENDER_PEARL: return new cItemEnderPearlHandler(); case E_ITEM_FIREWORK_ROCKET: return new cItemFireworkHandler(); + case E_ITEM_FISHING_ROD: return new cItemFishingRodHandler(a_ItemType); case E_ITEM_FLINT_AND_STEEL: return new cItemLighterHandler(a_ItemType); case E_ITEM_FLOWER_POT: return new cItemFlowerPotHandler(a_ItemType); case E_ITEM_NETHER_WART: return new cItemNetherWartHandler(a_ItemType); |