diff --git a/SDK b/SDK index 1bf8feab2..91345675d 160000 --- a/SDK +++ b/SDK @@ -1 +1 @@ -Subproject commit 1bf8feab24c66e73f8417752cb800cb8c71aba75 +Subproject commit 91345675d9d8c2b8ff53b3f0c031f96515ce4e6d diff --git a/Server/Components/CAPI/Impl/CustomModels/APIs.cpp b/Server/Components/CAPI/Impl/CustomModels/APIs.cpp index 217985eb9..dc6371e03 100644 --- a/Server/Components/CAPI/Impl/CustomModels/APIs.cpp +++ b/Server/Components/CAPI/Impl/CustomModels/APIs.cpp @@ -115,3 +115,26 @@ OMP_CAPI(CustomModel_GetPath, bool(int modelId, OutputStringViewPtr dffPath, Out return status; } + +OMP_CAPI(SetModelDownloadAtConnect, bool(bool value)) +{ + auto models = ComponentManager::Get()->models; + + if (!models) + return false; + + return models->setModelDownloadAtConnect(value); +} + +OMP_CAPI(StartDownloadForPlayer, bool(objectPtr player)) +{ + POOL_ENTITY_RET(players, IPlayer, player, player_, false); + auto models = ComponentManager::Get()->models; + + if (!models) + { + return false; + } + + return models->startDownloadForPlayer(*player_); +} \ No newline at end of file diff --git a/Server/Components/CAPI/Impl/Players/APIs.cpp b/Server/Components/CAPI/Impl/Players/APIs.cpp index 4a83c45bc..6884dd6aa 100644 --- a/Server/Components/CAPI/Impl/Players/APIs.cpp +++ b/Server/Components/CAPI/Impl/Players/APIs.cpp @@ -592,10 +592,16 @@ OMP_CAPI(Player_RemoveBuilding, bool(objectPtr player, int model, float x, float OMP_CAPI(Player_GetBuildingsRemoved, int(objectPtr player)) { POOL_ENTITY_RET(players, IPlayer, player, player_, false); - int count = player_->getDefaultObjectsRemoved(); + int count = player_->getDefaultObjectsRemovedCount(); return count; } +OMP_CAPI(Player_IsBuildingRemoved, bool(objectPtr player, int model, float x, float y, float z, float radius)) +{ + POOL_ENTITY_RET(players, IPlayer, player, player_, false); + return player_->isDefaultObjectRemoved(model, { x, y, z }, radius); +} + OMP_CAPI(Player_RemoveFromVehicle, bool(objectPtr player, bool force)) { POOL_ENTITY_RET(players, IPlayer, player, player_, false); diff --git a/Server/Components/CAPI/Impl/Vehicles/APIs.cpp b/Server/Components/CAPI/Impl/Vehicles/APIs.cpp index 0d3630f38..215c8a9de 100644 --- a/Server/Components/CAPI/Impl/Vehicles/APIs.cpp +++ b/Server/Components/CAPI/Impl/Vehicles/APIs.cpp @@ -780,3 +780,23 @@ OMP_CAPI(Vehicle_CountOccupants, int(objectPtr vehicle)) return occupants; } + +OMP_CAPI(ShowVehicle, bool(objectPtr vehicle)) +{ + POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, 0); + vehicle_->toggleHide(false); + return true; +} + +OMP_CAPI(HideVehicle, bool(objectPtr vehicle)) +{ + POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, 0); + vehicle_->toggleHide(true); + return true; +} + +OMP_CAPI(IsVehicleHidden, bool(objectPtr vehicle)) +{ + POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, 0); + return vehicle_->isHidden(); +} \ No newline at end of file diff --git a/Server/Components/CustomModels/models.cpp b/Server/Components/CustomModels/models.cpp index 5224c1f09..a39377c49 100644 --- a/Server/Components/CustomModels/models.cpp +++ b/Server/Components/CustomModels/models.cpp @@ -303,6 +303,7 @@ class CustomModelsComponent final : public ICustomModelsComponent, public Player bool usingCdn = false; uint16_t httpThreads = 50; // default max_players is 50 bool showCRCLogs = false; + bool DownloadAtConnect = true; DefaultEventDispatcher eventDispatcher; @@ -695,11 +696,8 @@ class CustomModelsComponent final : public ICustomModelsComponent, public Player return file.name; } - void onPlayerClientInit(IPlayer& player) override + void promptModelsForPlayer(IPlayer& player) { - if (player.getClientVersion() != ClientVersion::ClientVersion_SAMP_03DL) - return; - const auto modelsCount = storage.size(); for (auto i = 0; i != modelsCount; ++i) { @@ -707,7 +705,6 @@ class CustomModelsComponent final : public ICustomModelsComponent, public Player storage[i]->write(modelInfo); PacketHelper::send(modelInfo, player); } - // If client reconnected (lost connection to the server) let's force it to download files if there are any. NetCode::RPC::SetPlayerVirtualWorld setWorld; setWorld.worldId = player.getVirtualWorld() + 1; @@ -716,6 +713,15 @@ class CustomModelsComponent final : public ICustomModelsComponent, public Player PacketHelper::send(setWorld, player); } + void onPlayerClientInit(IPlayer& player) override + { + if (player.getClientVersion() != ClientVersion::ClientVersion_SAMP_03DL) + return; + + if (DownloadAtConnect) + promptModelsForPlayer(player); + } + IEventDispatcher& getEventDispatcher() override { return eventDispatcher; @@ -729,8 +735,10 @@ class CustomModelsComponent final : public ICustomModelsComponent, public Player { return; } - - webServer->allowIPAddress(player.getNetworkData().networkID.address.v4); + if (DownloadAtConnect) + { + webServer->allowIPAddress(player.getNetworkData().networkID.address.v4); + } } void onPlayerDisconnect(IPlayer& player, PeerDisconnectReason reason) override @@ -763,6 +771,22 @@ class CustomModelsComponent final : public ICustomModelsComponent, public Player } return false; } + + bool setModelDownloadAtConnect(bool toggle) override + { + DownloadAtConnect = toggle; + return DownloadAtConnect; + } + + bool startDownloadForPlayer(IPlayer& player) override + { + if (DownloadAtConnect) + return false; + + webServer->allowIPAddress(player.getNetworkData().networkID.address.v4); + promptModelsForPlayer(player); + return true; + } }; COMPONENT_ENTRY_POINT() diff --git a/Server/Components/Pawn/Scripting/CustomModels/Natives.cpp b/Server/Components/Pawn/Scripting/CustomModels/Natives.cpp index 420be65f0..17feb5554 100644 --- a/Server/Components/Pawn/Scripting/CustomModels/Natives.cpp +++ b/Server/Components/Pawn/Scripting/CustomModels/Natives.cpp @@ -113,3 +113,24 @@ SCRIPT_API(GetCustomModelPath, bool(int modelId, OutputOnlyString& dffPath, Outp return status; } + +SCRIPT_API(SetModelDownloadAtConnect, bool(bool value)) +{ + auto models = PawnManager::Get()->models; + + if (!models) + return false; + + return models->setModelDownloadAtConnect(value); +} + +SCRIPT_API(StartDownloadForPlayer, bool(IPlayer& player)) +{ + auto models = PawnManager::Get()->models; + + if (!models) + { + return false; + } + return models->startDownloadForPlayer(player); +} \ No newline at end of file diff --git a/Server/Components/Pawn/Scripting/Player/Natives.cpp b/Server/Components/Pawn/Scripting/Player/Natives.cpp index 437c678ea..996b5fa90 100644 --- a/Server/Components/Pawn/Scripting/Player/Natives.cpp +++ b/Server/Components/Pawn/Scripting/Player/Natives.cpp @@ -502,7 +502,12 @@ SCRIPT_API(RemoveBuildingForPlayer, bool(IPlayer& player, uint32_t model, Vector SCRIPT_API(GetPlayerBuildingsRemoved, int(IPlayer& player)) { - return player.getDefaultObjectsRemoved(); + return player.getDefaultObjectsRemovedCount(); +} + +SCRIPT_API(IsBuildingRemovedForPlayer, bool(IPlayer& player, uint32_t model, Vector3 pos, float radius)) +{ + return player.isDefaultObjectRemoved(model, pos, radius); } SCRIPT_API(RemovePlayerFromVehicle, bool(IPlayer& player)) diff --git a/Server/Components/Pawn/Scripting/Vehicle/Natives.cpp b/Server/Components/Pawn/Scripting/Vehicle/Natives.cpp index 38ef43b38..84084a4c3 100644 --- a/Server/Components/Pawn/Scripting/Vehicle/Natives.cpp +++ b/Server/Components/Pawn/Scripting/Vehicle/Natives.cpp @@ -679,3 +679,20 @@ SCRIPT_API(CountVehicleOccupants, int(IVehicle& vehicle)) occupants += passengers.size(); return occupants; } + +SCRIPT_API(ShowVehicle, bool(IVehicle& vehicle)) +{ + vehicle.toggleHide(false); + return true; +} + +SCRIPT_API(HideVehicle, bool(IVehicle& vehicle)) +{ + vehicle.toggleHide(true); + return true; +} + +SCRIPT_API(IsVehicleHidden, bool(IVehicle& vehicle)) +{ + return vehicle.isHidden(); +} \ No newline at end of file diff --git a/Server/Components/Vehicles/vehicle.hpp b/Server/Components/Vehicles/vehicle.hpp index 340b0e304..a4190658a 100644 --- a/Server/Components/Vehicles/vehicle.hpp +++ b/Server/Components/Vehicles/vehicle.hpp @@ -67,6 +67,7 @@ class Vehicle final : public IVehicle, public PoolIDProvider, public NoCopy uint32_t hydraThrustAngle = 0; float trainSpeed = 0.0f; int lastDriverPoolID = INVALID_PLAYER_ID; + bool hidden_ = false; /// Update the vehicle occupied status - set beenOccupied to true and update the lastOccupied time. void updateOccupied() @@ -154,6 +155,16 @@ class Vehicle final : public IVehicle, public PoolIDProvider, public NoCopy ~Vehicle(); void destream(); + void toggleHide(bool value) override + { + hidden_ = value; + } + + bool isHidden() const override + { + return hidden_; + } + int getVirtualWorld() const override { return virtualWorld_; diff --git a/Server/Components/Vehicles/vehicles_impl.hpp b/Server/Components/Vehicles/vehicles_impl.hpp index 0249857ec..c0595fa47 100644 --- a/Server/Components/Vehicles/vehicles_impl.hpp +++ b/Server/Components/Vehicles/vehicles_impl.hpp @@ -706,7 +706,7 @@ class VehiclesComponent final : public IVehiclesComponent, public CoreEventHandl } const Vector2 dist2D = vehicle->getPosition() - player.getPosition(); - const bool shouldBeStreamedIn = state != PlayerState_None && player.getVirtualWorld() == vehicle->getVirtualWorld() && (playerVehicle == vehicle || glm::dot(dist2D, dist2D) < maxDist); + const bool shouldBeStreamedIn = state != PlayerState_None && (vehicle->isHidden() != true) && player.getVirtualWorld() == vehicle->getVirtualWorld() && (playerVehicle == vehicle || glm::dot(dist2D, dist2D) < maxDist); const bool isStreamedIn = vehicle->isStreamedInForPlayer(player); if (!isStreamedIn && shouldBeStreamedIn) diff --git a/Server/Source/player_impl.hpp b/Server/Source/player_impl.hpp index 0d8eb820a..7cd9b074d 100644 --- a/Server/Source/player_impl.hpp +++ b/Server/Source/player_impl.hpp @@ -53,6 +53,13 @@ enum SecondarySyncUpdateType SecondarySyncUpdateType_Trailer = (1 << 2), }; +struct RemovedDefaultObject +{ + unsigned ModelId; + Vector3 pos; + float radius; +}; + struct Player final : public IPlayer, public PoolIDProvider, public NoCopy { PlayerPool& pool_; @@ -113,12 +120,13 @@ struct Player final : public IPlayer, public PoolIDProvider, public NoCopy PlayerSpectateData spectateData_; float gravity_; bool ghostMode_; - int defaultObjectsRemoved_; + DynamicArray defaultObjectsRemoved_; bool allowWeapons_; bool allowTeleport_; bool isUsingOfficialClient_; bool isUsingOmp_; bool leavingSpec_; + PrimarySyncUpdateType primarySyncUpdateType_; int secondarySyncUpdateType_; @@ -200,7 +208,7 @@ struct Player final : public IPlayer, public PoolIDProvider, public NoCopy spectateData_ = { false, INVALID_PLAYER_ID, PlayerSpectateData::ESpectateType::None }; gravity_ = 0.0f; ghostMode_ = false; - defaultObjectsRemoved_ = 0; + defaultObjectsRemoved_.clear(); primarySyncUpdateType_ = PrimarySyncUpdateType::None; secondarySyncUpdateType_ = 0; leavingSpec_ = false; @@ -258,7 +266,6 @@ struct Player final : public IPlayer, public PoolIDProvider, public NoCopy , spectateData_({ false, INVALID_PLAYER_ID, PlayerSpectateData::ESpectateType::None }) , gravity_(0.0f) , ghostMode_(false) - , defaultObjectsRemoved_(0) , allowWeapons_(true) , allowTeleport_(false) , isUsingOfficialClient_(params.isUsingOfficialClient) @@ -946,7 +953,12 @@ struct Player final : public IPlayer, public PoolIDProvider, public NoCopy void removeDefaultObjects(unsigned model, Vector3 pos, float radius) override { - defaultObjectsRemoved_++; + RemovedDefaultObject theObject; + theObject.ModelId = model; + theObject.pos = pos; + theObject.radius = radius; + + defaultObjectsRemoved_.push_back(theObject); NetCode::RPC::RemoveBuildingForPlayer removeBuildingForPlayerRPC; removeBuildingForPlayerRPC.ModelID = model; removeBuildingForPlayerRPC.Position = pos; @@ -954,9 +966,26 @@ struct Player final : public IPlayer, public PoolIDProvider, public NoCopy PacketHelper::send(removeBuildingForPlayerRPC, *this); } - int getDefaultObjectsRemoved() const override + int getDefaultObjectsRemovedCount() const override { - return defaultObjectsRemoved_; + return defaultObjectsRemoved_.size(); + } + + bool isDefaultObjectRemoved(unsigned model, Vector3 pos, float radius) const override + { + for (const auto& object : defaultObjectsRemoved_) + { + if (model == -1 || object.ModelId == -1 || model == object.ModelId) + { + float dist = (pos - object.pos).length(); + + if (dist + radius <= object.radius) + { + return true; + } + } + } + return false; } bool getKickStatus() const override