mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-09-08 02:42:58 +00:00
Compare commits
6 Commits
Author | SHA1 | Date | |
---|---|---|---|
442049d564 | |||
e375437439 | |||
c417ecd30d | |||
11612ed0e2 | |||
0b9e680753 | |||
275fdc4280 |
31
.github/workflows/build-docker-image.yml
vendored
31
.github/workflows/build-docker-image.yml
vendored
@ -4,6 +4,11 @@ on:
|
||||
release:
|
||||
types:
|
||||
- published
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
release:
|
||||
description: 'Tag name to build'
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@ -33,11 +38,23 @@ jobs:
|
||||
repository: pmmp/PocketMine-Docker
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Get tag names
|
||||
|
||||
- name: Get tag name
|
||||
id: tag-name
|
||||
run: |
|
||||
VERSION=$(echo "${{ github.ref }}" | sed 's{^refs/tags/{{')
|
||||
echo TAG_NAME=$VERSION >> $GITHUB_OUTPUT
|
||||
if [[ "${{ github.event_name }}" == "release" ]]; then
|
||||
echo TAG_NAME="${{ github.event.release.tag_name }}" >> $GITHUB_OUTPUT
|
||||
elif [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
|
||||
echo TAG_NAME="${{ github.event.inputs.release }}" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "Unsupported event type: ${{ github.event_name }}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Parse version
|
||||
id: version
|
||||
run: |
|
||||
VERSION="${{ steps.tag-name.outputs.TAG_NAME }}"
|
||||
echo MAJOR=$(echo $VERSION | cut -d. -f1) >> $GITHUB_OUTPUT
|
||||
echo MINOR=$(echo $VERSION | cut -d. -f1-2) >> $GITHUB_OUTPUT
|
||||
|
||||
@ -71,8 +88,8 @@ jobs:
|
||||
push: true
|
||||
context: ./pocketmine-mp
|
||||
tags: |
|
||||
${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.tag-name.outputs.MAJOR }}
|
||||
ghcr.io/${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.tag-name.outputs.MAJOR }}
|
||||
${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.version.outputs.MAJOR }}
|
||||
ghcr.io/${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.version.outputs.MAJOR }}
|
||||
build-args: |
|
||||
PMMP_TAG=${{ steps.tag-name.outputs.TAG_NAME }}
|
||||
PMMP_REPO=${{ github.repository }}
|
||||
@ -84,8 +101,8 @@ jobs:
|
||||
push: true
|
||||
context: ./pocketmine-mp
|
||||
tags: |
|
||||
${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.tag-name.outputs.MINOR }}
|
||||
ghcr.io/${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.tag-name.outputs.MINOR }}
|
||||
${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.version.outputs.MINOR }}
|
||||
ghcr.io/${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.version.outputs.MINOR }}
|
||||
build-args: |
|
||||
PMMP_TAG=${{ steps.tag-name.outputs.TAG_NAME }}
|
||||
PMMP_REPO=${{ github.repository }}
|
||||
|
17
.github/workflows/discord-release-notify.yml
vendored
17
.github/workflows/discord-release-notify.yml
vendored
@ -4,6 +4,11 @@ on:
|
||||
release:
|
||||
types:
|
||||
- published
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
release:
|
||||
description: 'Release to make notification for'
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@ -30,9 +35,17 @@ jobs:
|
||||
- name: Install Composer dependencies
|
||||
run: composer install --no-dev --prefer-dist --no-interaction --ignore-platform-reqs
|
||||
|
||||
- name: Get actual tag name
|
||||
- name: Get tag name
|
||||
id: tag-name
|
||||
run: echo TAG_NAME=$(echo "${{ github.ref }}" | sed 's{^refs/tags/{{') >> $GITHUB_OUTPUT
|
||||
run: |
|
||||
if [[ "${{ github.event_name }}" == "release" ]]; then
|
||||
echo TAG_NAME="${{ github.event.release.tag_name }}" >> $GITHUB_OUTPUT
|
||||
elif [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
|
||||
echo TAG_NAME="${{ github.event.inputs.release }}" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "Unsupported event type: ${{ github.event_name }}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Run webhook post script
|
||||
run: php .github/workflows/discord-release-embed.php ${{ github.repository }} ${{ steps.tag-name.outputs.TAG_NAME }} ${{ github.token }} ${{ secrets.DISCORD_RELEASE_WEBHOOK }} ${{ secrets.DISCORD_NEWS_PING_ROLE_ID }}
|
||||
|
17
.github/workflows/update-updater-api.yml
vendored
17
.github/workflows/update-updater-api.yml
vendored
@ -4,6 +4,11 @@ on:
|
||||
release:
|
||||
types:
|
||||
- published
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
release:
|
||||
description: 'Release to publish info for'
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@ -19,9 +24,17 @@ jobs:
|
||||
repository: ${{ github.repository_owner }}/update.pmmp.io
|
||||
ssh-key: ${{ secrets.UPDATE_PMMP_IO_DEPLOY_KEY }}
|
||||
|
||||
- name: Get actual tag name
|
||||
- name: Get tag name
|
||||
id: tag-name
|
||||
run: echo TAG_NAME=$(echo "${{ github.ref }}" | sed 's{^refs/tags/{{') >> $GITHUB_OUTPUT
|
||||
run: |
|
||||
if [[ "${{ github.event_name }}" == "release" ]]; then
|
||||
echo TAG_NAME="${{ github.event.release.tag_name }}" >> $GITHUB_OUTPUT
|
||||
elif [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
|
||||
echo TAG_NAME="${{ github.event.inputs.release }}" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "Unsupported event type: ${{ github.event_name }}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Download new release information
|
||||
run: curl -f -L ${{ github.server_url }}/${{ github.repository }}/releases/download/${{ steps.tag-name.outputs.TAG_NAME }}/build_info.json -o new_build_info.json
|
||||
|
@ -15,3 +15,11 @@ Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if
|
||||
|
||||
## Fixes
|
||||
- Fixed deadlock on RakLib thread crash (e.g. due to port binding failure).
|
||||
|
||||
# 5.32.1
|
||||
Released 14th August 2025.
|
||||
|
||||
## Fixes
|
||||
- Hardened checks when processing resource pack sending during player logins.
|
||||
- Fixed content log warning about crafting recipe with missing ID.
|
||||
- Fixed packets in a batch still being processed after one of them caused the session to be terminated.
|
||||
|
@ -31,7 +31,7 @@ use function str_repeat;
|
||||
|
||||
final class VersionInfo{
|
||||
public const NAME = "PocketMine-MP";
|
||||
public const BASE_VERSION = "5.32.0";
|
||||
public const BASE_VERSION = "5.32.1";
|
||||
public const IS_DEVELOPMENT_BUILD = false;
|
||||
public const BUILD_CHANNEL = "stable";
|
||||
|
||||
|
@ -415,6 +415,11 @@ class NetworkSession{
|
||||
$this->logger->debug($packet->getName() . ": " . base64_encode($buffer));
|
||||
throw PacketHandlingException::wrap($e, "Error processing " . $packet->getName());
|
||||
}
|
||||
if(!$this->isConnected()){
|
||||
//handling this packet may have caused a disconnection
|
||||
$this->logger->debug("Aborting batch processing due to server-side disconnection");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}catch(PacketDecodeException|BinaryDataException $e){
|
||||
$this->logger->logException($e);
|
||||
|
16
src/network/mcpe/cache/CraftingDataCache.php
vendored
16
src/network/mcpe/cache/CraftingDataCache.php
vendored
@ -56,6 +56,12 @@ final class CraftingDataCache{
|
||||
*/
|
||||
private array $caches = [];
|
||||
|
||||
/**
|
||||
* The client doesn't like recipes with ID 0 (as of 1.21.100) and complains about them in the content log
|
||||
* This doesn't actually affect the function of the recipe, but it is annoying, so this offset fixes it
|
||||
*/
|
||||
public const RECIPE_ID_OFFSET = 1;
|
||||
|
||||
public function getCache(CraftingManager $manager) : CraftingDataPacket{
|
||||
$id = spl_object_id($manager);
|
||||
if(!isset($this->caches[$id])){
|
||||
@ -82,6 +88,8 @@ final class CraftingDataCache{
|
||||
|
||||
$noUnlockingRequirement = new RecipeUnlockingRequirement(null);
|
||||
foreach($manager->getCraftingRecipeIndex() as $index => $recipe){
|
||||
//the client doesn't like recipes with an ID of 0, so we need to offset them
|
||||
$recipeNetId = $index + self::RECIPE_ID_OFFSET;
|
||||
if($recipe instanceof ShapelessRecipe){
|
||||
$typeTag = match($recipe->getType()){
|
||||
ShapelessRecipeType::CRAFTING => CraftingRecipeBlockName::CRAFTING_TABLE,
|
||||
@ -91,14 +99,14 @@ final class CraftingDataCache{
|
||||
};
|
||||
$recipesWithTypeIds[] = new ProtocolShapelessRecipe(
|
||||
CraftingDataPacket::ENTRY_SHAPELESS,
|
||||
Binary::writeInt($index),
|
||||
Binary::writeInt($recipeNetId),
|
||||
array_map($converter->coreRecipeIngredientToNet(...), $recipe->getIngredientList()),
|
||||
array_map($converter->coreItemStackToNet(...), $recipe->getResults()),
|
||||
$nullUUID,
|
||||
$typeTag,
|
||||
50,
|
||||
$noUnlockingRequirement,
|
||||
$index
|
||||
$recipeNetId
|
||||
);
|
||||
}elseif($recipe instanceof ShapedRecipe){
|
||||
$inputs = [];
|
||||
@ -110,7 +118,7 @@ final class CraftingDataCache{
|
||||
}
|
||||
$recipesWithTypeIds[] = $r = new ProtocolShapedRecipe(
|
||||
CraftingDataPacket::ENTRY_SHAPED,
|
||||
Binary::writeInt($index),
|
||||
Binary::writeInt($recipeNetId),
|
||||
$inputs,
|
||||
array_map($converter->coreItemStackToNet(...), $recipe->getResults()),
|
||||
$nullUUID,
|
||||
@ -118,7 +126,7 @@ final class CraftingDataCache{
|
||||
50,
|
||||
true,
|
||||
$noUnlockingRequirement,
|
||||
$index,
|
||||
$recipeNetId,
|
||||
);
|
||||
}else{
|
||||
//TODO: probably special recipe types
|
||||
|
@ -35,6 +35,7 @@ use pocketmine\inventory\transaction\TransactionBuilder;
|
||||
use pocketmine\inventory\transaction\TransactionBuilderInventory;
|
||||
use pocketmine\item\Durable;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\network\mcpe\cache\CraftingDataCache;
|
||||
use pocketmine\network\mcpe\InventoryManager;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\ContainerUIIds;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\FullContainerName;
|
||||
@ -238,9 +239,10 @@ class ItemStackRequestExecutor{
|
||||
throw new ItemStackRequestProcessException("Cannot craft a recipe more than 256 times");
|
||||
}
|
||||
$craftingManager = $this->player->getServer()->getCraftingManager();
|
||||
$recipe = $craftingManager->getCraftingRecipeFromIndex($recipeId);
|
||||
$recipeIndex = $recipeId - CraftingDataCache::RECIPE_ID_OFFSET;
|
||||
$recipe = $craftingManager->getCraftingRecipeFromIndex($recipeIndex);
|
||||
if($recipe === null){
|
||||
throw new ItemStackRequestProcessException("No such crafting recipe index: $recipeId");
|
||||
throw new ItemStackRequestProcessException("No such crafting recipe index: $recipeIndex");
|
||||
}
|
||||
|
||||
$this->specialTransaction = new CraftingTransaction($this->player, $craftingManager, [], $recipe, $repetitions);
|
||||
|
@ -36,6 +36,7 @@ use pocketmine\network\mcpe\protocol\types\Experiments;
|
||||
use pocketmine\network\mcpe\protocol\types\resourcepacks\ResourcePackInfoEntry;
|
||||
use pocketmine\network\mcpe\protocol\types\resourcepacks\ResourcePackStackEntry;
|
||||
use pocketmine\network\mcpe\protocol\types\resourcepacks\ResourcePackType;
|
||||
use pocketmine\network\PacketHandlingException;
|
||||
use pocketmine\resourcepacks\ResourcePack;
|
||||
use Ramsey\Uuid\Uuid;
|
||||
use function array_keys;
|
||||
@ -43,6 +44,7 @@ use function array_map;
|
||||
use function ceil;
|
||||
use function count;
|
||||
use function implode;
|
||||
use function sprintf;
|
||||
use function strpos;
|
||||
use function strtolower;
|
||||
use function substr;
|
||||
@ -66,6 +68,9 @@ class ResourcePacksPacketHandler extends PacketHandler{
|
||||
*/
|
||||
private array $resourcePacksById = [];
|
||||
|
||||
private bool $requestedMetadata = false;
|
||||
private bool $requestedStack = false;
|
||||
|
||||
/** @var bool[][] uuid => [chunk index => hasSent] */
|
||||
private array $downloadedChunks = [];
|
||||
|
||||
@ -140,6 +145,21 @@ class ResourcePacksPacketHandler extends PacketHandler{
|
||||
$this->session->disconnect("Refused resource packs", "You must accept resource packs to join this server.", true);
|
||||
break;
|
||||
case ResourcePackClientResponsePacket::STATUS_SEND_PACKS:
|
||||
if($this->requestedMetadata){
|
||||
throw new PacketHandlingException("Cannot request resource pack metadata multiple times");
|
||||
}
|
||||
$this->requestedMetadata = true;
|
||||
|
||||
if($this->requestedStack){
|
||||
//client already told us that they have all the packs, they shouldn't be asking for more
|
||||
throw new PacketHandlingException("Cannot request resource pack metadata after resource pack stack");
|
||||
}
|
||||
|
||||
if(count($packet->packIds) > count($this->resourcePacksById)){
|
||||
throw new PacketHandlingException(sprintf("Requested metadata for more resource packs (%d) than available on the server (%d)", count($packet->packIds), count($this->resourcePacksById)));
|
||||
}
|
||||
|
||||
$seen = [];
|
||||
foreach($packet->packIds as $uuid){
|
||||
//dirty hack for mojang's dirty hack for versions
|
||||
$splitPos = strpos($uuid, "_");
|
||||
@ -153,6 +173,9 @@ class ResourcePacksPacketHandler extends PacketHandler{
|
||||
$this->disconnectWithError("Unknown pack $uuid requested, available packs: " . implode(", ", array_keys($this->resourcePacksById)));
|
||||
return false;
|
||||
}
|
||||
if(isset($seen[$pack->getPackId()])){
|
||||
throw new PacketHandlingException("Repeated metadata request for pack $uuid");
|
||||
}
|
||||
|
||||
$this->session->sendDataPacket(ResourcePackDataInfoPacket::create(
|
||||
$pack->getPackId(),
|
||||
@ -163,11 +186,16 @@ class ResourcePacksPacketHandler extends PacketHandler{
|
||||
false,
|
||||
ResourcePackType::RESOURCES //TODO: this might be an addon (not behaviour pack), needed to properly support client-side custom items
|
||||
));
|
||||
$seen[$pack->getPackId()] = true;
|
||||
}
|
||||
$this->session->getLogger()->debug("Player requested download of " . count($packet->packIds) . " resource packs");
|
||||
|
||||
break;
|
||||
case ResourcePackClientResponsePacket::STATUS_HAVE_ALL_PACKS:
|
||||
if($this->requestedStack){
|
||||
throw new PacketHandlingException("Cannot request resource pack stack multiple times");
|
||||
}
|
||||
$this->requestedStack = true;
|
||||
|
||||
$stack = array_map(static function(ResourcePack $pack) : ResourcePackStackEntry{
|
||||
return new ResourcePackStackEntry($pack->getPackId(), $pack->getPackVersion(), ""); //TODO: subpacks
|
||||
}, $this->resourcePackStack);
|
||||
|
Reference in New Issue
Block a user