Implement swimming/gliding including AABB recalculation (#4446)

- The following events have been added:
  - PlayerToggleGlideEvent
  - PlayerToggleSwimEvent
- The following API methods have been added:
  - Entity->getSize()
  - Living->isSwimming()
  - Living->setSwimming()
  - Living->isGliding()
  - Living->setSwimming()
  - Player->toggleSwim()
  - Player->toggleGlide()
This commit is contained in:
XenialDan 2021-12-19 18:10:41 +01:00 committed by GitHub
parent 65dabefa3b
commit d41f933e7b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 166 additions and 9 deletions

View File

@ -304,12 +304,8 @@ abstract class Entity{
if($value <= 0){
throw new \InvalidArgumentException("Scale must be greater than 0");
}
$this->size = $this->getInitialSizeInfo()->scale($value);
$this->scale = $value;
$this->recalculateBoundingBox();
$this->networkPropertiesDirty = true;
$this->setSize($this->getInitialSizeInfo()->scale($value));
}
public function getBoundingBox() : AxisAlignedBB{
@ -329,6 +325,16 @@ abstract class Entity{
);
}
public function getSize() : EntitySizeInfo{
return $this->size;
}
protected function setSize(EntitySizeInfo $size) : void{
$this->size = $size;
$this->recalculateBoundingBox();
$this->networkPropertiesDirty = true;
}
public function isImmobile() : bool{
return $this->immobile;
}

View File

@ -116,6 +116,10 @@ abstract class Living extends Entity{
protected $sprinting = false;
/** @var bool */
protected $sneaking = false;
/** @var bool */
protected $gliding = false;
/** @var bool */
protected $swimming = false;
abstract public function getName() : string;
@ -227,6 +231,37 @@ abstract class Living extends Entity{
}
}
public function isGliding() : bool{
return $this->gliding;
}
public function setGliding(bool $value = true) : void{
$this->gliding = $value;
$this->networkPropertiesDirty = true;
$this->recalculateSize();
}
public function isSwimming() : bool{
return $this->swimming;
}
public function setSwimming(bool $value = true) : void{
$this->swimming = $value;
$this->networkPropertiesDirty = true;
$this->recalculateSize();
}
private function recalculateSize() : void{
$size = $this->getInitialSizeInfo();
if($this->isSwimming() || $this->isGliding()){
$width = $size->getWidth();
//we don't actually know an appropriate eye height for a swimming mob, but 2/3 should be good enough.
$this->setSize((new EntitySizeInfo($width, $width, $width * 2 / 3))->scale($this->getScale()));
}else{
$this->setSize($size->scale($this->getScale()));
}
}
public function getMovementSpeed() : float{
return $this->moveSpeedAttr->getValue();
}
@ -800,6 +835,8 @@ abstract class Living extends Entity{
$properties->setGenericFlag(EntityMetadataFlags::BREATHING, $this->breathing);
$properties->setGenericFlag(EntityMetadataFlags::SNEAKING, $this->sneaking);
$properties->setGenericFlag(EntityMetadataFlags::SPRINTING, $this->sprinting);
$properties->setGenericFlag(EntityMetadataFlags::GLIDING, $this->gliding);
$properties->setGenericFlag(EntityMetadataFlags::SWIMMING, $this->swimming);
}
protected function onDispose() : void{

View File

@ -0,0 +1,40 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\event\player;
use pocketmine\event\Cancellable;
use pocketmine\event\CancellableTrait;
use pocketmine\player\Player;
class PlayerToggleGlideEvent extends PlayerEvent implements Cancellable{
use CancellableTrait;
public function __construct(Player $player, protected bool $isGliding){
$this->player = $player;
}
public function isGliding() : bool{
return $this->isGliding;
}
}

View File

@ -0,0 +1,40 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\event\player;
use pocketmine\event\Cancellable;
use pocketmine\event\CancellableTrait;
use pocketmine\player\Player;
class PlayerToggleSwimEvent extends PlayerEvent implements Cancellable{
use CancellableTrait;
public function __construct(Player $player, protected bool $isSwimming){
$this->player = $player;
}
public function isSwimming() : bool{
return $this->isSwimming;
}
}

View File

@ -590,16 +590,28 @@ class InGamePacketHandler extends PacketHandler{
}
return true;
case PlayerAction::START_GLIDE:
if(!$this->player->toggleGlide(true)){
$this->player->sendData([$this->player]);
}
return true;
case PlayerAction::STOP_GLIDE:
break; //TODO
if(!$this->player->toggleGlide(false)){
$this->player->sendData([$this->player]);
}
return true;
case PlayerAction::CRACK_BREAK:
$this->player->continueBreakBlock($pos, $face);
break;
case PlayerAction::START_SWIMMING:
break; //TODO
if(!$this->player->toggleSwim(true)){
$this->player->sendData([$this->player]);
}
return true;
case PlayerAction::STOP_SWIMMING:
//TODO: handle this when it doesn't spam every damn tick (yet another spam bug!!)
break;
if(!$this->player->toggleSwim(false)){
$this->player->sendData([$this->player]);
}
return true;
case PlayerAction::INTERACT_BLOCK: //TODO: ignored (for now)
break;
case PlayerAction::CREATIVE_PLAYER_DESTROY_BLOCK:

View File

@ -68,8 +68,10 @@ use pocketmine\event\player\PlayerMoveEvent;
use pocketmine\event\player\PlayerQuitEvent;
use pocketmine\event\player\PlayerRespawnEvent;
use pocketmine\event\player\PlayerToggleFlightEvent;
use pocketmine\event\player\PlayerToggleGlideEvent;
use pocketmine\event\player\PlayerToggleSneakEvent;
use pocketmine\event\player\PlayerToggleSprintEvent;
use pocketmine\event\player\PlayerToggleSwimEvent;
use pocketmine\event\player\PlayerTransferEvent;
use pocketmine\form\Form;
use pocketmine\form\FormValidationException;
@ -1768,6 +1770,26 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
return true;
}
public function toggleGlide(bool $glide) : bool{
$ev = new PlayerToggleGlideEvent($this, $glide);
$ev->call();
if($ev->isCancelled()){
return false;
}
$this->setGliding($glide);
return true;
}
public function toggleSwim(bool $swimming) : bool{
$ev = new PlayerToggleSwimEvent($this, $swimming);
$ev->call();
if($ev->isCancelled()){
return false;
}
$this->setSwimming($swimming);
return true;
}
public function emote(string $emoteId) : void{
$currentTick = $this->server->getTick();
if($currentTick - $this->lastEmoteTick > 5){