mirror of
https://github.com/PaperMC/Paper.git
synced 2025-01-13 21:24:00 +01:00
Merge branch 'PaperMC:main' into add-effectiveName
This commit is contained in:
commit
791b26c200
1522 changed files with 58178 additions and 70227 deletions
|
@ -32,10 +32,7 @@ ij_java_generate_final_parameters = true
|
|||
ij_java_method_parameters_new_line_after_left_paren = true
|
||||
ij_java_method_parameters_right_paren_on_new_line = true
|
||||
|
||||
[test-plugin/**/*.java]
|
||||
ij_java_use_fq_class_names = false
|
||||
|
||||
[Paper-Server/src/main/resources/data/**/*.json]
|
||||
[paper-server/src/minecraft/resources/data/**/*.json]
|
||||
indent_size = 2
|
||||
|
||||
[paper-api-generator/generated/**/*.java]
|
||||
|
|
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
|
@ -102,7 +102,7 @@ jobs:
|
|||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: paper-${{ fromJSON(steps.determine.outputs.result).pr }}
|
||||
path: build/libs/paper-paperclip-*-mojmap.jar
|
||||
path: paper-server/build/libs/paper-paperclip-*-mojmap.jar
|
||||
event_file:
|
||||
name: "Event File"
|
||||
# Only run on PRs if the source branch is on someone else's repo
|
||||
|
|
10
.github/workflows/close_invalid_prs.yml
vendored
10
.github/workflows/close_invalid_prs.yml
vendored
|
@ -9,19 +9,19 @@ jobs:
|
|||
if: |
|
||||
github.repository != github.event.pull_request.head.repo.full_name &&
|
||||
(
|
||||
github.head_ref == 'master' ||
|
||||
github.head_ref == 'main' ||
|
||||
github.event.pull_request.head.repo.owner.type != 'User'
|
||||
)
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: superbrothers/close-pull-request@v3
|
||||
id: "master_branch"
|
||||
if: github.head_ref == 'master'
|
||||
id: "main_branch"
|
||||
if: github.head_ref == 'main'
|
||||
with:
|
||||
comment: "Please do not open pull requests from the `master` branch, create a new branch instead."
|
||||
comment: "Please do not open pull requests from the `main` branch, create a new branch instead."
|
||||
|
||||
- uses: superbrothers/close-pull-request@v3
|
||||
id: "org_account"
|
||||
if: github.event.pull_request.head.repo.owner.type != 'User' && steps.master_branch.outcome == 'skipped'
|
||||
if: github.event.pull_request.head.repo.owner.type != 'User' && steps.main_branch.outcome == 'skipped'
|
||||
with:
|
||||
comment: "Please do not open pull requests from non-user accounts like organizations. Create a fork on a user account instead."
|
||||
|
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -48,4 +48,4 @@ test-plugin.settings.gradle.kts
|
|||
paper-api-generator.settings.gradle.kts
|
||||
|
||||
# Don't track patched vanilla submodules
|
||||
paper-server/src/vanilla/
|
||||
paper-server/src/minecraft/
|
||||
|
|
|
@ -66,16 +66,16 @@ Assuming you have already forked the repository:
|
|||
2. Type `./gradlew applyPatches` in a terminal to apply the changes from upstream.
|
||||
On Windows, replace the `./` with `.\` at the beginning for all `gradlew` commands;
|
||||
3. cd into `paper-server` for server changes, and `paper-api` for API changes.
|
||||
**Only changes made in `paper-server/src/vanilla` have to deal with the patch system.**
|
||||
**Only changes made in `paper-server/src/minecraft` have to deal with the patch system.**
|
||||
|
||||
`paper-server/src/vanilla` is not a git repositories in the traditional sense. Its
|
||||
initial commits are the decompiled and deobfuscated Vanilla source files. The per-file
|
||||
`paper-server/src/minecraft` is not a git repositories in the traditional sense. Its
|
||||
initial commits are the decompiled and deobfuscated Minecraft source files. The per-file
|
||||
patches are applied on top of these files as a single, large commit, which is then followed
|
||||
by the individual feature-patch commits.
|
||||
|
||||
### Modifying (per-file) Vanilla patches
|
||||
### Modifying (per-file) Minecraft patches
|
||||
|
||||
This is generally what you need to do when editing Vanilla files. Updating our
|
||||
This is generally what you need to do when editing Minecraft files. Updating our
|
||||
per-file patches is as easy as making your changes and then running
|
||||
# TODO
|
||||
in the root directory. If nothing went wrong, you can rebuild patches with
|
||||
|
@ -169,13 +169,14 @@ move it under the line of the patch you wish to modify;
|
|||
|
||||
1. Make your change while at HEAD;
|
||||
1. Make a fixup commit. `git commit -a --fixup <hashOfPatchToFix>`;
|
||||
- If you want to modify a per-file patch, use `git commit -a --fixup file`
|
||||
- You can also use `--squash` instead of `--fixup` if you want the commit
|
||||
message to also be changed.
|
||||
- You can get the hash by looking at `git log` or `git blame`; your IDE can
|
||||
assist you too.
|
||||
- Alternatively, if you only know the name of the patch, you can do
|
||||
`git commit -a --fixup "Subject of Patch name"`.
|
||||
1. Rebase with autosquash: `git rebase -i --autosquash base`.
|
||||
1. Rebase with autosquash: `git rebase -i --autosquash mache/main`.
|
||||
This will automatically move your fixup commit to the right place, and you just
|
||||
need to "save" the changes.
|
||||
1. Type `./gradlew rebuildPatches` in the root directory;
|
||||
|
@ -184,11 +185,11 @@ need to "save" the changes.
|
|||
|
||||
## Rebasing PRs
|
||||
|
||||
Steps to rebase a PR to include the latest changes from `master`.
|
||||
Steps to rebase a PR to include the latest changes from `main`.
|
||||
These steps assume the `origin` remote is your fork of this repository and `upstream` is the official PaperMC repository.
|
||||
|
||||
1. Pull the latest changes from upstreams master: `git switch main && git pull upstream main`.
|
||||
1. Checkout feature/fix branch and rebase on master: `git checkout patch-branch && git rebase main`.
|
||||
1. Pull the latest changes from upstreams main: `git switch main && git pull upstream main`.
|
||||
1. Checkout feature/fix branch and rebase on main: `git checkout patch-branch && git rebase main`.
|
||||
1. Apply updated patches: `./gradlew applyPatches`.
|
||||
1. If there are conflicts, fix them.
|
||||
1. If your PR creates new feature patches instead of modifying existing ones, ensure your newly-created patch is the last commit by either:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
Paper [![Paper Build Status](https://img.shields.io/github/actions/workflow/status/PaperMC/Paper/build.yml?branch=master)](https://github.com/PaperMC/Paper/actions)
|
||||
Paper [![Paper Build Status](https://img.shields.io/github/actions/workflow/status/PaperMC/Paper/build.yml?branch=main)](https://github.com/PaperMC/Paper/actions)
|
||||
[![Discord](https://img.shields.io/discord/289587909051416579.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.gg/papermc)
|
||||
[![GitHub Sponsors](https://img.shields.io/github/sponsors/papermc?label=GitHub%20Sponsors)](https://github.com/sponsors/PaperMC)
|
||||
[![Open Collective](https://img.shields.io/opencollective/all/papermc?label=OpenCollective%20Sponsors)](https://opencollective.com/papermc)
|
||||
|
@ -65,7 +65,7 @@ How To (Compiling Jar From Source)
|
|||
------
|
||||
To compile Paper, you need JDK 21 and an internet connection.
|
||||
|
||||
Clone this repo, run `./gradlew applyPatches`, then `./gradlew createMojmapBundlerJar` from your terminal. You can find the compiled jar in the project root's `build/libs` directory.
|
||||
Clone this repo, run `./gradlew applyPatches`, then `./gradlew createMojmapBundlerJar` from your terminal. You can find the compiled jar in the `paper-server/build/libs` directory.
|
||||
|
||||
To get a full list of tasks, run `./gradlew tasks`.
|
||||
|
||||
|
@ -73,6 +73,10 @@ How To (Pull Request)
|
|||
------
|
||||
See [Contributing](CONTRIBUTING.md)
|
||||
|
||||
Old Versions (1.21.3 and below)
|
||||
------
|
||||
For branches of versions 1.8-1.21.3, please see our [archive repository](https://github.com/PaperMC/Paper-archive).
|
||||
|
||||
Support Us
|
||||
------
|
||||
First of all, thank you for considering helping out, we really appreciate that!
|
||||
|
|
|
@ -12,4 +12,3 @@
|
|||
# mc_data chat_type/chat.json
|
||||
# mc_data dimension_type/overworld.json
|
||||
#
|
||||
|
||||
|
|
|
@ -1,18 +1,735 @@
|
|||
# You can use this file to change the access modifiers on a member
|
||||
# This line would make the field rollAmount public in Bee
|
||||
#public net.minecraft.world.entity.animal.Bee rollAmount
|
||||
# This line would make the field public and remove the final modifier
|
||||
#public-f net.minecraft.network.protocol.game.ClientboundChatPacket sender
|
||||
# Leave out the member and it will apply to the class itself
|
||||
# More info, see here https://mcforge.readthedocs.io/en/latest/advanced/accesstransformers/#access-modifiers
|
||||
|
||||
# Remap/Decompile fix (unclear why this is happening)
|
||||
public net.minecraft.server.MinecraftServer doRunTask(Lnet/minecraft/server/TickTask;)V
|
||||
|
||||
# AT remap issue? todo 1.18
|
||||
public net.minecraft.world.level.dimension.end.EndDragonFight findExitPortal()Lnet/minecraft/world/level/block/state/pattern/BlockPattern$BlockPatternMatch;
|
||||
# This file is auto generated, any changes may be overridden!
|
||||
# See CONTRIBUTING.md on how to add access transformers.
|
||||
private-f net.minecraft.network.CompressionDecoder inflater
|
||||
private-f net.minecraft.server.MinecraftServer connection
|
||||
private-f net.minecraft.server.MinecraftServer levels
|
||||
private-f net.minecraft.world.item.ItemStack components
|
||||
private-f net.minecraft.world.item.ItemStack item
|
||||
private-f net.minecraft.world.level.block.entity.BeehiveBlockEntity stored
|
||||
protected net.minecraft.world.entity.LivingEntity skipDropExperience
|
||||
protected-f net.minecraft.server.MinecraftServer worldData
|
||||
public net.minecraft.ChatFormatting code
|
||||
public net.minecraft.Util onThreadException(Ljava/lang/Thread;Ljava/lang/Throwable;)V
|
||||
public net.minecraft.advancements.Advancement decorateName(Lnet/minecraft/advancements/DisplayInfo;)Lnet/minecraft/network/chat/Component;
|
||||
public net.minecraft.commands.CommandSourceStack source
|
||||
public net.minecraft.commands.arguments.DimensionArgument ERROR_INVALID_VALUE
|
||||
public net.minecraft.commands.arguments.blocks.BlockInput tag
|
||||
public net.minecraft.core.MappedRegistry validateWrite(Lnet/minecraft/resources/ResourceKey;)V
|
||||
public net.minecraft.nbt.ListTag <init>(Ljava/util/List;B)V
|
||||
public net.minecraft.nbt.TagParser readArrayTag()Lnet/minecraft/nbt/Tag;
|
||||
|
||||
# TODO 1.20 remapSpigotAt.at doesn't remap the return type for this method for some reason
|
||||
public net/minecraft/world/entity/Display$TextDisplay getText()Lnet/minecraft/network/chat/Component;
|
||||
public net/minecraft/world/entity/Display$BlockDisplay getBlockState()Lnet/minecraft/world/level/block/state/BlockState;
|
||||
public net.minecraft.nbt.TagParser type(Ljava/lang/String;)Lnet/minecraft/nbt/Tag;
|
||||
public net.minecraft.network.Connection address
|
||||
public net.minecraft.network.Connection channel
|
||||
public net.minecraft.network.chat.HoverEvent$ItemStackInfo components
|
||||
public net.minecraft.network.chat.HoverEvent$ItemStackInfo count
|
||||
public net.minecraft.network.chat.HoverEvent$ItemStackInfo item
|
||||
public net.minecraft.network.chat.TextColor name
|
||||
public net.minecraft.network.chat.contents.TranslatableContents filterAllowedArguments(Ljava/lang/Object;)Lcom/mojang/serialization/DataResult;
|
||||
public net.minecraft.network.chat.numbers.FixedFormat value
|
||||
public net.minecraft.network.chat.numbers.StyledFormat style
|
||||
public net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket <init>(Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/entity/BlockEntityType;Lnet/minecraft/nbt/CompoundTag;)V
|
||||
public net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket blockState
|
||||
public net.minecraft.network.protocol.game.ClientboundSetDefaultSpawnPositionPacket pos
|
||||
public net.minecraft.network.protocol.game.ServerboundMovePlayerPacket hasPos
|
||||
public net.minecraft.network.protocol.game.ServerboundMovePlayerPacket hasRot
|
||||
public net.minecraft.network.protocol.game.ServerboundMovePlayerPacket x
|
||||
public net.minecraft.network.protocol.game.ServerboundMovePlayerPacket xRot
|
||||
public net.minecraft.network.protocol.game.ServerboundMovePlayerPacket y
|
||||
public net.minecraft.network.protocol.game.ServerboundMovePlayerPacket yRot
|
||||
public net.minecraft.network.protocol.game.ServerboundMovePlayerPacket z
|
||||
public net.minecraft.resources.RegistryOps lookupProvider
|
||||
public net.minecraft.resources.RegistryOps$HolderLookupAdapter
|
||||
public net.minecraft.server.Main forceUpgrade(Lnet/minecraft/world/level/storage/LevelStorageSource$LevelStorageAccess;Lcom/mojang/datafixers/DataFixer;ZLjava/util/function/BooleanSupplier;Lnet/minecraft/core/RegistryAccess;Z)V
|
||||
public net.minecraft.server.MinecraftServer LOGGER
|
||||
public net.minecraft.server.MinecraftServer doRunTask(Lnet/minecraft/server/TickTask;)V
|
||||
public net.minecraft.server.MinecraftServer executor
|
||||
public net.minecraft.server.MinecraftServer fixerUpper
|
||||
public net.minecraft.server.MinecraftServer playerDataStorage
|
||||
public net.minecraft.server.MinecraftServer prepareLevels(Lnet/minecraft/server/level/progress/ChunkProgressListener;)V
|
||||
public net.minecraft.server.MinecraftServer progressListenerFactory
|
||||
public net.minecraft.server.MinecraftServer resources
|
||||
public net.minecraft.server.MinecraftServer serverThread
|
||||
public net.minecraft.server.MinecraftServer$ReloadableResources
|
||||
public net.minecraft.server.RegistryLayer STATIC_ACCESS
|
||||
public net.minecraft.server.ReloadableServerResources
|
||||
public net.minecraft.server.ServerAdvancementManager advancements
|
||||
public net.minecraft.server.dedicated.DedicatedServerProperties$WorldDimensionData
|
||||
public net.minecraft.server.dedicated.Settings getStringRaw(Ljava/lang/String;)Ljava/lang/String;
|
||||
public net.minecraft.server.dedicated.Settings properties
|
||||
public net.minecraft.server.level.ChunkHolder oldTicketLevel
|
||||
public net.minecraft.server.level.ChunkHolder playerProvider
|
||||
public net.minecraft.server.level.ChunkLevel ENTITY_TICKING_LEVEL
|
||||
public net.minecraft.server.level.ChunkMap addEntity(Lnet/minecraft/world/entity/Entity;)V
|
||||
public net.minecraft.server.level.ChunkMap anyPlayerCloseEnoughForSpawning(Lnet/minecraft/world/level/ChunkPos;)Z
|
||||
public net.minecraft.server.level.ChunkMap distanceManager
|
||||
public net.minecraft.server.level.ChunkMap entityMap
|
||||
public net.minecraft.server.level.ChunkMap getVisibleChunkIfPresent(J)Lnet/minecraft/server/level/ChunkHolder;
|
||||
public net.minecraft.server.level.ChunkMap level
|
||||
public net.minecraft.server.level.ChunkMap progressListener
|
||||
public net.minecraft.server.level.ChunkMap save(Lnet/minecraft/world/level/chunk/ChunkAccess;)Z
|
||||
public net.minecraft.server.level.ChunkMap serverViewDistance
|
||||
public net.minecraft.server.level.ChunkMap setServerViewDistance(I)V
|
||||
public net.minecraft.server.level.ChunkMap toDrop
|
||||
public net.minecraft.server.level.ChunkMap updatingChunkMap
|
||||
public net.minecraft.server.level.ChunkMap visibleChunkMap
|
||||
public net.minecraft.server.level.ChunkMap$TrackedEntity
|
||||
public net.minecraft.server.level.ChunkMap$TrackedEntity seenBy
|
||||
public net.minecraft.server.level.ChunkMap$TrackedEntity serverEntity
|
||||
public net.minecraft.server.level.DistanceManager simulationDistance
|
||||
public net.minecraft.server.level.DistanceManager tickets
|
||||
public net.minecraft.server.level.ServerBossEvent broadcast(Ljava/util/function/Function;)V
|
||||
public net.minecraft.server.level.ServerBossEvent visible
|
||||
public net.minecraft.server.level.ServerChunkCache mainThread
|
||||
public net.minecraft.server.level.ServerChunkCache mainThreadProcessor
|
||||
public net.minecraft.server.level.ServerChunkCache spawnEnemies
|
||||
public net.minecraft.server.level.ServerChunkCache spawnFriendlies
|
||||
public net.minecraft.server.level.ServerChunkCache$MainThreadExecutor
|
||||
public net.minecraft.server.level.ServerLevel chunkSource
|
||||
public net.minecraft.server.level.ServerLevel entityManager
|
||||
public net.minecraft.server.level.ServerLevel findLightningRod(Lnet/minecraft/core/BlockPos;)Ljava/util/Optional;
|
||||
public net.minecraft.server.level.ServerLevel getEntities()Lnet/minecraft/world/level/entity/LevelEntityGetter;
|
||||
public net.minecraft.server.level.ServerLevel serverLevelData
|
||||
public net.minecraft.server.level.ServerPlayer completeUsingItem()V
|
||||
public net.minecraft.server.level.ServerPlayer containerSynchronizer
|
||||
public net.minecraft.server.level.ServerPlayer findRespawnAndUseSpawnBlock(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/core/BlockPos;FZZ)Ljava/util/Optional;
|
||||
public net.minecraft.server.level.ServerPlayer initMenu(Lnet/minecraft/world/inventory/AbstractContainerMenu;)V
|
||||
public net.minecraft.server.level.ServerPlayer isChangingDimension
|
||||
public net.minecraft.server.level.ServerPlayer language
|
||||
public net.minecraft.server.level.ServerPlayer lastSentExp
|
||||
public net.minecraft.server.level.ServerPlayer nextContainerCounter()V
|
||||
public net.minecraft.server.level.ServerPlayer particleStatus
|
||||
public net.minecraft.server.level.ServerPlayer seenCredits
|
||||
public net.minecraft.server.level.ServerPlayer triggerDimensionChangeTriggers(Lnet/minecraft/server/level/ServerLevel;)V
|
||||
public net.minecraft.server.level.ServerPlayer wardenSpawnTracker
|
||||
public net.minecraft.server.level.ServerPlayer$RespawnPosAngle
|
||||
public net.minecraft.server.level.ServerPlayerGameMode level
|
||||
public net.minecraft.server.level.Ticket key
|
||||
public net.minecraft.server.network.ServerGamePacketListenerImpl isChatMessageIllegal(Ljava/lang/String;)Z
|
||||
public net.minecraft.server.network.ServerLoginPacketListenerImpl authenticatedProfile
|
||||
public net.minecraft.server.network.ServerLoginPacketListenerImpl connection
|
||||
public net.minecraft.server.network.ServerLoginPacketListenerImpl state
|
||||
public net.minecraft.server.network.ServerLoginPacketListenerImpl$State
|
||||
public net.minecraft.server.packs.VanillaPackResourcesBuilder safeGetPath(Ljava/net/URI;)Ljava/nio/file/Path;
|
||||
public net.minecraft.server.packs.repository.Pack resources
|
||||
public net.minecraft.server.players.PlayerList playerIo
|
||||
public net.minecraft.server.players.PlayerList players
|
||||
public net.minecraft.server.players.PlayerList updateEntireScoreboard(Lnet/minecraft/server/ServerScoreboard;Lnet/minecraft/server/level/ServerPlayer;)V
|
||||
public net.minecraft.server.players.StoredUserEntry getUser()Ljava/lang/Object;
|
||||
public net.minecraft.stats.ServerRecipeBook known
|
||||
public net.minecraft.tags.TagEntry id
|
||||
public net.minecraft.tags.TagEntry required
|
||||
public net.minecraft.tags.TagEntry tag
|
||||
public net.minecraft.util.datafix.fixes.BlockStateData register(ILjava/lang/String;[Ljava/lang/String;)V
|
||||
public net.minecraft.util.datafix.fixes.ItemIdFix ITEM_NAMES
|
||||
public net.minecraft.util.datafix.fixes.ItemSpawnEggFix ID_TO_ENTITY
|
||||
public net.minecraft.world.BossEvent color
|
||||
public net.minecraft.world.BossEvent name
|
||||
public net.minecraft.world.BossEvent overlay
|
||||
public net.minecraft.world.CompoundContainer container1
|
||||
public net.minecraft.world.CompoundContainer container2
|
||||
public net.minecraft.world.SimpleContainer items
|
||||
public net.minecraft.world.damagesource.DamageSource <init>(Lnet/minecraft/core/Holder;Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/phys/Vec3;)V
|
||||
public net.minecraft.world.effect.MobEffect attributeModifiers
|
||||
public net.minecraft.world.effect.MobEffect$AttributeTemplate
|
||||
public net.minecraft.world.effect.MobEffectInstance hiddenEffect
|
||||
public net.minecraft.world.entity.AreaEffectCloud durationOnUse
|
||||
public net.minecraft.world.entity.AreaEffectCloud ownerUUID
|
||||
public net.minecraft.world.entity.AreaEffectCloud potionContents
|
||||
public net.minecraft.world.entity.AreaEffectCloud radiusOnUse
|
||||
public net.minecraft.world.entity.AreaEffectCloud radiusPerTick
|
||||
public net.minecraft.world.entity.AreaEffectCloud reapplicationDelay
|
||||
public net.minecraft.world.entity.AreaEffectCloud updateColor()V
|
||||
public net.minecraft.world.entity.AreaEffectCloud waitTime
|
||||
public net.minecraft.world.entity.Display DATA_POS_ROT_INTERPOLATION_DURATION_ID
|
||||
public net.minecraft.world.entity.Display createTransformation(Lnet/minecraft/network/syncher/SynchedEntityData;)Lcom/mojang/math/Transformation;
|
||||
public net.minecraft.world.entity.Display getBillboardConstraints()Lnet/minecraft/world/entity/Display$BillboardConstraints;
|
||||
public net.minecraft.world.entity.Display getBrightnessOverride()Lnet/minecraft/util/Brightness;
|
||||
public net.minecraft.world.entity.Display getGlowColorOverride()I
|
||||
public net.minecraft.world.entity.Display getHeight()F
|
||||
public net.minecraft.world.entity.Display getShadowRadius()F
|
||||
public net.minecraft.world.entity.Display getShadowStrength()F
|
||||
public net.minecraft.world.entity.Display getTransformationInterpolationDelay()I
|
||||
public net.minecraft.world.entity.Display getTransformationInterpolationDuration()I
|
||||
public net.minecraft.world.entity.Display getViewRange()F
|
||||
public net.minecraft.world.entity.Display getWidth()F
|
||||
public net.minecraft.world.entity.Display setBillboardConstraints(Lnet/minecraft/world/entity/Display$BillboardConstraints;)V
|
||||
public net.minecraft.world.entity.Display setBrightnessOverride(Lnet/minecraft/util/Brightness;)V
|
||||
public net.minecraft.world.entity.Display setGlowColorOverride(I)V
|
||||
public net.minecraft.world.entity.Display setHeight(F)V
|
||||
public net.minecraft.world.entity.Display setShadowRadius(F)V
|
||||
public net.minecraft.world.entity.Display setShadowStrength(F)V
|
||||
public net.minecraft.world.entity.Display setTransformation(Lcom/mojang/math/Transformation;)V
|
||||
public net.minecraft.world.entity.Display setTransformationInterpolationDelay(I)V
|
||||
public net.minecraft.world.entity.Display setTransformationInterpolationDuration(I)V
|
||||
public net.minecraft.world.entity.Display setViewRange(F)V
|
||||
public net.minecraft.world.entity.Display setWidth(F)V
|
||||
public net.minecraft.world.entity.Display$BlockDisplay getBlockState()Lnet/minecraft/world/level/block/state/BlockState;
|
||||
public net.minecraft.world.entity.Display$BlockDisplay setBlockState(Lnet/minecraft/world/level/block/state/BlockState;)V
|
||||
public net.minecraft.world.entity.Display$ItemDisplay getItemStack()Lnet/minecraft/world/item/ItemStack;
|
||||
public net.minecraft.world.entity.Display$ItemDisplay getItemTransform()Lnet/minecraft/world/item/ItemDisplayContext;
|
||||
public net.minecraft.world.entity.Display$ItemDisplay setItemStack(Lnet/minecraft/world/item/ItemStack;)V
|
||||
public net.minecraft.world.entity.Display$ItemDisplay setItemTransform(Lnet/minecraft/world/item/ItemDisplayContext;)V
|
||||
public net.minecraft.world.entity.Display$TextDisplay DATA_BACKGROUND_COLOR_ID
|
||||
public net.minecraft.world.entity.Display$TextDisplay DATA_LINE_WIDTH_ID
|
||||
public net.minecraft.world.entity.Display$TextDisplay getBackgroundColor()I
|
||||
public net.minecraft.world.entity.Display$TextDisplay getFlags()B
|
||||
public net.minecraft.world.entity.Display$TextDisplay getLineWidth()I
|
||||
public net.minecraft.world.entity.Display$TextDisplay getText()Lnet/minecraft/network/chat/Component;
|
||||
public net.minecraft.world.entity.Display$TextDisplay getTextOpacity()B
|
||||
public net.minecraft.world.entity.Display$TextDisplay setFlags(B)V
|
||||
public net.minecraft.world.entity.Display$TextDisplay setText(Lnet/minecraft/network/chat/Component;)V
|
||||
public net.minecraft.world.entity.Display$TextDisplay setTextOpacity(B)V
|
||||
public net.minecraft.world.entity.Entity FLAG_INVISIBLE
|
||||
public net.minecraft.world.entity.Entity getEncodeId()Ljava/lang/String;
|
||||
public net.minecraft.world.entity.Entity getFireImmuneTicks()I
|
||||
public net.minecraft.world.entity.Entity getSharedFlag(I)Z
|
||||
public net.minecraft.world.entity.Entity hasVisualFire
|
||||
public net.minecraft.world.entity.Entity isInBubbleColumn()Z
|
||||
public net.minecraft.world.entity.Entity isInRain()Z
|
||||
public net.minecraft.world.entity.Entity isInvulnerableToBase(Lnet/minecraft/world/damagesource/DamageSource;)Z
|
||||
public net.minecraft.world.entity.Entity onGround
|
||||
public net.minecraft.world.entity.Entity passengers
|
||||
public net.minecraft.world.entity.Entity portalCooldown
|
||||
public net.minecraft.world.entity.Entity random
|
||||
public net.minecraft.world.entity.Entity setLevel(Lnet/minecraft/world/level/Level;)V
|
||||
public net.minecraft.world.entity.Entity setRot(FF)V
|
||||
public net.minecraft.world.entity.Entity setSharedFlag(IZ)V
|
||||
public net.minecraft.world.entity.Entity unsetRemoved()V
|
||||
public net.minecraft.world.entity.Entity wasTouchingWater
|
||||
public net.minecraft.world.entity.ExperienceOrb count
|
||||
public net.minecraft.world.entity.ExperienceOrb value
|
||||
public net.minecraft.world.entity.GlowSquid setDarkTicks(I)V
|
||||
public net.minecraft.world.entity.Interaction attack
|
||||
public net.minecraft.world.entity.Interaction getHeight()F
|
||||
public net.minecraft.world.entity.Interaction getResponse()Z
|
||||
public net.minecraft.world.entity.Interaction getWidth()F
|
||||
public net.minecraft.world.entity.Interaction interaction
|
||||
public net.minecraft.world.entity.Interaction setHeight(F)V
|
||||
public net.minecraft.world.entity.Interaction setResponse(Z)V
|
||||
public net.minecraft.world.entity.Interaction setWidth(F)V
|
||||
public net.minecraft.world.entity.Interaction$PlayerAction
|
||||
public net.minecraft.world.entity.ItemBasedSteering boostTime
|
||||
public net.minecraft.world.entity.ItemBasedSteering boostTimeTotal()I
|
||||
public net.minecraft.world.entity.ItemBasedSteering boosting
|
||||
public net.minecraft.world.entity.LightningBolt flashes
|
||||
public net.minecraft.world.entity.LightningBolt life
|
||||
public net.minecraft.world.entity.LightningBolt visualOnly
|
||||
public net.minecraft.world.entity.LivingEntity DATA_ARROW_COUNT_ID
|
||||
public net.minecraft.world.entity.LivingEntity DATA_HEALTH_ID
|
||||
public net.minecraft.world.entity.LivingEntity LIVING_ENTITY_FLAG_SPIN_ATTACK
|
||||
public net.minecraft.world.entity.LivingEntity activeEffects
|
||||
public net.minecraft.world.entity.LivingEntity completeUsingItem()V
|
||||
public net.minecraft.world.entity.LivingEntity detectEquipmentUpdates()V
|
||||
public net.minecraft.world.entity.LivingEntity effectsDirty
|
||||
public net.minecraft.world.entity.LivingEntity entityEventForEquipmentBreak(Lnet/minecraft/world/entity/EquipmentSlot;)B
|
||||
public net.minecraft.world.entity.LivingEntity getDeathSound()Lnet/minecraft/sounds/SoundEvent;
|
||||
public net.minecraft.world.entity.LivingEntity getSoundVolume()F
|
||||
public net.minecraft.world.entity.LivingEntity jumping
|
||||
public net.minecraft.world.entity.LivingEntity lastHurt
|
||||
public net.minecraft.world.entity.LivingEntity lastHurtByMob
|
||||
public net.minecraft.world.entity.LivingEntity lastHurtByMobTimestamp
|
||||
public net.minecraft.world.entity.LivingEntity lastHurtByPlayer
|
||||
public net.minecraft.world.entity.LivingEntity lastHurtByPlayerTime
|
||||
public net.minecraft.world.entity.LivingEntity setLivingEntityFlag(IZ)V
|
||||
public net.minecraft.world.entity.LivingEntity useItemRemaining
|
||||
public net.minecraft.world.entity.Mob armorDropChances
|
||||
public net.minecraft.world.entity.Mob getEquipmentDropChance(Lnet/minecraft/world/entity/EquipmentSlot;)F
|
||||
public net.minecraft.world.entity.Mob handDropChances
|
||||
public net.minecraft.world.entity.Mob isSunBurnTick()Z
|
||||
public net.minecraft.world.entity.Mob lootTable
|
||||
public net.minecraft.world.entity.Mob lootTableSeed
|
||||
public net.minecraft.world.entity.OminousItemSpawner setItem(Lnet/minecraft/world/item/ItemStack;)V
|
||||
public net.minecraft.world.entity.OminousItemSpawner spawnItemAfterTicks
|
||||
public net.minecraft.world.entity.ai.attributes.AttributeSupplier getAttributeInstance(Lnet/minecraft/core/Holder;)Lnet/minecraft/world/entity/ai/attributes/AttributeInstance;
|
||||
public net.minecraft.world.entity.ai.control.MoveControl$Operation
|
||||
public net.minecraft.world.entity.ai.gossip.GossipContainer gossips
|
||||
public net.minecraft.world.entity.ai.gossip.GossipContainer$EntityGossips
|
||||
public net.minecraft.world.entity.ai.gossip.GossipContainer$EntityGossips <init>()V
|
||||
public net.minecraft.world.entity.ai.navigation.PathNavigation pathFinder
|
||||
public net.minecraft.world.entity.ambient.Bat targetPosition
|
||||
public net.minecraft.world.entity.animal.AbstractSchoolingFish leader
|
||||
public net.minecraft.world.entity.animal.AbstractSchoolingFish schoolSize
|
||||
public net.minecraft.world.entity.animal.Animal inLove
|
||||
public net.minecraft.world.entity.animal.Animal loveCause
|
||||
public net.minecraft.world.entity.animal.Bee hivePos
|
||||
public net.minecraft.world.entity.animal.Bee isRolling()Z
|
||||
public net.minecraft.world.entity.animal.Bee numCropsGrownSincePollination
|
||||
public net.minecraft.world.entity.animal.Bee setHasNectar(Z)V
|
||||
public net.minecraft.world.entity.animal.Bee setHasStung(Z)V
|
||||
public net.minecraft.world.entity.animal.Bee setRolling(Z)V
|
||||
public net.minecraft.world.entity.animal.Bee stayOutOfHiveCountdown
|
||||
public net.minecraft.world.entity.animal.Bee ticksWithoutNectarSinceExitingHive
|
||||
public net.minecraft.world.entity.animal.Cat isRelaxStateOne()Z
|
||||
public net.minecraft.world.entity.animal.Cat setCollarColor(Lnet/minecraft/world/item/DyeColor;)V
|
||||
public net.minecraft.world.entity.animal.Cat setRelaxStateOne(Z)V
|
||||
public net.minecraft.world.entity.animal.Fox DATA_TRUSTED_ID_0
|
||||
public net.minecraft.world.entity.animal.Fox DATA_TRUSTED_ID_1
|
||||
public net.minecraft.world.entity.animal.Fox isDefending()Z
|
||||
public net.minecraft.world.entity.animal.Fox setDefending(Z)V
|
||||
public net.minecraft.world.entity.animal.Fox setFaceplanted(Z)V
|
||||
public net.minecraft.world.entity.animal.Fox setSleeping(Z)V
|
||||
public net.minecraft.world.entity.animal.MushroomCow stewEffects
|
||||
public net.minecraft.world.entity.animal.Ocelot isTrusting()Z
|
||||
public net.minecraft.world.entity.animal.Ocelot setTrusting(Z)V
|
||||
public net.minecraft.world.entity.animal.Panda getEatCounter()I
|
||||
public net.minecraft.world.entity.animal.Panda setEatCounter(I)V
|
||||
public net.minecraft.world.entity.animal.Pig steering
|
||||
public net.minecraft.world.entity.animal.Rabbit moreCarrotTicks
|
||||
public net.minecraft.world.entity.animal.Rabbit registerGoals()V
|
||||
public net.minecraft.world.entity.animal.TropicalFish getPackedVariant()I
|
||||
public net.minecraft.world.entity.animal.TropicalFish setPackedVariant(I)V
|
||||
public net.minecraft.world.entity.animal.Turtle getHomePos()Lnet/minecraft/core/BlockPos;
|
||||
public net.minecraft.world.entity.animal.Turtle isGoingHome()Z
|
||||
public net.minecraft.world.entity.animal.Turtle isTravelling()Z
|
||||
public net.minecraft.world.entity.animal.Turtle setGoingHome(Z)V
|
||||
public net.minecraft.world.entity.animal.Turtle setHasEgg(Z)V
|
||||
public net.minecraft.world.entity.animal.Turtle setTravelling(Z)V
|
||||
public net.minecraft.world.entity.animal.Wolf isWet
|
||||
public net.minecraft.world.entity.animal.Wolf setCollarColor(Lnet/minecraft/world/item/DyeColor;)V
|
||||
public net.minecraft.world.entity.animal.allay.Allay canDuplicate()Z
|
||||
public net.minecraft.world.entity.animal.allay.Allay duplicateAllay()V
|
||||
public net.minecraft.world.entity.animal.allay.Allay duplicationCooldown
|
||||
public net.minecraft.world.entity.animal.allay.Allay jukeboxPos
|
||||
public net.minecraft.world.entity.animal.allay.Allay resetDuplicationCooldown()V
|
||||
public net.minecraft.world.entity.animal.frog.Tadpole age
|
||||
public net.minecraft.world.entity.animal.goat.Goat DATA_HAS_LEFT_HORN
|
||||
public net.minecraft.world.entity.animal.goat.Goat DATA_HAS_RIGHT_HORN
|
||||
public net.minecraft.world.entity.animal.horse.AbstractHorse createInventory()V
|
||||
public net.minecraft.world.entity.animal.horse.AbstractHorse inventory
|
||||
public net.minecraft.world.entity.animal.horse.Horse setVariantAndMarkings(Lnet/minecraft/world/entity/animal/horse/Variant;Lnet/minecraft/world/entity/animal/horse/Markings;)V
|
||||
public net.minecraft.world.entity.animal.horse.SkeletonHorse trapTime
|
||||
public net.minecraft.world.entity.animal.sniffer.Sniffer calculateDigPosition()Ljava/util/Optional;
|
||||
public net.minecraft.world.entity.animal.sniffer.Sniffer canDig()Z
|
||||
public net.minecraft.world.entity.animal.sniffer.Sniffer getExploredPositions()Ljava/util/stream/Stream;
|
||||
public net.minecraft.world.entity.animal.sniffer.Sniffer getState()Lnet/minecraft/world/entity/animal/sniffer/Sniffer$State;
|
||||
public net.minecraft.world.entity.animal.sniffer.Sniffer storeExploredPosition(Lnet/minecraft/core/BlockPos;)Lnet/minecraft/world/entity/animal/sniffer/Sniffer;
|
||||
public net.minecraft.world.entity.boss.enderdragon.EnderDragon subEntities
|
||||
public net.minecraft.world.entity.boss.wither.WitherBoss bossEvent
|
||||
public net.minecraft.world.entity.decoration.ArmorStand bodyPose
|
||||
public net.minecraft.world.entity.decoration.ArmorStand disabledSlots
|
||||
public net.minecraft.world.entity.decoration.ArmorStand headPose
|
||||
public net.minecraft.world.entity.decoration.ArmorStand isDisabled(Lnet/minecraft/world/entity/EquipmentSlot;)Z
|
||||
public net.minecraft.world.entity.decoration.ArmorStand leftArmPose
|
||||
public net.minecraft.world.entity.decoration.ArmorStand leftLegPose
|
||||
public net.minecraft.world.entity.decoration.ArmorStand rightArmPose
|
||||
public net.minecraft.world.entity.decoration.ArmorStand rightLegPose
|
||||
public net.minecraft.world.entity.decoration.ArmorStand setMarker(Z)V
|
||||
public net.minecraft.world.entity.decoration.ArmorStand setSmall(Z)V
|
||||
public net.minecraft.world.entity.decoration.HangingEntity setDirection(Lnet/minecraft/core/Direction;)V
|
||||
public net.minecraft.world.entity.decoration.ItemFrame DATA_ITEM
|
||||
public net.minecraft.world.entity.decoration.ItemFrame DATA_ROTATION
|
||||
public net.minecraft.world.entity.decoration.ItemFrame dropChance
|
||||
public net.minecraft.world.entity.decoration.ItemFrame fixed
|
||||
public net.minecraft.world.entity.decoration.ItemFrame setDirection(Lnet/minecraft/core/Direction;)V
|
||||
public net.minecraft.world.entity.item.FallingBlockEntity <init>(Lnet/minecraft/world/level/Level;DDDLnet/minecraft/world/level/block/state/BlockState;)V
|
||||
public net.minecraft.world.entity.item.FallingBlockEntity blockState
|
||||
public net.minecraft.world.entity.item.FallingBlockEntity cancelDrop
|
||||
public net.minecraft.world.entity.item.FallingBlockEntity fallDamageMax
|
||||
public net.minecraft.world.entity.item.FallingBlockEntity fallDamagePerDistance
|
||||
public net.minecraft.world.entity.item.FallingBlockEntity hurtEntities
|
||||
public net.minecraft.world.entity.item.ItemEntity age
|
||||
public net.minecraft.world.entity.item.ItemEntity health
|
||||
public net.minecraft.world.entity.item.ItemEntity pickupDelay
|
||||
public net.minecraft.world.entity.item.ItemEntity target
|
||||
public net.minecraft.world.entity.item.ItemEntity thrower
|
||||
public net.minecraft.world.entity.item.PrimedTnt explosionPower
|
||||
public net.minecraft.world.entity.item.PrimedTnt owner
|
||||
public net.minecraft.world.entity.monster.Creeper explodeCreeper()V
|
||||
public net.minecraft.world.entity.monster.Creeper explosionRadius
|
||||
public net.minecraft.world.entity.monster.Creeper maxSwell
|
||||
public net.minecraft.world.entity.monster.Creeper swell
|
||||
public net.minecraft.world.entity.monster.Drowned groundNavigation
|
||||
public net.minecraft.world.entity.monster.Drowned waterNavigation
|
||||
public net.minecraft.world.entity.monster.EnderMan teleport()Z
|
||||
public net.minecraft.world.entity.monster.EnderMan teleportTowards(Lnet/minecraft/world/entity/Entity;)Z
|
||||
public net.minecraft.world.entity.monster.Endermite life
|
||||
public net.minecraft.world.entity.monster.Evoker getWololoTarget()Lnet/minecraft/world/entity/animal/Sheep;
|
||||
public net.minecraft.world.entity.monster.Evoker setWololoTarget(Lnet/minecraft/world/entity/animal/Sheep;)V
|
||||
public net.minecraft.world.entity.monster.Guardian randomStrollGoal
|
||||
public net.minecraft.world.entity.monster.Guardian setActiveAttackTarget(I)V
|
||||
public net.minecraft.world.entity.monster.Guardian$GuardianAttackGoal
|
||||
public net.minecraft.world.entity.monster.Guardian$GuardianAttackGoal attackTime
|
||||
public net.minecraft.world.entity.monster.Phantom anchorPoint
|
||||
public net.minecraft.world.entity.monster.Pillager inventory
|
||||
public net.minecraft.world.entity.monster.Ravager attackTick
|
||||
public net.minecraft.world.entity.monster.Ravager roarTick
|
||||
public net.minecraft.world.entity.monster.Ravager stunnedTick
|
||||
public net.minecraft.world.entity.monster.Shulker DATA_COLOR_ID
|
||||
public net.minecraft.world.entity.monster.Shulker getRawPeekAmount()I
|
||||
public net.minecraft.world.entity.monster.Shulker setAttachFace(Lnet/minecraft/core/Direction;)V
|
||||
public net.minecraft.world.entity.monster.Shulker setRawPeekAmount(I)V
|
||||
public net.minecraft.world.entity.monster.Skeleton DATA_STRAY_CONVERSION_ID
|
||||
public net.minecraft.world.entity.monster.Skeleton conversionTime
|
||||
public net.minecraft.world.entity.monster.Skeleton inPowderSnowTime
|
||||
public net.minecraft.world.entity.monster.SpellcasterIllager getCurrentSpell()Lnet/minecraft/world/entity/monster/SpellcasterIllager$IllagerSpell;
|
||||
public net.minecraft.world.entity.monster.SpellcasterIllager$IllagerSpell
|
||||
public net.minecraft.world.entity.monster.Strider steering
|
||||
public net.minecraft.world.entity.monster.Vex hasLimitedLife
|
||||
public net.minecraft.world.entity.monster.Vex limitedLifeTicks
|
||||
public net.minecraft.world.entity.monster.Vindicator DOOR_BREAKING_PREDICATE
|
||||
public net.minecraft.world.entity.monster.Vindicator isJohnny
|
||||
public net.minecraft.world.entity.monster.Witch usingTime
|
||||
public net.minecraft.world.entity.monster.Zombie DATA_DROWNED_CONVERSION_ID
|
||||
public net.minecraft.world.entity.monster.Zombie DOOR_BREAKING_PREDICATE
|
||||
public net.minecraft.world.entity.monster.Zombie conversionTime
|
||||
public net.minecraft.world.entity.monster.Zombie isSunSensitive()Z
|
||||
public net.minecraft.world.entity.monster.Zombie startUnderWaterConversion(I)V
|
||||
public net.minecraft.world.entity.monster.ZombieVillager DATA_CONVERTING_ID
|
||||
public net.minecraft.world.entity.monster.ZombieVillager conversionStarter
|
||||
public net.minecraft.world.entity.monster.ZombieVillager startConverting(Ljava/util/UUID;I)V
|
||||
public net.minecraft.world.entity.monster.ZombieVillager villagerConversionTime
|
||||
public net.minecraft.world.entity.monster.hoglin.Hoglin cannotBeHunted
|
||||
public net.minecraft.world.entity.monster.hoglin.Hoglin isImmuneToZombification()Z
|
||||
public net.minecraft.world.entity.monster.hoglin.Hoglin timeInOverworld
|
||||
public net.minecraft.world.entity.monster.piglin.AbstractPiglin isImmuneToZombification()Z
|
||||
public net.minecraft.world.entity.monster.piglin.AbstractPiglin timeInOverworld
|
||||
public net.minecraft.world.entity.monster.piglin.Piglin cannotHunt
|
||||
public net.minecraft.world.entity.monster.piglin.Piglin inventory
|
||||
public net.minecraft.world.entity.monster.piglin.Piglin isChargingCrossbow()Z
|
||||
public net.minecraft.world.entity.monster.warden.WardenSpawnTracker cooldownTicks
|
||||
public net.minecraft.world.entity.monster.warden.WardenSpawnTracker increaseWarningLevel()V
|
||||
public net.minecraft.world.entity.monster.warden.WardenSpawnTracker ticksSinceLastWarning
|
||||
public net.minecraft.world.entity.npc.Villager increaseMerchantCareer()V
|
||||
public net.minecraft.world.entity.npc.Villager numberOfRestocksToday
|
||||
public net.minecraft.world.entity.npc.Villager releaseAllPois()V
|
||||
public net.minecraft.world.entity.npc.Villager setUnhappy()V
|
||||
public net.minecraft.world.entity.npc.WanderingTrader getWanderTarget()Lnet/minecraft/core/BlockPos;
|
||||
public net.minecraft.world.entity.player.Abilities flyingSpeed
|
||||
public net.minecraft.world.entity.player.Abilities walkingSpeed
|
||||
public net.minecraft.world.entity.player.Inventory compartments
|
||||
public net.minecraft.world.entity.player.Player DATA_PLAYER_MODE_CUSTOMISATION
|
||||
public net.minecraft.world.entity.player.Player closeContainer()V
|
||||
public net.minecraft.world.entity.player.Player enchantmentSeed
|
||||
public net.minecraft.world.entity.player.Player getFireImmuneTicks()I
|
||||
public net.minecraft.world.entity.player.Player removeEntitiesOnShoulder()V
|
||||
public net.minecraft.world.entity.player.Player setShoulderEntityLeft(Lnet/minecraft/nbt/CompoundTag;)V
|
||||
public net.minecraft.world.entity.player.Player setShoulderEntityRight(Lnet/minecraft/nbt/CompoundTag;)V
|
||||
public net.minecraft.world.entity.player.Player sleepCounter
|
||||
public net.minecraft.world.entity.projectile.AbstractHurtingProjectile assignDirectionalMovement(Lnet/minecraft/world/phys/Vec3;D)V
|
||||
public net.minecraft.world.entity.projectile.Arrow NO_EFFECT_COLOR
|
||||
public net.minecraft.world.entity.projectile.Arrow getPotionContents()Lnet/minecraft/world/item/alchemy/PotionContents;
|
||||
public net.minecraft.world.entity.projectile.Arrow setPotionContents(Lnet/minecraft/world/item/alchemy/PotionContents;)V
|
||||
public net.minecraft.world.entity.projectile.Arrow updateColor()V
|
||||
public net.minecraft.world.entity.projectile.EvokerFangs warmupDelayTicks
|
||||
public net.minecraft.world.entity.projectile.EyeOfEnder life
|
||||
public net.minecraft.world.entity.projectile.EyeOfEnder surviveAfterDeath
|
||||
public net.minecraft.world.entity.projectile.EyeOfEnder tx
|
||||
public net.minecraft.world.entity.projectile.EyeOfEnder ty
|
||||
public net.minecraft.world.entity.projectile.EyeOfEnder tz
|
||||
public net.minecraft.world.entity.projectile.FireworkRocketEntity DATA_ATTACHED_TO_TARGET
|
||||
public net.minecraft.world.entity.projectile.FireworkRocketEntity DATA_ID_FIREWORKS_ITEM
|
||||
public net.minecraft.world.entity.projectile.FireworkRocketEntity DATA_SHOT_AT_ANGLE
|
||||
public net.minecraft.world.entity.projectile.FireworkRocketEntity attachedToEntity
|
||||
public net.minecraft.world.entity.projectile.FireworkRocketEntity getDefaultItem()Lnet/minecraft/world/item/ItemStack;
|
||||
public net.minecraft.world.entity.projectile.FireworkRocketEntity life
|
||||
public net.minecraft.world.entity.projectile.FireworkRocketEntity lifetime
|
||||
public net.minecraft.world.entity.projectile.FishingHook DATA_HOOKED_ENTITY
|
||||
public net.minecraft.world.entity.projectile.FishingHook calculateOpenWater(Lnet/minecraft/core/BlockPos;)Z
|
||||
public net.minecraft.world.entity.projectile.FishingHook currentState
|
||||
public net.minecraft.world.entity.projectile.FishingHook fishAngle
|
||||
public net.minecraft.world.entity.projectile.FishingHook hookedIn
|
||||
public net.minecraft.world.entity.projectile.FishingHook outOfWaterTime
|
||||
public net.minecraft.world.entity.projectile.FishingHook pullEntity(Lnet/minecraft/world/entity/Entity;)V
|
||||
public net.minecraft.world.entity.projectile.FishingHook setHookedEntity(Lnet/minecraft/world/entity/Entity;)V
|
||||
public net.minecraft.world.entity.projectile.FishingHook timeUntilHooked
|
||||
public net.minecraft.world.entity.projectile.FishingHook timeUntilLured
|
||||
public net.minecraft.world.entity.projectile.FishingHook$FishHookState
|
||||
public net.minecraft.world.entity.projectile.LargeFireball explosionPower
|
||||
public net.minecraft.world.entity.projectile.Projectile cachedOwner
|
||||
public net.minecraft.world.entity.projectile.Projectile hasBeenShot
|
||||
public net.minecraft.world.entity.projectile.Projectile leftOwner
|
||||
public net.minecraft.world.entity.projectile.Projectile ownerUUID
|
||||
public net.minecraft.world.entity.projectile.ShulkerBullet currentMoveDirection
|
||||
public net.minecraft.world.entity.projectile.ShulkerBullet flightSteps
|
||||
public net.minecraft.world.entity.projectile.ShulkerBullet targetDeltaX
|
||||
public net.minecraft.world.entity.projectile.ShulkerBullet targetDeltaY
|
||||
public net.minecraft.world.entity.projectile.ShulkerBullet targetDeltaZ
|
||||
public net.minecraft.world.entity.projectile.SpectralArrow duration
|
||||
public net.minecraft.world.entity.projectile.ThrownPotion isLingering()Z
|
||||
public net.minecraft.world.entity.projectile.ThrownTrident dealtDamage
|
||||
public net.minecraft.world.entity.projectile.windcharge.AbstractWindCharge explode(Lnet/minecraft/world/phys/Vec3;)V
|
||||
public net.minecraft.world.entity.projectile.windcharge.BreezeWindCharge explode(Lnet/minecraft/world/phys/Vec3;)V
|
||||
public net.minecraft.world.entity.projectile.windcharge.WindCharge explode(Lnet/minecraft/world/phys/Vec3;)V
|
||||
public net.minecraft.world.entity.raid.Raid heroesOfTheVillage
|
||||
public net.minecraft.world.entity.raid.Raid numGroups
|
||||
public net.minecraft.world.entity.raid.Raid raidEvent
|
||||
public net.minecraft.world.entity.raid.Raid raidOmenLevel
|
||||
public net.minecraft.world.entity.raid.Raid ticksActive
|
||||
public net.minecraft.world.entity.raid.Raid totalHealth
|
||||
public net.minecraft.world.entity.raid.Raider$HoldGroundAttackGoal
|
||||
public net.minecraft.world.entity.raid.Raids raidMap
|
||||
public net.minecraft.world.entity.vehicle.AbstractBoat getDropItem()Lnet/minecraft/world/item/Item;
|
||||
public net.minecraft.world.entity.vehicle.AbstractBoat getStatus()Lnet/minecraft/world/entity/vehicle/AbstractBoat$Status;
|
||||
public net.minecraft.world.entity.vehicle.AbstractBoat status
|
||||
public net.minecraft.world.entity.vehicle.AbstractMinecartContainer lootTable
|
||||
public net.minecraft.world.entity.vehicle.AbstractMinecartContainer lootTableSeed
|
||||
public net.minecraft.world.entity.vehicle.MinecartCommandBlock DATA_ID_COMMAND_NAME
|
||||
public net.minecraft.world.entity.vehicle.MinecartFurnace fuel
|
||||
public net.minecraft.world.entity.vehicle.MinecartTNT explode(D)V
|
||||
public net.minecraft.world.entity.vehicle.MinecartTNT explosionPowerBase
|
||||
public net.minecraft.world.entity.vehicle.MinecartTNT explosionSpeedFactor
|
||||
public net.minecraft.world.entity.vehicle.MinecartTNT fuse
|
||||
public net.minecraft.world.flag.FeatureFlag mask
|
||||
public net.minecraft.world.flag.FeatureFlag universe
|
||||
public net.minecraft.world.flag.FeatureFlagRegistry names
|
||||
public net.minecraft.world.food.FoodData exhaustionLevel
|
||||
public net.minecraft.world.food.FoodData foodLevel
|
||||
public net.minecraft.world.food.FoodData saturationLevel
|
||||
public net.minecraft.world.inventory.AbstractContainerMenu quickcraftSlots
|
||||
public net.minecraft.world.inventory.AbstractContainerMenu quickcraftStatus
|
||||
public net.minecraft.world.inventory.AbstractContainerMenu quickcraftType
|
||||
public net.minecraft.world.inventory.AbstractContainerMenu resetQuickCraft()V
|
||||
public net.minecraft.world.inventory.AbstractCraftingMenu craftSlots
|
||||
public net.minecraft.world.inventory.AbstractCraftingMenu resultSlots
|
||||
public net.minecraft.world.inventory.AnvilMenu cost
|
||||
public net.minecraft.world.inventory.AnvilMenu itemName
|
||||
public net.minecraft.world.inventory.AnvilMenu repairItemCountCost
|
||||
public net.minecraft.world.inventory.BrewingStandMenu brewingStandData
|
||||
public net.minecraft.world.inventory.CraftingMenu access
|
||||
public net.minecraft.world.inventory.DispenserMenu dispenser
|
||||
public net.minecraft.world.inventory.HorseInventoryMenu SLOT_BODY_ARMOR
|
||||
public net.minecraft.world.inventory.MerchantContainer selectionHint
|
||||
public net.minecraft.world.inventory.Slot slot
|
||||
public net.minecraft.world.item.AdventureModePredicate predicates
|
||||
public net.minecraft.world.item.BucketItem content
|
||||
public net.minecraft.world.item.CrossbowItem FIREWORK_POWER
|
||||
public net.minecraft.world.item.DebugStickItem handleInteraction(Lnet/minecraft/world/entity/player/Player;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/LevelAccessor;Lnet/minecraft/core/BlockPos;ZLnet/minecraft/world/item/ItemStack;)Z
|
||||
public net.minecraft.world.item.ItemCooldowns cooldowns
|
||||
public net.minecraft.world.item.ItemCooldowns tickCount
|
||||
public net.minecraft.world.item.ItemCooldowns$CooldownInstance
|
||||
public net.minecraft.world.item.ItemStackLinkedSet TYPE_AND_TAG
|
||||
public net.minecraft.world.item.JukeboxSongPlayer song
|
||||
public net.minecraft.world.item.MapItem createNewSavedData(Lnet/minecraft/world/level/Level;IIIZZLnet/minecraft/resources/ResourceKey;)Lnet/minecraft/world/level/saveddata/maps/MapId;
|
||||
public net.minecraft.world.item.StandingAndWallBlockItem wallBlock
|
||||
public net.minecraft.world.item.component.ItemContainerContents MAX_SIZE
|
||||
public net.minecraft.world.item.component.ItemContainerContents items
|
||||
public net.minecraft.world.item.context.UseOnContext <init>(Lnet/minecraft/world/level/Level;Lnet/minecraft/world/entity/player/Player;Lnet/minecraft/world/InteractionHand;Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/phys/BlockHitResult;)V
|
||||
public net.minecraft.world.item.crafting.RecipeManager recipes
|
||||
public net.minecraft.world.item.crafting.RecipeMap byKey
|
||||
public net.minecraft.world.item.crafting.RecipeMap byType
|
||||
public net.minecraft.world.item.enchantment.ItemEnchantments showInTooltip
|
||||
public net.minecraft.world.item.trading.MerchantOffer demand
|
||||
public net.minecraft.world.item.trading.MerchantOffer result
|
||||
public net.minecraft.world.item.trading.MerchantOffer specialPriceDiff
|
||||
public net.minecraft.world.item.trading.MerchantOffer uses
|
||||
public net.minecraft.world.level.BaseSpawner delay(Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;)V
|
||||
public net.minecraft.world.level.BaseSpawner isNearPlayer(Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;)Z
|
||||
public net.minecraft.world.level.BaseSpawner maxNearbyEntities
|
||||
public net.minecraft.world.level.BaseSpawner maxSpawnDelay
|
||||
public net.minecraft.world.level.BaseSpawner minSpawnDelay
|
||||
public net.minecraft.world.level.BaseSpawner nextSpawnData
|
||||
public net.minecraft.world.level.BaseSpawner requiredPlayerRange
|
||||
public net.minecraft.world.level.BaseSpawner setNextSpawnData(Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/SpawnData;)V
|
||||
public net.minecraft.world.level.BaseSpawner spawnCount
|
||||
public net.minecraft.world.level.BaseSpawner spawnDelay
|
||||
public net.minecraft.world.level.BaseSpawner spawnPotentials
|
||||
public net.minecraft.world.level.BaseSpawner spawnRange
|
||||
public net.minecraft.world.level.GameRules$Value onChanged(Lnet/minecraft/server/MinecraftServer;)V
|
||||
public net.minecraft.world.level.Level getEntities()Lnet/minecraft/world/level/entity/LevelEntityGetter;
|
||||
public net.minecraft.world.level.Level levelData
|
||||
public net.minecraft.world.level.Level rainLevel
|
||||
public net.minecraft.world.level.Level thread
|
||||
public net.minecraft.world.level.Level thunderLevel
|
||||
public net.minecraft.world.level.NaturalSpawner SPAWNING_CATEGORIES
|
||||
public net.minecraft.world.level.StructureManager level
|
||||
public net.minecraft.world.level.biome.Biome climateSettings
|
||||
public net.minecraft.world.level.biome.Biome getTemperature(Lnet/minecraft/core/BlockPos;I)F
|
||||
public net.minecraft.world.level.biome.Biome$ClimateSettings
|
||||
public net.minecraft.world.level.block.Block popExperience(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/core/BlockPos;I)V
|
||||
public net.minecraft.world.level.block.ChestBlock isBlockedChestByBlock(Lnet/minecraft/world/level/BlockGetter;Lnet/minecraft/core/BlockPos;)Z
|
||||
public net.minecraft.world.level.block.ChiseledBookShelfBlock getHitSlot(Lnet/minecraft/world/phys/BlockHitResult;Lnet/minecraft/world/level/block/state/BlockState;)Ljava/util/OptionalInt;
|
||||
public net.minecraft.world.level.block.ChiseledBookShelfBlock getSection(F)I
|
||||
public net.minecraft.world.level.block.ComposterBlock$EmptyContainer
|
||||
public net.minecraft.world.level.block.ComposterBlock$InputContainer
|
||||
public net.minecraft.world.level.block.ComposterBlock$OutputContainer
|
||||
public net.minecraft.world.level.block.DispenserBlock dispenseFrom(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/core/BlockPos;)V
|
||||
public net.minecraft.world.level.block.DropperBlock dispenseFrom(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/core/BlockPos;)V
|
||||
public net.minecraft.world.level.block.FireBlock igniteOdds
|
||||
public net.minecraft.world.level.block.RedStoneWireBlock canSurvive(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/LevelReader;Lnet/minecraft/core/BlockPos;)Z
|
||||
public net.minecraft.world.level.block.RedStoneWireBlock shouldSignal
|
||||
public net.minecraft.world.level.block.ShulkerBoxBlock color
|
||||
public net.minecraft.world.level.block.SoundType breakSound
|
||||
public net.minecraft.world.level.block.SoundType hitSound
|
||||
public net.minecraft.world.level.block.TurtleEggBlock decreaseEggs(Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;)V
|
||||
public net.minecraft.world.level.block.entity.AbstractFurnaceBlockEntity cookingTimer
|
||||
public net.minecraft.world.level.block.entity.AbstractFurnaceBlockEntity cookingTotalTime
|
||||
public net.minecraft.world.level.block.entity.AbstractFurnaceBlockEntity getTotalCookTime(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity;)I
|
||||
public net.minecraft.world.level.block.entity.AbstractFurnaceBlockEntity litTimeRemaining
|
||||
public net.minecraft.world.level.block.entity.AbstractFurnaceBlockEntity recipesUsed
|
||||
public net.minecraft.world.level.block.entity.BarrelBlockEntity openersCounter
|
||||
public net.minecraft.world.level.block.entity.BarrelBlockEntity playSound(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/sounds/SoundEvent;)V
|
||||
public net.minecraft.world.level.block.entity.BarrelBlockEntity updateBlockState(Lnet/minecraft/world/level/block/state/BlockState;Z)V
|
||||
public net.minecraft.world.level.block.entity.BaseContainerBlockEntity lockKey
|
||||
public net.minecraft.world.level.block.entity.BaseContainerBlockEntity name
|
||||
public net.minecraft.world.level.block.entity.BeaconBlockEntity levels
|
||||
public net.minecraft.world.level.block.entity.BeaconBlockEntity lockKey
|
||||
public net.minecraft.world.level.block.entity.BeaconBlockEntity name
|
||||
public net.minecraft.world.level.block.entity.BeaconBlockEntity primaryPower
|
||||
public net.minecraft.world.level.block.entity.BeaconBlockEntity secondaryPower
|
||||
public net.minecraft.world.level.block.entity.BedBlockEntity color
|
||||
public net.minecraft.world.level.block.entity.BeehiveBlockEntity savedFlowerPos
|
||||
public net.minecraft.world.level.block.entity.BellBlockEntity resonating
|
||||
public net.minecraft.world.level.block.entity.BellBlockEntity resonationTicks
|
||||
public net.minecraft.world.level.block.entity.BlockEntity saveId(Lnet/minecraft/nbt/CompoundTag;)V
|
||||
public net.minecraft.world.level.block.entity.BlockEntityType validBlocks
|
||||
public net.minecraft.world.level.block.entity.BrewingStandBlockEntity brewTime
|
||||
public net.minecraft.world.level.block.entity.BrewingStandBlockEntity fuel
|
||||
public net.minecraft.world.level.block.entity.BrushableBlockEntity item
|
||||
public net.minecraft.world.level.block.entity.BrushableBlockEntity lootTable
|
||||
public net.minecraft.world.level.block.entity.BrushableBlockEntity lootTableSeed
|
||||
public net.minecraft.world.level.block.entity.CampfireBlockEntity cookingProgress
|
||||
public net.minecraft.world.level.block.entity.CampfireBlockEntity cookingTime
|
||||
public net.minecraft.world.level.block.entity.ChestBlockEntity openersCounter
|
||||
public net.minecraft.world.level.block.entity.ChestBlockEntity playSound(Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/sounds/SoundEvent;)V
|
||||
public net.minecraft.world.level.block.entity.ChiseledBookShelfBlockEntity lastInteractedSlot
|
||||
public net.minecraft.world.level.block.entity.ConduitBlockEntity destroyTarget
|
||||
public net.minecraft.world.level.block.entity.ConduitBlockEntity destroyTargetUUID
|
||||
public net.minecraft.world.level.block.entity.ConduitBlockEntity effectBlocks
|
||||
public net.minecraft.world.level.block.entity.ConduitBlockEntity getDestroyRangeAABB(Lnet/minecraft/core/BlockPos;)Lnet/minecraft/world/phys/AABB;
|
||||
public net.minecraft.world.level.block.entity.CrafterBlockEntity craftingTicksRemaining
|
||||
public net.minecraft.world.level.block.entity.DecoratedPotBlockEntity decorations
|
||||
public net.minecraft.world.level.block.entity.EnderChestBlockEntity openersCounter
|
||||
public net.minecraft.world.level.block.entity.HopperBlockEntity cooldownTime
|
||||
public net.minecraft.world.level.block.entity.HopperBlockEntity setCooldown(I)V
|
||||
public net.minecraft.world.level.block.entity.LecternBlockEntity bookAccess
|
||||
public net.minecraft.world.level.block.entity.LecternBlockEntity setPage(I)V
|
||||
public net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity lootTable
|
||||
public net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity lootTableSeed
|
||||
public net.minecraft.world.level.block.entity.SculkCatalystBlockEntity$CatalystListener bloom(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/util/RandomSource;)V
|
||||
public net.minecraft.world.level.block.entity.SculkSensorBlockEntity lastVibrationFrequency
|
||||
public net.minecraft.world.level.block.entity.SculkShriekerBlockEntity warningLevel
|
||||
public net.minecraft.world.level.block.entity.ShulkerBoxBlockEntity openCount
|
||||
public net.minecraft.world.level.block.entity.SignBlockEntity playerWhoMayEdit
|
||||
public net.minecraft.world.level.block.entity.SkullBlockEntity noteBlockSound
|
||||
public net.minecraft.world.level.block.entity.SkullBlockEntity owner
|
||||
public net.minecraft.world.level.block.entity.StructureBlockEntity author
|
||||
public net.minecraft.world.level.block.entity.StructureBlockEntity ignoreEntities
|
||||
public net.minecraft.world.level.block.entity.StructureBlockEntity integrity
|
||||
public net.minecraft.world.level.block.entity.StructureBlockEntity metaData
|
||||
public net.minecraft.world.level.block.entity.StructureBlockEntity mirror
|
||||
public net.minecraft.world.level.block.entity.StructureBlockEntity mode
|
||||
public net.minecraft.world.level.block.entity.StructureBlockEntity rotation
|
||||
public net.minecraft.world.level.block.entity.StructureBlockEntity seed
|
||||
public net.minecraft.world.level.block.entity.StructureBlockEntity showAir
|
||||
public net.minecraft.world.level.block.entity.StructureBlockEntity showBoundingBox
|
||||
public net.minecraft.world.level.block.entity.StructureBlockEntity structurePos
|
||||
public net.minecraft.world.level.block.entity.StructureBlockEntity structureSize
|
||||
public net.minecraft.world.level.block.entity.TheEndGatewayBlockEntity age
|
||||
public net.minecraft.world.level.block.entity.TheEndGatewayBlockEntity exactTeleport
|
||||
public net.minecraft.world.level.block.entity.TheEndGatewayBlockEntity exitPortal
|
||||
public net.minecraft.world.level.block.entity.TrialSpawnerBlockEntity trialSpawner
|
||||
public net.minecraft.world.level.block.entity.trialspawner.TrialSpawner isOminous
|
||||
public net.minecraft.world.level.block.entity.trialspawner.TrialSpawner stateAccessor
|
||||
public net.minecraft.world.level.block.entity.trialspawner.TrialSpawnerData currentMobs
|
||||
public net.minecraft.world.level.block.entity.trialspawner.TrialSpawnerData detectedPlayers
|
||||
public net.minecraft.world.level.block.entity.trialspawner.TrialSpawnerData nextSpawnData
|
||||
public net.minecraft.world.level.block.state.BlockBehaviour getMenuProvider(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;)Lnet/minecraft/world/MenuProvider;
|
||||
public net.minecraft.world.level.block.state.BlockBehaviour hasCollision
|
||||
public net.minecraft.world.level.block.state.BlockBehaviour$BlockStateBase destroySpeed
|
||||
public net.minecraft.world.level.block.state.StateHolder PROPERTY_ENTRY_TO_STRING_FUNCTION
|
||||
public net.minecraft.world.level.block.state.properties.IntegerProperty max
|
||||
public net.minecraft.world.level.block.state.properties.IntegerProperty min
|
||||
public net.minecraft.world.level.chunk.ChunkAccess blockEntities
|
||||
public net.minecraft.world.level.chunk.ChunkAccess heightmaps
|
||||
public net.minecraft.world.level.chunk.ChunkGenerator generationSettingsGetter
|
||||
public net.minecraft.world.level.chunk.LevelChunk level
|
||||
public net.minecraft.world.level.chunk.LevelChunk loaded
|
||||
public net.minecraft.world.level.chunk.LevelChunkSection states
|
||||
public net.minecraft.world.level.chunk.PalettedContainer registry
|
||||
public net.minecraft.world.level.chunk.storage.EntityStorage entityDeserializerQueue
|
||||
public net.minecraft.world.level.chunk.storage.EntityStorage level
|
||||
public net.minecraft.world.level.chunk.storage.RegionFileStorage regionCache
|
||||
public net.minecraft.world.level.chunk.storage.SerializableChunkData BLOCK_STATE_CODEC
|
||||
public net.minecraft.world.level.dimension.end.EndDragonFight GATEWAY_COUNT
|
||||
public net.minecraft.world.level.dimension.end.EndDragonFight dragonEvent
|
||||
public net.minecraft.world.level.dimension.end.EndDragonFight dragonUUID
|
||||
public net.minecraft.world.level.dimension.end.EndDragonFight findExitPortal()Lnet/minecraft/world/level/block/state/pattern/BlockPattern$BlockPatternMatch;
|
||||
public net.minecraft.world.level.dimension.end.EndDragonFight gateways
|
||||
public net.minecraft.world.level.dimension.end.EndDragonFight level
|
||||
public net.minecraft.world.level.dimension.end.EndDragonFight portalLocation
|
||||
public net.minecraft.world.level.dimension.end.EndDragonFight previouslyKilled
|
||||
public net.minecraft.world.level.dimension.end.EndDragonFight respawnCrystals
|
||||
public net.minecraft.world.level.dimension.end.EndDragonFight respawnDragon(Ljava/util/List;)V
|
||||
public net.minecraft.world.level.dimension.end.EndDragonFight respawnStage
|
||||
public net.minecraft.world.level.dimension.end.EndDragonFight setRespawnStage(Lnet/minecraft/world/level/dimension/end/DragonRespawnAnimation;)V
|
||||
public net.minecraft.world.level.dimension.end.EndDragonFight spawnExitPortal(Z)V
|
||||
public net.minecraft.world.level.dimension.end.EndDragonFight spawnNewGateway(Lnet/minecraft/core/BlockPos;)V
|
||||
public net.minecraft.world.level.entity.PersistentEntitySectionManager ensureChunkQueuedForLoad(J)V
|
||||
public net.minecraft.world.level.entity.PersistentEntitySectionManager permanentStorage
|
||||
public net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator settings
|
||||
public net.minecraft.world.level.levelgen.SurfaceRules$Condition
|
||||
public net.minecraft.world.level.levelgen.SurfaceRules$Context
|
||||
public net.minecraft.world.level.levelgen.SurfaceRules$Context blockX
|
||||
public net.minecraft.world.level.levelgen.SurfaceRules$Context blockY
|
||||
public net.minecraft.world.level.levelgen.SurfaceRules$Context blockZ
|
||||
public net.minecraft.world.level.levelgen.SurfaceRules$Context context
|
||||
public net.minecraft.world.level.levelgen.SurfaceRules$Context randomState
|
||||
public net.minecraft.world.level.levelgen.SurfaceRules$LazyCondition
|
||||
public net.minecraft.world.level.levelgen.SurfaceRules$LazyYCondition
|
||||
public net.minecraft.world.level.levelgen.SurfaceRules$SurfaceRule
|
||||
public net.minecraft.world.level.levelgen.SurfaceRules$VerticalGradientConditionSource
|
||||
public net.minecraft.world.level.levelgen.structure.placement.StructurePlacement exclusionZone
|
||||
public net.minecraft.world.level.levelgen.structure.placement.StructurePlacement frequency
|
||||
public net.minecraft.world.level.levelgen.structure.placement.StructurePlacement frequencyReductionMethod
|
||||
public net.minecraft.world.level.levelgen.structure.placement.StructurePlacement locateOffset
|
||||
public net.minecraft.world.level.levelgen.structure.placement.StructurePlacement salt
|
||||
public net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate entityInfoList
|
||||
public net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate palettes
|
||||
public net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager loadFromGenerated(Lnet/minecraft/resources/ResourceLocation;)Ljava/util/Optional;
|
||||
public net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager loadFromResource(Lnet/minecraft/resources/ResourceLocation;)Ljava/util/Optional;
|
||||
public net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager readStructure(Ljava/io/InputStream;)Lnet/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate;
|
||||
public net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager structureRepository
|
||||
public net.minecraft.world.level.material.MapColor MATERIAL_COLORS
|
||||
public net.minecraft.world.level.pathfinder.Path nodes
|
||||
public net.minecraft.world.level.pathfinder.PathFinder nodeEvaluator
|
||||
public net.minecraft.world.level.saveddata.maps.MapItemSavedData carriedBy
|
||||
public net.minecraft.world.level.saveddata.maps.MapItemSavedData carriedByPlayers
|
||||
public net.minecraft.world.level.saveddata.maps.MapItemSavedData decorations
|
||||
public net.minecraft.world.level.saveddata.maps.MapItemSavedData setColorsDirty(II)V
|
||||
public net.minecraft.world.level.saveddata.maps.MapItemSavedData setDecorationsDirty()V
|
||||
public net.minecraft.world.level.storage.DimensionDataStorage cache
|
||||
public net.minecraft.world.level.storage.LevelStorageSource baseDir
|
||||
public net.minecraft.world.level.storage.LevelStorageSource$LevelStorageAccess levelDirectory
|
||||
public net.minecraft.world.level.storage.PrimaryLevelData settings
|
||||
public net.minecraft.world.scores.Objective displayName
|
||||
public net.minecraft.world.scores.criteria.ObjectiveCriteria CRITERIA_CACHE
|
||||
public-f net.minecraft.server.MinecraftServer potionBrewing
|
||||
public-f net.minecraft.server.MinecraftServer storageSource
|
||||
public-f net.minecraft.server.ReloadableServerResources commands
|
||||
public-f net.minecraft.server.dedicated.DedicatedServer serverLinks
|
||||
public-f net.minecraft.server.dedicated.DedicatedServer settings
|
||||
public-f net.minecraft.server.dedicated.DedicatedServerProperties pauseWhenEmptySeconds
|
||||
public-f net.minecraft.server.level.TicketType timeout
|
||||
public-f net.minecraft.server.players.PlayerList maxPlayers
|
||||
public-f net.minecraft.world.entity.LivingEntity combatTracker
|
||||
public-f net.minecraft.world.entity.LivingEntity invulnerableDuration
|
||||
public-f net.minecraft.world.entity.Mob goalSelector
|
||||
public-f net.minecraft.world.entity.Mob targetSelector
|
||||
public-f net.minecraft.world.entity.ai.attributes.RangedAttribute maxValue
|
||||
public-f net.minecraft.world.entity.player.Player gameProfile
|
||||
public-f net.minecraft.world.inventory.AbstractContainerMenu dataSlots
|
||||
public-f net.minecraft.world.inventory.AbstractContainerMenu lastSlots
|
||||
public-f net.minecraft.world.inventory.AbstractContainerMenu remoteDataSlots
|
||||
public-f net.minecraft.world.inventory.AbstractContainerMenu remoteSlots
|
||||
public-f net.minecraft.world.inventory.AbstractContainerMenu slots
|
||||
public-f net.minecraft.world.item.enchantment.ItemEnchantments$Mutable showInTooltip
|
||||
public-f net.minecraft.world.item.trading.MerchantOffer baseCostA
|
||||
public-f net.minecraft.world.item.trading.MerchantOffer costB
|
||||
public-f net.minecraft.world.item.trading.MerchantOffer maxUses
|
||||
public-f net.minecraft.world.item.trading.MerchantOffer priceMultiplier
|
||||
public-f net.minecraft.world.item.trading.MerchantOffer rewardExp
|
||||
public-f net.minecraft.world.item.trading.MerchantOffer xp
|
||||
public-f net.minecraft.world.level.LevelSettings hardcore
|
||||
public-f net.minecraft.world.level.LevelSettings levelName
|
||||
public-f net.minecraft.world.level.block.entity.BannerBlockEntity baseColor
|
||||
public-f net.minecraft.world.level.block.entity.trialspawner.TrialSpawner normalConfig
|
||||
public-f net.minecraft.world.level.block.entity.trialspawner.TrialSpawner ominousConfig
|
||||
public-f net.minecraft.world.level.block.entity.trialspawner.TrialSpawner requiredPlayerRange
|
||||
public-f net.minecraft.world.level.block.entity.trialspawner.TrialSpawner targetCooldownLength
|
||||
public-f net.minecraft.world.level.saveddata.maps.MapItemSavedData centerX
|
||||
public-f net.minecraft.world.level.saveddata.maps.MapItemSavedData centerZ
|
||||
public-f net.minecraft.world.level.saveddata.maps.MapItemSavedData dimension
|
||||
public-f net.minecraft.world.level.saveddata.maps.MapItemSavedData locked
|
||||
public-f net.minecraft.world.level.saveddata.maps.MapItemSavedData scale
|
||||
public-f net.minecraft.world.level.saveddata.maps.MapItemSavedData trackingPosition
|
||||
public-f net.minecraft.world.level.saveddata.maps.MapItemSavedData unlimitedTracking
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import io.papermc.paperweight.util.*
|
||||
import io.papermc.paperweight.util.constants.*
|
||||
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
|
||||
import org.gradle.api.tasks.testing.logging.TestLogEvent
|
||||
import java.io.IOException
|
||||
|
@ -8,9 +9,10 @@ import java.nio.file.Files
|
|||
import java.nio.file.SimpleFileVisitor
|
||||
import kotlin.io.path.*
|
||||
import java.nio.file.Path
|
||||
import kotlin.random.Random
|
||||
|
||||
plugins {
|
||||
id("io.papermc.paperweight.core") version "2.0.0-SNAPSHOT" apply false
|
||||
id("io.papermc.paperweight.core") version "2.0.0-beta.8" apply false
|
||||
}
|
||||
|
||||
subprojects {
|
||||
|
@ -23,10 +25,6 @@ subprojects {
|
|||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
"testRuntimeOnly"("org.junit.platform:junit-platform-launcher")
|
||||
}
|
||||
|
||||
tasks.withType<AbstractArchiveTask>().configureEach {
|
||||
isPreserveFileTimestamps = false
|
||||
isReproducibleFileOrder = true
|
||||
|
@ -89,7 +87,6 @@ tasks.register("gibWork") {
|
|||
val patchesFolder = layout.projectDirectory.dir("paper-server/patches/").convertToPath()
|
||||
val storage = layout.cache.resolve("last-updating-folder").also { it.parent.createDirectories() }
|
||||
|
||||
@OptIn(ExperimentalPathApi::class)
|
||||
doLast {
|
||||
val html = URI(issue).toURL().readText()
|
||||
|
||||
|
@ -98,18 +95,26 @@ tasks.register("gibWork") {
|
|||
val end = html.indexOf("```", start + beginMarker.length)
|
||||
val taskList = html.substring(start + beginMarker.length, end)
|
||||
|
||||
val next = taskList.split("\\n").first { it.startsWith("- [ ]") }.replace("- [ ] ", "")
|
||||
// Extract all incomplete tasks and select a random one
|
||||
val incompleteTasks = taskList.split("\\n").filter { it.startsWith("- [ ]") }.map { it.replace("- [ ] ", "") }
|
||||
if (incompleteTasks.isEmpty()) {
|
||||
error("No incomplete tasks found in the task list.")
|
||||
}
|
||||
|
||||
val next = incompleteTasks[Random.nextInt(incompleteTasks.size)]
|
||||
|
||||
println("checking out $next...")
|
||||
val dir = patchesFolder.resolve("unapplied").resolve(next)
|
||||
if (!dir.exists()) {
|
||||
error("Unapplied patch folder $next does not exist, did someone else already check it out and forgot to mark it?")
|
||||
}
|
||||
dir.copyToRecursively(
|
||||
patchesFolder.resolve("sources").resolve(next)
|
||||
.also { it.createDirectories() }, overwrite = true, followLinks = false
|
||||
)
|
||||
dir.deleteRecursively()
|
||||
dir.listDirectoryEntries("*.patch").forEach { patch ->
|
||||
patch.copyTo(patchesFolder.resolve("sources").resolve(next).resolve(patch.fileName).also { it.createDirectories() }, overwrite = true)
|
||||
patch.deleteIfExists()
|
||||
}
|
||||
if (dir.listDirectoryEntries().isEmpty()) {
|
||||
dir.deleteIfExists()
|
||||
}
|
||||
|
||||
storage.writeText(next)
|
||||
println("please tick the box in the issue: $issue")
|
||||
|
@ -133,23 +138,24 @@ tasks.register("showWork") {
|
|||
}
|
||||
|
||||
tasks.register("checkWork") {
|
||||
notCompatibleWithConfigurationCache("This task is interactive")
|
||||
fun expandUserHome(path: String): Path {
|
||||
return Path.of(path.replaceFirst("^~".toRegex(), System.getProperty("user.home")))
|
||||
}
|
||||
|
||||
val input = layout.cache.resolve("last-updating-folder").readText()
|
||||
val patchFolder = layout.projectDirectory.file("paper-server/patches/sources").convertToPath().resolve(input)
|
||||
val sourceFolder = layout.projectDirectory.file("paper-server/src/vanilla/java/").convertToPath().resolve(input)
|
||||
val targetFolder = expandUserHome(
|
||||
providers.gradleProperty("cleanPaperRepo").orNull
|
||||
?: error("cleanPaperRepo is required, define it in gradle.properties")
|
||||
).resolve(input)
|
||||
val input = providers.fileContents(layout.projectDirectory.file("$CACHE_PATH/last-updating-folder")).asText.map { it.trim() }
|
||||
val patchFolder = layout.projectDirectory.dir("paper-server/patches/sources").dir(input)
|
||||
val sourceFolder = layout.projectDirectory.dir("paper-server/src/minecraft/java").dir(input)
|
||||
val targetFolder = providers.gradleProperty("cleanPaperRepo").map {
|
||||
expandUserHome(it).resolve(input.get())
|
||||
}
|
||||
|
||||
fun copy(back: Boolean = false) {
|
||||
patchFolder.listDirectoryEntries().forEach {
|
||||
val relative = patchFolder.relativize(it).toString().replace(".patch", "")
|
||||
val source = sourceFolder.resolve(relative)
|
||||
val target = targetFolder.resolve(relative)
|
||||
patchFolder.path.listDirectoryEntries().forEach {
|
||||
val relative = patchFolder.path.relativize(it).toString().replace(".patch", "")
|
||||
val source = sourceFolder.path.resolve(relative)
|
||||
val target = targetFolder.get().resolve(relative)
|
||||
if (target.isDirectory()) { return@forEach }
|
||||
if (back) {
|
||||
target.copyTo(source, overwrite = true)
|
||||
} else {
|
||||
|
@ -159,8 +165,11 @@ tasks.register("checkWork") {
|
|||
}
|
||||
|
||||
doLast {
|
||||
if (!targetFolder.isPresent) {
|
||||
error("cleanPaperRepo is required, define it in gradle.properties")
|
||||
}
|
||||
copy()
|
||||
val files = patchFolder.listDirectoryEntries().map { it.fileName.toString().replace(".patch", "") }
|
||||
val files = patchFolder.path.listDirectoryEntries().map { it.fileName.toString().replace(".patch", "") }
|
||||
println("Copied $files from $sourceFolder to $targetFolder")
|
||||
println("Make the files compile, then press enter to copy them back!")
|
||||
System.`in`.read()
|
||||
|
|
|
@ -1,99 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Thu, 3 Mar 2016 02:07:55 -0600
|
||||
Subject: [PATCH] Optimize isInWorldBounds and getBlockState for inlining
|
||||
|
||||
Hot methods, so reduce # of instructions for the method.
|
||||
|
||||
Move is valid location test to the BlockPosition class so that it can access local variables.
|
||||
|
||||
Replace all calls to the new place to the unnecessary forward.
|
||||
|
||||
Optimize getType and getBlockData to manually inline and optimize the calls
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/core/Vec3i.java b/src/main/java/net/minecraft/core/Vec3i.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/core/Vec3i.java
|
||||
+++ b/src/main/java/net/minecraft/core/Vec3i.java
|
||||
@@ -0,0 +0,0 @@ public class Vec3i implements Comparable<Vec3i> {
|
||||
);
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ public final boolean isInsideBuildHeightAndWorldBoundsHorizontal(net.minecraft.world.level.LevelHeightAccessor levelHeightAccessor) {
|
||||
+ return getX() >= -30000000 && getZ() >= -30000000 && getX() < 30000000 && getZ() < 30000000 && !levelHeightAccessor.isOutsideBuildHeight(getY());
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
public Vec3i(int x, int y, int z) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -0,0 +0,0 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
// Paper end
|
||||
|
||||
public boolean isInWorldBounds(BlockPos pos) {
|
||||
- return !this.isOutsideBuildHeight(pos) && Level.isInWorldBoundsHorizontal(pos);
|
||||
+ return pos.isInsideBuildHeightAndWorldBoundsHorizontal(this); // Paper - use better/optimized check
|
||||
}
|
||||
|
||||
public static boolean isInSpawnableBounds(BlockPos pos) {
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java b/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java
|
||||
@@ -0,0 +0,0 @@ public abstract class ChunkAccess implements BiomeManager.NoiseBiomeSource, Ligh
|
||||
return GameEventListenerRegistry.NOOP;
|
||||
}
|
||||
|
||||
+ public abstract BlockState getBlockState(final int x, final int y, final int z); // Paper
|
||||
@Nullable
|
||||
public abstract BlockState setBlockState(BlockPos pos, BlockState state, boolean moved);
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/ImposterProtoChunk.java b/src/main/java/net/minecraft/world/level/chunk/ImposterProtoChunk.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/ImposterProtoChunk.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/ImposterProtoChunk.java
|
||||
@@ -0,0 +0,0 @@ public class ImposterProtoChunk extends ProtoChunk {
|
||||
public BlockState getBlockState(BlockPos pos) {
|
||||
return this.wrapped.getBlockState(pos);
|
||||
}
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public final BlockState getBlockState(final int x, final int y, final int z) {
|
||||
+ return this.wrapped.getBlockStateFinal(x, y, z);
|
||||
+ }
|
||||
+ // Paper end
|
||||
|
||||
@Override
|
||||
public FluidState getFluidState(BlockPos pos) {
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/ProtoChunk.java b/src/main/java/net/minecraft/world/level/chunk/ProtoChunk.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/ProtoChunk.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/ProtoChunk.java
|
||||
@@ -0,0 +0,0 @@ public class ProtoChunk extends ChunkAccess {
|
||||
|
||||
@Override
|
||||
public BlockState getBlockState(BlockPos pos) {
|
||||
- int i = pos.getY();
|
||||
- if (this.isOutsideBuildHeight(i)) {
|
||||
+ // Paper start
|
||||
+ return getBlockState(pos.getX(), pos.getY(), pos.getZ());
|
||||
+ }
|
||||
+ public BlockState getBlockState(final int x, final int y, final int z) {
|
||||
+ if (this.isOutsideBuildHeight(y)) {
|
||||
return Blocks.VOID_AIR.defaultBlockState();
|
||||
} else {
|
||||
- LevelChunkSection levelChunkSection = this.getSection(this.getSectionIndex(i));
|
||||
- return levelChunkSection.hasOnlyAir() ? Blocks.AIR.defaultBlockState() : levelChunkSection.getBlockState(pos.getX() & 15, i & 15, pos.getZ() & 15);
|
||||
+ LevelChunkSection levelChunkSection = this.getSections()[this.getSectionIndex(y)];
|
||||
+ return levelChunkSection.hasOnlyAir() ? Blocks.AIR.defaultBlockState() : levelChunkSection.getBlockState(x & 15, y & 15, z & 15);
|
||||
}
|
||||
}
|
||||
+ // Paper end
|
||||
|
||||
@Override
|
||||
public FluidState getFluidState(BlockPos pos) {
|
|
@ -1,124 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Fri, 29 Apr 2016 20:02:00 -0400
|
||||
Subject: [PATCH] Improve Maps (in item frames) performance and bug fixes
|
||||
|
||||
Maps used a modified version of rendering to support plugin controlled
|
||||
imaging on maps. The Craft Map Renderer is much slower than Vanilla,
|
||||
causing maps in item frames to cause a noticeable hit on server performance.
|
||||
|
||||
This updates the map system to not use the Craft system if we detect that no
|
||||
custom renderers are in use, defaulting to the much simpler Vanilla system.
|
||||
|
||||
Additionally, numerous issues to player position tracking on maps has been fixed.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
{
|
||||
if ( iter.next().player == entity )
|
||||
{
|
||||
+ map.decorations.remove(entity.getName().getString()); // Paper
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -0,0 +0,0 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player {
|
||||
this.awardStat(Stats.DROP);
|
||||
}
|
||||
|
||||
+ // Paper start - remove player from map on drop
|
||||
+ if (itemstack.getItem() == net.minecraft.world.item.Items.FILLED_MAP) {
|
||||
+ net.minecraft.world.level.saveddata.maps.MapItemSavedData worldmap = net.minecraft.world.item.MapItem.getSavedData(itemstack, this.level());
|
||||
+ if (worldmap != null) {
|
||||
+ worldmap.tickCarriedBy(this, itemstack);
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
return entityitem;
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java b/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java
|
||||
@@ -0,0 +0,0 @@ public class MapItemSavedData extends SavedData {
|
||||
public final Map<String, MapDecoration> decorations = Maps.newLinkedHashMap();
|
||||
private final Map<String, MapFrame> frameMarkers = Maps.newHashMap();
|
||||
private int trackedDecorationCount;
|
||||
+ private org.bukkit.craftbukkit.map.RenderData vanillaRender = new org.bukkit.craftbukkit.map.RenderData(); // Paper
|
||||
|
||||
// CraftBukkit start
|
||||
public final CraftMapView mapView;
|
||||
@@ -0,0 +0,0 @@ public class MapItemSavedData extends SavedData {
|
||||
// CraftBukkit start
|
||||
this.mapView = new CraftMapView(this);
|
||||
this.server = (CraftServer) org.bukkit.Bukkit.getServer();
|
||||
+ this.vanillaRender.buffer = colors; // Paper
|
||||
// CraftBukkit end
|
||||
}
|
||||
|
||||
@@ -0,0 +0,0 @@ public class MapItemSavedData extends SavedData {
|
||||
if (abyte.length == 16384) {
|
||||
worldmap.colors = abyte;
|
||||
}
|
||||
+ worldmap.vanillaRender.buffer = abyte; // Paper
|
||||
|
||||
RegistryOps<Tag> registryops = registries.createSerializationContext(NbtOps.INSTANCE);
|
||||
List<MapBanner> list = (List) MapBanner.LIST_CODEC.parse(registryops, nbt.get("banners")).resultOrPartial((s) -> {
|
||||
@@ -0,0 +0,0 @@ public class MapItemSavedData extends SavedData {
|
||||
--this.trackedDecorationCount;
|
||||
}
|
||||
|
||||
- this.setDecorationsDirty();
|
||||
+ if (mapicon != null) this.setDecorationsDirty(); // Paper - only mark dirty if a change occurs
|
||||
}
|
||||
|
||||
public static void addTargetDecoration(ItemStack stack, BlockPos pos, String id, Holder<MapDecorationType> decorationType) {
|
||||
@@ -0,0 +0,0 @@ public class MapItemSavedData extends SavedData {
|
||||
|
||||
public class HoldingPlayer {
|
||||
|
||||
+ // Paper start
|
||||
+ private void addSeenPlayers(java.util.Collection<MapDecoration> icons) {
|
||||
+ org.bukkit.entity.Player player = (org.bukkit.entity.Player) this.player.getBukkitEntity();
|
||||
+ MapItemSavedData.this.decorations.forEach((name, mapIcon) -> {
|
||||
+ // If this cursor is for a player check visibility with vanish system
|
||||
+ org.bukkit.entity.Player other = org.bukkit.Bukkit.getPlayerExact(name); // Spigot
|
||||
+ if (other == null || player.canSee(other)) {
|
||||
+ icons.add(mapIcon);
|
||||
+ }
|
||||
+ });
|
||||
+ }
|
||||
+ private boolean shouldUseVanillaMap() {
|
||||
+ return mapView.getRenderers().size() == 1 && mapView.getRenderers().get(0).getClass() == org.bukkit.craftbukkit.map.CraftMapRenderer.class;
|
||||
+ }
|
||||
+ // Paper end
|
||||
public final Player player;
|
||||
private boolean dirtyData = true;
|
||||
private int minDirtyX;
|
||||
@@ -0,0 +0,0 @@ public class MapItemSavedData extends SavedData {
|
||||
@Nullable
|
||||
Packet<?> nextUpdatePacket(MapId mapId) {
|
||||
MapItemSavedData.MapPatch worldmap_c;
|
||||
- org.bukkit.craftbukkit.map.RenderData render = MapItemSavedData.this.mapView.render((org.bukkit.craftbukkit.entity.CraftPlayer) this.player.getBukkitEntity()); // CraftBukkit
|
||||
+ if (!this.dirtyData && this.tick % 5 != 0) { this.tick++; return null; } // Paper - this won't end up sending, so don't render it!
|
||||
+ boolean vanillaMaps = shouldUseVanillaMap(); // Paper
|
||||
+ org.bukkit.craftbukkit.map.RenderData render = !vanillaMaps ? MapItemSavedData.this.mapView.render((org.bukkit.craftbukkit.entity.CraftPlayer) this.player.getBukkitEntity()) : MapItemSavedData.this.vanillaRender; // CraftBukkit // Paper
|
||||
|
||||
if (this.dirtyData) {
|
||||
this.dirtyData = false;
|
||||
@@ -0,0 +0,0 @@ public class MapItemSavedData extends SavedData {
|
||||
// CraftBukkit start
|
||||
java.util.Collection<MapDecoration> icons = new java.util.ArrayList<MapDecoration>();
|
||||
|
||||
+ if (vanillaMaps) addSeenPlayers(icons); // Paper
|
||||
+
|
||||
for (org.bukkit.map.MapCursor cursor : render.cursors) {
|
||||
if (cursor.isVisible()) {
|
||||
icons.add(new MapDecoration(CraftMapCursor.CraftType.bukkitToMinecraftHolder(cursor.getType()), cursor.getX(), cursor.getY(), cursor.getDirection(), Optional.ofNullable(PaperAdventure.asVanilla(cursor.caption()))));
|
|
@ -1,292 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Byteflux <byte@byteflux.net>
|
||||
Date: Wed, 2 Mar 2016 02:17:54 -0600
|
||||
Subject: [PATCH] Flat bedrock generator settings
|
||||
|
||||
== AT ==
|
||||
public net.minecraft.world.level.levelgen.SurfaceRules$Condition
|
||||
public net.minecraft.world.level.levelgen.SurfaceRules$Context
|
||||
public net.minecraft.world.level.levelgen.SurfaceRules$Context blockX
|
||||
public net.minecraft.world.level.levelgen.SurfaceRules$Context blockY
|
||||
public net.minecraft.world.level.levelgen.SurfaceRules$Context blockZ
|
||||
public net.minecraft.world.level.levelgen.SurfaceRules$Context context
|
||||
public net.minecraft.world.level.levelgen.SurfaceRules$Context randomState
|
||||
public net.minecraft.world.level.levelgen.SurfaceRules$LazyYCondition
|
||||
public net.minecraft.world.level.levelgen.SurfaceRules$LazyCondition
|
||||
public net.minecraft.world.level.levelgen.SurfaceRules$VerticalGradientConditionSource
|
||||
public net.minecraft.world.level.levelgen.SurfaceRules$SurfaceRule
|
||||
|
||||
Co-authored-by: Noah van der Aa <ndvdaa@gmail.com>
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/world/worldgen/OptionallyFlatBedrockConditionSource.java b/src/main/java/io/papermc/paper/world/worldgen/OptionallyFlatBedrockConditionSource.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/world/worldgen/OptionallyFlatBedrockConditionSource.java
|
||||
@@ -0,0 +0,0 @@
|
||||
+package io.papermc.paper.world.worldgen;
|
||||
+
|
||||
+import com.mojang.serialization.Codec;
|
||||
+import com.mojang.serialization.MapCodec;
|
||||
+import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
+import net.minecraft.core.Registry;
|
||||
+import net.minecraft.core.registries.BuiltInRegistries;
|
||||
+import net.minecraft.core.registries.Registries;
|
||||
+import net.minecraft.resources.ResourceKey;
|
||||
+import net.minecraft.resources.ResourceLocation;
|
||||
+import net.minecraft.util.KeyDispatchDataCodec;
|
||||
+import net.minecraft.util.Mth;
|
||||
+import net.minecraft.util.RandomSource;
|
||||
+import net.minecraft.world.level.levelgen.PositionalRandomFactory;
|
||||
+import net.minecraft.world.level.levelgen.SurfaceRules;
|
||||
+import net.minecraft.world.level.levelgen.VerticalAnchor;
|
||||
+import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
+import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
+
|
||||
+// Modelled off of SurfaceRules$VerticalGradientConditionSource
|
||||
+@DefaultQualifier(NonNull.class)
|
||||
+public record OptionallyFlatBedrockConditionSource(ResourceLocation randomName, VerticalAnchor trueAtAndBelow, VerticalAnchor falseAtAndAbove, boolean isRoof) implements SurfaceRules.ConditionSource {
|
||||
+
|
||||
+ private static final ResourceKey<MapCodec<? extends SurfaceRules.ConditionSource>> CODEC_RESOURCE_KEY = ResourceKey.create(
|
||||
+ Registries.MATERIAL_CONDITION,
|
||||
+ ResourceLocation.fromNamespaceAndPath(ResourceLocation.PAPER_NAMESPACE, "optionally_flat_bedrock_condition_source")
|
||||
+ );
|
||||
+ private static final KeyDispatchDataCodec<OptionallyFlatBedrockConditionSource> CODEC = KeyDispatchDataCodec.of(RecordCodecBuilder.mapCodec((instance) -> {
|
||||
+ return instance.group(
|
||||
+ ResourceLocation.CODEC.fieldOf("random_name").forGetter(OptionallyFlatBedrockConditionSource::randomName),
|
||||
+ VerticalAnchor.CODEC.fieldOf("true_at_and_below").forGetter(OptionallyFlatBedrockConditionSource::trueAtAndBelow),
|
||||
+ VerticalAnchor.CODEC.fieldOf("false_at_and_above").forGetter(OptionallyFlatBedrockConditionSource::falseAtAndAbove),
|
||||
+ Codec.BOOL.fieldOf("is_roof").forGetter(OptionallyFlatBedrockConditionSource::isRoof)
|
||||
+ ).apply(instance, OptionallyFlatBedrockConditionSource::new);
|
||||
+ }));
|
||||
+
|
||||
+ public static void bootstrap() {
|
||||
+ Registry.register(BuiltInRegistries.MATERIAL_CONDITION, CODEC_RESOURCE_KEY, CODEC.codec());
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public KeyDispatchDataCodec<? extends SurfaceRules.ConditionSource> codec() {
|
||||
+ return CODEC;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public SurfaceRules.Condition apply(final SurfaceRules.Context context) {
|
||||
+ boolean hasFlatBedrock = context.context.getWorld().paperConfig().environment.generateFlatBedrock;
|
||||
+ int tempTrueAtAndBelowY = this.trueAtAndBelow().resolveY(context.context);
|
||||
+ int tempFalseAtAndAboveY = this.falseAtAndAbove().resolveY(context.context);
|
||||
+
|
||||
+ int flatYLevel = this.isRoof ? Math.max(tempFalseAtAndAboveY, tempTrueAtAndBelowY) - 1 : Math.min(tempFalseAtAndAboveY, tempTrueAtAndBelowY);
|
||||
+ final int trueAtAndBelowY = hasFlatBedrock ? flatYLevel : tempTrueAtAndBelowY;
|
||||
+ final int falseAtAndAboveY = hasFlatBedrock ? flatYLevel : tempFalseAtAndAboveY;
|
||||
+
|
||||
+ final PositionalRandomFactory positionalRandomFactory = context.randomState.getOrCreateRandomFactory(this.randomName());
|
||||
+
|
||||
+ class VerticalGradientCondition extends SurfaceRules.LazyYCondition {
|
||||
+ VerticalGradientCondition(SurfaceRules.Context context) {
|
||||
+ super(context);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ protected boolean compute() {
|
||||
+ int blockY = this.context.blockY;
|
||||
+ if (blockY <= trueAtAndBelowY) {
|
||||
+ return true;
|
||||
+ } else if (blockY >= falseAtAndAboveY) {
|
||||
+ return false;
|
||||
+ } else {
|
||||
+ double d = Mth.map(blockY, trueAtAndBelowY, falseAtAndAboveY, 1.0D, 0.0D);
|
||||
+ RandomSource randomSource = positionalRandomFactory.at(this.context.blockX, blockY, this.context.blockZ);
|
||||
+ return (double)randomSource.nextFloat() < d;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return new VerticalGradientCondition(context);
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/net/minecraft/server/Bootstrap.java b/src/main/java/net/minecraft/server/Bootstrap.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/Bootstrap.java
|
||||
+++ b/src/main/java/net/minecraft/server/Bootstrap.java
|
||||
@@ -0,0 +0,0 @@ public class Bootstrap {
|
||||
CauldronInteraction.bootStrap();
|
||||
// Paper start
|
||||
BuiltInRegistries.bootStrap(() -> {
|
||||
+ io.papermc.paper.world.worldgen.OptionallyFlatBedrockConditionSource.bootstrap(); // Paper - Flat bedrock generator settings
|
||||
});
|
||||
// Paper end
|
||||
CreativeModeTabs.validate();
|
||||
diff --git a/src/main/java/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java b/src/main/java/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java
|
||||
@@ -0,0 +0,0 @@ public final class NoiseBasedChunkGenerator extends ChunkGenerator {
|
||||
@Override
|
||||
public void buildSurface(WorldGenRegion region, StructureManager structures, RandomState noiseConfig, ChunkAccess chunk) {
|
||||
if (!SharedConstants.debugVoidTerrain(chunk.getPos())) {
|
||||
- WorldGenerationContext worldgenerationcontext = new WorldGenerationContext(this, region);
|
||||
+ WorldGenerationContext worldgenerationcontext = new WorldGenerationContext(this, region, region.getMinecraftWorld()); // Paper - Flat bedrock generator settings
|
||||
|
||||
this.buildSurface(chunk, worldgenerationcontext, noiseConfig, structures, region.getBiomeManager(), region.registryAccess().lookupOrThrow(Registries.BIOME), Blender.of(region));
|
||||
}
|
||||
@@ -0,0 +0,0 @@ public final class NoiseBasedChunkGenerator extends ChunkGenerator {
|
||||
return this.createNoiseChunk(ichunkaccess1, structureAccessor, Blender.of(chunkRegion), noiseConfig);
|
||||
});
|
||||
Aquifer aquifer = noisechunk.aquifer();
|
||||
- CarvingContext carvingcontext = new CarvingContext(this, chunkRegion.registryAccess(), chunk.getHeightAccessorForGeneration(), noisechunk, noiseConfig, ((NoiseGeneratorSettings) this.settings.value()).surfaceRule());
|
||||
+ CarvingContext carvingcontext = new CarvingContext(this, chunkRegion.registryAccess(), chunk.getHeightAccessorForGeneration(), noisechunk, noiseConfig, ((NoiseGeneratorSettings) this.settings.value()).surfaceRule(), chunkRegion.getMinecraftWorld()); // Paper - Flat bedrock generator settings
|
||||
CarvingMask carvingmask = ((ProtoChunk) chunk).getOrCreateCarvingMask();
|
||||
|
||||
for (int j = -8; j <= 8; ++j) {
|
||||
diff --git a/src/main/java/net/minecraft/world/level/levelgen/WorldGenerationContext.java b/src/main/java/net/minecraft/world/level/levelgen/WorldGenerationContext.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/levelgen/WorldGenerationContext.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/levelgen/WorldGenerationContext.java
|
||||
@@ -0,0 +0,0 @@ import net.minecraft.world.level.chunk.ChunkGenerator;
|
||||
public class WorldGenerationContext {
|
||||
private final int minY;
|
||||
private final int height;
|
||||
+ private final @javax.annotation.Nullable net.minecraft.world.level.Level level; // Paper - Flat bedrock generator settings
|
||||
|
||||
- public WorldGenerationContext(ChunkGenerator generator, LevelHeightAccessor world) {
|
||||
+ public WorldGenerationContext(ChunkGenerator generator, LevelHeightAccessor world) { this(generator, world, null); } // Paper - Flat bedrock generator settings
|
||||
+ public WorldGenerationContext(ChunkGenerator generator, LevelHeightAccessor world, @org.jetbrains.annotations.Nullable net.minecraft.world.level.Level level) { // Paper - Flat bedrock generator settings
|
||||
this.minY = Math.max(world.getMinY(), generator.getMinY());
|
||||
this.height = Math.min(world.getHeight(), generator.getGenDepth());
|
||||
+ this.level = level; // Paper - Flat bedrock generator settings
|
||||
}
|
||||
|
||||
public int getMinGenY() {
|
||||
@@ -0,0 +0,0 @@ public class WorldGenerationContext {
|
||||
public int getGenDepth() {
|
||||
return this.height;
|
||||
}
|
||||
+
|
||||
+ // Paper start - Flat bedrock generator settings
|
||||
+ public net.minecraft.world.level.Level getWorld() {
|
||||
+ if (this.level == null) {
|
||||
+ throw new NullPointerException("WorldGenerationContext was initialized without a Level, but WorldGenerationContext#getWorld was called");
|
||||
+ }
|
||||
+ return this.level;
|
||||
+ }
|
||||
+ // Paper end - Flat bedrock generator settings
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/level/levelgen/carver/CarvingContext.java b/src/main/java/net/minecraft/world/level/levelgen/carver/CarvingContext.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/levelgen/carver/CarvingContext.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/levelgen/carver/CarvingContext.java
|
||||
@@ -0,0 +0,0 @@ public class CarvingContext extends WorldGenerationContext {
|
||||
LevelHeightAccessor heightLimitView,
|
||||
NoiseChunk chunkNoiseSampler,
|
||||
RandomState noiseConfig,
|
||||
- SurfaceRules.RuleSource materialRule
|
||||
+ SurfaceRules.RuleSource materialRule, @javax.annotation.Nullable net.minecraft.world.level.Level level // Paper - Flat bedrock generator settings
|
||||
) {
|
||||
- super(noiseChunkGenerator, heightLimitView);
|
||||
+ super(noiseChunkGenerator, heightLimitView, level); // Paper - Flat bedrock generator settings
|
||||
this.registryAccess = registryManager;
|
||||
this.noiseChunk = chunkNoiseSampler;
|
||||
this.randomState = noiseConfig;
|
||||
diff --git a/src/main/java/net/minecraft/world/level/levelgen/placement/PlacementContext.java b/src/main/java/net/minecraft/world/level/levelgen/placement/PlacementContext.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/levelgen/placement/PlacementContext.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/levelgen/placement/PlacementContext.java
|
||||
@@ -0,0 +0,0 @@ public class PlacementContext extends WorldGenerationContext {
|
||||
private final Optional<PlacedFeature> topFeature;
|
||||
|
||||
public PlacementContext(WorldGenLevel world, ChunkGenerator generator, Optional<PlacedFeature> placedFeature) {
|
||||
- super(generator, world);
|
||||
+ super(generator, world, world.getLevel()); // Paper - Flat bedrock generator settings
|
||||
this.level = world;
|
||||
this.generator = generator;
|
||||
this.topFeature = placedFeature;
|
||||
diff --git a/src/main/resources/data/minecraft/worldgen/noise_settings/amplified.json b/src/main/resources/data/minecraft/worldgen/noise_settings/amplified.json
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/resources/data/minecraft/worldgen/noise_settings/amplified.json
|
||||
+++ b/src/main/resources/data/minecraft/worldgen/noise_settings/amplified.json
|
||||
@@ -0,0 +0,0 @@
|
||||
{
|
||||
"type": "minecraft:condition",
|
||||
"if_true": {
|
||||
- "type": "minecraft:vertical_gradient",
|
||||
+ "type": "paper:optionally_flat_bedrock_condition_source",
|
||||
+ "is_roof": false,
|
||||
"false_at_and_above": {
|
||||
"above_bottom": 5
|
||||
},
|
||||
diff --git a/src/main/resources/data/minecraft/worldgen/noise_settings/caves.json b/src/main/resources/data/minecraft/worldgen/noise_settings/caves.json
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/resources/data/minecraft/worldgen/noise_settings/caves.json
|
||||
+++ b/src/main/resources/data/minecraft/worldgen/noise_settings/caves.json
|
||||
@@ -0,0 +0,0 @@
|
||||
"if_true": {
|
||||
"type": "minecraft:not",
|
||||
"invert": {
|
||||
- "type": "minecraft:vertical_gradient",
|
||||
+ "type": "paper:optionally_flat_bedrock_condition_source",
|
||||
+ "is_roof": true,
|
||||
"false_at_and_above": {
|
||||
"below_top": 0
|
||||
},
|
||||
@@ -0,0 +0,0 @@
|
||||
{
|
||||
"type": "minecraft:condition",
|
||||
"if_true": {
|
||||
- "type": "minecraft:vertical_gradient",
|
||||
+ "type": "paper:optionally_flat_bedrock_condition_source",
|
||||
+ "is_roof": false,
|
||||
"false_at_and_above": {
|
||||
"above_bottom": 5
|
||||
},
|
||||
diff --git a/src/main/resources/data/minecraft/worldgen/noise_settings/large_biomes.json b/src/main/resources/data/minecraft/worldgen/noise_settings/large_biomes.json
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/resources/data/minecraft/worldgen/noise_settings/large_biomes.json
|
||||
+++ b/src/main/resources/data/minecraft/worldgen/noise_settings/large_biomes.json
|
||||
@@ -0,0 +0,0 @@
|
||||
{
|
||||
"type": "minecraft:condition",
|
||||
"if_true": {
|
||||
- "type": "minecraft:vertical_gradient",
|
||||
+ "type": "paper:optionally_flat_bedrock_condition_source",
|
||||
+ "is_roof": false,
|
||||
"false_at_and_above": {
|
||||
"above_bottom": 5
|
||||
},
|
||||
diff --git a/src/main/resources/data/minecraft/worldgen/noise_settings/nether.json b/src/main/resources/data/minecraft/worldgen/noise_settings/nether.json
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/resources/data/minecraft/worldgen/noise_settings/nether.json
|
||||
+++ b/src/main/resources/data/minecraft/worldgen/noise_settings/nether.json
|
||||
@@ -0,0 +0,0 @@
|
||||
{
|
||||
"type": "minecraft:condition",
|
||||
"if_true": {
|
||||
- "type": "minecraft:vertical_gradient",
|
||||
+ "type": "paper:optionally_flat_bedrock_condition_source",
|
||||
+ "is_roof": false,
|
||||
"false_at_and_above": {
|
||||
"above_bottom": 5
|
||||
},
|
||||
@@ -0,0 +0,0 @@
|
||||
"if_true": {
|
||||
"type": "minecraft:not",
|
||||
"invert": {
|
||||
- "type": "minecraft:vertical_gradient",
|
||||
+ "type": "paper:optionally_flat_bedrock_condition_source",
|
||||
+ "is_roof": true,
|
||||
"false_at_and_above": {
|
||||
"below_top": 0
|
||||
},
|
||||
diff --git a/src/main/resources/data/minecraft/worldgen/noise_settings/overworld.json b/src/main/resources/data/minecraft/worldgen/noise_settings/overworld.json
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/resources/data/minecraft/worldgen/noise_settings/overworld.json
|
||||
+++ b/src/main/resources/data/minecraft/worldgen/noise_settings/overworld.json
|
||||
@@ -0,0 +0,0 @@
|
||||
{
|
||||
"type": "minecraft:condition",
|
||||
"if_true": {
|
||||
- "type": "minecraft:vertical_gradient",
|
||||
+ "type": "paper:optionally_flat_bedrock_condition_source",
|
||||
+ "is_roof": false,
|
||||
"false_at_and_above": {
|
||||
"above_bottom": 5
|
||||
},
|
|
@ -1,775 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Fri, 13 May 2016 01:38:06 -0400
|
||||
Subject: [PATCH] Entity Activation Range 2.0
|
||||
|
||||
Optimizes performance of Activation Range
|
||||
|
||||
Adds many new configurations and a new wake up inactive system
|
||||
|
||||
Fixes and adds new Immunities to improve gameplay behavior
|
||||
|
||||
Adds water Mobs to activation range config and nerfs fish
|
||||
Adds flying monsters to control ghast and phantoms
|
||||
Adds villagers as separate config
|
||||
|
||||
== AT ==
|
||||
public net.minecraft.world.entity.Entity isInsidePortal
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
|
||||
public void tickNonPassenger(Entity entity) {
|
||||
// Spigot start
|
||||
- if (!org.spigotmc.ActivationRange.checkIfActive(entity)) {
|
||||
+ /*if (!org.spigotmc.ActivationRange.checkIfActive(entity)) { // Paper - comment out EAR 2
|
||||
entity.tickCount++;
|
||||
entity.inactiveTick();
|
||||
return;
|
||||
- }
|
||||
+ }*/ // Paper - comment out EAR 2
|
||||
// Spigot end
|
||||
entity.setOldPosAndRot();
|
||||
ProfilerFiller gameprofilerfiller = Profiler.get();
|
||||
@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
return BuiltInRegistries.ENTITY_TYPE.getKey(entity.getType()).toString();
|
||||
});
|
||||
gameprofilerfiller.incrementCounter("tickNonPassenger");
|
||||
+ final boolean isActive = org.spigotmc.ActivationRange.checkIfActive(entity); // Paper - EAR 2
|
||||
+ if (isActive) { // Paper - EAR 2
|
||||
entity.tick();
|
||||
entity.postTick(); // CraftBukkit
|
||||
+ } else { entity.inactiveTick(); } // Paper - EAR 2
|
||||
gameprofilerfiller.pop();
|
||||
Iterator iterator = entity.getPassengers().iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
Entity entity1 = (Entity) iterator.next();
|
||||
|
||||
- this.tickPassenger(entity, entity1);
|
||||
+ this.tickPassenger(entity, entity1, isActive); // Paper - EAR 2
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
- private void tickPassenger(Entity vehicle, Entity passenger) {
|
||||
+ private void tickPassenger(Entity vehicle, Entity passenger, boolean isActive) { // Paper - EAR 2
|
||||
if (!passenger.isRemoved() && passenger.getVehicle() == vehicle) {
|
||||
if (passenger instanceof Player || this.entityTickList.contains(passenger)) {
|
||||
passenger.setOldPosAndRot();
|
||||
@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
return BuiltInRegistries.ENTITY_TYPE.getKey(passenger.getType()).toString();
|
||||
});
|
||||
gameprofilerfiller.incrementCounter("tickPassenger");
|
||||
+ // Paper start - EAR 2
|
||||
+ if (isActive) {
|
||||
passenger.rideTick();
|
||||
passenger.postTick(); // CraftBukkit
|
||||
+ } else {
|
||||
+ passenger.setDeltaMovement(Vec3.ZERO);
|
||||
+ passenger.inactiveTick();
|
||||
+ // copied from inside of if (isPassenger()) of passengerTick, but that ifPassenger is unnecessary
|
||||
+ vehicle.positionRider(passenger);
|
||||
+ }
|
||||
+ // Paper end - EAR 2
|
||||
gameprofilerfiller.pop();
|
||||
Iterator iterator = passenger.getPassengers().iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
Entity entity2 = (Entity) iterator.next();
|
||||
|
||||
- this.tickPassenger(passenger, entity2);
|
||||
+ this.tickPassenger(passenger, entity2, isActive); // Paper - EAR 2
|
||||
}
|
||||
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -0,0 +0,0 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
// Spigot end
|
||||
protected int numCollisions = 0; // Paper - Cap entity collisions
|
||||
public boolean fromNetherPortal; // Paper - Add option to nerf pigmen from nether portals
|
||||
+ public long activatedImmunityTick = Integer.MIN_VALUE; // Paper - EAR
|
||||
+ public boolean isTemporarilyActive; // Paper - EAR
|
||||
public boolean spawnedViaMobSpawner; // Paper - Yes this name is similar to above, upstream took the better one
|
||||
// Paper start - Entity origin API
|
||||
@javax.annotation.Nullable
|
||||
@@ -0,0 +0,0 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
} else {
|
||||
this.wasOnFire = this.isOnFire();
|
||||
if (type == MoverType.PISTON) {
|
||||
+ this.activatedTick = Math.max(this.activatedTick, MinecraftServer.currentTick + 20); // Paper - EAR 2
|
||||
+ this.activatedImmunityTick = Math.max(this.activatedImmunityTick, MinecraftServer.currentTick + 20); // Paper - EAR 2
|
||||
movement = this.limitPistonMovement(movement);
|
||||
if (movement.equals(Vec3.ZERO)) {
|
||||
return;
|
||||
@@ -0,0 +0,0 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
this.stuckSpeedMultiplier = Vec3.ZERO;
|
||||
this.setDeltaMovement(Vec3.ZERO);
|
||||
}
|
||||
+ // Paper start - ignore movement changes while inactive.
|
||||
+ if (isTemporarilyActive && !(this instanceof ItemEntity) && movement == getDeltaMovement() && type == MoverType.SELF) {
|
||||
+ setDeltaMovement(Vec3.ZERO);
|
||||
+ gameprofilerfiller.pop();
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end
|
||||
|
||||
movement = this.maybeBackOffFromEdge(movement, type);
|
||||
Vec3 vec3d1 = this.collide(movement);
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Mob.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Mob.java
|
||||
@@ -0,0 +0,0 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
|
||||
return this.lookControl;
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public void inactiveTick() {
|
||||
+ super.inactiveTick();
|
||||
+ if (this.goalSelector.inactiveTick()) {
|
||||
+ this.goalSelector.tick();
|
||||
+ }
|
||||
+ if (this.targetSelector.inactiveTick()) {
|
||||
+ this.targetSelector.tick();
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
public MoveControl getMoveControl() {
|
||||
Entity entity = this.getControlledVehicle();
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/PathfinderMob.java b/src/main/java/net/minecraft/world/entity/PathfinderMob.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/PathfinderMob.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/PathfinderMob.java
|
||||
@@ -0,0 +0,0 @@ public abstract class PathfinderMob extends Mob {
|
||||
super(type, world);
|
||||
}
|
||||
|
||||
+ public BlockPos movingTarget; public BlockPos getMovingTarget() { return movingTarget; } // Paper
|
||||
+
|
||||
public float getWalkTargetValue(BlockPos pos) {
|
||||
return this.getWalkTargetValue(pos, this.level());
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java b/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java
|
||||
@@ -0,0 +0,0 @@ public class GoalSelector {
|
||||
private final Map<Goal.Flag, WrappedGoal> lockedFlags = new EnumMap<>(Goal.Flag.class);
|
||||
private final Set<WrappedGoal> availableGoals = new ObjectLinkedOpenHashSet<>();
|
||||
private final EnumSet<Goal.Flag> disabledFlags = EnumSet.noneOf(Goal.Flag.class);
|
||||
+ private int curRate; // Paper - EAR 2
|
||||
|
||||
public void addGoal(int priority, Goal goal) {
|
||||
this.availableGoals.add(new WrappedGoal(priority, goal));
|
||||
@@ -0,0 +0,0 @@ public class GoalSelector {
|
||||
this.availableGoals.removeIf(goal -> predicate.test(goal.getGoal()));
|
||||
}
|
||||
|
||||
+ // Paper start - EAR 2
|
||||
+ public boolean inactiveTick() {
|
||||
+ this.curRate++;
|
||||
+ return this.curRate % 3 == 0; // TODO newGoalRate was already unused in 1.20.4, check if this is correct
|
||||
+ }
|
||||
+ public boolean hasTasks() {
|
||||
+ for (WrappedGoal task : this.availableGoals) {
|
||||
+ if (task.isRunning()) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ }
|
||||
+ return false;
|
||||
+ }
|
||||
+ // Paper end - EAR 2
|
||||
public void removeGoal(Goal goal) {
|
||||
for (WrappedGoal wrappedGoal : this.availableGoals) {
|
||||
if (wrappedGoal.getGoal() == goal && wrappedGoal.isRunning()) {
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java
|
||||
@@ -0,0 +0,0 @@ public abstract class MoveToBlockGoal extends Goal {
|
||||
public MoveToBlockGoal(PathfinderMob mob, double speed, int range) {
|
||||
this(mob, speed, range, 1);
|
||||
}
|
||||
+ // Paper start - activation range improvements
|
||||
+ @Override
|
||||
+ public void stop() {
|
||||
+ super.stop();
|
||||
+ this.blockPos = BlockPos.ZERO;
|
||||
+ this.mob.movingTarget = null;
|
||||
+ }
|
||||
+ // Paper end
|
||||
|
||||
public MoveToBlockGoal(PathfinderMob mob, double speed, int range, int maxYDifference) {
|
||||
this.mob = mob;
|
||||
@@ -0,0 +0,0 @@ public abstract class MoveToBlockGoal extends Goal {
|
||||
mutableBlockPos.setWithOffset(blockPos, m, k - 1, n);
|
||||
if (this.mob.isWithinRestriction(mutableBlockPos) && this.isValidTarget(this.mob.level(), mutableBlockPos)) {
|
||||
this.blockPos = mutableBlockPos;
|
||||
+ this.mob.movingTarget = mutableBlockPos == BlockPos.ZERO ? null : mutableBlockPos.immutable(); // Paper
|
||||
return true;
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/npc/Villager.java b/src/main/java/net/minecraft/world/entity/npc/Villager.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/npc/Villager.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/npc/Villager.java
|
||||
@@ -0,0 +0,0 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
|
||||
@Override
|
||||
public void inactiveTick() {
|
||||
// SPIGOT-3874, SPIGOT-3894, SPIGOT-3846, SPIGOT-5286 :(
|
||||
- if (this.level().spigotConfig.tickInactiveVillagers && this.isEffectiveAi()) {
|
||||
- this.customServerAiStep((ServerLevel) this.level());
|
||||
+ // Paper start
|
||||
+ if (this.getUnhappyCounter() > 0) {
|
||||
+ this.setUnhappyCounter(this.getUnhappyCounter() - 1);
|
||||
+ }
|
||||
+ if (this.isEffectiveAi()) {
|
||||
+ if (this.level().spigotConfig.tickInactiveVillagers) {
|
||||
+ this.customServerAiStep(this.level().getMinecraftWorld());
|
||||
+ } else {
|
||||
+ this.customServerAiStep(this.level().getMinecraftWorld(), true);
|
||||
+ }
|
||||
}
|
||||
+ maybeDecayGossip();
|
||||
+ // Paper end
|
||||
super.inactiveTick();
|
||||
}
|
||||
// Spigot End
|
||||
|
||||
@Override
|
||||
protected void customServerAiStep(ServerLevel world) {
|
||||
+ // Paper start - EAR 2
|
||||
+ this.customServerAiStep(world, false);
|
||||
+ }
|
||||
+ protected void customServerAiStep(ServerLevel world, final boolean inactive) {
|
||||
+ // Paper end - EAR 2
|
||||
ProfilerFiller gameprofilerfiller = Profiler.get();
|
||||
|
||||
gameprofilerfiller.push("villagerBrain");
|
||||
- this.getBrain().tick(world, this);
|
||||
+ if (!inactive) this.getBrain().tick(world, this);
|
||||
gameprofilerfiller.pop();
|
||||
if (this.assignProfessionWhenSpawned) {
|
||||
this.assignProfessionWhenSpawned = false;
|
||||
@@ -0,0 +0,0 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
|
||||
this.lastTradedPlayer = null;
|
||||
}
|
||||
|
||||
- if (!this.isNoAi() && this.random.nextInt(100) == 0) {
|
||||
+ if (!inactive && !this.isNoAi() && this.random.nextInt(100) == 0) { // Paper - EAR 2
|
||||
Raid raid = world.getRaidAt(this.blockPosition());
|
||||
|
||||
if (raid != null && raid.isActive() && !raid.isOver()) {
|
||||
@@ -0,0 +0,0 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
|
||||
if (this.getVillagerData().getProfession() == VillagerProfession.NONE && this.isTrading()) {
|
||||
this.stopTrading();
|
||||
}
|
||||
+ if (inactive) return; // Paper - EAR 2
|
||||
|
||||
super.customServerAiStep(world);
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/vehicle/MinecartHopper.java b/src/main/java/net/minecraft/world/entity/vehicle/MinecartHopper.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/vehicle/MinecartHopper.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/vehicle/MinecartHopper.java
|
||||
@@ -0,0 +0,0 @@ public class MinecartHopper extends AbstractMinecartContainer implements Hopper
|
||||
if (bl != this.isEnabled()) {
|
||||
this.setEnabled(bl);
|
||||
}
|
||||
+ this.immunize(); // Paper
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
@@ -0,0 +0,0 @@ public class MinecartHopper extends AbstractMinecartContainer implements Hopper
|
||||
|
||||
public boolean suckInItems() {
|
||||
if (HopperBlockEntity.suckInItems(this.level(), this)) {
|
||||
+ this.immunize(); // Paper
|
||||
return true;
|
||||
} else {
|
||||
for (ItemEntity itemEntity : this.level()
|
||||
.getEntitiesOfClass(ItemEntity.class, this.getBoundingBox().inflate(0.25, 0.0, 0.25), EntitySelector.ENTITY_STILL_ALIVE)) {
|
||||
if (HopperBlockEntity.addItem(this, itemEntity)) {
|
||||
+ this.immunize(); // Paper
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +0,0 @@ public class MinecartHopper extends AbstractMinecartContainer implements Hopper
|
||||
public AbstractContainerMenu createMenu(int syncId, Inventory playerInventory) {
|
||||
return new HopperMenu(syncId, playerInventory, this);
|
||||
}
|
||||
+
|
||||
+ // Paper start
|
||||
+ public void immunize() {
|
||||
+ this.activatedImmunityTick = Math.max(this.activatedImmunityTick, net.minecraft.server.MinecraftServer.currentTick + 20);
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -0,0 +0,0 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
public Map<BlockPos, BlockEntity> capturedTileEntities = new java.util.LinkedHashMap<>(); // Paper - Retain block place order when capturing blockstates
|
||||
public List<ItemEntity> captureDrops;
|
||||
public final it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap<SpawnCategory> ticksPerSpawnCategory = new it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap<>();
|
||||
+ // Paper start
|
||||
+ public int wakeupInactiveRemainingAnimals;
|
||||
+ public int wakeupInactiveRemainingFlying;
|
||||
+ public int wakeupInactiveRemainingMonsters;
|
||||
+ public int wakeupInactiveRemainingVillagers;
|
||||
+ // Paper end
|
||||
public boolean populating;
|
||||
public final org.spigotmc.SpigotWorldConfig spigotConfig; // Spigot
|
||||
// Paper start - add paper world config
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java b/src/main/java/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
|
||||
@@ -0,0 +0,0 @@ public class PistonMovingBlockEntity extends BlockEntity {
|
||||
}
|
||||
|
||||
entity.setDeltaMovement(e, g, h);
|
||||
+ // Paper - EAR items stuck in in slime pushed by a piston
|
||||
+ entity.activatedTick = Math.max(entity.activatedTick, net.minecraft.server.MinecraftServer.currentTick + 10);
|
||||
+ entity.activatedImmunityTick = Math.max(entity.activatedImmunityTick, net.minecraft.server.MinecraftServer.currentTick + 10);
|
||||
+ // Paper end
|
||||
break;
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/org/spigotmc/ActivationRange.java b/src/main/java/org/spigotmc/ActivationRange.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/org/spigotmc/ActivationRange.java
|
||||
+++ b/src/main/java/org/spigotmc/ActivationRange.java
|
||||
@@ -0,0 +0,0 @@
|
||||
package org.spigotmc;
|
||||
|
||||
+import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
+import net.minecraft.server.level.ServerChunkCache;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.ExperienceOrb;
|
||||
+import net.minecraft.world.entity.FlyingMob;
|
||||
import net.minecraft.world.entity.LightningBolt;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
+import net.minecraft.world.entity.Mob;
|
||||
import net.minecraft.world.entity.PathfinderMob;
|
||||
+import net.minecraft.world.entity.ai.Brain;
|
||||
import net.minecraft.world.entity.ambient.AmbientCreature;
|
||||
import net.minecraft.world.entity.animal.Animal;
|
||||
+import net.minecraft.world.entity.animal.Bee;
|
||||
import net.minecraft.world.entity.animal.Sheep;
|
||||
+import net.minecraft.world.entity.animal.WaterAnimal;
|
||||
+import net.minecraft.world.entity.animal.horse.Llama;
|
||||
import net.minecraft.world.entity.boss.EnderDragonPart;
|
||||
import net.minecraft.world.entity.boss.enderdragon.EndCrystal;
|
||||
import net.minecraft.world.entity.boss.enderdragon.EnderDragon;
|
||||
@@ -0,0 +0,0 @@ import net.minecraft.world.entity.boss.wither.WitherBoss;
|
||||
import net.minecraft.world.entity.item.ItemEntity;
|
||||
import net.minecraft.world.entity.item.PrimedTnt;
|
||||
import net.minecraft.world.entity.monster.Creeper;
|
||||
-import net.minecraft.world.entity.monster.Monster;
|
||||
-import net.minecraft.world.entity.monster.Slime;
|
||||
+import net.minecraft.world.entity.monster.Enemy;
|
||||
+import net.minecraft.world.entity.monster.Pillager;
|
||||
import net.minecraft.world.entity.npc.Villager;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.entity.projectile.AbstractArrow;
|
||||
import net.minecraft.world.entity.projectile.AbstractHurtingProjectile;
|
||||
+import net.minecraft.world.entity.projectile.EyeOfEnder;
|
||||
import net.minecraft.world.entity.projectile.FireworkRocketEntity;
|
||||
import net.minecraft.world.entity.projectile.ThrowableProjectile;
|
||||
import net.minecraft.world.entity.projectile.ThrownTrident;
|
||||
@@ -0,0 +0,0 @@ public class ActivationRange
|
||||
|
||||
AABB boundingBox = new AABB( 0, 0, 0, 0, 0, 0 );
|
||||
}
|
||||
+ // Paper start
|
||||
+
|
||||
+ static net.minecraft.world.entity.schedule.Activity[] VILLAGER_PANIC_IMMUNITIES = {
|
||||
+ net.minecraft.world.entity.schedule.Activity.HIDE,
|
||||
+ net.minecraft.world.entity.schedule.Activity.PRE_RAID,
|
||||
+ net.minecraft.world.entity.schedule.Activity.RAID,
|
||||
+ net.minecraft.world.entity.schedule.Activity.PANIC
|
||||
+ };
|
||||
+
|
||||
+ private static int checkInactiveWakeup(Entity entity) {
|
||||
+ Level world = entity.level();
|
||||
+ SpigotWorldConfig config = world.spigotConfig;
|
||||
+ long inactiveFor = MinecraftServer.currentTick - entity.activatedTick;
|
||||
+ if (entity.activationType == ActivationType.VILLAGER) {
|
||||
+ if (inactiveFor > config.wakeUpInactiveVillagersEvery && world.wakeupInactiveRemainingVillagers > 0) {
|
||||
+ world.wakeupInactiveRemainingVillagers--;
|
||||
+ return config.wakeUpInactiveVillagersFor;
|
||||
+ }
|
||||
+ } else if (entity.activationType == ActivationType.ANIMAL) {
|
||||
+ if (inactiveFor > config.wakeUpInactiveAnimalsEvery && world.wakeupInactiveRemainingAnimals > 0) {
|
||||
+ world.wakeupInactiveRemainingAnimals--;
|
||||
+ return config.wakeUpInactiveAnimalsFor;
|
||||
+ }
|
||||
+ } else if (entity.activationType == ActivationType.FLYING_MONSTER) {
|
||||
+ if (inactiveFor > config.wakeUpInactiveFlyingEvery && world.wakeupInactiveRemainingFlying > 0) {
|
||||
+ world.wakeupInactiveRemainingFlying--;
|
||||
+ return config.wakeUpInactiveFlyingFor;
|
||||
+ }
|
||||
+ } else if (entity.activationType == ActivationType.MONSTER || entity.activationType == ActivationType.RAIDER) {
|
||||
+ if (inactiveFor > config.wakeUpInactiveMonstersEvery && world.wakeupInactiveRemainingMonsters > 0) {
|
||||
+ world.wakeupInactiveRemainingMonsters--;
|
||||
+ return config.wakeUpInactiveMonstersFor;
|
||||
+ }
|
||||
+ }
|
||||
+ return -1;
|
||||
+ }
|
||||
+ // Paper end
|
||||
|
||||
static AABB maxBB = new AABB( 0, 0, 0, 0, 0, 0 );
|
||||
|
||||
@@ -0,0 +0,0 @@ public class ActivationRange
|
||||
*/
|
||||
public static ActivationType initializeEntityActivationType(Entity entity)
|
||||
{
|
||||
+ if (entity instanceof WaterAnimal) { return ActivationType.WATER; } // Paper
|
||||
+ else if (entity instanceof Villager) { return ActivationType.VILLAGER; } // Paper
|
||||
+ else if (entity instanceof FlyingMob && entity instanceof Enemy) { return ActivationType.FLYING_MONSTER; } // Paper - doing & Monster incase Flying no longer includes monster in future
|
||||
if ( entity instanceof Raider )
|
||||
{
|
||||
return ActivationType.RAIDER;
|
||||
- } else if ( entity instanceof Monster || entity instanceof Slime )
|
||||
+ } else if ( entity instanceof Enemy ) // Paper - correct monster check
|
||||
{
|
||||
return ActivationType.MONSTER;
|
||||
} else if ( entity instanceof PathfinderMob || entity instanceof AmbientCreature )
|
||||
@@ -0,0 +0,0 @@ public class ActivationRange
|
||||
*/
|
||||
public static boolean initializeEntityActivationState(Entity entity, SpigotWorldConfig config)
|
||||
{
|
||||
- if ( ( entity.activationType == ActivationType.MISC && config.miscActivationRange == 0 )
|
||||
- || ( entity.activationType == ActivationType.RAIDER && config.raiderActivationRange == 0 )
|
||||
- || ( entity.activationType == ActivationType.ANIMAL && config.animalActivationRange == 0 )
|
||||
- || ( entity.activationType == ActivationType.MONSTER && config.monsterActivationRange == 0 )
|
||||
+ if ( ( entity.activationType == ActivationType.MISC && config.miscActivationRange <= 0 )
|
||||
+ || ( entity.activationType == ActivationType.RAIDER && config.raiderActivationRange <= 0 )
|
||||
+ || ( entity.activationType == ActivationType.ANIMAL && config.animalActivationRange <= 0 )
|
||||
+ || ( entity.activationType == ActivationType.MONSTER && config.monsterActivationRange <= 0 )
|
||||
+ || ( entity.activationType == ActivationType.VILLAGER && config.villagerActivationRange <= 0 ) // Paper
|
||||
+ || ( entity.activationType == ActivationType.WATER && config.waterActivationRange <= 0 ) // Paper
|
||||
+ || ( entity.activationType == ActivationType.FLYING_MONSTER && config.flyingMonsterActivationRange <= 0 ) // Paper
|
||||
+ || entity instanceof EyeOfEnder // Paper
|
||||
|| entity instanceof Player
|
||||
|| entity instanceof ThrowableProjectile
|
||||
|| entity instanceof EnderDragon
|
||||
@@ -0,0 +0,0 @@ public class ActivationRange
|
||||
final int raiderActivationRange = world.spigotConfig.raiderActivationRange;
|
||||
final int animalActivationRange = world.spigotConfig.animalActivationRange;
|
||||
final int monsterActivationRange = world.spigotConfig.monsterActivationRange;
|
||||
+ // Paper start
|
||||
+ final int waterActivationRange = world.spigotConfig.waterActivationRange;
|
||||
+ final int flyingActivationRange = world.spigotConfig.flyingMonsterActivationRange;
|
||||
+ final int villagerActivationRange = world.spigotConfig.villagerActivationRange;
|
||||
+ world.wakeupInactiveRemainingAnimals = Math.min(world.wakeupInactiveRemainingAnimals + 1, world.spigotConfig.wakeUpInactiveAnimals);
|
||||
+ world.wakeupInactiveRemainingVillagers = Math.min(world.wakeupInactiveRemainingVillagers + 1, world.spigotConfig.wakeUpInactiveVillagers);
|
||||
+ world.wakeupInactiveRemainingMonsters = Math.min(world.wakeupInactiveRemainingMonsters + 1, world.spigotConfig.wakeUpInactiveMonsters);
|
||||
+ world.wakeupInactiveRemainingFlying = Math.min(world.wakeupInactiveRemainingFlying + 1, world.spigotConfig.wakeUpInactiveFlying);
|
||||
+ final ServerChunkCache chunkProvider = (ServerChunkCache) world.getChunkSource();
|
||||
+ // Paper end
|
||||
|
||||
int maxRange = Math.max( monsterActivationRange, animalActivationRange );
|
||||
maxRange = Math.max( maxRange, raiderActivationRange );
|
||||
maxRange = Math.max( maxRange, miscActivationRange );
|
||||
+ // Paper start
|
||||
+ maxRange = Math.max( maxRange, flyingActivationRange );
|
||||
+ maxRange = Math.max( maxRange, waterActivationRange );
|
||||
+ maxRange = Math.max( maxRange, villagerActivationRange );
|
||||
+ // Paper end
|
||||
maxRange = Math.min( ( world.spigotConfig.simulationDistance << 4 ) - 8, maxRange );
|
||||
|
||||
for ( Player player : world.players() )
|
||||
@@ -0,0 +0,0 @@ public class ActivationRange
|
||||
continue;
|
||||
}
|
||||
|
||||
- ActivationRange.maxBB = player.getBoundingBox().inflate( maxRange, 256, maxRange );
|
||||
- ActivationType.MISC.boundingBox = player.getBoundingBox().inflate( miscActivationRange, 256, miscActivationRange );
|
||||
- ActivationType.RAIDER.boundingBox = player.getBoundingBox().inflate( raiderActivationRange, 256, raiderActivationRange );
|
||||
- ActivationType.ANIMAL.boundingBox = player.getBoundingBox().inflate( animalActivationRange, 256, animalActivationRange );
|
||||
- ActivationType.MONSTER.boundingBox = player.getBoundingBox().inflate( monsterActivationRange, 256, monsterActivationRange );
|
||||
+ // Paper start
|
||||
+ int worldHeight = world.getHeight();
|
||||
+ ActivationRange.maxBB = player.getBoundingBox().inflate( maxRange, worldHeight, maxRange );
|
||||
+ ActivationType.MISC.boundingBox = player.getBoundingBox().inflate( miscActivationRange, worldHeight, miscActivationRange );
|
||||
+ ActivationType.RAIDER.boundingBox = player.getBoundingBox().inflate( raiderActivationRange, worldHeight, raiderActivationRange );
|
||||
+ ActivationType.ANIMAL.boundingBox = player.getBoundingBox().inflate( animalActivationRange, worldHeight, animalActivationRange );
|
||||
+ ActivationType.MONSTER.boundingBox = player.getBoundingBox().inflate( monsterActivationRange, worldHeight, monsterActivationRange );
|
||||
+ ActivationType.WATER.boundingBox = player.getBoundingBox().inflate( waterActivationRange, worldHeight, waterActivationRange );
|
||||
+ ActivationType.FLYING_MONSTER.boundingBox = player.getBoundingBox().inflate( flyingActivationRange, worldHeight, flyingActivationRange );
|
||||
+ ActivationType.VILLAGER.boundingBox = player.getBoundingBox().inflate( villagerActivationRange, worldHeight, villagerActivationRange );
|
||||
+ // Paper end
|
||||
|
||||
- world.getEntities().get(ActivationRange.maxBB, ActivationRange::activateEntity);
|
||||
+ // Paper start
|
||||
+ java.util.List<Entity> entities = world.getEntities((Entity)null, ActivationRange.maxBB, null);
|
||||
+ boolean tickMarkers = world.paperConfig().entities.markers.tick; // Paper - Configurable marker ticking
|
||||
+ for (Entity entity : entities) {
|
||||
+ // Paper start - Configurable marker ticking
|
||||
+ if (!tickMarkers && entity instanceof net.minecraft.world.entity.Marker) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ // Paper end - Configurable marker ticking
|
||||
+ ActivationRange.activateEntity(entity);
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +0,0 @@ public class ActivationRange
|
||||
* @param entity
|
||||
* @return
|
||||
*/
|
||||
- public static boolean checkEntityImmunities(Entity entity)
|
||||
+ public static int checkEntityImmunities(Entity entity) // Paper - return # of ticks to get immunity
|
||||
{
|
||||
+ // Paper start
|
||||
+ SpigotWorldConfig config = entity.level().spigotConfig;
|
||||
+ int inactiveWakeUpImmunity = checkInactiveWakeup(entity);
|
||||
+ if (inactiveWakeUpImmunity > -1) {
|
||||
+ return inactiveWakeUpImmunity;
|
||||
+ }
|
||||
+ if (entity.getRemainingFireTicks() > 0) {
|
||||
+ return 2;
|
||||
+ }
|
||||
+ if (entity.activatedImmunityTick >= MinecraftServer.currentTick) {
|
||||
+ return 1;
|
||||
+ }
|
||||
+ long inactiveFor = MinecraftServer.currentTick - entity.activatedTick;
|
||||
+ // Paper end
|
||||
// quick checks.
|
||||
- if ( entity.wasTouchingWater || entity.getRemainingFireTicks() > 0 )
|
||||
+ if ( (entity.activationType != ActivationType.WATER && entity.wasTouchingWater && entity.isPushedByFluid()) ) // Paper
|
||||
{
|
||||
- return true;
|
||||
+ return 100; // Paper
|
||||
+ }
|
||||
+ // Paper start
|
||||
+ if ( !entity.onGround() || entity.getDeltaMovement().horizontalDistanceSqr() > 9.999999747378752E-6D )
|
||||
+ {
|
||||
+ return 100;
|
||||
}
|
||||
+ // Paper end
|
||||
if ( !( entity instanceof AbstractArrow ) )
|
||||
{
|
||||
- if ( !entity.onGround() || !entity.passengers.isEmpty() || entity.isPassenger() )
|
||||
+ if ( (!entity.onGround() && !(entity instanceof FlyingMob)) ) // Paper - remove passengers logic
|
||||
{
|
||||
- return true;
|
||||
+ return 10; // Paper
|
||||
}
|
||||
} else if ( !( (AbstractArrow) entity ).isInGround() )
|
||||
{
|
||||
- return true;
|
||||
+ return 1; // Paper
|
||||
}
|
||||
// special cases.
|
||||
if ( entity instanceof LivingEntity )
|
||||
{
|
||||
LivingEntity living = (LivingEntity) entity;
|
||||
- if ( /*TODO: Missed mapping? living.attackTicks > 0 || */ living.hurtTime > 0 || living.activeEffects.size() > 0 )
|
||||
+ if ( living.onClimbable() || living.jumping || living.hurtTime > 0 || living.activeEffects.size() > 0 || living.isFreezing()) // Paper
|
||||
{
|
||||
- return true;
|
||||
+ return 1; // Paper
|
||||
}
|
||||
- if ( entity instanceof PathfinderMob && ( (PathfinderMob) entity ).getTarget() != null )
|
||||
+ if ( entity instanceof Mob && ((Mob) entity ).getTarget() != null) // Paper
|
||||
{
|
||||
- return true;
|
||||
+ return 20; // Paper
|
||||
}
|
||||
- if ( entity instanceof Villager && ( (Villager) entity ).canBreed() )
|
||||
+ // Paper start
|
||||
+ if (entity instanceof Bee) {
|
||||
+ Bee bee = (Bee)entity;
|
||||
+ BlockPos movingTarget = bee.getMovingTarget();
|
||||
+ if (bee.isAngry() ||
|
||||
+ (bee.getHivePos() != null && bee.getHivePos().equals(movingTarget)) ||
|
||||
+ (bee.getSavedFlowerPos() != null && bee.getSavedFlowerPos().equals(movingTarget))
|
||||
+ ) {
|
||||
+ return 20;
|
||||
+ }
|
||||
+ }
|
||||
+ if ( entity instanceof Villager ) {
|
||||
+ Brain<Villager> behaviorController = ((Villager) entity).getBrain();
|
||||
+
|
||||
+ if (config.villagersActiveForPanic) {
|
||||
+ for (net.minecraft.world.entity.schedule.Activity activity : VILLAGER_PANIC_IMMUNITIES) {
|
||||
+ if (behaviorController.isActive(activity)) {
|
||||
+ return 20*5;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (config.villagersWorkImmunityAfter > 0 && inactiveFor >= config.villagersWorkImmunityAfter) {
|
||||
+ if (behaviorController.isActive(net.minecraft.world.entity.schedule.Activity.WORK)) {
|
||||
+ return config.villagersWorkImmunityFor;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ if ( entity instanceof Llama && ( (Llama) entity ).inCaravan() )
|
||||
{
|
||||
- return true;
|
||||
+ return 1;
|
||||
}
|
||||
+ // Paper end
|
||||
if ( entity instanceof Animal )
|
||||
{
|
||||
Animal animal = (Animal) entity;
|
||||
if ( animal.isBaby() || animal.isInLove() )
|
||||
{
|
||||
- return true;
|
||||
+ return 5; // Paper
|
||||
}
|
||||
if ( entity instanceof Sheep && ( (Sheep) entity ).isSheared() )
|
||||
{
|
||||
- return true;
|
||||
+ return 1; // Paper
|
||||
}
|
||||
}
|
||||
if (entity instanceof Creeper && ((Creeper) entity).isIgnited()) { // isExplosive
|
||||
- return true;
|
||||
+ return 20; // Paper
|
||||
+ }
|
||||
+ // Paper start
|
||||
+ if (entity instanceof Mob && ((Mob) entity).targetSelector.hasTasks() ) {
|
||||
+ return 0;
|
||||
}
|
||||
+ if (entity instanceof Pillager) {
|
||||
+ Pillager pillager = (Pillager) entity;
|
||||
+ // TODO:?
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
// SPIGOT-6644: Otherwise the target refresh tick will be missed
|
||||
if (entity instanceof ExperienceOrb) {
|
||||
- return true;
|
||||
+ return 20; // Paper
|
||||
}
|
||||
- return false;
|
||||
+ return -1; // Paper
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -0,0 +0,0 @@ public class ActivationRange
|
||||
if (entity instanceof FireworkRocketEntity || (entity instanceof ItemEntity && (entity.tickCount + entity.getId()) % 4 == 0)) { // Paper - Needed for item gravity, see ItemEntity tick
|
||||
return true;
|
||||
}
|
||||
+ // Paper start - special case always immunities
|
||||
+ // immunize brand new entities, dead entities, and portal scenarios
|
||||
+ if (entity.defaultActivationState || entity.tickCount < 20*10 || !entity.isAlive() || (entity.portalProcess != null && !entity.portalProcess.hasExpired()) || entity.portalCooldown > 0) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ // immunize leashed entities
|
||||
+ if (entity instanceof Mob && ((Mob)entity).getLeashHolder() instanceof Player) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ // Paper end
|
||||
|
||||
- boolean isActive = entity.activatedTick >= MinecraftServer.currentTick || entity.defaultActivationState;
|
||||
+ boolean isActive = entity.activatedTick >= MinecraftServer.currentTick;
|
||||
+ entity.isTemporarilyActive = false; // Paper
|
||||
|
||||
// Should this entity tick?
|
||||
if ( !isActive )
|
||||
@@ -0,0 +0,0 @@ public class ActivationRange
|
||||
if ( ( MinecraftServer.currentTick - entity.activatedTick - 1 ) % 20 == 0 )
|
||||
{
|
||||
// Check immunities every 20 ticks.
|
||||
- if ( ActivationRange.checkEntityImmunities( entity ) )
|
||||
- {
|
||||
- // Triggered some sort of immunity, give 20 full ticks before we check again.
|
||||
- entity.activatedTick = MinecraftServer.currentTick + 20;
|
||||
+ // Paper start
|
||||
+ int immunity = checkEntityImmunities(entity);
|
||||
+ if (immunity >= 0) {
|
||||
+ entity.activatedTick = MinecraftServer.currentTick + immunity;
|
||||
+ } else {
|
||||
+ entity.isTemporarilyActive = true;
|
||||
}
|
||||
+ // Paper end
|
||||
isActive = true;
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/org/spigotmc/SpigotWorldConfig.java b/src/main/java/org/spigotmc/SpigotWorldConfig.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/org/spigotmc/SpigotWorldConfig.java
|
||||
+++ b/src/main/java/org/spigotmc/SpigotWorldConfig.java
|
||||
@@ -0,0 +0,0 @@ public class SpigotWorldConfig
|
||||
public int monsterActivationRange = 32;
|
||||
public int raiderActivationRange = 64;
|
||||
public int miscActivationRange = 16;
|
||||
+ // Paper start
|
||||
+ public int flyingMonsterActivationRange = 32;
|
||||
+ public int waterActivationRange = 16;
|
||||
+ public int villagerActivationRange = 32;
|
||||
+ public int wakeUpInactiveAnimals = 4;
|
||||
+ public int wakeUpInactiveAnimalsEvery = 60*20;
|
||||
+ public int wakeUpInactiveAnimalsFor = 5*20;
|
||||
+ public int wakeUpInactiveMonsters = 8;
|
||||
+ public int wakeUpInactiveMonstersEvery = 20*20;
|
||||
+ public int wakeUpInactiveMonstersFor = 5*20;
|
||||
+ public int wakeUpInactiveVillagers = 4;
|
||||
+ public int wakeUpInactiveVillagersEvery = 30*20;
|
||||
+ public int wakeUpInactiveVillagersFor = 5*20;
|
||||
+ public int wakeUpInactiveFlying = 8;
|
||||
+ public int wakeUpInactiveFlyingEvery = 10*20;
|
||||
+ public int wakeUpInactiveFlyingFor = 5*20;
|
||||
+ public int villagersWorkImmunityAfter = 5*20;
|
||||
+ public int villagersWorkImmunityFor = 20;
|
||||
+ public boolean villagersActiveForPanic = true;
|
||||
+ // Paper end
|
||||
public boolean tickInactiveVillagers = true;
|
||||
public boolean ignoreSpectatorActivation = false;
|
||||
private void activationRange()
|
||||
{
|
||||
+ boolean hasAnimalsConfig = config.getInt("entity-activation-range.animals", this.animalActivationRange) != this.animalActivationRange; // Paper
|
||||
this.animalActivationRange = this.getInt( "entity-activation-range.animals", this.animalActivationRange );
|
||||
this.monsterActivationRange = this.getInt( "entity-activation-range.monsters", this.monsterActivationRange );
|
||||
this.raiderActivationRange = this.getInt( "entity-activation-range.raiders", this.raiderActivationRange );
|
||||
this.miscActivationRange = this.getInt( "entity-activation-range.misc", this.miscActivationRange );
|
||||
+ // Paper start
|
||||
+ this.waterActivationRange = this.getInt( "entity-activation-range.water", this.waterActivationRange );
|
||||
+ this.villagerActivationRange = this.getInt( "entity-activation-range.villagers", hasAnimalsConfig ? this.animalActivationRange : this.villagerActivationRange );
|
||||
+ this.flyingMonsterActivationRange = this.getInt( "entity-activation-range.flying-monsters", this.flyingMonsterActivationRange );
|
||||
+
|
||||
+ this.wakeUpInactiveAnimals = this.getInt("entity-activation-range.wake-up-inactive.animals-max-per-tick", this.wakeUpInactiveAnimals);
|
||||
+ this.wakeUpInactiveAnimalsEvery = this.getInt("entity-activation-range.wake-up-inactive.animals-every", this.wakeUpInactiveAnimalsEvery);
|
||||
+ this.wakeUpInactiveAnimalsFor = this.getInt("entity-activation-range.wake-up-inactive.animals-for", this.wakeUpInactiveAnimalsFor);
|
||||
+
|
||||
+ this.wakeUpInactiveMonsters = this.getInt("entity-activation-range.wake-up-inactive.monsters-max-per-tick", this.wakeUpInactiveMonsters);
|
||||
+ this.wakeUpInactiveMonstersEvery = this.getInt("entity-activation-range.wake-up-inactive.monsters-every", this.wakeUpInactiveMonstersEvery);
|
||||
+ this.wakeUpInactiveMonstersFor = this.getInt("entity-activation-range.wake-up-inactive.monsters-for", this.wakeUpInactiveMonstersFor);
|
||||
+
|
||||
+ this.wakeUpInactiveVillagers = this.getInt("entity-activation-range.wake-up-inactive.villagers-max-per-tick", this.wakeUpInactiveVillagers);
|
||||
+ this.wakeUpInactiveVillagersEvery = this.getInt("entity-activation-range.wake-up-inactive.villagers-every", this.wakeUpInactiveVillagersEvery);
|
||||
+ this.wakeUpInactiveVillagersFor = this.getInt("entity-activation-range.wake-up-inactive.villagers-for", this.wakeUpInactiveVillagersFor);
|
||||
+
|
||||
+ this.wakeUpInactiveFlying = this.getInt("entity-activation-range.wake-up-inactive.flying-monsters-max-per-tick", this.wakeUpInactiveFlying);
|
||||
+ this.wakeUpInactiveFlyingEvery = this.getInt("entity-activation-range.wake-up-inactive.flying-monsters-every", this.wakeUpInactiveFlyingEvery);
|
||||
+ this.wakeUpInactiveFlyingFor = this.getInt("entity-activation-range.wake-up-inactive.flying-monsters-for", this.wakeUpInactiveFlyingFor);
|
||||
+
|
||||
+ this.villagersWorkImmunityAfter = this.getInt( "entity-activation-range.villagers-work-immunity-after", this.villagersWorkImmunityAfter );
|
||||
+ this.villagersWorkImmunityFor = this.getInt( "entity-activation-range.villagers-work-immunity-for", this.villagersWorkImmunityFor );
|
||||
+ this.villagersActiveForPanic = this.getBoolean( "entity-activation-range.villagers-active-for-panic", this.villagersActiveForPanic );
|
||||
+ // Paper end
|
||||
this.tickInactiveVillagers = this.getBoolean( "entity-activation-range.tick-inactive-villagers", this.tickInactiveVillagers );
|
||||
this.ignoreSpectatorActivation = this.getBoolean( "entity-activation-range.ignore-spectators", this.ignoreSpectatorActivation );
|
||||
this.log( "Entity Activation Range: An " + this.animalActivationRange + " / Mo " + this.monsterActivationRange + " / Ra " + this.raiderActivationRange + " / Mi " + this.miscActivationRange + " / Tiv " + this.tickInactiveVillagers + " / Isa " + this.ignoreSpectatorActivation );
|
File diff suppressed because it is too large
Load diff
|
@ -1,387 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Andrew Steinborn <git@steinborn.me>
|
||||
Date: Mon, 26 Jul 2021 02:15:17 -0400
|
||||
Subject: [PATCH] Use Velocity compression and cipher natives
|
||||
|
||||
== AT ==
|
||||
private-f net.minecraft.network.CompressionDecoder inflater
|
||||
|
||||
diff --git a/build.gradle.kts b/build.gradle.kts
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/build.gradle.kts
|
||||
+++ b/build.gradle.kts
|
||||
@@ -0,0 +0,0 @@ dependencies {
|
||||
runtimeOnly("org.xerial:sqlite-jdbc:3.47.0.0")
|
||||
runtimeOnly("com.mysql:mysql-connector-j:9.1.0")
|
||||
runtimeOnly("com.lmax:disruptor:3.4.4") // Paper
|
||||
+ // Paper start - Use Velocity cipher
|
||||
+ implementation("com.velocitypowered:velocity-native:3.3.0-SNAPSHOT") {
|
||||
+ isTransitive = false
|
||||
+ }
|
||||
+ // Paper end - Use Velocity cipher
|
||||
|
||||
runtimeOnly("org.apache.maven:maven-resolver-provider:3.9.6")
|
||||
runtimeOnly("org.apache.maven.resolver:maven-resolver-connector-basic:1.9.18")
|
||||
diff --git a/src/main/java/net/minecraft/network/CipherDecoder.java b/src/main/java/net/minecraft/network/CipherDecoder.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/network/CipherDecoder.java
|
||||
+++ b/src/main/java/net/minecraft/network/CipherDecoder.java
|
||||
@@ -0,0 +0,0 @@ import java.util.List;
|
||||
import javax.crypto.Cipher;
|
||||
|
||||
public class CipherDecoder extends MessageToMessageDecoder<ByteBuf> {
|
||||
- private final CipherBase cipher;
|
||||
+ private final com.velocitypowered.natives.encryption.VelocityCipher cipher; // Paper - Use Velocity cipher
|
||||
|
||||
- public CipherDecoder(Cipher cipher) {
|
||||
- this.cipher = new CipherBase(cipher);
|
||||
+ public CipherDecoder(com.velocitypowered.natives.encryption.VelocityCipher cipher) { // Paper - Use Velocity cipher
|
||||
+ this.cipher = cipher; // Paper - Use Velocity cipher
|
||||
}
|
||||
|
||||
protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception {
|
||||
- list.add(this.cipher.decipher(channelHandlerContext, byteBuf));
|
||||
+ // Paper start - Use Velocity cipher
|
||||
+ ByteBuf compatible = com.velocitypowered.natives.util.MoreByteBufUtils.ensureCompatible(channelHandlerContext.alloc(), cipher, byteBuf);
|
||||
+ try {
|
||||
+ cipher.process(compatible);
|
||||
+ list.add(compatible);
|
||||
+ } catch (Exception e) {
|
||||
+ compatible.release(); // compatible will never be used if we throw an exception
|
||||
+ throw e;
|
||||
+ }
|
||||
+ // Paper end - Use Velocity cipher
|
||||
}
|
||||
+
|
||||
+ // Paper start - Use Velocity cipher
|
||||
+ @Override
|
||||
+ public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
|
||||
+ cipher.close();
|
||||
+ }
|
||||
+ // Paper end - Use Velocity cipher
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/network/CipherEncoder.java b/src/main/java/net/minecraft/network/CipherEncoder.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/network/CipherEncoder.java
|
||||
+++ b/src/main/java/net/minecraft/network/CipherEncoder.java
|
||||
@@ -0,0 +0,0 @@ import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.MessageToByteEncoder;
|
||||
import javax.crypto.Cipher;
|
||||
+import java.util.List;
|
||||
|
||||
-public class CipherEncoder extends MessageToByteEncoder<ByteBuf> {
|
||||
- private final CipherBase cipher;
|
||||
+public class CipherEncoder extends io.netty.handler.codec.MessageToMessageEncoder<ByteBuf> { // Paper - Use Velocity cipher; change superclass
|
||||
+ private final com.velocitypowered.natives.encryption.VelocityCipher cipher; // Paper - Use Velocity cipher
|
||||
|
||||
- public CipherEncoder(Cipher cipher) {
|
||||
- this.cipher = new CipherBase(cipher);
|
||||
+ public CipherEncoder(com.velocitypowered.natives.encryption.VelocityCipher cipher) { // Paper - Use Velocity cipher
|
||||
+ this.cipher = cipher; // Paper - Use Velocity cipher
|
||||
}
|
||||
|
||||
- protected void encode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, ByteBuf byteBuf2) throws Exception {
|
||||
- this.cipher.encipher(byteBuf, byteBuf2);
|
||||
+ protected void encode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception {
|
||||
+ // Paper start - Use Velocity cipher
|
||||
+ ByteBuf compatible = com.velocitypowered.natives.util.MoreByteBufUtils.ensureCompatible(channelHandlerContext.alloc(), cipher, byteBuf);
|
||||
+ try {
|
||||
+ cipher.process(compatible);
|
||||
+ list.add(compatible);
|
||||
+ } catch (Exception e) {
|
||||
+ compatible.release(); // compatible will never be used if we throw an exception
|
||||
+ throw e;
|
||||
+ }
|
||||
+ // Paper end - Use Velocity cipher
|
||||
}
|
||||
+
|
||||
+ // Paper start - Use Velocity cipher
|
||||
+ @Override
|
||||
+ public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
|
||||
+ cipher.close();
|
||||
+ }
|
||||
+ // Paper end - Use Velocity cipher
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/network/CompressionDecoder.java b/src/main/java/net/minecraft/network/CompressionDecoder.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/network/CompressionDecoder.java
|
||||
+++ b/src/main/java/net/minecraft/network/CompressionDecoder.java
|
||||
@@ -0,0 +0,0 @@ public class CompressionDecoder extends ByteToMessageDecoder {
|
||||
public static final int MAXIMUM_COMPRESSED_LENGTH = 2097152;
|
||||
public static final int MAXIMUM_UNCOMPRESSED_LENGTH = 8388608;
|
||||
private Inflater inflater;
|
||||
+ private com.velocitypowered.natives.compression.VelocityCompressor compressor; // Paper - Use Velocity cipher
|
||||
private int threshold;
|
||||
private boolean validateDecompressed;
|
||||
|
||||
+ // Paper start - Use Velocity cipher
|
||||
+ @io.papermc.paper.annotation.DoNotUse
|
||||
public CompressionDecoder(int compressionThreshold, boolean rejectsBadPackets) {
|
||||
+ this(null, compressionThreshold, rejectsBadPackets);
|
||||
+ }
|
||||
+ public CompressionDecoder(com.velocitypowered.natives.compression.VelocityCompressor compressor, int compressionThreshold, boolean rejectsBadPackets) {
|
||||
this.threshold = compressionThreshold;
|
||||
this.validateDecompressed = rejectsBadPackets;
|
||||
- this.inflater = new Inflater();
|
||||
+ this.inflater = compressor == null ? new Inflater() : null;
|
||||
+ this.compressor = compressor;
|
||||
+ // Paper end - Use Velocity cipher
|
||||
}
|
||||
|
||||
protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception {
|
||||
@@ -0,0 +0,0 @@ public class CompressionDecoder extends ByteToMessageDecoder {
|
||||
}
|
||||
}
|
||||
|
||||
+ if (inflater != null) { // Paper - Use Velocity cipher; fallback to vanilla inflater
|
||||
this.setupInflaterInput(byteBuf);
|
||||
ByteBuf byteBuf2 = this.inflate(channelHandlerContext, i);
|
||||
this.inflater.reset();
|
||||
list.add(byteBuf2);
|
||||
+ return; // Paper - Use Velocity cipher
|
||||
+ } // Paper - use velocity compression
|
||||
+
|
||||
+ // Paper start - Use Velocity cipher
|
||||
+ int claimedUncompressedSize = i; // OBFHELPER
|
||||
+ ByteBuf compatibleIn = com.velocitypowered.natives.util.MoreByteBufUtils.ensureCompatible(channelHandlerContext.alloc(), this.compressor, byteBuf);
|
||||
+ ByteBuf uncompressed = com.velocitypowered.natives.util.MoreByteBufUtils.preferredBuffer(channelHandlerContext.alloc(), this.compressor, claimedUncompressedSize);
|
||||
+ try {
|
||||
+ this.compressor.inflate(compatibleIn, uncompressed, claimedUncompressedSize);
|
||||
+ list.add(uncompressed);
|
||||
+ byteBuf.clear();
|
||||
+ } catch (Exception e) {
|
||||
+ uncompressed.release();
|
||||
+ throw e;
|
||||
+ } finally {
|
||||
+ compatibleIn.release();
|
||||
+ }
|
||||
+ // Paper end - Use Velocity cipher
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+ // Paper start - Use Velocity cipher
|
||||
+ @Override
|
||||
+ public void handlerRemoved0(ChannelHandlerContext ctx) throws Exception {
|
||||
+ if (this.compressor != null) {
|
||||
+ this.compressor.close();
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - Use Velocity cipher
|
||||
+
|
||||
private void setupInflaterInput(ByteBuf buf) {
|
||||
ByteBuffer byteBuffer;
|
||||
if (buf.nioBufferCount() > 0) {
|
||||
@@ -0,0 +0,0 @@ public class CompressionDecoder extends ByteToMessageDecoder {
|
||||
}
|
||||
}
|
||||
|
||||
- public void setThreshold(int compressionThreshold, boolean rejectsBadPackets) {
|
||||
+ // Paper start - Use Velocity cipher
|
||||
+ public void setThreshold(com.velocitypowered.natives.compression.VelocityCompressor compressor, int compressionThreshold, boolean rejectsBadPackets) {
|
||||
+ if (this.compressor == null && compressor != null) { // Only re-configure once. Re-reconfiguring would require closing the native compressor.
|
||||
+ this.compressor = compressor;
|
||||
+ this.inflater = null;
|
||||
+ }
|
||||
+ // Paper end - Use Velocity cipher
|
||||
this.threshold = compressionThreshold;
|
||||
this.validateDecompressed = rejectsBadPackets;
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/network/CompressionEncoder.java b/src/main/java/net/minecraft/network/CompressionEncoder.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/network/CompressionEncoder.java
|
||||
+++ b/src/main/java/net/minecraft/network/CompressionEncoder.java
|
||||
@@ -0,0 +0,0 @@ import io.netty.handler.codec.MessageToByteEncoder;
|
||||
import java.util.zip.Deflater;
|
||||
|
||||
public class CompressionEncoder extends MessageToByteEncoder<ByteBuf> {
|
||||
- private final byte[] encodeBuf = new byte[8192];
|
||||
+ @javax.annotation.Nullable private final byte[] encodeBuf; // Paper - Use Velocity cipher
|
||||
+ @javax.annotation.Nullable // Paper - Use Velocity cipher
|
||||
private final Deflater deflater;
|
||||
+ @javax.annotation.Nullable // Paper - Use Velocity cipher
|
||||
+ private final com.velocitypowered.natives.compression.VelocityCompressor compressor; // Paper - Use Velocity cipher
|
||||
private int threshold;
|
||||
|
||||
+ // Paper start - Use Velocity cipher
|
||||
public CompressionEncoder(int compressionThreshold) {
|
||||
+ this(null, compressionThreshold);
|
||||
+ }
|
||||
+ public CompressionEncoder(@javax.annotation.Nullable com.velocitypowered.natives.compression.VelocityCompressor compressor, int compressionThreshold) {
|
||||
this.threshold = compressionThreshold;
|
||||
- this.deflater = new Deflater();
|
||||
+ if (compressor == null) {
|
||||
+ this.encodeBuf = new byte[8192];
|
||||
+ this.deflater = new Deflater();
|
||||
+ } else {
|
||||
+ this.encodeBuf = null;
|
||||
+ this.deflater = null;
|
||||
+ }
|
||||
+ this.compressor = compressor;
|
||||
+ // Paper end - Use Velocity cipher
|
||||
}
|
||||
|
||||
- protected void encode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, ByteBuf byteBuf2) {
|
||||
+ protected void encode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, ByteBuf byteBuf2) throws Exception { // Paper - Use Velocity cipher
|
||||
int i = byteBuf.readableBytes();
|
||||
if (i > 8388608) {
|
||||
throw new IllegalArgumentException("Packet too big (is " + i + ", should be less than 8388608)");
|
||||
@@ -0,0 +0,0 @@ public class CompressionEncoder extends MessageToByteEncoder<ByteBuf> {
|
||||
VarInt.write(byteBuf2, 0);
|
||||
byteBuf2.writeBytes(byteBuf);
|
||||
} else {
|
||||
+ if (this.deflater != null) { // Paper - Use Velocity cipher
|
||||
byte[] bs = new byte[i];
|
||||
byteBuf.readBytes(bs);
|
||||
VarInt.write(byteBuf2, bs.length);
|
||||
@@ -0,0 +0,0 @@ public class CompressionEncoder extends MessageToByteEncoder<ByteBuf> {
|
||||
}
|
||||
|
||||
this.deflater.reset();
|
||||
+ // Paper start - Use Velocity cipher
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ VarInt.write(byteBuf2, i);
|
||||
+ final ByteBuf compatibleIn = com.velocitypowered.natives.util.MoreByteBufUtils.ensureCompatible(channelHandlerContext.alloc(), this.compressor, byteBuf);
|
||||
+ try {
|
||||
+ this.compressor.deflate(compatibleIn, byteBuf2);
|
||||
+ } finally {
|
||||
+ compatibleIn.release();
|
||||
+ }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+ @Override
|
||||
+ protected ByteBuf allocateBuffer(ChannelHandlerContext ctx, ByteBuf msg, boolean preferDirect) throws Exception{
|
||||
+ if (this.compressor != null) {
|
||||
+ // We allocate bytes to be compressed plus 1 byte. This covers two cases:
|
||||
+ //
|
||||
+ // - Compression
|
||||
+ // According to https://github.com/ebiggers/libdeflate/blob/master/libdeflate.h#L103,
|
||||
+ // if the data compresses well (and we do not have some pathological case) then the maximum
|
||||
+ // size the compressed size will ever be is the input size minus one.
|
||||
+ // - Uncompressed
|
||||
+ // This is fairly obvious - we will then have one more than the uncompressed size.
|
||||
+ final int initialBufferSize = msg.readableBytes() + 1;
|
||||
+ return com.velocitypowered.natives.util.MoreByteBufUtils.preferredBuffer(ctx.alloc(), this.compressor, initialBufferSize);
|
||||
+ }
|
||||
+
|
||||
+ return super.allocateBuffer(ctx, msg, preferDirect);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
|
||||
+ if (this.compressor != null) {
|
||||
+ this.compressor.close();
|
||||
+ // Paper end - Use Velocity cipher
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
public int getThreshold() {
|
||||
return this.threshold;
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/network/Connection.java
|
||||
+++ b/src/main/java/net/minecraft/network/Connection.java
|
||||
@@ -0,0 +0,0 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
return networkmanager;
|
||||
}
|
||||
|
||||
- public void setEncryptionKey(Cipher decryptionCipher, Cipher encryptionCipher) {
|
||||
- this.encrypted = true;
|
||||
- this.channel.pipeline().addBefore("splitter", "decrypt", new CipherDecoder(decryptionCipher));
|
||||
- this.channel.pipeline().addBefore("prepender", "encrypt", new CipherEncoder(encryptionCipher));
|
||||
+ // Paper start - Use Velocity cipher
|
||||
+// public void setEncryptionKey(Cipher decryptionCipher, Cipher encryptionCipher) {
|
||||
+// this.encrypted = true;
|
||||
+// this.channel.pipeline().addBefore("splitter", "decrypt", new CipherDecoder(decryptionCipher));
|
||||
+// this.channel.pipeline().addBefore("prepender", "encrypt", new CipherEncoder(encryptionCipher));
|
||||
+// }
|
||||
+
|
||||
+ public void setupEncryption(javax.crypto.SecretKey key) throws net.minecraft.util.CryptException {
|
||||
+ if (!this.encrypted) {
|
||||
+ try {
|
||||
+ com.velocitypowered.natives.encryption.VelocityCipher decryption = com.velocitypowered.natives.util.Natives.cipher.get().forDecryption(key);
|
||||
+ com.velocitypowered.natives.encryption.VelocityCipher encryption = com.velocitypowered.natives.util.Natives.cipher.get().forEncryption(key);
|
||||
+
|
||||
+ this.encrypted = true;
|
||||
+ this.channel.pipeline().addBefore("splitter", "decrypt", new CipherDecoder(decryption));
|
||||
+ this.channel.pipeline().addBefore("prepender", "encrypt", new CipherEncoder(encryption));
|
||||
+ } catch (java.security.GeneralSecurityException e) {
|
||||
+ throw new net.minecraft.util.CryptException(e);
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
+ // Paper end - Use Velocity cipher
|
||||
|
||||
public boolean isEncrypted() {
|
||||
return this.encrypted;
|
||||
@@ -0,0 +0,0 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
|
||||
public void setupCompression(int compressionThreshold, boolean rejectsBadPackets) {
|
||||
if (compressionThreshold >= 0) {
|
||||
+ com.velocitypowered.natives.compression.VelocityCompressor compressor = com.velocitypowered.natives.util.Natives.compress.get().create(io.papermc.paper.configuration.GlobalConfiguration.get().misc.compressionLevel.or(-1)); // Paper - Use Velocity cipher
|
||||
ChannelHandler channelhandler = this.channel.pipeline().get("decompress");
|
||||
|
||||
if (channelhandler instanceof CompressionDecoder) {
|
||||
CompressionDecoder packetdecompressor = (CompressionDecoder) channelhandler;
|
||||
|
||||
- packetdecompressor.setThreshold(compressionThreshold, rejectsBadPackets);
|
||||
+ packetdecompressor.setThreshold(compressor, compressionThreshold, rejectsBadPackets); // Paper - Use Velocity cipher
|
||||
} else {
|
||||
- this.channel.pipeline().addAfter("splitter", "decompress", new CompressionDecoder(compressionThreshold, rejectsBadPackets));
|
||||
+ this.channel.pipeline().addAfter("splitter", "decompress", new CompressionDecoder(compressor, compressionThreshold, rejectsBadPackets)); // Paper - Use Velocity cipher
|
||||
}
|
||||
|
||||
channelhandler = this.channel.pipeline().get("compress");
|
||||
@@ -0,0 +0,0 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
|
||||
packetcompressor.setThreshold(compressionThreshold);
|
||||
} else {
|
||||
- this.channel.pipeline().addAfter("prepender", "compress", new CompressionEncoder(compressionThreshold));
|
||||
+ this.channel.pipeline().addAfter("prepender", "compress", new CompressionEncoder(compressor, compressionThreshold)); // Paper - Use Velocity cipher
|
||||
}
|
||||
this.channel.pipeline().fireUserEventTriggered(io.papermc.paper.network.ConnectionEvent.COMPRESSION_THRESHOLD_SET); // Paper - Add Channel initialization listeners
|
||||
} else {
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java
|
||||
@@ -0,0 +0,0 @@ public class ServerConnectionListener {
|
||||
}
|
||||
// Paper end - Warn people with console access that HAProxy is in use.
|
||||
|
||||
+ // Paper start - Use Velocity cipher
|
||||
+ ServerConnectionListener.LOGGER.info("Paper: Using " + com.velocitypowered.natives.util.Natives.compress.getLoadedVariant() + " compression from Velocity.");
|
||||
+ ServerConnectionListener.LOGGER.info("Paper: Using " + com.velocitypowered.natives.util.Natives.cipher.getLoadedVariant() + " cipher from Velocity.");
|
||||
+ // Paper end - Use Velocity cipher
|
||||
+
|
||||
this.channels.add(((ServerBootstrap) ((ServerBootstrap) (new ServerBootstrap()).channel(oclass)).childHandler(new ChannelInitializer<Channel>() {
|
||||
protected void initChannel(Channel channel) {
|
||||
try {
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
@@ -0,0 +0,0 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
|
||||
}
|
||||
|
||||
SecretKey secretkey = packet.getSecretKey(privatekey);
|
||||
- Cipher cipher = Crypt.getCipher(2, secretkey);
|
||||
- Cipher cipher1 = Crypt.getCipher(1, secretkey);
|
||||
+ // Paper start - Use Velocity cipher
|
||||
+// Cipher cipher = Crypt.getCipher(2, secretkey);
|
||||
+// Cipher cipher1 = Crypt.getCipher(1, secretkey);
|
||||
+ // Paper end - Use Velocity cipher
|
||||
|
||||
s = (new BigInteger(Crypt.digestData("", this.server.getKeyPair().getPublic(), secretkey))).toString(16);
|
||||
this.state = ServerLoginPacketListenerImpl.State.AUTHENTICATING;
|
||||
- this.connection.setEncryptionKey(cipher, cipher1);
|
||||
+ this.connection.setupEncryption(secretkey); // Paper - Use Velocity cipher
|
||||
} catch (CryptException cryptographyexception) {
|
||||
throw new IllegalStateException("Protocol error", cryptographyexception);
|
||||
}
|
|
@ -1,171 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Mon, 6 Apr 2020 17:53:29 -0700
|
||||
Subject: [PATCH] Optimize GoalSelector Goal.Flag Set operations
|
||||
|
||||
Optimise the stream.anyMatch statement to move to a bitset
|
||||
where we can replace the call with a single bitwise operation.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/Goal.java b/src/main/java/net/minecraft/world/entity/ai/goal/Goal.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/ai/goal/Goal.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/ai/goal/Goal.java
|
||||
@@ -0,0 +0,0 @@ import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.level.Level;
|
||||
|
||||
public abstract class Goal {
|
||||
- private final EnumSet<Goal.Flag> flags = EnumSet.noneOf(Goal.Flag.class);
|
||||
+ private final EnumSet<Goal.Flag> flags = EnumSet.noneOf(Goal.Flag.class); // Paper unused, but dummy to prevent plugins from crashing as hard. Theyll need to support paper in a special case if this is super important, but really doesn't seem like it would be.
|
||||
+ private final ca.spottedleaf.moonrise.common.set.OptimizedSmallEnumSet<net.minecraft.world.entity.ai.goal.Goal.Flag> goalTypes = new ca.spottedleaf.moonrise.common.set.OptimizedSmallEnumSet<>(Goal.Flag.class); // Paper - remove streams from pathfindergoalselector
|
||||
+
|
||||
+ // Paper start - remove streams from pathfindergoalselector; make sure types are not empty
|
||||
+ public Goal() {
|
||||
+ if (this.goalTypes.size() == 0) {
|
||||
+ this.goalTypes.addUnchecked(Flag.UNKNOWN_BEHAVIOR);
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - remove streams from pathfindergoalselector
|
||||
|
||||
public abstract boolean canUse();
|
||||
|
||||
@@ -0,0 +0,0 @@ public abstract class Goal {
|
||||
}
|
||||
|
||||
public void setFlags(EnumSet<Goal.Flag> controls) {
|
||||
- this.flags.clear();
|
||||
- this.flags.addAll(controls);
|
||||
+ // Paper start - remove streams from pathfindergoalselector
|
||||
+ this.goalTypes.clear();
|
||||
+ this.goalTypes.addAllUnchecked(controls);
|
||||
+ if (this.goalTypes.size() == 0) {
|
||||
+ this.goalTypes.addUnchecked(Flag.UNKNOWN_BEHAVIOR);
|
||||
+ }
|
||||
+ // Paper end - remove streams from pathfindergoalselector
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -0,0 +0,0 @@ public abstract class Goal {
|
||||
return this.getClass().getSimpleName();
|
||||
}
|
||||
|
||||
- public EnumSet<Goal.Flag> getFlags() {
|
||||
- return this.flags;
|
||||
+ // Paper start - remove streams from pathfindergoalselector
|
||||
+ public ca.spottedleaf.moonrise.common.set.OptimizedSmallEnumSet<Goal.Flag> getFlags() {
|
||||
+ return this.goalTypes;
|
||||
+ // Paper end - remove streams from pathfindergoalselector
|
||||
}
|
||||
|
||||
// Paper start - Mob Goal API
|
||||
public boolean hasFlag(final Goal.Flag flag) {
|
||||
- return this.flags.contains(flag);
|
||||
+ return this.goalTypes.hasElement(flag);
|
||||
}
|
||||
|
||||
public void addFlag(final Goal.Flag flag) {
|
||||
- this.flags.add(flag);
|
||||
+ this.goalTypes.addUnchecked(flag);
|
||||
}
|
||||
// Paper end - Mob Goal API
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java b/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java
|
||||
@@ -0,0 +0,0 @@ public class GoalSelector {
|
||||
};
|
||||
private final Map<Goal.Flag, WrappedGoal> lockedFlags = new EnumMap<>(Goal.Flag.class);
|
||||
private final Set<WrappedGoal> availableGoals = new ObjectLinkedOpenHashSet<>();
|
||||
- private final EnumSet<Goal.Flag> disabledFlags = EnumSet.noneOf(Goal.Flag.class);
|
||||
+ private static final Goal.Flag[] GOAL_FLAG_VALUES = Goal.Flag.values(); // Paper - remove streams from pathfindergoalselector
|
||||
+ private final ca.spottedleaf.moonrise.common.set.OptimizedSmallEnumSet<net.minecraft.world.entity.ai.goal.Goal.Flag> goalTypes = new ca.spottedleaf.moonrise.common.set.OptimizedSmallEnumSet<>(Goal.Flag.class); // Paper - remove streams from pathfindergoalselector
|
||||
private int curRate; // Paper - EAR 2
|
||||
|
||||
public void addGoal(int priority, Goal goal) {
|
||||
@@ -0,0 +0,0 @@ public class GoalSelector {
|
||||
this.availableGoals.removeIf(wrappedGoalx -> wrappedGoalx.getGoal() == goal);
|
||||
}
|
||||
|
||||
- private static boolean goalContainsAnyFlags(WrappedGoal goal, EnumSet<Goal.Flag> controls) {
|
||||
- for (Goal.Flag flag : goal.getFlags()) {
|
||||
- if (controls.contains(flag)) {
|
||||
- return true;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- return false;
|
||||
+ // Paper start
|
||||
+ private static boolean goalContainsAnyFlags(WrappedGoal goal, ca.spottedleaf.moonrise.common.set.OptimizedSmallEnumSet<Goal.Flag> controls) {
|
||||
+ return goal.getFlags().hasCommonElements(controls);
|
||||
}
|
||||
|
||||
private static boolean goalCanBeReplacedForAllFlags(WrappedGoal goal, Map<Goal.Flag, WrappedGoal> goalsByControl) {
|
||||
- for (Goal.Flag flag : goal.getFlags()) {
|
||||
+ long flagIterator = goal.getFlags().getBackingSet();
|
||||
+ int wrappedGoalSize = goal.getFlags().size();
|
||||
+ for (int i = 0; i < wrappedGoalSize; ++i) {
|
||||
+ final Goal.Flag flag = GOAL_FLAG_VALUES[Long.numberOfTrailingZeros(flagIterator)];
|
||||
+ flagIterator ^= ca.spottedleaf.concurrentutil.util.IntegerUtil.getTrailingBit(flagIterator);
|
||||
+ // Paper end
|
||||
if (!goalsByControl.getOrDefault(flag, NO_GOAL).canBeReplacedBy(goal)) {
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +0,0 @@ public class GoalSelector {
|
||||
profilerFiller.push("goalCleanup");
|
||||
|
||||
for (WrappedGoal wrappedGoal : this.availableGoals) {
|
||||
- if (wrappedGoal.isRunning() && (goalContainsAnyFlags(wrappedGoal, this.disabledFlags) || !wrappedGoal.canContinueToUse())) {
|
||||
+ if (wrappedGoal.isRunning() && (goalContainsAnyFlags(wrappedGoal, this.goalTypes) || !wrappedGoal.canContinueToUse())) { // Paper - Perf: optimize goal types by removing streams
|
||||
wrappedGoal.stop();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +0,0 @@ public class GoalSelector {
|
||||
profilerFiller.push("goalUpdate");
|
||||
|
||||
for (WrappedGoal wrappedGoal2 : this.availableGoals) {
|
||||
- if (!wrappedGoal2.isRunning()
|
||||
- && !goalContainsAnyFlags(wrappedGoal2, this.disabledFlags)
|
||||
- && goalCanBeReplacedForAllFlags(wrappedGoal2, this.lockedFlags)
|
||||
- && wrappedGoal2.canUse()) {
|
||||
- for (Goal.Flag flag : wrappedGoal2.getFlags()) {
|
||||
+ // Paper start
|
||||
+ if (!wrappedGoal2.isRunning() && !goalContainsAnyFlags(wrappedGoal2, this.goalTypes) && goalCanBeReplacedForAllFlags(wrappedGoal2, this.lockedFlags) && wrappedGoal2.canUse()) {
|
||||
+ long flagIterator = wrappedGoal2.getFlags().getBackingSet();
|
||||
+ int wrappedGoalSize = wrappedGoal2.getFlags().size();
|
||||
+ for (int i = 0; i < wrappedGoalSize; ++i) {
|
||||
+ final Goal.Flag flag = GOAL_FLAG_VALUES[Long.numberOfTrailingZeros(flagIterator)];
|
||||
+ flagIterator ^= ca.spottedleaf.concurrentutil.util.IntegerUtil.getTrailingBit(flagIterator);
|
||||
+ // Paper end
|
||||
WrappedGoal wrappedGoal3 = this.lockedFlags.getOrDefault(flag, NO_GOAL);
|
||||
wrappedGoal3.stop();
|
||||
this.lockedFlags.put(flag, wrappedGoal2);
|
||||
@@ -0,0 +0,0 @@ public class GoalSelector {
|
||||
}
|
||||
|
||||
public void disableControlFlag(Goal.Flag control) {
|
||||
- this.disabledFlags.add(control);
|
||||
+ this.goalTypes.addUnchecked(control); // Paper - remove streams from pathfindergoalselector
|
||||
}
|
||||
|
||||
public void enableControlFlag(Goal.Flag control) {
|
||||
- this.disabledFlags.remove(control);
|
||||
+ this.goalTypes.removeUnchecked(control); // Paper - remove streams from pathfindergoalselector
|
||||
}
|
||||
|
||||
public void setControlFlag(Goal.Flag control, boolean enabled) {
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/WrappedGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/WrappedGoal.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/ai/goal/WrappedGoal.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/ai/goal/WrappedGoal.java
|
||||
@@ -0,0 +0,0 @@ public class WrappedGoal extends Goal {
|
||||
}
|
||||
|
||||
@Override
|
||||
- public EnumSet<Goal.Flag> getFlags() {
|
||||
+ // Paper start - remove streams from pathfindergoalselector
|
||||
+ public ca.spottedleaf.moonrise.common.set.OptimizedSmallEnumSet<Goal.Flag> getFlags() {
|
||||
return this.goal.getFlags();
|
||||
+ // Paper end - remove streams from pathfindergoalselector
|
||||
}
|
||||
|
||||
public boolean isRunning() {
|
|
@ -1,664 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Wed, 27 Apr 2016 22:09:52 -0400
|
||||
Subject: [PATCH] Optimize Hoppers
|
||||
|
||||
* Removes unnecessary extra calls to .update() that are very expensive
|
||||
* Lots of itemstack cloning removed. Only clone if the item is actually moved
|
||||
* Return true when a plugin cancels inventory move item event instead of false, as false causes pulls to cycle through all items.
|
||||
However, pushes do not exhibit the same behavior, so this is not something plugins could of been relying on.
|
||||
* Add option (Default on) to cooldown hoppers when they fail to move an item due to full inventory
|
||||
* Skip subsequent InventoryMoveItemEvents if a plugin does not use the item after first event fire for an iteration by tracking changes to the event via an internal event implementation.
|
||||
* Don't check for Entities with Inventories if the block above us is also occluding (not just Inventoried)
|
||||
* Remove Streams from Item Suck In and restore restore 1.12 AABB checks which is simpler and no voxel allocations (was doing TWO Item Suck ins)
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/event/inventory/PaperInventoryMoveItemEvent.java b/src/main/java/io/papermc/paper/event/inventory/PaperInventoryMoveItemEvent.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/event/inventory/PaperInventoryMoveItemEvent.java
|
||||
@@ -0,0 +0,0 @@
|
||||
+package io.papermc.paper.event.inventory;
|
||||
+
|
||||
+import org.bukkit.event.inventory.InventoryMoveItemEvent;
|
||||
+import org.bukkit.inventory.Inventory;
|
||||
+import org.bukkit.inventory.ItemStack;
|
||||
+import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
+import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
+import org.jetbrains.annotations.NotNull;
|
||||
+
|
||||
+@DefaultQualifier(NonNull.class)
|
||||
+public class PaperInventoryMoveItemEvent extends InventoryMoveItemEvent {
|
||||
+
|
||||
+ public boolean calledSetItem;
|
||||
+ public boolean calledGetItem;
|
||||
+
|
||||
+ public PaperInventoryMoveItemEvent(final @NotNull Inventory sourceInventory, final @NotNull ItemStack itemStack, final @NotNull Inventory destinationInventory, final boolean didSourceInitiate) {
|
||||
+ super(sourceInventory, itemStack, destinationInventory, didSourceInitiate);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public ItemStack getItem() {
|
||||
+ this.calledGetItem = true;
|
||||
+ return super.getItem();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setItem(final ItemStack itemStack) {
|
||||
+ super.setItem(itemStack);
|
||||
+ this.calledSetItem = true;
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
ServerLevel worldserver = (ServerLevel) iterator.next();
|
||||
worldserver.hasPhysicsEvent = org.bukkit.event.block.BlockPhysicsEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - BlockPhysicsEvent
|
||||
worldserver.hasEntityMoveEvent = io.papermc.paper.event.entity.EntityMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - Add EntityMoveEvent
|
||||
+ net.minecraft.world.level.block.entity.HopperBlockEntity.skipHopperEvents = worldserver.paperConfig().hopper.disableMoveEvent || org.bukkit.event.inventory.InventoryMoveItemEvent.getHandlerList().getRegisteredListeners().length == 0; // Paper - Perf: Optimize Hoppers
|
||||
|
||||
gameprofilerfiller.push(() -> {
|
||||
String s = String.valueOf(worldserver);
|
||||
diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/item/ItemStack.java
|
||||
+++ b/src/main/java/net/minecraft/world/item/ItemStack.java
|
||||
@@ -0,0 +0,0 @@ public final class ItemStack implements DataComponentHolder {
|
||||
}
|
||||
|
||||
public ItemStack copy() {
|
||||
- if (this.isEmpty()) {
|
||||
+ // Paper start - Perf: Optimize Hoppers
|
||||
+ return this.copy(false);
|
||||
+ }
|
||||
+
|
||||
+ public ItemStack copy(boolean originalItem) {
|
||||
+ if (!originalItem && this.isEmpty()) {
|
||||
+ // Paper end - Perf: Optimize Hoppers
|
||||
return ItemStack.EMPTY;
|
||||
} else {
|
||||
- ItemStack itemstack = new ItemStack(this.getItem(), this.count, this.components.copy());
|
||||
+ ItemStack itemstack = new ItemStack(originalItem ? this.item : this.getItem(), this.count, this.components.copy()); // Paper - Perf: Optimize Hoppers
|
||||
|
||||
itemstack.setPopTime(this.getPopTime());
|
||||
return itemstack;
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java
|
||||
@@ -0,0 +0,0 @@ import org.bukkit.inventory.InventoryHolder;
|
||||
// CraftBukkit end
|
||||
|
||||
public abstract class BlockEntity {
|
||||
+ static boolean ignoreTileUpdates; // Paper - Perf: Optimize Hoppers
|
||||
|
||||
// CraftBukkit start - data containers
|
||||
private static final CraftPersistentDataTypeRegistry DATA_TYPE_REGISTRY = new CraftPersistentDataTypeRegistry();
|
||||
@@ -0,0 +0,0 @@ public abstract class BlockEntity {
|
||||
|
||||
public void setChanged() {
|
||||
if (this.level != null) {
|
||||
+ if (ignoreTileUpdates) return; // Paper - Perf: Optimize Hoppers
|
||||
BlockEntity.setChanged(this.level, this.worldPosition, this.blockState);
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java
|
||||
@@ -0,0 +0,0 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
||||
|
||||
}
|
||||
|
||||
+ // Paper start - Perf: Optimize Hoppers
|
||||
+ private static final int HOPPER_EMPTY = 0;
|
||||
+ private static final int HOPPER_HAS_ITEMS = 1;
|
||||
+ private static final int HOPPER_IS_FULL = 2;
|
||||
+
|
||||
+ private static int getFullState(final HopperBlockEntity tileEntity) {
|
||||
+ tileEntity.unpackLootTable(null);
|
||||
+
|
||||
+ final List<ItemStack> hopperItems = tileEntity.getItems();
|
||||
+
|
||||
+ boolean empty = true;
|
||||
+ boolean full = true;
|
||||
+
|
||||
+ for (int i = 0, len = hopperItems.size(); i < len; ++i) {
|
||||
+ final ItemStack stack = hopperItems.get(i);
|
||||
+ if (stack.isEmpty()) {
|
||||
+ full = false;
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (!full) {
|
||||
+ // can't be full
|
||||
+ return HOPPER_HAS_ITEMS;
|
||||
+ }
|
||||
+
|
||||
+ empty = false;
|
||||
+
|
||||
+ if (stack.getCount() != stack.getMaxStackSize()) {
|
||||
+ // can't be full or empty
|
||||
+ return HOPPER_HAS_ITEMS;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return empty ? HOPPER_EMPTY : (full ? HOPPER_IS_FULL : HOPPER_HAS_ITEMS);
|
||||
+ }
|
||||
+ // Paper end - Perf: Optimize Hoppers
|
||||
+
|
||||
private static boolean tryMoveItems(Level world, BlockPos pos, BlockState state, HopperBlockEntity blockEntity, BooleanSupplier booleansupplier) {
|
||||
if (world.isClientSide) {
|
||||
return false;
|
||||
@@ -0,0 +0,0 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
||||
if (!blockEntity.isOnCooldown() && (Boolean) state.getValue(HopperBlock.ENABLED)) {
|
||||
boolean flag = false;
|
||||
|
||||
- if (!blockEntity.isEmpty()) {
|
||||
+ final int fullState = getFullState(blockEntity); // Paper - Perf: Optimize Hoppers
|
||||
+ if (fullState != HOPPER_EMPTY) { // Paper - Perf: Optimize Hoppers
|
||||
flag = HopperBlockEntity.ejectItems(world, pos, blockEntity);
|
||||
}
|
||||
|
||||
- if (!blockEntity.inventoryFull()) {
|
||||
+ if (fullState != HOPPER_IS_FULL || flag) { // Paper - Perf: Optimize Hoppers
|
||||
flag |= booleansupplier.getAsBoolean();
|
||||
}
|
||||
|
||||
@@ -0,0 +0,0 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
||||
return false;
|
||||
}
|
||||
|
||||
+ // Paper start - Perf: Optimize Hoppers
|
||||
+ private static boolean skipPullModeEventFire;
|
||||
+ private static boolean skipPushModeEventFire;
|
||||
+ public static boolean skipHopperEvents;
|
||||
+
|
||||
+ private static boolean hopperPush(final Level level, final Container destination, final Direction direction, final HopperBlockEntity hopper) {
|
||||
+ skipPushModeEventFire = skipHopperEvents;
|
||||
+ boolean foundItem = false;
|
||||
+ for (int i = 0; i < hopper.getContainerSize(); ++i) {
|
||||
+ final ItemStack item = hopper.getItem(i);
|
||||
+ if (!item.isEmpty()) {
|
||||
+ foundItem = true;
|
||||
+ ItemStack origItemStack = item;
|
||||
+ ItemStack movedItem = origItemStack;
|
||||
+
|
||||
+ final int originalItemCount = origItemStack.getCount();
|
||||
+ final int movedItemCount = Math.min(level.spigotConfig.hopperAmount, originalItemCount);
|
||||
+ origItemStack.setCount(movedItemCount);
|
||||
+
|
||||
+ // We only need to fire the event once to give protection plugins a chance to cancel this event
|
||||
+ // Because nothing uses getItem, every event call should end up the same result.
|
||||
+ if (!skipPushModeEventFire) {
|
||||
+ movedItem = callPushMoveEvent(destination, movedItem, hopper);
|
||||
+ if (movedItem == null) { // cancelled
|
||||
+ origItemStack.setCount(originalItemCount);
|
||||
+ return false;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ final ItemStack remainingItem = addItem(hopper, destination, movedItem, direction);
|
||||
+ final int remainingItemCount = remainingItem.getCount();
|
||||
+ if (remainingItemCount != movedItemCount) {
|
||||
+ origItemStack = origItemStack.copy(true);
|
||||
+ origItemStack.setCount(originalItemCount);
|
||||
+ if (!origItemStack.isEmpty()) {
|
||||
+ origItemStack.setCount(originalItemCount - movedItemCount + remainingItemCount);
|
||||
+ }
|
||||
+ hopper.setItem(i, origItemStack);
|
||||
+ destination.setChanged();
|
||||
+ return true;
|
||||
+ }
|
||||
+ origItemStack.setCount(originalItemCount);
|
||||
+ }
|
||||
+ }
|
||||
+ if (foundItem && level.paperConfig().hopper.cooldownWhenFull) { // Inventory was full - cooldown
|
||||
+ hopper.setCooldown(level.spigotConfig.hopperTransfer);
|
||||
+ }
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ private static boolean hopperPull(final Level level, final Hopper hopper, final Container container, ItemStack origItemStack, final int i) {
|
||||
+ ItemStack movedItem = origItemStack;
|
||||
+ final int originalItemCount = origItemStack.getCount();
|
||||
+ final int movedItemCount = Math.min(level.spigotConfig.hopperAmount, originalItemCount);
|
||||
+ container.setChanged(); // original logic always marks source inv as changed even if no move happens.
|
||||
+ movedItem.setCount(movedItemCount);
|
||||
+
|
||||
+ if (!skipPullModeEventFire) {
|
||||
+ movedItem = callPullMoveEvent(hopper, container, movedItem);
|
||||
+ if (movedItem == null) { // cancelled
|
||||
+ origItemStack.setCount(originalItemCount);
|
||||
+ // Drastically improve performance by returning true.
|
||||
+ // No plugin could of relied on the behavior of false as the other call
|
||||
+ // site for IMIE did not exhibit the same behavior
|
||||
+ return true;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ final ItemStack remainingItem = addItem(container, hopper, movedItem, null);
|
||||
+ final int remainingItemCount = remainingItem.getCount();
|
||||
+ if (remainingItemCount != movedItemCount) {
|
||||
+ origItemStack = origItemStack.copy(true);
|
||||
+ origItemStack.setCount(originalItemCount);
|
||||
+ if (!origItemStack.isEmpty()) {
|
||||
+ origItemStack.setCount(originalItemCount - movedItemCount + remainingItemCount);
|
||||
+ }
|
||||
+
|
||||
+ ignoreTileUpdates = true;
|
||||
+ container.setItem(i, origItemStack);
|
||||
+ ignoreTileUpdates = false;
|
||||
+ container.setChanged();
|
||||
+ return true;
|
||||
+ }
|
||||
+ origItemStack.setCount(originalItemCount);
|
||||
+
|
||||
+ if (level.paperConfig().hopper.cooldownWhenFull) {
|
||||
+ cooldownHopper(hopper);
|
||||
+ }
|
||||
+
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ @Nullable
|
||||
+ private static ItemStack callPushMoveEvent(Container iinventory, ItemStack itemstack, HopperBlockEntity hopper) {
|
||||
+ final Inventory destinationInventory = getInventory(iinventory);
|
||||
+ final io.papermc.paper.event.inventory.PaperInventoryMoveItemEvent event = new io.papermc.paper.event.inventory.PaperInventoryMoveItemEvent(hopper.getOwner(false).getInventory(),
|
||||
+ CraftItemStack.asCraftMirror(itemstack), destinationInventory, true);
|
||||
+ final boolean result = event.callEvent();
|
||||
+ if (!event.calledGetItem && !event.calledSetItem) {
|
||||
+ skipPushModeEventFire = true;
|
||||
+ }
|
||||
+ if (!result) {
|
||||
+ cooldownHopper(hopper);
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ if (event.calledSetItem) {
|
||||
+ return CraftItemStack.asNMSCopy(event.getItem());
|
||||
+ } else {
|
||||
+ return itemstack;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Nullable
|
||||
+ private static ItemStack callPullMoveEvent(final Hopper hopper, final Container container, final ItemStack itemstack) {
|
||||
+ final Inventory sourceInventory = getInventory(container);
|
||||
+ final Inventory destination = getInventory(hopper);
|
||||
+
|
||||
+ // Mirror is safe as no plugins ever use this item
|
||||
+ final io.papermc.paper.event.inventory.PaperInventoryMoveItemEvent event = new io.papermc.paper.event.inventory.PaperInventoryMoveItemEvent(sourceInventory, CraftItemStack.asCraftMirror(itemstack), destination, false);
|
||||
+ final boolean result = event.callEvent();
|
||||
+ if (!event.calledGetItem && !event.calledSetItem) {
|
||||
+ skipPullModeEventFire = true;
|
||||
+ }
|
||||
+ if (!result) {
|
||||
+ cooldownHopper(hopper);
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ if (event.calledSetItem) {
|
||||
+ return CraftItemStack.asNMSCopy(event.getItem());
|
||||
+ } else {
|
||||
+ return itemstack;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private static Inventory getInventory(final Container container) {
|
||||
+ final Inventory sourceInventory;
|
||||
+ if (container instanceof CompoundContainer compoundContainer) {
|
||||
+ // Have to special-case large chests as they work oddly
|
||||
+ sourceInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest(compoundContainer);
|
||||
+ } else if (container instanceof BlockEntity blockEntity) {
|
||||
+ sourceInventory = blockEntity.getOwner(false).getInventory();
|
||||
+ } else if (container.getOwner() != null) {
|
||||
+ sourceInventory = container.getOwner().getInventory();
|
||||
+ } else {
|
||||
+ sourceInventory = new CraftInventory(container);
|
||||
+ }
|
||||
+ return sourceInventory;
|
||||
+ }
|
||||
+
|
||||
+ private static void cooldownHopper(final Hopper hopper) {
|
||||
+ if (hopper instanceof HopperBlockEntity blockEntity && blockEntity.getLevel() != null) {
|
||||
+ blockEntity.setCooldown(blockEntity.getLevel().spigotConfig.hopperTransfer);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private static boolean allMatch(Container iinventory, Direction enumdirection, java.util.function.BiPredicate<ItemStack, Integer> test) {
|
||||
+ if (iinventory instanceof WorldlyContainer) {
|
||||
+ for (int i : ((WorldlyContainer) iinventory).getSlotsForFace(enumdirection)) {
|
||||
+ if (!test.test(iinventory.getItem(i), i)) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ }
|
||||
+ } else {
|
||||
+ int size = iinventory.getContainerSize();
|
||||
+ for (int i = 0; i < size; i++) {
|
||||
+ if (!test.test(iinventory.getItem(i), i)) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ private static boolean anyMatch(Container iinventory, Direction enumdirection, java.util.function.BiPredicate<ItemStack, Integer> test) {
|
||||
+ if (iinventory instanceof WorldlyContainer) {
|
||||
+ for (int i : ((WorldlyContainer) iinventory).getSlotsForFace(enumdirection)) {
|
||||
+ if (test.test(iinventory.getItem(i), i)) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ }
|
||||
+ } else {
|
||||
+ int size = iinventory.getContainerSize();
|
||||
+ for (int i = 0; i < size; i++) {
|
||||
+ if (test.test(iinventory.getItem(i), i)) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ return true;
|
||||
+ }
|
||||
+ private static final java.util.function.BiPredicate<ItemStack, Integer> STACK_SIZE_TEST = (itemstack, i) -> itemstack.getCount() >= itemstack.getMaxStackSize();
|
||||
+ private static final java.util.function.BiPredicate<ItemStack, Integer> IS_EMPTY_TEST = (itemstack, i) -> itemstack.isEmpty();
|
||||
+ // Paper end - Perf: Optimize Hoppers
|
||||
+
|
||||
private static boolean ejectItems(Level world, BlockPos pos, HopperBlockEntity blockEntity) {
|
||||
Container iinventory = HopperBlockEntity.getAttachedContainer(world, pos, blockEntity);
|
||||
|
||||
@@ -0,0 +0,0 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
||||
if (HopperBlockEntity.isFullContainer(iinventory, enumdirection)) {
|
||||
return false;
|
||||
} else {
|
||||
- for (int i = 0; i < blockEntity.getContainerSize(); ++i) {
|
||||
- ItemStack itemstack = blockEntity.getItem(i);
|
||||
-
|
||||
- if (!itemstack.isEmpty()) {
|
||||
- int j = itemstack.getCount();
|
||||
- // CraftBukkit start - Call event when pushing items into other inventories
|
||||
- ItemStack original = itemstack.copy();
|
||||
- CraftItemStack oitemstack = CraftItemStack.asCraftMirror(blockEntity.removeItem(i, world.spigotConfig.hopperAmount)); // Spigot
|
||||
-
|
||||
- Inventory destinationInventory;
|
||||
- // Have to special case large chests as they work oddly
|
||||
- if (iinventory instanceof CompoundContainer) {
|
||||
- destinationInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest((CompoundContainer) iinventory);
|
||||
- } else if (iinventory.getOwner() != null) {
|
||||
- destinationInventory = iinventory.getOwner().getInventory();
|
||||
- } else {
|
||||
- destinationInventory = new CraftInventory(iinventory);
|
||||
- }
|
||||
-
|
||||
- InventoryMoveItemEvent event = new InventoryMoveItemEvent(blockEntity.getOwner().getInventory(), oitemstack, destinationInventory, true);
|
||||
- world.getCraftServer().getPluginManager().callEvent(event);
|
||||
- if (event.isCancelled()) {
|
||||
- blockEntity.setItem(i, original);
|
||||
- blockEntity.setCooldown(world.spigotConfig.hopperTransfer); // Delay hopper checks // Spigot
|
||||
- return false;
|
||||
- }
|
||||
- int origCount = event.getItem().getAmount(); // Spigot
|
||||
- ItemStack itemstack1 = HopperBlockEntity.addItem(blockEntity, iinventory, CraftItemStack.asNMSCopy(event.getItem()), enumdirection);
|
||||
- // CraftBukkit end
|
||||
-
|
||||
- if (itemstack1.isEmpty()) {
|
||||
- iinventory.setChanged();
|
||||
- return true;
|
||||
- }
|
||||
-
|
||||
- itemstack.setCount(j);
|
||||
- // Spigot start
|
||||
- itemstack.shrink(origCount - itemstack1.getCount());
|
||||
- if (j <= world.spigotConfig.hopperAmount) {
|
||||
- // Spigot end
|
||||
- blockEntity.setItem(i, itemstack);
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- return false;
|
||||
+ // Paper start - Perf: Optimize Hoppers
|
||||
+ return hopperPush(world, iinventory, enumdirection, blockEntity);
|
||||
+ //for (int i = 0; i < blockEntity.getContainerSize(); ++i) {
|
||||
+ // ItemStack itemstack = blockEntity.getItem(i);
|
||||
+
|
||||
+ // if (!itemstack.isEmpty()) {
|
||||
+ // int j = itemstack.getCount();
|
||||
+ // // CraftBukkit start - Call event when pushing items into other inventories
|
||||
+ // ItemStack original = itemstack.copy();
|
||||
+ // CraftItemStack oitemstack = CraftItemStack.asCraftMirror(blockEntity.removeItem(i, world.spigotConfig.hopperAmount)); // Spigot
|
||||
+
|
||||
+ // Inventory destinationInventory;
|
||||
+ // // Have to special case large chests as they work oddly
|
||||
+ // if (iinventory instanceof CompoundContainer) {
|
||||
+ // destinationInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest((CompoundContainer) iinventory);
|
||||
+ // } else if (iinventory.getOwner() != null) {
|
||||
+ // destinationInventory = iinventory.getOwner().getInventory();
|
||||
+ // } else {
|
||||
+ // destinationInventory = new CraftInventory(iinventory);
|
||||
+ // }
|
||||
+
|
||||
+ // InventoryMoveItemEvent event = new InventoryMoveItemEvent(tileentityhopper.getOwner().getInventory(), oitemstack, destinationInventory, true);
|
||||
+ // world.getCraftServer().getPluginManager().callEvent(event);
|
||||
+ // if (event.isCancelled()) {
|
||||
+ // blockEntity.setItem(i, original);
|
||||
+ // blockEntity.setCooldown(world.spigotConfig.hopperTransfer); // Delay hopper checks // Spigot
|
||||
+ // return false;
|
||||
+ // }
|
||||
+ // int origCount = event.getItem().getAmount(); // Spigot
|
||||
+ // ItemStack itemstack1 = HopperBlockEntity.addItem(blockEntity, iinventory, CraftItemStack.asNMSCopy(event.getItem()), enumdirection);
|
||||
+ // // CraftBukkit end
|
||||
+
|
||||
+ // if (itemstack1.isEmpty()) {
|
||||
+ // iinventory.setChanged();
|
||||
+ // return true;
|
||||
+ // }
|
||||
+
|
||||
+ // itemstack.setCount(j);
|
||||
+ // // Spigot start
|
||||
+ // itemstack.shrink(origCount - itemstack1.getCount());
|
||||
+ // if (j <= world.spigotConfig.hopperAmount) {
|
||||
+ // // Spigot end
|
||||
+ // blockEntity.setItem(i, itemstack);
|
||||
+ // }
|
||||
+ // }
|
||||
+ //}
|
||||
+
|
||||
+ // return false;
|
||||
+ // Paper end - Perf: Optimize Hoppers
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +0,0 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
||||
return false;
|
||||
}
|
||||
}
|
||||
-
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -0,0 +0,0 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
||||
|
||||
if (iinventory != null) {
|
||||
Direction enumdirection = Direction.DOWN;
|
||||
+ skipPullModeEventFire = skipHopperEvents; // Paper - Perf: Optimize Hoppers
|
||||
int[] aint = HopperBlockEntity.getSlots(iinventory, enumdirection);
|
||||
int i = aint.length;
|
||||
|
||||
@@ -0,0 +0,0 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
||||
ItemStack itemstack = iinventory.getItem(i);
|
||||
|
||||
if (!itemstack.isEmpty() && HopperBlockEntity.canTakeItemFromContainer(ihopper, iinventory, itemstack, i, enumdirection)) {
|
||||
- int j = itemstack.getCount();
|
||||
- // CraftBukkit start - Call event on collection of items from inventories into the hopper
|
||||
- ItemStack original = itemstack.copy();
|
||||
- CraftItemStack oitemstack = CraftItemStack.asCraftMirror(iinventory.removeItem(i, world.spigotConfig.hopperAmount)); // Spigot
|
||||
-
|
||||
- Inventory sourceInventory;
|
||||
- // Have to special case large chests as they work oddly
|
||||
- if (iinventory instanceof CompoundContainer) {
|
||||
- sourceInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest((CompoundContainer) iinventory);
|
||||
- } else if (iinventory.getOwner() != null) {
|
||||
- sourceInventory = iinventory.getOwner().getInventory();
|
||||
- } else {
|
||||
- sourceInventory = new CraftInventory(iinventory);
|
||||
- }
|
||||
-
|
||||
- InventoryMoveItemEvent event = new InventoryMoveItemEvent(sourceInventory, oitemstack, ihopper.getOwner().getInventory(), false);
|
||||
-
|
||||
- Bukkit.getServer().getPluginManager().callEvent(event);
|
||||
- if (event.isCancelled()) {
|
||||
- iinventory.setItem(i, original);
|
||||
-
|
||||
- if (ihopper instanceof HopperBlockEntity) {
|
||||
- ((HopperBlockEntity) ihopper).setCooldown(world.spigotConfig.hopperTransfer); // Spigot
|
||||
- }
|
||||
-
|
||||
- return false;
|
||||
- }
|
||||
- int origCount = event.getItem().getAmount(); // Spigot
|
||||
- ItemStack itemstack1 = HopperBlockEntity.addItem(iinventory, ihopper, CraftItemStack.asNMSCopy(event.getItem()), null);
|
||||
- // CraftBukkit end
|
||||
-
|
||||
- if (itemstack1.isEmpty()) {
|
||||
- iinventory.setChanged();
|
||||
- return true;
|
||||
- }
|
||||
-
|
||||
- itemstack.setCount(j);
|
||||
- // Spigot start
|
||||
- itemstack.shrink(origCount - itemstack1.getCount());
|
||||
- if (j <= world.spigotConfig.hopperAmount) {
|
||||
- // Spigot end
|
||||
- iinventory.setItem(i, itemstack);
|
||||
- }
|
||||
+ // Paper start - Perf: Optimize Hoppers
|
||||
+ return hopperPull(world, ihopper, iinventory, itemstack, i);
|
||||
+ // int j = itemstack.getCount();
|
||||
+ // // CraftBukkit start - Call event on collection of items from inventories into the hopper
|
||||
+ // ItemStack original = itemstack.copy();
|
||||
+ // CraftItemStack oitemstack = CraftItemStack.asCraftMirror(iinventory.removeItem(i, world.spigotConfig.hopperAmount)); // Spigot
|
||||
+
|
||||
+ // Inventory sourceInventory;
|
||||
+ // // Have to special case large chests as they work oddly
|
||||
+ // if (iinventory instanceof CompoundContainer) {
|
||||
+ // sourceInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest((CompoundContainer) iinventory);
|
||||
+ // } else if (iinventory.getOwner() != null) {
|
||||
+ // sourceInventory = iinventory.getOwner().getInventory();
|
||||
+ // } else {
|
||||
+ // sourceInventory = new CraftInventory(iinventory);
|
||||
+ // }
|
||||
+
|
||||
+ // InventoryMoveItemEvent event = new InventoryMoveItemEvent(sourceInventory, oitemstack, ihopper.getOwner().getInventory(), false);
|
||||
+
|
||||
+ // Bukkit.getServer().getPluginManager().callEvent(event);
|
||||
+ // if (event.isCancelled()) {
|
||||
+ // iinventory.setItem(i, original);
|
||||
+
|
||||
+ // if (ihopper instanceof HopperBlockEntity) {
|
||||
+ // ((HopperBlockEntity) ihopper).setCooldown(world.spigotConfig.hopperTransfer); // Spigot
|
||||
+ // }
|
||||
+
|
||||
+ // return false;
|
||||
+ // }
|
||||
+ // int origCount = event.getItem().getAmount(); // Spigot
|
||||
+ // ItemStack itemstack1 = HopperBlockEntity.addItem(iinventory, ihopper, CraftItemStack.asNMSCopy(event.getItem()), null);
|
||||
+ // // CraftBukkit end
|
||||
+
|
||||
+ // if (itemstack1.isEmpty()) {
|
||||
+ // iinventory.setChanged();
|
||||
+ // return true;
|
||||
+ // }
|
||||
+
|
||||
+ // itemstack.setCount(j);
|
||||
+ // // Spigot start
|
||||
+ // itemstack.shrink(origCount - itemstack1.getCount());
|
||||
+ // if (j <= world.spigotConfig.hopperAmount) {
|
||||
+ // // Spigot end
|
||||
+ // iinventory.setItem(i, itemstack);
|
||||
+ // }
|
||||
+ // Paper end - Perf: Optimize Hoppers
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -0,0 +0,0 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
||||
public static boolean addItem(Container inventory, ItemEntity itemEntity) {
|
||||
boolean flag = false;
|
||||
// CraftBukkit start
|
||||
- InventoryPickupItemEvent event = new InventoryPickupItemEvent(inventory.getOwner().getInventory(), (org.bukkit.entity.Item) itemEntity.getBukkitEntity());
|
||||
+ if (InventoryPickupItemEvent.getHandlerList().getRegisteredListeners().length > 0) { // Paper - optimize hoppers
|
||||
+ InventoryPickupItemEvent event = new InventoryPickupItemEvent(getInventory(inventory), (org.bukkit.entity.Item) itemEntity.getBukkitEntity()); // Paper - Perf: Optimize Hoppers; use getInventory() to avoid snapshot creation
|
||||
itemEntity.level().getCraftServer().getPluginManager().callEvent(event);
|
||||
if (event.isCancelled()) {
|
||||
return false;
|
||||
}
|
||||
// CraftBukkit end
|
||||
+ } // Paper - Perf: Optimize Hoppers
|
||||
ItemStack itemstack = itemEntity.getItem().copy();
|
||||
ItemStack itemstack1 = HopperBlockEntity.addItem((Container) null, inventory, itemstack, (Direction) null);
|
||||
|
||||
@@ -0,0 +0,0 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
||||
stack = stack.split(to.getMaxStackSize());
|
||||
}
|
||||
// Spigot end
|
||||
+ ignoreTileUpdates = true; // Paper - Perf: Optimize Hoppers
|
||||
to.setItem(slot, stack);
|
||||
+ ignoreTileUpdates = false; // Paper - Perf: Optimize Hoppers
|
||||
stack = leftover; // Paper - Make hoppers respect inventory max stack size
|
||||
flag = true;
|
||||
} else if (HopperBlockEntity.canMergeItems(itemstack1, stack)) {
|
||||
@@ -0,0 +0,0 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
||||
|
||||
@Nullable
|
||||
public static Container getContainerAt(Level world, BlockPos pos) {
|
||||
- return HopperBlockEntity.getContainerAt(world, pos, world.getBlockState(pos), (double) pos.getX() + 0.5D, (double) pos.getY() + 0.5D, (double) pos.getZ() + 0.5D);
|
||||
+ return HopperBlockEntity.getContainerAt(world, pos, world.getBlockState(pos), (double) pos.getX() + 0.5D, (double) pos.getY() + 0.5D, (double) pos.getZ() + 0.5D, true);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Container getContainerAt(Level world, BlockPos pos, BlockState state, double x, double y, double z) {
|
||||
+ // Paper start - Perf: Optimize Hoppers
|
||||
+ return HopperBlockEntity.getContainerAt(world, pos, state, x, y, z, false);
|
||||
+ }
|
||||
+ @Nullable
|
||||
+ private static Container getContainerAt(Level world, BlockPos pos, BlockState state, double x, double y, double z, boolean optimizeEntities) {
|
||||
+ // Paper end - Perf: Optimize Hoppers
|
||||
Container iinventory = HopperBlockEntity.getBlockContainer(world, pos, state);
|
||||
|
||||
- if (iinventory == null) {
|
||||
+ if (iinventory == null && (!optimizeEntities || !world.paperConfig().hopper.ignoreOccludingBlocks || !state.getBukkitMaterial().isOccluding())) { // Paper - Perf: Optimize Hoppers
|
||||
iinventory = HopperBlockEntity.getEntityContainer(world, x, y, z);
|
||||
}
|
||||
|
||||
@@ -0,0 +0,0 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
||||
|
||||
@Nullable
|
||||
private static Container getEntityContainer(Level world, double x, double y, double z) {
|
||||
- List<Entity> list = world.getEntities((Entity) null, new AABB(x - 0.5D, y - 0.5D, z - 0.5D, x + 0.5D, y + 0.5D, z + 0.5D), EntitySelector.CONTAINER_ENTITY_SELECTOR);
|
||||
+ List<Entity> list = world.getEntitiesOfClass((Class) Container.class, new AABB(x - 0.5D, y - 0.5D, z - 0.5D, x + 0.5D, y + 0.5D, z + 0.5D), EntitySelector.CONTAINER_ENTITY_SELECTOR); // Paper - Perf: Optimize hoppers
|
||||
|
||||
return !list.isEmpty() ? (Container) list.get(world.random.nextInt(list.size())) : null;
|
||||
}
|
||||
|
||||
private static boolean canMergeItems(ItemStack first, ItemStack second) {
|
||||
- return first.getCount() <= first.getMaxStackSize() && ItemStack.isSameItemSameComponents(first, second);
|
||||
+ return first.getCount() < first.getMaxStackSize() && ItemStack.isSameItemSameComponents(first, second); // Paper - Perf: Optimize Hoppers; used to return true for full itemstacks?!
|
||||
}
|
||||
|
||||
@Override
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java
|
||||
@@ -0,0 +0,0 @@ public abstract class RandomizableContainerBlockEntity extends BaseContainerBloc
|
||||
|
||||
@Override
|
||||
public ItemStack getItem(int slot) {
|
||||
- this.unpackLootTable(null);
|
||||
+ if (slot == 0) this.unpackLootTable(null); // Paper - Perf: Optimize Hoppers
|
||||
return super.getItem(slot);
|
||||
}
|
||||
|
|
@ -1,123 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sun, 3 May 2020 22:35:09 -0400
|
||||
Subject: [PATCH] Optimize Voxel Shape Merging
|
||||
|
||||
This method shows up as super hot in profiler, and also a high "self" time.
|
||||
|
||||
Upon analyzing, it appears most usages of this method fall down to the final
|
||||
else statement of the nasty ternary.
|
||||
|
||||
Upon even further analyzation, it appears then the majority of those have a
|
||||
consistent list 1.... One with Infinity head and Tails.
|
||||
|
||||
First optimization is to detect these infinite states and immediately return that
|
||||
VoxelShapeMergerList so we can avoid testing the rest for most cases.
|
||||
|
||||
Break the method into 2 to help the JVM promote inlining of this fast path.
|
||||
|
||||
Then it was also noticed that VoxelShapeMergerList constructor is also a hotspot
|
||||
with a high self time...
|
||||
|
||||
Well, knowing that in most cases our list 1 is actualy the same value, it allows
|
||||
us to know that with an infinite list1, the result on the merger is essentially
|
||||
list2 as the final values.
|
||||
|
||||
This let us analyze the 2 potential states (Infinite with 2 sources or 4 sources)
|
||||
and compute a deterministic result for the MergerList values.
|
||||
|
||||
Additionally, this lets us avoid even allocating new objects for this too, further
|
||||
reducing memory usage.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/phys/shapes/IndirectMerger.java b/src/main/java/net/minecraft/world/phys/shapes/IndirectMerger.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/phys/shapes/IndirectMerger.java
|
||||
+++ b/src/main/java/net/minecraft/world/phys/shapes/IndirectMerger.java
|
||||
@@ -0,0 +0,0 @@ public class IndirectMerger implements IndexMerger {
|
||||
private final int[] firstIndices;
|
||||
private final int[] secondIndices;
|
||||
private final int resultLength;
|
||||
+ // Paper start
|
||||
+ private static final int[] INFINITE_B_1 = new int[]{1, 1};
|
||||
+ private static final int[] INFINITE_B_0 = new int[]{0, 0};
|
||||
+ private static final int[] INFINITE_C = new int[]{0, 1};
|
||||
+ // Paper end
|
||||
|
||||
public IndirectMerger(DoubleList first, DoubleList second, boolean includeFirstOnly, boolean includeSecondOnly) {
|
||||
double d = Double.NaN;
|
||||
int i = first.size();
|
||||
int j = second.size();
|
||||
int k = i + j;
|
||||
+ // Paper start - optimize common path of infinity doublelist
|
||||
+ int size = first.size();
|
||||
+ double tail = first.getDouble(size - 1);
|
||||
+ double head = first.getDouble(0);
|
||||
+ if (head == Double.NEGATIVE_INFINITY && tail == Double.POSITIVE_INFINITY && !includeFirstOnly && !includeSecondOnly && (size == 2 || size == 4)) {
|
||||
+ this.result = second.toDoubleArray();
|
||||
+ this.resultLength = second.size();
|
||||
+ if (size == 2) {
|
||||
+ this.firstIndices = INFINITE_B_0;
|
||||
+ } else {
|
||||
+ this.firstIndices = INFINITE_B_1;
|
||||
+ }
|
||||
+ this.secondIndices = INFINITE_C;
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end
|
||||
this.result = new double[k];
|
||||
this.firstIndices = new int[k];
|
||||
this.secondIndices = new int[k];
|
||||
diff --git a/src/main/java/net/minecraft/world/phys/shapes/Shapes.java b/src/main/java/net/minecraft/world/phys/shapes/Shapes.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/phys/shapes/Shapes.java
|
||||
+++ b/src/main/java/net/minecraft/world/phys/shapes/Shapes.java
|
||||
@@ -0,0 +0,0 @@ public final class Shapes {
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
- protected static IndexMerger createIndexMerger(int size, DoubleList first, DoubleList second, boolean includeFirst, boolean includeSecond) {
|
||||
+ private static IndexMerger createIndexMerger(int size, DoubleList first, DoubleList second, boolean includeFirst, boolean includeSecond) { // Paper - private
|
||||
+ // Paper start - fast track the most common scenario
|
||||
+ // doublelist is usually a DoubleArrayList with Infinite head/tails that falls to the final else clause
|
||||
+ // This is actually the most common path, so jump to it straight away
|
||||
+ if (first.getDouble(0) == Double.NEGATIVE_INFINITY && first.getDouble(first.size() - 1) == Double.POSITIVE_INFINITY) {
|
||||
+ return new IndirectMerger(first, second, includeFirst, includeSecond);
|
||||
+ }
|
||||
+ // Split out rest to hopefully inline the above
|
||||
+ return lessCommonMerge(size, first, second, includeFirst, includeSecond);
|
||||
+ }
|
||||
+
|
||||
+ private static IndexMerger lessCommonMerge(int size, DoubleList first, DoubleList second, boolean includeFirst, boolean includeSecond) {
|
||||
int i = first.size() - 1;
|
||||
int j = second.size() - 1;
|
||||
+ // Paper note - Rewrite below as optimized order if instead of nasty ternary
|
||||
if (first instanceof CubePointRange && second instanceof CubePointRange) {
|
||||
long l = lcm(i, j);
|
||||
if ((long)size * l <= 256L) {
|
||||
@@ -0,0 +0,0 @@ public final class Shapes {
|
||||
}
|
||||
}
|
||||
|
||||
- if (first.getDouble(i) < second.getDouble(0) - 1.0E-7) {
|
||||
+ // Paper start - Identical happens more often than Disjoint
|
||||
+ if (i == j && Objects.equals(first, second)) {
|
||||
+ if (first instanceof IdenticalMerger) {
|
||||
+ return (IndexMerger) first;
|
||||
+ } else if (second instanceof IdenticalMerger) {
|
||||
+ return (IndexMerger) second;
|
||||
+ }
|
||||
+ return new IdenticalMerger(first);
|
||||
+ } else if (first.getDouble(i) < second.getDouble(0) - 1.0E-7) {
|
||||
return new NonOverlappingMerger(first, second, false);
|
||||
} else if (second.getDouble(j) < first.getDouble(0) - 1.0E-7) {
|
||||
return new NonOverlappingMerger(second, first, true);
|
||||
} else {
|
||||
- return (IndexMerger)(i == j && Objects.equals(first, second)
|
||||
- ? new IdenticalMerger(first)
|
||||
- : new IndirectMerger(first, second, includeFirst, includeSecond));
|
||||
+ return new IndirectMerger(first, second, includeFirst, includeSecond);
|
||||
}
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
public interface DoubleLineConsumer {
|
|
@ -1,213 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Thu, 4 Jun 2020 02:24:49 -0400
|
||||
Subject: [PATCH] Optimize Bit Operations by inlining
|
||||
|
||||
Inline bit operations and reduce instruction count to make these hot
|
||||
operations faster
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/core/BlockPos.java b/src/main/java/net/minecraft/core/BlockPos.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/core/BlockPos.java
|
||||
+++ b/src/main/java/net/minecraft/core/BlockPos.java
|
||||
@@ -0,0 +0,0 @@ public class BlockPos extends Vec3i {
|
||||
};
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
public static final BlockPos ZERO = new BlockPos(0, 0, 0);
|
||||
- public static final int PACKED_HORIZONTAL_LENGTH = 1 + Mth.log2(Mth.smallestEncompassingPowerOfTwo(30000000));
|
||||
- public static final int PACKED_Y_LENGTH = 64 - 2 * PACKED_HORIZONTAL_LENGTH;
|
||||
- private static final long PACKED_X_MASK = (1L << PACKED_HORIZONTAL_LENGTH) - 1L;
|
||||
- private static final long PACKED_Y_MASK = (1L << PACKED_Y_LENGTH) - 1L;
|
||||
- private static final long PACKED_Z_MASK = (1L << PACKED_HORIZONTAL_LENGTH) - 1L;
|
||||
+ // Paper start - Optimize Bit Operations by inlining
|
||||
+ public static final int PACKED_HORIZONTAL_LENGTH = 26;
|
||||
+ public static final int PACKED_Y_LENGTH = 12;
|
||||
+ private static final long PACKED_X_MASK = 67108863;
|
||||
+ private static final long PACKED_Y_MASK = 4095;
|
||||
+ private static final long PACKED_Z_MASK = 67108863;
|
||||
private static final int Y_OFFSET = 0;
|
||||
- private static final int Z_OFFSET = PACKED_Y_LENGTH;
|
||||
- private static final int X_OFFSET = PACKED_Y_LENGTH + PACKED_HORIZONTAL_LENGTH;
|
||||
- public static final int MAX_HORIZONTAL_COORDINATE = (1 << PACKED_HORIZONTAL_LENGTH) / 2 - 1;
|
||||
+ private static final int Z_OFFSET = 12;
|
||||
+ private static final int X_OFFSET = 38;
|
||||
+ public static final int MAX_HORIZONTAL_COORDINATE = 33554431;
|
||||
+ // Paper end - Optimize Bit Operations by inlining
|
||||
|
||||
public BlockPos(int x, int y, int z) {
|
||||
super(x, y, z);
|
||||
@@ -0,0 +0,0 @@ public class BlockPos extends Vec3i {
|
||||
this(pos.getX(), pos.getY(), pos.getZ());
|
||||
}
|
||||
|
||||
+ public static long getAdjacent(int baseX, int baseY, int baseZ, Direction enumdirection) { return asLong(baseX + enumdirection.getStepX(), baseY + enumdirection.getStepY(), baseZ + enumdirection.getStepZ()); } // Paper
|
||||
public static long offset(long value, Direction direction) {
|
||||
return offset(value, direction.getStepX(), direction.getStepY(), direction.getStepZ());
|
||||
}
|
||||
|
||||
public static long offset(long value, int x, int y, int z) {
|
||||
- return asLong(getX(value) + x, getY(value) + y, getZ(value) + z);
|
||||
+ return asLong((int) (value >> 38) + x, (int) ((value << 52) >> 52) + y, (int) ((value << 26) >> 38) + z); // Paper - simplify/inline
|
||||
}
|
||||
|
||||
public static int getX(long packedPos) {
|
||||
- return (int)(packedPos << 64 - X_OFFSET - PACKED_HORIZONTAL_LENGTH >> 64 - PACKED_HORIZONTAL_LENGTH);
|
||||
+ return (int) (packedPos >> 38); // Paper - simplify/inline
|
||||
}
|
||||
|
||||
public static int getY(long packedPos) {
|
||||
- return (int)(packedPos << 64 - PACKED_Y_LENGTH >> 64 - PACKED_Y_LENGTH);
|
||||
+ return (int) ((packedPos << 52) >> 52); // Paper - simplify/inline
|
||||
}
|
||||
|
||||
public static int getZ(long packedPos) {
|
||||
- return (int)(packedPos << 64 - Z_OFFSET - PACKED_HORIZONTAL_LENGTH >> 64 - PACKED_HORIZONTAL_LENGTH);
|
||||
+ return (int) ((packedPos << 26) >> 38); // Paper - simplify/inline
|
||||
}
|
||||
|
||||
public static BlockPos of(long packedPos) {
|
||||
- return new BlockPos(getX(packedPos), getY(packedPos), getZ(packedPos));
|
||||
+ return new BlockPos((int) (packedPos >> 38), (int) ((packedPos << 52) >> 52), (int) ((packedPos << 26) >> 38)); // Paper - simplify/inline
|
||||
}
|
||||
|
||||
public static BlockPos containing(double x, double y, double z) {
|
||||
@@ -0,0 +0,0 @@ public class BlockPos extends Vec3i {
|
||||
}
|
||||
|
||||
public static long asLong(int x, int y, int z) {
|
||||
- long l = 0L;
|
||||
- l |= ((long)x & PACKED_X_MASK) << X_OFFSET;
|
||||
- l |= ((long)y & PACKED_Y_MASK) << 0;
|
||||
- return l | ((long)z & PACKED_Z_MASK) << Z_OFFSET;
|
||||
+ return (((long) x & (long) 67108863) << 38) | (((long) y & (long) 4095)) | (((long) z & (long) 67108863) << 12); // Paper - inline constants and simplify
|
||||
}
|
||||
|
||||
public static long getFlatIndex(long y) {
|
||||
diff --git a/src/main/java/net/minecraft/core/SectionPos.java b/src/main/java/net/minecraft/core/SectionPos.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/core/SectionPos.java
|
||||
+++ b/src/main/java/net/minecraft/core/SectionPos.java
|
||||
@@ -0,0 +0,0 @@ public class SectionPos extends Vec3i {
|
||||
}
|
||||
|
||||
public static SectionPos of(BlockPos pos) {
|
||||
- return new SectionPos(blockToSectionCoord(pos.getX()), blockToSectionCoord(pos.getY()), blockToSectionCoord(pos.getZ()));
|
||||
+ return new SectionPos(pos.getX() >> 4, pos.getY() >> 4, pos.getZ() >> 4); // Paper
|
||||
}
|
||||
|
||||
public static SectionPos of(ChunkPos chunkPos, int y) {
|
||||
@@ -0,0 +0,0 @@ public class SectionPos extends Vec3i {
|
||||
}
|
||||
|
||||
public static SectionPos of(long packed) {
|
||||
- return new SectionPos(x(packed), y(packed), z(packed));
|
||||
+ return new SectionPos((int) (packed >> 42), (int) (packed << 44 >> 44), (int) (packed << 22 >> 42)); // Paper
|
||||
}
|
||||
|
||||
public static SectionPos bottomOf(ChunkAccess chunk) {
|
||||
@@ -0,0 +0,0 @@ public class SectionPos extends Vec3i {
|
||||
return offset(packed, direction.getStepX(), direction.getStepY(), direction.getStepZ());
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ public static long getAdjacentFromBlockPos(int x, int y, int z, Direction enumdirection) {
|
||||
+ return (((long) ((x >> 4) + enumdirection.getStepX()) & 4194303L) << 42) | (((long) ((y >> 4) + enumdirection.getStepY()) & 1048575L)) | (((long) ((z >> 4) + enumdirection.getStepZ()) & 4194303L) << 20);
|
||||
+ }
|
||||
+ public static long getAdjacentFromSectionPos(int x, int y, int z, Direction enumdirection) {
|
||||
+ return (((long) (x + enumdirection.getStepX()) & 4194303L) << 42) | (((long) ((y) + enumdirection.getStepY()) & 1048575L)) | (((long) (z + enumdirection.getStepZ()) & 4194303L) << 20);
|
||||
+ }
|
||||
+ // Paper end
|
||||
public static long offset(long packed, int x, int y, int z) {
|
||||
- return asLong(x(packed) + x, y(packed) + y, z(packed) + z);
|
||||
+ return (((long) ((int) (packed >> 42) + x) & 4194303L) << 42) | (((long) ((int) (packed << 44 >> 44) + y) & 1048575L)) | (((long) ((int) (packed << 22 >> 42) + z) & 4194303L) << 20); // Simplify to reduce instruction count
|
||||
}
|
||||
|
||||
public static int posToSectionCoord(double coord) {
|
||||
@@ -0,0 +0,0 @@ public class SectionPos extends Vec3i {
|
||||
}
|
||||
|
||||
public static short sectionRelativePos(BlockPos pos) {
|
||||
- int i = sectionRelative(pos.getX());
|
||||
- int j = sectionRelative(pos.getY());
|
||||
- int k = sectionRelative(pos.getZ());
|
||||
- return (short)(i << 8 | k << 4 | j << 0);
|
||||
+ return (short) ((pos.getX() & 15) << 8 | (pos.getZ() & 15) << 4 | pos.getY() & 15); // Paper - simplify/inline
|
||||
}
|
||||
|
||||
public static int sectionRelativeX(short packedLocalPos) {
|
||||
@@ -0,0 +0,0 @@ public class SectionPos extends Vec3i {
|
||||
return this.getZ();
|
||||
}
|
||||
|
||||
- public int minBlockX() {
|
||||
- return sectionToBlockCoord(this.x());
|
||||
+ public final int minBlockX() { // Paper - make final
|
||||
+ return this.getX() << 4; // Paper - inline
|
||||
}
|
||||
|
||||
- public int minBlockY() {
|
||||
- return sectionToBlockCoord(this.y());
|
||||
+ public final int minBlockY() { // Paper - make final
|
||||
+ return this.getY() << 4; // Paper - inline
|
||||
}
|
||||
|
||||
- public int minBlockZ() {
|
||||
- return sectionToBlockCoord(this.z());
|
||||
+ public int minBlockZ() { // Paper - make final
|
||||
+ return this.getZ() << 4; // Paper - inline
|
||||
}
|
||||
|
||||
public int maxBlockX() {
|
||||
@@ -0,0 +0,0 @@ public class SectionPos extends Vec3i {
|
||||
}
|
||||
|
||||
public static long blockToSection(long blockPos) {
|
||||
- return asLong(blockToSectionCoord(BlockPos.getX(blockPos)), blockToSectionCoord(BlockPos.getY(blockPos)), blockToSectionCoord(BlockPos.getZ(blockPos)));
|
||||
+ // b(a(BlockPosition.b(i)), a(BlockPosition.c(i)), a(BlockPosition.d(i)));
|
||||
+ return (((long) (int) (blockPos >> 42) & 4194303L) << 42) | (((long) (int) ((blockPos << 52) >> 56) & 1048575L)) | (((long) (int) ((blockPos << 26) >> 42) & 4194303L) << 20); // Simplify to reduce instruction count
|
||||
}
|
||||
|
||||
public static long getZeroNode(int x, int z) {
|
||||
@@ -0,0 +0,0 @@ public class SectionPos extends Vec3i {
|
||||
return asLong(blockToSectionCoord(pos.getX()), blockToSectionCoord(pos.getY()), blockToSectionCoord(pos.getZ()));
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ public static long blockPosAsSectionLong(int i, int j, int k) {
|
||||
+ return (((long) (i >> 4) & 4194303L) << 42) | (((long) (j >> 4) & 1048575L)) | (((long) (k >> 4) & 4194303L) << 20);
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
public static long asLong(int x, int y, int z) {
|
||||
- long l = 0L;
|
||||
- l |= ((long)x & 4194303L) << 42;
|
||||
- l |= ((long)y & 1048575L) << 0;
|
||||
- return l | ((long)z & 4194303L) << 20;
|
||||
+ return (((long) x & 4194303L) << 42) | (((long) y & 1048575L)) | (((long) z & 4194303L) << 20); // Paper - Simplify to reduce instruction count
|
||||
}
|
||||
|
||||
public long asLong() {
|
||||
- return asLong(this.x(), this.y(), this.z());
|
||||
+ return (((long) getX() & 4194303L) << 42) | (((long) getY() & 1048575L)) | (((long) getZ() & 4194303L) << 20); // Paper - Simplify to reduce instruction count
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -0,0 +0,0 @@ public class SectionPos extends Vec3i {
|
||||
}
|
||||
|
||||
public static Stream<SectionPos> cube(SectionPos center, int radius) {
|
||||
- int i = center.x();
|
||||
- int j = center.y();
|
||||
- int k = center.z();
|
||||
- return betweenClosedStream(i - radius, j - radius, k - radius, i + radius, j + radius, k + radius);
|
||||
+ return betweenClosedStream(center.getX() - radius, center.getY() - radius, center.getZ() - radius, center.getX() + radius, center.getY() + radius, center.getZ() + radius); // Paper - simplify/inline
|
||||
}
|
||||
|
||||
public static Stream<SectionPos> aroundChunk(ChunkPos center, int radius, int minY, int maxY) {
|
||||
- int i = center.x;
|
||||
- int j = center.z;
|
||||
- return betweenClosedStream(i - radius, minY, j - radius, i + radius, maxY, j + radius);
|
||||
+ return betweenClosedStream(center.x - radius, minY, center.z - radius, center.x + radius, maxY, center.z + radius); // Paper - simplify/inline
|
||||
}
|
||||
|
||||
public static Stream<SectionPos> betweenClosedStream(int minX, int minY, int minZ, int maxX, int maxY, int maxZ) {
|
|
@ -1,215 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Josh Roy <10731363+JRoy@users.noreply.github.com>
|
||||
Date: Wed, 1 Jul 2020 18:01:49 -0400
|
||||
Subject: [PATCH] Remove streams from hot code
|
||||
|
||||
Co-authored-by: Bjarne Koll <git@lynxplay.dev>
|
||||
Co-authored-by: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/GateBehavior.java b/src/main/java/net/minecraft/world/entity/ai/behavior/GateBehavior.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/ai/behavior/GateBehavior.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/GateBehavior.java
|
||||
@@ -0,0 +0,0 @@ public class GateBehavior<E extends LivingEntity> implements BehaviorControl<E>
|
||||
if (this.hasRequiredMemories(entity)) {
|
||||
this.status = Behavior.Status.RUNNING;
|
||||
this.orderPolicy.apply(this.behaviors);
|
||||
- this.runningPolicy.apply(this.behaviors.stream(), world, entity, time);
|
||||
+ this.runningPolicy.apply(this.behaviors, world, entity, time); // Paper - Perf: Remove streams from hot code
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
@@ -0,0 +0,0 @@ public class GateBehavior<E extends LivingEntity> implements BehaviorControl<E>
|
||||
|
||||
@Override
|
||||
public final void tickOrStop(ServerLevel world, E entity, long time) {
|
||||
- this.behaviors.stream().filter(task -> task.getStatus() == Behavior.Status.RUNNING).forEach(task -> task.tickOrStop(world, entity, time));
|
||||
+ // Paper start - Perf: Remove streams from hot code
|
||||
+ for (final BehaviorControl<? super E> task : this.behaviors) {
|
||||
+ if (task.getStatus() == Behavior.Status.RUNNING) {
|
||||
+ task.tickOrStop(world, entity, time);
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - Perf: Remove streams from hot code
|
||||
if (this.behaviors.stream().noneMatch(task -> task.getStatus() == Behavior.Status.RUNNING)) {
|
||||
this.doStop(world, entity, time);
|
||||
}
|
||||
@@ -0,0 +0,0 @@ public class GateBehavior<E extends LivingEntity> implements BehaviorControl<E>
|
||||
@Override
|
||||
public final void doStop(ServerLevel world, E entity, long time) {
|
||||
this.status = Behavior.Status.STOPPED;
|
||||
- this.behaviors.stream().filter(task -> task.getStatus() == Behavior.Status.RUNNING).forEach(task -> task.doStop(world, entity, time));
|
||||
- this.exitErasedMemories.forEach(entity.getBrain()::eraseMemory);
|
||||
+ // Paper start - Perf: Remove streams from hot code
|
||||
+ for (final BehaviorControl<? super E> task : this.behaviors) {
|
||||
+ if (task.getStatus() == Behavior.Status.RUNNING) {
|
||||
+ task.doStop(world, entity, time);
|
||||
+ }
|
||||
+ }
|
||||
+ for (final MemoryModuleType<?> exitErasedMemory : this.exitErasedMemories) {
|
||||
+ entity.getBrain().eraseMemory(exitErasedMemory);
|
||||
+ }
|
||||
+ // Paper end - Perf: Remove streams from hot code
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -0,0 +0,0 @@ public class GateBehavior<E extends LivingEntity> implements BehaviorControl<E>
|
||||
|
||||
public static enum RunningPolicy {
|
||||
RUN_ONE {
|
||||
+ // Paper start - Perf: Remove streams from hot code
|
||||
@Override
|
||||
- public <E extends LivingEntity> void apply(Stream<BehaviorControl<? super E>> tasks, ServerLevel world, E entity, long time) {
|
||||
- tasks.filter(task -> task.getStatus() == Behavior.Status.STOPPED).filter(task -> task.tryStart(world, entity, time)).findFirst();
|
||||
+ public <E extends LivingEntity> void apply(ShufflingList<BehaviorControl<? super E>> tasks, ServerLevel world, E entity, long time) {
|
||||
+ for (final BehaviorControl<? super E> task : tasks) {
|
||||
+ if (task.getStatus() == Behavior.Status.STOPPED && task.tryStart(world, entity, time)) {
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - Perf: Remove streams from hot code
|
||||
}
|
||||
},
|
||||
TRY_ALL {
|
||||
+ // Paper start - Perf: Remove streams from hot code
|
||||
@Override
|
||||
- public <E extends LivingEntity> void apply(Stream<BehaviorControl<? super E>> tasks, ServerLevel world, E entity, long time) {
|
||||
- tasks.filter(task -> task.getStatus() == Behavior.Status.STOPPED).forEach(task -> task.tryStart(world, entity, time));
|
||||
+ public <E extends LivingEntity> void apply(ShufflingList<BehaviorControl<? super E>> tasks, ServerLevel world, E entity, long time) {
|
||||
+ for (final BehaviorControl<? super E> task : tasks) {
|
||||
+ if (task.getStatus() == Behavior.Status.STOPPED) {
|
||||
+ task.tryStart(world, entity, time);
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - Perf: Remove streams from hot code
|
||||
}
|
||||
};
|
||||
|
||||
- public abstract <E extends LivingEntity> void apply(Stream<BehaviorControl<? super E>> tasks, ServerLevel world, E entity, long time);
|
||||
+ public abstract <E extends LivingEntity> void apply(ShufflingList<BehaviorControl<? super E>> tasks, ServerLevel world, E entity, long time); // Paper - Perf: Remove streams from hot code
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/ai/gossip/GossipContainer.java b/src/main/java/net/minecraft/world/entity/ai/gossip/GossipContainer.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/ai/gossip/GossipContainer.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/ai/gossip/GossipContainer.java
|
||||
@@ -0,0 +0,0 @@ public class GossipContainer {
|
||||
return this.gossips.entrySet().stream().flatMap(entry -> entry.getValue().unpack(entry.getKey()));
|
||||
}
|
||||
|
||||
+ // Paper start - Perf: Remove streams from hot code
|
||||
+ private List<GossipContainer.GossipEntry> decompress() {
|
||||
+ List<GossipContainer.GossipEntry> list = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>();
|
||||
+ for (Map.Entry<UUID, GossipContainer.EntityGossips> entry : this.gossips.entrySet()) {
|
||||
+ for (GossipContainer.GossipEntry cur : entry.getValue().decompress(entry.getKey())) {
|
||||
+ if (cur.weightedValue() != 0) {
|
||||
+ list.add(cur);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ return list;
|
||||
+ }
|
||||
+ // Paper end - Perf: Remove streams from hot code
|
||||
+
|
||||
private Collection<GossipContainer.GossipEntry> selectGossipsForTransfer(RandomSource random, int count) {
|
||||
- List<GossipContainer.GossipEntry> list = this.unpack().toList();
|
||||
+ List<GossipContainer.GossipEntry> list = this.decompress(); // Paper - Perf: Remove streams from hot code
|
||||
if (list.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
} else {
|
||||
@@ -0,0 +0,0 @@ public class GossipContainer {
|
||||
|
||||
public <T> T store(DynamicOps<T> ops) {
|
||||
return GossipContainer.GossipEntry.LIST_CODEC
|
||||
- .encodeStart(ops, this.unpack().toList())
|
||||
+ .encodeStart(ops, this.decompress()) // Paper - Perf: Remove streams from hot code
|
||||
.resultOrPartial(error -> LOGGER.warn("Failed to serialize gossips: {}", error))
|
||||
.orElseGet(ops::emptyList);
|
||||
}
|
||||
@@ -0,0 +0,0 @@ public class GossipContainer {
|
||||
final Object2IntMap<GossipType> entries = new Object2IntOpenHashMap<>();
|
||||
|
||||
public int weightedValue(Predicate<GossipType> gossipTypeFilter) {
|
||||
- return this.entries
|
||||
- .object2IntEntrySet()
|
||||
- .stream()
|
||||
- .filter(entry -> gossipTypeFilter.test(entry.getKey()))
|
||||
- .mapToInt(entry -> entry.getIntValue() * entry.getKey().weight)
|
||||
- .sum();
|
||||
+ // Paper start - Perf: Remove streams from hot code
|
||||
+ int weight = 0;
|
||||
+ for (Object2IntMap.Entry<GossipType> entry : entries.object2IntEntrySet()) {
|
||||
+ if (gossipTypeFilter.test(entry.getKey())) {
|
||||
+ weight += entry.getIntValue() * entry.getKey().weight;
|
||||
+ }
|
||||
+ }
|
||||
+ return weight;
|
||||
+ }
|
||||
+
|
||||
+ public List<GossipContainer.GossipEntry> decompress(UUID uuid) {
|
||||
+ List<GossipContainer.GossipEntry> list = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>();
|
||||
+ for (Object2IntMap.Entry<GossipType> entry : entries.object2IntEntrySet()) {
|
||||
+ list.add(new GossipContainer.GossipEntry(uuid, entry.getKey(), entry.getIntValue()));
|
||||
+ }
|
||||
+ return list;
|
||||
+ // Paper end - Perf: Remove streams from hot code
|
||||
}
|
||||
|
||||
public Stream<GossipContainer.GossipEntry> unpack(UUID target) {
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/ai/sensing/NearestItemSensor.java b/src/main/java/net/minecraft/world/entity/ai/sensing/NearestItemSensor.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/ai/sensing/NearestItemSensor.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/ai/sensing/NearestItemSensor.java
|
||||
@@ -0,0 +0,0 @@ public class NearestItemSensor extends Sensor<Mob> {
|
||||
@Override
|
||||
protected void doTick(ServerLevel world, Mob entity) {
|
||||
Brain<?> brain = entity.getBrain();
|
||||
- List<ItemEntity> list = world.getEntitiesOfClass(ItemEntity.class, entity.getBoundingBox().inflate(32.0, 16.0, 32.0), itemEntity -> true);
|
||||
+ List<ItemEntity> list = world.getEntitiesOfClass(ItemEntity.class, entity.getBoundingBox().inflate(32.0, 16.0, 32.0), itemEntity -> itemEntity.closerThan(entity, MAX_DISTANCE_TO_WANTED_ITEM) && entity.wantsToPickUp(world, itemEntity.getItem())); // Paper - Perf: Move predicate into getEntities
|
||||
list.sort(Comparator.comparingDouble(entity::distanceToSqr));
|
||||
- Optional<ItemEntity> optional = list.stream()
|
||||
- .filter(itemEntity -> entity.wantsToPickUp(world, itemEntity.getItem()))
|
||||
- .filter(itemEntityx -> itemEntityx.closerThan(entity, 32.0))
|
||||
- .filter(entity::hasLineOfSight)
|
||||
- .findFirst();
|
||||
- brain.setMemory(MemoryModuleType.NEAREST_VISIBLE_WANTED_ITEM, optional);
|
||||
+ // Paper start - Perf: remove streams from hot code
|
||||
+ ItemEntity nearest = null;
|
||||
+ for (ItemEntity entityItem : list) {
|
||||
+ if (entity.hasLineOfSight(entityItem)) { // Paper - Perf: Move predicate into getEntities
|
||||
+ nearest = entityItem;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ brain.setMemory(MemoryModuleType.NEAREST_VISIBLE_WANTED_ITEM, Optional.ofNullable(nearest));
|
||||
+ // Paper end - Perf: remove streams from hot code
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/level/levelgen/Beardifier.java b/src/main/java/net/minecraft/world/level/levelgen/Beardifier.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/levelgen/Beardifier.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/levelgen/Beardifier.java
|
||||
@@ -0,0 +0,0 @@ public class Beardifier implements DensityFunctions.BeardifierOrMarker {
|
||||
int j = pos.getMinBlockZ();
|
||||
ObjectList<Beardifier.Rigid> objectList = new ObjectArrayList<>(10);
|
||||
ObjectList<JigsawJunction> objectList2 = new ObjectArrayList<>(32);
|
||||
- world.startsForStructure(pos, structure -> structure.terrainAdaptation() != TerrainAdjustment.NONE)
|
||||
- .forEach(
|
||||
- start -> {
|
||||
+ // Paper start - Perf: Remove streams from hot code
|
||||
+ for (net.minecraft.world.level.levelgen.structure.StructureStart start : world.startsForStructure(pos, (structure) -> {
|
||||
+ return structure.terrainAdaptation() != TerrainAdjustment.NONE;
|
||||
+ })) { // Paper end - Perf: Remove streams from hot code
|
||||
TerrainAdjustment terrainAdjustment = start.getStructure().terrainAdaptation();
|
||||
|
||||
for (StructurePiece structurePiece : start.getPieces()) {
|
||||
@@ -0,0 +0,0 @@ public class Beardifier implements DensityFunctions.BeardifierOrMarker {
|
||||
}
|
||||
}
|
||||
}
|
||||
- }
|
||||
- );
|
||||
+ } // Paper - Perf: Remove streams from hot code
|
||||
return new Beardifier(objectList.iterator(), objectList2.iterator());
|
||||
}
|
||||
|
|
@ -1,152 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jake Potrebic <jake.m.potrebic@gmail.com>
|
||||
Date: Sun, 22 Aug 2021 15:21:57 -0700
|
||||
Subject: [PATCH] Fix entity type tags suggestions in selectors
|
||||
|
||||
This would really be better as a client fix because just to fix it
|
||||
all EntityArguments have been told to ask the server for completions
|
||||
when if this was fixed on the client, that wouldn't be needed.
|
||||
|
||||
Mojira Issue: https://bugs.mojang.com/browse/MC-235045
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/commands/CommandSourceStack.java b/src/main/java/net/minecraft/commands/CommandSourceStack.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/commands/CommandSourceStack.java
|
||||
+++ b/src/main/java/net/minecraft/commands/CommandSourceStack.java
|
||||
@@ -0,0 +0,0 @@ public class CommandSourceStack implements ExecutionCommandSource<CommandSourceS
|
||||
return this.source.getBukkitSender(this);
|
||||
}
|
||||
// CraftBukkit end
|
||||
+ // Paper start - tell clients to ask server for suggestions for EntityArguments
|
||||
+ @Override
|
||||
+ public Collection<String> getSelectedEntities() {
|
||||
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().commands.fixTargetSelectorTagCompletion && this.source instanceof ServerPlayer player) {
|
||||
+ final Entity cameraEntity = player.getCamera();
|
||||
+ final double pickDistance = player.entityInteractionRange();
|
||||
+ final Vec3 min = cameraEntity.getEyePosition(1.0F);
|
||||
+ final Vec3 viewVector = cameraEntity.getViewVector(1.0F);
|
||||
+ final Vec3 max = min.add(viewVector.x * pickDistance, viewVector.y * pickDistance, viewVector.z * pickDistance);
|
||||
+ final net.minecraft.world.phys.AABB aabb = cameraEntity.getBoundingBox().expandTowards(viewVector.scale(pickDistance)).inflate(1.0D, 1.0D, 1.0D);
|
||||
+ final net.minecraft.world.phys.EntityHitResult hitResult = net.minecraft.world.entity.projectile.ProjectileUtil.getEntityHitResult(cameraEntity, min, max, aabb, (e) -> !e.isSpectator() && e.isPickable(), pickDistance * pickDistance);
|
||||
+ return hitResult != null ? java.util.Collections.singletonList(hitResult.getEntity().getStringUUID()) : SharedSuggestionProvider.super.getSelectedEntities();
|
||||
+ }
|
||||
+ return SharedSuggestionProvider.super.getSelectedEntities();
|
||||
+ }
|
||||
+ // Paper end - tell clients to ask server for suggestions for EntityArguments
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/commands/Commands.java
|
||||
+++ b/src/main/java/net/minecraft/commands/Commands.java
|
||||
@@ -0,0 +0,0 @@ public class Commands {
|
||||
Iterator iterator = children.iterator();
|
||||
// Paper end - Perf: Async command map building
|
||||
|
||||
+ boolean registeredAskServerSuggestionsForTree = false; // Paper - tell clients to ask server for suggestions for EntityArguments
|
||||
while (iterator.hasNext()) {
|
||||
CommandNode<CommandSourceStack> commandnode2 = (CommandNode) iterator.next();
|
||||
// Paper start - Brigadier API
|
||||
@@ -0,0 +0,0 @@ public class Commands {
|
||||
|
||||
if (requiredargumentbuilder.getSuggestionsProvider() != null) {
|
||||
requiredargumentbuilder.suggests(SuggestionProviders.safelySwap(requiredargumentbuilder.getSuggestionsProvider()));
|
||||
+ // Paper start - tell clients to ask server for suggestions for EntityArguments
|
||||
+ registeredAskServerSuggestionsForTree = requiredargumentbuilder.getSuggestionsProvider() == net.minecraft.commands.synchronization.SuggestionProviders.ASK_SERVER;
|
||||
+ } else if (io.papermc.paper.configuration.GlobalConfiguration.get().commands.fixTargetSelectorTagCompletion && !registeredAskServerSuggestionsForTree && requiredargumentbuilder.getType() instanceof net.minecraft.commands.arguments.EntityArgument) {
|
||||
+ requiredargumentbuilder.suggests(requiredargumentbuilder.getType()::listSuggestions);
|
||||
+ registeredAskServerSuggestionsForTree = true; // You can only
|
||||
+ // Paper end - tell clients to ask server for suggestions for EntityArguments
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/commands/arguments/EntityArgument.java b/src/main/java/net/minecraft/commands/arguments/EntityArgument.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/commands/arguments/EntityArgument.java
|
||||
+++ b/src/main/java/net/minecraft/commands/arguments/EntityArgument.java
|
||||
@@ -0,0 +0,0 @@ public class EntityArgument implements ArgumentType<EntitySelector> {
|
||||
final boolean permission = object instanceof CommandSourceStack stack
|
||||
? stack.bypassSelectorPermissions || stack.hasPermission(2, "minecraft.command.selector")
|
||||
: icompletionprovider.hasPermission(2);
|
||||
- EntitySelectorParser argumentparserselector = new EntitySelectorParser(stringreader, permission);
|
||||
+ EntitySelectorParser argumentparserselector = new EntitySelectorParser(stringreader, permission, true); // Paper - tell clients to ask server for suggestions for EntityArguments
|
||||
// Paper end - Fix EntityArgument permissions
|
||||
|
||||
try {
|
||||
@@ -0,0 +0,0 @@ public class EntityArgument implements ArgumentType<EntitySelector> {
|
||||
}
|
||||
|
||||
return argumentparserselector.fillSuggestions(suggestionsbuilder, (suggestionsbuilder1) -> {
|
||||
- Collection<String> collection = icompletionprovider.getOnlinePlayerNames();
|
||||
+ // Paper start - tell clients to ask server for suggestions for EntityArguments
|
||||
+ final Collection<String> collection;
|
||||
+ if (icompletionprovider instanceof CommandSourceStack commandSourceStack && commandSourceStack.getEntity() instanceof ServerPlayer sourcePlayer) {
|
||||
+ collection = new java.util.ArrayList<>();
|
||||
+ for (final ServerPlayer player : commandSourceStack.getServer().getPlayerList().getPlayers()) {
|
||||
+ if (sourcePlayer.getBukkitEntity().canSee(player.getBukkitEntity())) {
|
||||
+ collection.add(player.getGameProfile().getName());
|
||||
+ }
|
||||
+ }
|
||||
+ } else {
|
||||
+ collection = icompletionprovider.getOnlinePlayerNames();
|
||||
+ }
|
||||
+ // Paper end - tell clients to ask server for suggestions for EntityArguments
|
||||
Iterable<String> iterable = this.playersOnly ? collection : Iterables.concat(collection, icompletionprovider.getSelectedEntities());
|
||||
|
||||
SharedSuggestionProvider.suggest((Iterable) iterable, suggestionsbuilder1);
|
||||
diff --git a/src/main/java/net/minecraft/commands/arguments/selector/EntitySelectorParser.java b/src/main/java/net/minecraft/commands/arguments/selector/EntitySelectorParser.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/commands/arguments/selector/EntitySelectorParser.java
|
||||
+++ b/src/main/java/net/minecraft/commands/arguments/selector/EntitySelectorParser.java
|
||||
@@ -0,0 +0,0 @@ public class EntitySelectorParser {
|
||||
private boolean hasScores;
|
||||
private boolean hasAdvancements;
|
||||
private boolean usesSelectors;
|
||||
+ public boolean parsingEntityArgumentSuggestions; // Paper - tell clients to ask server for suggestions for EntityArguments
|
||||
|
||||
public EntitySelectorParser(StringReader reader, boolean atAllowed) {
|
||||
+ // Paper start - tell clients to ask server for suggestions for EntityArguments
|
||||
+ this(reader, atAllowed, false);
|
||||
+ }
|
||||
+ public EntitySelectorParser(StringReader reader, boolean atAllowed, boolean parsingEntityArgumentSuggestions) {
|
||||
+ this.parsingEntityArgumentSuggestions = parsingEntityArgumentSuggestions;
|
||||
+ // Paper end - tell clients to ask server for suggestions for EntityArguments
|
||||
this.distance = MinMaxBounds.Doubles.ANY;
|
||||
this.level = MinMaxBounds.Ints.ANY;
|
||||
this.rotX = WrappedMinMaxBounds.ANY;
|
||||
diff --git a/src/main/java/net/minecraft/commands/arguments/selector/options/EntitySelectorOptions.java b/src/main/java/net/minecraft/commands/arguments/selector/options/EntitySelectorOptions.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/commands/arguments/selector/options/EntitySelectorOptions.java
|
||||
+++ b/src/main/java/net/minecraft/commands/arguments/selector/options/EntitySelectorOptions.java
|
||||
@@ -0,0 +0,0 @@ public class EntitySelectorOptions {
|
||||
public static final DynamicCommandExceptionType ERROR_ENTITY_TYPE_INVALID = new DynamicCommandExceptionType(
|
||||
entity -> Component.translatableEscape("argument.entity.options.type.invalid", entity)
|
||||
);
|
||||
+ // Paper start - tell clients to ask server for suggestions for EntityArguments
|
||||
+ public static final DynamicCommandExceptionType ERROR_ENTITY_TAG_INVALID = new DynamicCommandExceptionType((object) -> {
|
||||
+ return io.papermc.paper.adventure.PaperAdventure
|
||||
+ .asVanilla(net.kyori.adventure.text.Component
|
||||
+ .text("Invalid or unknown entity type tag '" + object + "'")
|
||||
+ .hoverEvent(net.kyori.adventure.text.event.HoverEvent
|
||||
+ .showText(net.kyori.adventure.text.Component
|
||||
+ .text("You can disable this error in 'paper.yml'")
|
||||
+ )
|
||||
+ )
|
||||
+ );
|
||||
+ });
|
||||
+ // Paper end - tell clients to ask server for suggestions for EntityArguments
|
||||
|
||||
private static void register(String id, EntitySelectorOptions.Modifier handler, Predicate<EntitySelectorParser> condition, Component description) {
|
||||
OPTIONS.put(id, new EntitySelectorOptions.Option(handler, condition, description));
|
||||
@@ -0,0 +0,0 @@ public class EntitySelectorOptions {
|
||||
|
||||
if (reader.isTag()) {
|
||||
TagKey<EntityType<?>> tagKey = TagKey.create(Registries.ENTITY_TYPE, ResourceLocation.read(reader.getReader()));
|
||||
+ // Paper start - tell clients to ask server for suggestions for EntityArguments; throw error if invalid entity tag (only on suggestions to keep cmd success behavior)
|
||||
+ if (reader.parsingEntityArgumentSuggestions && io.papermc.paper.configuration.GlobalConfiguration.get().commands.fixTargetSelectorTagCompletion && net.minecraft.core.registries.BuiltInRegistries.ENTITY_TYPE.get(tagKey).isEmpty()) {
|
||||
+ reader.getReader().setCursor(i);
|
||||
+ throw ERROR_ENTITY_TAG_INVALID.createWithContext(reader.getReader(), tagKey);
|
||||
+ }
|
||||
+ // Paper end - tell clients to ask server for suggestions for EntityArguments
|
||||
reader.addPredicate(entity -> entity.getType().is(tagKey) != bl);
|
||||
} else {
|
||||
ResourceLocation resourceLocation = ResourceLocation.read(reader.getReader());
|
|
@ -1,68 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Mon, 2 Aug 2021 10:10:40 +0200
|
||||
Subject: [PATCH] Check distance in entity interactions
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/Util.java b/src/main/java/net/minecraft/Util.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/Util.java
|
||||
+++ b/src/main/java/net/minecraft/Util.java
|
||||
@@ -0,0 +0,0 @@ public class Util {
|
||||
.filter(fileSystemProvider -> fileSystemProvider.getScheme().equalsIgnoreCase("jar"))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new IllegalStateException("No jar file system provider found"));
|
||||
+ public static final double COLLISION_EPSILON = 1.0E-7; // Paper - Check distance in entity interactions
|
||||
private static Consumer<String> thePauser = message -> {
|
||||
};
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -0,0 +0,0 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
if (!source.is(DamageTypeTags.IS_PROJECTILE)) {
|
||||
Entity entity = source.getDirectEntity();
|
||||
|
||||
- if (entity instanceof LivingEntity) {
|
||||
+ if (entity instanceof LivingEntity && entity.distanceToSqr(this) <= (200.0D * 200.0D)) { // Paper - Check distance in entity interactions
|
||||
LivingEntity entityliving = (LivingEntity) entity;
|
||||
|
||||
this.blockUsingShield(entityliving);
|
||||
@@ -0,0 +0,0 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
d0 = source.getSourcePosition().x() - this.getX();
|
||||
d1 = source.getSourcePosition().z() - this.getZ();
|
||||
}
|
||||
+ // Paper start - Check distance in entity interactions; see for loop in knockback method
|
||||
+ if (Math.abs(d0) > 200) {
|
||||
+ d0 = Math.random() - Math.random();
|
||||
+ }
|
||||
+ if (Math.abs(d1) > 200) {
|
||||
+ d1 = Math.random() - Math.random();
|
||||
+ }
|
||||
+ // Paper end - Check distance in entity interactions
|
||||
|
||||
this.knockback(0.4000000059604645D, d0, d1, entity1, entity1 == null ? io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.DAMAGE : io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.ENTITY_ATTACK); // CraftBukkit // Paper - knockback events
|
||||
if (!flag) {
|
||||
@@ -0,0 +0,0 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
this.hurtCurrentlyUsedShield((float) -event.getDamage(DamageModifier.BLOCKING));
|
||||
Entity entity = damagesource.getDirectEntity();
|
||||
|
||||
- if (!damagesource.is(DamageTypeTags.IS_PROJECTILE) && entity instanceof LivingEntity) { // Paper - Fix shield disable inconsistency
|
||||
+ if (!damagesource.is(DamageTypeTags.IS_PROJECTILE) && entity instanceof LivingEntity && entity.distanceToSqr(this) <= (200.0D * 200.0D)) { // Paper - Fix shield disable inconsistency & Check distance in entity interactions
|
||||
this.blockUsingShield((LivingEntity) entity);
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/vehicle/AbstractBoat.java b/src/main/java/net/minecraft/world/entity/vehicle/AbstractBoat.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/vehicle/AbstractBoat.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/vehicle/AbstractBoat.java
|
||||
@@ -0,0 +0,0 @@ public abstract class AbstractBoat extends VehicleEntity implements Leashable {
|
||||
double d2 = (double) (this.getWaterLevelAbove() - this.getBbHeight()) + 0.101D;
|
||||
|
||||
if (this.level().noCollision(this, this.getBoundingBox().move(0.0D, d2 - this.getY(), 0.0D))) {
|
||||
- this.setPos(this.getX(), d2, this.getZ());
|
||||
+ this.move(MoverType.SELF, new Vec3(0.0D, d2 - this.getY(), 0.0D)); // Paper - Check distance in entity interactions // TODO Still needed??
|
||||
this.setDeltaMovement(this.getDeltaMovement().multiply(1.0D, 0.0D, 1.0D));
|
||||
this.lastYd = 0.0D;
|
||||
}
|
|
@ -1,78 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: lukas81298 <lukas81298@gommehd.net>
|
||||
Date: Fri, 22 Jan 2021 21:50:18 +0100
|
||||
Subject: [PATCH] optimize dirt and snow spreading
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/SpreadingSnowyDirtBlock.java b/src/main/java/net/minecraft/world/level/block/SpreadingSnowyDirtBlock.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/SpreadingSnowyDirtBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/SpreadingSnowyDirtBlock.java
|
||||
@@ -0,0 +0,0 @@ public abstract class SpreadingSnowyDirtBlock extends SnowyDirtBlock {
|
||||
}
|
||||
|
||||
private static boolean canBeGrass(BlockState state, LevelReader world, BlockPos pos) {
|
||||
+ // Paper start - Perf: optimize dirt and snow spreading
|
||||
+ return canBeGrass(world.getChunk(pos), state, world, pos);
|
||||
+ }
|
||||
+ private static boolean canBeGrass(net.minecraft.world.level.chunk.ChunkAccess chunk, BlockState state, LevelReader world, BlockPos pos) {
|
||||
+ // Paper end - Perf: optimize dirt and snow spreading
|
||||
BlockPos blockposition1 = pos.above();
|
||||
- BlockState iblockdata1 = world.getBlockState(blockposition1);
|
||||
+ BlockState iblockdata1 = chunk.getBlockState(blockposition1); // Paper - Perf: optimize dirt and snow spreading
|
||||
|
||||
if (iblockdata1.is(Blocks.SNOW) && (Integer) iblockdata1.getValue(SnowLayerBlock.LAYERS) == 1) {
|
||||
return true;
|
||||
@@ -0,0 +0,0 @@ public abstract class SpreadingSnowyDirtBlock extends SnowyDirtBlock {
|
||||
protected abstract MapCodec<? extends SpreadingSnowyDirtBlock> codec();
|
||||
|
||||
private static boolean canPropagate(BlockState state, LevelReader world, BlockPos pos) {
|
||||
+ // Paper start - Perf: optimize dirt and snow spreading
|
||||
+ return canPropagate(world.getChunk(pos), state, world, pos);
|
||||
+ }
|
||||
+
|
||||
+ private static boolean canPropagate(net.minecraft.world.level.chunk.ChunkAccess chunk, BlockState state, LevelReader world, BlockPos pos) {
|
||||
+ // Paper end - Perf: optimize dirt and snow spreading
|
||||
BlockPos blockposition1 = pos.above();
|
||||
|
||||
- return SpreadingSnowyDirtBlock.canBeGrass(state, world, pos) && !world.getFluidState(blockposition1).is(FluidTags.WATER);
|
||||
+ return SpreadingSnowyDirtBlock.canBeGrass(chunk, state, world, pos) && !chunk.getFluidState(blockposition1).is(FluidTags.WATER); // Paper - Perf: optimize dirt and snow spreading
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void randomTick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) {
|
||||
if (this instanceof GrassBlock && world.paperConfig().tickRates.grassSpread != 1 && (world.paperConfig().tickRates.grassSpread < 1 || (net.minecraft.server.MinecraftServer.currentTick + pos.hashCode()) % world.paperConfig().tickRates.grassSpread != 0)) { return; } // Paper - Configurable random tick rates for blocks
|
||||
- if (!SpreadingSnowyDirtBlock.canBeGrass(state, world, pos)) {
|
||||
+ // Paper start - Perf: optimize dirt and snow spreading
|
||||
+ final net.minecraft.world.level.chunk.ChunkAccess cachedBlockChunk = world.getChunkIfLoaded(pos);
|
||||
+ if (cachedBlockChunk == null) { // Is this needed?
|
||||
+ return;
|
||||
+ }
|
||||
+ if (!SpreadingSnowyDirtBlock.canBeGrass(cachedBlockChunk, state, world, pos)) {
|
||||
+ // Paper end - Perf: optimize dirt and snow spreading
|
||||
// CraftBukkit start
|
||||
if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockFadeEvent(world, pos, Blocks.DIRT.defaultBlockState()).isCancelled()) {
|
||||
return;
|
||||
@@ -0,0 +0,0 @@ public abstract class SpreadingSnowyDirtBlock extends SnowyDirtBlock {
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
BlockPos blockposition1 = pos.offset(random.nextInt(3) - 1, random.nextInt(5) - 3, random.nextInt(3) - 1);
|
||||
|
||||
- if (world.getBlockState(blockposition1).is(Blocks.DIRT) && SpreadingSnowyDirtBlock.canPropagate(iblockdata1, world, blockposition1)) {
|
||||
- org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(world, pos, blockposition1, (BlockState) iblockdata1.setValue(SpreadingSnowyDirtBlock.SNOWY, isSnowySetting(world.getBlockState(blockposition1.above())))); // CraftBukkit
|
||||
+ // Paper start - Perf: optimize dirt and snow spreading
|
||||
+ if (pos.getX() == blockposition1.getX() && pos.getY() == blockposition1.getY() && pos.getZ() == blockposition1.getZ()) {
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ final net.minecraft.world.level.chunk.ChunkAccess access;
|
||||
+ if (cachedBlockChunk.locX == blockposition1.getX() >> 4 && cachedBlockChunk.locZ == blockposition1.getZ() >> 4) {
|
||||
+ access = cachedBlockChunk;
|
||||
+ } else {
|
||||
+ access = world.getChunkAt(blockposition1);
|
||||
+ }
|
||||
+ if (access.getBlockState(blockposition1).is(Blocks.DIRT) && SpreadingSnowyDirtBlock.canPropagate(access, iblockdata1, world, blockposition1)) {
|
||||
+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(world, pos, blockposition1, (BlockState) iblockdata1.setValue(SpreadingSnowyDirtBlock.SNOWY, isSnowySetting(access.getBlockState(blockposition1.above())))); // CraftBukkit
|
||||
+ // Paper end - Perf: optimize dirt and snow spreading
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Sat, 25 Jan 2020 17:04:35 -0800
|
||||
Subject: [PATCH] Optimise getChunkAt calls for loaded chunks
|
||||
|
||||
bypass the need to get a player chunk, then get the either,
|
||||
then unwrap it...
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource {
|
||||
return this.getChunk(x, z, leastStatus, create);
|
||||
}, this.mainThreadProcessor).join();
|
||||
} else {
|
||||
+ // Paper start - Perf: Optimise getChunkAt calls for loaded chunks
|
||||
+ LevelChunk ifLoaded = this.getChunkAtIfLoadedMainThread(x, z);
|
||||
+ if (ifLoaded != null) {
|
||||
+ return ifLoaded;
|
||||
+ }
|
||||
+ // Paper end - Perf: Optimise getChunkAt calls for loaded chunks
|
||||
ProfilerFiller gameprofilerfiller = Profiler.get();
|
||||
|
||||
gameprofilerfiller.incrementCounter("getChunk");
|
||||
@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource {
|
||||
if (Thread.currentThread() != this.mainThread) {
|
||||
return null;
|
||||
} else {
|
||||
- Profiler.get().incrementCounter("getChunkNow");
|
||||
- long k = ChunkPos.asLong(chunkX, chunkZ);
|
||||
-
|
||||
- ChunkAccess ichunkaccess;
|
||||
-
|
||||
- for (int l = 0; l < 4; ++l) {
|
||||
- if (k == this.lastChunkPos[l] && this.lastChunkStatus[l] == ChunkStatus.FULL) {
|
||||
- ichunkaccess = this.lastChunk[l];
|
||||
- return ichunkaccess instanceof LevelChunk ? (LevelChunk) ichunkaccess : null;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- ChunkHolder playerchunk = this.getVisibleChunkIfPresent(k);
|
||||
-
|
||||
- if (playerchunk == null) {
|
||||
- return null;
|
||||
- } else {
|
||||
- ichunkaccess = playerchunk.getChunkIfPresent(ChunkStatus.FULL);
|
||||
- if (ichunkaccess != null) {
|
||||
- this.storeInCache(k, ichunkaccess, ChunkStatus.FULL);
|
||||
- if (ichunkaccess instanceof LevelChunk) {
|
||||
- return (LevelChunk) ichunkaccess;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- return null;
|
||||
- }
|
||||
+ return this.getChunkAtIfLoadedMainThread(chunkX, chunkZ); // Paper - Perf: Optimise getChunkAt calls for loaded chunks
|
||||
}
|
||||
}
|
||||
|
|
@ -1,455 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sun, 12 Apr 2020 15:50:48 -0400
|
||||
Subject: [PATCH] Improved Watchdog Support
|
||||
|
||||
Forced Watchdog Crash support and Improve Async Shutdown
|
||||
|
||||
If the request to shut down the server is received while we are in
|
||||
a watchdog hang, immediately treat it as a crash and begin the shutdown
|
||||
process. Shutdown process is now improved to also shutdown cleanly when
|
||||
not using restart scripts either.
|
||||
|
||||
If a server is deadlocked, a server owner can send SIGUP (or any other signal
|
||||
the JVM understands to shut down as it currently does) and the watchdog
|
||||
will no longer need to wait until the full timeout, allowing you to trigger
|
||||
a close process and try to shut the server down gracefully, saving player and
|
||||
world data.
|
||||
|
||||
Previously there was no way to trigger this outside of waiting for a full watchdog
|
||||
timeout, which may be set to a really long time...
|
||||
|
||||
Additionally, fix everything to do with shutting the server down asynchronously.
|
||||
|
||||
Previously, nearly everything about the process was fragile and unsafe. Main might
|
||||
not have actually been frozen, and might still be manipulating state.
|
||||
|
||||
Or, some reuest might ask main to do something in the shutdown but main is dead.
|
||||
|
||||
Or worse, other things might start closing down items such as the Console or Thread Pool
|
||||
before we are fully shutdown.
|
||||
|
||||
This change tries to resolve all of these issues by moving everything into the stop
|
||||
method and guaranteeing only one thread is stopping the server.
|
||||
|
||||
We then issue Thread Death to the main thread of another thread initiates the stop process.
|
||||
We have to ensure Thread Death propagates correctly though to stop main completely.
|
||||
|
||||
This is to ensure that if main isn't truely stuck, it's not manipulating state we are trying to save.
|
||||
|
||||
This also moves all plugins who register "delayed init" tasks to occur just before "Done" so they
|
||||
are properly accounted for and wont trip watchdog on init.
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/util/LogManagerShutdownThread.java b/src/main/java/io/papermc/paper/util/LogManagerShutdownThread.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/util/LogManagerShutdownThread.java
|
||||
@@ -0,0 +0,0 @@
|
||||
+package io.papermc.paper.util;
|
||||
+
|
||||
+public class LogManagerShutdownThread extends Thread {
|
||||
+
|
||||
+ static LogManagerShutdownThread INSTANCE = new LogManagerShutdownThread();
|
||||
+ public static final void hook() {
|
||||
+ if (INSTANCE == null) {
|
||||
+ throw new IllegalStateException("Cannot re-hook after being unhooked");
|
||||
+ }
|
||||
+ Runtime.getRuntime().addShutdownHook(INSTANCE);
|
||||
+ }
|
||||
+
|
||||
+ public static final void unhook() {
|
||||
+ Runtime.getRuntime().removeShutdownHook(INSTANCE);
|
||||
+ INSTANCE = null;
|
||||
+ }
|
||||
+
|
||||
+ private LogManagerShutdownThread() {
|
||||
+ super("Log4j2 Shutdown Thread");
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void run() {
|
||||
+ org.apache.logging.log4j.LogManager.shutdown();
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/net/minecraft/CrashReport.java b/src/main/java/net/minecraft/CrashReport.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/CrashReport.java
|
||||
+++ b/src/main/java/net/minecraft/CrashReport.java
|
||||
@@ -0,0 +0,0 @@ public class CrashReport {
|
||||
}
|
||||
|
||||
public static CrashReport forThrowable(Throwable cause, String title) {
|
||||
+ if (cause instanceof ThreadDeath) com.destroystokyo.paper.util.SneakyThrow.sneaky(cause); // Paper
|
||||
while (cause instanceof CompletionException && cause.getCause() != null) {
|
||||
cause = cause.getCause();
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/server/Main.java b/src/main/java/net/minecraft/server/Main.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/Main.java
|
||||
+++ b/src/main/java/net/minecraft/server/Main.java
|
||||
@@ -0,0 +0,0 @@ public class Main {
|
||||
@SuppressForbidden(reason = "System.out needed before bootstrap") // CraftBukkit - decompile error
|
||||
@DontObfuscate
|
||||
public static void main(final OptionSet optionset) { // CraftBukkit - replaces main(String[] astring)
|
||||
+ io.papermc.paper.util.LogManagerShutdownThread.hook(); // Paper
|
||||
SharedConstants.tryDetectVersion();
|
||||
/* CraftBukkit start - Replace everything
|
||||
OptionParser optionparser = new OptionParser();
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
public java.util.Queue<Runnable> processQueue = new java.util.concurrent.ConcurrentLinkedQueue<Runnable>();
|
||||
public int autosavePeriod;
|
||||
// Paper - don't store the vanilla dispatcher
|
||||
- private boolean forceTicks;
|
||||
+ public boolean forceTicks; // Paper - Improved watchdog support
|
||||
// CraftBukkit end
|
||||
// Spigot start
|
||||
public static final int TPS = 20;
|
||||
@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
public boolean isIteratingOverLevels = false; // Paper - Throw exception on world create while being ticked
|
||||
private final Set<String> pluginsBlockingSleep = new java.util.HashSet<>(); // Paper - API to allow/disallow tick sleeping
|
||||
|
||||
+ public volatile Thread shutdownThread; // Paper
|
||||
+ public volatile boolean abnormalExit = false; // Paper
|
||||
+
|
||||
public static <S extends MinecraftServer> S spin(Function<Thread, S> serverFactory) {
|
||||
ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.init(); // Paper - rewrite data converter system
|
||||
AtomicReference<S> atomicreference = new AtomicReference();
|
||||
@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
}
|
||||
*/
|
||||
// Paper end
|
||||
+ io.papermc.paper.util.LogManagerShutdownThread.unhook(); // Paper
|
||||
Runtime.getRuntime().addShutdownHook(new org.bukkit.craftbukkit.util.ServerShutdownThread(this));
|
||||
// CraftBukkit end
|
||||
this.paperConfigurations = services.paperConfigurations(); // Paper - add paper configuration files
|
||||
@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
// CraftBukkit start
|
||||
private boolean hasStopped = false;
|
||||
private boolean hasLoggedStop = false; // Paper - Debugging
|
||||
+ public volatile boolean hasFullyShutdown = false; // Paper
|
||||
private final Object stopLock = new Object();
|
||||
public final boolean hasStopped() {
|
||||
synchronized (this.stopLock) {
|
||||
@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
this.hasStopped = true;
|
||||
}
|
||||
if (!hasLoggedStop && isDebugging()) io.papermc.paper.util.TraceUtil.dumpTraceForThread("Server stopped"); // Paper - Debugging
|
||||
+ // Paper start - kill main thread, and kill it hard
|
||||
+ shutdownThread = Thread.currentThread();
|
||||
+ org.spigotmc.WatchdogThread.doStop(); // Paper
|
||||
+ // Paper end
|
||||
// CraftBukkit end
|
||||
if (this.metricsRecorder.isRecording()) {
|
||||
this.cancelRecordingMetrics();
|
||||
@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
ca.spottedleaf.moonrise.common.util.MoonriseCommon.haltExecutors();
|
||||
}
|
||||
// Paper end - rewrite chunk system
|
||||
+ // Paper start - Improved watchdog support - move final shutdown items here
|
||||
+ Util.shutdownExecutors();
|
||||
+ try {
|
||||
+ net.minecrell.terminalconsole.TerminalConsoleAppender.close(); // Paper - Use TerminalConsoleAppender
|
||||
+ } catch (final Exception ignored) {
|
||||
+ }
|
||||
+ io.papermc.paper.log.CustomLogManager.forceReset(); // Paper - Reset loggers after shutdown
|
||||
+ this.onServerExit();
|
||||
+ // Paper end - Improved watchdog support - move final shutdown items here
|
||||
}
|
||||
|
||||
public String getLocalIp() {
|
||||
@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
|
||||
protected void runServer() {
|
||||
try {
|
||||
+ long serverStartTime = Util.getNanos(); // Paper
|
||||
if (!this.initServer()) {
|
||||
throw new IllegalStateException("Failed to initialize server");
|
||||
}
|
||||
@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
|
||||
this.server.spark.enableBeforePlugins(); // Paper - spark
|
||||
// Spigot start
|
||||
+ // Paper start - Improved Watchdog Support
|
||||
+ LOGGER.info("Running delayed init tasks");
|
||||
+ this.server.getScheduler().mainThreadHeartbeat(); // run all 1 tick delay tasks during init,
|
||||
+ // this is going to be the first thing the tick process does anyways, so move done and run it after
|
||||
+ // everything is init before watchdog tick.
|
||||
+ // anything at 3+ won't be caught here but also will trip watchdog....
|
||||
+ // tasks are default scheduled at -1 + delay, and first tick will tick at 1
|
||||
+ final long actualDoneTimeMs = System.currentTimeMillis() - org.bukkit.craftbukkit.Main.BOOT_TIME.toEpochMilli(); // Paper - Add total time
|
||||
+ LOGGER.info("Done ({})! For help, type \"help\"", String.format(java.util.Locale.ROOT, "%.3fs", actualDoneTimeMs / 1000.00D)); // Paper - Add total time
|
||||
+ org.spigotmc.WatchdogThread.tick();
|
||||
+ // Paper end - Improved Watchdog Support
|
||||
org.spigotmc.WatchdogThread.hasStarted = true; // Paper
|
||||
Arrays.fill( this.recentTps, 20 );
|
||||
// Paper start - further improve server tick loop
|
||||
@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
JvmProfiler.INSTANCE.onServerTick(this.smoothedTickTimeMillis);
|
||||
}
|
||||
} catch (Throwable throwable2) {
|
||||
+ // Paper start
|
||||
+ if (throwable2 instanceof ThreadDeath) {
|
||||
+ MinecraftServer.LOGGER.error("Main thread terminated by WatchDog due to hard crash", throwable2);
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end
|
||||
MinecraftServer.LOGGER.error("Encountered an unexpected exception", throwable2);
|
||||
CrashReport crashreport = MinecraftServer.constructOrExtractCrashReport(throwable2);
|
||||
|
||||
@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
this.services.profileCache().clearExecutor();
|
||||
}
|
||||
|
||||
- org.spigotmc.WatchdogThread.doStop(); // Spigot
|
||||
+ //org.spigotmc.WatchdogThread.doStop(); // Spigot // Paper - move into stop
|
||||
// CraftBukkit start - Restore terminal to original settings
|
||||
try {
|
||||
- net.minecrell.terminalconsole.TerminalConsoleAppender.close(); // Paper - Use TerminalConsoleAppender
|
||||
+ //net.minecrell.terminalconsole.TerminalConsoleAppender.close(); // Paper - Move into stop
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
// CraftBukkit end
|
||||
- io.papermc.paper.log.CustomLogManager.forceReset(); // Paper - Reset loggers after shutdown
|
||||
- this.onServerExit();
|
||||
+ //io.papermc.paper.log.CustomLogManager.forceReset(); // Paper - Reset loggers after shutdown
|
||||
+ //this.onServerExit(); // Paper - moved into stop
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
|
||||
@Override
|
||||
public TickTask wrapRunnable(Runnable runnable) {
|
||||
+ // Paper start - anything that does try to post to main during watchdog crash, run on watchdog
|
||||
+ if (this.hasStopped && Thread.currentThread().equals(shutdownThread)) {
|
||||
+ runnable.run();
|
||||
+ runnable = () -> {};
|
||||
+ }
|
||||
+ // Paper end
|
||||
return new TickTask(this.tickCount, runnable);
|
||||
}
|
||||
|
||||
@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
this.resources.managers.updateStaticRegistryTags();
|
||||
this.resources.managers.getRecipeManager().finalizeRecipeLoading(this.worldData.enabledFeatures());
|
||||
this.potionBrewing = this.potionBrewing.reload(this.worldData.enabledFeatures()); // Paper - Custom Potion Mixes
|
||||
- this.getPlayerList().saveAll();
|
||||
+ // Paper start
|
||||
+ if (Thread.currentThread() != this.serverThread) {
|
||||
+ return;
|
||||
+ }
|
||||
+ // this.getPlayerList().saveAll(); // Paper - we don't need to save everything, just advancements // TODO Move this to a different patch
|
||||
+ for (ServerPlayer player : this.getPlayerList().getPlayers()) {
|
||||
+ player.getAdvancements().save();
|
||||
+ }
|
||||
+ // Paper end
|
||||
this.getPlayerList().reloadResources();
|
||||
this.functionManager.replaceLibrary(this.resources.managers.getFunctionLibrary());
|
||||
this.structureTemplateManager.onResourceManagerReload(this.resources.resourceManager);
|
||||
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
@@ -0,0 +0,0 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
||||
long j = Util.getNanos() - i;
|
||||
String s = String.format(Locale.ROOT, "%.3fs", (double) j / 1.0E9D);
|
||||
|
||||
- DedicatedServer.LOGGER.info("Done ({})! For help, type \"help\"", s);
|
||||
+ DedicatedServer.LOGGER.info("Done preparing level \"{}\" ({})", this.getLevelIdName(), s); // Paper - clarify startup log messages & add total time
|
||||
if (dedicatedserverproperties.announcePlayerAchievements != null) {
|
||||
((GameRules.BooleanValue) this.getGameRules().getRule(GameRules.RULE_ANNOUNCE_ADVANCEMENTS)).set(dedicatedserverproperties.announcePlayerAchievements, this.overworld()); // CraftBukkit - per-world
|
||||
}
|
||||
@@ -0,0 +0,0 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
||||
// this.remoteStatusListener.stop(); // Paper - don't wait for remote connections
|
||||
}
|
||||
|
||||
- System.exit(0); // CraftBukkit
|
||||
+ hasFullyShutdown = true; // Paper
|
||||
+ System.exit(this.abnormalExit ? 70 : 0); // CraftBukkit // Paper
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -0,0 +0,0 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
||||
@Override
|
||||
public void stopServer() {
|
||||
super.stopServer();
|
||||
- Util.shutdownExecutors();
|
||||
+ //Util.shutdownExecutors(); // Paper - moved into super
|
||||
SkullBlockEntity.clear();
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
@@ -0,0 +0,0 @@ public abstract class PlayerList {
|
||||
this.cserver.getPluginManager().callEvent(playerQuitEvent);
|
||||
entityplayer.getBukkitEntity().disconnect(playerQuitEvent.getQuitMessage());
|
||||
|
||||
- entityplayer.doTick(); // SPIGOT-924
|
||||
+ if (server.isSameThread()) entityplayer.doTick(); // SPIGOT-924 // Paper - don't tick during emergency shutdowns (Watchdog)
|
||||
// CraftBukkit end
|
||||
|
||||
// Paper start - Configurable player collision; Remove from collideRule team if needed
|
||||
diff --git a/src/main/java/net/minecraft/util/thread/BlockableEventLoop.java b/src/main/java/net/minecraft/util/thread/BlockableEventLoop.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/util/thread/BlockableEventLoop.java
|
||||
+++ b/src/main/java/net/minecraft/util/thread/BlockableEventLoop.java
|
||||
@@ -0,0 +0,0 @@ public abstract class BlockableEventLoop<R extends Runnable> implements Profiler
|
||||
public static boolean isNonRecoverable(Throwable exception) {
|
||||
return exception instanceof ReportedException reportedException
|
||||
? isNonRecoverable(reportedException.getCause())
|
||||
- : exception instanceof OutOfMemoryError || exception instanceof StackOverflowError;
|
||||
+ : exception instanceof OutOfMemoryError || exception instanceof StackOverflowError || exception instanceof ThreadDeath; // Paper
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -0,0 +0,0 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
||||
try {
|
||||
tickConsumer.accept(entity);
|
||||
} catch (Throwable throwable) {
|
||||
+ if (throwable instanceof ThreadDeath) throw throwable; // Paper
|
||||
// Paper start - Prevent block entity and entity crashes
|
||||
final String msg = String.format("Entity threw exception at %s:%s,%s,%s", entity.level().getWorld().getName(), entity.getX(), entity.getY(), entity.getZ());
|
||||
MinecraftServer.LOGGER.error(msg, throwable);
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
@@ -0,0 +0,0 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p
|
||||
|
||||
gameprofilerfiller.pop();
|
||||
} catch (Throwable throwable) {
|
||||
+ if (throwable instanceof ThreadDeath) throw throwable; // Paper
|
||||
// Paper start - Prevent block entity and entity crashes
|
||||
final String msg = String.format("BlockEntity threw exception at %s:%s,%s,%s", LevelChunk.this.getLevel().getWorld().getName(), this.getPos().getX(), this.getPos().getY(), this.getPos().getZ());
|
||||
net.minecraft.server.MinecraftServer.LOGGER.error(msg, throwable);
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java b/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java
|
||||
@@ -0,0 +0,0 @@ public class ServerShutdownThread extends Thread {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
+ // Paper start - try to shutdown on main
|
||||
+ server.safeShutdown(false, false);
|
||||
+ for (int i = 1000; i > 0 && !server.hasStopped(); i -= 100) {
|
||||
+ Thread.sleep(100);
|
||||
+ }
|
||||
+ if (server.hasStopped()) {
|
||||
+ while (!server.hasFullyShutdown) Thread.sleep(1000);
|
||||
+ return;
|
||||
+ }
|
||||
+ // Looks stalled, close async
|
||||
org.spigotmc.AsyncCatcher.enabled = false; // Spigot
|
||||
+ server.forceTicks = true;
|
||||
this.server.close();
|
||||
+ while (!server.hasFullyShutdown) Thread.sleep(1000);
|
||||
+ } catch (InterruptedException e) {
|
||||
+ e.printStackTrace();
|
||||
+ // Paper end
|
||||
} finally {
|
||||
+ org.apache.logging.log4j.LogManager.shutdown(); // Paper
|
||||
try {
|
||||
- net.minecrell.terminalconsole.TerminalConsoleAppender.close(); // Paper - Use TerminalConsoleAppender
|
||||
+ //net.minecrell.terminalconsole.TerminalConsoleAppender.close(); // Paper - Move into stop
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/org/spigotmc/RestartCommand.java b/src/main/java/org/spigotmc/RestartCommand.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/org/spigotmc/RestartCommand.java
|
||||
+++ b/src/main/java/org/spigotmc/RestartCommand.java
|
||||
@@ -0,0 +0,0 @@ public class RestartCommand extends Command
|
||||
// Paper end
|
||||
|
||||
// Paper start - copied from above and modified to return if the hook registered
|
||||
- private static boolean addShutdownHook(String restartScript)
|
||||
+ public static boolean addShutdownHook(String restartScript) // Paper
|
||||
{
|
||||
String[] split = restartScript.split( " " );
|
||||
if ( split.length > 0 && new File( split[0] ).isFile() )
|
||||
diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
+++ b/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
@@ -0,0 +0,0 @@ import org.bukkit.Bukkit;
|
||||
public class WatchdogThread extends ca.spottedleaf.moonrise.common.util.TickThread // Paper - rewrite chunk system
|
||||
{
|
||||
|
||||
+ public static final boolean DISABLE_WATCHDOG = Boolean.getBoolean("disable.watchdog"); // Paper - Improved watchdog support
|
||||
private static WatchdogThread instance;
|
||||
private long timeoutTime;
|
||||
private boolean restart;
|
||||
@@ -0,0 +0,0 @@ public class WatchdogThread extends ca.spottedleaf.moonrise.common.util.TickThre
|
||||
{
|
||||
if ( WatchdogThread.instance == null )
|
||||
{
|
||||
+ if (timeoutTime <= 0) timeoutTime = 300; // Paper
|
||||
WatchdogThread.instance = new WatchdogThread( timeoutTime * 1000L, restart );
|
||||
WatchdogThread.instance.start();
|
||||
} else
|
||||
@@ -0,0 +0,0 @@ public class WatchdogThread extends ca.spottedleaf.moonrise.common.util.TickThre
|
||||
// Paper start
|
||||
Logger log = Bukkit.getServer().getLogger();
|
||||
long currentTime = WatchdogThread.monotonicMillis();
|
||||
- if ( this.lastTick != 0 && this.timeoutTime > 0 && currentTime > this.lastTick + this.earlyWarningEvery && !Boolean.getBoolean("disable.watchdog")) // Paper - Add property to disable
|
||||
+ MinecraftServer server = MinecraftServer.getServer();
|
||||
+ if ( this.lastTick != 0 && this.timeoutTime > 0 && WatchdogThread.hasStarted && (!server.isRunning() || (currentTime > this.lastTick + this.earlyWarningEvery && !DISABLE_WATCHDOG) )) // Paper - add property to disable
|
||||
{
|
||||
- boolean isLongTimeout = currentTime > lastTick + timeoutTime;
|
||||
+ boolean isLongTimeout = currentTime > lastTick + timeoutTime || (!server.isRunning() && !server.hasStopped() && currentTime > lastTick + 1000);
|
||||
// Don't spam early warning dumps
|
||||
if ( !isLongTimeout && (earlyWarningEvery <= 0 || !hasStarted || currentTime < lastEarlyWarning + earlyWarningEvery || currentTime < lastTick + earlyWarningDelay)) continue;
|
||||
- if ( !isLongTimeout && MinecraftServer.getServer().hasStopped()) continue; // Don't spam early watchdog warnings during shutdown, we'll come back to this...
|
||||
+ if ( !isLongTimeout && server.hasStopped()) continue; // Don't spam early watchdog warnings during shutdown, we'll come back to this...
|
||||
lastEarlyWarning = currentTime;
|
||||
if (isLongTimeout) {
|
||||
// Paper end
|
||||
@@ -0,0 +0,0 @@ public class WatchdogThread extends ca.spottedleaf.moonrise.common.util.TickThre
|
||||
|
||||
if ( isLongTimeout )
|
||||
{
|
||||
- if ( this.restart && !MinecraftServer.getServer().hasStopped() )
|
||||
+ if ( !server.hasStopped() )
|
||||
{
|
||||
- RestartCommand.restart();
|
||||
+ AsyncCatcher.enabled = false; // Disable async catcher incase it interferes with us
|
||||
+ server.forceTicks = true;
|
||||
+ if (restart) {
|
||||
+ RestartCommand.addShutdownHook( SpigotConfig.restartScript );
|
||||
+ }
|
||||
+ // try one last chance to safe shutdown on main incase it 'comes back'
|
||||
+ server.abnormalExit = true;
|
||||
+ server.safeShutdown(false, restart);
|
||||
+ try {
|
||||
+ Thread.sleep(1000);
|
||||
+ } catch (InterruptedException e) {
|
||||
+ e.printStackTrace();
|
||||
+ }
|
||||
+ if (!server.hasStopped()) {
|
||||
+ server.close();
|
||||
+ }
|
||||
}
|
||||
break;
|
||||
} // Paper end
|
||||
diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/resources/log4j2.xml
|
||||
+++ b/src/main/resources/log4j2.xml
|
||||
@@ -0,0 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
-<Configuration status="WARN">
|
||||
+<Configuration status="WARN" shutdownHook="disable">
|
||||
<Appenders>
|
||||
<Queue name="ServerGuiConsole">
|
||||
<PatternLayout pattern="[%d{HH:mm:ss} %level]: %msg{nolookups}%n" />
|
|
@ -1,295 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Thu, 26 Mar 2020 21:59:32 -0700
|
||||
Subject: [PATCH] Detail more information in watchdog dumps
|
||||
|
||||
- Dump position, world, velocity, and uuid for currently ticking entities
|
||||
- Dump player name, player uuid, position, and world for packet handling
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/network/Connection.java
|
||||
+++ b/src/main/java/net/minecraft/network/Connection.java
|
||||
@@ -0,0 +0,0 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
if (!(this.packetListener instanceof net.minecraft.server.network.ServerLoginPacketListenerImpl loginPacketListener)
|
||||
|| loginPacketListener.state != net.minecraft.server.network.ServerLoginPacketListenerImpl.State.VERIFYING
|
||||
|| Connection.joinAttemptsThisTick++ < MAX_PER_TICK) {
|
||||
+ // Paper start - detailed watchdog information
|
||||
+ net.minecraft.network.protocol.PacketUtils.packetProcessing.push(this.packetListener);
|
||||
+ try {
|
||||
tickablepacketlistener.tick();
|
||||
+ } finally {
|
||||
+ net.minecraft.network.protocol.PacketUtils.packetProcessing.pop();
|
||||
+ } // Paper end - detailed watchdog information
|
||||
} // Paper end - Buffer joins to world
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/network/protocol/PacketUtils.java b/src/main/java/net/minecraft/network/protocol/PacketUtils.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/network/protocol/PacketUtils.java
|
||||
+++ b/src/main/java/net/minecraft/network/protocol/PacketUtils.java
|
||||
@@ -0,0 +0,0 @@ public class PacketUtils {
|
||||
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
|
||||
+ // Paper start - detailed watchdog information
|
||||
+ public static final java.util.concurrent.ConcurrentLinkedDeque<PacketListener> packetProcessing = new java.util.concurrent.ConcurrentLinkedDeque<>();
|
||||
+ static final java.util.concurrent.atomic.AtomicLong totalMainThreadPacketsProcessed = new java.util.concurrent.atomic.AtomicLong();
|
||||
+
|
||||
+ public static long getTotalProcessedPackets() {
|
||||
+ return totalMainThreadPacketsProcessed.get();
|
||||
+ }
|
||||
+
|
||||
+ public static java.util.List<PacketListener> getCurrentPacketProcessors() {
|
||||
+ java.util.List<PacketListener> ret = new java.util.ArrayList<>(4);
|
||||
+ for (PacketListener listener : packetProcessing) {
|
||||
+ ret.add(listener);
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+ }
|
||||
+ // Paper end - detailed watchdog information
|
||||
+
|
||||
public PacketUtils() {}
|
||||
|
||||
public static <T extends PacketListener> void ensureRunningOnSameThread(Packet<T> packet, T listener, ServerLevel world) throws RunningOnDifferentThreadException {
|
||||
@@ -0,0 +0,0 @@ public class PacketUtils {
|
||||
public static <T extends PacketListener> void ensureRunningOnSameThread(Packet<T> packet, T listener, BlockableEventLoop<?> engine) throws RunningOnDifferentThreadException {
|
||||
if (!engine.isSameThread()) {
|
||||
engine.executeIfPossible(() -> {
|
||||
+ packetProcessing.push(listener); // Paper - detailed watchdog information
|
||||
+ try { // Paper - detailed watchdog information
|
||||
if (listener instanceof ServerCommonPacketListenerImpl serverCommonPacketListener && serverCommonPacketListener.processedDisconnect) return; // CraftBukkit - Don't handle sync packets for kicked players
|
||||
if (listener.shouldHandleMessage(packet)) {
|
||||
try {
|
||||
@@ -0,0 +0,0 @@ public class PacketUtils {
|
||||
} else {
|
||||
PacketUtils.LOGGER.debug("Ignoring packet due to disconnection: {}", packet);
|
||||
}
|
||||
+ // Paper start - detailed watchdog information
|
||||
+ } finally {
|
||||
+ totalMainThreadPacketsProcessed.getAndIncrement();
|
||||
+ packetProcessing.pop();
|
||||
+ }
|
||||
+ // Paper end - detailed watchdog information
|
||||
|
||||
});
|
||||
throw RunningOnDifferentThreadException.RUNNING_ON_DIFFERENT_THREAD;
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
|
||||
}
|
||||
|
||||
+ // Paper start - log detailed entity tick information
|
||||
+ // TODO replace with varhandle
|
||||
+ static final java.util.concurrent.atomic.AtomicReference<Entity> currentlyTickingEntity = new java.util.concurrent.atomic.AtomicReference<>();
|
||||
+
|
||||
+ public static List<Entity> getCurrentlyTickingEntities() {
|
||||
+ Entity ticking = currentlyTickingEntity.get();
|
||||
+ List<Entity> ret = java.util.Arrays.asList(ticking == null ? new Entity[0] : new Entity[] { ticking });
|
||||
+
|
||||
+ return ret;
|
||||
+ }
|
||||
+ // Paper end - log detailed entity tick information
|
||||
+
|
||||
public void tickNonPassenger(Entity entity) {
|
||||
+ // Paper start - log detailed entity tick information
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread("Cannot tick an entity off-main");
|
||||
+ try {
|
||||
+ if (currentlyTickingEntity.get() == null) {
|
||||
+ currentlyTickingEntity.lazySet(entity);
|
||||
+ }
|
||||
+ // Paper end - log detailed entity tick information
|
||||
// Spigot start
|
||||
/*if (!org.spigotmc.ActivationRange.checkIfActive(entity)) { // Paper - comment out EAR 2
|
||||
entity.tickCount++;
|
||||
@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
this.tickPassenger(entity, entity1, isActive); // Paper - EAR 2
|
||||
}
|
||||
|
||||
+ // Paper start - log detailed entity tick information
|
||||
+ } finally {
|
||||
+ if (currentlyTickingEntity.get() == entity) {
|
||||
+ currentlyTickingEntity.lazySet(null);
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - log detailed entity tick information
|
||||
}
|
||||
|
||||
private void tickPassenger(Entity vehicle, Entity passenger, boolean isActive) { // Paper - EAR 2
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -0,0 +0,0 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
return this.onGround;
|
||||
}
|
||||
|
||||
+ // Paper start - detailed watchdog information
|
||||
+ public final Object posLock = new Object(); // Paper - log detailed entity tick information
|
||||
+
|
||||
+ private Vec3 moveVector;
|
||||
+ private double moveStartX;
|
||||
+ private double moveStartY;
|
||||
+ private double moveStartZ;
|
||||
+
|
||||
+ public final Vec3 getMoveVector() {
|
||||
+ return this.moveVector;
|
||||
+ }
|
||||
+
|
||||
+ public final double getMoveStartX() {
|
||||
+ return this.moveStartX;
|
||||
+ }
|
||||
+
|
||||
+ public final double getMoveStartY() {
|
||||
+ return this.moveStartY;
|
||||
+ }
|
||||
+
|
||||
+ public final double getMoveStartZ() {
|
||||
+ return this.moveStartZ;
|
||||
+ }
|
||||
+ // Paper end - detailed watchdog information
|
||||
+
|
||||
public void move(MoverType type, Vec3 movement) {
|
||||
final Vec3 originalMovement = movement; // Paper - Expose pre-collision velocity
|
||||
+ // Paper start - detailed watchdog information
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread("Cannot move an entity off-main");
|
||||
+ synchronized (this.posLock) {
|
||||
+ this.moveStartX = this.getX();
|
||||
+ this.moveStartY = this.getY();
|
||||
+ this.moveStartZ = this.getZ();
|
||||
+ this.moveVector = movement;
|
||||
+ }
|
||||
+ try {
|
||||
+ // Paper end - detailed watchdog information
|
||||
if (this.noPhysics) {
|
||||
this.setPos(this.getX() + movement.x, this.getY() + movement.y, this.getZ() + movement.z);
|
||||
} else {
|
||||
@@ -0,0 +0,0 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
gameprofilerfiller.pop();
|
||||
}
|
||||
}
|
||||
+ // Paper start - detailed watchdog information
|
||||
+ } finally {
|
||||
+ synchronized (this.posLock) { // Paper
|
||||
+ this.moveVector = null;
|
||||
+ } // Paper
|
||||
+ }
|
||||
+ // Paper end - detailed watchdog information
|
||||
}
|
||||
|
||||
private void applyMovementEmissionAndPlaySound(Entity.MovementEmission moveEffect, Vec3 movement, BlockPos landingPos, BlockState landingState) {
|
||||
@@ -0,0 +0,0 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
}
|
||||
|
||||
public void setDeltaMovement(Vec3 velocity) {
|
||||
+ synchronized (this.posLock) { // Paper
|
||||
this.deltaMovement = velocity;
|
||||
+ } // Paper
|
||||
}
|
||||
|
||||
public void addDeltaMovement(Vec3 velocity) {
|
||||
@@ -0,0 +0,0 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
}
|
||||
// Paper end - Fix MC-4
|
||||
if (this.position.x != x || this.position.y != y || this.position.z != z) {
|
||||
+ synchronized (this.posLock) { // Paper
|
||||
this.position = new Vec3(x, y, z);
|
||||
+ } // Paper
|
||||
int i = Mth.floor(x);
|
||||
int j = Mth.floor(y);
|
||||
int k = Mth.floor(z);
|
||||
diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
+++ b/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
@@ -0,0 +0,0 @@ public class WatchdogThread extends ca.spottedleaf.moonrise.common.util.TickThre
|
||||
private volatile long lastTick;
|
||||
private volatile boolean stopping;
|
||||
|
||||
+ // Paper start - log detailed tick information
|
||||
+ private void dumpEntity(net.minecraft.world.entity.Entity entity) {
|
||||
+ Logger log = Bukkit.getServer().getLogger();
|
||||
+ double posX, posY, posZ;
|
||||
+ net.minecraft.world.phys.Vec3 mot;
|
||||
+ double moveStartX, moveStartY, moveStartZ;
|
||||
+ net.minecraft.world.phys.Vec3 moveVec;
|
||||
+ synchronized (entity.posLock) {
|
||||
+ posX = entity.getX();
|
||||
+ posY = entity.getY();
|
||||
+ posZ = entity.getZ();
|
||||
+ mot = entity.getDeltaMovement();
|
||||
+ moveStartX = entity.getMoveStartX();
|
||||
+ moveStartY = entity.getMoveStartY();
|
||||
+ moveStartZ = entity.getMoveStartZ();
|
||||
+ moveVec = entity.getMoveVector();
|
||||
+ }
|
||||
+
|
||||
+ String entityType = net.minecraft.world.entity.EntityType.getKey(entity.getType()).toString();
|
||||
+ java.util.UUID entityUUID = entity.getUUID();
|
||||
+ net.minecraft.world.level.Level world = entity.level();
|
||||
+
|
||||
+ log.log(Level.SEVERE, "Ticking entity: " + entityType + ", entity class: " + entity.getClass().getName());
|
||||
+ log.log(Level.SEVERE, "Entity status: removed: " + entity.isRemoved() + ", valid: " + entity.valid + ", alive: " + entity.isAlive() + ", is passenger: " + entity.isPassenger());
|
||||
+ log.log(Level.SEVERE, "Entity UUID: " + entityUUID);
|
||||
+ log.log(Level.SEVERE, "Position: world: '" + (world == null ? "unknown world?" : world.getWorld().getName()) + "' at location (" + posX + ", " + posY + ", " + posZ + ")");
|
||||
+ log.log(Level.SEVERE, "Velocity: " + (mot == null ? "unknown velocity" : mot.toString()) + " (in blocks per tick)");
|
||||
+ log.log(Level.SEVERE, "Entity AABB: " + entity.getBoundingBox());
|
||||
+ if (moveVec != null) {
|
||||
+ log.log(Level.SEVERE, "Move call information: ");
|
||||
+ log.log(Level.SEVERE, "Start position: (" + moveStartX + ", " + moveStartY + ", " + moveStartZ + ")");
|
||||
+ log.log(Level.SEVERE, "Move vector: " + moveVec.toString());
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private void dumpTickingInfo() {
|
||||
+ Logger log = Bukkit.getServer().getLogger();
|
||||
+
|
||||
+ // ticking entities
|
||||
+ for (net.minecraft.world.entity.Entity entity : net.minecraft.server.level.ServerLevel.getCurrentlyTickingEntities()) {
|
||||
+ this.dumpEntity(entity);
|
||||
+ net.minecraft.world.entity.Entity vehicle = entity.getVehicle();
|
||||
+ if (vehicle != null) {
|
||||
+ log.log(Level.SEVERE, "Detailing vehicle for above entity:");
|
||||
+ this.dumpEntity(vehicle);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ // packet processors
|
||||
+ for (net.minecraft.network.PacketListener packetListener : net.minecraft.network.protocol.PacketUtils.getCurrentPacketProcessors()) {
|
||||
+ if (packetListener instanceof net.minecraft.server.network.ServerGamePacketListenerImpl) {
|
||||
+ net.minecraft.server.level.ServerPlayer player = ((net.minecraft.server.network.ServerGamePacketListenerImpl)packetListener).player;
|
||||
+ long totalPackets = net.minecraft.network.protocol.PacketUtils.getTotalProcessedPackets();
|
||||
+ if (player == null) {
|
||||
+ log.log(Level.SEVERE, "Handling packet for player connection or ticking player connection (null player): " + packetListener);
|
||||
+ log.log(Level.SEVERE, "Total packets processed on the main thread for all players: " + totalPackets);
|
||||
+ } else {
|
||||
+ this.dumpEntity(player);
|
||||
+ net.minecraft.world.entity.Entity vehicle = player.getVehicle();
|
||||
+ if (vehicle != null) {
|
||||
+ log.log(Level.SEVERE, "Detailing vehicle for above entity:");
|
||||
+ this.dumpEntity(vehicle);
|
||||
+ }
|
||||
+ log.log(Level.SEVERE, "Total packets processed on the main thread for all players: " + totalPackets);
|
||||
+ }
|
||||
+ } else {
|
||||
+ log.log(Level.SEVERE, "Handling packet for connection: " + packetListener);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - log detailed tick information
|
||||
+
|
||||
private WatchdogThread(long timeoutTime, boolean restart)
|
||||
{
|
||||
super( "Paper Watchdog Thread" );
|
||||
@@ -0,0 +0,0 @@ public class WatchdogThread extends ca.spottedleaf.moonrise.common.util.TickThre
|
||||
log.log( Level.SEVERE, "------------------------------" );
|
||||
log.log( Level.SEVERE, "Server thread dump (Look for plugins here before reporting to Paper!):" ); // Paper
|
||||
ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkTaskScheduler.dumpAllChunkLoadInfo(MinecraftServer.getServer(), isLongTimeout); // Paper - rewrite chunk system
|
||||
+ this.dumpTickingInfo(); // Paper - log detailed tick information
|
||||
WatchdogThread.dumpThread( ManagementFactory.getThreadMXBean().getThreadInfo( MinecraftServer.getServer().serverThread.getId(), Integer.MAX_VALUE ), log );
|
||||
log.log( Level.SEVERE, "------------------------------" );
|
||||
//
|
|
@ -1,92 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jake Potrebic <jake.m.potrebic@gmail.com>
|
||||
Date: Sun, 13 Aug 2023 15:41:52 -0700
|
||||
Subject: [PATCH] Improve performance of mass crafts
|
||||
|
||||
When the server crafts all available items in CraftingMenu or InventoryMenu the game
|
||||
checks either 4 or 9 times for each individual craft for a matching recipe for that container.
|
||||
This check can be expensive if 64 total crafts are being performed with the recipe matching logic
|
||||
being run 64 * 9 + 64 times. A breakdown of those times is below. This patch caches the last matching
|
||||
recipe so that it is checked first and only if it doesn't match does the rest of the matching logic run.
|
||||
|
||||
Shift-click crafts are processed one at a time, so shift clicking on an item in the result of a iron block craft
|
||||
where all the 9 inputs are full stacks of iron will run 64 iron block crafts. For each of those crafts, the
|
||||
'remaining' blocks are calculated. This is due to recipes that have leftover items like buckets. This is done
|
||||
for each craft, and done once to get the full 9 leftover items which are usually air. Then 1 item is removed
|
||||
from each of the 9 inputs and each time that happens, logic is triggered to update the result itemstack. So
|
||||
for each craft, that logic is run 9 times (hence the 64 * 9). The + 64 is from the 64 checks for remaining items.
|
||||
|
||||
After this patch, the full iteration over all recipes checking for a match should run once for a full craft to find the
|
||||
initial recipe match. Then that recipe will be checked first for all future recipe match checks.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/inventory/CraftingContainer.java b/src/main/java/net/minecraft/world/inventory/CraftingContainer.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/inventory/CraftingContainer.java
|
||||
+++ b/src/main/java/net/minecraft/world/inventory/CraftingContainer.java
|
||||
@@ -0,0 +0,0 @@ public interface CraftingContainer extends Container, StackedContentsCompatible
|
||||
List<ItemStack> getItems();
|
||||
|
||||
// CraftBukkit start
|
||||
- default RecipeHolder<?> getCurrentRecipe() {
|
||||
+ default RecipeHolder<net.minecraft.world.item.crafting.CraftingRecipe> getCurrentRecipe() { // Paper - use correct generic
|
||||
return null;
|
||||
}
|
||||
|
||||
- default void setCurrentRecipe(RecipeHolder<?> recipe) {
|
||||
+ default void setCurrentRecipe(RecipeHolder<net.minecraft.world.item.crafting.CraftingRecipe> recipe) { // Paper - use correct generic
|
||||
}
|
||||
// CraftBukkit end
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/inventory/CraftingMenu.java b/src/main/java/net/minecraft/world/inventory/CraftingMenu.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/inventory/CraftingMenu.java
|
||||
+++ b/src/main/java/net/minecraft/world/inventory/CraftingMenu.java
|
||||
@@ -0,0 +0,0 @@ public class CraftingMenu extends AbstractCraftingMenu {
|
||||
CraftingInput craftinginput = craftingInventory.asCraftInput();
|
||||
ServerPlayer entityplayer = (ServerPlayer) player;
|
||||
ItemStack itemstack = ItemStack.EMPTY;
|
||||
+ if (recipe == null) recipe = craftingInventory.getCurrentRecipe(); // Paper - Perf: Improve mass crafting; check last recipe used first
|
||||
Optional<RecipeHolder<CraftingRecipe>> optional = world.getServer().getRecipeManager().getRecipeFor(RecipeType.CRAFTING, craftinginput, world, recipe);
|
||||
craftingInventory.setCurrentRecipe(optional.orElse(null)); // CraftBukkit
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/inventory/ResultSlot.java b/src/main/java/net/minecraft/world/inventory/ResultSlot.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/inventory/ResultSlot.java
|
||||
+++ b/src/main/java/net/minecraft/world/inventory/ResultSlot.java
|
||||
@@ -0,0 +0,0 @@ public class ResultSlot extends Slot {
|
||||
private NonNullList<ItemStack> getRemainingItems(CraftingInput input, Level world) {
|
||||
return world instanceof ServerLevel serverLevel
|
||||
? serverLevel.recipeAccess()
|
||||
- .getRecipeFor(RecipeType.CRAFTING, input, serverLevel)
|
||||
+ .getRecipeFor(RecipeType.CRAFTING, input, serverLevel, this.craftSlots.getCurrentRecipe()) // Paper - Perf: Improve mass crafting; check last recipe used first
|
||||
.map(recipe -> recipe.value().getRemainingItems(input))
|
||||
.orElseGet(() -> copyAllInputItems(input))
|
||||
: CraftingRecipe.defaultCraftingReminder(input);
|
||||
diff --git a/src/main/java/net/minecraft/world/inventory/TransientCraftingContainer.java b/src/main/java/net/minecraft/world/inventory/TransientCraftingContainer.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/inventory/TransientCraftingContainer.java
|
||||
+++ b/src/main/java/net/minecraft/world/inventory/TransientCraftingContainer.java
|
||||
@@ -0,0 +0,0 @@ public class TransientCraftingContainer implements CraftingContainer {
|
||||
|
||||
// CraftBukkit start - add fields
|
||||
public List<HumanEntity> transaction = new java.util.ArrayList<HumanEntity>();
|
||||
- private RecipeHolder<?> currentRecipe;
|
||||
+ private RecipeHolder<net.minecraft.world.item.crafting.CraftingRecipe> currentRecipe; // Paper - use correct generic
|
||||
public Container resultInventory;
|
||||
private Player owner;
|
||||
private int maxStack = MAX_STACK;
|
||||
@@ -0,0 +0,0 @@ public class TransientCraftingContainer implements CraftingContainer {
|
||||
}
|
||||
|
||||
@Override
|
||||
- public RecipeHolder<?> getCurrentRecipe() {
|
||||
+ public RecipeHolder<net.minecraft.world.item.crafting.CraftingRecipe> getCurrentRecipe() { // Paper - use correct generic
|
||||
return this.currentRecipe;
|
||||
}
|
||||
|
||||
@Override
|
||||
- public void setCurrentRecipe(RecipeHolder<?> currentRecipe) {
|
||||
+ public void setCurrentRecipe(RecipeHolder<net.minecraft.world.item.crafting.CraftingRecipe> currentRecipe) { // Paper - use correct generic
|
||||
this.currentRecipe = currentRecipe;
|
||||
}
|
||||
|
|
@ -1,129 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Sat, 23 Sep 2023 22:05:35 -0700
|
||||
Subject: [PATCH] Lag compensation ticks
|
||||
|
||||
Areas affected by lag comepnsation:
|
||||
- Block breaking and destroying
|
||||
- Eating food items
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
|
||||
public volatile Thread shutdownThread; // Paper
|
||||
public volatile boolean abnormalExit = false; // Paper
|
||||
+ public static final long SERVER_INIT = System.nanoTime(); // Paper - Lag compensation
|
||||
|
||||
public static <S extends MinecraftServer> S spin(Function<Thread, S> serverFactory) {
|
||||
ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.init(); // Paper - rewrite data converter system
|
||||
@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
worldserver.hasPhysicsEvent = org.bukkit.event.block.BlockPhysicsEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - BlockPhysicsEvent
|
||||
worldserver.hasEntityMoveEvent = io.papermc.paper.event.entity.EntityMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - Add EntityMoveEvent
|
||||
net.minecraft.world.level.block.entity.HopperBlockEntity.skipHopperEvents = worldserver.paperConfig().hopper.disableMoveEvent || org.bukkit.event.inventory.InventoryMoveItemEvent.getHandlerList().getRegisteredListeners().length == 0; // Paper - Perf: Optimize Hoppers
|
||||
+ worldserver.updateLagCompensationTick(); // Paper - lag compensation
|
||||
|
||||
gameprofilerfiller.push(() -> {
|
||||
String s = String.valueOf(worldserver);
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
);
|
||||
}
|
||||
// Paper end - chunk tick iteration
|
||||
+ // Paper start - lag compensation
|
||||
+ private long lagCompensationTick = net.minecraft.server.MinecraftServer.SERVER_INIT;
|
||||
+
|
||||
+ public long getLagCompensationTick() {
|
||||
+ return this.lagCompensationTick;
|
||||
+ }
|
||||
+
|
||||
+ public void updateLagCompensationTick() {
|
||||
+ this.lagCompensationTick = (System.nanoTime() - net.minecraft.server.MinecraftServer.SERVER_INIT) / (java.util.concurrent.TimeUnit.MILLISECONDS.toNanos(50L));
|
||||
+ }
|
||||
+ // Paper end - lag compensation
|
||||
|
||||
// Add env and gen to constructor, IWorldDataServer -> WorldDataServer
|
||||
public ServerLevel(MinecraftServer minecraftserver, Executor executor, LevelStorageSource.LevelStorageAccess convertable_conversionsession, PrimaryLevelData iworlddataserver, ResourceKey<Level> resourcekey, LevelStem worlddimension, ChunkProgressListener worldloadlistener, boolean flag, long i, List<CustomSpawner> list, boolean flag1, @Nullable RandomSequences randomsequences, org.bukkit.World.Environment env, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider) {
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
|
||||
@@ -0,0 +0,0 @@ public class ServerPlayerGameMode {
|
||||
}
|
||||
|
||||
public void tick() {
|
||||
- this.gameTicks = MinecraftServer.currentTick; // CraftBukkit;
|
||||
+ this.gameTicks = (int)this.level.getLagCompensationTick(); // CraftBukkit; // Paper - lag compensation
|
||||
BlockState iblockdata;
|
||||
|
||||
if (this.hasDelayedDestroy) {
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -0,0 +0,0 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
this.resendPossiblyDesyncedDataValues(java.util.List.of(DATA_LIVING_ENTITY_FLAGS), serverPlayer);
|
||||
}
|
||||
// Paper end - Properly cancel usable items
|
||||
+ // Paper start - lag compensate eating
|
||||
+ protected long eatStartTime;
|
||||
+ protected int totalEatTimeTicks;
|
||||
+ // Paper end - lag compensate eating
|
||||
private void updatingUsingItem() {
|
||||
if (this.isUsingItem()) {
|
||||
if (ItemStack.isSameItem(this.getItemInHand(this.getUsedItemHand()), this.useItem)) {
|
||||
@@ -0,0 +0,0 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
|
||||
protected void updateUsingItem(ItemStack stack) {
|
||||
stack.onUseTick(this.level(), this, this.getUseItemRemainingTicks());
|
||||
- if (--this.useItemRemaining == 0 && !this.level().isClientSide && !stack.useOnRelease()) {
|
||||
+ // Paper start - lag compensate eating
|
||||
+ // we add 1 to the expected time to avoid lag compensating when we should not
|
||||
+ final boolean shouldLagCompensate = this.useItem.has(DataComponents.FOOD) && this.eatStartTime != -1 && (System.nanoTime() - this.eatStartTime) > ((1L + this.totalEatTimeTicks) * 50L * (1000L * 1000L));
|
||||
+ if ((--this.useItemRemaining == 0 || shouldLagCompensate) && !this.level().isClientSide && !stack.useOnRelease()) {
|
||||
+ this.useItemRemaining = 0;
|
||||
+ // Paper end - lag compensate eating
|
||||
this.completeUsingItem();
|
||||
}
|
||||
|
||||
@@ -0,0 +0,0 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
|
||||
if (!itemstack.isEmpty() && !this.isUsingItem() || forceUpdate) { // Paper - Prevent consuming the wrong itemstack
|
||||
this.useItem = itemstack;
|
||||
- this.useItemRemaining = itemstack.getUseDuration(this);
|
||||
+ // Paper start - lag compensate eating
|
||||
+ this.useItemRemaining = this.totalEatTimeTicks = itemstack.getUseDuration(this);
|
||||
+ this.eatStartTime = System.nanoTime();
|
||||
+ // Paper end - lag compensate eating
|
||||
if (!this.level().isClientSide) {
|
||||
this.setLivingEntityFlag(1, true);
|
||||
this.setLivingEntityFlag(2, hand == InteractionHand.OFF_HAND);
|
||||
@@ -0,0 +0,0 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
}
|
||||
} else if (!this.isUsingItem() && !this.useItem.isEmpty()) {
|
||||
this.useItem = ItemStack.EMPTY;
|
||||
- this.useItemRemaining = 0;
|
||||
+ // Paper start - lag compensate eating
|
||||
+ this.useItemRemaining = this.totalEatTimeTicks = 0;
|
||||
+ this.eatStartTime = -1L;
|
||||
+ // Paper end - lag compensate eating
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +0,0 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
}
|
||||
|
||||
this.useItem = ItemStack.EMPTY;
|
||||
- this.useItemRemaining = 0;
|
||||
+ // Paper start - lag compensate eating
|
||||
+ this.useItemRemaining = this.totalEatTimeTicks = 0;
|
||||
+ this.eatStartTime = -1L;
|
||||
+ // Paper end - lag compensate eating
|
||||
}
|
||||
|
||||
public boolean isBlocking() {
|
|
@ -1,232 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: kickash32 <kickash32@gmail.com>
|
||||
Date: Mon, 19 Aug 2019 01:27:58 +0500
|
||||
Subject: [PATCH] Optional per player mob spawns
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
}
|
||||
|
||||
// Paper start
|
||||
+ // Paper start - Optional per player mob spawns
|
||||
+ public void updatePlayerMobTypeMap(final Entity entity) {
|
||||
+ if (!this.level.paperConfig().entities.spawning.perPlayerMobSpawns) {
|
||||
+ return;
|
||||
+ }
|
||||
+ final int index = entity.getType().getCategory().ordinal();
|
||||
+
|
||||
+ final ca.spottedleaf.moonrise.common.list.ReferenceList<ServerPlayer> inRange =
|
||||
+ this.level.moonrise$getNearbyPlayers().getPlayers(entity.chunkPosition(), ca.spottedleaf.moonrise.common.misc.NearbyPlayers.NearbyMapType.TICK_VIEW_DISTANCE);
|
||||
+ if (inRange == null) {
|
||||
+ return;
|
||||
+ }
|
||||
+ final ServerPlayer[] backingSet = inRange.getRawDataUnchecked();
|
||||
+ for (int i = 0, len = inRange.size(); i < len; i++) {
|
||||
+ ++(backingSet[i].mobCounts[index]);
|
||||
+ }
|
||||
+ }
|
||||
public int getMobCountNear(final ServerPlayer player, final net.minecraft.world.entity.MobCategory mobCategory) {
|
||||
- return -1;
|
||||
+ return player.mobCounts[mobCategory.ordinal()];
|
||||
+ // Paper end - Optional per player mob spawns
|
||||
}
|
||||
// Paper end
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
||||
gameprofilerfiller.popPush("shuffleChunks");
|
||||
// Paper start - chunk tick iteration optimisation
|
||||
this.shuffleRandom.setSeed(this.level.random.nextLong());
|
||||
- Util.shuffle(list, this.shuffleRandom);
|
||||
+ if (!this.level.paperConfig().entities.spawning.perPlayerMobSpawns) Util.shuffle(list, this.shuffleRandom); // Paper - Optional per player mob spawns; do not need this when per-player is enabled
|
||||
// Paper end - chunk tick iteration optimisation
|
||||
this.tickChunks(gameprofilerfiller, j, list);
|
||||
gameprofilerfiller.pop();
|
||||
@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
||||
private void tickChunks(ProfilerFiller profiler, long timeDelta, List<LevelChunk> chunks) {
|
||||
profiler.popPush("naturalSpawnCount");
|
||||
int j = this.distanceManager.getNaturalSpawnChunkCount();
|
||||
- NaturalSpawner.SpawnState spawnercreature_d = NaturalSpawner.createState(j, this.level.getAllEntities(), this::getFullChunk, new LocalMobCapCalculator(this.chunkMap));
|
||||
+ // Paper start - Optional per player mob spawns
|
||||
+ final int naturalSpawnChunkCount = j;
|
||||
+ NaturalSpawner.SpawnState spawnercreature_d; // moved down
|
||||
+ if ((this.spawnFriendlies || this.spawnEnemies) && this.level.paperConfig().entities.spawning.perPlayerMobSpawns) { // don't count mobs when animals and monsters are disabled
|
||||
+ // re-set mob counts
|
||||
+ for (ServerPlayer player : this.level.players) {
|
||||
+ Arrays.fill(player.mobCounts, 0);
|
||||
+ }
|
||||
+ spawnercreature_d = NaturalSpawner.createState(naturalSpawnChunkCount, this.level.getAllEntities(), this::getFullChunk, null, true);
|
||||
+ } else {
|
||||
+ spawnercreature_d = NaturalSpawner.createState(naturalSpawnChunkCount, this.level.getAllEntities(), this::getFullChunk, !this.level.paperConfig().entities.spawning.perPlayerMobSpawns ? new LocalMobCapCalculator(this.chunkMap) : null, false);
|
||||
+ }
|
||||
+ // Paper end - Optional per player mob spawns
|
||||
|
||||
this.lastSpawnState = spawnercreature_d;
|
||||
profiler.popPush("spawnAndTick");
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -0,0 +0,0 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player imple
|
||||
public boolean queueHealthUpdatePacket;
|
||||
public net.minecraft.network.protocol.game.ClientboundSetHealthPacket queuedHealthUpdatePacket;
|
||||
// Paper end - cancellable death event
|
||||
+ // Paper start - Optional per player mob spawns
|
||||
+ public static final int MOBCATEGORY_TOTAL_ENUMS = net.minecraft.world.entity.MobCategory.values().length;
|
||||
+ public final int[] mobCounts = new int[MOBCATEGORY_TOTAL_ENUMS]; // Paper
|
||||
+ // Paper end - Optional per player mob spawns
|
||||
|
||||
// CraftBukkit start
|
||||
public CraftPlayer.TransferCookieConnection transferCookieConnection;
|
||||
diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
|
||||
@@ -0,0 +0,0 @@ public final class NaturalSpawner {
|
||||
private NaturalSpawner() {}
|
||||
|
||||
public static NaturalSpawner.SpawnState createState(int spawningChunkCount, Iterable<Entity> entities, NaturalSpawner.ChunkGetter chunkSource, LocalMobCapCalculator densityCapper) {
|
||||
+ // Paper start - Optional per player mob spawns
|
||||
+ return createState(spawningChunkCount, entities, chunkSource, densityCapper, false);
|
||||
+ }
|
||||
+
|
||||
+ public static NaturalSpawner.SpawnState createState(int spawningChunkCount, Iterable<Entity> entities, NaturalSpawner.ChunkGetter chunkSource, LocalMobCapCalculator densityCapper, boolean countMobs) {
|
||||
+ // Paper end - Optional per player mob spawns
|
||||
PotentialCalculator spawnercreatureprobabilities = new PotentialCalculator();
|
||||
Object2IntOpenHashMap<MobCategory> object2intopenhashmap = new Object2IntOpenHashMap();
|
||||
Iterator iterator = entities.iterator();
|
||||
@@ -0,0 +0,0 @@ public final class NaturalSpawner {
|
||||
spawnercreatureprobabilities.addCharge(entity.blockPosition(), biomesettingsmobs_b.charge());
|
||||
}
|
||||
|
||||
- if (entity instanceof Mob) {
|
||||
+ if (densityCapper != null && entity instanceof Mob) { // Paper - Optional per player mob spawns
|
||||
densityCapper.addMob(chunk.getPos(), enumcreaturetype);
|
||||
}
|
||||
|
||||
object2intopenhashmap.addTo(enumcreaturetype, 1);
|
||||
+ // Paper start - Optional per player mob spawns
|
||||
+ if (countMobs) {
|
||||
+ chunk.level.getChunkSource().chunkMap.updatePlayerMobTypeMap(entity);
|
||||
+ }
|
||||
+ // Paper end - Optional per player mob spawns
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +0,0 @@ public final class NaturalSpawner {
|
||||
continue;
|
||||
}
|
||||
|
||||
- if ((flag || !enumcreaturetype.isFriendly()) && (flag1 || enumcreaturetype.isFriendly()) && (flag2 || !enumcreaturetype.isPersistent()) && spawnercreature_d.canSpawnForCategoryGlobal(enumcreaturetype, limit)) {
|
||||
+ if ((flag || !enumcreaturetype.isFriendly()) && (flag1 || enumcreaturetype.isFriendly()) && (flag2 || !enumcreaturetype.isPersistent()) && (worldserver.paperConfig().entities.spawning.perPlayerMobSpawns || spawnercreature_d.canSpawnForCategoryGlobal(enumcreaturetype, limit))) { // Paper - Optional per player mob spawns; remove global check, check later during the local one
|
||||
// CraftBukkit end
|
||||
list.add(enumcreaturetype);
|
||||
}
|
||||
@@ -0,0 +0,0 @@ public final class NaturalSpawner {
|
||||
while (iterator.hasNext()) {
|
||||
MobCategory enumcreaturetype = (MobCategory) iterator.next();
|
||||
|
||||
- if (info.canSpawnForCategoryLocal(enumcreaturetype, chunk.getPos())) {
|
||||
+ // Paper start - Optional per player mob spawns
|
||||
+ final boolean canSpawn;
|
||||
+ int maxSpawns = Integer.MAX_VALUE;
|
||||
+ if (world.paperConfig().entities.spawning.perPlayerMobSpawns) {
|
||||
+ // Copied from getFilteredSpawningCategories
|
||||
+ int limit = enumcreaturetype.getMaxInstancesPerChunk();
|
||||
+ SpawnCategory spawnCategory = CraftSpawnCategory.toBukkit(enumcreaturetype);
|
||||
+ if (CraftSpawnCategory.isValidForLimits(spawnCategory)) {
|
||||
+ limit = world.getWorld().getSpawnLimit(spawnCategory);
|
||||
+ }
|
||||
+
|
||||
+ // Apply per-player limit
|
||||
+ int minDiff = Integer.MAX_VALUE;
|
||||
+ final ca.spottedleaf.moonrise.common.list.ReferenceList<net.minecraft.server.level.ServerPlayer> inRange =
|
||||
+ world.moonrise$getNearbyPlayers().getPlayers(chunk.getPos(), ca.spottedleaf.moonrise.common.misc.NearbyPlayers.NearbyMapType.TICK_VIEW_DISTANCE);
|
||||
+ if (inRange != null) {
|
||||
+ final net.minecraft.server.level.ServerPlayer[] backingSet = inRange.getRawDataUnchecked();
|
||||
+ for (int k = 0, len = inRange.size(); k < len; k++) {
|
||||
+ minDiff = Math.min(limit - world.getChunkSource().chunkMap.getMobCountNear(backingSet[k], enumcreaturetype), minDiff);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ maxSpawns = (minDiff == Integer.MAX_VALUE) ? 0 : minDiff;
|
||||
+ canSpawn = maxSpawns > 0;
|
||||
+ } else {
|
||||
+ canSpawn = info.canSpawnForCategoryLocal(enumcreaturetype, chunk.getPos());
|
||||
+ }
|
||||
+ if (canSpawn) {
|
||||
+ // Paper end - Optional per player mob spawns
|
||||
Objects.requireNonNull(info);
|
||||
NaturalSpawner.SpawnPredicate spawnercreature_c = info::canSpawn;
|
||||
|
||||
Objects.requireNonNull(info);
|
||||
- NaturalSpawner.spawnCategoryForChunk(enumcreaturetype, world, chunk, spawnercreature_c, info::afterSpawn);
|
||||
+ // Paper start - Optional per player mob spawns
|
||||
+ NaturalSpawner.spawnCategoryForChunk(enumcreaturetype, world, chunk, spawnercreature_c, info::afterSpawn,
|
||||
+ maxSpawns, world.paperConfig().entities.spawning.perPlayerMobSpawns ? world.getChunkSource().chunkMap::updatePlayerMobTypeMap : null);
|
||||
+ // Paper end - Optional per player mob spawns
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +0,0 @@ public final class NaturalSpawner {
|
||||
// Paper end - Add mobcaps commands
|
||||
|
||||
public static void spawnCategoryForChunk(MobCategory group, ServerLevel world, LevelChunk chunk, NaturalSpawner.SpawnPredicate checker, NaturalSpawner.AfterSpawnCallback runner) {
|
||||
+ // Paper start - Optional per player mob spawns
|
||||
+ spawnCategoryForChunk(group, world, chunk, checker, runner, Integer.MAX_VALUE, null);
|
||||
+ }
|
||||
+ public static void spawnCategoryForChunk(MobCategory group, ServerLevel world, LevelChunk chunk, NaturalSpawner.SpawnPredicate checker, NaturalSpawner.AfterSpawnCallback runner, int maxSpawns, Consumer<Entity> trackEntity) {
|
||||
+ // Paper end - Optional per player mob spawns
|
||||
BlockPos blockposition = NaturalSpawner.getRandomPosWithin(world, chunk);
|
||||
|
||||
if (blockposition.getY() >= world.getMinY() + 1) {
|
||||
- NaturalSpawner.spawnCategoryForPosition(group, world, chunk, blockposition, checker, runner);
|
||||
+ NaturalSpawner.spawnCategoryForPosition(group, world, chunk, blockposition, checker, runner, maxSpawns, trackEntity); // Paper - Optional per player mob spawns
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +0,0 @@ public final class NaturalSpawner {
|
||||
});
|
||||
}
|
||||
|
||||
+ // Paper start - Optional per player mob spawns
|
||||
public static void spawnCategoryForPosition(MobCategory group, ServerLevel world, ChunkAccess chunk, BlockPos pos, NaturalSpawner.SpawnPredicate checker, NaturalSpawner.AfterSpawnCallback runner) {
|
||||
+ spawnCategoryForPosition(group, world,chunk, pos, checker, runner, Integer.MAX_VALUE, null);
|
||||
+ }
|
||||
+ public static void spawnCategoryForPosition(MobCategory group, ServerLevel world, ChunkAccess chunk, BlockPos pos, NaturalSpawner.SpawnPredicate checker, NaturalSpawner.AfterSpawnCallback runner, int maxSpawns, Consumer<Entity> trackEntity) {
|
||||
+ // Paper end - Optional per player mob spawns
|
||||
StructureManager structuremanager = world.structureManager();
|
||||
ChunkGenerator chunkgenerator = world.getChunkSource().getGenerator();
|
||||
int i = pos.getY();
|
||||
@@ -0,0 +0,0 @@ public final class NaturalSpawner {
|
||||
++j;
|
||||
++k1;
|
||||
runner.run(entityinsentient, chunk);
|
||||
+ // Paper start - Optional per player mob spawns
|
||||
+ if (trackEntity != null) {
|
||||
+ trackEntity.accept(entityinsentient);
|
||||
+ }
|
||||
+ // Paper end - Optional per player mob spawns
|
||||
}
|
||||
// CraftBukkit end
|
||||
- if (j >= entityinsentient.getMaxSpawnClusterSize()) {
|
||||
+ if (j >= entityinsentient.getMaxSpawnClusterSize() || j >= maxSpawns) { // Paper - Optional per player mob spawns
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -0,0 +0,0 @@ public final class NaturalSpawner {
|
||||
MobCategory enumcreaturetype = entitytypes.getCategory();
|
||||
|
||||
this.mobCategoryCounts.addTo(enumcreaturetype, 1);
|
||||
- this.localMobCapCalculator.addMob(new ChunkPos(blockposition), enumcreaturetype);
|
||||
+ if (this.localMobCapCalculator != null) this.localMobCapCalculator.addMob(new ChunkPos(blockposition), enumcreaturetype); // Paper - Optional per player mob spawns
|
||||
}
|
||||
|
||||
public int getSpawnableChunkCount() {
|
|
@ -1,89 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: kickash32 <kickash32@gmail.com>
|
||||
Date: Mon, 5 Apr 2021 01:42:35 -0400
|
||||
Subject: [PATCH] Improve cancelling PreCreatureSpawnEvent with per player mob
|
||||
spawns
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
++(backingSet[i].mobCounts[index]);
|
||||
}
|
||||
}
|
||||
+ // Paper start - per player mob count backoff
|
||||
+ public void updateFailurePlayerMobTypeMap(int chunkX, int chunkZ, net.minecraft.world.entity.MobCategory mobCategory) {
|
||||
+ if (!this.level.paperConfig().entities.spawning.perPlayerMobSpawns) {
|
||||
+ return;
|
||||
+ }
|
||||
+ int idx = mobCategory.ordinal();
|
||||
+ final ca.spottedleaf.moonrise.common.list.ReferenceList<ServerPlayer> inRange =
|
||||
+ this.level.moonrise$getNearbyPlayers().getPlayersByChunk(chunkX, chunkZ, ca.spottedleaf.moonrise.common.misc.NearbyPlayers.NearbyMapType.TICK_VIEW_DISTANCE);
|
||||
+ if (inRange == null) {
|
||||
+ return;
|
||||
+ }
|
||||
+ final ServerPlayer[] backingSet = inRange.getRawDataUnchecked();
|
||||
+ for (int i = 0, len = inRange.size(); i < len; i++) {
|
||||
+ ++(backingSet[i].mobBackoffCounts[idx]);
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - per player mob count backoff
|
||||
public int getMobCountNear(final ServerPlayer player, final net.minecraft.world.entity.MobCategory mobCategory) {
|
||||
- return player.mobCounts[mobCategory.ordinal()];
|
||||
+ return player.mobCounts[mobCategory.ordinal()] + player.mobBackoffCounts[mobCategory.ordinal()]; // Paper - per player mob count backoff
|
||||
// Paper end - Optional per player mob spawns
|
||||
}
|
||||
// Paper end
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
||||
if ((this.spawnFriendlies || this.spawnEnemies) && this.level.paperConfig().entities.spawning.perPlayerMobSpawns) { // don't count mobs when animals and monsters are disabled
|
||||
// re-set mob counts
|
||||
for (ServerPlayer player : this.level.players) {
|
||||
- Arrays.fill(player.mobCounts, 0);
|
||||
+ // Paper start - per player mob spawning backoff
|
||||
+ for (int ii = 0; ii < ServerPlayer.MOBCATEGORY_TOTAL_ENUMS; ii++) {
|
||||
+ player.mobCounts[ii] = 0;
|
||||
+
|
||||
+ int newBackoff = player.mobBackoffCounts[ii] - 1; // TODO make configurable bleed // TODO use nonlinear algorithm?
|
||||
+ if (newBackoff < 0) {
|
||||
+ newBackoff = 0;
|
||||
+ }
|
||||
+ player.mobBackoffCounts[ii] = newBackoff;
|
||||
+ }
|
||||
+ // Paper end - per player mob spawning backoff
|
||||
}
|
||||
spawnercreature_d = NaturalSpawner.createState(naturalSpawnChunkCount, this.level.getAllEntities(), this::getFullChunk, null, true);
|
||||
} else {
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -0,0 +0,0 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player imple
|
||||
public static final int MOBCATEGORY_TOTAL_ENUMS = net.minecraft.world.entity.MobCategory.values().length;
|
||||
public final int[] mobCounts = new int[MOBCATEGORY_TOTAL_ENUMS]; // Paper
|
||||
// Paper end - Optional per player mob spawns
|
||||
+ public final int[] mobBackoffCounts = new int[MOBCATEGORY_TOTAL_ENUMS]; // Paper - per player mob count backoff
|
||||
|
||||
// CraftBukkit start
|
||||
public CraftPlayer.TransferCookieConnection transferCookieConnection;
|
||||
diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
|
||||
@@ -0,0 +0,0 @@ public final class NaturalSpawner {
|
||||
|
||||
// Paper start - PreCreatureSpawnEvent
|
||||
PreSpawnStatus doSpawning = isValidSpawnPostitionForType(world, group, structuremanager, chunkgenerator, biomesettingsmobs_c, blockposition_mutableblockposition, d2);
|
||||
+ // Paper start - per player mob count backoff
|
||||
+ if (doSpawning == PreSpawnStatus.ABORT || doSpawning == PreSpawnStatus.CANCELLED) {
|
||||
+ world.getChunkSource().chunkMap.updateFailurePlayerMobTypeMap(blockposition_mutableblockposition.getX() >> 4, blockposition_mutableblockposition.getZ() >> 4, group);
|
||||
+ }
|
||||
+ // Paper end - per player mob count backoff
|
||||
if (doSpawning == PreSpawnStatus.ABORT) {
|
||||
return;
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Flo0 <flo.roma@web.de>
|
||||
Date: Thu, 5 Dec 2024 12:15:07 +0100
|
||||
Subject: [PATCH] Implement chunk view API
|
||||
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/FeatureHooks.java b/src/main/java/io/papermc/paper/FeatureHooks.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/io/papermc/paper/FeatureHooks.java
|
||||
+++ b/src/main/java/io/papermc/paper/FeatureHooks.java
|
||||
@@ -0,0 +0,0 @@ package io.papermc.paper;
|
||||
import io.papermc.paper.command.PaperSubcommand;
|
||||
import io.papermc.paper.command.subcommands.ChunkDebugCommand;
|
||||
import io.papermc.paper.command.subcommands.FixLightCommand;
|
||||
+import it.unimi.dsi.fastutil.longs.LongIterator;
|
||||
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
|
||||
-import it.unimi.dsi.fastutil.longs.LongSet;
|
||||
import it.unimi.dsi.fastutil.longs.LongSets;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectSet;
|
||||
@@ -0,0 +0,0 @@ public final class FeatureHooks {
|
||||
}
|
||||
|
||||
public static Set<Long> getSentChunkKeys(final ServerPlayer player) {
|
||||
- final LongSet keys = new LongOpenHashSet();
|
||||
- player.getChunkTrackingView().forEach(pos -> keys.add(pos.longKey));
|
||||
- return LongSets.unmodifiable(keys);
|
||||
+ return LongSets.unmodifiable(player.moonrise$getChunkLoader().getSentChunksRaw().clone());
|
||||
}
|
||||
|
||||
public static Set<Chunk> getSentChunks(final ServerPlayer player) {
|
||||
- final ObjectSet<Chunk> chunks = new ObjectOpenHashSet<>();
|
||||
+ final LongOpenHashSet rawChunkKeys = player.moonrise$getChunkLoader().getSentChunksRaw();
|
||||
+ final ObjectSet<org.bukkit.Chunk> chunks = new ObjectOpenHashSet<>(rawChunkKeys.size());
|
||||
final World world = player.serverLevel().getWorld();
|
||||
- player.getChunkTrackingView().forEach(pos -> {
|
||||
- final org.bukkit.Chunk chunk = world.getChunkAt(pos.longKey);
|
||||
- chunks.add(chunk);
|
||||
- });
|
||||
+ final LongIterator iter = player.moonrise$getChunkLoader().getSentChunksRaw().longIterator();
|
||||
+ while (iter.hasNext()) {
|
||||
+ chunks.add(world.getChunkAt(iter.nextLong(), false));
|
||||
+ }
|
||||
return ObjectSets.unmodifiable(chunks);
|
||||
}
|
||||
|
||||
public static boolean isChunkSent(final ServerPlayer player, final long chunkKey) {
|
||||
- return player.getChunkTrackingView().contains(new ChunkPos(chunkKey));
|
||||
+ return player.moonrise$getChunkLoader().getSentChunksRaw().contains(chunkKey);
|
||||
}
|
||||
}
|
|
@ -4,8 +4,7 @@ mcVersion=1.21.4
|
|||
|
||||
# Set to true while updating Minecraft version
|
||||
updatingMinecraft=false
|
||||
#cleanPaperRepo=~/IdeaProjects/Paper/Paper-Server/src/main/java
|
||||
updateTaskListIssue=https://github.com/PaperMC/testing/issues/2
|
||||
updateTaskListIssue=https://github.com/PaperMC/Paper/issues/11736
|
||||
|
||||
org.gradle.configuration-cache=true
|
||||
org.gradle.caching=true
|
||||
|
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
|
@ -1,6 +1,6 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
|
3
gradlew
vendored
3
gradlew
vendored
|
@ -86,8 +86,7 @@ done
|
|||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
|
||||
' "$PWD" ) || exit
|
||||
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
|
|
|
@ -39,7 +39,7 @@ abstract class MockitoAgentProvider : CommandLineArgumentProvider {
|
|||
// Paper end - configure mockito agent that is needed in newer java versions
|
||||
|
||||
dependencies {
|
||||
api("com.mojang:brigadier:1.2.9") // Paper - Brigadier command api
|
||||
api("com.mojang:brigadier:1.3.10") // Paper - Brigadier command api
|
||||
// api dependencies are listed transitively to API consumers
|
||||
api("com.google.guava:guava:33.3.1-jre")
|
||||
api("com.google.code.gson:gson:2.11.0")
|
||||
|
@ -92,6 +92,7 @@ dependencies {
|
|||
testImplementation("org.mockito:mockito-core:5.14.1")
|
||||
testImplementation("org.ow2.asm:asm-tree:9.7.1")
|
||||
mockitoAgent("org.mockito:mockito-core:5.14.1") { isTransitive = false } // Paper - configure mockito agent that is needed in newer java versions
|
||||
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
|
||||
}
|
||||
|
||||
// Paper start
|
||||
|
@ -121,8 +122,13 @@ configurations {
|
|||
}
|
||||
outgoing {
|
||||
capability(mainCapability)
|
||||
// Paper-MojangAPI has been merged into Paper-API
|
||||
capability("io.papermc.paper:paper-mojangapi:${project.version}")
|
||||
capability("com.destroystokyo.paper:paper-mojangapi:${project.version}")
|
||||
// Conflict with old coordinates
|
||||
capability("com.destroystokyo.paper:paper-api:${project.version}")
|
||||
capability("org.spigotmc:spigot-api:${project.version}")
|
||||
capability("org.bukkit:bukkit:${project.version}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,7 +55,7 @@ public class BlockDestroyEvent extends BlockExpEvent implements Cancellable {
|
|||
* @param effectBlock block effect
|
||||
*/
|
||||
public void setEffectBlock(final BlockData effectBlock) {
|
||||
this.effectBlock = effectBlock;
|
||||
this.effectBlock = effectBlock.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -79,7 +79,7 @@ public class PlayerJumpEvent extends PlayerEvent implements Cancellable {
|
|||
public void setFrom(final Location from) {
|
||||
Preconditions.checkArgument(from != null, "Cannot use null from location!");
|
||||
Preconditions.checkArgument(from.getWorld() != null, "Cannot use from location with null world!");
|
||||
this.from = from;
|
||||
this.from = from.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -66,7 +66,7 @@ public class PlayerSetSpawnEvent extends PlayerEvent implements Cancellable {
|
|||
* @param location the spawn location, or {@code null} to remove the spawn location
|
||||
*/
|
||||
public void setLocation(final @Nullable Location location) {
|
||||
this.location = location;
|
||||
this.location = location != null ? location.clone() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -37,10 +37,31 @@ public interface CustomArgumentType<T, N> extends ArgumentType<T> {
|
|||
* @param reader string reader input
|
||||
* @return parsed value
|
||||
* @throws CommandSyntaxException if an error occurs while parsing
|
||||
* @see #parse(StringReader, Object)
|
||||
*/
|
||||
@Override
|
||||
T parse(final StringReader reader) throws CommandSyntaxException;
|
||||
|
||||
/**
|
||||
* Parses the argument into the custom type ({@code T}). Keep in mind
|
||||
* that this parsing will be done on the server. This means that if
|
||||
* you throw a {@link CommandSyntaxException} during parsing, this
|
||||
* will only show up to the user after the user has executed the command
|
||||
* not while they are still entering it.
|
||||
* <p>
|
||||
* This method provides the command source for additional context when parsing. You
|
||||
* may have to do your own {@code instanceof} checks for {@link io.papermc.paper.command.brigadier.CommandSourceStack}.
|
||||
*
|
||||
* @param reader string reader input
|
||||
* @param source source of the command
|
||||
* @return parsed value
|
||||
* @throws CommandSyntaxException if an error occurs while parsing
|
||||
*/
|
||||
@Override
|
||||
default <S> T parse(final StringReader reader, final S source) throws CommandSyntaxException {
|
||||
return ArgumentType.super.parse(reader, source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the native type that this argument uses,
|
||||
* the type that is sent to the client.
|
||||
|
@ -95,13 +116,35 @@ public interface CustomArgumentType<T, N> extends ArgumentType<T> {
|
|||
return this.convert(this.getNativeType().parse(reader));
|
||||
}
|
||||
|
||||
@ApiStatus.NonExtendable
|
||||
@Override
|
||||
default <S> T parse(final StringReader reader, final S source) throws CommandSyntaxException {
|
||||
return this.convert(this.getNativeType().parse(reader, source), source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the value from the native type to the custom argument type.
|
||||
*
|
||||
* @param nativeType native argument provided value
|
||||
* @return converted value
|
||||
* @throws CommandSyntaxException if an exception occurs while parsing
|
||||
* @see #convert(Object, Object)
|
||||
*/
|
||||
T convert(N nativeType) throws CommandSyntaxException;
|
||||
|
||||
/**
|
||||
* Converts the value from the native type to the custom argument type.
|
||||
* <p>
|
||||
* This method provides the command source for additional context when converting. You
|
||||
* may have to do your own {@code instanceof} checks for {@link io.papermc.paper.command.brigadier.CommandSourceStack}.
|
||||
*
|
||||
* @param nativeType native argument provided value
|
||||
* @param source source of the command
|
||||
* @return converted value
|
||||
* @throws CommandSyntaxException if an exception occurs while parsing
|
||||
*/
|
||||
default <S> T convert(final N nativeType, final S source) throws CommandSyntaxException {
|
||||
return this.convert(nativeType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ public class EntityMoveEvent extends EntityEvent implements Cancellable {
|
|||
*/
|
||||
public void setFrom(final Location from) {
|
||||
this.validateLocation(from);
|
||||
this.from = from;
|
||||
this.from = from.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -72,7 +72,7 @@ public class EntityMoveEvent extends EntityEvent implements Cancellable {
|
|||
*/
|
||||
public void setTo(final Location to) {
|
||||
this.validateLocation(to);
|
||||
this.to = to;
|
||||
this.to = to.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -52,7 +52,7 @@ public class WorldBorderCenterChangeEvent extends WorldBorderEvent implements Ca
|
|||
* @param newCenter the new center
|
||||
*/
|
||||
public void setNewCenter(final Location newCenter) {
|
||||
this.newCenter = newCenter;
|
||||
this.newCenter = newCenter.clone();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -30,9 +30,9 @@ public final class PotionMix implements Keyed {
|
|||
*/
|
||||
public PotionMix(final NamespacedKey key, final ItemStack result, final RecipeChoice input, final RecipeChoice ingredient) {
|
||||
this.key = key;
|
||||
this.result = result;
|
||||
this.input = input;
|
||||
this.ingredient = ingredient;
|
||||
this.result = result.clone();
|
||||
this.input = input.clone();
|
||||
this.ingredient = ingredient.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -58,7 +58,7 @@ public final class PotionMix implements Keyed {
|
|||
* @return the result itemstack
|
||||
*/
|
||||
public ItemStack getResult() {
|
||||
return this.result;
|
||||
return this.result.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -67,7 +67,7 @@ public final class PotionMix implements Keyed {
|
|||
* @return the bottom 3 slot ingredients
|
||||
*/
|
||||
public RecipeChoice getInput() {
|
||||
return this.input;
|
||||
return this.input.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -76,7 +76,7 @@ public final class PotionMix implements Keyed {
|
|||
* @return the top slot input
|
||||
*/
|
||||
public RecipeChoice getIngredient() {
|
||||
return this.ingredient;
|
||||
return this.ingredient.clone();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -79,7 +79,7 @@ public class Vibration {
|
|||
private final Location block;
|
||||
|
||||
public BlockDestination(@NotNull Location block) {
|
||||
this.block = block;
|
||||
this.block = block.clone();
|
||||
}
|
||||
|
||||
public BlockDestination(@NotNull Block block) {
|
||||
|
@ -88,7 +88,7 @@ public class Vibration {
|
|||
|
||||
@NotNull
|
||||
public Location getLocation() {
|
||||
return block;
|
||||
return block.clone();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
|
|
@ -191,7 +191,7 @@ public interface Mob extends LivingEntity, Lootable, io.papermc.paper.entity.Lea
|
|||
* set by {@link #setAggressive(boolean)}. {@link Panda}'s are always
|
||||
* aggressive if their combined {@link Panda.Gene} is {@link Panda.Gene#AGGRESSIVE}.
|
||||
*
|
||||
* @return wether the mob is aggressive or not
|
||||
* @return whether the mob is aggressive or not
|
||||
*/
|
||||
boolean isAggressive();
|
||||
|
||||
|
@ -199,7 +199,7 @@ public interface Mob extends LivingEntity, Lootable, io.papermc.paper.entity.Lea
|
|||
* Some mobs will raise their arm(s) when aggressive,
|
||||
* see {@link #isAggressive()} for full list.
|
||||
*
|
||||
* @param aggressive wether the mob should be aggressive or not
|
||||
* @param aggressive whether the mob should be aggressive or not
|
||||
* @see #isAggressive()
|
||||
*/
|
||||
void setAggressive(boolean aggressive);
|
||||
|
|
|
@ -65,7 +65,7 @@ public class BlockDispenseEvent extends BlockEvent implements Cancellable {
|
|||
* @param vel the velocity of the item being dispensed
|
||||
*/
|
||||
public void setVelocity(@NotNull Vector vel) {
|
||||
velocity = vel;
|
||||
velocity = vel.clone();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -43,7 +43,7 @@ public class FluidLevelChangeEvent extends BlockEvent implements Cancellable {
|
|||
Preconditions.checkArgument(newData != null, "newData null");
|
||||
Preconditions.checkArgument(this.newData.getMaterial().equals(newData.getMaterial()), "Cannot change fluid type");
|
||||
|
||||
this.newData = newData;
|
||||
this.newData = newData.clone();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -11,7 +11,7 @@ import org.jetbrains.annotations.Nullable;
|
|||
/**
|
||||
* Thrown whenever a LivingEntity dies
|
||||
*/
|
||||
public class EntityDeathEvent extends EntityEvent implements org.bukkit.event.Cancellable { // Paper - make cancellable
|
||||
public class EntityDeathEvent extends EntityEvent implements org.bukkit.event.Cancellable { // Paper - make cancellable
|
||||
private static final HandlerList handlers = new HandlerList();
|
||||
private final DamageSource damageSource;
|
||||
private final List<ItemStack> drops;
|
||||
|
|
|
@ -99,7 +99,7 @@ public class EntityKnockbackEvent extends EntityEvent implements Cancellable {
|
|||
public void setFinalKnockback(@NotNull Vector knockback) {
|
||||
Preconditions.checkArgument(knockback != null, "Knockback cannot be null");
|
||||
|
||||
this.knockback = knockback;
|
||||
this.knockback = knockback.clone();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -52,7 +52,7 @@ public class EntityTeleportEvent extends EntityEvent implements Cancellable {
|
|||
* @param from New location this entity moved from
|
||||
*/
|
||||
public void setFrom(@NotNull Location from) {
|
||||
this.from = from;
|
||||
this.from = from.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -71,7 +71,7 @@ public class EntityTeleportEvent extends EntityEvent implements Cancellable {
|
|||
* @param to New Location this entity moved to
|
||||
*/
|
||||
public void setTo(@Nullable Location to) {
|
||||
this.to = to;
|
||||
this.to = to != null ? to.clone() : null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
|
|
@ -241,7 +241,7 @@ public class PlayerInteractEvent extends PlayerEvent implements Cancellable {
|
|||
@Nullable
|
||||
@Deprecated // Paper
|
||||
public Vector getClickedPosition() {
|
||||
return clickedPosistion;
|
||||
return clickedPosistion.clone();
|
||||
}
|
||||
|
||||
// Paper start
|
||||
|
|
|
@ -70,7 +70,7 @@ public class PlayerMoveEvent extends PlayerEvent implements Cancellable {
|
|||
*/
|
||||
public void setFrom(@NotNull Location from) {
|
||||
validateLocation(from);
|
||||
this.from = from;
|
||||
this.from = from.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -90,7 +90,7 @@ public class PlayerMoveEvent extends PlayerEvent implements Cancellable {
|
|||
*/
|
||||
public void setTo(@NotNull Location to) {
|
||||
validateLocation(to);
|
||||
this.to = to;
|
||||
this.to = to.clone();
|
||||
}
|
||||
|
||||
// Paper start - PlayerMoveEvent improvements
|
||||
|
|
|
@ -69,7 +69,7 @@ public class PlayerRespawnEvent extends PlayerEvent {
|
|||
Preconditions.checkArgument(respawnLocation != null, "Respawn location can not be null");
|
||||
Preconditions.checkArgument(respawnLocation.getWorld() != null, "Respawn world can not be null");
|
||||
|
||||
this.respawnLocation = respawnLocation;
|
||||
this.respawnLocation = respawnLocation.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -45,7 +45,7 @@ public class PlayerVelocityEvent extends PlayerEvent implements Cancellable {
|
|||
* @param velocity The velocity vector that will be sent to the player
|
||||
*/
|
||||
public void setVelocity(@NotNull Vector velocity) {
|
||||
this.velocity = velocity;
|
||||
this.velocity = velocity.clone();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
|
|
@ -45,7 +45,7 @@ public class AsyncStructureSpawnEvent extends WorldEvent implements Cancellable
|
|||
*/
|
||||
@NotNull
|
||||
public BoundingBox getBoundingBox() {
|
||||
return boundingBox;
|
||||
return boundingBox.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -25,7 +25,7 @@ public final class EquipmentSlotGroup implements Predicate<EquipmentSlot> {
|
|||
public static final EquipmentSlotGroup LEGS = get("legs", EquipmentSlot.LEGS);
|
||||
public static final EquipmentSlotGroup CHEST = get("chest", EquipmentSlot.CHEST);
|
||||
public static final EquipmentSlotGroup HEAD = get("head", EquipmentSlot.HEAD);
|
||||
public static final EquipmentSlotGroup ARMOR = get("armor", (test) -> test == EquipmentSlot.FEET || test == EquipmentSlot.LEGS || test == EquipmentSlot.CHEST || test == EquipmentSlot.HEAD || test == EquipmentSlot.BODY, EquipmentSlot.CHEST); // Paper - add missing slot type
|
||||
public static final EquipmentSlotGroup ARMOR = get("armor", (test) -> test == EquipmentSlot.FEET || test == EquipmentSlot.LEGS || test == EquipmentSlot.CHEST || test == EquipmentSlot.HEAD || test == EquipmentSlot.BODY, EquipmentSlot.CHEST); // Paper - add missing slot type
|
||||
public static final EquipmentSlotGroup BODY = get("body", EquipmentSlot.BODY); // Paper - add missing slot group
|
||||
//
|
||||
private final String key;
|
||||
|
|
|
@ -24,7 +24,7 @@ public final class LootContext {
|
|||
private LootContext(@NotNull Location location, float luck, int lootingModifier, @Nullable Entity lootedEntity, @Nullable HumanEntity killer) {
|
||||
Preconditions.checkArgument(location != null, "LootContext location cannot be null");
|
||||
Preconditions.checkArgument(location.getWorld() != null, "LootContext World cannot be null");
|
||||
this.location = location;
|
||||
this.location = location.clone();
|
||||
this.luck = luck;
|
||||
this.lootingModifier = lootingModifier;
|
||||
this.lootedEntity = lootedEntity;
|
||||
|
@ -38,7 +38,7 @@ public final class LootContext {
|
|||
*/
|
||||
@NotNull
|
||||
public Location getLocation() {
|
||||
return location;
|
||||
return location.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -110,7 +110,7 @@ public final class LootContext {
|
|||
* @param location the location the LootContext should use
|
||||
*/
|
||||
public Builder(@NotNull Location location) {
|
||||
this.location = location;
|
||||
this.location = location.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -27,9 +27,9 @@ public class Transformation {
|
|||
Preconditions.checkArgument(scale != null, "scale cannot be null");
|
||||
Preconditions.checkArgument(rightRotation != null, "rightRotation cannot be null");
|
||||
|
||||
this.translation = translation;
|
||||
this.translation = new Vector3f(translation);
|
||||
this.leftRotation = new Quaternionf(leftRotation);
|
||||
this.scale = scale;
|
||||
this.scale = new Vector3f(scale);
|
||||
this.rightRotation = new Quaternionf(rightRotation);
|
||||
}
|
||||
|
||||
|
@ -39,10 +39,10 @@ public class Transformation {
|
|||
Preconditions.checkArgument(scale != null, "scale cannot be null");
|
||||
Preconditions.checkArgument(rightRotation != null, "rightRotation cannot be null");
|
||||
|
||||
this.translation = translation;
|
||||
this.leftRotation = leftRotation;
|
||||
this.scale = scale;
|
||||
this.rightRotation = rightRotation;
|
||||
this.translation = new Vector3f(translation);
|
||||
this.leftRotation = new Quaternionf(leftRotation);
|
||||
this.scale = new Vector3f(scale);
|
||||
this.rightRotation = new Quaternionf(rightRotation);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -52,7 +52,7 @@ public class Transformation {
|
|||
*/
|
||||
@NotNull
|
||||
public Vector3f getTranslation() {
|
||||
return this.translation;
|
||||
return new Vector3f(this.translation);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -62,7 +62,7 @@ public class Transformation {
|
|||
*/
|
||||
@NotNull
|
||||
public Quaternionf getLeftRotation() {
|
||||
return this.leftRotation;
|
||||
return new Quaternionf(this.leftRotation);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -72,7 +72,7 @@ public class Transformation {
|
|||
*/
|
||||
@NotNull
|
||||
public Vector3f getScale() {
|
||||
return this.scale;
|
||||
return new Vector3f(this.scale);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -82,7 +82,7 @@ public class Transformation {
|
|||
*/
|
||||
@NotNull
|
||||
public Quaternionf getRightRotation() {
|
||||
return this.rightRotation;
|
||||
return new Quaternionf(this.rightRotation);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -37,7 +37,7 @@ public class PlayerSpawnLocationEvent extends PlayerEvent {
|
|||
* @param location the spawn location
|
||||
*/
|
||||
public void setSpawnLocation(@NotNull Location location) {
|
||||
this.spawnLocation = location;
|
||||
this.spawnLocation = location.clone();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
|
|
@ -11,9 +11,9 @@ plugins {
|
|||
val paperMavenPublicUrl = "https://repo.papermc.io/repository/maven-public/"
|
||||
|
||||
dependencies {
|
||||
mache("io.papermc:mache:1.21.4+build.5")
|
||||
mache("io.papermc:mache:1.21.4+build.6")
|
||||
paperclip("io.papermc:paperclip:3.0.3")
|
||||
remapper("net.fabricmc:tiny-remapper:0.10.3:fat")
|
||||
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
|
||||
}
|
||||
|
||||
paperweight {
|
||||
|
@ -23,23 +23,24 @@ paperweight {
|
|||
|
||||
paper {
|
||||
reobfMappingsPatch = layout.projectDirectory.file("../build-data/reobf-mappings-patch.tiny")
|
||||
reobfPackagesToFix.addAll(
|
||||
"co.aikar.timings",
|
||||
"com.destroystokyo.paper",
|
||||
"com.mojang",
|
||||
"io.papermc.paper",
|
||||
"ca.spottedleaf",
|
||||
"net.kyori.adventure.bossbar",
|
||||
"net.minecraft",
|
||||
"org.bukkit.craftbukkit",
|
||||
"org.spigotmc",
|
||||
)
|
||||
}
|
||||
|
||||
spigot {
|
||||
buildDataRef = "3edaf46ec1eed4115ce1b18d2846cded42577e42"
|
||||
packageVersion = "v1_21_R3" // also needs to be updated in MappingEnvironment
|
||||
}
|
||||
|
||||
reobfPackagesToFix.addAll(
|
||||
"co.aikar.timings",
|
||||
"com.destroystokyo.paper",
|
||||
"com.mojang",
|
||||
"io.papermc.paper",
|
||||
"ca.spottedleaf",
|
||||
"net.kyori.adventure.bossbar",
|
||||
"net.minecraft",
|
||||
"org.bukkit.craftbukkit",
|
||||
"org.spigotmc",
|
||||
)
|
||||
}
|
||||
|
||||
tasks.generateDevelopmentBundle {
|
||||
|
@ -58,45 +59,45 @@ abstract class Services {
|
|||
}
|
||||
val services = objects.newInstance<Services>()
|
||||
|
||||
publishing {
|
||||
if (project.providers.gradleProperty("publishDevBundle").isPresent) {
|
||||
val devBundleComponent = services.softwareComponentFactory.adhoc("devBundle")
|
||||
components.add(devBundleComponent)
|
||||
if (project.providers.gradleProperty("publishDevBundle").isPresent) {
|
||||
val devBundleComponent = services.softwareComponentFactory.adhoc("devBundle")
|
||||
components.add(devBundleComponent)
|
||||
|
||||
val devBundle = configurations.consumable("devBundle") {
|
||||
attributes.attribute(DevBundleOutput.ATTRIBUTE, objects.named(DevBundleOutput.ZIP))
|
||||
outgoing.artifact(tasks.generateDevelopmentBundle.flatMap { it.devBundleFile })
|
||||
}
|
||||
devBundleComponent.addVariantsFromConfiguration(devBundle.get()) {}
|
||||
val devBundle = configurations.consumable("devBundle") {
|
||||
attributes.attribute(DevBundleOutput.ATTRIBUTE, objects.named(DevBundleOutput.ZIP))
|
||||
outgoing.artifact(tasks.generateDevelopmentBundle.flatMap { it.devBundleFile })
|
||||
}
|
||||
devBundleComponent.addVariantsFromConfiguration(devBundle.get()) {}
|
||||
|
||||
val runtime = configurations.consumable("serverRuntimeClasspath") {
|
||||
attributes.attribute(DevBundleOutput.ATTRIBUTE, objects.named(DevBundleOutput.SERVER_DEPENDENCIES))
|
||||
attributes.attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage.JAVA_RUNTIME))
|
||||
extendsFrom(configurations.runtimeClasspath.get())
|
||||
}
|
||||
devBundleComponent.addVariantsFromConfiguration(runtime.get()) {
|
||||
mapToMavenScope("runtime")
|
||||
}
|
||||
val runtime = configurations.consumable("serverRuntimeClasspath") {
|
||||
attributes.attribute(DevBundleOutput.ATTRIBUTE, objects.named(DevBundleOutput.SERVER_DEPENDENCIES))
|
||||
attributes.attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage.JAVA_RUNTIME))
|
||||
extendsFrom(configurations.runtimeClasspath.get())
|
||||
}
|
||||
devBundleComponent.addVariantsFromConfiguration(runtime.get()) {
|
||||
mapToMavenScope("runtime")
|
||||
}
|
||||
|
||||
val compile = configurations.consumable("serverCompileClasspath") {
|
||||
attributes.attribute(DevBundleOutput.ATTRIBUTE, objects.named(DevBundleOutput.SERVER_DEPENDENCIES))
|
||||
attributes.attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage.JAVA_API))
|
||||
extendsFrom(configurations.compileClasspath.get())
|
||||
}
|
||||
devBundleComponent.addVariantsFromConfiguration(compile.get()) {
|
||||
mapToMavenScope("compile")
|
||||
}
|
||||
val compile = configurations.consumable("serverCompileClasspath") {
|
||||
attributes.attribute(DevBundleOutput.ATTRIBUTE, objects.named(DevBundleOutput.SERVER_DEPENDENCIES))
|
||||
attributes.attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage.JAVA_API))
|
||||
extendsFrom(configurations.compileClasspath.get())
|
||||
}
|
||||
devBundleComponent.addVariantsFromConfiguration(compile.get()) {
|
||||
mapToMavenScope("compile")
|
||||
}
|
||||
|
||||
tasks.withType(GenerateMavenPom::class).configureEach {
|
||||
doLast {
|
||||
val text = destination.readText()
|
||||
// Remove dependencies from pom, dev bundle is designed for gradle module metadata consumers
|
||||
destination.writeText(
|
||||
text.substringBefore("<dependencies>") + text.substringAfter("</dependencies>")
|
||||
)
|
||||
}
|
||||
tasks.withType(GenerateMavenPom::class).configureEach {
|
||||
doLast {
|
||||
val text = destination.readText()
|
||||
// Remove dependencies from pom, dev bundle is designed for gradle module metadata consumers
|
||||
destination.writeText(
|
||||
text.substringBefore("<dependencies>") + text.substringAfter("</dependencies>")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications.create<MavenPublication>("devBundle") {
|
||||
artifactId = "dev-bundle"
|
||||
from(devBundleComponent)
|
||||
|
@ -149,6 +150,11 @@ dependencies {
|
|||
runtimeOnly("org.xerial:sqlite-jdbc:3.47.0.0")
|
||||
runtimeOnly("com.mysql:mysql-connector-j:9.1.0")
|
||||
runtimeOnly("com.lmax:disruptor:3.4.4") // Paper
|
||||
// Paper start - Use Velocity cipher
|
||||
implementation("com.velocitypowered:velocity-native:3.3.0-SNAPSHOT") {
|
||||
isTransitive = false
|
||||
}
|
||||
// Paper end - Use Velocity cipher
|
||||
|
||||
runtimeOnly("org.apache.maven:maven-resolver-provider:3.9.6")
|
||||
runtimeOnly("org.apache.maven.resolver:maven-resolver-connector-basic:1.9.18")
|
||||
|
@ -176,12 +182,12 @@ dependencies {
|
|||
// Paper end - spark
|
||||
}
|
||||
|
||||
|
||||
tasks.jar {
|
||||
manifest {
|
||||
val git = Git(rootProject.layout.projectDirectory.path)
|
||||
val mcVersion = rootProject.providers.gradleProperty("mcVersion").get()
|
||||
val build = System.getenv("BUILD_NUMBER") ?: null
|
||||
val buildTime = if (build != null) Instant.now() else Instant.EPOCH
|
||||
val gitHash = git.exec(providers, "rev-parse", "--short=7", "HEAD").get().trim()
|
||||
val implementationVersion = "$mcVersion-${build ?: "DEV"}-$gitHash"
|
||||
val date = git.exec(providers, "show", "-s", "--format=%ci", gitHash).get().trim() // Paper
|
||||
|
@ -197,7 +203,7 @@ tasks.jar {
|
|||
"Brand-Id" to "papermc:paper",
|
||||
"Brand-Name" to "Paper",
|
||||
"Build-Number" to (build ?: ""),
|
||||
"Build-Time" to Instant.now().toString(),
|
||||
"Build-Time" to buildTime.toString(),
|
||||
"Git-Branch" to gitBranch, // Paper
|
||||
"Git-Commit" to gitHash, // Paper
|
||||
)
|
||||
|
@ -256,7 +262,7 @@ fun TaskContainer.registerRunTask(
|
|||
name: String,
|
||||
block: JavaExec.() -> Unit
|
||||
): TaskProvider<JavaExec> = register<JavaExec>(name) {
|
||||
group = "paper"
|
||||
group = "runs"
|
||||
mainClass.set("org.bukkit.craftbukkit.Main")
|
||||
standardInput = System.`in`
|
||||
workingDir = rootProject.layout.projectDirectory
|
||||
|
@ -266,7 +272,7 @@ fun TaskContainer.registerRunTask(
|
|||
languageVersion.set(JavaLanguageVersion.of(21))
|
||||
vendor.set(JvmVendorSpec.JETBRAINS)
|
||||
})
|
||||
jvmArgs("-XX:+AllowEnhancedClassRedefinition", "-XX:+AllowRedefinitionToAddDeleteMethods")
|
||||
jvmArgs("-XX:+AllowEnhancedClassRedefinition")
|
||||
|
||||
if (rootProject.childProjects["test-plugin"] != null) {
|
||||
val testPluginJar = rootProject.project(":test-plugin").tasks.jar.flatMap { it.archiveFile }
|
||||
|
@ -312,21 +318,21 @@ tasks.registerRunTask("runDevServer") {
|
|||
|
||||
tasks.registerRunTask("runBundler") {
|
||||
description = "Spin up a test server from the Mojang mapped bundler jar"
|
||||
classpath(tasks.named<io.papermc.paperweight.tasks.CreateBundlerJar>("createMojmapBundlerJar").flatMap { it.outputZip })
|
||||
classpath(tasks.createMojmapBundlerJar.flatMap { it.outputZip })
|
||||
mainClass.set(null as String?)
|
||||
}
|
||||
tasks.registerRunTask("runReobfBundler") {
|
||||
description = "Spin up a test server from the reobf bundler jar"
|
||||
classpath(rootProject.tasks.named<io.papermc.paperweight.tasks.CreateBundlerJar>("createReobfBundlerJar").flatMap { it.outputZip })
|
||||
classpath(tasks.createReobfBundlerJar.flatMap { it.outputZip })
|
||||
mainClass.set(null as String?)
|
||||
}
|
||||
tasks.registerRunTask("runPaperclip") {
|
||||
description = "Spin up a test server from the Mojang mapped Paperclip jar"
|
||||
classpath(tasks.named<io.papermc.paperweight.tasks.CreatePaperclipJar>("createMojmapPaperclipJar").flatMap { it.outputZip })
|
||||
classpath(tasks.createMojmapPaperclipJar.flatMap { it.outputZip })
|
||||
mainClass.set(null as String?)
|
||||
}
|
||||
tasks.registerRunTask("runReobfPaperclip") {
|
||||
description = "Spin up a test server from the reobf Paperclip jar"
|
||||
classpath(rootProject.tasks.named<io.papermc.paperweight.tasks.CreatePaperclipJar>("createReobfPaperclipJar").flatMap { it.outputZip })
|
||||
classpath(tasks.createReobfPaperclipJar.flatMap { it.outputZip })
|
||||
mainClass.set(null as String?)
|
||||
}
|
||||
|
|
|
@ -27,34 +27,34 @@ and then catch exceptions and close if they fire.
|
|||
|
||||
Part of this commit was authored by: Spottedleaf, sandtechnology
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/network/Connection.java
|
||||
+++ b/src/main/java/net/minecraft/network/Connection.java
|
||||
@@ -0,0 +0,0 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
diff --git a/net/minecraft/network/Connection.java b/net/minecraft/network/Connection.java
|
||||
index 42f44c7cb0bd55ddfacd18acb0e596e7a953870e..ad8f8428b75e37097487cdfbd0db2421ee4cbe37 100644
|
||||
--- a/net/minecraft/network/Connection.java
|
||||
+++ b/net/minecraft/network/Connection.java
|
||||
@@ -85,7 +85,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
private static final ProtocolInfo<ServerHandshakePacketListener> INITIAL_PROTOCOL = HandshakeProtocols.SERVERBOUND;
|
||||
private final PacketFlow receiving;
|
||||
private volatile boolean sendLoginDisconnect = true;
|
||||
- private final Queue<Consumer<Connection>> pendingActions = Queues.newConcurrentLinkedQueue();
|
||||
+ private final Queue<WrappedConsumer> pendingActions = Queues.newConcurrentLinkedQueue(); // Paper
|
||||
+ private final Queue<WrappedConsumer> pendingActions = Queues.newConcurrentLinkedQueue(); // Paper - Optimize network
|
||||
public Channel channel;
|
||||
public SocketAddress address;
|
||||
// Spigot Start
|
||||
@@ -0,0 +0,0 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
public java.net.InetSocketAddress virtualHost;
|
||||
private static boolean enableExplicitFlush = Boolean.getBoolean("paper.explicit-flush"); // Paper - Disable explicit network manager flushing
|
||||
// Paper end
|
||||
// Spigot start
|
||||
@@ -145,6 +145,10 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
}
|
||||
// Paper end - packet limiter
|
||||
@Nullable public SocketAddress haProxyAddress; // Paper - Add API to get player's proxy address
|
||||
+ // Paper start - Optimize network
|
||||
+ public boolean isPending = true;
|
||||
+ public boolean queueImmunity;
|
||||
+ // Paper end - Optimize network
|
||||
|
||||
// Paper start - add utility methods
|
||||
public final net.minecraft.server.level.ServerPlayer getPlayer() {
|
||||
@@ -0,0 +0,0 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
public Connection(PacketFlow receiving) {
|
||||
this.receiving = receiving;
|
||||
@@ -423,11 +427,38 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
}
|
||||
|
||||
public void send(Packet<?> packet, @Nullable PacketSendListener callbacks, boolean flush) {
|
||||
public void send(Packet<?> packet, @Nullable PacketSendListener listener, boolean flush) {
|
||||
- if (this.isConnected()) {
|
||||
- this.flushQueue();
|
||||
+ // Paper start - Optimize network: Handle oversized packets better
|
||||
|
@ -67,17 +67,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ if (connected && (InnerUtil.canSendImmediate(this, packet)
|
||||
+ || (io.papermc.paper.util.MCUtil.isMainThread() && packet.isReady() && this.pendingActions.isEmpty()
|
||||
+ && (packet.getExtraPackets() == null || packet.getExtraPackets().isEmpty())))) {
|
||||
this.sendPacket(packet, callbacks, flush);
|
||||
this.sendPacket(packet, listener, flush);
|
||||
} else {
|
||||
- this.pendingActions.add((networkmanager) -> {
|
||||
- networkmanager.sendPacket(packet, callbacks, flush);
|
||||
- });
|
||||
- }
|
||||
- this.pendingActions.add(connection -> connection.sendPacket(packet, listener, flush));
|
||||
+ // Write the packets to the queue, then flush - antixray hooks there already
|
||||
+ final java.util.List<Packet<?>> extraPackets = InnerUtil.buildExtraPackets(packet);
|
||||
+ final boolean hasExtraPackets = extraPackets != null && !extraPackets.isEmpty();
|
||||
+ if (!hasExtraPackets) {
|
||||
+ this.pendingActions.add(new PacketSendAction(packet, callbacks, flush));
|
||||
+ this.pendingActions.add(new PacketSendAction(packet, listener, flush));
|
||||
+ } else {
|
||||
+ final java.util.List<PacketSendAction> actions = new java.util.ArrayList<>(1 + extraPackets.size());
|
||||
+ actions.add(new PacketSendAction(packet, null, false)); // Delay the future listener until the end of the extra packets
|
||||
|
@ -85,31 +82,30 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ for (int i = 0, len = extraPackets.size(); i < len;) {
|
||||
+ final Packet<?> extraPacket = extraPackets.get(i);
|
||||
+ final boolean end = ++i == len;
|
||||
+ actions.add(new PacketSendAction(extraPacket, end ? callbacks : null, end)); // Append listener to the end
|
||||
+ actions.add(new PacketSendAction(extraPacket, end ? listener : null, end)); // Append listener to the end
|
||||
+ }
|
||||
+
|
||||
+ this.pendingActions.addAll(actions);
|
||||
+ }
|
||||
|
||||
+
|
||||
+ this.flushQueue();
|
||||
+ // Paper end - Optimize network
|
||||
+ }
|
||||
}
|
||||
|
||||
public void runOnceConnected(Consumer<Connection> task) {
|
||||
@@ -0,0 +0,0 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
this.flushQueue();
|
||||
task.accept(this);
|
||||
} else {
|
||||
- this.pendingActions.add(task);
|
||||
+ this.pendingActions.add(new WrappedConsumer(task)); // Paper - Optimize network
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +0,0 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
}
|
||||
|
||||
private void doSendPacket(Packet<?> packet, @Nullable PacketSendListener callbacks, boolean flush) {
|
||||
@@ -436,7 +467,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
this.flushQueue();
|
||||
action.accept(this);
|
||||
} else {
|
||||
- this.pendingActions.add(action);
|
||||
+ this.pendingActions.add(new WrappedConsumer(action)); // Paper - Optimize network
|
||||
}
|
||||
}
|
||||
|
||||
@@ -450,6 +481,14 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
}
|
||||
|
||||
private void doSendPacket(Packet<?> packet, @Nullable PacketSendListener sendListener, boolean flush) {
|
||||
+ // Paper start - Optimize network
|
||||
+ final net.minecraft.server.level.ServerPlayer player = this.getPlayer();
|
||||
+ if (!this.isConnected()) {
|
||||
|
@ -118,18 +114,18 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ }
|
||||
+ try {
|
||||
+ // Paper end - Optimize network
|
||||
ChannelFuture channelfuture = flush ? this.channel.writeAndFlush(packet) : this.channel.write(packet);
|
||||
|
||||
if (callbacks != null) {
|
||||
@@ -0,0 +0,0 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
ChannelFuture channelFuture = flush ? this.channel.writeAndFlush(packet) : this.channel.write(packet);
|
||||
if (sendListener != null) {
|
||||
channelFuture.addListener(future -> {
|
||||
@@ -465,14 +504,24 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
});
|
||||
}
|
||||
|
||||
+ // Paper start - Optimize network
|
||||
+ if (packet.hasFinishListener()) {
|
||||
+ channelfuture.addListener((ChannelFutureListener) channelFuture -> packet.onPacketDispatchFinish(player, channelFuture));
|
||||
+ channelFuture.addListener((ChannelFutureListener) future -> packet.onPacketDispatchFinish(player, future));
|
||||
+ }
|
||||
channelfuture.addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE);
|
||||
channelFuture.addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE);
|
||||
+ } catch (final Exception e) {
|
||||
+ LOGGER.error("NetworkException: {}", player, e);
|
||||
+ this.disconnect(Component.translatable("disconnect.genericReason", "Internal Exception: " + e.getMessage()));
|
||||
|
@ -145,16 +141,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
- this.pendingActions.add(Connection::flush);
|
||||
+ this.pendingActions.add(new WrappedConsumer(Connection::flush)); // Paper - Optimize network
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +0,0 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
|
||||
@@ -484,16 +533,57 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
}
|
||||
}
|
||||
|
||||
- private void flushQueue() {
|
||||
- if (this.channel != null && this.channel.isOpen()) {
|
||||
- Queue queue = this.pendingActions;
|
||||
-
|
||||
+ // Paper start - Optimize network: Rewrite this to be safer if ran off main thread
|
||||
+ private boolean flushQueue() {
|
||||
+ if (!this.isConnected()) {
|
||||
|
@ -165,7 +159,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ } else if (this.isPending) {
|
||||
+ // Should only happen during login/status stages
|
||||
synchronized (this.pendingActions) {
|
||||
- Consumer consumer;
|
||||
- Consumer<Connection> consumer;
|
||||
- while ((consumer = this.pendingActions.poll()) != null) {
|
||||
- consumer.accept(this);
|
||||
+ return this.processQueue();
|
||||
+ }
|
||||
+ }
|
||||
|
@ -176,9 +172,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ if (this.pendingActions.isEmpty()) {
|
||||
+ return true;
|
||||
+ }
|
||||
|
||||
- while ((consumer = (Consumer) this.pendingActions.poll()) != null) {
|
||||
- consumer.accept(this);
|
||||
+
|
||||
+ // If we are on main, we are safe here in that nothing else should be processing queue off main anymore
|
||||
+ // But if we are not on main due to login/status, the parent is synchronized on packetQueue
|
||||
+ final java.util.Iterator<WrappedConsumer> iterator = this.pendingActions.iterator();
|
||||
|
@ -199,12 +193,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ if (!packet.isReady()) {
|
||||
+ return false;
|
||||
}
|
||||
+ }
|
||||
|
||||
}
|
||||
+
|
||||
+ iterator.remove();
|
||||
+ if (queued.tryMarkConsumed()) {
|
||||
+ queued.accept(this);
|
||||
}
|
||||
+ }
|
||||
}
|
||||
+ return true;
|
||||
}
|
||||
|
@ -212,35 +206,35 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
|
||||
private static final int MAX_PER_TICK = io.papermc.paper.configuration.GlobalConfiguration.get().misc.maxJoinsPerTick; // Paper - Buffer joins to world
|
||||
private static int joinAttemptsThisTick; // Paper - Buffer joins to world
|
||||
@@ -0,0 +0,0 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
public void disconnect(DisconnectionDetails disconnectionInfo) {
|
||||
// Spigot Start
|
||||
this.preparing = false;
|
||||
@@ -563,6 +653,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
|
||||
public void disconnect(DisconnectionDetails disconnectionDetails) {
|
||||
this.preparing = false; // Spigot
|
||||
+ this.clearPacketQueue(); // Paper - Optimize network
|
||||
// Spigot End
|
||||
if (this.channel == null) {
|
||||
this.delayedDisconnect = disconnectionInfo;
|
||||
@@ -0,0 +0,0 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
this.delayedDisconnect = disconnectionDetails;
|
||||
}
|
||||
@@ -751,7 +842,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
public void handleDisconnection() {
|
||||
if (this.channel != null && !this.channel.isOpen()) {
|
||||
if (this.disconnectionHandled) {
|
||||
- Connection.LOGGER.warn("handleDisconnection() called twice");
|
||||
+ // Connection.LOGGER.warn("handleDisconnection() called twice"); // Paper - Don't log useless message
|
||||
- LOGGER.warn("handleDisconnection() called twice");
|
||||
+ // LOGGER.warn("handleDisconnection() called twice"); // Paper - Don't log useless message
|
||||
} else {
|
||||
this.disconnectionHandled = true;
|
||||
PacketListener packetlistener = this.getPacketListener();
|
||||
@@ -0,0 +0,0 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
|
||||
packetlistener1.onDisconnect(disconnectiondetails);
|
||||
PacketListener packetListener = this.getPacketListener();
|
||||
@@ -762,7 +853,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
);
|
||||
packetListener1.onDisconnect(disconnectionDetails);
|
||||
}
|
||||
- this.pendingActions.clear(); // Free up packet queue.
|
||||
+ this.clearPacketQueue(); // Paper - Optimize network
|
||||
// Paper start - Add PlayerConnectionCloseEvent
|
||||
final PacketListener packetListener = this.getPacketListener();
|
||||
if (packetListener instanceof net.minecraft.server.network.ServerCommonPacketListenerImpl commonPacketListener) {
|
||||
@@ -0,0 +0,0 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
public void setBandwidthLogger(LocalSampleLogger log) {
|
||||
this.bandwidthDebugMonitor = new BandwidthDebugMonitor(log);
|
||||
/* Player was logged in, either game listener or configuration listener */
|
||||
@@ -797,4 +888,93 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
public void setBandwidthLogger(LocalSampleLogger bandwithLogger) {
|
||||
this.bandwidthDebugMonitor = new BandwidthDebugMonitor(bandwithLogger);
|
||||
}
|
||||
+
|
||||
+ // Paper start - Optimize network
|
||||
|
@ -332,11 +326,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ }
|
||||
+ // Paper end - Optimize network
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/network/protocol/Packet.java b/src/main/java/net/minecraft/network/protocol/Packet.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/network/protocol/Packet.java
|
||||
+++ b/src/main/java/net/minecraft/network/protocol/Packet.java
|
||||
@@ -0,0 +0,0 @@ public interface Packet<T extends PacketListener> {
|
||||
diff --git a/net/minecraft/network/protocol/Packet.java b/net/minecraft/network/protocol/Packet.java
|
||||
index 65ff8b9112ec76eeac48c679044fc02ae7d4ffeb..e4789584cbe43959681a8522c66eab58369bebd0 100644
|
||||
--- a/net/minecraft/network/protocol/Packet.java
|
||||
+++ b/net/minecraft/network/protocol/Packet.java
|
||||
@@ -35,4 +35,32 @@ public interface Packet<T extends PacketListener> {
|
||||
static <B extends ByteBuf, T extends Packet<?>> StreamCodec<B, T> codec(StreamMemberEncoder<B, T> encoder, StreamDecoder<B, T> decoder) {
|
||||
return StreamCodec.ofMember(encoder, decoder);
|
||||
}
|
||||
|
@ -352,7 +346,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ * @param player Null if not at PLAY stage yet
|
||||
+ * @param future Can be null if packet was cancelled
|
||||
+ */
|
||||
+ default void onPacketDispatchFinish(@org.jetbrains.annotations.Nullable net.minecraft.server.level.ServerPlayer player, @org.jetbrains.annotations.Nullable io.netty.channel.ChannelFuture future) {}
|
||||
+ default void onPacketDispatchFinish(@org.jetbrains.annotations.Nullable net.minecraft.server.level.ServerPlayer player, @org.jetbrains.annotations.Nullable io.netty.channel.ChannelFuture future) {
|
||||
+ }
|
||||
+
|
||||
+ default boolean hasFinishListener() {
|
||||
+ return false;
|
||||
|
@ -368,28 +363,29 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java
|
||||
@@ -0,0 +0,0 @@ public class ServerConnectionListener {
|
||||
final List<Connection> connections = Collections.synchronizedList(Lists.newArrayList());
|
||||
diff --git a/net/minecraft/server/network/ServerConnectionListener.java b/net/minecraft/server/network/ServerConnectionListener.java
|
||||
index b873af7183d9b1aabc87e63d254a4326f17b21c9..7de11ba404f0b60e7f7b7c16954811a343688219 100644
|
||||
--- a/net/minecraft/server/network/ServerConnectionListener.java
|
||||
+++ b/net/minecraft/server/network/ServerConnectionListener.java
|
||||
@@ -66,11 +66,13 @@ public class ServerConnectionListener {
|
||||
|
||||
// Paper start - prevent blocking on adding a new connection while the server is ticking
|
||||
private final java.util.Queue<Connection> pending = new java.util.concurrent.ConcurrentLinkedQueue<>();
|
||||
+ private static final boolean disableFlushConsolidation = Boolean.getBoolean("Paper.disableFlushConsolidate"); // Paper - Optimize network
|
||||
|
||||
private final void addPending() {
|
||||
Connection connection;
|
||||
while ((connection = pending.poll()) != null) {
|
||||
connections.add(connection);
|
||||
while ((connection = this.pending.poll()) != null) {
|
||||
this.connections.add(connection);
|
||||
+ connection.isPending = false; // Paper - Optimize network
|
||||
}
|
||||
}
|
||||
// Paper end - prevent blocking on adding a new connection while the server is ticking
|
||||
@@ -0,0 +0,0 @@ public class ServerConnectionListener {
|
||||
;
|
||||
}
|
||||
@@ -120,6 +122,7 @@ public class ServerConnectionListener {
|
||||
} catch (ChannelException var5) {
|
||||
}
|
||||
|
||||
+ if (!disableFlushConsolidation) channel.pipeline().addFirst(new io.netty.handler.flush.FlushConsolidationHandler()); // Paper - Optimize network
|
||||
ChannelPipeline channelpipeline = channel.pipeline().addLast("timeout", new ReadTimeoutHandler(30));
|
||||
|
||||
if (ServerConnectionListener.this.server.repliesToStatus()) {
|
||||
+ if (!disableFlushConsolidation) channel.pipeline().addFirst(new io.netty.handler.flush.FlushConsolidationHandler()); // Paper - Optimize network
|
||||
ChannelPipeline channelPipeline = channel.pipeline().addLast("timeout", new ReadTimeoutHandler(30));
|
||||
if (ServerConnectionListener.this.server.repliesToStatus()) {
|
||||
channelPipeline.addLast("legacy_query", new LegacyQueryHandler(ServerConnectionListener.this.getServer()));
|
|
@ -30,36 +30,23 @@ This fix also maintains compatability if someone switches server jars to one wit
|
|||
this fix, as the data will remain in the oversized file. Once the server returns
|
||||
to a jar with this fix, the data will be restored.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||
@@ -0,0 +0,0 @@ import java.nio.file.LinkOption;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
+import java.util.zip.InflaterInputStream; // Paper
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.Util;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.util.profiling.jfr.JvmProfiler;
|
||||
+import net.minecraft.nbt.CompoundTag; // Paper
|
||||
+import net.minecraft.nbt.NbtIo; // Paper
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable {
|
||||
this.usedSectors = new RegionBitmap();
|
||||
this.info = storageKey;
|
||||
diff --git a/net/minecraft/world/level/chunk/storage/RegionFile.java b/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||
index d0854fa02be52f560fc91adeb8495a6bd22f6f74..783a2d80f6197dd0af0dc81909f0353a8ea2ecf4 100644
|
||||
--- a/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||
+++ b/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||
@@ -53,6 +53,7 @@ public class RegionFile implements AutoCloseable {
|
||||
this.info = info;
|
||||
this.path = path;
|
||||
+ initOversizedState(); // Paper
|
||||
this.version = compressionFormat;
|
||||
if (!Files.isDirectory(directory, new LinkOption[0])) {
|
||||
throw new IllegalArgumentException("Expected directory, got " + String.valueOf(directory.toAbsolutePath()));
|
||||
@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable {
|
||||
|
||||
this.version = version;
|
||||
+ this.initOversizedState(); // Paper
|
||||
if (!Files.isDirectory(externalFileDir)) {
|
||||
throw new IllegalArgumentException("Expected directory, got " + externalFileDir.toAbsolutePath());
|
||||
} else {
|
||||
@@ -423,4 +424,75 @@ public class RegionFile implements AutoCloseable {
|
||||
interface CommitOp {
|
||||
void run() throws IOException;
|
||||
}
|
||||
|
||||
+
|
||||
+ // Paper start
|
||||
+ private final byte[] oversized = new byte[1024];
|
||||
+ private int oversizedCount;
|
||||
|
@ -78,9 +65,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ private static int getChunkIndex(int x, int z) {
|
||||
+ return (x & 31) + (z & 31) * 32;
|
||||
+ }
|
||||
+
|
||||
+ synchronized boolean isOversized(int x, int z) {
|
||||
+ return this.oversized[getChunkIndex(x, z)] == 1;
|
||||
+ }
|
||||
+
|
||||
+ synchronized void setOversized(int x, int z, boolean oversized) throws IOException {
|
||||
+ final int offset = getChunkIndex(x, z);
|
||||
+ boolean previous = this.oversized[offset] == 1;
|
||||
|
@ -120,22 +109,20 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ return this.path.getParent().resolve(this.path.getFileName().toString().replaceAll("\\.mca$", "") + "_oversized_" + x + "_" + z + ".nbt");
|
||||
+ }
|
||||
+
|
||||
+ synchronized CompoundTag getOversizedData(int x, int z) throws IOException {
|
||||
+ synchronized net.minecraft.nbt.CompoundTag getOversizedData(int x, int z) throws IOException {
|
||||
+ Path file = getOversizedFile(x, z);
|
||||
+ try (DataInputStream out = new DataInputStream(new java.io.BufferedInputStream(new InflaterInputStream(Files.newInputStream(file))))) {
|
||||
+ return NbtIo.read((java.io.DataInput) out);
|
||||
+ try (DataInputStream out = new DataInputStream(new java.io.BufferedInputStream(new java.util.zip.InflaterInputStream(Files.newInputStream(file))))) {
|
||||
+ return net.minecraft.nbt.NbtIo.read((java.io.DataInput) out);
|
||||
+ }
|
||||
+
|
||||
+ }
|
||||
+ // Paper end
|
||||
private class ChunkBuffer extends ByteArrayOutputStream {
|
||||
|
||||
private final ChunkPos pos;
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||
@@ -0,0 +0,0 @@ public final class RegionFileStorage implements AutoCloseable {
|
||||
}
|
||||
diff --git a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||
index 5ac84d6b47e7fdc16e1c09b739829de3d316bf5b..51bf310423013d0ae9d3202d66e36a053a767197 100644
|
||||
--- a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||
+++ b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||
@@ -47,6 +47,43 @@ public final class RegionFileStorage implements AutoCloseable {
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -148,7 +135,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ synchronized (regionfile) {
|
||||
+ try (DataInputStream datainputstream = regionfile.getChunkDataInputStream(chunkCoordinate)) {
|
||||
+ CompoundTag oversizedData = regionfile.getOversizedData(chunkCoordinate.x, chunkCoordinate.z);
|
||||
+ CompoundTag chunk = NbtIo.read((DataInput) datainputstream);
|
||||
+ CompoundTag chunk = NbtIo.read(datainputstream);
|
||||
+ if (oversizedData == null) {
|
||||
+ return chunk;
|
||||
+ }
|
||||
|
@ -177,26 +164,26 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ // Paper end
|
||||
+
|
||||
@Nullable
|
||||
public CompoundTag read(ChunkPos pos) throws IOException {
|
||||
public CompoundTag read(ChunkPos chunkPos) throws IOException {
|
||||
// CraftBukkit start - SPIGOT-5680: There's no good reason to preemptively create files on read, save that for writing
|
||||
@@ -0,0 +0,0 @@ public final class RegionFileStorage implements AutoCloseable {
|
||||
@@ -55,6 +92,12 @@ public final class RegionFileStorage implements AutoCloseable {
|
||||
return null;
|
||||
}
|
||||
// CraftBukkit end
|
||||
DataInputStream datainputstream = regionfile.getChunkDataInputStream(pos);
|
||||
|
||||
+ // Paper start
|
||||
+ if (regionfile.isOversized(pos.x, pos.z)) {
|
||||
+ printOversizedLog("Loading Oversized Chunk!", regionfile.getPath(), pos.x, pos.z);
|
||||
+ return readOversizedChunk(regionfile, pos);
|
||||
+ if (regionFile.isOversized(chunkPos.x, chunkPos.z)) {
|
||||
+ printOversizedLog("Loading Oversized Chunk!", regionFile.getPath(), chunkPos.x, chunkPos.z);
|
||||
+ return readOversizedChunk(regionFile, chunkPos);
|
||||
+ }
|
||||
+ // Paper end
|
||||
CompoundTag nbttagcompound;
|
||||
label43:
|
||||
{
|
||||
@@ -0,0 +0,0 @@ public final class RegionFileStorage implements AutoCloseable {
|
||||
|
||||
try {
|
||||
NbtIo.write(nbt, (DataOutput) dataoutputstream);
|
||||
+ regionfile.setOversized(pos.x, pos.z, false); // Paper - We don't do this anymore, mojang stores differently, but clear old meta flag if it exists to get rid of our own meta file once last oversized is gone
|
||||
} catch (Throwable throwable) {
|
||||
if (dataoutputstream != null) {
|
||||
try {
|
||||
CompoundTag var4;
|
||||
try (DataInputStream chunkDataInputStream = regionFile.getChunkDataInputStream(chunkPos)) {
|
||||
@@ -90,6 +133,7 @@ public final class RegionFileStorage implements AutoCloseable {
|
||||
} else {
|
||||
try (DataOutputStream chunkDataOutputStream = regionFile.getChunkDataOutputStream(chunkPos)) {
|
||||
NbtIo.write(chunkData, chunkDataOutputStream);
|
||||
+ regionFile.setOversized(chunkPos.x, chunkPos.z, false); // Paper - We don't do this anymore, mojang stores differently, but clear old meta flag if it exists to get rid of our own meta file once last oversized is gone
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,861 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Fri, 13 May 2016 01:38:06 -0400
|
||||
Subject: [PATCH] Entity Activation Range 2.0
|
||||
|
||||
Optimizes performance of Activation Range
|
||||
|
||||
Adds many new configurations and a new wake up inactive system
|
||||
|
||||
Fixes and adds new Immunities to improve gameplay behavior
|
||||
|
||||
Adds water Mobs to activation range config and nerfs fish
|
||||
Adds flying monsters to control ghast and phantoms
|
||||
Adds villagers as separate config
|
||||
|
||||
diff --git a/io/papermc/paper/entity/activation/ActivationRange.java b/io/papermc/paper/entity/activation/ActivationRange.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..bd888ef719b9bfc93bace0b1d0fb771ac659f515
|
||||
--- /dev/null
|
||||
+++ b/io/papermc/paper/entity/activation/ActivationRange.java
|
||||
@@ -0,0 +1,318 @@
|
||||
+package io.papermc.paper.entity.activation;
|
||||
+
|
||||
+import net.minecraft.core.BlockPos;
|
||||
+import net.minecraft.server.MinecraftServer;
|
||||
+import net.minecraft.world.entity.Entity;
|
||||
+import net.minecraft.world.entity.ExperienceOrb;
|
||||
+import net.minecraft.world.entity.FlyingMob;
|
||||
+import net.minecraft.world.entity.LightningBolt;
|
||||
+import net.minecraft.world.entity.LivingEntity;
|
||||
+import net.minecraft.world.entity.Mob;
|
||||
+import net.minecraft.world.entity.ai.Brain;
|
||||
+import net.minecraft.world.entity.animal.Animal;
|
||||
+import net.minecraft.world.entity.animal.Bee;
|
||||
+import net.minecraft.world.entity.animal.Sheep;
|
||||
+import net.minecraft.world.entity.animal.horse.Llama;
|
||||
+import net.minecraft.world.entity.boss.EnderDragonPart;
|
||||
+import net.minecraft.world.entity.boss.enderdragon.EndCrystal;
|
||||
+import net.minecraft.world.entity.boss.enderdragon.EnderDragon;
|
||||
+import net.minecraft.world.entity.boss.wither.WitherBoss;
|
||||
+import net.minecraft.world.entity.item.ItemEntity;
|
||||
+import net.minecraft.world.entity.item.PrimedTnt;
|
||||
+import net.minecraft.world.entity.monster.Creeper;
|
||||
+import net.minecraft.world.entity.monster.Pillager;
|
||||
+import net.minecraft.world.entity.npc.Villager;
|
||||
+import net.minecraft.world.entity.player.Player;
|
||||
+import net.minecraft.world.entity.projectile.AbstractArrow;
|
||||
+import net.minecraft.world.entity.projectile.AbstractHurtingProjectile;
|
||||
+import net.minecraft.world.entity.projectile.EyeOfEnder;
|
||||
+import net.minecraft.world.entity.projectile.FireworkRocketEntity;
|
||||
+import net.minecraft.world.entity.projectile.ThrowableProjectile;
|
||||
+import net.minecraft.world.entity.projectile.ThrownTrident;
|
||||
+import net.minecraft.world.entity.schedule.Activity;
|
||||
+import net.minecraft.world.level.Level;
|
||||
+import net.minecraft.world.phys.AABB;
|
||||
+import org.spigotmc.SpigotWorldConfig;
|
||||
+
|
||||
+public final class ActivationRange {
|
||||
+
|
||||
+ private ActivationRange() {
|
||||
+ }
|
||||
+
|
||||
+ static Activity[] VILLAGER_PANIC_IMMUNITIES = {
|
||||
+ Activity.HIDE,
|
||||
+ Activity.PRE_RAID,
|
||||
+ Activity.RAID,
|
||||
+ Activity.PANIC
|
||||
+ };
|
||||
+
|
||||
+ private static int checkInactiveWakeup(final Entity entity) {
|
||||
+ final Level world = entity.level();
|
||||
+ final SpigotWorldConfig config = world.spigotConfig;
|
||||
+ final long inactiveFor = MinecraftServer.currentTick - entity.activatedTick;
|
||||
+ if (entity.activationType == ActivationType.VILLAGER) {
|
||||
+ if (inactiveFor > config.wakeUpInactiveVillagersEvery && world.wakeupInactiveRemainingVillagers > 0) {
|
||||
+ world.wakeupInactiveRemainingVillagers--;
|
||||
+ return config.wakeUpInactiveVillagersFor;
|
||||
+ }
|
||||
+ } else if (entity.activationType == ActivationType.ANIMAL) {
|
||||
+ if (inactiveFor > config.wakeUpInactiveAnimalsEvery && world.wakeupInactiveRemainingAnimals > 0) {
|
||||
+ world.wakeupInactiveRemainingAnimals--;
|
||||
+ return config.wakeUpInactiveAnimalsFor;
|
||||
+ }
|
||||
+ } else if (entity.activationType == ActivationType.FLYING_MONSTER) {
|
||||
+ if (inactiveFor > config.wakeUpInactiveFlyingEvery && world.wakeupInactiveRemainingFlying > 0) {
|
||||
+ world.wakeupInactiveRemainingFlying--;
|
||||
+ return config.wakeUpInactiveFlyingFor;
|
||||
+ }
|
||||
+ } else if (entity.activationType == ActivationType.MONSTER || entity.activationType == ActivationType.RAIDER) {
|
||||
+ if (inactiveFor > config.wakeUpInactiveMonstersEvery && world.wakeupInactiveRemainingMonsters > 0) {
|
||||
+ world.wakeupInactiveRemainingMonsters--;
|
||||
+ return config.wakeUpInactiveMonstersFor;
|
||||
+ }
|
||||
+ }
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ static AABB maxBB = new AABB(0, 0, 0, 0, 0, 0);
|
||||
+
|
||||
+ /**
|
||||
+ * These entities are excluded from Activation range checks.
|
||||
+ *
|
||||
+ * @param entity
|
||||
+ * @param config
|
||||
+ * @return boolean If it should always tick.
|
||||
+ */
|
||||
+ public static boolean initializeEntityActivationState(final Entity entity, final SpigotWorldConfig config) {
|
||||
+ return (entity.activationType == ActivationType.MISC && config.miscActivationRange == 0)
|
||||
+ || (entity.activationType == ActivationType.RAIDER && config.raiderActivationRange == 0)
|
||||
+ || (entity.activationType == ActivationType.ANIMAL && config.animalActivationRange == 0)
|
||||
+ || (entity.activationType == ActivationType.MONSTER && config.monsterActivationRange == 0)
|
||||
+ || (entity.activationType == ActivationType.VILLAGER && config.villagerActivationRange <= 0)
|
||||
+ || (entity.activationType == ActivationType.WATER && config.waterActivationRange <= 0)
|
||||
+ || (entity.activationType == ActivationType.FLYING_MONSTER && config.flyingMonsterActivationRange <= 0)
|
||||
+ || entity instanceof EyeOfEnder
|
||||
+ || entity instanceof Player
|
||||
+ || entity instanceof ThrowableProjectile
|
||||
+ || entity instanceof EnderDragon
|
||||
+ || entity instanceof EnderDragonPart
|
||||
+ || entity instanceof WitherBoss
|
||||
+ || entity instanceof AbstractHurtingProjectile
|
||||
+ || entity instanceof LightningBolt
|
||||
+ || entity instanceof PrimedTnt
|
||||
+ || entity instanceof net.minecraft.world.entity.item.FallingBlockEntity
|
||||
+ || entity instanceof net.minecraft.world.entity.vehicle.AbstractMinecart
|
||||
+ || entity instanceof net.minecraft.world.entity.vehicle.AbstractBoat
|
||||
+ || entity instanceof EndCrystal
|
||||
+ || entity instanceof FireworkRocketEntity
|
||||
+ || entity instanceof ThrownTrident;
|
||||
+ }
|
||||
+
|
||||
+ /**
|
||||
+ * Find what entities are in range of the players in the world and set
|
||||
+ * active if in range.
|
||||
+ *
|
||||
+ * @param world
|
||||
+ */
|
||||
+ public static void activateEntities(final Level world) {
|
||||
+ final int miscActivationRange = world.spigotConfig.miscActivationRange;
|
||||
+ final int raiderActivationRange = world.spigotConfig.raiderActivationRange;
|
||||
+ final int animalActivationRange = world.spigotConfig.animalActivationRange;
|
||||
+ final int monsterActivationRange = world.spigotConfig.monsterActivationRange;
|
||||
+ final int waterActivationRange = world.spigotConfig.waterActivationRange;
|
||||
+ final int flyingActivationRange = world.spigotConfig.flyingMonsterActivationRange;
|
||||
+ final int villagerActivationRange = world.spigotConfig.villagerActivationRange;
|
||||
+ world.wakeupInactiveRemainingAnimals = Math.min(world.wakeupInactiveRemainingAnimals + 1, world.spigotConfig.wakeUpInactiveAnimals);
|
||||
+ world.wakeupInactiveRemainingVillagers = Math.min(world.wakeupInactiveRemainingVillagers + 1, world.spigotConfig.wakeUpInactiveVillagers);
|
||||
+ world.wakeupInactiveRemainingMonsters = Math.min(world.wakeupInactiveRemainingMonsters + 1, world.spigotConfig.wakeUpInactiveMonsters);
|
||||
+ world.wakeupInactiveRemainingFlying = Math.min(world.wakeupInactiveRemainingFlying + 1, world.spigotConfig.wakeUpInactiveFlying);
|
||||
+
|
||||
+ int maxRange = Math.max(monsterActivationRange, animalActivationRange);
|
||||
+ maxRange = Math.max(maxRange, raiderActivationRange);
|
||||
+ maxRange = Math.max(maxRange, miscActivationRange);
|
||||
+ maxRange = Math.max(maxRange, flyingActivationRange);
|
||||
+ maxRange = Math.max(maxRange, waterActivationRange);
|
||||
+ maxRange = Math.max(maxRange, villagerActivationRange);
|
||||
+ maxRange = Math.min((world.spigotConfig.simulationDistance << 4) - 8, maxRange);
|
||||
+
|
||||
+ for (final Player player : world.players()) {
|
||||
+ player.activatedTick = MinecraftServer.currentTick;
|
||||
+ if (world.spigotConfig.ignoreSpectatorActivation && player.isSpectator()) {
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ final int worldHeight = world.getHeight();
|
||||
+ ActivationRange.maxBB = player.getBoundingBox().inflate(maxRange, worldHeight, maxRange);
|
||||
+ ActivationType.MISC.boundingBox = player.getBoundingBox().inflate(miscActivationRange, worldHeight, miscActivationRange);
|
||||
+ ActivationType.RAIDER.boundingBox = player.getBoundingBox().inflate(raiderActivationRange, worldHeight, raiderActivationRange);
|
||||
+ ActivationType.ANIMAL.boundingBox = player.getBoundingBox().inflate(animalActivationRange, worldHeight, animalActivationRange);
|
||||
+ ActivationType.MONSTER.boundingBox = player.getBoundingBox().inflate(monsterActivationRange, worldHeight, monsterActivationRange);
|
||||
+ ActivationType.WATER.boundingBox = player.getBoundingBox().inflate(waterActivationRange, worldHeight, waterActivationRange);
|
||||
+ ActivationType.FLYING_MONSTER.boundingBox = player.getBoundingBox().inflate(flyingActivationRange, worldHeight, flyingActivationRange);
|
||||
+ ActivationType.VILLAGER.boundingBox = player.getBoundingBox().inflate(villagerActivationRange, worldHeight, villagerActivationRange);
|
||||
+
|
||||
+ final java.util.List<Entity> entities = world.getEntities((Entity) null, ActivationRange.maxBB, e -> true);
|
||||
+ final boolean tickMarkers = world.paperConfig().entities.markers.tick;
|
||||
+ for (final Entity entity : entities) {
|
||||
+ if (!tickMarkers && entity instanceof net.minecraft.world.entity.Marker) {
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ ActivationRange.activateEntity(entity);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /**
|
||||
+ * Tries to activate an entity.
|
||||
+ *
|
||||
+ * @param entity
|
||||
+ */
|
||||
+ private static void activateEntity(final Entity entity) {
|
||||
+ if (MinecraftServer.currentTick > entity.activatedTick) {
|
||||
+ if (entity.defaultActivationState) {
|
||||
+ entity.activatedTick = MinecraftServer.currentTick;
|
||||
+ return;
|
||||
+ }
|
||||
+ if (entity.activationType.boundingBox.intersects(entity.getBoundingBox())) {
|
||||
+ entity.activatedTick = MinecraftServer.currentTick;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /**
|
||||
+ * If an entity is not in range, do some more checks to see if we should
|
||||
+ * give it a shot.
|
||||
+ *
|
||||
+ * @param entity
|
||||
+ * @return
|
||||
+ */
|
||||
+ public static int checkEntityImmunities(final Entity entity) { // return # of ticks to get immunity
|
||||
+ final SpigotWorldConfig config = entity.level().spigotConfig;
|
||||
+ final int inactiveWakeUpImmunity = checkInactiveWakeup(entity);
|
||||
+ if (inactiveWakeUpImmunity > -1) {
|
||||
+ return inactiveWakeUpImmunity;
|
||||
+ }
|
||||
+ if (entity.getRemainingFireTicks() > 0) {
|
||||
+ return 2;
|
||||
+ }
|
||||
+ if (entity.activatedImmunityTick >= MinecraftServer.currentTick) {
|
||||
+ return 1;
|
||||
+ }
|
||||
+ final long inactiveFor = MinecraftServer.currentTick - entity.activatedTick;
|
||||
+ if ((entity.activationType != ActivationType.WATER && entity.isInWater() && entity.isPushedByFluid())) {
|
||||
+ return 100;
|
||||
+ }
|
||||
+ if (!entity.onGround() || entity.getDeltaMovement().horizontalDistanceSqr() > 9.999999747378752E-6D) {
|
||||
+ return 100;
|
||||
+ }
|
||||
+ if (!(entity instanceof final AbstractArrow arrow)) {
|
||||
+ if ((!entity.onGround() && !(entity instanceof FlyingMob))) {
|
||||
+ return 10;
|
||||
+ }
|
||||
+ } else if (!arrow.isInGround()) {
|
||||
+ return 1;
|
||||
+ }
|
||||
+ // special cases.
|
||||
+ if (entity instanceof final LivingEntity living) {
|
||||
+ if (living.onClimbable() || living.jumping || living.hurtTime > 0 || !living.activeEffects.isEmpty() || living.isFreezing()) {
|
||||
+ return 1;
|
||||
+ }
|
||||
+ if (entity instanceof final Mob mob && mob.getTarget() != null) {
|
||||
+ return 20;
|
||||
+ }
|
||||
+ if (entity instanceof final Bee bee) {
|
||||
+ final BlockPos movingTarget = bee.getMovingTarget();
|
||||
+ if (bee.isAngry() ||
|
||||
+ (bee.getHivePos() != null && bee.getHivePos().equals(movingTarget)) ||
|
||||
+ (bee.getSavedFlowerPos() != null && bee.getSavedFlowerPos().equals(movingTarget))
|
||||
+ ) {
|
||||
+ return 20;
|
||||
+ }
|
||||
+ }
|
||||
+ if (entity instanceof final Villager villager) {
|
||||
+ final Brain<Villager> behaviorController = villager.getBrain();
|
||||
+
|
||||
+ if (config.villagersActiveForPanic) {
|
||||
+ for (final Activity activity : VILLAGER_PANIC_IMMUNITIES) {
|
||||
+ if (behaviorController.isActive(activity)) {
|
||||
+ return 20 * 5;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (config.villagersWorkImmunityAfter > 0 && inactiveFor >= config.villagersWorkImmunityAfter) {
|
||||
+ if (behaviorController.isActive(Activity.WORK)) {
|
||||
+ return config.villagersWorkImmunityFor;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ if (entity instanceof final Llama llama && llama.inCaravan()) {
|
||||
+ return 1;
|
||||
+ }
|
||||
+ if (entity instanceof final Animal animal) {
|
||||
+ if (animal.isBaby() || animal.isInLove()) {
|
||||
+ return 5;
|
||||
+ }
|
||||
+ if (entity instanceof final Sheep sheep && sheep.isSheared()) {
|
||||
+ return 1;
|
||||
+ }
|
||||
+ }
|
||||
+ if (entity instanceof final Creeper creeper && creeper.isIgnited()) { // isExplosive
|
||||
+ return 20;
|
||||
+ }
|
||||
+ if (entity instanceof final Mob mob && mob.targetSelector.hasTasks()) {
|
||||
+ return 0;
|
||||
+ }
|
||||
+ if (entity instanceof final Pillager pillager) {
|
||||
+ // TODO:?
|
||||
+ }
|
||||
+ }
|
||||
+ // SPIGOT-6644: Otherwise the target refresh tick will be missed
|
||||
+ if (entity instanceof ExperienceOrb) {
|
||||
+ return 20;
|
||||
+ }
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ /**
|
||||
+ * Checks if the entity is active for this tick.
|
||||
+ *
|
||||
+ * @param entity
|
||||
+ * @return
|
||||
+ */
|
||||
+ public static boolean checkIfActive(final Entity entity) {
|
||||
+ // Never safe to skip fireworks or item gravity
|
||||
+ if (entity instanceof FireworkRocketEntity || (entity instanceof ItemEntity && (entity.tickCount + entity.getId()) % 4 == 0)) { // Needed for item gravity, see ItemEntity tick
|
||||
+ return true;
|
||||
+ }
|
||||
+ // special case always immunities
|
||||
+ // immunize brand-new entities, dead entities, and portal scenarios
|
||||
+ if (entity.defaultActivationState || entity.tickCount < 20 * 10 || !entity.isAlive() || (entity.portalProcess != null && !entity.portalProcess.hasExpired()) || entity.portalCooldown > 0) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ // immunize leashed entities
|
||||
+ if (entity instanceof final Mob mob && mob.getLeashHolder() instanceof Player) {
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ boolean isActive = entity.activatedTick >= MinecraftServer.currentTick;
|
||||
+ entity.isTemporarilyActive = false;
|
||||
+
|
||||
+ // Should this entity tick?
|
||||
+ if (!isActive) {
|
||||
+ if ((MinecraftServer.currentTick - entity.activatedTick - 1) % 20 == 0) {
|
||||
+ // Check immunities every 20 ticks.
|
||||
+ final int immunity = checkEntityImmunities(entity);
|
||||
+ if (immunity >= 0) {
|
||||
+ entity.activatedTick = MinecraftServer.currentTick + immunity;
|
||||
+ } else {
|
||||
+ entity.isTemporarilyActive = true;
|
||||
+ }
|
||||
+ isActive = true;
|
||||
+ }
|
||||
+ }
|
||||
+ // removed the original's dumb tick skipping for active entities
|
||||
+ return isActive;
|
||||
+ }
|
||||
+}
|
||||
diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java
|
||||
index d95413af04121fe91ca0f3b0c70025b9808acef9..ad665c7535c615d2b03a3e7864be435f933235dd 100644
|
||||
--- a/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -4,7 +4,6 @@ import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Queues;
|
||||
-import com.google.common.collect.Sets;
|
||||
import com.google.common.collect.ImmutableList.Builder;
|
||||
import com.mojang.datafixers.DataFixer;
|
||||
import com.mojang.logging.LogUtils;
|
||||
@@ -19,7 +18,6 @@ import it.unimi.dsi.fastutil.longs.LongIterator;
|
||||
import it.unimi.dsi.fastutil.longs.LongLinkedOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.longs.LongSet;
|
||||
-import it.unimi.dsi.fastutil.longs.Long2ObjectMap.Entry;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.nio.file.Path;
|
||||
@@ -95,7 +93,6 @@ import net.minecraft.world.level.levelgen.structure.StructureStart;
|
||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
|
||||
import net.minecraft.world.level.storage.DimensionDataStorage;
|
||||
import net.minecraft.world.level.storage.LevelStorageSource;
|
||||
-import net.minecraft.world.phys.Vec3;
|
||||
import org.apache.commons.lang3.mutable.MutableBoolean;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
||||
index 3164f3784131babf9a6663335517a12df7e88a7b..da8848e2a3e3745949eb2356a049451d30f763a7 100644
|
||||
--- a/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -551,6 +551,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
profilerFiller.pop();
|
||||
}
|
||||
|
||||
+ io.papermc.paper.entity.activation.ActivationRange.activateEntities(this); // Paper - EAR
|
||||
this.entityTickList
|
||||
.forEach(
|
||||
entity -> {
|
||||
@@ -979,12 +980,15 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
entity.tickCount++;
|
||||
profilerFiller.push(() -> BuiltInRegistries.ENTITY_TYPE.getKey(entity.getType()).toString());
|
||||
profilerFiller.incrementCounter("tickNonPassenger");
|
||||
+ final boolean isActive = io.papermc.paper.entity.activation.ActivationRange.checkIfActive(entity); // Paper - EAR 2
|
||||
+ if (isActive) { // Paper - EAR 2
|
||||
entity.tick();
|
||||
entity.postTick(); // CraftBukkit
|
||||
+ } else {entity.inactiveTick();} // Paper - EAR 2
|
||||
profilerFiller.pop();
|
||||
|
||||
for (Entity entity1 : entity.getPassengers()) {
|
||||
- this.tickPassenger(entity, entity1);
|
||||
+ this.tickPassenger(entity, entity1, isActive); // Paper - EAR 2
|
||||
}
|
||||
// Paper start - log detailed entity tick information
|
||||
} finally {
|
||||
@@ -995,7 +999,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
// Paper end - log detailed entity tick information
|
||||
}
|
||||
|
||||
- private void tickPassenger(Entity ridingEntity, Entity passengerEntity) {
|
||||
+ private void tickPassenger(Entity ridingEntity, Entity passengerEntity, final boolean isActive) { // Paper - EAR 2
|
||||
if (passengerEntity.isRemoved() || passengerEntity.getVehicle() != ridingEntity) {
|
||||
passengerEntity.stopRiding();
|
||||
} else if (passengerEntity instanceof Player || this.entityTickList.contains(passengerEntity)) {
|
||||
@@ -1004,12 +1008,21 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
ProfilerFiller profilerFiller = Profiler.get();
|
||||
profilerFiller.push(() -> BuiltInRegistries.ENTITY_TYPE.getKey(passengerEntity.getType()).toString());
|
||||
profilerFiller.incrementCounter("tickPassenger");
|
||||
+ // Paper start - EAR 2
|
||||
+ if (isActive) {
|
||||
passengerEntity.rideTick();
|
||||
passengerEntity.postTick(); // CraftBukkit
|
||||
+ } else {
|
||||
+ passengerEntity.setDeltaMovement(Vec3.ZERO);
|
||||
+ passengerEntity.inactiveTick();
|
||||
+ // copied from inside of if (isPassenger()) of passengerTick, but that ifPassenger is unnecessary
|
||||
+ ridingEntity.positionRider(passengerEntity);
|
||||
+ }
|
||||
+ // Paper end - EAR 2
|
||||
profilerFiller.pop();
|
||||
|
||||
for (Entity entity : passengerEntity.getPassengers()) {
|
||||
- this.tickPassenger(passengerEntity, entity);
|
||||
+ this.tickPassenger(passengerEntity, entity, isActive); // Paper - EAR 2
|
||||
}
|
||||
}
|
||||
}
|
||||
diff --git a/net/minecraft/world/entity/AgeableMob.java b/net/minecraft/world/entity/AgeableMob.java
|
||||
index a9f01e616ef6b0d74caf57cd68eb371a4fd30fd5..179f4e4b9b1eb57f78bbb2f9fa34b11ea79b7a88 100644
|
||||
--- a/net/minecraft/world/entity/AgeableMob.java
|
||||
+++ b/net/minecraft/world/entity/AgeableMob.java
|
||||
@@ -126,6 +126,23 @@ public abstract class AgeableMob extends PathfinderMob {
|
||||
super.onSyncedDataUpdated(key);
|
||||
}
|
||||
|
||||
+ // Paper start - EAR 2
|
||||
+ @Override
|
||||
+ public void inactiveTick() {
|
||||
+ super.inactiveTick();
|
||||
+ if (this.level().isClientSide || this.ageLocked) { // CraftBukkit
|
||||
+ this.refreshDimensions();
|
||||
+ } else {
|
||||
+ int age = this.getAge();
|
||||
+ if (age < 0) {
|
||||
+ this.setAge(++age);
|
||||
+ } else if (age > 0) {
|
||||
+ this.setAge(--age);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - EAR 2
|
||||
+
|
||||
@Override
|
||||
public void aiStep() {
|
||||
super.aiStep();
|
||||
diff --git a/net/minecraft/world/entity/AreaEffectCloud.java b/net/minecraft/world/entity/AreaEffectCloud.java
|
||||
index 24735284fda151414d99faad401d25ba60995f9a..23b342cc31c7e72ade0e1ccad86a9ccf34380f13 100644
|
||||
--- a/net/minecraft/world/entity/AreaEffectCloud.java
|
||||
+++ b/net/minecraft/world/entity/AreaEffectCloud.java
|
||||
@@ -128,6 +128,16 @@ public class AreaEffectCloud extends Entity implements TraceableEntity {
|
||||
this.duration = duration;
|
||||
}
|
||||
|
||||
+ // Paper start - EAR 2
|
||||
+ @Override
|
||||
+ public void inactiveTick() {
|
||||
+ super.inactiveTick();
|
||||
+ if (this.tickCount >= this.waitTime + this.duration) {
|
||||
+ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - EAR 2
|
||||
+
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
|
||||
index e7889c9c7b155db46730f5e168bb7fd3d1732a8c..334859c5ff7023c730513301cc11c9837b2c7823 100644
|
||||
--- a/net/minecraft/world/entity/Entity.java
|
||||
+++ b/net/minecraft/world/entity/Entity.java
|
||||
@@ -380,6 +380,15 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
public boolean fixedPose = false; // Paper - Expand Pose API
|
||||
private final int despawnTime; // Paper - entity despawn time limit
|
||||
public final io.papermc.paper.entity.activation.ActivationType activationType = io.papermc.paper.entity.activation.ActivationType.activationTypeFor(this); // Paper - EAR 2/tracking ranges
|
||||
+ // Paper start - EAR 2
|
||||
+ public final boolean defaultActivationState;
|
||||
+ public long activatedTick = Integer.MIN_VALUE;
|
||||
+ public boolean isTemporarilyActive;
|
||||
+ public long activatedImmunityTick = Integer.MIN_VALUE;
|
||||
+
|
||||
+ public void inactiveTick() {
|
||||
+ }
|
||||
+ // Paper end - EAR 2
|
||||
|
||||
public void setOrigin(@javax.annotation.Nonnull org.bukkit.Location location) {
|
||||
this.origin = location.toVector();
|
||||
@@ -417,6 +426,13 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
this.position = Vec3.ZERO;
|
||||
this.blockPosition = BlockPos.ZERO;
|
||||
this.chunkPosition = ChunkPos.ZERO;
|
||||
+ // Paper start - EAR 2
|
||||
+ if (level != null) {
|
||||
+ this.defaultActivationState = io.papermc.paper.entity.activation.ActivationRange.initializeEntityActivationState(this, level.spigotConfig);
|
||||
+ } else {
|
||||
+ this.defaultActivationState = false;
|
||||
+ }
|
||||
+ // Paper end - EAR 2
|
||||
SynchedEntityData.Builder builder = new SynchedEntityData.Builder(this);
|
||||
builder.define(DATA_SHARED_FLAGS_ID, (byte)0);
|
||||
builder.define(DATA_AIR_SUPPLY_ID, this.getMaxAirSupply());
|
||||
@@ -981,6 +997,8 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
} else {
|
||||
this.wasOnFire = this.isOnFire();
|
||||
if (type == MoverType.PISTON) {
|
||||
+ this.activatedTick = Math.max(this.activatedTick, MinecraftServer.currentTick + 20); // Paper - EAR 2
|
||||
+ this.activatedImmunityTick = Math.max(this.activatedImmunityTick, MinecraftServer.currentTick + 20); // Paper - EAR 2
|
||||
movement = this.limitPistonMovement(movement);
|
||||
if (movement.equals(Vec3.ZERO)) {
|
||||
return;
|
||||
@@ -994,6 +1012,13 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
this.stuckSpeedMultiplier = Vec3.ZERO;
|
||||
this.setDeltaMovement(Vec3.ZERO);
|
||||
}
|
||||
+ // Paper start - ignore movement changes while inactive.
|
||||
+ if (isTemporarilyActive && !(this instanceof ItemEntity) && movement == getDeltaMovement() && type == MoverType.SELF) {
|
||||
+ setDeltaMovement(Vec3.ZERO);
|
||||
+ profilerFiller.pop();
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end
|
||||
|
||||
movement = this.maybeBackOffFromEdge(movement, type);
|
||||
Vec3 vec3 = this.collide(movement);
|
||||
diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java
|
||||
index a71a153a91de5a564b946091d8d3ccbb330e4b89..195e1151f7b2a32d6c4eb67edd1952e38f58b266 100644
|
||||
--- a/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -3094,6 +3094,14 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
return false;
|
||||
}
|
||||
|
||||
+ // Paper start - EAR 2
|
||||
+ @Override
|
||||
+ public void inactiveTick() {
|
||||
+ super.inactiveTick();
|
||||
+ ++this.noActionTime; // Above all the floats
|
||||
+ }
|
||||
+ // Paper end - EAR 2
|
||||
+
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
diff --git a/net/minecraft/world/entity/Mob.java b/net/minecraft/world/entity/Mob.java
|
||||
index f7d69db61d1293510428ae275e8a50571dde5ddf..1ed07fd23985a6bf8cf8300f74c92b7531a79fc6 100644
|
||||
--- a/net/minecraft/world/entity/Mob.java
|
||||
+++ b/net/minecraft/world/entity/Mob.java
|
||||
@@ -215,6 +215,19 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
|
||||
return this.lookControl;
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public void inactiveTick() {
|
||||
+ super.inactiveTick();
|
||||
+ if (this.goalSelector.inactiveTick()) {
|
||||
+ this.goalSelector.tick();
|
||||
+ }
|
||||
+ if (this.targetSelector.inactiveTick()) {
|
||||
+ this.targetSelector.tick();
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
public MoveControl getMoveControl() {
|
||||
return this.getControlledVehicle() instanceof Mob mob ? mob.getMoveControl() : this.moveControl;
|
||||
}
|
||||
diff --git a/net/minecraft/world/entity/PathfinderMob.java b/net/minecraft/world/entity/PathfinderMob.java
|
||||
index 0caf50ec50f056b83a20bbc6a2fe0144593aef39..af59a700755654eb68d6bf57d0712c4a2ac6c09b 100644
|
||||
--- a/net/minecraft/world/entity/PathfinderMob.java
|
||||
+++ b/net/minecraft/world/entity/PathfinderMob.java
|
||||
@@ -17,6 +17,8 @@ public abstract class PathfinderMob extends Mob {
|
||||
super(entityType, level);
|
||||
}
|
||||
|
||||
+ public BlockPos movingTarget; public BlockPos getMovingTarget() { return movingTarget; } // Paper
|
||||
+
|
||||
public float getWalkTargetValue(BlockPos pos) {
|
||||
return this.getWalkTargetValue(pos, this.level());
|
||||
}
|
||||
diff --git a/net/minecraft/world/entity/ai/goal/GoalSelector.java b/net/minecraft/world/entity/ai/goal/GoalSelector.java
|
||||
index 9338e63cc28413f5559bb0122ef5e04a84bd51d1..eeba224bd575451ba6023df65ef9d9b97f7f1c71 100644
|
||||
--- a/net/minecraft/world/entity/ai/goal/GoalSelector.java
|
||||
+++ b/net/minecraft/world/entity/ai/goal/GoalSelector.java
|
||||
@@ -25,6 +25,7 @@ public class GoalSelector {
|
||||
private final Map<Goal.Flag, WrappedGoal> lockedFlags = new EnumMap<>(Goal.Flag.class);
|
||||
private final Set<WrappedGoal> availableGoals = new ObjectLinkedOpenHashSet<>();
|
||||
private final EnumSet<Goal.Flag> disabledFlags = EnumSet.noneOf(Goal.Flag.class);
|
||||
+ private int curRate; // Paper - EAR 2
|
||||
|
||||
public void addGoal(int priority, Goal goal) {
|
||||
this.availableGoals.add(new WrappedGoal(priority, goal));
|
||||
@@ -35,6 +36,22 @@ public class GoalSelector {
|
||||
this.availableGoals.removeIf(wrappedGoal -> filter.test(wrappedGoal.getGoal()));
|
||||
}
|
||||
|
||||
+ // Paper start - EAR 2
|
||||
+ public boolean inactiveTick() {
|
||||
+ this.curRate++;
|
||||
+ return this.curRate % 3 == 0; // TODO newGoalRate was already unused in 1.20.4, check if this is correct
|
||||
+ }
|
||||
+
|
||||
+ public boolean hasTasks() {
|
||||
+ for (WrappedGoal task : this.availableGoals) {
|
||||
+ if (task.isRunning()) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ }
|
||||
+ return false;
|
||||
+ }
|
||||
+ // Paper end - EAR 2
|
||||
+
|
||||
public void removeGoal(Goal goal) {
|
||||
for (WrappedGoal wrappedGoal : this.availableGoals) {
|
||||
if (wrappedGoal.getGoal() == goal && wrappedGoal.isRunning()) {
|
||||
diff --git a/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java b/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java
|
||||
index 789fea258d70e60d38271ebb31270562dc7eb3ab..d0ab3db7bbd2942db19f473474371b20ce822608 100644
|
||||
--- a/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java
|
||||
+++ b/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java
|
||||
@@ -23,6 +23,14 @@ public abstract class MoveToBlockGoal extends Goal {
|
||||
public MoveToBlockGoal(PathfinderMob mob, double speedModifier, int searchRange) {
|
||||
this(mob, speedModifier, searchRange, 1);
|
||||
}
|
||||
+ // Paper start - activation range improvements
|
||||
+ @Override
|
||||
+ public void stop() {
|
||||
+ super.stop();
|
||||
+ this.blockPos = BlockPos.ZERO;
|
||||
+ this.mob.movingTarget = null;
|
||||
+ }
|
||||
+ // Paper end
|
||||
|
||||
public MoveToBlockGoal(PathfinderMob mob, double speedModifier, int searchRange, int verticalSearchRange) {
|
||||
this.mob = mob;
|
||||
@@ -113,6 +121,7 @@ public abstract class MoveToBlockGoal extends Goal {
|
||||
mutableBlockPos.setWithOffset(blockPos, i4, i2 - 1, i5);
|
||||
if (this.mob.isWithinRestriction(mutableBlockPos) && this.isValidTarget(this.mob.level(), mutableBlockPos)) {
|
||||
this.blockPos = mutableBlockPos;
|
||||
+ this.mob.movingTarget = mutableBlockPos == BlockPos.ZERO ? null : mutableBlockPos.immutable(); // Paper
|
||||
return true;
|
||||
}
|
||||
}
|
||||
diff --git a/net/minecraft/world/entity/item/ItemEntity.java b/net/minecraft/world/entity/item/ItemEntity.java
|
||||
index 8b034b6bda937b25dbb3d09b8293fed6d7dc512c..52a7ed0d991758bad0dcedcb7f97fb15ac6c6d04 100644
|
||||
--- a/net/minecraft/world/entity/item/ItemEntity.java
|
||||
+++ b/net/minecraft/world/entity/item/ItemEntity.java
|
||||
@@ -124,6 +124,29 @@ public class ItemEntity extends Entity implements TraceableEntity {
|
||||
return 0.04;
|
||||
}
|
||||
|
||||
+ // Paper start - EAR 2
|
||||
+ @Override
|
||||
+ public void inactiveTick() {
|
||||
+ super.inactiveTick();
|
||||
+ if (this.pickupDelay > 0 && this.pickupDelay != 32767) {
|
||||
+ this.pickupDelay--;
|
||||
+ }
|
||||
+ if (this.age != -32768) {
|
||||
+ this.age++;
|
||||
+ }
|
||||
+
|
||||
+ if (!this.level().isClientSide && this.age >= this.despawnRate) {// Paper - Alternative item-despawn-rate
|
||||
+ // CraftBukkit start - fire ItemDespawnEvent
|
||||
+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callItemDespawnEvent(this).isCancelled()) {
|
||||
+ this.age = 0;
|
||||
+ return;
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
+ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - EAR 2
|
||||
+
|
||||
@Override
|
||||
public void tick() {
|
||||
if (this.getItem().isEmpty()) {
|
||||
diff --git a/net/minecraft/world/entity/npc/Villager.java b/net/minecraft/world/entity/npc/Villager.java
|
||||
index 27568a1604d2dd5d46e836bbc25431929e218aa1..2b83262e4a13eae86df82913ce4f3121e3631a43 100644
|
||||
--- a/net/minecraft/world/entity/npc/Villager.java
|
||||
+++ b/net/minecraft/world/entity/npc/Villager.java
|
||||
@@ -265,11 +265,35 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
|
||||
return this.assignProfessionWhenSpawned;
|
||||
}
|
||||
|
||||
+ // Paper start - EAR 2
|
||||
+ @Override
|
||||
+ public void inactiveTick() {
|
||||
+ // SPIGOT-3874, SPIGOT-3894, SPIGOT-3846, SPIGOT-5286 :(
|
||||
+ if (this.getUnhappyCounter() > 0) {
|
||||
+ this.setUnhappyCounter(this.getUnhappyCounter() - 1);
|
||||
+ }
|
||||
+ if (this.isEffectiveAi()) {
|
||||
+ if (this.level().spigotConfig.tickInactiveVillagers) {
|
||||
+ this.customServerAiStep(this.level().getMinecraftWorld());
|
||||
+ } else {
|
||||
+ this.customServerAiStep(this.level().getMinecraftWorld(), true);
|
||||
+ }
|
||||
+ }
|
||||
+ maybeDecayGossip();
|
||||
+ super.inactiveTick();
|
||||
+ }
|
||||
+ // Paper end - EAR 2
|
||||
+
|
||||
@Override
|
||||
protected void customServerAiStep(ServerLevel level) {
|
||||
+ // Paper start - EAR 2
|
||||
+ this.customServerAiStep(level, false);
|
||||
+ }
|
||||
+ protected void customServerAiStep(ServerLevel level, final boolean inactive) {
|
||||
+ // Paper end - EAR 2
|
||||
ProfilerFiller profilerFiller = Profiler.get();
|
||||
profilerFiller.push("villagerBrain");
|
||||
- this.getBrain().tick(level, this);
|
||||
+ if (!inactive) this.getBrain().tick(level, this); // Paper - EAR 2
|
||||
profilerFiller.pop();
|
||||
if (this.assignProfessionWhenSpawned) {
|
||||
this.assignProfessionWhenSpawned = false;
|
||||
@@ -293,7 +317,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
|
||||
this.lastTradedPlayer = null;
|
||||
}
|
||||
|
||||
- if (!this.isNoAi() && this.random.nextInt(100) == 0) {
|
||||
+ if (!inactive && !this.isNoAi() && this.random.nextInt(100) == 0) { // Paper - EAR 2
|
||||
Raid raidAt = level.getRaidAt(this.blockPosition());
|
||||
if (raidAt != null && raidAt.isActive() && !raidAt.isOver()) {
|
||||
level.broadcastEntityEvent(this, (byte)42);
|
||||
@@ -303,6 +327,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
|
||||
if (this.getVillagerData().getProfession() == VillagerProfession.NONE && this.isTrading()) {
|
||||
this.stopTrading();
|
||||
}
|
||||
+ if (inactive) return; // Paper - EAR 2
|
||||
|
||||
super.customServerAiStep(level);
|
||||
}
|
||||
diff --git a/net/minecraft/world/entity/projectile/Arrow.java b/net/minecraft/world/entity/projectile/Arrow.java
|
||||
index c1e09e701757a300183b62d343ded03033e63aa7..56574f8ef879159edc0114da09300143a2c79a35 100644
|
||||
--- a/net/minecraft/world/entity/projectile/Arrow.java
|
||||
+++ b/net/minecraft/world/entity/projectile/Arrow.java
|
||||
@@ -66,6 +66,16 @@ public class Arrow extends AbstractArrow {
|
||||
builder.define(ID_EFFECT_COLOR, -1);
|
||||
}
|
||||
|
||||
+ // Paper start - EAR 2
|
||||
+ @Override
|
||||
+ public void inactiveTick() {
|
||||
+ if (this.isInGround()) {
|
||||
+ this.life++;
|
||||
+ }
|
||||
+ super.inactiveTick();
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
diff --git a/net/minecraft/world/entity/projectile/FireworkRocketEntity.java b/net/minecraft/world/entity/projectile/FireworkRocketEntity.java
|
||||
index 7c0862c50b44555fb27ce7dc46f4ec95a3eb0022..774ca9e0b56fd175ae246051de762d0c4256ca58 100644
|
||||
--- a/net/minecraft/world/entity/projectile/FireworkRocketEntity.java
|
||||
+++ b/net/minecraft/world/entity/projectile/FireworkRocketEntity.java
|
||||
@@ -102,6 +102,21 @@ public class FireworkRocketEntity extends Projectile implements ItemSupplier {
|
||||
return super.shouldRender(x, y, z) && !this.isAttachedToEntity();
|
||||
}
|
||||
|
||||
+ // Paper start - EAR 2
|
||||
+ @Override
|
||||
+ public void inactiveTick() {
|
||||
+ this.life++;
|
||||
+ if (this.life > this.lifetime && this.level() instanceof ServerLevel serverLevel) {
|
||||
+ // CraftBukkit start
|
||||
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callFireworkExplodeEvent(this).isCancelled()) {
|
||||
+ this.explode(serverLevel);
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
+ }
|
||||
+ super.inactiveTick();
|
||||
+ }
|
||||
+ // Paper end - EAR 2
|
||||
+
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
diff --git a/net/minecraft/world/entity/vehicle/MinecartHopper.java b/net/minecraft/world/entity/vehicle/MinecartHopper.java
|
||||
index c553cf0592dfa606dbbb1e6854d3377b9feb5efb..8341e7f01606fca90e69384c16fc19bb9e20d1b7 100644
|
||||
--- a/net/minecraft/world/entity/vehicle/MinecartHopper.java
|
||||
+++ b/net/minecraft/world/entity/vehicle/MinecartHopper.java
|
||||
@@ -47,6 +47,7 @@ public class MinecartHopper extends AbstractMinecartContainer implements Hopper
|
||||
if (flag != this.isEnabled()) {
|
||||
this.setEnabled(flag);
|
||||
}
|
||||
+ this.immunize(); // Paper
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
@@ -100,11 +101,13 @@ public class MinecartHopper extends AbstractMinecartContainer implements Hopper
|
||||
|
||||
public boolean suckInItems() {
|
||||
if (HopperBlockEntity.suckInItems(this.level(), this)) {
|
||||
+ this.immunize(); // Paper
|
||||
return true;
|
||||
} else {
|
||||
for (ItemEntity itemEntity : this.level()
|
||||
.getEntitiesOfClass(ItemEntity.class, this.getBoundingBox().inflate(0.25, 0.0, 0.25), EntitySelector.ENTITY_STILL_ALIVE)) {
|
||||
if (HopperBlockEntity.addItem(this, itemEntity)) {
|
||||
+ this.immunize(); // Paper
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -139,4 +142,11 @@ public class MinecartHopper extends AbstractMinecartContainer implements Hopper
|
||||
public AbstractContainerMenu createMenu(int id, Inventory playerInventory) {
|
||||
return new HopperMenu(id, playerInventory, this);
|
||||
}
|
||||
+
|
||||
+ // Paper start
|
||||
+ public void immunize() {
|
||||
+ this.activatedImmunityTick = Math.max(this.activatedImmunityTick, net.minecraft.server.MinecraftServer.currentTick + 20);
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
}
|
||||
diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java
|
||||
index 32f184288f6065259c921293922c1b0163df4dc4..0f346faa82b988e86834c38837f6f11bea7f31c6 100644
|
||||
--- a/net/minecraft/world/level/Level.java
|
||||
+++ b/net/minecraft/world/level/Level.java
|
||||
@@ -153,6 +153,12 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
public Map<BlockPos, BlockEntity> capturedTileEntities = new java.util.LinkedHashMap<>(); // Paper - Retain block place order when capturing blockstates
|
||||
public List<net.minecraft.world.entity.item.ItemEntity> captureDrops;
|
||||
public final it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap<SpawnCategory> ticksPerSpawnCategory = new it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap<>();
|
||||
+ // Paper start
|
||||
+ public int wakeupInactiveRemainingAnimals;
|
||||
+ public int wakeupInactiveRemainingFlying;
|
||||
+ public int wakeupInactiveRemainingMonsters;
|
||||
+ public int wakeupInactiveRemainingVillagers;
|
||||
+ // Paper end
|
||||
public boolean populating;
|
||||
public final org.spigotmc.SpigotWorldConfig spigotConfig; // Spigot
|
||||
// Paper start - add paper world config
|
||||
diff --git a/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java b/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
|
||||
index 754cfdcd5a28287aa3545aaffdce1e391cbefc1e..1e6e940fca9d96ef410c7bf05524bd9b24db4a79 100644
|
||||
--- a/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
|
||||
+++ b/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
|
||||
@@ -149,6 +149,10 @@ public class PistonMovingBlockEntity extends BlockEntity {
|
||||
}
|
||||
|
||||
entity.setDeltaMovement(d1, d2, d3);
|
||||
+ // Paper - EAR items stuck in slime pushed by a piston
|
||||
+ entity.activatedTick = Math.max(entity.activatedTick, net.minecraft.server.MinecraftServer.currentTick + 10);
|
||||
+ entity.activatedImmunityTick = Math.max(entity.activatedImmunityTick, net.minecraft.server.MinecraftServer.currentTick + 10);
|
||||
+ // Paper end
|
||||
break;
|
||||
}
|
||||
}
|
623
paper-server/patches/features/0004-Anti-Xray.patch
Normal file
623
paper-server/patches/features/0004-Anti-Xray.patch
Normal file
|
@ -0,0 +1,623 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: stonar96 <minecraft.stonar96@gmail.com>
|
||||
Date: Thu, 25 Nov 2021 13:27:51 +0100
|
||||
Subject: [PATCH] Anti-Xray
|
||||
|
||||
|
||||
diff --git a/io/papermc/paper/FeatureHooks.java b/io/papermc/paper/FeatureHooks.java
|
||||
index b97e0a8d4c429776b86def10739faee089e2bc9b..184e6c6fe2ba522d0ea0774604839320c4152371 100644
|
||||
--- a/io/papermc/paper/FeatureHooks.java
|
||||
+++ b/io/papermc/paper/FeatureHooks.java
|
||||
@@ -7,6 +7,7 @@ import it.unimi.dsi.fastutil.longs.LongSets;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectSet;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectSets;
|
||||
+import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -36,20 +37,25 @@ public final class FeatureHooks {
|
||||
}
|
||||
|
||||
public static LevelChunkSection createSection(final Registry<Biome> biomeRegistry, final Level level, final ChunkPos chunkPos, final int chunkSection) {
|
||||
- return new LevelChunkSection(biomeRegistry);
|
||||
+ return new LevelChunkSection(biomeRegistry, level, chunkPos, chunkSection); // Paper - Anti-Xray - Add parameters
|
||||
}
|
||||
|
||||
public static void sendChunkRefreshPackets(final List<ServerPlayer> playersInRange, final LevelChunk chunk) {
|
||||
- final ClientboundLevelChunkWithLightPacket refreshPacket = new ClientboundLevelChunkWithLightPacket(chunk, chunk.level.getLightEngine(), null, null);
|
||||
+ // Paper start - Anti-Xray
|
||||
+ final Map<Object, ClientboundLevelChunkWithLightPacket> refreshPackets = new HashMap<>();
|
||||
for (final ServerPlayer player : playersInRange) {
|
||||
if (player.connection == null) continue;
|
||||
|
||||
- player.connection.send(refreshPacket);
|
||||
+ final Boolean shouldModify = chunk.getLevel().chunkPacketBlockController.shouldModify(player, chunk);
|
||||
+ player.connection.send(refreshPackets.computeIfAbsent(shouldModify, s -> { // Use connection to prevent creating firing event
|
||||
+ return new ClientboundLevelChunkWithLightPacket(chunk, chunk.level.getLightEngine(), null, null, (Boolean) s);
|
||||
+ }));
|
||||
}
|
||||
+ // Paper end - Anti-Xray
|
||||
}
|
||||
|
||||
public static PalettedContainer<BlockState> emptyPalettedBlockContainer() {
|
||||
- return new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES);
|
||||
+ return new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES, null); // Paper - Anti-Xray - Add preset block states
|
||||
}
|
||||
|
||||
public static Set<Long> getSentChunkKeys(final ServerPlayer player) {
|
||||
diff --git a/net/minecraft/network/protocol/game/ClientboundChunksBiomesPacket.java b/net/minecraft/network/protocol/game/ClientboundChunksBiomesPacket.java
|
||||
index d4872b7f4e9591b3b1c67406312905851303f521..cb41460e94161675e2ab43f4b1b5286ee38e2e13 100644
|
||||
--- a/net/minecraft/network/protocol/game/ClientboundChunksBiomesPacket.java
|
||||
+++ b/net/minecraft/network/protocol/game/ClientboundChunksBiomesPacket.java
|
||||
@@ -70,8 +70,10 @@ public record ClientboundChunksBiomesPacket(List<ClientboundChunksBiomesPacket.C
|
||||
}
|
||||
|
||||
public static void extractChunkData(FriendlyByteBuf buffer, LevelChunk chunk) {
|
||||
+ int chunkSectionIndex = 0; // Paper - Anti-Xray
|
||||
for (LevelChunkSection levelChunkSection : chunk.getSections()) {
|
||||
- levelChunkSection.getBiomes().write(buffer);
|
||||
+ levelChunkSection.getBiomes().write(buffer, null, chunkSectionIndex); // Paper - Anti-Xray
|
||||
+ chunkSectionIndex++; // Paper - Anti-Xray
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java b/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
|
||||
index 5d1943d37dfad0c12e77179f0866851532d983e9..3aea76690bc3e35758d3bf274777130af17d8a0f 100644
|
||||
--- a/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
|
||||
+++ b/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
|
||||
@@ -28,7 +28,13 @@ public class ClientboundLevelChunkPacketData {
|
||||
private final byte[] buffer;
|
||||
private final List<ClientboundLevelChunkPacketData.BlockEntityInfo> blockEntitiesData;
|
||||
|
||||
+ // Paper start - Anti-Xray - Add chunk packet info
|
||||
+ @Deprecated @io.papermc.paper.annotation.DoNotUse
|
||||
public ClientboundLevelChunkPacketData(LevelChunk levelChunk) {
|
||||
+ this(levelChunk, null);
|
||||
+ }
|
||||
+ public ClientboundLevelChunkPacketData(LevelChunk levelChunk, io.papermc.paper.antixray.ChunkPacketInfo<net.minecraft.world.level.block.state.BlockState> chunkPacketInfo) {
|
||||
+ // Paper end
|
||||
this.heightmaps = new CompoundTag();
|
||||
|
||||
for (Entry<Heightmap.Types, Heightmap> entry : levelChunk.getHeightmaps()) {
|
||||
@@ -38,7 +44,11 @@ public class ClientboundLevelChunkPacketData {
|
||||
}
|
||||
|
||||
this.buffer = new byte[calculateChunkSize(levelChunk)];
|
||||
- extractChunkData(new FriendlyByteBuf(this.getWriteBuffer()), levelChunk);
|
||||
+ // Paper start - Anti-Xray - Add chunk packet info
|
||||
+ if (chunkPacketInfo != null) {
|
||||
+ chunkPacketInfo.setBuffer(this.buffer);
|
||||
+ }
|
||||
+ extractChunkData(new FriendlyByteBuf(this.getWriteBuffer()), levelChunk, chunkPacketInfo);
|
||||
this.blockEntitiesData = Lists.newArrayList();
|
||||
|
||||
for (Entry<BlockPos, BlockEntity> entryx : levelChunk.getBlockEntities().entrySet()) {
|
||||
@@ -85,9 +95,17 @@ public class ClientboundLevelChunkPacketData {
|
||||
return byteBuf;
|
||||
}
|
||||
|
||||
+ // Paper start - Anti-Xray - Add chunk packet info
|
||||
+ @Deprecated @io.papermc.paper.annotation.DoNotUse
|
||||
public static void extractChunkData(FriendlyByteBuf buffer, LevelChunk chunk) {
|
||||
+ ClientboundLevelChunkPacketData.extractChunkData(buffer, chunk, null);
|
||||
+ }
|
||||
+ public static void extractChunkData(FriendlyByteBuf buffer, LevelChunk chunk, io.papermc.paper.antixray.ChunkPacketInfo<net.minecraft.world.level.block.state.BlockState> chunkPacketInfo) {
|
||||
+ int chunkSectionIndex = 0;
|
||||
for (LevelChunkSection levelChunkSection : chunk.getSections()) {
|
||||
- levelChunkSection.write(buffer);
|
||||
+ levelChunkSection.write(buffer, chunkPacketInfo, chunkSectionIndex);
|
||||
+ chunkSectionIndex++;
|
||||
+ // Paper end - Anti-Xray - Add chunk packet info
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java b/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java
|
||||
index 3a384175f8e7f204234bbaf3081bdc20c47a0d4b..5699bc15eba92e22433a20cb8326b59f2ebd3036 100644
|
||||
--- a/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java
|
||||
+++ b/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java
|
||||
@@ -18,18 +18,31 @@ public class ClientboundLevelChunkWithLightPacket implements Packet<ClientGamePa
|
||||
private final int z;
|
||||
private final ClientboundLevelChunkPacketData chunkData;
|
||||
private final ClientboundLightUpdatePacketData lightData;
|
||||
- // Paper start - Anti-Xray
|
||||
+ // Paper start - Async-Anti-Xray - Ready flag for the connection, add chunk packet info
|
||||
+ private volatile boolean ready;
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean isReady() {
|
||||
+ return this.ready;
|
||||
+ }
|
||||
+
|
||||
public void setReady(final boolean ready) {
|
||||
- // Empty hook, updated by feature patch
|
||||
+ this.ready = ready;
|
||||
}
|
||||
- // Paper end - Anti-Xray
|
||||
|
||||
+ @Deprecated @io.papermc.paper.annotation.DoNotUse
|
||||
public ClientboundLevelChunkWithLightPacket(LevelChunk chunk, LevelLightEngine lightEngine, @Nullable BitSet skyLight, @Nullable BitSet blockLight) {
|
||||
+ this(chunk, lightEngine, skyLight, blockLight, true);
|
||||
+ }
|
||||
+ public ClientboundLevelChunkWithLightPacket(LevelChunk chunk, LevelLightEngine lightEngine, @Nullable BitSet skyLight, @Nullable BitSet blockLight, boolean modifyBlocks) {
|
||||
+ // Paper end - Anti-Xray
|
||||
ChunkPos pos = chunk.getPos();
|
||||
this.x = pos.x;
|
||||
this.z = pos.z;
|
||||
- this.chunkData = new ClientboundLevelChunkPacketData(chunk);
|
||||
+ io.papermc.paper.antixray.ChunkPacketInfo<net.minecraft.world.level.block.state.BlockState> chunkPacketInfo = modifyBlocks ? chunk.getLevel().chunkPacketBlockController.getChunkPacketInfo(this, chunk) : null; // Paper - Ant-Xray
|
||||
+ this.chunkData = new ClientboundLevelChunkPacketData(chunk, chunkPacketInfo); // Paper - Anti-Xray
|
||||
this.lightData = new ClientboundLightUpdatePacketData(pos, lightEngine, skyLight, blockLight);
|
||||
+ chunk.getLevel().chunkPacketBlockController.modifyBlocks(this, chunkPacketInfo); // Paper - Anti-Xray - Modify blocks
|
||||
}
|
||||
|
||||
private ClientboundLevelChunkWithLightPacket(RegistryFriendlyByteBuf buffer) {
|
||||
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
||||
index da8848e2a3e3745949eb2356a049451d30f763a7..192977dd661ee795ada13db895db770293e9b402 100644
|
||||
--- a/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -348,7 +348,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
org.bukkit.generator.BiomeProvider biomeProvider // CraftBukkit
|
||||
) {
|
||||
// CraftBukkit start
|
||||
- super(serverLevelData, dimension, server.registryAccess(), levelStem.type(), false, isDebug, biomeZoomSeed, server.getMaxChainedNeighborUpdates(), gen, biomeProvider, env, spigotConfig -> server.paperConfigurations.createWorldConfig(io.papermc.paper.configuration.PaperConfigurations.createWorldContextMap(levelStorageAccess.levelDirectory.path(), serverLevelData.getLevelName(), dimension.location(), spigotConfig, server.registryAccess(), serverLevelData.getGameRules()))); // Paper - create paper world configs
|
||||
+ super(serverLevelData, dimension, server.registryAccess(), levelStem.type(), false, isDebug, biomeZoomSeed, server.getMaxChainedNeighborUpdates(), gen, biomeProvider, env, spigotConfig -> server.paperConfigurations.createWorldConfig(io.papermc.paper.configuration.PaperConfigurations.createWorldContextMap(levelStorageAccess.levelDirectory.path(), serverLevelData.getLevelName(), dimension.location(), spigotConfig, server.registryAccess(), serverLevelData.getGameRules())), dispatcher); // Paper - create paper world configs; Async-Anti-Xray: Pass executor
|
||||
this.pvpMode = server.isPvpAllowed();
|
||||
this.levelStorageAccess = levelStorageAccess;
|
||||
this.uuid = org.bukkit.craftbukkit.util.WorldUUID.getUUID(levelStorageAccess.levelDirectory.path().toFile());
|
||||
diff --git a/net/minecraft/server/level/ServerPlayerGameMode.java b/net/minecraft/server/level/ServerPlayerGameMode.java
|
||||
index 47ed3ad5c0b4753f58e0bafff5e5e70b2f0bb40b..623c069f1fe079e020c6391a3db1a3d95cd3dbf5 100644
|
||||
--- a/net/minecraft/server/level/ServerPlayerGameMode.java
|
||||
+++ b/net/minecraft/server/level/ServerPlayerGameMode.java
|
||||
@@ -299,6 +299,7 @@ public class ServerPlayerGameMode {
|
||||
org.bukkit.craftbukkit.event.CraftEventFactory.callBlockDamageAbortEvent(this.player, pos, this.player.getInventory().getSelected()); // CraftBukkit
|
||||
}
|
||||
}
|
||||
+ this.level.chunkPacketBlockController.onPlayerLeftClickBlock(this, pos, action, face, maxBuildHeight, sequence); // Paper - Anti-Xray
|
||||
}
|
||||
|
||||
public void destroyAndAck(BlockPos pos, int sequence, String message) {
|
||||
diff --git a/net/minecraft/server/network/PlayerChunkSender.java b/net/minecraft/server/network/PlayerChunkSender.java
|
||||
index 342bc843c384761e883de861044f4f8930ae8763..14878690a88fd4de3e2c127086607e6c819c636c 100644
|
||||
--- a/net/minecraft/server/network/PlayerChunkSender.java
|
||||
+++ b/net/minecraft/server/network/PlayerChunkSender.java
|
||||
@@ -78,8 +78,11 @@ public class PlayerChunkSender {
|
||||
}
|
||||
}
|
||||
|
||||
- private static void sendChunk(ServerGamePacketListenerImpl packetListener, ServerLevel level, LevelChunk chunk) {
|
||||
- packetListener.send(new ClientboundLevelChunkWithLightPacket(chunk, level.getLightEngine(), null, null));
|
||||
+ // Paper start - Anti-Xray
|
||||
+ public static void sendChunk(ServerGamePacketListenerImpl packetListener, ServerLevel level, LevelChunk chunk) {
|
||||
+ final boolean shouldModify = level.chunkPacketBlockController.shouldModify(packetListener.player, chunk);
|
||||
+ packetListener.send(new ClientboundLevelChunkWithLightPacket(chunk, level.getLightEngine(), null, null, shouldModify));
|
||||
+ // Paper end - Anti-Xray
|
||||
// Paper start - PlayerChunkLoadEvent
|
||||
if (io.papermc.paper.event.packet.PlayerChunkLoadEvent.getHandlerList().getRegisteredListeners().length > 0) {
|
||||
new io.papermc.paper.event.packet.PlayerChunkLoadEvent(new org.bukkit.craftbukkit.CraftChunk(chunk), packetListener.getPlayer().getBukkitEntity()).callEvent();
|
||||
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
|
||||
index 38fb0f569ffcd96e0eb6cb6f0769155a17d62874..3d5d84c1c1d431e9b369aa727ab0876f90ff5d61 100644
|
||||
--- a/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/net/minecraft/server/players/PlayerList.java
|
||||
@@ -403,7 +403,7 @@ public abstract class PlayerList {
|
||||
.getOrThrow(net.minecraft.world.level.biome.Biomes.PLAINS);
|
||||
player.connection.send(new net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket(
|
||||
new net.minecraft.world.level.chunk.EmptyLevelChunk(serverLevel, player.chunkPosition(), plains),
|
||||
- serverLevel.getLightEngine(), (java.util.BitSet)null, (java.util.BitSet) null)
|
||||
+ serverLevel.getLightEngine(), (java.util.BitSet)null, (java.util.BitSet) null, true) // Paper - Anti-Xray
|
||||
);
|
||||
}
|
||||
// Paper end - Send empty chunk
|
||||
diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java
|
||||
index 0f346faa82b988e86834c38837f6f11bea7f31c6..771d6ed6a7c889c09efd4ff6e20298c851eaa79f 100644
|
||||
--- a/net/minecraft/world/level/Level.java
|
||||
+++ b/net/minecraft/world/level/Level.java
|
||||
@@ -168,6 +168,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
}
|
||||
// Paper end - add paper world config
|
||||
|
||||
+ public final io.papermc.paper.antixray.ChunkPacketBlockController chunkPacketBlockController; // Paper - Anti-Xray
|
||||
public static BlockPos lastPhysicsProblem; // Spigot
|
||||
private org.spigotmc.TickLimiter entityLimiter;
|
||||
private org.spigotmc.TickLimiter tileLimiter;
|
||||
@@ -214,7 +215,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
org.bukkit.generator.BiomeProvider biomeProvider, // CraftBukkit
|
||||
org.bukkit.World.Environment env, // CraftBukkit
|
||||
java.util.function.Function<org.spigotmc.SpigotWorldConfig, // Spigot - create per world config
|
||||
- io.papermc.paper.configuration.WorldConfiguration> paperWorldConfigCreator // Paper - create paper world config
|
||||
+ io.papermc.paper.configuration.WorldConfiguration> paperWorldConfigCreator, // Paper - create paper world config
|
||||
+ java.util.concurrent.Executor executor // Paper - Anti-Xray
|
||||
) {
|
||||
this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) levelData).getLevelName()); // Spigot
|
||||
this.paperConfig = paperWorldConfigCreator.apply(this.spigotConfig); // Paper - create paper world config
|
||||
@@ -295,6 +297,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
// CraftBukkit end
|
||||
this.entityLimiter = new org.spigotmc.TickLimiter(this.spigotConfig.entityMaxTickTime);
|
||||
this.tileLimiter = new org.spigotmc.TickLimiter(this.spigotConfig.tileMaxTickTime);
|
||||
+ this.chunkPacketBlockController = this.paperConfig().anticheat.antiXray.enabled ? new io.papermc.paper.antixray.ChunkPacketBlockControllerAntiXray(this, executor) : io.papermc.paper.antixray.ChunkPacketBlockController.NO_OPERATION_INSTANCE; // Paper - Anti-Xray
|
||||
}
|
||||
|
||||
// Paper start - Cancel hit for vanished players
|
||||
@@ -495,6 +498,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
// CraftBukkit end
|
||||
|
||||
BlockState blockState = chunkAt.setBlockState(pos, state, (flags & 64) != 0, (flags & 1024) == 0); // CraftBukkit custom NO_PLACE flag
|
||||
+ this.chunkPacketBlockController.onBlockChange(this, pos, state, blockState, flags, recursionLeft); // Paper - Anti-Xray
|
||||
|
||||
if (blockState == null) {
|
||||
// CraftBukkit start - remove blockstate if failed (or the same)
|
||||
diff --git a/net/minecraft/world/level/chunk/ChunkAccess.java b/net/minecraft/world/level/chunk/ChunkAccess.java
|
||||
index 809b3c37d3749c76c3c243cd91c593d03693e9b3..860d1c9729c4ee97ec6f40f7aa969829070b27c0 100644
|
||||
--- a/net/minecraft/world/level/chunk/ChunkAccess.java
|
||||
+++ b/net/minecraft/world/level/chunk/ChunkAccess.java
|
||||
@@ -114,14 +114,14 @@ public abstract class ChunkAccess implements BiomeManager.NoiseBiomeSource, Ligh
|
||||
}
|
||||
}
|
||||
|
||||
- replaceMissingSections(biomeRegistry, this.sections);
|
||||
+ this.replaceMissingSections(biomeRegistry, this.sections); // Paper - Anti-Xray - make it a non-static method
|
||||
this.biomeRegistry = biomeRegistry; // CraftBukkit
|
||||
}
|
||||
|
||||
- private static void replaceMissingSections(Registry<Biome> biomeRegistry, LevelChunkSection[] sections) {
|
||||
+ private void replaceMissingSections(Registry<Biome> biomeRegistry, LevelChunkSection[] sections) { // Paper - Anti-Xray - make it a non-static method
|
||||
for (int i = 0; i < sections.length; i++) {
|
||||
if (sections[i] == null) {
|
||||
- sections[i] = new LevelChunkSection(biomeRegistry);
|
||||
+ sections[i] = new LevelChunkSection(biomeRegistry, this.levelHeightAccessor instanceof net.minecraft.world.level.Level ? (net.minecraft.world.level.Level) this.levelHeightAccessor : null, this.chunkPos, this.levelHeightAccessor.getSectionYFromSectionIndex(i)); // Paper - Anti-Xray - Add parameters
|
||||
}
|
||||
}
|
||||
}
|
||||
diff --git a/net/minecraft/world/level/chunk/LevelChunk.java b/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
index 51a136cf015de730ca0d1b48cf618a2ed69ea89f..96b0342ab7b922aa16d07b6c00542e6cb66c974a 100644
|
||||
--- a/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
+++ b/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
@@ -109,7 +109,7 @@ public class LevelChunk extends ChunkAccess {
|
||||
@Nullable LevelChunk.PostLoadProcessor postLoad,
|
||||
@Nullable BlendingData blendingData
|
||||
) {
|
||||
- super(pos, data, level, level.registryAccess().lookupOrThrow(Registries.BIOME), inhabitedTime, sections, blendingData);
|
||||
+ super(pos, data, level, net.minecraft.server.MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.BIOME), inhabitedTime, sections, blendingData); // Paper - Anti-Xray - The world isn't ready yet, use server singleton for registry
|
||||
this.level = (net.minecraft.server.level.ServerLevel) level; // CraftBukkit - type
|
||||
this.gameEventListenerRegistrySections = new Int2ObjectOpenHashMap<>();
|
||||
|
||||
diff --git a/net/minecraft/world/level/chunk/LevelChunkSection.java b/net/minecraft/world/level/chunk/LevelChunkSection.java
|
||||
index baa9f3e2e6e45c250930658e82bad70a3a292b05..fc21c3268c4b4fda2933d71f0913db28e3796653 100644
|
||||
--- a/net/minecraft/world/level/chunk/LevelChunkSection.java
|
||||
+++ b/net/minecraft/world/level/chunk/LevelChunkSection.java
|
||||
@@ -38,9 +38,15 @@ public class LevelChunkSection {
|
||||
this.recalcBlockCounts();
|
||||
}
|
||||
|
||||
+ // Paper start - Anti-Xray - Add parameters
|
||||
+ @Deprecated @io.papermc.paper.annotation.DoNotUse
|
||||
public LevelChunkSection(Registry<Biome> biomeRegistry) {
|
||||
- this.states = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES);
|
||||
- this.biomes = new PalettedContainer<>(biomeRegistry.asHolderIdMap(), biomeRegistry.getOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES);
|
||||
+ this(biomeRegistry, null, null, 0);
|
||||
+ }
|
||||
+ public LevelChunkSection(Registry<Biome> biomeRegistry, net.minecraft.world.level.Level level, net.minecraft.world.level.ChunkPos chunkPos, int chunkSectionY) {
|
||||
+ // Paper end - Anti-Xray
|
||||
+ this.states = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES, level == null || level.chunkPacketBlockController == null ? null : level.chunkPacketBlockController.getPresetBlockStates(level, chunkPos, chunkSectionY)); // Paper - Anti-Xray - Add preset block states
|
||||
+ this.biomes = new PalettedContainer<>(biomeRegistry.asHolderIdMap(), biomeRegistry.getOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES, null); // Paper - Anti-Xray - Add preset biomes
|
||||
}
|
||||
|
||||
public BlockState getBlockState(int x, int y, int z) {
|
||||
@@ -168,10 +174,16 @@ public class LevelChunkSection {
|
||||
this.biomes = palettedContainer;
|
||||
}
|
||||
|
||||
+ // Paper start - Anti-Xray - Add chunk packet info
|
||||
+ @Deprecated @io.papermc.paper.annotation.DoNotUse
|
||||
public void write(FriendlyByteBuf buffer) {
|
||||
+ this.write(buffer, null, 0);
|
||||
+ }
|
||||
+ public void write(FriendlyByteBuf buffer, io.papermc.paper.antixray.ChunkPacketInfo<BlockState> chunkPacketInfo, int chunkSectionIndex) {
|
||||
buffer.writeShort(this.nonEmptyBlockCount);
|
||||
- this.states.write(buffer);
|
||||
- this.biomes.write(buffer);
|
||||
+ this.states.write(buffer, chunkPacketInfo, chunkSectionIndex);
|
||||
+ this.biomes.write(buffer, null, chunkSectionIndex);
|
||||
+ // Paper end - Anti-Xray
|
||||
}
|
||||
|
||||
public int getSerializedSize() {
|
||||
diff --git a/net/minecraft/world/level/chunk/PalettedContainer.java b/net/minecraft/world/level/chunk/PalettedContainer.java
|
||||
index e8ec28ce3fe13561b45c4654e174776d9d2d7b71..a6028a54c75de068515e95913b21160ab4326985 100644
|
||||
--- a/net/minecraft/world/level/chunk/PalettedContainer.java
|
||||
+++ b/net/minecraft/world/level/chunk/PalettedContainer.java
|
||||
@@ -28,6 +28,7 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer
|
||||
private static final int MIN_PALETTE_BITS = 0;
|
||||
private final PaletteResize<T> dummyPaletteResize = (bits, objectAdded) -> 0;
|
||||
public final IdMap<T> registry;
|
||||
+ private final T @org.jetbrains.annotations.Nullable [] presetValues; // Paper - Anti-Xray - Add preset values
|
||||
private volatile PalettedContainer.Data<T> data;
|
||||
private final PalettedContainer.Strategy strategy;
|
||||
//private final ThreadingDetector threadingDetector = new ThreadingDetector("PalettedContainer"); // Paper - unused
|
||||
@@ -40,13 +41,21 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer
|
||||
// this.threadingDetector.checkAndUnlock(); // Paper - disable this - use proper synchronization
|
||||
}
|
||||
|
||||
+ // Paper start - Anti-Xray - Add preset values
|
||||
+ @Deprecated @io.papermc.paper.annotation.DoNotUse
|
||||
public static <T> Codec<PalettedContainer<T>> codecRW(IdMap<T> registry, Codec<T> codec, PalettedContainer.Strategy strategy, T value) {
|
||||
- PalettedContainerRO.Unpacker<T, PalettedContainer<T>> unpacker = PalettedContainer::unpack;
|
||||
+ return PalettedContainer.codecRW(registry, codec, strategy, value, null);
|
||||
+ }
|
||||
+ public static <T> Codec<PalettedContainer<T>> codecRW(IdMap<T> registry, Codec<T> codec, PalettedContainer.Strategy strategy, T value, T @org.jetbrains.annotations.Nullable [] presetValues) {
|
||||
+ PalettedContainerRO.Unpacker<T, PalettedContainer<T>> unpacker = (idListx, paletteProviderx, serialized) -> {
|
||||
+ return unpack(idListx, paletteProviderx, serialized, value, presetValues);
|
||||
+ };
|
||||
+ // Paper end
|
||||
return codec(registry, codec, strategy, value, unpacker);
|
||||
}
|
||||
|
||||
public static <T> Codec<PalettedContainerRO<T>> codecRO(IdMap<T> registry, Codec<T> codec, PalettedContainer.Strategy strategy, T value) {
|
||||
- PalettedContainerRO.Unpacker<T, PalettedContainerRO<T>> unpacker = (registry1, strategy1, packedData) -> unpack(registry1, strategy1, packedData)
|
||||
+ PalettedContainerRO.Unpacker<T, PalettedContainerRO<T>> unpacker = (registry1, strategy1, packedData) -> unpack(registry1, strategy1, packedData, value, null) // Paper - Anti-Xray - Add preset values
|
||||
.map(container -> (PalettedContainerRO<T>)container);
|
||||
return codec(registry, codec, strategy, value, unpacker);
|
||||
}
|
||||
@@ -66,27 +75,66 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer
|
||||
);
|
||||
}
|
||||
|
||||
+ // Paper start - Anti-Xray - Add preset values
|
||||
+ @Deprecated @io.papermc.paper.annotation.DoNotUse
|
||||
+ public PalettedContainer(IdMap<T> registry, PalettedContainer.Strategy strategy, PalettedContainer.Configuration<T> configuration, BitStorage storage, List<T> values) {
|
||||
+ this(registry, strategy, configuration, storage, values, null, null);
|
||||
+ }
|
||||
public PalettedContainer(
|
||||
- IdMap<T> registry, PalettedContainer.Strategy strategy, PalettedContainer.Configuration<T> configuration, BitStorage storage, List<T> values
|
||||
+ IdMap<T> registry, PalettedContainer.Strategy strategy, PalettedContainer.Configuration<T> configuration, BitStorage storage, List<T> values, T defaultValue, T @org.jetbrains.annotations.Nullable [] presetValues
|
||||
) {
|
||||
+ this.presetValues = presetValues;
|
||||
this.registry = registry;
|
||||
this.strategy = strategy;
|
||||
this.data = new PalettedContainer.Data<>(configuration, storage, configuration.factory().create(configuration.bits(), registry, this, values));
|
||||
+ if (presetValues != null && (configuration.factory() == PalettedContainer.Strategy.SINGLE_VALUE_PALETTE_FACTORY ? this.data.palette.valueFor(0) != defaultValue : configuration.factory() != PalettedContainer.Strategy.GLOBAL_PALETTE_FACTORY)) {
|
||||
+ // In 1.18 Mojang unfortunately removed code that already handled possible resize operations on read from disk for us
|
||||
+ // We readd this here but in a smarter way than it was before
|
||||
+ int maxSize = 1 << configuration.bits();
|
||||
+
|
||||
+ for (T presetValue : presetValues) {
|
||||
+ if (this.data.palette.getSize() >= maxSize) {
|
||||
+ java.util.Set<T> allValues = new java.util.HashSet<>(values);
|
||||
+ allValues.addAll(Arrays.asList(presetValues));
|
||||
+ int newBits = Mth.ceillog2(allValues.size());
|
||||
+
|
||||
+ if (newBits > configuration.bits()) {
|
||||
+ this.onResize(newBits, null);
|
||||
+ }
|
||||
+
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ this.data.palette.idFor(presetValue);
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
- private PalettedContainer(IdMap<T> registry, PalettedContainer.Strategy strategy, PalettedContainer.Data<T> data) {
|
||||
+ // Paper start - Anti-Xray - Add preset values
|
||||
+ private PalettedContainer(IdMap<T> registry, PalettedContainer.Strategy strategy, PalettedContainer.Data<T> data, T @org.jetbrains.annotations.Nullable [] presetValues) {
|
||||
+ this.presetValues = presetValues;
|
||||
+ // Paper end - Anti-Xray
|
||||
this.registry = registry;
|
||||
this.strategy = strategy;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
- private PalettedContainer(PalettedContainer<T> other) {
|
||||
+ private PalettedContainer(PalettedContainer<T> other, T @org.jetbrains.annotations.Nullable [] presetValues) { // Paper - Anti-Xray - Add preset values
|
||||
+ this.presetValues = presetValues; // Paper - Anti-Xray - Add preset values
|
||||
this.registry = other.registry;
|
||||
this.strategy = other.strategy;
|
||||
this.data = other.data.copy(this);
|
||||
}
|
||||
|
||||
+ // Paper start - Anti-Xray - Add preset values
|
||||
+ @Deprecated @io.papermc.paper.annotation.DoNotUse
|
||||
public PalettedContainer(IdMap<T> registry, T palette, PalettedContainer.Strategy strategy) {
|
||||
+ this(registry, palette, strategy, null);
|
||||
+ }
|
||||
+ public PalettedContainer(IdMap<T> registry, T palette, PalettedContainer.Strategy strategy, T @org.jetbrains.annotations.Nullable [] presetValues) {
|
||||
+ this.presetValues = presetValues;
|
||||
+ // Paper end - Anti-Xray
|
||||
this.strategy = strategy;
|
||||
this.registry = registry;
|
||||
this.data = this.createOrReuseData(null, 0);
|
||||
@@ -101,11 +149,30 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer
|
||||
@Override
|
||||
public synchronized int onResize(int bits, T objectAdded) { // Paper - synchronize
|
||||
PalettedContainer.Data<T> data = this.data;
|
||||
+ // Paper start - Anti-Xray - Add preset values
|
||||
+ if (this.presetValues != null && objectAdded != null && data.configuration().factory() == PalettedContainer.Strategy.SINGLE_VALUE_PALETTE_FACTORY) {
|
||||
+ int duplicates = 0;
|
||||
+ List<T> presetValues = Arrays.asList(this.presetValues);
|
||||
+ duplicates += presetValues.contains(objectAdded) ? 1 : 0;
|
||||
+ duplicates += presetValues.contains(data.palette.valueFor(0)) ? 1 : 0;
|
||||
+ bits = Mth.ceillog2((1 << this.strategy.calculateBitsForSerialization(this.registry, 1 << bits)) + presetValues.size() - duplicates);
|
||||
+ }
|
||||
+ // Paper end - Anti-Xray
|
||||
PalettedContainer.Data<T> data1 = this.createOrReuseData(data, bits);
|
||||
data1.copyFrom(data.palette, data.storage);
|
||||
this.data = data1;
|
||||
- return data1.palette.idFor(objectAdded);
|
||||
+ // Paper start - Anti-Xray
|
||||
+ this.addPresetValues();
|
||||
+ return objectAdded == null ? -1 : data1.palette.idFor(objectAdded);
|
||||
+ }
|
||||
+ private void addPresetValues() {
|
||||
+ if (this.presetValues != null && this.data.configuration().factory() != PalettedContainer.Strategy.GLOBAL_PALETTE_FACTORY) {
|
||||
+ for (T presetValue : this.presetValues) {
|
||||
+ this.data.palette.idFor(presetValue);
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
+ // Paper end - Anti-Xray
|
||||
|
||||
public synchronized T getAndSet(int x, int y, int z, T state) { // Paper - synchronize
|
||||
this.acquire();
|
||||
@@ -172,24 +239,35 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer
|
||||
data.palette.read(buffer);
|
||||
buffer.readLongArray(data.storage.getRaw());
|
||||
this.data = data;
|
||||
+ this.addPresetValues(); // Paper - Anti-Xray - Add preset values (inefficient, but this isn't used by the server)
|
||||
} finally {
|
||||
this.release();
|
||||
}
|
||||
}
|
||||
|
||||
+ // Paper start - Anti-Xray; Add chunk packet info
|
||||
@Override
|
||||
- public synchronized void write(FriendlyByteBuf buffer) { // Paper - synchronize
|
||||
+ @Deprecated @io.papermc.paper.annotation.DoNotUse
|
||||
+ public void write(FriendlyByteBuf buffer) {
|
||||
+ this.write(buffer, null, 0);
|
||||
+ }
|
||||
+ @Override
|
||||
+ public synchronized void write(FriendlyByteBuf buffer, @Nullable io.papermc.paper.antixray.ChunkPacketInfo<T> chunkPacketInfo, int chunkSectionIndex) { // Paper - Synchronize
|
||||
this.acquire();
|
||||
|
||||
try {
|
||||
- this.data.write(buffer);
|
||||
+ this.data.write(buffer, chunkPacketInfo, chunkSectionIndex);
|
||||
+ if (chunkPacketInfo != null) {
|
||||
+ chunkPacketInfo.setPresetValues(chunkSectionIndex, this.presetValues);
|
||||
+ }
|
||||
+ // Paper end - Anti-Xray
|
||||
} finally {
|
||||
this.release();
|
||||
}
|
||||
}
|
||||
|
||||
private static <T> DataResult<PalettedContainer<T>> unpack(
|
||||
- IdMap<T> registry, PalettedContainer.Strategy strategy, PalettedContainerRO.PackedData<T> packedData
|
||||
+ IdMap<T> registry, PalettedContainer.Strategy strategy, PalettedContainerRO.PackedData<T> packedData, T defaultValue, T @org.jetbrains.annotations.Nullable [] presetValues // Paper - Anti-Xray - Add preset values
|
||||
) {
|
||||
List<T> list = packedData.paletteEntries();
|
||||
int size = strategy.size();
|
||||
@@ -222,7 +300,7 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer
|
||||
}
|
||||
}
|
||||
|
||||
- return DataResult.success(new PalettedContainer<>(registry, strategy, configuration, bitStorage, list));
|
||||
+ return DataResult.success(new PalettedContainer<>(registry, strategy, configuration, bitStorage, list, defaultValue, presetValues)); // Paper - Anti-Xray - Add preset values
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -280,12 +358,12 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer
|
||||
|
||||
@Override
|
||||
public PalettedContainer<T> copy() {
|
||||
- return new PalettedContainer<>(this);
|
||||
+ return new PalettedContainer<>(this, this.presetValues); // Paper - Anti-Xray - Add preset values
|
||||
}
|
||||
|
||||
@Override
|
||||
public PalettedContainer<T> recreate() {
|
||||
- return new PalettedContainer<>(this.registry, this.data.palette.valueFor(0), this.strategy);
|
||||
+ return new PalettedContainer<>(this.registry, this.data.palette.valueFor(0), this.strategy, this.presetValues); // Paper - Anti-Xray - Add preset values
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -324,9 +402,16 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer
|
||||
return 1 + this.palette.getSerializedSize() + VarInt.getByteSize(this.storage.getRaw().length) + this.storage.getRaw().length * 8;
|
||||
}
|
||||
|
||||
- public void write(FriendlyByteBuf buffer) {
|
||||
+ // Paper start - Anti-Xray - Add chunk packet info
|
||||
+ public void write(FriendlyByteBuf buffer, @Nullable io.papermc.paper.antixray.ChunkPacketInfo<T> chunkPacketInfo, int chunkSectionIndex) {
|
||||
buffer.writeByte(this.storage.getBits());
|
||||
this.palette.write(buffer);
|
||||
+ if (chunkPacketInfo != null) {
|
||||
+ chunkPacketInfo.setBits(chunkSectionIndex, this.configuration.bits());
|
||||
+ chunkPacketInfo.setPalette(chunkSectionIndex, this.palette);
|
||||
+ chunkPacketInfo.setIndex(chunkSectionIndex, buffer.writerIndex() + VarInt.getByteSize(this.storage.getRaw().length));
|
||||
+ }
|
||||
+ // Paper end
|
||||
buffer.writeLongArray(this.storage.getRaw());
|
||||
}
|
||||
|
||||
diff --git a/net/minecraft/world/level/chunk/PalettedContainerRO.java b/net/minecraft/world/level/chunk/PalettedContainerRO.java
|
||||
index bfbb1a2bb4abbb369a24f2f01439e9ea3e16794b..8d6ed8be4d93f7d4e6ea80c351020d88ee98aa4d 100644
|
||||
--- a/net/minecraft/world/level/chunk/PalettedContainerRO.java
|
||||
+++ b/net/minecraft/world/level/chunk/PalettedContainerRO.java
|
||||
@@ -14,7 +14,10 @@ public interface PalettedContainerRO<T> {
|
||||
|
||||
void getAll(Consumer<T> consumer);
|
||||
|
||||
- void write(FriendlyByteBuf buffer);
|
||||
+ // Paper start - Anti-Xray - Add chunk packet info
|
||||
+ @Deprecated @io.papermc.paper.annotation.DoNotUse void write(FriendlyByteBuf buffer);
|
||||
+ void write(FriendlyByteBuf buffer, @javax.annotation.Nullable io.papermc.paper.antixray.ChunkPacketInfo<T> chunkPacketInfo, int chunkSectionIndex);
|
||||
+ // Paper end
|
||||
|
||||
int getSerializedSize();
|
||||
|
||||
diff --git a/net/minecraft/world/level/chunk/storage/SerializableChunkData.java b/net/minecraft/world/level/chunk/storage/SerializableChunkData.java
|
||||
index 37437a86d74291fab1de9495008aafb15dfadce0..cf6e2053d81f7b0f8c8e58b9c0fad3285ebc047d 100644
|
||||
--- a/net/minecraft/world/level/chunk/storage/SerializableChunkData.java
|
||||
+++ b/net/minecraft/world/level/chunk/storage/SerializableChunkData.java
|
||||
@@ -94,7 +94,7 @@ public record SerializableChunkData(
|
||||
, @Nullable net.minecraft.nbt.Tag persistentDataContainer // CraftBukkit - persistentDataContainer
|
||||
) {
|
||||
public static final Codec<PalettedContainer<BlockState>> BLOCK_STATE_CODEC = PalettedContainer.codecRW(
|
||||
- Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState()
|
||||
+ Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState(), null // Paper - Anti-Xray
|
||||
);
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
private static final String TAG_UPGRADE_DATA = "UpgradeData";
|
||||
@@ -128,6 +128,7 @@ public record SerializableChunkData(
|
||||
|
||||
@Nullable
|
||||
public static SerializableChunkData parse(LevelHeightAccessor levelHeightAccessor, RegistryAccess registries, CompoundTag tag) {
|
||||
+ net.minecraft.server.level.ServerLevel serverLevel = (net.minecraft.server.level.ServerLevel) levelHeightAccessor; // Paper - Anti-Xray This is is seemingly only called from ChunkMap, where, we have a server level. We'll fight this later if needed.
|
||||
if (!tag.contains("Status", 8)) {
|
||||
return null;
|
||||
} else {
|
||||
@@ -212,18 +213,21 @@ public record SerializableChunkData(
|
||||
Codec<PalettedContainer<Holder<Biome>>> codec = makeBiomeCodecRW(registry); // CraftBukkit - read/write
|
||||
|
||||
for (int i2 = 0; i2 < list7.size(); i2++) {
|
||||
- CompoundTag compound2 = list7.getCompound(i2);
|
||||
+ CompoundTag compound2 = list7.getCompound(i2); final CompoundTag sectionData = compound2; // Paper - Anti-Xray - OBFHELPER
|
||||
int _byte = compound2.getByte("Y");
|
||||
LevelChunkSection levelChunkSection;
|
||||
if (_byte >= levelHeightAccessor.getMinSectionY() && _byte <= levelHeightAccessor.getMaxSectionY()) {
|
||||
+ // Paper start - Anti-Xray - Add preset block states
|
||||
+ BlockState[] presetBlockStates = serverLevel.chunkPacketBlockController.getPresetBlockStates(serverLevel, chunkPos, _byte);
|
||||
PalettedContainer<BlockState> palettedContainer;
|
||||
if (compound2.contains("block_states", 10)) {
|
||||
- palettedContainer = BLOCK_STATE_CODEC.parse(NbtOps.INSTANCE, compound2.getCompound("block_states"))
|
||||
+ Codec<PalettedContainer<BlockState>> blockStateCodec = presetBlockStates == null ? BLOCK_STATE_CODEC : PalettedContainer.codecRW(Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState(), presetBlockStates); // Paper - Anti-Xray
|
||||
+ palettedContainer = blockStateCodec.parse(NbtOps.INSTANCE, sectionData.getCompound("block_states")) // Paper - Anti-Xray
|
||||
.promotePartial(string -> logErrors(chunkPos, _byte, string))
|
||||
.getOrThrow(SerializableChunkData.ChunkReadException::new);
|
||||
} else {
|
||||
palettedContainer = new PalettedContainer<>(
|
||||
- Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES
|
||||
+ Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES, presetBlockStates // Paper - Anti-Xray
|
||||
);
|
||||
}
|
||||
|
||||
@@ -234,7 +238,7 @@ public record SerializableChunkData(
|
||||
.getOrThrow(SerializableChunkData.ChunkReadException::new);
|
||||
} else {
|
||||
palettedContainerRo = new PalettedContainer<>(
|
||||
- registry.asHolderIdMap(), registry.getOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES
|
||||
+ registry.asHolderIdMap(), registry.getOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES, null // Paper - Anti-Xray - Add preset biomes
|
||||
);
|
||||
}
|
||||
|
||||
@@ -414,7 +418,7 @@ public record SerializableChunkData(
|
||||
|
||||
// CraftBukkit start - read/write
|
||||
private static Codec<PalettedContainer<Holder<Biome>>> makeBiomeCodecRW(Registry<Biome> iregistry) {
|
||||
- return PalettedContainer.codecRW(iregistry.asHolderIdMap(), iregistry.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, iregistry.getOrThrow(Biomes.PLAINS));
|
||||
+ return PalettedContainer.codecRW(iregistry.asHolderIdMap(), iregistry.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, iregistry.getOrThrow(Biomes.PLAINS), null); // Paper - Anti-Xray - Add preset biomes
|
||||
}
|
||||
// CraftBukkit end
|
||||
|
|
@ -0,0 +1,354 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Andrew Steinborn <git@steinborn.me>
|
||||
Date: Mon, 26 Jul 2021 02:15:17 -0400
|
||||
Subject: [PATCH] Use Velocity compression and cipher natives
|
||||
|
||||
|
||||
diff --git a/net/minecraft/network/CipherDecoder.java b/net/minecraft/network/CipherDecoder.java
|
||||
index 429325ffb7db2b85ed271ddf3da64c6fdc593673..d764552aea825af7bbf0f47c9d88af527d9dbe62 100644
|
||||
--- a/net/minecraft/network/CipherDecoder.java
|
||||
+++ b/net/minecraft/network/CipherDecoder.java
|
||||
@@ -7,14 +7,30 @@ import java.util.List;
|
||||
import javax.crypto.Cipher;
|
||||
|
||||
public class CipherDecoder extends MessageToMessageDecoder<ByteBuf> {
|
||||
- private final CipherBase cipher;
|
||||
+ private final com.velocitypowered.natives.encryption.VelocityCipher cipher; // Paper - Use Velocity cipher
|
||||
|
||||
- public CipherDecoder(Cipher cipher) {
|
||||
- this.cipher = new CipherBase(cipher);
|
||||
+ public CipherDecoder(com.velocitypowered.natives.encryption.VelocityCipher cipher) { // Paper - Use Velocity cipher
|
||||
+ this.cipher = cipher; // Paper - Use Velocity cipher
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void decode(ChannelHandlerContext context, ByteBuf in, List<Object> out) throws Exception {
|
||||
- out.add(this.cipher.decipher(context, in));
|
||||
+ // Paper start - Use Velocity cipher
|
||||
+ ByteBuf compatible = com.velocitypowered.natives.util.MoreByteBufUtils.ensureCompatible(context.alloc(), this.cipher, in);
|
||||
+ try {
|
||||
+ this.cipher.process(compatible);
|
||||
+ out.add(compatible);
|
||||
+ } catch (Exception e) {
|
||||
+ compatible.release(); // compatible will never be used if we throw an exception
|
||||
+ throw e;
|
||||
+ }
|
||||
+ // Paper end - Use Velocity cipher
|
||||
}
|
||||
+
|
||||
+ // Paper start - Use Velocity cipher
|
||||
+ @Override
|
||||
+ public void handlerRemoved(ChannelHandlerContext ctx) {
|
||||
+ this.cipher.close();
|
||||
+ }
|
||||
+ // Paper end - Use Velocity cipher
|
||||
}
|
||||
diff --git a/net/minecraft/network/CipherEncoder.java b/net/minecraft/network/CipherEncoder.java
|
||||
index 992b9c7aed57ce29cdd2b4f66737d39db214f0cf..b927c85923147d2b346e892a3e4deee48b3d073e 100644
|
||||
--- a/net/minecraft/network/CipherEncoder.java
|
||||
+++ b/net/minecraft/network/CipherEncoder.java
|
||||
@@ -5,15 +5,31 @@ import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.MessageToByteEncoder;
|
||||
import javax.crypto.Cipher;
|
||||
|
||||
-public class CipherEncoder extends MessageToByteEncoder<ByteBuf> {
|
||||
- private final CipherBase cipher;
|
||||
+public class CipherEncoder extends io.netty.handler.codec.MessageToMessageEncoder<ByteBuf> { // Paper - Use Velocity cipher; change superclass
|
||||
+ private final com.velocitypowered.natives.encryption.VelocityCipher cipher; // Paper - Use Velocity cipher
|
||||
|
||||
- public CipherEncoder(Cipher cipher) {
|
||||
- this.cipher = new CipherBase(cipher);
|
||||
+ public CipherEncoder(com.velocitypowered.natives.encryption.VelocityCipher cipher) { // Paper - Use Velocity cipher
|
||||
+ this.cipher = cipher; // Paper - Use Velocity cipher
|
||||
}
|
||||
|
||||
+ // Paper start - Use Velocity cipher
|
||||
@Override
|
||||
- protected void encode(ChannelHandlerContext context, ByteBuf message, ByteBuf out) throws Exception {
|
||||
- this.cipher.encipher(message, out);
|
||||
+ protected void encode(ChannelHandlerContext context, ByteBuf message, java.util.List<Object> list) throws Exception {
|
||||
+ ByteBuf compatible = com.velocitypowered.natives.util.MoreByteBufUtils.ensureCompatible(context.alloc(), this.cipher, message);
|
||||
+ try {
|
||||
+ this.cipher.process(compatible);
|
||||
+ list.add(compatible);
|
||||
+ } catch (Exception e) {
|
||||
+ compatible.release(); // compatible will never be used if we throw an exception
|
||||
+ throw e;
|
||||
+ }
|
||||
+ // Paper end - Use Velocity cipher
|
||||
}
|
||||
+
|
||||
+ // Paper start - Use Velocity cipher
|
||||
+ @Override
|
||||
+ public void handlerRemoved(ChannelHandlerContext ctx) {
|
||||
+ this.cipher.close();
|
||||
+ }
|
||||
+ // Paper end - Use Velocity cipher
|
||||
}
|
||||
diff --git a/net/minecraft/network/CompressionDecoder.java b/net/minecraft/network/CompressionDecoder.java
|
||||
index fcf0e557fbcbd5f306625096d859578fe8511734..2c7f935fcecb24a4394fdde523219a5b5984a673 100644
|
||||
--- a/net/minecraft/network/CompressionDecoder.java
|
||||
+++ b/net/minecraft/network/CompressionDecoder.java
|
||||
@@ -12,14 +12,22 @@ import java.util.zip.Inflater;
|
||||
public class CompressionDecoder extends ByteToMessageDecoder {
|
||||
public static final int MAXIMUM_COMPRESSED_LENGTH = 2097152;
|
||||
public static final int MAXIMUM_UNCOMPRESSED_LENGTH = 8388608;
|
||||
+ private com.velocitypowered.natives.compression.VelocityCompressor compressor; // Paper - Use Velocity cipher
|
||||
private Inflater inflater;
|
||||
private int threshold;
|
||||
private boolean validateDecompressed;
|
||||
|
||||
+ // Paper start - Use Velocity cipher
|
||||
+ @io.papermc.paper.annotation.DoNotUse
|
||||
public CompressionDecoder(int threshold, boolean validateDecompressed) {
|
||||
+ this(null, threshold, validateDecompressed);
|
||||
+ }
|
||||
+ public CompressionDecoder(com.velocitypowered.natives.compression.VelocityCompressor compressor, int threshold, boolean validateDecompressed) {
|
||||
this.threshold = threshold;
|
||||
this.validateDecompressed = validateDecompressed;
|
||||
- this.inflater = new Inflater();
|
||||
+ this.inflater = compressor == null ? new Inflater() : null;
|
||||
+ this.compressor = compressor;
|
||||
+ // Paper end - Use Velocity cipher
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -39,14 +47,42 @@ public class CompressionDecoder extends ByteToMessageDecoder {
|
||||
}
|
||||
}
|
||||
|
||||
+ if (inflater != null) { // Paper - Use Velocity cipher; fallback to vanilla inflater
|
||||
this.setupInflaterInput(in);
|
||||
ByteBuf byteBuf = this.inflate(context, i);
|
||||
this.inflater.reset();
|
||||
out.add(byteBuf);
|
||||
+ return; // Paper - Use Velocity cipher
|
||||
+ } // Paper - use velocity compression
|
||||
+
|
||||
+ // Paper start - Use Velocity cipher
|
||||
+ int claimedUncompressedSize = i; // OBFHELPER
|
||||
+ ByteBuf compatibleIn = com.velocitypowered.natives.util.MoreByteBufUtils.ensureCompatible(context.alloc(), this.compressor, in);
|
||||
+ ByteBuf uncompressed = com.velocitypowered.natives.util.MoreByteBufUtils.preferredBuffer(context.alloc(), this.compressor, claimedUncompressedSize);
|
||||
+ try {
|
||||
+ this.compressor.inflate(compatibleIn, uncompressed, claimedUncompressedSize);
|
||||
+ out.add(uncompressed);
|
||||
+ in.clear();
|
||||
+ } catch (Exception e) {
|
||||
+ uncompressed.release();
|
||||
+ throw e;
|
||||
+ } finally {
|
||||
+ compatibleIn.release();
|
||||
+ }
|
||||
+ // Paper end - Use Velocity cipher
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+ // Paper start - Use Velocity cipher
|
||||
+ @Override
|
||||
+ public void handlerRemoved0(ChannelHandlerContext ctx) {
|
||||
+ if (this.compressor != null) {
|
||||
+ this.compressor.close();
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - Use Velocity cipher
|
||||
+
|
||||
private void setupInflaterInput(ByteBuf buffer) {
|
||||
ByteBuffer byteBuffer;
|
||||
if (buffer.nioBufferCount() > 0) {
|
||||
@@ -81,7 +117,13 @@ public class CompressionDecoder extends ByteToMessageDecoder {
|
||||
}
|
||||
}
|
||||
|
||||
- public void setThreshold(int threshold, boolean validateDecompressed) {
|
||||
+ // Paper start - Use Velocity cipher
|
||||
+ public void setThreshold(com.velocitypowered.natives.compression.VelocityCompressor compressor, int threshold, boolean validateDecompressed) {
|
||||
+ if (this.compressor == null && compressor != null) { // Only re-configure once. Re-reconfiguring would require closing the native compressor.
|
||||
+ this.compressor = compressor;
|
||||
+ this.inflater = null;
|
||||
+ }
|
||||
+ // Paper end - Use Velocity cipher
|
||||
this.threshold = threshold;
|
||||
this.validateDecompressed = validateDecompressed;
|
||||
}
|
||||
diff --git a/net/minecraft/network/CompressionEncoder.java b/net/minecraft/network/CompressionEncoder.java
|
||||
index bc674b08a41d5529fe06c6d3f077051cf4138f73..ea8a894158c44c2e7943dea43ecd8e1f0075b18f 100644
|
||||
--- a/net/minecraft/network/CompressionEncoder.java
|
||||
+++ b/net/minecraft/network/CompressionEncoder.java
|
||||
@@ -6,17 +6,31 @@ import io.netty.handler.codec.MessageToByteEncoder;
|
||||
import java.util.zip.Deflater;
|
||||
|
||||
public class CompressionEncoder extends MessageToByteEncoder<ByteBuf> {
|
||||
- private final byte[] encodeBuf = new byte[8192];
|
||||
+ @javax.annotation.Nullable private final byte[] encodeBuf; // Paper - Use Velocity cipher
|
||||
+ @javax.annotation.Nullable // Paper - Use Velocity cipher
|
||||
private final Deflater deflater;
|
||||
+ @javax.annotation.Nullable private final com.velocitypowered.natives.compression.VelocityCompressor compressor; // Paper - Use Velocity cipher
|
||||
private int threshold;
|
||||
|
||||
+ // Paper start - Use Velocity cipher
|
||||
public CompressionEncoder(int threshold) {
|
||||
+ this(null, threshold);
|
||||
+ }
|
||||
+ public CompressionEncoder(@javax.annotation.Nullable com.velocitypowered.natives.compression.VelocityCompressor compressor, int threshold) {
|
||||
this.threshold = threshold;
|
||||
- this.deflater = new Deflater();
|
||||
+ if (compressor == null) {
|
||||
+ this.encodeBuf = new byte[8192];
|
||||
+ this.deflater = new Deflater();
|
||||
+ } else {
|
||||
+ this.encodeBuf = null;
|
||||
+ this.deflater = null;
|
||||
+ }
|
||||
+ this.compressor = compressor;
|
||||
+ // Paper end - Use Velocity cipher
|
||||
}
|
||||
|
||||
@Override
|
||||
- protected void encode(ChannelHandlerContext context, ByteBuf encodingByteBuf, ByteBuf byteBuf) {
|
||||
+ protected void encode(ChannelHandlerContext context, ByteBuf encodingByteBuf, ByteBuf byteBuf) throws Exception { // Paper - Use Velocity cipher
|
||||
int i = encodingByteBuf.readableBytes();
|
||||
if (i > 8388608) {
|
||||
throw new IllegalArgumentException("Packet too big (is " + i + ", should be less than 8388608)");
|
||||
@@ -25,6 +39,7 @@ public class CompressionEncoder extends MessageToByteEncoder<ByteBuf> {
|
||||
VarInt.write(byteBuf, 0);
|
||||
byteBuf.writeBytes(encodingByteBuf);
|
||||
} else {
|
||||
+ if (this.deflater != null) { // Paper - Use Velocity cipher
|
||||
byte[] bytes = new byte[i];
|
||||
encodingByteBuf.readBytes(bytes);
|
||||
VarInt.write(byteBuf, bytes.length);
|
||||
@@ -37,6 +52,17 @@ public class CompressionEncoder extends MessageToByteEncoder<ByteBuf> {
|
||||
}
|
||||
|
||||
this.deflater.reset();
|
||||
+ // Paper start - Use Velocity cipher
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ VarInt.write(byteBuf, i);
|
||||
+ final ByteBuf compatibleIn = com.velocitypowered.natives.util.MoreByteBufUtils.ensureCompatible(context.alloc(), this.compressor, encodingByteBuf);
|
||||
+ try {
|
||||
+ this.compressor.deflate(compatibleIn, byteBuf);
|
||||
+ } finally {
|
||||
+ compatibleIn.release();
|
||||
+ }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -48,4 +74,31 @@ public class CompressionEncoder extends MessageToByteEncoder<ByteBuf> {
|
||||
public void setThreshold(int threshold) {
|
||||
this.threshold = threshold;
|
||||
}
|
||||
+
|
||||
+ // Paper start - Use Velocity cipher
|
||||
+ @Override
|
||||
+ protected ByteBuf allocateBuffer(ChannelHandlerContext ctx, ByteBuf msg, boolean preferDirect) throws Exception {
|
||||
+ if (this.compressor != null) {
|
||||
+ // We allocate bytes to be compressed plus 1 byte. This covers two cases:
|
||||
+ //
|
||||
+ // - Compression
|
||||
+ // According to https://github.com/ebiggers/libdeflate/blob/master/libdeflate.h#L103,
|
||||
+ // if the data compresses well (and we do not have some pathological case) then the maximum
|
||||
+ // size the compressed size will ever be is the input size minus one.
|
||||
+ // - Uncompressed
|
||||
+ // This is fairly obvious - we will then have one more than the uncompressed size.
|
||||
+ final int initialBufferSize = msg.readableBytes() + 1;
|
||||
+ return com.velocitypowered.natives.util.MoreByteBufUtils.preferredBuffer(ctx.alloc(), this.compressor, initialBufferSize);
|
||||
+ }
|
||||
+
|
||||
+ return super.allocateBuffer(ctx, msg, preferDirect);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void handlerRemoved(ChannelHandlerContext ctx) {
|
||||
+ if (this.compressor != null) {
|
||||
+ this.compressor.close();
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - Use Velocity cipher
|
||||
}
|
||||
diff --git a/net/minecraft/network/Connection.java b/net/minecraft/network/Connection.java
|
||||
index ad8f8428b75e37097487cdfbd0db2421ee4cbe37..208efae06c7c44f220d4192219a86ec55c98a2fe 100644
|
||||
--- a/net/minecraft/network/Connection.java
|
||||
+++ b/net/minecraft/network/Connection.java
|
||||
@@ -772,11 +772,22 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
return connection;
|
||||
}
|
||||
|
||||
- public void setEncryptionKey(Cipher decryptingCipher, Cipher encryptingCipher) {
|
||||
- this.encrypted = true;
|
||||
- this.channel.pipeline().addBefore("splitter", "decrypt", new CipherDecoder(decryptingCipher));
|
||||
- this.channel.pipeline().addBefore("prepender", "encrypt", new CipherEncoder(encryptingCipher));
|
||||
+ // Paper start - Use Velocity cipher
|
||||
+ public void setEncryptionKey(javax.crypto.SecretKey key) throws net.minecraft.util.CryptException {
|
||||
+ if (!this.encrypted) {
|
||||
+ try {
|
||||
+ com.velocitypowered.natives.encryption.VelocityCipher decryptionCipher = com.velocitypowered.natives.util.Natives.cipher.get().forDecryption(key);
|
||||
+ com.velocitypowered.natives.encryption.VelocityCipher encryptionCipher = com.velocitypowered.natives.util.Natives.cipher.get().forEncryption(key);
|
||||
+
|
||||
+ this.encrypted = true;
|
||||
+ this.channel.pipeline().addBefore("splitter", "decrypt", new CipherDecoder(decryptionCipher));
|
||||
+ this.channel.pipeline().addBefore("prepender", "encrypt", new CipherEncoder(encryptionCipher));
|
||||
+ } catch (java.security.GeneralSecurityException e) {
|
||||
+ throw new net.minecraft.util.CryptException(e);
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
+ // Paper end - Use Velocity cipher
|
||||
|
||||
public boolean isEncrypted() {
|
||||
return this.encrypted;
|
||||
@@ -815,16 +826,17 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
// Paper end - add proper async disconnect
|
||||
public void setupCompression(int threshold, boolean validateDecompressed) {
|
||||
if (threshold >= 0) {
|
||||
+ com.velocitypowered.natives.compression.VelocityCompressor compressor = com.velocitypowered.natives.util.Natives.compress.get().create(io.papermc.paper.configuration.GlobalConfiguration.get().misc.compressionLevel.or(-1)); // Paper - Use Velocity cipher
|
||||
if (this.channel.pipeline().get("decompress") instanceof CompressionDecoder compressionDecoder) {
|
||||
- compressionDecoder.setThreshold(threshold, validateDecompressed);
|
||||
+ compressionDecoder.setThreshold(compressor, threshold, validateDecompressed); // Paper - Use Velocity cipher
|
||||
} else {
|
||||
- this.channel.pipeline().addAfter("splitter", "decompress", new CompressionDecoder(threshold, validateDecompressed));
|
||||
+ this.channel.pipeline().addAfter("splitter", "decompress", new CompressionDecoder(compressor, threshold, validateDecompressed)); // Paper - Use Velocity cipher
|
||||
}
|
||||
|
||||
if (this.channel.pipeline().get("compress") instanceof CompressionEncoder compressionEncoder) {
|
||||
compressionEncoder.setThreshold(threshold);
|
||||
} else {
|
||||
- this.channel.pipeline().addAfter("prepender", "compress", new CompressionEncoder(threshold));
|
||||
+ this.channel.pipeline().addAfter("prepender", "compress", new CompressionEncoder(compressor, threshold)); // Paper - Use Velocity cipher
|
||||
}
|
||||
this.channel.pipeline().fireUserEventTriggered(io.papermc.paper.network.ConnectionEvent.COMPRESSION_THRESHOLD_SET); // Paper - Add Channel initialization listeners
|
||||
} else {
|
||||
diff --git a/net/minecraft/server/network/ServerConnectionListener.java b/net/minecraft/server/network/ServerConnectionListener.java
|
||||
index 7de11ba404f0b60e7f7b7c16954811a343688219..bd07e6a5aa1883786d789ea71711a0c0c0a95c26 100644
|
||||
--- a/net/minecraft/server/network/ServerConnectionListener.java
|
||||
+++ b/net/minecraft/server/network/ServerConnectionListener.java
|
||||
@@ -108,6 +108,10 @@ public class ServerConnectionListener {
|
||||
LOGGER.warn("Using HAProxy, please ensure the server port is adequately firewalled.");
|
||||
}
|
||||
// Paper end - Warn people with console access that HAProxy is in use.
|
||||
+ // Paper start - Use Velocity cipher
|
||||
+ ServerConnectionListener.LOGGER.info("Paper: Using " + com.velocitypowered.natives.util.Natives.compress.getLoadedVariant() + " compression from Velocity.");
|
||||
+ ServerConnectionListener.LOGGER.info("Paper: Using " + com.velocitypowered.natives.util.Natives.cipher.getLoadedVariant() + " cipher from Velocity.");
|
||||
+ // Paper end - Use Velocity cipher
|
||||
|
||||
this.channels
|
||||
.add(
|
||||
diff --git a/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
index bb28453d230921d662ed69c8dd48021f428ef060..6689aeacf50d1498e8d23cce696fb4fecbd1cf39 100644
|
||||
--- a/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
+++ b/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
@@ -276,11 +276,9 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
|
||||
}
|
||||
|
||||
SecretKey secretKey = packet.getSecretKey(_private);
|
||||
- Cipher cipher = Crypt.getCipher(2, secretKey);
|
||||
- Cipher cipher1 = Crypt.getCipher(1, secretKey);
|
||||
string = new BigInteger(Crypt.digestData("", this.server.getKeyPair().getPublic(), secretKey)).toString(16);
|
||||
this.state = ServerLoginPacketListenerImpl.State.AUTHENTICATING;
|
||||
- this.connection.setEncryptionKey(cipher, cipher1);
|
||||
+ this.connection.setEncryptionKey(secretKey); // Paper - Use Velocity cipher
|
||||
} catch (CryptException var7) {
|
||||
throw new IllegalStateException("Protocol error", var7);
|
||||
}
|
|
@ -13,44 +13,44 @@ If that serting is not enabled, collisions will be ignored for players, since
|
|||
movement will load only the chunk the player enters anyways and avoids loading
|
||||
massive amounts of surrounding chunks due to large AABB lookups.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -0,0 +0,0 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
|
||||
index 334859c5ff7023c730513301cc11c9837b2c7823..45f69a914d5a0565196c4105d61541047301470f 100644
|
||||
--- a/net/minecraft/world/entity/Entity.java
|
||||
+++ b/net/minecraft/world/entity/Entity.java
|
||||
@@ -218,6 +218,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
// Paper end - Share random for entities to make them more random
|
||||
public org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason spawnReason; // Paper - Entity#getEntitySpawnReason
|
||||
|
||||
+ public boolean collisionLoadChunks = false; // Paper
|
||||
private CraftEntity bukkitEntity;
|
||||
private org.bukkit.craftbukkit.entity.CraftEntity bukkitEntity;
|
||||
|
||||
public CraftEntity getBukkitEntity() {
|
||||
diff --git a/src/main/java/net/minecraft/world/level/BlockCollisions.java b/src/main/java/net/minecraft/world/level/BlockCollisions.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/BlockCollisions.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/BlockCollisions.java
|
||||
@@ -0,0 +0,0 @@ public class BlockCollisions<T> extends AbstractIterator<T> {
|
||||
public org.bukkit.craftbukkit.entity.CraftEntity getBukkitEntity() {
|
||||
diff --git a/net/minecraft/world/level/BlockCollisions.java b/net/minecraft/world/level/BlockCollisions.java
|
||||
index fd2c338db43aad070cc32c24891b40599c544ac9..2861ea4b699d403b1245f8be5a62503d366ded65 100644
|
||||
--- a/net/minecraft/world/level/BlockCollisions.java
|
||||
+++ b/net/minecraft/world/level/BlockCollisions.java
|
||||
@@ -80,16 +80,37 @@ public class BlockCollisions<T> extends AbstractIterator<T> {
|
||||
@Override
|
||||
protected T computeNext() {
|
||||
while (this.cursor.advance()) {
|
||||
- int i = this.cursor.nextX();
|
||||
- int j = this.cursor.nextY();
|
||||
- int k = this.cursor.nextZ();
|
||||
- int i1 = this.cursor.nextY();
|
||||
- int i2 = this.cursor.nextZ();
|
||||
+ int i = this.cursor.nextX(); final int x = i; // Paper - OBFHELPER
|
||||
+ int j = this.cursor.nextY(); final int y = j; // Paper - OBFHELPER
|
||||
+ int k = this.cursor.nextZ(); final int z = k; // Paper - OBFHELPER
|
||||
int l = this.cursor.getNextType();
|
||||
if (l != 3) {
|
||||
- BlockGetter blockGetter = this.getChunk(i, k);
|
||||
- if (blockGetter != null) {
|
||||
- this.pos.set(i, j, k);
|
||||
- BlockState blockState = blockGetter.getBlockState(this.pos);
|
||||
- if ((!this.onlySuffocatingBlocks || blockState.isSuffocating(blockGetter, this.pos))
|
||||
+ int i1 = this.cursor.nextY(); final int y = i1; // Paper - OBFHELPER
|
||||
+ int i2 = this.cursor.nextZ(); final int z = i2; // Paper - OBFHELPER
|
||||
int nextType = this.cursor.getNextType();
|
||||
if (nextType != 3) {
|
||||
- BlockGetter chunk = this.getChunk(i, i2);
|
||||
- if (chunk != null) {
|
||||
- this.pos.set(i, i1, i2);
|
||||
- BlockState blockState = chunk.getBlockState(this.pos);
|
||||
- if ((!this.onlySuffocatingBlocks || blockState.isSuffocating(chunk, this.pos))
|
||||
+ // Paper start - ensure we don't load chunks
|
||||
+ // BlockGetter blockGetter = this.getChunk(i, k);
|
||||
+ if (true) {
|
||||
+ final @Nullable Entity source = this.context instanceof net.minecraft.world.phys.shapes.EntityCollisionContext entityContext ? entityContext.getEntity() : null;
|
||||
+ boolean far = source != null && io.papermc.paper.util.MCUtil.distanceSq(source.getX(), y, source.getZ(), x, y, z) > 14;
|
||||
+ @Nullable final Entity source = this.context instanceof net.minecraft.world.phys.shapes.EntityCollisionContext entityContext ? entityContext.getEntity() : null;
|
||||
+ final boolean far = source != null && io.papermc.paper.util.MCUtil.distanceSq(source.getX(), y, source.getZ(), x, y, z) > 14;
|
||||
+ this.pos.set(x, y, z);
|
||||
+ BlockState blockState;
|
||||
+ if (this.collisionGetter instanceof net.minecraft.server.level.WorldGenRegion) {
|
||||
|
@ -72,25 +72,24 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ }
|
||||
+ if (true // onlySuffocatingBlocks is only true on the client, so we don't care about it here
|
||||
+ // Paper end - ensure we don't load chunks
|
||||
&& (l != 1 || blockState.hasLargeCollisionShape())
|
||||
&& (l != 2 || blockState.is(Blocks.MOVING_PISTON))) {
|
||||
VoxelShape voxelShape = this.context.getCollisionShape(blockState, this.collisionGetter, this.pos);
|
||||
diff --git a/src/main/java/net/minecraft/world/level/CollisionGetter.java b/src/main/java/net/minecraft/world/level/CollisionGetter.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/CollisionGetter.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/CollisionGetter.java
|
||||
@@ -0,0 +0,0 @@ public interface CollisionGetter extends BlockGetter {
|
||||
&& (nextType != 1 || blockState.hasLargeCollisionShape())
|
||||
&& (nextType != 2 || blockState.is(Blocks.MOVING_PISTON))) {
|
||||
VoxelShape collisionShape = this.context.getCollisionShape(blockState, this.collisionGetter, this.pos);
|
||||
diff --git a/net/minecraft/world/level/CollisionGetter.java b/net/minecraft/world/level/CollisionGetter.java
|
||||
index cb54c3aadd8f3c719d3f7ef1fda4aa517919b7c3..844f76a38884e823a558fe59c421ffd4711f80b4 100644
|
||||
--- a/net/minecraft/world/level/CollisionGetter.java
|
||||
+++ b/net/minecraft/world/level/CollisionGetter.java
|
||||
@@ -50,11 +50,13 @@ public interface CollisionGetter extends BlockGetter {
|
||||
}
|
||||
|
||||
default boolean noCollision(@Nullable Entity entity, AABB box, boolean checkFluid) {
|
||||
- for (VoxelShape voxelShape : checkFluid ? this.getBlockAndLiquidCollisions(entity, box) : this.getBlockCollisions(entity, box)) {
|
||||
default boolean noCollision(@Nullable Entity entity, AABB collisionBox, boolean checkLiquid) {
|
||||
+ try { if (entity != null) entity.collisionLoadChunks = true; // Paper
|
||||
+ for (VoxelShape voxelShape : checkFluid ? this.getBlockAndLiquidCollisions(entity, box) : this.getBlockCollisions(entity, box)) {
|
||||
for (VoxelShape voxelShape : checkLiquid ? this.getBlockAndLiquidCollisions(entity, collisionBox) : this.getBlockCollisions(entity, collisionBox)) {
|
||||
if (!voxelShape.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+ } finally { if (entity != null) entity.collisionLoadChunks = false; } // Paper
|
||||
|
||||
if (!this.getEntityCollisions(entity, box).isEmpty()) {
|
||||
if (!this.getEntityCollisions(entity, collisionBox).isEmpty()) {
|
||||
return false;
|
|
@ -0,0 +1,168 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Mon, 6 Apr 2020 17:53:29 -0700
|
||||
Subject: [PATCH] Optimize GoalSelector Goal.Flag Set operations
|
||||
|
||||
Optimise the stream.anyMatch statement to move to a bitset
|
||||
where we can replace the call with a single bitwise operation.
|
||||
|
||||
diff --git a/net/minecraft/world/entity/ai/goal/Goal.java b/net/minecraft/world/entity/ai/goal/Goal.java
|
||||
index d4f8387254a65b25fc808932a069298d0f8da091..5f5bf0e710ecff09a571091e5a923332be70cb74 100644
|
||||
--- a/net/minecraft/world/entity/ai/goal/Goal.java
|
||||
+++ b/net/minecraft/world/entity/ai/goal/Goal.java
|
||||
@@ -7,7 +7,15 @@ import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.level.Level;
|
||||
|
||||
public abstract class Goal {
|
||||
- private final EnumSet<Goal.Flag> flags = EnumSet.noneOf(Goal.Flag.class);
|
||||
+ private final ca.spottedleaf.moonrise.common.set.OptimizedSmallEnumSet<net.minecraft.world.entity.ai.goal.Goal.Flag> goalTypes = new ca.spottedleaf.moonrise.common.set.OptimizedSmallEnumSet<>(Goal.Flag.class); // Paper - remove streams from GoalSelector
|
||||
+
|
||||
+ // Paper start - remove streams from GoalSelector; make sure types are not empty
|
||||
+ protected Goal() {
|
||||
+ if (this.goalTypes.size() == 0) {
|
||||
+ this.goalTypes.addUnchecked(Flag.UNKNOWN_BEHAVIOR);
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - remove streams from GoalSelector
|
||||
|
||||
public abstract boolean canUse();
|
||||
|
||||
@@ -33,8 +41,13 @@ public abstract class Goal {
|
||||
}
|
||||
|
||||
public void setFlags(EnumSet<Goal.Flag> flagSet) {
|
||||
- this.flags.clear();
|
||||
- this.flags.addAll(flagSet);
|
||||
+ // Paper start - remove streams from GoalSelector
|
||||
+ this.goalTypes.clear();
|
||||
+ this.goalTypes.addAllUnchecked(flagSet);
|
||||
+ if (this.goalTypes.size() == 0) {
|
||||
+ this.goalTypes.addUnchecked(Flag.UNKNOWN_BEHAVIOR);
|
||||
+ }
|
||||
+ // Paper end - remove streams from GoalSelector
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -42,18 +55,20 @@ public abstract class Goal {
|
||||
return this.getClass().getSimpleName();
|
||||
}
|
||||
|
||||
- public EnumSet<Goal.Flag> getFlags() {
|
||||
- return this.flags;
|
||||
+ // Paper start - remove streams from GoalSelector
|
||||
+ public ca.spottedleaf.moonrise.common.set.OptimizedSmallEnumSet<Goal.Flag> getFlags() {
|
||||
+ return this.goalTypes;
|
||||
+ // Paper end - remove streams from GoalSelector
|
||||
}
|
||||
|
||||
|
||||
// Paper start - Mob Goal API
|
||||
public boolean hasFlag(final Goal.Flag flag) {
|
||||
- return this.flags.contains(flag);
|
||||
+ return this.goalTypes.hasElement(flag);
|
||||
}
|
||||
|
||||
public void addFlag(final Goal.Flag flag) {
|
||||
- this.flags.add(flag);
|
||||
+ this.goalTypes.addUnchecked(flag);
|
||||
}
|
||||
// Paper end - Mob Goal API
|
||||
|
||||
diff --git a/net/minecraft/world/entity/ai/goal/GoalSelector.java b/net/minecraft/world/entity/ai/goal/GoalSelector.java
|
||||
index eeba224bd575451ba6023df65ef9d9b97f7f1c71..a927c2790c8ab9ccaa7161b970e10b0b44817dd8 100644
|
||||
--- a/net/minecraft/world/entity/ai/goal/GoalSelector.java
|
||||
+++ b/net/minecraft/world/entity/ai/goal/GoalSelector.java
|
||||
@@ -24,7 +24,8 @@ public class GoalSelector {
|
||||
};
|
||||
private final Map<Goal.Flag, WrappedGoal> lockedFlags = new EnumMap<>(Goal.Flag.class);
|
||||
private final Set<WrappedGoal> availableGoals = new ObjectLinkedOpenHashSet<>();
|
||||
- private final EnumSet<Goal.Flag> disabledFlags = EnumSet.noneOf(Goal.Flag.class);
|
||||
+ private static final Goal.Flag[] GOAL_FLAG_VALUES = Goal.Flag.values(); // Paper - remove streams from GoalSelector
|
||||
+ private final ca.spottedleaf.moonrise.common.set.OptimizedSmallEnumSet<net.minecraft.world.entity.ai.goal.Goal.Flag> goalTypes = new ca.spottedleaf.moonrise.common.set.OptimizedSmallEnumSet<>(Goal.Flag.class); // Paper - remove streams from GoalSelector
|
||||
private int curRate; // Paper - EAR 2
|
||||
|
||||
public void addGoal(int priority, Goal goal) {
|
||||
@@ -62,18 +63,18 @@ public class GoalSelector {
|
||||
this.availableGoals.removeIf(wrappedGoal1 -> wrappedGoal1.getGoal() == goal);
|
||||
}
|
||||
|
||||
- private static boolean goalContainsAnyFlags(WrappedGoal goal, EnumSet<Goal.Flag> flag) {
|
||||
- for (Goal.Flag flag1 : goal.getFlags()) {
|
||||
- if (flag.contains(flag1)) {
|
||||
- return true;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- return false;
|
||||
+ // Paper start - Perf: optimize goal types
|
||||
+ private static boolean goalContainsAnyFlags(WrappedGoal goal, ca.spottedleaf.moonrise.common.set.OptimizedSmallEnumSet<Goal.Flag> flags) {
|
||||
+ return goal.getFlags().hasCommonElements(flags);
|
||||
}
|
||||
|
||||
private static boolean goalCanBeReplacedForAllFlags(WrappedGoal goal, Map<Goal.Flag, WrappedGoal> flag) {
|
||||
- for (Goal.Flag flag1 : goal.getFlags()) {
|
||||
+ long flagIterator = goal.getFlags().getBackingSet();
|
||||
+ int wrappedGoalSize = goal.getFlags().size();
|
||||
+ for (int i = 0; i < wrappedGoalSize; ++i) {
|
||||
+ final Goal.Flag flag1 = GOAL_FLAG_VALUES[Long.numberOfTrailingZeros(flagIterator)];
|
||||
+ flagIterator ^= ca.spottedleaf.concurrentutil.util.IntegerUtil.getTrailingBit(flagIterator);
|
||||
+ // Paper end - Perf: optimize goal types
|
||||
if (!flag.getOrDefault(flag1, NO_GOAL).canBeReplacedBy(goal)) {
|
||||
return false;
|
||||
}
|
||||
@@ -87,7 +88,7 @@ public class GoalSelector {
|
||||
profilerFiller.push("goalCleanup");
|
||||
|
||||
for (WrappedGoal wrappedGoal : this.availableGoals) {
|
||||
- if (wrappedGoal.isRunning() && (goalContainsAnyFlags(wrappedGoal, this.disabledFlags) || !wrappedGoal.canContinueToUse())) {
|
||||
+ if (wrappedGoal.isRunning() && (goalContainsAnyFlags(wrappedGoal, this.goalTypes) || !wrappedGoal.canContinueToUse())) { // Paper - Perf: optimize goal types by removing streams
|
||||
wrappedGoal.stop();
|
||||
}
|
||||
}
|
||||
@@ -97,11 +98,14 @@ public class GoalSelector {
|
||||
profilerFiller.push("goalUpdate");
|
||||
|
||||
for (WrappedGoal wrappedGoalx : this.availableGoals) {
|
||||
- if (!wrappedGoalx.isRunning()
|
||||
- && !goalContainsAnyFlags(wrappedGoalx, this.disabledFlags)
|
||||
- && goalCanBeReplacedForAllFlags(wrappedGoalx, this.lockedFlags)
|
||||
- && wrappedGoalx.canUse()) {
|
||||
- for (Goal.Flag flag : wrappedGoalx.getFlags()) {
|
||||
+ // Paper start
|
||||
+ if (!wrappedGoalx.isRunning() && !goalContainsAnyFlags(wrappedGoalx, this.goalTypes) && goalCanBeReplacedForAllFlags(wrappedGoalx, this.lockedFlags) && wrappedGoalx.canUse()) {
|
||||
+ long flagIterator = wrappedGoalx.getFlags().getBackingSet();
|
||||
+ int wrappedGoalSize = wrappedGoalx.getFlags().size();
|
||||
+ for (int i = 0; i < wrappedGoalSize; ++i) {
|
||||
+ final Goal.Flag flag = GOAL_FLAG_VALUES[Long.numberOfTrailingZeros(flagIterator)];
|
||||
+ flagIterator ^= ca.spottedleaf.concurrentutil.util.IntegerUtil.getTrailingBit(flagIterator);
|
||||
+ // Paper end
|
||||
WrappedGoal wrappedGoal1 = this.lockedFlags.getOrDefault(flag, NO_GOAL);
|
||||
wrappedGoal1.stop();
|
||||
this.lockedFlags.put(flag, wrappedGoalx);
|
||||
@@ -133,11 +137,11 @@ public class GoalSelector {
|
||||
}
|
||||
|
||||
public void disableControlFlag(Goal.Flag flag) {
|
||||
- this.disabledFlags.add(flag);
|
||||
+ this.goalTypes.addUnchecked(flag); // Paper - remove streams from GoalSelector
|
||||
}
|
||||
|
||||
public void enableControlFlag(Goal.Flag flag) {
|
||||
- this.disabledFlags.remove(flag);
|
||||
+ this.goalTypes.removeUnchecked(flag); // Paper - remove streams from GoalSelector
|
||||
}
|
||||
|
||||
public void setControlFlag(Goal.Flag flag, boolean enabled) {
|
||||
diff --git a/net/minecraft/world/entity/ai/goal/WrappedGoal.java b/net/minecraft/world/entity/ai/goal/WrappedGoal.java
|
||||
index 4bdbd323b642ed3422948fe24780be8b503602dc..2c2ab6a1df9d3d23773e44ce4041cc1c21b55163 100644
|
||||
--- a/net/minecraft/world/entity/ai/goal/WrappedGoal.java
|
||||
+++ b/net/minecraft/world/entity/ai/goal/WrappedGoal.java
|
||||
@@ -69,7 +69,7 @@ public class WrappedGoal extends Goal {
|
||||
}
|
||||
|
||||
@Override
|
||||
- public EnumSet<Goal.Flag> getFlags() {
|
||||
+ public ca.spottedleaf.moonrise.common.set.OptimizedSmallEnumSet<Goal.Flag> getFlags() { // Paper - remove streams from GoalSelector
|
||||
return this.goal.getFlags();
|
||||
}
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sun, 3 May 2020 22:35:09 -0400
|
||||
Subject: [PATCH] Optimize Voxel Shape Merging
|
||||
|
||||
This method shows up as super hot in profiler, and also a high "self" time.
|
||||
|
||||
Upon analyzing, it appears most usages of this method fall down to the final
|
||||
else statement of the nasty ternary.
|
||||
|
||||
Upon even further analyzation, it appears then the majority of those have a
|
||||
consistent list 1.... One with Infinity head and Tails.
|
||||
|
||||
First optimization is to detect these infinite states and immediately return that
|
||||
VoxelShapeMergerList so we can avoid testing the rest for most cases.
|
||||
|
||||
Break the method into 2 to help the JVM promote inlining of this fast path.
|
||||
|
||||
Then it was also noticed that VoxelShapeMergerList constructor is also a hotspot
|
||||
with a high self time...
|
||||
|
||||
Well, knowing that in most cases our list 1 is actualy the same value, it allows
|
||||
us to know that with an infinite list1, the result on the merger is essentially
|
||||
list2 as the final values.
|
||||
|
||||
This let us analyze the 2 potential states (Infinite with 2 sources or 4 sources)
|
||||
and compute a deterministic result for the MergerList values.
|
||||
|
||||
Additionally, this lets us avoid even allocating new objects for this too, further
|
||||
reducing memory usage.
|
||||
|
||||
diff --git a/net/minecraft/world/phys/shapes/IndirectMerger.java b/net/minecraft/world/phys/shapes/IndirectMerger.java
|
||||
index 60b56a5086b8aad0fad693f686b89138b3a4c80d..5b079ec43c259368d0eed4e8385880712abda4f7 100644
|
||||
--- a/net/minecraft/world/phys/shapes/IndirectMerger.java
|
||||
+++ b/net/minecraft/world/phys/shapes/IndirectMerger.java
|
||||
@@ -10,12 +10,32 @@ public class IndirectMerger implements IndexMerger {
|
||||
private final int[] firstIndices;
|
||||
private final int[] secondIndices;
|
||||
private final int resultLength;
|
||||
+ // Paper start
|
||||
+ private static final int[] INFINITE_B_1 = {1, 1};
|
||||
+ private static final int[] INFINITE_B_0 = {0, 0};
|
||||
+ private static final int[] INFINITE_C = {0, 1};
|
||||
+ // Paper end
|
||||
|
||||
public IndirectMerger(DoubleList lower, DoubleList upper, boolean excludeUpper, boolean excludeLower) {
|
||||
double d = Double.NaN;
|
||||
int size = lower.size();
|
||||
int size1 = upper.size();
|
||||
int i = size + size1;
|
||||
+ // Paper start - optimize common path of infinity doublelist
|
||||
+ double tail = lower.getDouble(size - 1);
|
||||
+ double head = lower.getDouble(0);
|
||||
+ if (head == Double.NEGATIVE_INFINITY && tail == Double.POSITIVE_INFINITY && !excludeUpper && !excludeLower && (size == 2 || size == 4)) {
|
||||
+ this.result = upper.toDoubleArray();
|
||||
+ this.resultLength = upper.size();
|
||||
+ if (size == 2) {
|
||||
+ this.firstIndices = INFINITE_B_0;
|
||||
+ } else {
|
||||
+ this.firstIndices = INFINITE_B_1;
|
||||
+ }
|
||||
+ this.secondIndices = INFINITE_C;
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end
|
||||
this.result = new double[i];
|
||||
this.firstIndices = new int[i];
|
||||
this.secondIndices = new int[i];
|
||||
diff --git a/net/minecraft/world/phys/shapes/Shapes.java b/net/minecraft/world/phys/shapes/Shapes.java
|
||||
index e1b4c4b53844b0755e0640a05e8782fd9a7700a2..e759221fb54aa510d2d8bbba47e1d794367aec6d 100644
|
||||
--- a/net/minecraft/world/phys/shapes/Shapes.java
|
||||
+++ b/net/minecraft/world/phys/shapes/Shapes.java
|
||||
@@ -279,9 +279,22 @@ public final class Shapes {
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
- protected static IndexMerger createIndexMerger(int size, DoubleList list1, DoubleList list2, boolean excludeUpper, boolean excludeLower) {
|
||||
+ private static IndexMerger createIndexMerger(int size, DoubleList list1, DoubleList list2, boolean excludeUpper, boolean excludeLower) { // Paper - private
|
||||
+ // Paper start - fast track the most common scenario
|
||||
+ // doublelist is usually a DoubleArrayList with Infinite head/tails that falls to the final else clause
|
||||
+ // This is actually the most common path, so jump to it straight away
|
||||
+ if (list1.getDouble(0) == Double.NEGATIVE_INFINITY && list1.getDouble(list1.size() - 1) == Double.POSITIVE_INFINITY) {
|
||||
+ return new IndirectMerger(list1, list2, excludeUpper, excludeLower);
|
||||
+ }
|
||||
+ // Split out rest to hopefully inline the above
|
||||
+ return lessCommonMerge(size, list1, list2, excludeUpper, excludeLower);
|
||||
+ }
|
||||
+
|
||||
+ private static IndexMerger lessCommonMerge(int size, DoubleList list1, DoubleList list2, boolean excludeUpper, boolean excludeLower) {
|
||||
+ // Paper end - fast track the most common scenario
|
||||
int i = list1.size() - 1;
|
||||
int i1 = list2.size() - 1;
|
||||
+ // Paper note - Rewrite below as optimized order if instead of nasty ternary
|
||||
if (list1 instanceof CubePointRange && list2 instanceof CubePointRange) {
|
||||
long l = lcm(i, i1);
|
||||
if (size * l <= 256L) {
|
||||
@@ -289,14 +302,21 @@ public final class Shapes {
|
||||
}
|
||||
}
|
||||
|
||||
- if (list1.getDouble(i) < list2.getDouble(0) - 1.0E-7) {
|
||||
+ // Paper start - Identical happens more often than Disjoint
|
||||
+ if (i == i1 && Objects.equals(list1, list2)) {
|
||||
+ if (list1 instanceof IdenticalMerger) {
|
||||
+ return (IndexMerger) list1;
|
||||
+ } else if (list2 instanceof IdenticalMerger) {
|
||||
+ return (IndexMerger) list2;
|
||||
+ }
|
||||
+ return new IdenticalMerger(list1);
|
||||
+ } else if (list1.getDouble(i) < list2.getDouble(0) - 1.0E-7) {
|
||||
+ // Paper end - Identical happens more often than Disjoint
|
||||
return new NonOverlappingMerger(list1, list2, false);
|
||||
} else if (list2.getDouble(i1) < list1.getDouble(0) - 1.0E-7) {
|
||||
return new NonOverlappingMerger(list2, list1, true);
|
||||
} else {
|
||||
- return (IndexMerger)(i == i1 && Objects.equals(list1, list2)
|
||||
- ? new IdenticalMerger(list1)
|
||||
- : new IndirectMerger(list1, list2, excludeUpper, excludeLower));
|
||||
+ return new IndirectMerger(list1, list2, excludeUpper, excludeLower); // Paper - Identical happens more often than Disjoint
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,152 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jake Potrebic <jake.m.potrebic@gmail.com>
|
||||
Date: Sun, 22 Aug 2021 15:21:57 -0700
|
||||
Subject: [PATCH] Fix entity type tags suggestions in selectors
|
||||
|
||||
This would really be better as a client fix because just to fix it
|
||||
all EntityArguments have been told to ask the server for completions
|
||||
when if this was fixed on the client, that wouldn't be needed.
|
||||
|
||||
Mojira Issue: https://bugs.mojang.com/browse/MC-235045
|
||||
|
||||
diff --git a/net/minecraft/commands/CommandSourceStack.java b/net/minecraft/commands/CommandSourceStack.java
|
||||
index 704a63890a06d793f8ac3452838917e7c7335232..75262c8c9eaecb4a88a94f4076d67119c67a97da 100644
|
||||
--- a/net/minecraft/commands/CommandSourceStack.java
|
||||
+++ b/net/minecraft/commands/CommandSourceStack.java
|
||||
@@ -652,4 +652,20 @@ public class CommandSourceStack implements ExecutionCommandSource<CommandSourceS
|
||||
return this.source.getBukkitSender(this);
|
||||
}
|
||||
// CraftBukkit end
|
||||
+ // Paper start - tell clients to ask server for suggestions for EntityArguments
|
||||
+ @Override
|
||||
+ public Collection<String> getSelectedEntities() {
|
||||
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().commands.fixTargetSelectorTagCompletion && this.source instanceof ServerPlayer player) {
|
||||
+ final Entity cameraEntity = player.getCamera();
|
||||
+ final double pickDistance = player.entityInteractionRange();
|
||||
+ final Vec3 min = cameraEntity.getEyePosition(1.0F);
|
||||
+ final Vec3 viewVector = cameraEntity.getViewVector(1.0F);
|
||||
+ final Vec3 max = min.add(viewVector.x * pickDistance, viewVector.y * pickDistance, viewVector.z * pickDistance);
|
||||
+ final net.minecraft.world.phys.AABB aabb = cameraEntity.getBoundingBox().expandTowards(viewVector.scale(pickDistance)).inflate(1.0D, 1.0D, 1.0D);
|
||||
+ final net.minecraft.world.phys.EntityHitResult hitResult = net.minecraft.world.entity.projectile.ProjectileUtil.getEntityHitResult(cameraEntity, min, max, aabb, (e) -> !e.isSpectator() && e.isPickable(), pickDistance * pickDistance);
|
||||
+ return hitResult != null ? java.util.Collections.singletonList(hitResult.getEntity().getStringUUID()) : SharedSuggestionProvider.super.getSelectedEntities();
|
||||
+ }
|
||||
+ return SharedSuggestionProvider.super.getSelectedEntities();
|
||||
+ }
|
||||
+ // Paper end - tell clients to ask server for suggestions for EntityArguments
|
||||
}
|
||||
diff --git a/net/minecraft/commands/Commands.java b/net/minecraft/commands/Commands.java
|
||||
index fa8c5ba4e0efd0c36613aaa8eaafba0cb70ceb87..19ccf3abf14c67f72a1ca065e4a304f50e645ef4 100644
|
||||
--- a/net/minecraft/commands/Commands.java
|
||||
+++ b/net/minecraft/commands/Commands.java
|
||||
@@ -509,6 +509,7 @@ public class Commands {
|
||||
Map<CommandNode<CommandSourceStack>, CommandNode<SharedSuggestionProvider>> commandNodeToSuggestionNode
|
||||
) {
|
||||
commandNodeToSuggestionNode.keySet().removeIf((node) -> !org.spigotmc.SpigotConfig.sendNamespaced && node.getName().contains(":")); // Paper - Remove namedspaced from result nodes to prevent redirect trimming ~ see comment below
|
||||
+ boolean registeredAskServerSuggestionsForTree = false; // Paper - tell clients to ask server for suggestions for EntityArguments
|
||||
for (CommandNode<CommandSourceStack> commandNode : children) { // Paper - Perf: Async command map building; pass copy of children
|
||||
// Paper start - Brigadier API
|
||||
if (commandNode.clientNode != null) {
|
||||
@@ -572,6 +573,12 @@ public class Commands {
|
||||
RequiredArgumentBuilder<SharedSuggestionProvider, ?> requiredArgumentBuilder = (RequiredArgumentBuilder<SharedSuggestionProvider, ?>)argumentBuilder;
|
||||
if (requiredArgumentBuilder.getSuggestionsProvider() != null) {
|
||||
requiredArgumentBuilder.suggests(SuggestionProviders.safelySwap(requiredArgumentBuilder.getSuggestionsProvider()));
|
||||
+ // Paper start - tell clients to ask server for suggestions for EntityArguments
|
||||
+ registeredAskServerSuggestionsForTree = requiredArgumentBuilder.getSuggestionsProvider() == net.minecraft.commands.synchronization.SuggestionProviders.ASK_SERVER;
|
||||
+ } else if (io.papermc.paper.configuration.GlobalConfiguration.get().commands.fixTargetSelectorTagCompletion && !registeredAskServerSuggestionsForTree && requiredArgumentBuilder.getType() instanceof net.minecraft.commands.arguments.EntityArgument) {
|
||||
+ requiredArgumentBuilder.suggests(requiredArgumentBuilder.getType()::listSuggestions);
|
||||
+ registeredAskServerSuggestionsForTree = true; // You can only
|
||||
+ // Paper end - tell clients to ask server for suggestions for EntityArguments
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/net/minecraft/commands/arguments/EntityArgument.java b/net/minecraft/commands/arguments/EntityArgument.java
|
||||
index 0a01df6ebd14afe79bc76364cb1df5e0c5c08074..7a06ad9940d25e163178370bfa9ccc3bbd3d1189 100644
|
||||
--- a/net/minecraft/commands/arguments/EntityArgument.java
|
||||
+++ b/net/minecraft/commands/arguments/EntityArgument.java
|
||||
@@ -138,7 +138,7 @@ public class EntityArgument implements ArgumentType<EntitySelector> {
|
||||
final boolean permission = sharedSuggestionProvider instanceof CommandSourceStack stack
|
||||
? stack.bypassSelectorPermissions || stack.hasPermission(2, "minecraft.command.selector")
|
||||
: sharedSuggestionProvider.hasPermission(2);
|
||||
- EntitySelectorParser entitySelectorParser = new EntitySelectorParser(stringReader, permission);
|
||||
+ EntitySelectorParser entitySelectorParser = new EntitySelectorParser(stringReader, permission, true); // Paper - tell clients to ask server for suggestions for EntityArguments
|
||||
// Paper end - Fix EntityArgument permissions
|
||||
|
||||
try {
|
||||
@@ -149,7 +149,19 @@ public class EntityArgument implements ArgumentType<EntitySelector> {
|
||||
return entitySelectorParser.fillSuggestions(
|
||||
builder,
|
||||
offsetBuilder -> {
|
||||
- Collection<String> onlinePlayerNames = sharedSuggestionProvider.getOnlinePlayerNames();
|
||||
+ // Paper start - tell clients to ask server for suggestions for EntityArguments
|
||||
+ final Collection<String> onlinePlayerNames;
|
||||
+ if (sharedSuggestionProvider instanceof CommandSourceStack commandSourceStack && commandSourceStack.getEntity() instanceof ServerPlayer sourcePlayer) {
|
||||
+ onlinePlayerNames = new java.util.ArrayList<>();
|
||||
+ for (final ServerPlayer player : commandSourceStack.getServer().getPlayerList().getPlayers()) {
|
||||
+ if (sourcePlayer.getBukkitEntity().canSee(player.getBukkitEntity())) {
|
||||
+ onlinePlayerNames.add(player.getGameProfile().getName());
|
||||
+ }
|
||||
+ }
|
||||
+ } else {
|
||||
+ onlinePlayerNames = sharedSuggestionProvider.getOnlinePlayerNames();
|
||||
+ }
|
||||
+ // Paper end - tell clients to ask server for suggestions for EntityArguments
|
||||
Iterable<String> iterable = (Iterable<String>)(this.playersOnly
|
||||
? onlinePlayerNames
|
||||
: Iterables.concat(onlinePlayerNames, sharedSuggestionProvider.getSelectedEntities()));
|
||||
diff --git a/net/minecraft/commands/arguments/selector/EntitySelectorParser.java b/net/minecraft/commands/arguments/selector/EntitySelectorParser.java
|
||||
index a6f232747df631f6afe440606bea94c588f1a0dd..fb42630741674c6cbd20b7d45d78dea1dc73a78f 100644
|
||||
--- a/net/minecraft/commands/arguments/selector/EntitySelectorParser.java
|
||||
+++ b/net/minecraft/commands/arguments/selector/EntitySelectorParser.java
|
||||
@@ -115,8 +115,15 @@ public class EntitySelectorParser {
|
||||
private boolean hasScores;
|
||||
private boolean hasAdvancements;
|
||||
private boolean usesSelectors;
|
||||
+ public boolean parsingEntityArgumentSuggestions; // Paper - tell clients to ask server for suggestions for EntityArguments
|
||||
|
||||
public EntitySelectorParser(StringReader reader, boolean allowSelectors) {
|
||||
+ // Paper start - tell clients to ask server for suggestions for EntityArguments
|
||||
+ this(reader, allowSelectors, false);
|
||||
+ }
|
||||
+ public EntitySelectorParser(StringReader reader, boolean allowSelectors, boolean parsingEntityArgumentSuggestions) {
|
||||
+ this.parsingEntityArgumentSuggestions = parsingEntityArgumentSuggestions;
|
||||
+ // Paper end - tell clients to ask server for suggestions for EntityArguments
|
||||
this.reader = reader;
|
||||
this.allowSelectors = allowSelectors;
|
||||
}
|
||||
diff --git a/net/minecraft/commands/arguments/selector/options/EntitySelectorOptions.java b/net/minecraft/commands/arguments/selector/options/EntitySelectorOptions.java
|
||||
index f6b58139aace70436034f0a16370236d975cb4ae..ee9949c41d38817b21b6f4fd728059a46fddf135 100644
|
||||
--- a/net/minecraft/commands/arguments/selector/options/EntitySelectorOptions.java
|
||||
+++ b/net/minecraft/commands/arguments/selector/options/EntitySelectorOptions.java
|
||||
@@ -76,6 +76,19 @@ public class EntitySelectorOptions {
|
||||
public static final DynamicCommandExceptionType ERROR_ENTITY_TYPE_INVALID = new DynamicCommandExceptionType(
|
||||
type -> Component.translatableEscape("argument.entity.options.type.invalid", type)
|
||||
);
|
||||
+ // Paper start - tell clients to ask server for suggestions for EntityArguments
|
||||
+ public static final DynamicCommandExceptionType ERROR_ENTITY_TAG_INVALID = new DynamicCommandExceptionType((object) -> {
|
||||
+ return io.papermc.paper.adventure.PaperAdventure
|
||||
+ .asVanilla(net.kyori.adventure.text.Component
|
||||
+ .text("Invalid or unknown entity type tag '" + object + "'")
|
||||
+ .hoverEvent(net.kyori.adventure.text.event.HoverEvent
|
||||
+ .showText(net.kyori.adventure.text.Component
|
||||
+ .text("You can disable this error in 'paper.yml'")
|
||||
+ )
|
||||
+ )
|
||||
+ );
|
||||
+ });
|
||||
+ // Paper end - tell clients to ask server for suggestions for EntityArguments
|
||||
|
||||
private static void register(String id, EntitySelectorOptions.Modifier handler, Predicate<EntitySelectorParser> predicate, Component tooltip) {
|
||||
OPTIONS.put(id, new EntitySelectorOptions.Option(handler, predicate, tooltip));
|
||||
@@ -299,6 +312,12 @@ public class EntitySelectorOptions {
|
||||
|
||||
if (parser.isTag()) {
|
||||
TagKey<EntityType<?>> tagKey = TagKey.create(Registries.ENTITY_TYPE, ResourceLocation.read(parser.getReader()));
|
||||
+ // Paper start - tell clients to ask server for suggestions for EntityArguments; throw error if invalid entity tag (only on suggestions to keep cmd success behavior)
|
||||
+ if (parser.parsingEntityArgumentSuggestions && io.papermc.paper.configuration.GlobalConfiguration.get().commands.fixTargetSelectorTagCompletion && net.minecraft.core.registries.BuiltInRegistries.ENTITY_TYPE.get(tagKey).isEmpty()) {
|
||||
+ parser.getReader().setCursor(cursor);
|
||||
+ throw ERROR_ENTITY_TAG_INVALID.createWithContext(parser.getReader(), tagKey);
|
||||
+ }
|
||||
+ // Paper end - tell clients to ask server for suggestions for EntityArguments
|
||||
parser.addPredicate(entity -> entity.getType().is(tagKey) != shouldInvertValue);
|
||||
} else {
|
||||
ResourceLocation resourceLocation = ResourceLocation.read(parser.getReader());
|
|
@ -8,17 +8,17 @@ creating too large of a packet to sed.
|
|||
|
||||
Co-authored-by: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
|
||||
+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
|
||||
@@ -0,0 +0,0 @@ public class ClientboundLevelChunkPacketData {
|
||||
diff --git a/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java b/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
|
||||
index 3aea76690bc3e35758d3bf274777130af17d8a0f..9e321ef1c3d5803519b243685f4ee598dc0cf640 100644
|
||||
--- a/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
|
||||
+++ b/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
|
||||
@@ -27,6 +27,14 @@ public class ClientboundLevelChunkPacketData {
|
||||
private final CompoundTag heightmaps;
|
||||
private final byte[] buffer;
|
||||
private final List<ClientboundLevelChunkPacketData.BlockEntityInfo> blockEntitiesData;
|
||||
+ // Paper start - Handle oversized block entities in chunks
|
||||
+ private final java.util.List<net.minecraft.network.protocol.Packet<?>> extraPackets = new java.util.ArrayList<>();
|
||||
+ private static final int TE_LIMIT = Integer.getInteger("Paper.excessiveTELimit", 750);
|
||||
+ private static final int BLOCK_ENTITY_LIMIT = Integer.getInteger("Paper.excessiveTELimit", 750);
|
||||
+
|
||||
+ public List<net.minecraft.network.protocol.Packet<?>> getExtraPackets() {
|
||||
+ return this.extraPackets;
|
||||
|
@ -26,31 +26,31 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ // Paper end - Handle oversized block entities in chunks
|
||||
|
||||
// Paper start - Anti-Xray - Add chunk packet info
|
||||
@Deprecated @io.papermc.paper.annotation.DoNotUse public ClientboundLevelChunkPacketData(LevelChunk chunk) { this(chunk, null); }
|
||||
@@ -0,0 +0,0 @@ public class ClientboundLevelChunkPacketData {
|
||||
extractChunkData(new FriendlyByteBuf(this.getWriteBuffer()), chunk, chunkPacketInfo);
|
||||
// Paper end
|
||||
@Deprecated @io.papermc.paper.annotation.DoNotUse
|
||||
@@ -50,8 +58,18 @@ public class ClientboundLevelChunkPacketData {
|
||||
}
|
||||
extractChunkData(new FriendlyByteBuf(this.getWriteBuffer()), levelChunk, chunkPacketInfo);
|
||||
this.blockEntitiesData = Lists.newArrayList();
|
||||
+ int totalTileEntities = 0; // Paper - Handle oversized block entities in chunks
|
||||
|
||||
for (Entry<BlockPos, BlockEntity> entry2 : chunk.getBlockEntities().entrySet()) {
|
||||
for (Entry<BlockPos, BlockEntity> entryx : levelChunk.getBlockEntities().entrySet()) {
|
||||
+ // Paper start - Handle oversized block entities in chunks
|
||||
+ if (++totalTileEntities > TE_LIMIT) {
|
||||
+ var packet = entry2.getValue().getUpdatePacket();
|
||||
+ if (++totalTileEntities > BLOCK_ENTITY_LIMIT) {
|
||||
+ net.minecraft.network.protocol.Packet<ClientGamePacketListener> packet = entryx.getValue().getUpdatePacket();
|
||||
+ if (packet != null) {
|
||||
+ this.extraPackets.add(packet);
|
||||
+ continue;
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - Handle oversized block entities in chunks
|
||||
this.blockEntitiesData.add(ClientboundLevelChunkPacketData.BlockEntityInfo.create(entry2.getValue()));
|
||||
this.blockEntitiesData.add(ClientboundLevelChunkPacketData.BlockEntityInfo.create(entryx.getValue()));
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java
|
||||
+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java
|
||||
@@ -0,0 +0,0 @@ public class ClientboundLevelChunkWithLightPacket implements Packet<ClientGamePa
|
||||
diff --git a/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java b/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java
|
||||
index 5699bc15eba92e22433a20cb8326b59f2ebd3036..8578d1f78ddd1bb75f3230f04bfaa35af9f5f822 100644
|
||||
--- a/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java
|
||||
+++ b/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java
|
||||
@@ -84,4 +84,11 @@ public class ClientboundLevelChunkWithLightPacket implements Packet<ClientGamePa
|
||||
public ClientboundLightUpdatePacketData getLightData() {
|
||||
return this.lightData;
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: lukas81298 <lukas81298@gommehd.net>
|
||||
Date: Fri, 22 Jan 2021 21:50:18 +0100
|
||||
Subject: [PATCH] optimize dirt and snow spreading
|
||||
|
||||
|
||||
diff --git a/net/minecraft/world/level/block/SpreadingSnowyDirtBlock.java b/net/minecraft/world/level/block/SpreadingSnowyDirtBlock.java
|
||||
index 11937aa74efe08bdbd66a619c7a825f91d971afd..722f2b9a24679e0fc67aae2cd27051f96f962efe 100644
|
||||
--- a/net/minecraft/world/level/block/SpreadingSnowyDirtBlock.java
|
||||
+++ b/net/minecraft/world/level/block/SpreadingSnowyDirtBlock.java
|
||||
@@ -17,8 +17,13 @@ public abstract class SpreadingSnowyDirtBlock extends SnowyDirtBlock {
|
||||
}
|
||||
|
||||
private static boolean canBeGrass(BlockState state, LevelReader levelReader, BlockPos pos) {
|
||||
+ // Paper start - Perf: optimize dirt and snow spreading
|
||||
+ return canBeGrass(levelReader.getChunk(pos), state, levelReader, pos);
|
||||
+ }
|
||||
+ private static boolean canBeGrass(net.minecraft.world.level.chunk.ChunkAccess chunk, BlockState state, LevelReader levelReader, BlockPos pos) {
|
||||
+ // Paper end - Perf: optimize dirt and snow spreading
|
||||
BlockPos blockPos = pos.above();
|
||||
- BlockState blockState = levelReader.getBlockState(blockPos);
|
||||
+ BlockState blockState = chunk.getBlockState(blockPos); // Paper - Perf: optimize dirt and snow spreading
|
||||
if (blockState.is(Blocks.SNOW) && blockState.getValue(SnowLayerBlock.LAYERS) == 1) {
|
||||
return true;
|
||||
} else if (blockState.getFluidState().getAmount() == 8) {
|
||||
@@ -33,14 +38,27 @@ public abstract class SpreadingSnowyDirtBlock extends SnowyDirtBlock {
|
||||
protected abstract MapCodec<? extends SpreadingSnowyDirtBlock> codec();
|
||||
|
||||
private static boolean canPropagate(BlockState state, LevelReader level, BlockPos pos) {
|
||||
+ // Paper start - Perf: optimize dirt and snow spreading
|
||||
+ return canPropagate(level.getChunk(pos), state, level, pos);
|
||||
+ }
|
||||
+
|
||||
+ private static boolean canPropagate(net.minecraft.world.level.chunk.ChunkAccess chunk, BlockState state, LevelReader level, BlockPos pos) {
|
||||
+ // Paper end - Perf: optimize dirt and snow spreading
|
||||
BlockPos blockPos = pos.above();
|
||||
- return canBeGrass(state, level, pos) && !level.getFluidState(blockPos).is(FluidTags.WATER);
|
||||
+ return canBeGrass(chunk, state, level, pos) && !chunk.getFluidState(blockPos).is(FluidTags.WATER); // Paper - Perf: optimize dirt and snow spreading
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
|
||||
if (this instanceof GrassBlock && level.paperConfig().tickRates.grassSpread != 1 && (level.paperConfig().tickRates.grassSpread < 1 || (net.minecraft.server.MinecraftServer.currentTick + pos.hashCode()) % level.paperConfig().tickRates.grassSpread != 0)) { return; } // Paper - Configurable random tick rates for blocks
|
||||
- if (!canBeGrass(state, level, pos)) {
|
||||
+ // Paper start - Perf: optimize dirt and snow spreading
|
||||
+ final net.minecraft.world.level.chunk.ChunkAccess cachedBlockChunk = level.getChunkIfLoaded(pos);
|
||||
+ if (cachedBlockChunk == null) { // Is this needed?
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ if (!canBeGrass(cachedBlockChunk, state, level, pos)) {
|
||||
+ // Paper end - Perf: optimize dirt and snow spreading
|
||||
// CraftBukkit start
|
||||
if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockFadeEvent(level, pos, Blocks.DIRT.defaultBlockState()).isCancelled()) {
|
||||
return;
|
||||
@@ -53,8 +71,20 @@ public abstract class SpreadingSnowyDirtBlock extends SnowyDirtBlock {
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
BlockPos blockPos = pos.offset(random.nextInt(3) - 1, random.nextInt(5) - 3, random.nextInt(3) - 1);
|
||||
- if (level.getBlockState(blockPos).is(Blocks.DIRT) && canPropagate(blockState, level, blockPos)) {
|
||||
- org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(level, pos, blockPos, blockState.setValue(SNOWY, Boolean.valueOf(isSnowySetting(level.getBlockState(blockPos.above()))))); // CraftBukkit
|
||||
+ // Paper start - Perf: optimize dirt and snow spreading
|
||||
+ if (pos.getX() == blockPos.getX() && pos.getY() == blockPos.getY() && pos.getZ() == blockPos.getZ()) {
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ final net.minecraft.world.level.chunk.ChunkAccess access;
|
||||
+ if (cachedBlockChunk.locX == blockPos.getX() >> 4 && cachedBlockChunk.locZ == blockPos.getZ() >> 4) {
|
||||
+ access = cachedBlockChunk;
|
||||
+ } else {
|
||||
+ access = level.getChunkAt(blockPos);
|
||||
+ }
|
||||
+ if (access.getBlockState(blockPos).is(Blocks.DIRT) && SpreadingSnowyDirtBlock.canPropagate(access, blockState, level, blockPos)) {
|
||||
+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(level, pos, blockPos, (BlockState) blockState.setValue(SpreadingSnowyDirtBlock.SNOWY, isSnowySetting(access.getBlockState(blockPos.above())))); // CraftBukkit
|
||||
+ // Paper end - Perf: optimize dirt and snow spreading
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Sat, 25 Jan 2020 17:04:35 -0800
|
||||
Subject: [PATCH] Optimise getChunkAt calls for loaded chunks
|
||||
|
||||
bypass the need to get a player chunk, then get the either,
|
||||
then unwrap it...
|
||||
|
||||
diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java
|
||||
index c3553385074108d686425a7637b8975076d906b9..2f49dbc919f7f5eea9abce6106723c72f5ae45fb 100644
|
||||
--- a/net/minecraft/server/level/ServerChunkCache.java
|
||||
+++ b/net/minecraft/server/level/ServerChunkCache.java
|
||||
@@ -218,6 +218,12 @@ public class ServerChunkCache extends ChunkSource {
|
||||
if (Thread.currentThread() != this.mainThread) {
|
||||
return CompletableFuture.<ChunkAccess>supplyAsync(() -> this.getChunk(x, z, chunkStatus, requireChunk), this.mainThreadProcessor).join();
|
||||
} else {
|
||||
+ // Paper start - Perf: Optimise getChunkAt calls for loaded chunks
|
||||
+ LevelChunk ifLoaded = this.getChunkAtIfCachedImmediately(x, z);
|
||||
+ if (ifLoaded != null) {
|
||||
+ return ifLoaded;
|
||||
+ }
|
||||
+ // Paper end - Perf: Optimise getChunkAt calls for loaded chunks
|
||||
ProfilerFiller profilerFiller = Profiler.get();
|
||||
profilerFiller.incrementCounter("getChunk");
|
||||
long packedChunkPos = ChunkPos.asLong(x, z);
|
||||
@@ -252,30 +258,7 @@ public class ServerChunkCache extends ChunkSource {
|
||||
if (Thread.currentThread() != this.mainThread) {
|
||||
return null;
|
||||
} else {
|
||||
- Profiler.get().incrementCounter("getChunkNow");
|
||||
- long packedChunkPos = ChunkPos.asLong(chunkX, chunkZ);
|
||||
-
|
||||
- for (int i = 0; i < 4; i++) {
|
||||
- if (packedChunkPos == this.lastChunkPos[i] && this.lastChunkStatus[i] == ChunkStatus.FULL) {
|
||||
- ChunkAccess chunkAccess = this.lastChunk[i];
|
||||
- return chunkAccess instanceof LevelChunk ? (LevelChunk)chunkAccess : null;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- ChunkHolder visibleChunkIfPresent = this.getVisibleChunkIfPresent(packedChunkPos);
|
||||
- if (visibleChunkIfPresent == null) {
|
||||
- return null;
|
||||
- } else {
|
||||
- ChunkAccess chunkAccess = visibleChunkIfPresent.getChunkIfPresent(ChunkStatus.FULL);
|
||||
- if (chunkAccess != null) {
|
||||
- this.storeInCache(packedChunkPos, chunkAccess, ChunkStatus.FULL);
|
||||
- if (chunkAccess instanceof LevelChunk) {
|
||||
- return (LevelChunk)chunkAccess;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- return null;
|
||||
- }
|
||||
+ return this.getChunkAtIfCachedImmediately(chunkX, chunkZ); // Paper - Perf: Optimise getChunkAt calls for loaded chunks
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,212 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Thu, 4 Jun 2020 02:24:49 -0400
|
||||
Subject: [PATCH] Optimize Bit Operations by inlining
|
||||
|
||||
Inline bit operations and reduce instruction count to make these hot
|
||||
operations faster
|
||||
|
||||
diff --git a/net/minecraft/core/BlockPos.java b/net/minecraft/core/BlockPos.java
|
||||
index 98f0b1cf19d7a035849a9a2fa25e2be3a4c5a980..a81694a22e94cca6f7110f7d5b205d1303f4e071 100644
|
||||
--- a/net/minecraft/core/BlockPos.java
|
||||
+++ b/net/minecraft/core/BlockPos.java
|
||||
@@ -51,15 +51,17 @@ public class BlockPos extends Vec3i {
|
||||
};
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
public static final BlockPos ZERO = new BlockPos(0, 0, 0);
|
||||
- public static final int PACKED_HORIZONTAL_LENGTH = 1 + Mth.log2(Mth.smallestEncompassingPowerOfTwo(30000000));
|
||||
- public static final int PACKED_Y_LENGTH = 64 - 2 * PACKED_HORIZONTAL_LENGTH;
|
||||
- private static final long PACKED_X_MASK = (1L << PACKED_HORIZONTAL_LENGTH) - 1L;
|
||||
- private static final long PACKED_Y_MASK = (1L << PACKED_Y_LENGTH) - 1L;
|
||||
- private static final long PACKED_Z_MASK = (1L << PACKED_HORIZONTAL_LENGTH) - 1L;
|
||||
+ // Paper start - Optimize Bit Operations by inlining
|
||||
+ public static final int PACKED_HORIZONTAL_LENGTH = 26;
|
||||
+ public static final int PACKED_Y_LENGTH = 12;
|
||||
+ private static final long PACKED_X_MASK = 67108863;
|
||||
+ private static final long PACKED_Y_MASK = 4095;
|
||||
+ private static final long PACKED_Z_MASK = 67108863;
|
||||
private static final int Y_OFFSET = 0;
|
||||
- private static final int Z_OFFSET = PACKED_Y_LENGTH;
|
||||
- private static final int X_OFFSET = PACKED_Y_LENGTH + PACKED_HORIZONTAL_LENGTH;
|
||||
- public static final int MAX_HORIZONTAL_COORDINATE = (1 << PACKED_HORIZONTAL_LENGTH) / 2 - 1;
|
||||
+ private static final int Z_OFFSET = 12;
|
||||
+ private static final int X_OFFSET = 38;
|
||||
+ public static final int MAX_HORIZONTAL_COORDINATE = 33554431;
|
||||
+ // Paper end - Optimize Bit Operations by inlining
|
||||
|
||||
public BlockPos(int x, int y, int z) {
|
||||
super(x, y, z);
|
||||
@@ -69,28 +71,29 @@ public class BlockPos extends Vec3i {
|
||||
this(vector.getX(), vector.getY(), vector.getZ());
|
||||
}
|
||||
|
||||
+ public static long getAdjacent(int baseX, int baseY, int baseZ, Direction direction) { return asLong(baseX + direction.getStepX(), baseY + direction.getStepY(), baseZ + direction.getStepZ()); } // Paper
|
||||
public static long offset(long pos, Direction direction) {
|
||||
return offset(pos, direction.getStepX(), direction.getStepY(), direction.getStepZ());
|
||||
}
|
||||
|
||||
public static long offset(long pos, int dx, int dy, int dz) {
|
||||
- return asLong(getX(pos) + dx, getY(pos) + dy, getZ(pos) + dz);
|
||||
+ return asLong((int) (pos >> 38) + dx, (int) ((pos << 52) >> 52) + dy, (int) ((pos << 26) >> 38) + dz); // Paper - simplify/inline
|
||||
}
|
||||
|
||||
public static int getX(long packedPos) {
|
||||
- return (int)(packedPos << 64 - X_OFFSET - PACKED_HORIZONTAL_LENGTH >> 64 - PACKED_HORIZONTAL_LENGTH);
|
||||
+ return (int) (packedPos >> 38); // Paper - simplify/inline
|
||||
}
|
||||
|
||||
public static int getY(long packedPos) {
|
||||
- return (int)(packedPos << 64 - PACKED_Y_LENGTH >> 64 - PACKED_Y_LENGTH);
|
||||
+ return (int) ((packedPos << 52) >> 52); // Paper - simplify/inline
|
||||
}
|
||||
|
||||
public static int getZ(long packedPos) {
|
||||
- return (int)(packedPos << 64 - Z_OFFSET - PACKED_HORIZONTAL_LENGTH >> 64 - PACKED_HORIZONTAL_LENGTH);
|
||||
+ return (int) ((packedPos << 26) >> 38); // Paper - simplify/inline
|
||||
}
|
||||
|
||||
public static BlockPos of(long packedPos) {
|
||||
- return new BlockPos(getX(packedPos), getY(packedPos), getZ(packedPos));
|
||||
+ return new BlockPos((int) (packedPos >> 38), (int) ((packedPos << 52) >> 52), (int) ((packedPos << 26) >> 38)); // Paper - simplify/inline
|
||||
}
|
||||
|
||||
public static BlockPos containing(double x, double y, double z) {
|
||||
@@ -114,10 +117,7 @@ public class BlockPos extends Vec3i {
|
||||
}
|
||||
|
||||
public static long asLong(int x, int y, int z) {
|
||||
- long l = 0L;
|
||||
- l |= (x & PACKED_X_MASK) << X_OFFSET;
|
||||
- l |= (y & PACKED_Y_MASK) << 0;
|
||||
- return l | (z & PACKED_Z_MASK) << Z_OFFSET;
|
||||
+ return ((x & 67108863L) << 38) | ((y & 4095L)) | ((z & 67108863L) << 12); // Paper - inline constants and simplify
|
||||
}
|
||||
|
||||
public static long getFlatIndex(long packedPos) {
|
||||
diff --git a/net/minecraft/core/SectionPos.java b/net/minecraft/core/SectionPos.java
|
||||
index 1780d8e14cea62971da75e4dcc80d1805434037b..ce8c394ea1a7bc5bf5c568c82e6158b19df517d8 100644
|
||||
--- a/net/minecraft/core/SectionPos.java
|
||||
+++ b/net/minecraft/core/SectionPos.java
|
||||
@@ -38,7 +38,7 @@ public class SectionPos extends Vec3i {
|
||||
}
|
||||
|
||||
public static SectionPos of(BlockPos pos) {
|
||||
- return new SectionPos(blockToSectionCoord(pos.getX()), blockToSectionCoord(pos.getY()), blockToSectionCoord(pos.getZ()));
|
||||
+ return new SectionPos(pos.getX() >> 4, pos.getY() >> 4, pos.getZ() >> 4); // Paper
|
||||
}
|
||||
|
||||
public static SectionPos of(ChunkPos chunkPos, int y) {
|
||||
@@ -54,7 +54,7 @@ public class SectionPos extends Vec3i {
|
||||
}
|
||||
|
||||
public static SectionPos of(long packed) {
|
||||
- return new SectionPos(x(packed), y(packed), z(packed));
|
||||
+ return new SectionPos((int) (packed >> 42), (int) (packed << 44 >> 44), (int) (packed << 22 >> 42)); // Paper
|
||||
}
|
||||
|
||||
public static SectionPos bottomOf(ChunkAccess chunk) {
|
||||
@@ -65,8 +65,16 @@ public class SectionPos extends Vec3i {
|
||||
return offset(packed, direction.getStepX(), direction.getStepY(), direction.getStepZ());
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ public static long getAdjacentFromBlockPos(int x, int y, int z, Direction direction) {
|
||||
+ return (((long) ((x >> 4) + direction.getStepX()) & 4194303L) << 42) | (((long) ((y >> 4) + direction.getStepY()) & 1048575L)) | (((long) ((z >> 4) + direction.getStepZ()) & 4194303L) << 20);
|
||||
+ }
|
||||
+ public static long getAdjacentFromSectionPos(int x, int y, int z, Direction direction) {
|
||||
+ return (((long) (x + direction.getStepX()) & 4194303L) << 42) | (((long) ((y) + direction.getStepY()) & 1048575L)) | (((long) (z + direction.getStepZ()) & 4194303L) << 20);
|
||||
+ }
|
||||
+ // Paper end
|
||||
public static long offset(long packed, int dx, int dy, int dz) {
|
||||
- return asLong(x(packed) + dx, y(packed) + dy, z(packed) + dz);
|
||||
+ return (((long) ((int) (packed >> 42) + dx) & 4194303L) << 42) | (((long) ((int) (packed << 44 >> 44) + dy) & 1048575L)) | (((long) ((int) (packed << 22 >> 42) + dz) & 4194303L) << 20); // Simplify to reduce instruction count
|
||||
}
|
||||
|
||||
public static int posToSectionCoord(double pos) {
|
||||
@@ -86,10 +94,7 @@ public class SectionPos extends Vec3i {
|
||||
}
|
||||
|
||||
public static short sectionRelativePos(BlockPos pos) {
|
||||
- int relativeBlockPosX = sectionRelative(pos.getX());
|
||||
- int relativeBlockPosY = sectionRelative(pos.getY());
|
||||
- int relativeBlockPosZ = sectionRelative(pos.getZ());
|
||||
- return (short)(relativeBlockPosX << 8 | relativeBlockPosZ << 4 | relativeBlockPosY << 0);
|
||||
+ return (short) ((pos.getX() & 15) << 8 | (pos.getZ() & 15) << 4 | pos.getY() & 15); // Paper - simplify/inline
|
||||
}
|
||||
|
||||
public static int sectionRelativeX(short x) {
|
||||
@@ -152,16 +157,16 @@ public class SectionPos extends Vec3i {
|
||||
return this.getZ();
|
||||
}
|
||||
|
||||
- public int minBlockX() {
|
||||
- return sectionToBlockCoord(this.x());
|
||||
+ public final int minBlockX() { // Paper - final
|
||||
+ return this.getX() << 4; // Paper - inline
|
||||
}
|
||||
|
||||
- public int minBlockY() {
|
||||
- return sectionToBlockCoord(this.y());
|
||||
+ public final int minBlockY() { // Paper - final
|
||||
+ return this.getY() << 4; // Paper - inline
|
||||
}
|
||||
|
||||
- public int minBlockZ() {
|
||||
- return sectionToBlockCoord(this.z());
|
||||
+ public final int minBlockZ() { // Paper - final
|
||||
+ return this.getZ() << 4; // Paper - inline
|
||||
}
|
||||
|
||||
public int maxBlockX() {
|
||||
@@ -177,7 +182,7 @@ public class SectionPos extends Vec3i {
|
||||
}
|
||||
|
||||
public static long blockToSection(long levelPos) {
|
||||
- return asLong(blockToSectionCoord(BlockPos.getX(levelPos)), blockToSectionCoord(BlockPos.getY(levelPos)), blockToSectionCoord(BlockPos.getZ(levelPos)));
|
||||
+ return (((long) (int) (levelPos >> 42) & 4194303L) << 42) | (((long) (int) ((levelPos << 52) >> 56) & 1048575L)) | (((long) (int) ((levelPos << 26) >> 42) & 4194303L) << 20); // Simplify to reduce instruction count
|
||||
}
|
||||
|
||||
public static long getZeroNode(int x, int z) {
|
||||
@@ -205,15 +210,17 @@ public class SectionPos extends Vec3i {
|
||||
return asLong(blockToSectionCoord(blockPos.getX()), blockToSectionCoord(blockPos.getY()), blockToSectionCoord(blockPos.getZ()));
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ public static long blockPosAsSectionLong(int x, int y, int z) {
|
||||
+ return (((long) (x >> 4) & 4194303L) << 42) | (((long) (y >> 4) & 1048575L)) | (((long) (z >> 4) & 4194303L) << 20);
|
||||
+ }
|
||||
+ // Paper end
|
||||
public static long asLong(int x, int y, int z) {
|
||||
- long l = 0L;
|
||||
- l |= (x & 4194303L) << 42;
|
||||
- l |= (y & 1048575L) << 0;
|
||||
- return l | (z & 4194303L) << 20;
|
||||
+ return ((x & 4194303L) << 42) | ((y & 1048575L)) | ((z & 4194303L) << 20); // Paper - Simplify to reduce instruction count
|
||||
}
|
||||
|
||||
public long asLong() {
|
||||
- return asLong(this.x(), this.y(), this.z());
|
||||
+ return ((this.getX() & 4194303L) << 42) | ((this.getY() & 1048575L)) | ((this.getZ() & 4194303L) << 20); // Paper - Simplify to reduce instruction count
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -226,16 +233,13 @@ public class SectionPos extends Vec3i {
|
||||
}
|
||||
|
||||
public static Stream<SectionPos> cube(SectionPos center, int radius) {
|
||||
- int sectionX = center.x();
|
||||
- int sectionY = center.y();
|
||||
- int sectionZ = center.z();
|
||||
- return betweenClosedStream(sectionX - radius, sectionY - radius, sectionZ - radius, sectionX + radius, sectionY + radius, sectionZ + radius);
|
||||
+ return betweenClosedStream(center.getX() - radius, center.getY() - radius, center.getZ() - radius, center.getX() + radius, center.getY() + radius, center.getZ() + radius); // Paper - simplify/inline
|
||||
}
|
||||
|
||||
- public static Stream<SectionPos> aroundChunk(ChunkPos chunkPos, int x, int y, int z) {
|
||||
+ public static Stream<SectionPos> aroundChunk(ChunkPos chunkPos, int radius, int minY, int maxY) { // Paper - fix params
|
||||
int i = chunkPos.x;
|
||||
int i1 = chunkPos.z;
|
||||
- return betweenClosedStream(i - x, y, i1 - x, i + x, z, i1 + x);
|
||||
+ return betweenClosedStream(i - radius, minY, i1 - radius, i + radius, maxY, i1 + radius); // Paper - simplify/inline
|
||||
}
|
||||
|
||||
public static Stream<SectionPos> betweenClosedStream(final int x1, final int y1, final int z1, final int x2, final int y2, final int z2) {
|
|
@ -0,0 +1,223 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Josh Roy <10731363+JRoy@users.noreply.github.com>
|
||||
Date: Wed, 1 Jul 2020 18:01:49 -0400
|
||||
Subject: [PATCH] Remove streams from hot code
|
||||
|
||||
Co-authored-by: Bjarne Koll <git@lynxplay.dev>
|
||||
Co-authored-by: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
|
||||
diff --git a/net/minecraft/world/entity/ai/behavior/GateBehavior.java b/net/minecraft/world/entity/ai/behavior/GateBehavior.java
|
||||
index c215d97c24e6501e1a48a76fc08bf48ff4dfe462..bd31d1cac0d022a72bd536c41d1ef811886e7068 100644
|
||||
--- a/net/minecraft/world/entity/ai/behavior/GateBehavior.java
|
||||
+++ b/net/minecraft/world/entity/ai/behavior/GateBehavior.java
|
||||
@@ -57,7 +57,7 @@ public class GateBehavior<E extends LivingEntity> implements BehaviorControl<E>
|
||||
if (this.hasRequiredMemories(entity)) {
|
||||
this.status = Behavior.Status.RUNNING;
|
||||
this.orderPolicy.apply(this.behaviors);
|
||||
- this.runningPolicy.apply(this.behaviors.stream(), level, entity, gameTime);
|
||||
+ this.runningPolicy.apply(this.behaviors, level, entity, gameTime); // Paper - Perf: Remove streams from hot code
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
@@ -66,10 +66,13 @@ public class GateBehavior<E extends LivingEntity> implements BehaviorControl<E>
|
||||
|
||||
@Override
|
||||
public final void tickOrStop(ServerLevel level, E entity, long gameTime) {
|
||||
- this.behaviors
|
||||
- .stream()
|
||||
- .filter(behavior -> behavior.getStatus() == Behavior.Status.RUNNING)
|
||||
- .forEach(behavior -> behavior.tickOrStop(level, entity, gameTime));
|
||||
+ // Paper start - Perf: Remove streams from hot code
|
||||
+ for (final BehaviorControl<? super E> behavior : this.behaviors) {
|
||||
+ if (behavior.getStatus() == Behavior.Status.RUNNING) {
|
||||
+ behavior.tickOrStop(level, entity, gameTime);
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - Perf: Remove streams from hot code
|
||||
if (this.behaviors.stream().noneMatch(behavior -> behavior.getStatus() == Behavior.Status.RUNNING)) {
|
||||
this.doStop(level, entity, gameTime);
|
||||
}
|
||||
@@ -78,11 +81,16 @@ public class GateBehavior<E extends LivingEntity> implements BehaviorControl<E>
|
||||
@Override
|
||||
public final void doStop(ServerLevel level, E entity, long gameTime) {
|
||||
this.status = Behavior.Status.STOPPED;
|
||||
- this.behaviors
|
||||
- .stream()
|
||||
- .filter(behavior -> behavior.getStatus() == Behavior.Status.RUNNING)
|
||||
- .forEach(behavior -> behavior.doStop(level, entity, gameTime));
|
||||
- this.exitErasedMemories.forEach(entity.getBrain()::eraseMemory);
|
||||
+ // Paper start - Perf: Remove streams from hot code
|
||||
+ for (final BehaviorControl<? super E> behavior : this.behaviors) {
|
||||
+ if (behavior.getStatus() == Behavior.Status.RUNNING) {
|
||||
+ behavior.doStop(level, entity, gameTime);
|
||||
+ }
|
||||
+ }
|
||||
+ for (final MemoryModuleType<?> exitErasedMemory : this.exitErasedMemories) {
|
||||
+ entity.getBrain().eraseMemory(exitErasedMemory);
|
||||
+ }
|
||||
+ // Paper end - Perf: Remove streams from hot code
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -116,20 +124,30 @@ public class GateBehavior<E extends LivingEntity> implements BehaviorControl<E>
|
||||
|
||||
public static enum RunningPolicy {
|
||||
RUN_ONE {
|
||||
+ // Paper start - Perf: Remove streams from hot code
|
||||
@Override
|
||||
- public <E extends LivingEntity> void apply(Stream<BehaviorControl<? super E>> behaviors, ServerLevel level, E owner, long gameTime) {
|
||||
- behaviors.filter(behavior -> behavior.getStatus() == Behavior.Status.STOPPED)
|
||||
- .filter(behavior -> behavior.tryStart(level, owner, gameTime))
|
||||
- .findFirst();
|
||||
+ public <E extends LivingEntity> void apply(ShufflingList<BehaviorControl<? super E>> behaviors, ServerLevel level, E owner, long gameTime) {
|
||||
+ for (final BehaviorControl<? super E> behavior : behaviors) {
|
||||
+ if (behavior.getStatus() == Behavior.Status.STOPPED && behavior.tryStart(level, owner, gameTime)) {
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - Perf: Remove streams from hot code
|
||||
}
|
||||
},
|
||||
TRY_ALL {
|
||||
+ // Paper start - Perf: Remove streams from hot code
|
||||
@Override
|
||||
- public <E extends LivingEntity> void apply(Stream<BehaviorControl<? super E>> behaviors, ServerLevel level, E owner, long gameTime) {
|
||||
- behaviors.filter(behavior -> behavior.getStatus() == Behavior.Status.STOPPED).forEach(behavior -> behavior.tryStart(level, owner, gameTime));
|
||||
+ public <E extends LivingEntity> void apply(ShufflingList<BehaviorControl<? super E>> behaviors, ServerLevel level, E owner, long gameTime) {
|
||||
+ for (final BehaviorControl<? super E> behavior : behaviors) {
|
||||
+ if (behavior.getStatus() == Behavior.Status.STOPPED) {
|
||||
+ behavior.tryStart(level, owner, gameTime);
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - Perf: Remove streams from hot code
|
||||
}
|
||||
};
|
||||
|
||||
- public abstract <E extends LivingEntity> void apply(Stream<BehaviorControl<? super E>> behaviors, ServerLevel level, E owner, long gameTime);
|
||||
+ public abstract <E extends LivingEntity> void apply(ShufflingList<BehaviorControl<? super E>> behaviors, ServerLevel level, E owner, long gameTime); // Paper - Perf: Remove streams from hot code
|
||||
}
|
||||
}
|
||||
diff --git a/net/minecraft/world/entity/ai/gossip/GossipContainer.java b/net/minecraft/world/entity/ai/gossip/GossipContainer.java
|
||||
index 2c839dc80f451c83135828a97aced1a531004bab..b74a4ce1b629d440681a1f5c026997ccaf1d0373 100644
|
||||
--- a/net/minecraft/world/entity/ai/gossip/GossipContainer.java
|
||||
+++ b/net/minecraft/world/entity/ai/gossip/GossipContainer.java
|
||||
@@ -59,8 +59,22 @@ public class GossipContainer {
|
||||
return this.gossips.entrySet().stream().flatMap(gossip -> gossip.getValue().unpack(gossip.getKey()));
|
||||
}
|
||||
|
||||
+ // Paper start - Perf: Remove streams from hot code
|
||||
+ private List<GossipContainer.GossipEntry> decompress() {
|
||||
+ List<GossipContainer.GossipEntry> list = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>();
|
||||
+ for (Map.Entry<UUID, GossipContainer.EntityGossips> entry : this.gossips.entrySet()) {
|
||||
+ for (GossipContainer.GossipEntry cur : entry.getValue().decompress(entry.getKey())) {
|
||||
+ if (cur.weightedValue() != 0) {
|
||||
+ list.add(cur);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ return list;
|
||||
+ }
|
||||
+ // Paper end - Perf: Remove streams from hot code
|
||||
+
|
||||
private Collection<GossipContainer.GossipEntry> selectGossipsForTransfer(RandomSource random, int amount) {
|
||||
- List<GossipContainer.GossipEntry> list = this.unpack().toList();
|
||||
+ List<GossipContainer.GossipEntry> list = this.decompress(); // Paper - Perf: Remove streams from hot code
|
||||
if (list.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
} else {
|
||||
@@ -145,7 +159,7 @@ public class GossipContainer {
|
||||
|
||||
public <T> T store(DynamicOps<T> ops) {
|
||||
return GossipContainer.GossipEntry.LIST_CODEC
|
||||
- .encodeStart(ops, this.unpack().toList())
|
||||
+ .encodeStart(ops, this.decompress()) // Paper - Perf: Remove streams from hot code
|
||||
.resultOrPartial(errorMessage -> LOGGER.warn("Failed to serialize gossips: {}", errorMessage))
|
||||
.orElseGet(ops::emptyList);
|
||||
}
|
||||
@@ -172,12 +186,23 @@ public class GossipContainer {
|
||||
final Object2IntMap<GossipType> entries = new Object2IntOpenHashMap<>();
|
||||
|
||||
public int weightedValue(Predicate<GossipType> gossipType) {
|
||||
- return this.entries
|
||||
- .object2IntEntrySet()
|
||||
- .stream()
|
||||
- .filter(gossip -> gossipType.test(gossip.getKey()))
|
||||
- .mapToInt(gossip -> gossip.getIntValue() * gossip.getKey().weight)
|
||||
- .sum();
|
||||
+ // Paper start - Perf: Remove streams from hot code
|
||||
+ int weight = 0;
|
||||
+ for (Object2IntMap.Entry<GossipType> entry : entries.object2IntEntrySet()) {
|
||||
+ if (gossipType.test(entry.getKey())) {
|
||||
+ weight += entry.getIntValue() * entry.getKey().weight;
|
||||
+ }
|
||||
+ }
|
||||
+ return weight;
|
||||
+ }
|
||||
+
|
||||
+ public List<GossipContainer.GossipEntry> decompress(UUID uuid) {
|
||||
+ List<GossipContainer.GossipEntry> list = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>();
|
||||
+ for (Object2IntMap.Entry<GossipType> entry : entries.object2IntEntrySet()) {
|
||||
+ list.add(new GossipContainer.GossipEntry(uuid, entry.getKey(), entry.getIntValue()));
|
||||
+ }
|
||||
+ return list;
|
||||
+ // Paper end - Perf: Remove streams from hot code
|
||||
}
|
||||
|
||||
public Stream<GossipContainer.GossipEntry> unpack(UUID identifier) {
|
||||
diff --git a/net/minecraft/world/entity/ai/sensing/NearestItemSensor.java b/net/minecraft/world/entity/ai/sensing/NearestItemSensor.java
|
||||
index 38873e56e95dc772b184e4271f7af1fb411ac9f8..09fd13e2d958da8326276c4dadf25bf488aff5ac 100644
|
||||
--- a/net/minecraft/world/entity/ai/sensing/NearestItemSensor.java
|
||||
+++ b/net/minecraft/world/entity/ai/sensing/NearestItemSensor.java
|
||||
@@ -24,13 +24,17 @@ public class NearestItemSensor extends Sensor<Mob> {
|
||||
@Override
|
||||
protected void doTick(ServerLevel level, Mob entity) {
|
||||
Brain<?> brain = entity.getBrain();
|
||||
- List<ItemEntity> entitiesOfClass = level.getEntitiesOfClass(ItemEntity.class, entity.getBoundingBox().inflate(32.0, 16.0, 32.0), itemEntity -> true);
|
||||
+ List<ItemEntity> entitiesOfClass = level.getEntitiesOfClass(ItemEntity.class, entity.getBoundingBox().inflate(32.0, 16.0, 32.0), itemEntity -> itemEntity.closerThan(entity, MAX_DISTANCE_TO_WANTED_ITEM) && entity.wantsToPickUp(level, itemEntity.getItem())); // Paper - Perf: Move predicate into getEntities
|
||||
entitiesOfClass.sort(Comparator.comparingDouble(entity::distanceToSqr));
|
||||
- Optional<ItemEntity> optional = entitiesOfClass.stream()
|
||||
- .filter(itemEntity -> entity.wantsToPickUp(level, itemEntity.getItem()))
|
||||
- .filter(itemEntity -> itemEntity.closerThan(entity, 32.0))
|
||||
- .filter(entity::hasLineOfSight)
|
||||
- .findFirst();
|
||||
- brain.setMemory(MemoryModuleType.NEAREST_VISIBLE_WANTED_ITEM, optional);
|
||||
+ // Paper start - Perf: remove streams from hot code
|
||||
+ ItemEntity nearest = null;
|
||||
+ for (final ItemEntity itemEntity : entitiesOfClass) {
|
||||
+ if (entity.hasLineOfSight(itemEntity)) { // Paper - Perf: Move predicate into getEntities
|
||||
+ nearest = itemEntity;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ brain.setMemory(MemoryModuleType.NEAREST_VISIBLE_WANTED_ITEM, Optional.ofNullable(nearest));
|
||||
+ // Paper end - Perf: remove streams from hot code
|
||||
}
|
||||
}
|
||||
diff --git a/net/minecraft/world/level/levelgen/Beardifier.java b/net/minecraft/world/level/levelgen/Beardifier.java
|
||||
index 1a09da5aa1ae047a002d6779326c2a29e47d32b5..131923282c9ecbcb1d7f45a826da907c02bd2716 100644
|
||||
--- a/net/minecraft/world/level/levelgen/Beardifier.java
|
||||
+++ b/net/minecraft/world/level/levelgen/Beardifier.java
|
||||
@@ -35,9 +35,10 @@ public class Beardifier implements DensityFunctions.BeardifierOrMarker {
|
||||
int minBlockZ = chunkPos.getMinBlockZ();
|
||||
ObjectList<Beardifier.Rigid> list = new ObjectArrayList<>(10);
|
||||
ObjectList<JigsawJunction> list1 = new ObjectArrayList<>(32);
|
||||
- structureManager.startsForStructure(chunkPos, structure -> structure.terrainAdaptation() != TerrainAdjustment.NONE)
|
||||
- .forEach(
|
||||
- structureStart -> {
|
||||
+ // Paper start - Perf: Remove streams from hot code
|
||||
+ for (net.minecraft.world.level.levelgen.structure.StructureStart structureStart : structureManager.startsForStructure(chunkPos, structure -> {
|
||||
+ return structure.terrainAdaptation() != TerrainAdjustment.NONE;
|
||||
+ })) { // Paper end - Perf: Remove streams from hot code
|
||||
TerrainAdjustment terrainAdjustment = structureStart.getStructure().terrainAdaptation();
|
||||
|
||||
for (StructurePiece structurePiece : structureStart.getPieces()) {
|
||||
@@ -65,8 +66,7 @@ public class Beardifier implements DensityFunctions.BeardifierOrMarker {
|
||||
}
|
||||
}
|
||||
}
|
||||
- }
|
||||
- );
|
||||
+ } // Paper - Perf: Remove streams from hot code
|
||||
return new Beardifier(list.iterator(), list1.iterator());
|
||||
}
|
||||
|
|
@ -15,100 +15,103 @@ Optimize collection by creating a list instead of a set of the key and value.
|
|||
This lets us get faster foreach iteration, as well as avoids map lookups on
|
||||
the values when needed.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/pathfinder/PathFinder.java b/src/main/java/net/minecraft/world/level/pathfinder/PathFinder.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/pathfinder/PathFinder.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/pathfinder/PathFinder.java
|
||||
@@ -0,0 +0,0 @@ public class PathFinder {
|
||||
if (node == null) {
|
||||
diff --git a/net/minecraft/world/level/pathfinder/PathFinder.java b/net/minecraft/world/level/pathfinder/PathFinder.java
|
||||
index a6ef296f7af1f784e1f0772947a6cb3519a3bc2a..81de6c1bbef1cafd3036e736dd305fbedc8368c6 100644
|
||||
--- a/net/minecraft/world/level/pathfinder/PathFinder.java
|
||||
+++ b/net/minecraft/world/level/pathfinder/PathFinder.java
|
||||
@@ -43,8 +43,12 @@ public class PathFinder {
|
||||
if (start == null) {
|
||||
return null;
|
||||
} else {
|
||||
- Map<Target, BlockPos> map = positions.stream()
|
||||
- .collect(Collectors.toMap(pos -> this.nodeEvaluator.getTarget((double)pos.getX(), (double)pos.getY(), (double)pos.getZ()), Function.identity()));
|
||||
- Map<Target, BlockPos> map = targetPositions.stream()
|
||||
- .collect(Collectors.toMap(pos -> this.nodeEvaluator.getTarget(pos.getX(), pos.getY(), pos.getZ()), Function.identity()));
|
||||
+ // Paper start - Perf: remove streams and optimize collection
|
||||
+ List<Map.Entry<Target, BlockPos>> map = Lists.newArrayList();
|
||||
+ for (final BlockPos pos : positions) {
|
||||
+ for (BlockPos pos : targetPositions) {
|
||||
+ map.add(new java.util.AbstractMap.SimpleEntry<>(this.nodeEvaluator.getTarget(pos.getX(), pos.getY(), pos.getZ()), pos));
|
||||
+ }
|
||||
+ // Paper end - Perf: remove streams and optimize collection
|
||||
Path path = this.findPath(node, map, followRange, distance, rangeMultiplier);
|
||||
Path path = this.findPath(start, map, maxRange, accuracy, searchDepthMultiplier);
|
||||
this.nodeEvaluator.done();
|
||||
return path;
|
||||
@@ -0,0 +0,0 @@ public class PathFinder {
|
||||
@@ -52,19 +56,19 @@ public class PathFinder {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
- private Path findPath(Node startNode, Map<Target, BlockPos> positions, float followRange, int distance, float rangeMultiplier) {
|
||||
+ // Paper start - Perf: remove streams and optimize collection
|
||||
+ private Path findPath(Node startNode, List<Map.Entry<Target, BlockPos>> positions, float followRange, int distance, float rangeMultiplier) {
|
||||
- private Path findPath(Node node, Map<Target, BlockPos> targetPositions, float maxRange, int accuracy, float searchDepthMultiplier) {
|
||||
+ private Path findPath(Node node, List<Map.Entry<Target, BlockPos>> positions, float maxRange, int accuracy, float searchDepthMultiplier) { // Paper - optimize collection
|
||||
ProfilerFiller profilerFiller = Profiler.get();
|
||||
profilerFiller.push("find_path");
|
||||
profilerFiller.markForCharting(MetricCategory.PATH_FINDING);
|
||||
- Set<Target> set = positions.keySet();
|
||||
+ // Set<Target> set = positions.keySet();
|
||||
startNode.g = 0.0F;
|
||||
- startNode.h = this.getBestH(startNode, set);
|
||||
+ startNode.h = this.getBestH(startNode, positions); // Paper - optimize collection
|
||||
startNode.f = startNode.h;
|
||||
- Set<Target> set = targetPositions.keySet();
|
||||
+ // Set<Target> set = targetPositions.keySet(); // Paper
|
||||
node.g = 0.0F;
|
||||
- node.h = this.getBestH(node, set);
|
||||
+ node.h = this.getBestH(node, positions); // Paper - optimize collection
|
||||
node.f = node.h;
|
||||
this.openSet.clear();
|
||||
this.openSet.insert(startNode);
|
||||
- Set<Node> set2 = ImmutableSet.of();
|
||||
+ // Set<Node> set2 = ImmutableSet.of(); // Paper - unused - diff on change
|
||||
this.openSet.insert(node);
|
||||
- Set<Node> set1 = ImmutableSet.of();
|
||||
+ // Set<Node> set1 = ImmutableSet.of(); // Paper - unused - diff on change
|
||||
int i = 0;
|
||||
- Set<Target> set3 = Sets.newHashSetWithExpectedSize(set.size());
|
||||
- Set<Target> set2 = Sets.newHashSetWithExpectedSize(set.size());
|
||||
+ List<Map.Entry<Target, BlockPos>> entryList = Lists.newArrayListWithExpectedSize(positions.size()); // Paper - optimize collection
|
||||
int j = (int)((float)this.maxVisitedNodes * rangeMultiplier);
|
||||
int i1 = (int)(this.maxVisitedNodes * searchDepthMultiplier);
|
||||
|
||||
while (!this.openSet.isEmpty()) {
|
||||
@@ -0,0 +0,0 @@ public class PathFinder {
|
||||
Node node = this.openSet.pop();
|
||||
node.closed = true;
|
||||
@@ -75,14 +79,18 @@ public class PathFinder {
|
||||
Node node1 = this.openSet.pop();
|
||||
node1.closed = true;
|
||||
|
||||
- for (Target target : set) {
|
||||
+ // Paper start - optimize collection
|
||||
+ for (int i1 = 0; i1 < positions.size(); i1++) {
|
||||
+ final Map.Entry<Target, BlockPos> entry = positions.get(i1);
|
||||
+ for (int positionIndex = 0, size = positions.size(); positionIndex < size; positionIndex++) {
|
||||
+ final Map.Entry<Target, BlockPos> entry = positions.get(positionIndex);
|
||||
+ Target target = entry.getKey();
|
||||
if (node.distanceManhattan(target) <= (float)distance) {
|
||||
if (node1.distanceManhattan(target) <= accuracy) {
|
||||
target.setReached();
|
||||
- set3.add(target);
|
||||
- set2.add(target);
|
||||
+ entryList.add(entry);
|
||||
+ // Paper end - Perf: remove streams and optimize collection
|
||||
}
|
||||
}
|
||||
|
||||
- if (!set3.isEmpty()) {
|
||||
- if (!set2.isEmpty()) {
|
||||
+ if (!entryList.isEmpty()) { // Paper - Perf: remove streams and optimize collection; rename
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -0,0 +0,0 @@ public class PathFinder {
|
||||
if (node2.walkedDistance < followRange && (!node2.inOpenSet() || g < node2.g)) {
|
||||
node2.cameFrom = node;
|
||||
node2.g = g;
|
||||
@@ -97,7 +105,7 @@ public class PathFinder {
|
||||
if (node2.walkedDistance < maxRange && (!node2.inOpenSet() || f1 < node2.g)) {
|
||||
node2.cameFrom = node1;
|
||||
node2.g = f1;
|
||||
- node2.h = this.getBestH(node2, set) * 1.5F;
|
||||
+ node2.h = this.getBestH(node2, positions) * 1.5F; // Paper - Perf: remove streams and optimize collection
|
||||
if (node2.inOpenSet()) {
|
||||
this.openSet.changeCost(node2, node2.g + node2.h);
|
||||
} else {
|
||||
@@ -0,0 +0,0 @@ public class PathFinder {
|
||||
@@ -109,25 +117,34 @@ public class PathFinder {
|
||||
}
|
||||
}
|
||||
|
||||
- Optional<Path> optional = !set3.isEmpty()
|
||||
- ? set3.stream().map(node -> this.reconstructPath(node.getBestNode(), positions.get(node), true)).min(Comparator.comparingInt(Path::getNodeCount))
|
||||
- Optional<Path> optional = !set2.isEmpty()
|
||||
- ? set2.stream()
|
||||
- .map(pathfinder -> this.reconstructPath(pathfinder.getBestNode(), targetPositions.get(pathfinder), true))
|
||||
- .min(Comparator.comparingInt(Path::getNodeCount))
|
||||
- : set.stream()
|
||||
- .map(targetx -> this.reconstructPath(targetx.getBestNode(), positions.get(targetx), false))
|
||||
- .map(pathfinder -> this.reconstructPath(pathfinder.getBestNode(), targetPositions.get(pathfinder), false))
|
||||
- .min(Comparator.comparingDouble(Path::getDistToTarget).thenComparingInt(Path::getNodeCount));
|
||||
+ // Paper start - Perf: remove streams and optimize collection
|
||||
+ Path best = null;
|
||||
+ boolean entryListIsEmpty = entryList.isEmpty();
|
||||
+ Comparator<Path> comparator = entryListIsEmpty ? Comparator.comparingInt(Path::getNodeCount)
|
||||
+ Comparator<Path> comparator = entryListIsEmpty
|
||||
+ ? Comparator.comparingInt(Path::getNodeCount)
|
||||
+ : Comparator.comparingDouble(Path::getDistToTarget).thenComparingInt(Path::getNodeCount);
|
||||
+ for (Map.Entry<Target, BlockPos> entry : entryListIsEmpty ? positions : entryList) {
|
||||
+ Path path = this.reconstructPath(entry.getKey().getBestNode(), entry.getValue(), !entryListIsEmpty);
|
||||
+ if (best == null || comparator.compare(path, best) < 0)
|
||||
+ if (best == null || comparator.compare(path, best) < 0) {
|
||||
+ best = path;
|
||||
+ }
|
||||
+ }
|
||||
profilerFiller.pop();
|
||||
- return optional.isEmpty() ? null : optional.get();
|
||||
|
@ -116,8 +119,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ // Paper end - Perf: remove streams and optimize collection
|
||||
}
|
||||
|
||||
protected float distance(Node a, Node b) {
|
||||
return a.distanceTo(b);
|
||||
protected float distance(Node first, Node second) {
|
||||
return first.distanceTo(second);
|
||||
}
|
||||
|
||||
- private float getBestH(Node node, Set<Target> targets) {
|
||||
|
@ -129,6 +132,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ for (int i = 0, targetsSize = targets.size(); i < targetsSize; i++) {
|
||||
+ final Target target = targets.get(i).getKey();
|
||||
+ // Paper end - Perf: remove streams and optimize collection
|
||||
float g = node.distanceTo(target);
|
||||
target.updateBest(g, node);
|
||||
f = Math.min(g, f);
|
||||
float f1 = node.distanceTo(target);
|
||||
target.updateBest(f1, node);
|
||||
f = Math.min(f1, f);
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -28,30 +28,30 @@ which is most likely in an unloaded chunk - which means that the
|
|||
client will not tick the entity and thus not lerp the entity
|
||||
from its old position to its new position.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundAddEntityPacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundAddEntityPacket.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundAddEntityPacket.java
|
||||
+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundAddEntityPacket.java
|
||||
@@ -0,0 +0,0 @@ public class ClientboundAddEntityPacket implements Packet<ClientGamePacketListen
|
||||
diff --git a/net/minecraft/network/protocol/game/ClientboundAddEntityPacket.java b/net/minecraft/network/protocol/game/ClientboundAddEntityPacket.java
|
||||
index db31989ebe3d7021cfd2311439e9a00f819b0841..1373977b339405ef59bb3ea03d195285c96dd3fe 100644
|
||||
--- a/net/minecraft/network/protocol/game/ClientboundAddEntityPacket.java
|
||||
+++ b/net/minecraft/network/protocol/game/ClientboundAddEntityPacket.java
|
||||
@@ -42,9 +42,11 @@ public class ClientboundAddEntityPacket implements Packet<ClientGamePacketListen
|
||||
this(
|
||||
entity.getId(),
|
||||
entity.getUUID(),
|
||||
- entityTrackerEntry.getPositionBase().x(),
|
||||
- entityTrackerEntry.getPositionBase().y(),
|
||||
- entityTrackerEntry.getPositionBase().z(),
|
||||
- serverEntity.getPositionBase().x(),
|
||||
- serverEntity.getPositionBase().y(),
|
||||
- serverEntity.getPositionBase().z(),
|
||||
+ // Paper start - fix entity tracker desync
|
||||
+ entity.trackingPosition().x(),
|
||||
+ entity.trackingPosition().y(),
|
||||
+ entity.trackingPosition().z(),
|
||||
+ // Paper end - fix entity tracker desync
|
||||
entityTrackerEntry.getLastSentXRot(),
|
||||
entityTrackerEntry.getLastSentYRot(),
|
||||
serverEntity.getLastSentXRot(),
|
||||
serverEntity.getLastSentYRot(),
|
||||
entity.getType(),
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java
|
||||
index 3dff97f13586be3b52bbe786852c185f6753a019..ff6503bf8eb88d1264c3d848a89d0255b4b3ae68 100644
|
||||
--- a/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -1208,6 +1208,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
this.serverEntity.addPairing(player);
|
||||
}
|
||||
// Paper end - entity tracking events
|
||||
|
@ -59,11 +59,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
}
|
||||
} else if (this.seenBy.remove(player.connection)) {
|
||||
this.serverEntity.removePairing(player);
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerEntity.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerEntity.java
|
||||
@@ -0,0 +0,0 @@ public class ServerEntity {
|
||||
diff --git a/net/minecraft/server/level/ServerEntity.java b/net/minecraft/server/level/ServerEntity.java
|
||||
index 870b9efd445ddadb3725e88351555ad986ce7c72..a4da36060ca75968f5831adfc3f7117281649b7a 100644
|
||||
--- a/net/minecraft/server/level/ServerEntity.java
|
||||
+++ b/net/minecraft/server/level/ServerEntity.java
|
||||
@@ -90,6 +90,13 @@ public class ServerEntity {
|
||||
this.trackedDataValues = entity.getEntityData().getNonDefaultValues();
|
||||
}
|
||||
|
||||
|
@ -77,29 +77,29 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
public void sendChanges() {
|
||||
// Paper start - optimise collisions
|
||||
if (((ca.spottedleaf.moonrise.patches.chunk_system.entity.ChunkSystemEntity)this.entity).moonrise$isHardColliding()) {
|
||||
@@ -0,0 +0,0 @@ public class ServerEntity {
|
||||
}
|
||||
@@ -130,7 +137,7 @@ public class ServerEntity {
|
||||
this.sendDirtyEntityData();
|
||||
}
|
||||
|
||||
- if (this.tickCount % this.updateInterval == 0 || this.entity.hasImpulse || this.entity.getEntityData().isDirty()) {
|
||||
+ if (this.forceStateResync || this.tickCount % this.updateInterval == 0 || this.entity.hasImpulse || this.entity.getEntityData().isDirty()) { // Paper - fix desync when a player is added to the tracker
|
||||
byte b0 = Mth.packDegrees(this.entity.getYRot());
|
||||
byte b = Mth.packDegrees(this.entity.getYRot());
|
||||
byte b1 = Mth.packDegrees(this.entity.getXRot());
|
||||
boolean flag = Math.abs(b0 - this.lastSentYRot) >= 1 || Math.abs(b1 - this.lastSentXRot) >= 1;
|
||||
@@ -0,0 +0,0 @@ public class ServerEntity {
|
||||
long k = this.positionCodec.encodeZ(vec3d);
|
||||
boolean flag5 = i < -32768L || i > 32767L || j < -32768L || j > 32767L || k < -32768L || k > 32767L;
|
||||
|
||||
- if (!flag5 && this.teleportDelay <= 400 && !this.wasRiding && this.wasOnGround == this.entity.onGround()) {
|
||||
+ if (!this.forceStateResync && !flag5 && this.teleportDelay <= 400 && !this.wasRiding && this.wasOnGround == this.entity.onGround()) { // Paper - fix desync when a player is added to the tracker
|
||||
if ((!flag2 || !flag) && !(this.entity instanceof AbstractArrow)) {
|
||||
if (flag2) {
|
||||
packet1 = new ClientboundMoveEntityPacket.Pos(this.entity.getId(), (short) ((int) i), (short) ((int) j), (short) ((int) k), this.entity.onGround());
|
||||
@@ -0,0 +0,0 @@ public class ServerEntity {
|
||||
boolean flag = Math.abs(b - this.lastSentYRot) >= 1 || Math.abs(b1 - this.lastSentXRot) >= 1;
|
||||
@@ -165,7 +172,7 @@ public class ServerEntity {
|
||||
long l1 = this.positionCodec.encodeY(vec3);
|
||||
long l2 = this.positionCodec.encodeZ(vec3);
|
||||
boolean flag5 = l < -32768L || l > 32767L || l1 < -32768L || l1 > 32767L || l2 < -32768L || l2 > 32767L;
|
||||
- if (flag5 || this.teleportDelay > 400 || this.wasRiding || this.wasOnGround != this.entity.onGround()) {
|
||||
+ if (this.forceStateResync || flag5 || this.teleportDelay > 400 || this.wasRiding || this.wasOnGround != this.entity.onGround()) { // Paper - fix desync when a player is added to the tracker
|
||||
this.wasOnGround = this.entity.onGround();
|
||||
this.teleportDelay = 0;
|
||||
packet = ClientboundEntityPositionSyncPacket.of(this.entity);
|
||||
@@ -230,6 +237,7 @@ public class ServerEntity {
|
||||
}
|
||||
|
||||
this.entity.hasImpulse = false;
|
||||
+ this.forceStateResync = false; // Paper - fix desync when a player is added to the tracker
|
||||
}
|
||||
|
||||
++this.tickCount;
|
||||
this.tickCount++;
|
|
@ -3,8 +3,6 @@ From: theosib <millerti@172.16.221.1>
|
|||
Date: Thu, 27 Sep 2018 01:43:35 -0600
|
||||
Subject: [PATCH] Eigencraft redstone implementation
|
||||
|
||||
Author: theosib <millerti@172.16.221.1>
|
||||
|
||||
Original license: MIT
|
||||
|
||||
This patch implements theosib's redstone algorithms to completely overhaul the way redstone works.
|
||||
|
@ -17,19 +15,15 @@ A lot of this code is self-contained in a helper class.
|
|||
Aside from making the obvious class/function renames and obfhelpers I didn't need to modify much.
|
||||
Just added Bukkit's event system and took a few liberties with dead code and comment misspellings.
|
||||
|
||||
== AT ==
|
||||
public net.minecraft.world.level.block.RedStoneWireBlock shouldSignal
|
||||
public net.minecraft.world.level.block.RedStoneWireBlock canSurvive(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/LevelReader;Lnet/minecraft/core/BlockPos;)Z
|
||||
|
||||
Co-authored-by: egg82 <eggys82@gmail.com>
|
||||
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/util/RedstoneWireTurbo.java b/src/main/java/com/destroystokyo/paper/util/RedstoneWireTurbo.java
|
||||
diff --git a/io/papermc/paper/redstone/RedstoneWireTurbo.java b/io/papermc/paper/redstone/RedstoneWireTurbo.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
|
||||
index 0000000000000000000000000000000000000000..ff747a1ecdf3c888bca0d69de4f85dcd810b6139
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/com/destroystokyo/paper/util/RedstoneWireTurbo.java
|
||||
@@ -0,0 +0,0 @@
|
||||
+package com.destroystokyo.paper.util;
|
||||
+++ b/io/papermc/paper/redstone/RedstoneWireTurbo.java
|
||||
@@ -0,0 +1,954 @@
|
||||
+package io.papermc.paper.redstone;
|
||||
+
|
||||
+import java.util.List;
|
||||
+import java.util.Map;
|
||||
|
@ -48,14 +42,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+import com.google.common.collect.Lists;
|
||||
+import com.google.common.collect.Maps;
|
||||
+
|
||||
+/**
|
||||
+ * Used for the faster redstone algorithm.
|
||||
+ * Original author: theosib
|
||||
+ * Original license: MIT
|
||||
+ *
|
||||
+ * Ported to Paper and updated to 1.13 by egg82
|
||||
+ */
|
||||
+public class RedstoneWireTurbo {
|
||||
+public final class RedstoneWireTurbo {
|
||||
+ /*
|
||||
+ * This is Helper class for BlockRedstoneWire. It implements a minimally-invasive
|
||||
+ * bolt-on accelerator that performs a breadth-first search through redstone wire blocks
|
||||
|
@ -862,7 +849,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ */
|
||||
+ private BlockState calculateCurrentChanges(final Level worldIn, final UpdateNode upd) {
|
||||
+ BlockState state = upd.currentState;
|
||||
+ final int i = state.getValue(RedStoneWireBlock.POWER).intValue();
|
||||
+ final int i = state.getValue(RedStoneWireBlock.POWER);
|
||||
+ int j = 0;
|
||||
+ j = getMaxCurrentStrength(upd, j);
|
||||
+ int l = 0;
|
||||
|
@ -986,21 +973,21 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ */
|
||||
+ private static int getMaxCurrentStrength(final UpdateNode upd, final int strength) {
|
||||
+ if (upd.type != UpdateNode.Type.REDSTONE) return strength;
|
||||
+ final int i = upd.currentState.getValue(RedStoneWireBlock.POWER).intValue();
|
||||
+ final int i = upd.currentState.getValue(RedStoneWireBlock.POWER);
|
||||
+ return i > strength ? i : strength;
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/RedStoneWireBlock.java b/src/main/java/net/minecraft/world/level/block/RedStoneWireBlock.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/RedStoneWireBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/RedStoneWireBlock.java
|
||||
@@ -0,0 +0,0 @@ public class RedStoneWireBlock extends Block {
|
||||
return floor.isFaceSturdy(world, pos, Direction.UP) || floor.is(Blocks.HOPPER);
|
||||
diff --git a/net/minecraft/world/level/block/RedStoneWireBlock.java b/net/minecraft/world/level/block/RedStoneWireBlock.java
|
||||
index 84e6c986917128d4488afa23d29c689cadb4f55d..f02232ce97779db0d12a5d5da1d767326d78ea4c 100644
|
||||
--- a/net/minecraft/world/level/block/RedStoneWireBlock.java
|
||||
+++ b/net/minecraft/world/level/block/RedStoneWireBlock.java
|
||||
@@ -290,6 +290,60 @@ public class RedStoneWireBlock extends Block {
|
||||
return state.isFaceSturdy(level, pos, Direction.UP) || state.is(Blocks.HOPPER);
|
||||
}
|
||||
|
||||
+ // Paper start - Optimize redstone
|
||||
+ // The bulk of the new functionality is found in RedstoneWireTurbo.java
|
||||
+ com.destroystokyo.paper.util.RedstoneWireTurbo turbo = new com.destroystokyo.paper.util.RedstoneWireTurbo(this);
|
||||
+ io.papermc.paper.redstone.RedstoneWireTurbo turbo = new io.papermc.paper.redstone.RedstoneWireTurbo(this);
|
||||
+
|
||||
+ /*
|
||||
+ * Modified version of pre-existing updateSurroundingRedstone, which is called from
|
||||
|
@ -1052,46 +1039,46 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
private void updatePowerStrength(Level world, BlockPos pos, BlockState state, @Nullable Orientation orientation, boolean blockAdded) {
|
||||
if (useExperimentalEvaluator(world)) {
|
||||
new ExperimentalRedstoneWireEvaluator(this).updatePowerStrength(world, pos, state, orientation, blockAdded);
|
||||
@@ -0,0 +0,0 @@ public class RedStoneWireBlock extends Block {
|
||||
private void updatePowerStrength(Level level, BlockPos pos, BlockState state, @Nullable Orientation orientation, boolean updateShape) {
|
||||
if (useExperimentalEvaluator(level)) {
|
||||
new ExperimentalRedstoneWireEvaluator(this).updatePowerStrength(level, pos, state, orientation, updateShape);
|
||||
@@ -318,7 +372,7 @@ public class RedStoneWireBlock extends Block {
|
||||
@Override
|
||||
protected void onPlace(BlockState state, Level world, BlockPos pos, BlockState oldState, boolean notify) {
|
||||
if (!oldState.is(state.getBlock()) && !world.isClientSide) {
|
||||
- this.updatePowerStrength(world, pos, state, null, true);
|
||||
+ this.updateSurroundingRedstone(world, pos, state, null, true); // Paper - Optimize redstone
|
||||
protected void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean isMoving) {
|
||||
if (!oldState.is(state.getBlock()) && !level.isClientSide) {
|
||||
- this.updatePowerStrength(level, pos, state, null, true);
|
||||
+ this.updateSurroundingRedstone(level, pos, state, null, true); // Paper - Optimize redstone
|
||||
|
||||
for (Direction direction : Direction.Plane.VERTICAL) {
|
||||
world.updateNeighborsAt(pos.relative(direction), this);
|
||||
@@ -0,0 +0,0 @@ public class RedStoneWireBlock extends Block {
|
||||
world.updateNeighborsAt(pos.relative(direction), this);
|
||||
level.updateNeighborsAt(pos.relative(direction), this);
|
||||
@@ -337,7 +391,7 @@ public class RedStoneWireBlock extends Block {
|
||||
level.updateNeighborsAt(pos.relative(direction), this);
|
||||
}
|
||||
|
||||
- this.updatePowerStrength(world, pos, state, null, false);
|
||||
+ this.updateSurroundingRedstone(world, pos, state, null, false); // Paper - Optimize redstone
|
||||
this.updateNeighborsOfNeighboringWires(world, pos);
|
||||
- this.updatePowerStrength(level, pos, state, null, false);
|
||||
+ this.updateSurroundingRedstone(level, pos, state, null, false); // Paper - Optimize redstone
|
||||
this.updateNeighborsOfNeighboringWires(level, pos);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +0,0 @@ public class RedStoneWireBlock extends Block {
|
||||
if (!world.isClientSide) {
|
||||
if (sourceBlock != this || !useExperimentalEvaluator(world)) {
|
||||
if (state.canSurvive(world, pos)) {
|
||||
- this.updatePowerStrength(world, pos, state, wireOrientation, false);
|
||||
+ this.updateSurroundingRedstone(world, pos, state, wireOrientation, false); // Paper - Optimize redstone
|
||||
@@ -363,7 +417,7 @@ public class RedStoneWireBlock extends Block {
|
||||
if (!level.isClientSide) {
|
||||
if (neighborBlock != this || !useExperimentalEvaluator(level)) {
|
||||
if (state.canSurvive(level, pos)) {
|
||||
- this.updatePowerStrength(level, pos, state, orientation, false);
|
||||
+ this.updateSurroundingRedstone(level, pos, state, orientation, false); // Paper - Optimize redstone
|
||||
} else {
|
||||
dropResources(state, world, pos);
|
||||
world.removeBlock(pos, false);
|
||||
diff --git a/src/main/java/net/minecraft/world/level/redstone/DefaultRedstoneWireEvaluator.java b/src/main/java/net/minecraft/world/level/redstone/DefaultRedstoneWireEvaluator.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/redstone/DefaultRedstoneWireEvaluator.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/redstone/DefaultRedstoneWireEvaluator.java
|
||||
@@ -0,0 +0,0 @@ public class DefaultRedstoneWireEvaluator extends RedstoneWireEvaluator {
|
||||
|
||||
dropResources(state, level, pos);
|
||||
level.removeBlock(pos, false);
|
||||
diff --git a/net/minecraft/world/level/redstone/DefaultRedstoneWireEvaluator.java b/net/minecraft/world/level/redstone/DefaultRedstoneWireEvaluator.java
|
||||
index 380fc51a252022195e178daccd8aa53dd1d71a2e..2d77780b6727f82ffc3cb216ca5f2d6483496cfd 100644
|
||||
--- a/net/minecraft/world/level/redstone/DefaultRedstoneWireEvaluator.java
|
||||
+++ b/net/minecraft/world/level/redstone/DefaultRedstoneWireEvaluator.java
|
||||
@@ -44,7 +44,7 @@ public class DefaultRedstoneWireEvaluator extends RedstoneWireEvaluator {
|
||||
}
|
||||
}
|
||||
|
||||
- private int calculateTargetStrength(Level world, BlockPos pos) {
|
||||
+ public int calculateTargetStrength(Level world, BlockPos pos) { // Paper - Optimize redstone
|
||||
int i = this.getBlockSignal(world, pos);
|
||||
|
||||
return i == 15 ? i : Math.max(i, this.getIncomingWireSignal(world, pos));
|
||||
- private int calculateTargetStrength(Level level, BlockPos pos) {
|
||||
+ public int calculateTargetStrength(Level level, BlockPos pos) { // Paper - Optimize redstone
|
||||
int blockSignal = this.getBlockSignal(level, pos);
|
||||
return blockSignal == 15 ? blockSignal : Math.max(blockSignal, this.getIncomingWireSignal(level, pos));
|
||||
}
|
|
@ -20,12 +20,12 @@ Alternate Current needs the following modifications:
|
|||
* RedStoneWireBlock: Replace calls to vanilla's or Eigencraft's methods for handling power changes with calls to
|
||||
Alternate Current's wire handler.
|
||||
|
||||
diff --git a/src/main/java/alternate/current/wire/LevelHelper.java b/src/main/java/alternate/current/wire/LevelHelper.java
|
||||
diff --git a/alternate/current/wire/LevelHelper.java b/alternate/current/wire/LevelHelper.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
|
||||
index 0000000000000000000000000000000000000000..eda108e2df9bf7d1ddd89287b8d2c2d7f1637c96
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/alternate/current/wire/LevelHelper.java
|
||||
@@ -0,0 +0,0 @@
|
||||
+++ b/alternate/current/wire/LevelHelper.java
|
||||
@@ -0,0 +1,66 @@
|
||||
+package alternate.current.wire;
|
||||
+
|
||||
+import org.bukkit.craftbukkit.block.CraftBlock;
|
||||
|
@ -92,12 +92,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ return true;
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/alternate/current/wire/Node.java b/src/main/java/alternate/current/wire/Node.java
|
||||
diff --git a/alternate/current/wire/Node.java b/alternate/current/wire/Node.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
|
||||
index 0000000000000000000000000000000000000000..8af6c69098e64945361d116b5fd6ac21e97fcd8d
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/alternate/current/wire/Node.java
|
||||
@@ -0,0 +0,0 @@
|
||||
+++ b/alternate/current/wire/Node.java
|
||||
@@ -0,0 +1,113 @@
|
||||
+package alternate.current.wire;
|
||||
+
|
||||
+import java.util.Arrays;
|
||||
|
@ -211,12 +211,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ throw new UnsupportedOperationException("Not a WireNode!");
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/alternate/current/wire/PriorityQueue.java b/src/main/java/alternate/current/wire/PriorityQueue.java
|
||||
diff --git a/alternate/current/wire/PriorityQueue.java b/alternate/current/wire/PriorityQueue.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
|
||||
index 0000000000000000000000000000000000000000..d71b4d0e4c44a2620b41b89475412db53bea20ed
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/alternate/current/wire/PriorityQueue.java
|
||||
@@ -0,0 +0,0 @@
|
||||
+++ b/alternate/current/wire/PriorityQueue.java
|
||||
@@ -0,0 +1,211 @@
|
||||
+package alternate.current.wire;
|
||||
+
|
||||
+import java.util.AbstractQueue;
|
||||
|
@ -428,12 +428,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ return prev;
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/alternate/current/wire/SimpleQueue.java b/src/main/java/alternate/current/wire/SimpleQueue.java
|
||||
diff --git a/alternate/current/wire/SimpleQueue.java b/alternate/current/wire/SimpleQueue.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
|
||||
index 0000000000000000000000000000000000000000..2b30074252551e1dc55d5be17d26fb4a2d8eb2e4
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/alternate/current/wire/SimpleQueue.java
|
||||
@@ -0,0 +0,0 @@
|
||||
+++ b/alternate/current/wire/SimpleQueue.java
|
||||
@@ -0,0 +1,112 @@
|
||||
+package alternate.current.wire;
|
||||
+
|
||||
+import java.util.AbstractQueue;
|
||||
|
@ -546,12 +546,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ }
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/alternate/current/wire/UpdateOrder.java b/src/main/java/alternate/current/wire/UpdateOrder.java
|
||||
diff --git a/alternate/current/wire/UpdateOrder.java b/alternate/current/wire/UpdateOrder.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
|
||||
index 0000000000000000000000000000000000000000..29338efd16cf62bb49e81cce09fbafd9b4319e7c
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/alternate/current/wire/UpdateOrder.java
|
||||
@@ -0,0 +0,0 @@
|
||||
+++ b/alternate/current/wire/UpdateOrder.java
|
||||
@@ -0,0 +1,390 @@
|
||||
+package alternate.current.wire;
|
||||
+
|
||||
+import java.util.Locale;
|
||||
|
@ -942,12 +942,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ public abstract void forEachNeighbor(NodeProvider nodes, Node source, int forward, Consumer<Node> action);
|
||||
+
|
||||
+}
|
||||
diff --git a/src/main/java/alternate/current/wire/WireConnection.java b/src/main/java/alternate/current/wire/WireConnection.java
|
||||
diff --git a/alternate/current/wire/WireConnection.java b/alternate/current/wire/WireConnection.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
|
||||
index 0000000000000000000000000000000000000000..4fd8cb29024330397cfe4cbc1f237d285bfb7b3e
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/alternate/current/wire/WireConnection.java
|
||||
@@ -0,0 +0,0 @@
|
||||
+++ b/alternate/current/wire/WireConnection.java
|
||||
@@ -0,0 +1,30 @@
|
||||
+package alternate.current.wire;
|
||||
+
|
||||
+/**
|
||||
|
@ -978,12 +978,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ this.accept = accept;
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/alternate/current/wire/WireConnectionManager.java b/src/main/java/alternate/current/wire/WireConnectionManager.java
|
||||
diff --git a/alternate/current/wire/WireConnectionManager.java b/alternate/current/wire/WireConnectionManager.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
|
||||
index 0000000000000000000000000000000000000000..f03b313e58385d626490a9e64c9616fd08aa951e
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/alternate/current/wire/WireConnectionManager.java
|
||||
@@ -0,0 +0,0 @@
|
||||
+++ b/alternate/current/wire/WireConnectionManager.java
|
||||
@@ -0,0 +1,134 @@
|
||||
+package alternate.current.wire;
|
||||
+
|
||||
+import java.util.Arrays;
|
||||
|
@ -1118,12 +1118,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ }
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/alternate/current/wire/WireHandler.java b/src/main/java/alternate/current/wire/WireHandler.java
|
||||
diff --git a/alternate/current/wire/WireHandler.java b/alternate/current/wire/WireHandler.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
|
||||
index 0000000000000000000000000000000000000000..259b301b2c8b64cb7974a235afb260e0e991af54
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/alternate/current/wire/WireHandler.java
|
||||
@@ -0,0 +0,0 @@
|
||||
+++ b/alternate/current/wire/WireHandler.java
|
||||
@@ -0,0 +1,1073 @@
|
||||
+package alternate.current.wire;
|
||||
+
|
||||
+import java.util.Iterator;
|
||||
|
@ -2197,12 +2197,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/alternate/current/wire/WireNode.java b/src/main/java/alternate/current/wire/WireNode.java
|
||||
diff --git a/alternate/current/wire/WireNode.java b/alternate/current/wire/WireNode.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
|
||||
index 0000000000000000000000000000000000000000..298076a0db4e6ee6e4775ac43bf749d9f5689bdb
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/alternate/current/wire/WireNode.java
|
||||
@@ -0,0 +0,0 @@
|
||||
+++ b/alternate/current/wire/WireNode.java
|
||||
@@ -0,0 +1,122 @@
|
||||
+package alternate.current.wire;
|
||||
+
|
||||
+import net.minecraft.core.BlockPos;
|
||||
|
@ -2325,11 +2325,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ return LevelHelper.setWireState(level, pos, state, added);
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
||||
index 95a4e37a3c93f9b3c56c7a7376ed521cd46fbb6f..46dfaed12c998c219a20c711a06531aed2c68012 100644
|
||||
--- a/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -214,6 +214,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
public final UUID uuid;
|
||||
public boolean hasPhysicsEvent = true; // Paper - BlockPhysicsEvent
|
||||
public boolean hasEntityMoveEvent; // Paper - Add EntityMoveEvent
|
||||
|
@ -2337,7 +2337,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
|
||||
public LevelChunk getChunkIfLoaded(int x, int z) {
|
||||
return this.chunkSource.getChunkAtIfLoadedImmediately(x, z); // Paper - Use getChunkIfLoadedImmediately
|
||||
@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
@@ -2555,6 +2556,13 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
return this.chunkSource.getGenerator().getSeaLevel();
|
||||
}
|
||||
|
||||
|
@ -2348,14 +2348,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ }
|
||||
+ // Paper end - optimize redstone (Alternate Current)
|
||||
+
|
||||
private final class EntityCallbacks implements LevelCallback<Entity> {
|
||||
|
||||
EntityCallbacks() {}
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -0,0 +0,0 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
||||
final class EntityCallbacks implements LevelCallback<Entity> {
|
||||
@Override
|
||||
public void onCreated(Entity entity) {
|
||||
diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java
|
||||
index 8331b49185500ab3b4307e9ae05126b4f83a318a..2bbebb4335d927f240abcac67a5b423e38dc33d7 100644
|
||||
--- a/net/minecraft/world/level/Level.java
|
||||
+++ b/net/minecraft/world/level/Level.java
|
||||
@@ -2099,6 +2099,17 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
||||
|
||||
public abstract FuelValues fuelValues();
|
||||
|
||||
|
@ -2371,77 +2371,78 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ // Paper end - optimize redstone (Alternate Current)
|
||||
+
|
||||
public static enum ExplosionInteraction implements StringRepresentable {
|
||||
|
||||
NONE("none"), BLOCK("block"), MOB("mob"), TNT("tnt"), TRIGGER("trigger"), STANDARD("standard"); // CraftBukkit - Add STANDARD which will always use Explosion.Effect.DESTROY
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/RedStoneWireBlock.java b/src/main/java/net/minecraft/world/level/block/RedStoneWireBlock.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/RedStoneWireBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/RedStoneWireBlock.java
|
||||
@@ -0,0 +0,0 @@ public class RedStoneWireBlock extends Block {
|
||||
return floor.isFaceSturdy(world, pos, Direction.UP) || floor.is(Blocks.HOPPER);
|
||||
NONE("none"),
|
||||
BLOCK("block"),
|
||||
diff --git a/net/minecraft/world/level/block/RedStoneWireBlock.java b/net/minecraft/world/level/block/RedStoneWireBlock.java
|
||||
index f02232ce97779db0d12a5d5da1d767326d78ea4c..12c9d60314c99fb65e640d255a2d0c6b7790ad4d 100644
|
||||
--- a/net/minecraft/world/level/block/RedStoneWireBlock.java
|
||||
+++ b/net/minecraft/world/level/block/RedStoneWireBlock.java
|
||||
@@ -290,7 +290,7 @@ public class RedStoneWireBlock extends Block {
|
||||
return state.isFaceSturdy(level, pos, Direction.UP) || state.is(Blocks.HOPPER);
|
||||
}
|
||||
|
||||
- // Paper start - Optimize redstone
|
||||
+ // Paper start - Optimize redstone (Eigencraft)
|
||||
// The bulk of the new functionality is found in RedstoneWireTurbo.java
|
||||
com.destroystokyo.paper.util.RedstoneWireTurbo turbo = new com.destroystokyo.paper.util.RedstoneWireTurbo(this);
|
||||
io.papermc.paper.redstone.RedstoneWireTurbo turbo = new io.papermc.paper.redstone.RedstoneWireTurbo(this);
|
||||
|
||||
@@ -0,0 +0,0 @@ public class RedStoneWireBlock extends Block {
|
||||
@@ -372,7 +372,13 @@ public class RedStoneWireBlock extends Block {
|
||||
@Override
|
||||
protected void onPlace(BlockState state, Level world, BlockPos pos, BlockState oldState, boolean notify) {
|
||||
if (!oldState.is(state.getBlock()) && !world.isClientSide) {
|
||||
- this.updateSurroundingRedstone(world, pos, state, null, true); // Paper - Optimize redstone
|
||||
protected void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean isMoving) {
|
||||
if (!oldState.is(state.getBlock()) && !level.isClientSide) {
|
||||
- this.updateSurroundingRedstone(level, pos, state, null, true); // Paper - Optimize redstone
|
||||
+ // Paper start - optimize redstone - replace call to updatePowerStrength
|
||||
+ if (world.paperConfig().misc.redstoneImplementation == io.papermc.paper.configuration.WorldConfiguration.Misc.RedstoneImplementation.ALTERNATE_CURRENT) {
|
||||
+ world.getWireHandler().onWireAdded(pos, state); // Alternate Current
|
||||
+ if (level.paperConfig().misc.redstoneImplementation == io.papermc.paper.configuration.WorldConfiguration.Misc.RedstoneImplementation.ALTERNATE_CURRENT) {
|
||||
+ level.getWireHandler().onWireAdded(pos, state); // Alternate Current
|
||||
+ } else {
|
||||
+ this.updateSurroundingRedstone(world, pos, state, null, true); // Vanilla/Eigencraft
|
||||
+ this.updateSurroundingRedstone(level, pos, state, null, true); // Vanilla/Eigencraft
|
||||
+ }
|
||||
+ // Paper end
|
||||
+ // Paper end - optimize redstone
|
||||
|
||||
for (Direction direction : Direction.Plane.VERTICAL) {
|
||||
world.updateNeighborsAt(pos.relative(direction), this);
|
||||
@@ -0,0 +0,0 @@ public class RedStoneWireBlock extends Block {
|
||||
world.updateNeighborsAt(pos.relative(direction), this);
|
||||
level.updateNeighborsAt(pos.relative(direction), this);
|
||||
@@ -391,7 +397,13 @@ public class RedStoneWireBlock extends Block {
|
||||
level.updateNeighborsAt(pos.relative(direction), this);
|
||||
}
|
||||
|
||||
- this.updateSurroundingRedstone(world, pos, state, null, false); // Paper - Optimize redstone
|
||||
- this.updateSurroundingRedstone(level, pos, state, null, false); // Paper - Optimize redstone
|
||||
+ // Paper start - optimize redstone - replace call to updatePowerStrength
|
||||
+ if (world.paperConfig().misc.redstoneImplementation == io.papermc.paper.configuration.WorldConfiguration.Misc.RedstoneImplementation.ALTERNATE_CURRENT) {
|
||||
+ world.getWireHandler().onWireRemoved(pos, state); // Alternate Current
|
||||
+ if (level.paperConfig().misc.redstoneImplementation == io.papermc.paper.configuration.WorldConfiguration.Misc.RedstoneImplementation.ALTERNATE_CURRENT) {
|
||||
+ level.getWireHandler().onWireRemoved(pos, state); // Alternate Current
|
||||
+ } else {
|
||||
+ this.updateSurroundingRedstone(world, pos, state, null, false); // Vanilla/Eigencraft
|
||||
+ this.updateSurroundingRedstone(level, pos, state, null, false); // Vanilla/Eigencraft
|
||||
+ }
|
||||
this.updateNeighborsOfNeighboringWires(world, pos);
|
||||
+ // Paper end - optimize redstone
|
||||
this.updateNeighborsOfNeighboringWires(level, pos);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +0,0 @@ public class RedStoneWireBlock extends Block {
|
||||
@@ -415,9 +427,15 @@ public class RedStoneWireBlock extends Block {
|
||||
@Override
|
||||
protected void neighborChanged(BlockState state, Level world, BlockPos pos, Block sourceBlock, @Nullable Orientation wireOrientation, boolean notify) {
|
||||
if (!world.isClientSide) {
|
||||
protected void neighborChanged(BlockState state, Level level, BlockPos pos, Block neighborBlock, @Nullable Orientation orientation, boolean movedByPiston) {
|
||||
if (!level.isClientSide) {
|
||||
+ // Paper start - optimize redstone (Alternate Current)
|
||||
+ // Alternate Current handles breaking of redstone wires in the WireHandler.
|
||||
+ if (world.paperConfig().misc.redstoneImplementation == io.papermc.paper.configuration.WorldConfiguration.Misc.RedstoneImplementation.ALTERNATE_CURRENT) {
|
||||
+ world.getWireHandler().onWireUpdated(pos, state, wireOrientation);
|
||||
+ if (level.paperConfig().misc.redstoneImplementation == io.papermc.paper.configuration.WorldConfiguration.Misc.RedstoneImplementation.ALTERNATE_CURRENT) {
|
||||
+ level.getWireHandler().onWireUpdated(pos, state, orientation);
|
||||
+ } else
|
||||
+ // Paper end - optimize redstone (Alternate Current)
|
||||
if (sourceBlock != this || !useExperimentalEvaluator(world)) {
|
||||
if (state.canSurvive(world, pos)) {
|
||||
- this.updateSurroundingRedstone(world, pos, state, wireOrientation, false); // Paper - Optimize redstone
|
||||
+ this.updateSurroundingRedstone(world, pos, state, wireOrientation, false); // Paper - Optimize redstone (Eigencraft)
|
||||
+ // Paper end - optimize redstone (Alternate Current)
|
||||
if (neighborBlock != this || !useExperimentalEvaluator(level)) {
|
||||
if (state.canSurvive(level, pos)) {
|
||||
- this.updateSurroundingRedstone(level, pos, state, orientation, false); // Paper - Optimize redstone
|
||||
+ this.updateSurroundingRedstone(level, pos, state, orientation, false); // Paper - Optimize redstone (Eigencraft)
|
||||
} else {
|
||||
dropResources(state, world, pos);
|
||||
world.removeBlock(pos, false);
|
||||
diff --git a/src/main/java/net/minecraft/world/level/redstone/ExperimentalRedstoneUtils.java b/src/main/java/net/minecraft/world/level/redstone/ExperimentalRedstoneUtils.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/redstone/ExperimentalRedstoneUtils.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/redstone/ExperimentalRedstoneUtils.java
|
||||
@@ -0,0 +0,0 @@ public class ExperimentalRedstoneUtils {
|
||||
if (up != null) {
|
||||
orientation = orientation.withFront(up);
|
||||
dropResources(state, level, pos);
|
||||
level.removeBlock(pos, false);
|
||||
diff --git a/net/minecraft/world/level/redstone/ExperimentalRedstoneUtils.java b/net/minecraft/world/level/redstone/ExperimentalRedstoneUtils.java
|
||||
index 83f5da3e24834882193b9d7e3a788517e4b12b55..0c50a0bbbef1229230712b7c04364fea06859674 100644
|
||||
--- a/net/minecraft/world/level/redstone/ExperimentalRedstoneUtils.java
|
||||
+++ b/net/minecraft/world/level/redstone/ExperimentalRedstoneUtils.java
|
||||
@@ -17,6 +17,11 @@ public class ExperimentalRedstoneUtils {
|
||||
if (front != null) {
|
||||
orientation = orientation.withFront(front);
|
||||
}
|
||||
+ // Paper start - Optimize redstone (Alternate Current) - use default front instead of random
|
||||
+ else if (world.paperConfig().misc.redstoneImplementation == io.papermc.paper.configuration.WorldConfiguration.Misc.RedstoneImplementation.ALTERNATE_CURRENT) {
|
||||
+ else if (level.paperConfig().misc.redstoneImplementation == io.papermc.paper.configuration.WorldConfiguration.Misc.RedstoneImplementation.ALTERNATE_CURRENT) {
|
||||
+ orientation = orientation.withFront(Direction.WEST);
|
||||
+ }
|
||||
+ // Paper end - Optimize redstone (Alternate Current)
|
|
@ -6,15 +6,12 @@ Subject: [PATCH] Improve exact choice recipe ingredients
|
|||
Fixes exact choices not working with recipe book clicks
|
||||
and shapeless recipes.
|
||||
|
||||
== AT ==
|
||||
public net.minecraft.world.item.ItemStackLinkedSet TYPE_AND_TAG
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/inventory/recipe/ItemOrExact.java b/src/main/java/io/papermc/paper/inventory/recipe/ItemOrExact.java
|
||||
diff --git a/io/papermc/paper/inventory/recipe/ItemOrExact.java b/io/papermc/paper/inventory/recipe/ItemOrExact.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
|
||||
index 0000000000000000000000000000000000000000..ce745e49cd54fe3ae187785563a1bd311d14b5b2
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/inventory/recipe/ItemOrExact.java
|
||||
@@ -0,0 +0,0 @@
|
||||
+++ b/io/papermc/paper/inventory/recipe/ItemOrExact.java
|
||||
@@ -0,0 +1,63 @@
|
||||
+package io.papermc.paper.inventory.recipe;
|
||||
+
|
||||
+import net.minecraft.core.Holder;
|
||||
|
@ -78,12 +75,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ }
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/io/papermc/paper/inventory/recipe/StackedContentsExtrasMap.java b/src/main/java/io/papermc/paper/inventory/recipe/StackedContentsExtrasMap.java
|
||||
diff --git a/io/papermc/paper/inventory/recipe/StackedContentsExtrasMap.java b/io/papermc/paper/inventory/recipe/StackedContentsExtrasMap.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
|
||||
index 0000000000000000000000000000000000000000..f47c12e9dd6cfa857ca07a764edc22de372e25b6
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/inventory/recipe/StackedContentsExtrasMap.java
|
||||
@@ -0,0 +0,0 @@
|
||||
+++ b/io/papermc/paper/inventory/recipe/StackedContentsExtrasMap.java
|
||||
@@ -0,0 +1,68 @@
|
||||
+package io.papermc.paper.inventory.recipe;
|
||||
+
|
||||
+import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||
|
@ -152,92 +149,94 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ return false;
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/net/minecraft/recipebook/ServerPlaceRecipe.java b/src/main/java/net/minecraft/recipebook/ServerPlaceRecipe.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/recipebook/ServerPlaceRecipe.java
|
||||
+++ b/src/main/java/net/minecraft/recipebook/ServerPlaceRecipe.java
|
||||
@@ -0,0 +0,0 @@ public class ServerPlaceRecipe<R extends Recipe<?>> {
|
||||
diff --git a/net/minecraft/recipebook/ServerPlaceRecipe.java b/net/minecraft/recipebook/ServerPlaceRecipe.java
|
||||
index 6475509689439636275b06b9eac33f0922d8fcfd..6c398c91909f42e352e80d0781549df9d834a060 100644
|
||||
--- a/net/minecraft/recipebook/ServerPlaceRecipe.java
|
||||
+++ b/net/minecraft/recipebook/ServerPlaceRecipe.java
|
||||
@@ -40,6 +40,7 @@ public class ServerPlaceRecipe<R extends Recipe<?>> {
|
||||
return RecipeBookMenu.PostPlaceAction.NOTHING;
|
||||
} else {
|
||||
StackedItemContents stackedItemContents = new StackedItemContents();
|
||||
+ stackedItemContents.initializeExtras(recipe.value(), null); // Paper - Improve exact choice recipe ingredients
|
||||
inventory.fillStackedContents(stackedItemContents);
|
||||
handler.fillCraftSlotsStackedContents(stackedItemContents);
|
||||
menu.fillCraftSlotsStackedContents(stackedItemContents);
|
||||
return serverPlaceRecipe.tryPlaceRecipe(recipe, stackedItemContents);
|
||||
@@ -0,0 +0,0 @@ public class ServerPlaceRecipe<R extends Recipe<?>> {
|
||||
@@ -99,7 +100,7 @@ public class ServerPlaceRecipe<R extends Recipe<?>> {
|
||||
}
|
||||
|
||||
int j = this.calculateAmountToCraft(i, bl);
|
||||
int i = this.calculateAmountToCraft(biggestCraftableStack, flag);
|
||||
- List<Holder<Item>> list = new ArrayList<>();
|
||||
+ List<io.papermc.paper.inventory.recipe.ItemOrExact> list = new ArrayList<>(); // Paper - Improve exact choice recipe ingredients
|
||||
if (finder.canCraft(recipe.value(), j, list::add)) {
|
||||
int k = clampToMaxStackSize(j, list);
|
||||
if (k != j) {
|
||||
@@ -0,0 +0,0 @@ public class ServerPlaceRecipe<R extends Recipe<?>> {
|
||||
this.gridWidth, this.gridHeight, recipe.value(), recipe.value().placementInfo().slotsToIngredientIndex(), (slotx, index, x, y) -> {
|
||||
if (slotx != -1) {
|
||||
Slot slot2 = this.inputGridSlots.get(index);
|
||||
- Holder<Item> holder = list.get(slotx);
|
||||
+ io.papermc.paper.inventory.recipe.ItemOrExact holder = list.get(slotx); // Paper - Improve exact choice recipe ingredients
|
||||
int jx = k;
|
||||
if (stackedItemContents.canCraft(recipe.value(), i, list::add)) {
|
||||
int i1 = clampToMaxStackSize(i, list);
|
||||
if (i1 != i) {
|
||||
@@ -114,7 +115,7 @@ public class ServerPlaceRecipe<R extends Recipe<?>> {
|
||||
this.gridWidth, this.gridHeight, recipe.value(), recipe.value().placementInfo().slotsToIngredientIndex(), (item1, slot1, x, y) -> {
|
||||
if (item1 != -1) {
|
||||
Slot slot2 = this.inputGridSlots.get(slot1);
|
||||
- Holder<Item> holder = list.get(item1);
|
||||
+ io.papermc.paper.inventory.recipe.ItemOrExact holder = list.get(item1); // Paper - Improve exact choice recipe ingredients
|
||||
int i2 = i1;
|
||||
|
||||
while (jx > 0) {
|
||||
@@ -0,0 +0,0 @@ public class ServerPlaceRecipe<R extends Recipe<?>> {
|
||||
while (i2 > 0) {
|
||||
@@ -129,9 +130,11 @@ public class ServerPlaceRecipe<R extends Recipe<?>> {
|
||||
}
|
||||
}
|
||||
|
||||
- private static int clampToMaxStackSize(int count, List<Holder<Item>> entries) {
|
||||
- for (Holder<Item> holder : entries) {
|
||||
- count = Math.min(count, holder.value().getDefaultMaxStackSize());
|
||||
- private static int clampToMaxStackSize(int amount, List<Holder<Item>> items) {
|
||||
- for (Holder<Item> holder : items) {
|
||||
- amount = Math.min(amount, holder.value().getDefaultMaxStackSize());
|
||||
+ // Paper start - Improve exact choice recipe ingredients
|
||||
+ private static int clampToMaxStackSize(int count, List<io.papermc.paper.inventory.recipe.ItemOrExact> entries) {
|
||||
+ for (io.papermc.paper.inventory.recipe.ItemOrExact holder : entries) {
|
||||
+ count = Math.min(count, holder.getMaxStackSize());
|
||||
+ private static int clampToMaxStackSize(int amount, List<io.papermc.paper.inventory.recipe.ItemOrExact> items) {
|
||||
+ for (io.papermc.paper.inventory.recipe.ItemOrExact holder : items) {
|
||||
+ amount = Math.min(amount, holder.getMaxStackSize());
|
||||
+ // Paper end - Improve exact choice recipe ingredients
|
||||
}
|
||||
|
||||
return count;
|
||||
@@ -0,0 +0,0 @@ public class ServerPlaceRecipe<R extends Recipe<?>> {
|
||||
return amount;
|
||||
@@ -160,7 +163,7 @@ public class ServerPlaceRecipe<R extends Recipe<?>> {
|
||||
}
|
||||
}
|
||||
|
||||
- private int moveItemToGrid(Slot slot, Holder<Item> item, int count) {
|
||||
+ private int moveItemToGrid(Slot slot, io.papermc.paper.inventory.recipe.ItemOrExact item, int count) { // Paper - Improve exact choice recipe ingredients
|
||||
ItemStack itemStack = slot.getItem();
|
||||
int i = this.inventory.findSlotMatchingCraftingIngredient(item, itemStack);
|
||||
ItemStack item1 = slot.getItem();
|
||||
int i = this.inventory.findSlotMatchingCraftingIngredient(item, item1);
|
||||
if (i == -1) {
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/player/Inventory.java b/src/main/java/net/minecraft/world/entity/player/Inventory.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/player/Inventory.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/player/Inventory.java
|
||||
@@ -0,0 +0,0 @@ public class Inventory implements Container, Nameable {
|
||||
diff --git a/net/minecraft/world/entity/player/Inventory.java b/net/minecraft/world/entity/player/Inventory.java
|
||||
index 8a29d771046667db22fba166fa5337de1896cd0d..839cbb67d3d38960d9114a4db5bab911b66a573c 100644
|
||||
--- a/net/minecraft/world/entity/player/Inventory.java
|
||||
+++ b/net/minecraft/world/entity/player/Inventory.java
|
||||
@@ -185,12 +185,12 @@ public class Inventory implements Container, Nameable {
|
||||
return !stack.isDamaged() && !stack.isEnchanted() && !stack.has(DataComponents.CUSTOM_NAME);
|
||||
}
|
||||
|
||||
- public int findSlotMatchingCraftingIngredient(Holder<Item> item, ItemStack stack) {
|
||||
+ public int findSlotMatchingCraftingIngredient(io.papermc.paper.inventory.recipe.ItemOrExact item, ItemStack stack) { // Paper - Improve exact choice recipe ingredients
|
||||
for (int i = 0; i < this.items.size(); ++i) {
|
||||
ItemStack itemstack1 = (ItemStack) this.items.get(i);
|
||||
|
||||
- if (!itemstack1.isEmpty() && itemstack1.is(item) && Inventory.isUsableForCrafting(itemstack1) && (stack.isEmpty() || ItemStack.isSameItemSameComponents(stack, itemstack1))) {
|
||||
+ if (!itemstack1.isEmpty() && item.matches(itemstack1) && (!(item instanceof io.papermc.paper.inventory.recipe.ItemOrExact.Item) || Inventory.isUsableForCrafting(itemstack1)) && (stack.isEmpty() || ItemStack.isSameItemSameComponents(stack, itemstack1))) { // Paper - Improve exact choice recipe ingredients
|
||||
for (int i = 0; i < this.items.size(); i++) {
|
||||
ItemStack itemStack = this.items.get(i);
|
||||
if (!itemStack.isEmpty()
|
||||
- && itemStack.is(item)
|
||||
- && isUsableForCrafting(itemStack)
|
||||
+ && item.matches(itemStack) // Paper - Improve exact choice recipe ingredients
|
||||
+ && (!(item instanceof io.papermc.paper.inventory.recipe.ItemOrExact.Item) || Inventory.isUsableForCrafting(itemStack)) // Paper - Improve exact choice recipe ingredients
|
||||
&& (stack.isEmpty() || ItemStack.isSameItemSameComponents(stack, itemStack))) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/player/StackedContents.java b/src/main/java/net/minecraft/world/entity/player/StackedContents.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/player/StackedContents.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/player/StackedContents.java
|
||||
@@ -0,0 +0,0 @@ import java.util.List;
|
||||
diff --git a/net/minecraft/world/entity/player/StackedContents.java b/net/minecraft/world/entity/player/StackedContents.java
|
||||
index a4b528574ab371af94b0e07819e471cec94da244..a3fea6c8397046596afe3c8b5589f2ed37fcdfc3 100644
|
||||
--- a/net/minecraft/world/entity/player/StackedContents.java
|
||||
+++ b/net/minecraft/world/entity/player/StackedContents.java
|
||||
@@ -13,7 +13,7 @@ import java.util.List;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class StackedContents<T> {
|
||||
- public final Reference2IntOpenHashMap<T> amounts = new Reference2IntOpenHashMap<>();
|
||||
+ public final it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap<T> amounts = new it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap<>(); // Paper - Improve exact choice recipe ingredients (don't use "reference" map)
|
||||
|
||||
boolean hasAtLeast(T input, int minimum) {
|
||||
return this.amounts.getInt(input) >= minimum;
|
||||
@@ -0,0 +0,0 @@ public class StackedContents<T> {
|
||||
boolean hasAtLeast(T item, int amount) {
|
||||
return this.amounts.getInt(item) >= amount;
|
||||
@@ -49,7 +49,7 @@ public class StackedContents<T> {
|
||||
List<T> getUniqueAvailableIngredientItems(Iterable<? extends StackedContents.IngredientInfo<T>> ingredients) {
|
||||
List<T> list = new ArrayList<>();
|
||||
|
||||
|
@ -246,7 +245,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
if (entry.getIntValue() > 0 && anyIngredientMatches(ingredients, entry.getKey())) {
|
||||
list.add(entry.getKey());
|
||||
}
|
||||
@@ -0,0 +0,0 @@ public class StackedContents<T> {
|
||||
@@ -71,13 +71,13 @@ public class StackedContents<T> {
|
||||
@VisibleForTesting
|
||||
public int getResultUpperBound(List<? extends StackedContents.IngredientInfo<T>> ingredients) {
|
||||
int i = Integer.MAX_VALUE;
|
||||
|
@ -255,18 +254,18 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
|
||||
label31:
|
||||
for (StackedContents.IngredientInfo<T> ingredientInfo : ingredients) {
|
||||
int j = 0;
|
||||
int i1 = 0;
|
||||
|
||||
- for (Entry<T> entry : objectIterable) {
|
||||
+ for (it.unimi.dsi.fastutil.objects.Object2IntMap.Entry<T> entry : objectIterable) { // Paper - Improve exact choice recipe ingredients (don't use "reference" map)
|
||||
int k = entry.getIntValue();
|
||||
if (k > j) {
|
||||
int intValue = entry.getIntValue();
|
||||
if (intValue > i1) {
|
||||
if (ingredientInfo.acceptsItem(entry.getKey())) {
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/player/StackedItemContents.java b/src/main/java/net/minecraft/world/entity/player/StackedItemContents.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/player/StackedItemContents.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/player/StackedItemContents.java
|
||||
@@ -0,0 +0,0 @@ import net.minecraft.world.item.crafting.PlacementInfo;
|
||||
diff --git a/net/minecraft/world/entity/player/StackedItemContents.java b/net/minecraft/world/entity/player/StackedItemContents.java
|
||||
index 6bbe2e51ef71d193e0a5d3cace2b0ad1760ce759..83ccde54c625d40dc595e000c533f60aa929bd5a 100644
|
||||
--- a/net/minecraft/world/entity/player/StackedItemContents.java
|
||||
+++ b/net/minecraft/world/entity/player/StackedItemContents.java
|
||||
@@ -9,9 +9,14 @@ import net.minecraft.world.item.crafting.PlacementInfo;
|
||||
import net.minecraft.world.item.crafting.Recipe;
|
||||
|
||||
public class StackedItemContents {
|
||||
|
@ -274,25 +273,30 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ // Paper start - Improve exact choice recipe ingredients
|
||||
+ private final StackedContents<io.papermc.paper.inventory.recipe.ItemOrExact> raw = new StackedContents<>();
|
||||
+ @Nullable
|
||||
+ private io.papermc.paper.inventory.recipe.StackedContentsExtrasMap extrasMap = null;
|
||||
+ private io.papermc.paper.inventory.recipe.StackedContentsExtrasMap extrasMap;
|
||||
+ // Paper start - Improve exact choice recipe ingredients
|
||||
|
||||
public void accountSimpleStack(ItemStack item) {
|
||||
+ if (this.extrasMap != null && this.extrasMap.accountStack(item, Math.min(64, item.getCount()))) return; // Paper - Improve exact choice recipe ingredients; max of 64 due to accountStack method below
|
||||
if (Inventory.isUsableForCrafting(item)) {
|
||||
this.accountStack(item);
|
||||
public void accountSimpleStack(ItemStack stack) {
|
||||
+ if (this.extrasMap != null && this.extrasMap.accountStack(stack, Math.min(64, stack.getCount()))) return; // Paper - Improve exact choice recipe ingredients; max of 64 due to accountStack method below
|
||||
if (Inventory.isUsableForCrafting(stack)) {
|
||||
this.accountStack(stack);
|
||||
}
|
||||
@@ -0,0 +0,0 @@ public class StackedItemContents {
|
||||
public void accountStack(ItemStack item, int maxCount) {
|
||||
if (!item.isEmpty()) {
|
||||
int i = Math.min(maxCount, item.getCount());
|
||||
- this.raw.account(item.getItemHolder(), i);
|
||||
+ if (this.extrasMap != null && !item.getComponentsPatch().isEmpty() && this.extrasMap.accountStack(item, i)) return; // Paper - Improve exact choice recipe ingredients; if an exact ingredient, don't include it
|
||||
+ this.raw.account(new io.papermc.paper.inventory.recipe.ItemOrExact.Item(item.getItemHolder()), i);
|
||||
@@ -24,34 +29,51 @@ public class StackedItemContents {
|
||||
public void accountStack(ItemStack stack, int maxStackSize) {
|
||||
if (!stack.isEmpty()) {
|
||||
int min = Math.min(maxStackSize, stack.getCount());
|
||||
- this.raw.account(stack.getItemHolder(), min);
|
||||
+ if (this.extrasMap != null && !stack.getComponentsPatch().isEmpty() && this.extrasMap.accountStack(stack, min)) return; // Paper - Improve exact choice recipe ingredients; if an exact ingredient, don't include it
|
||||
+ this.raw.account(new io.papermc.paper.inventory.recipe.ItemOrExact.Item(stack.getItemHolder()), min);
|
||||
}
|
||||
}
|
||||
|
||||
- public boolean canCraft(Recipe<?> recipe, @Nullable StackedContents.Output<Holder<Item>> itemCallback) {
|
||||
- public boolean canCraft(Recipe<?> recipe, @Nullable StackedContents.Output<Holder<Item>> output) {
|
||||
+ public boolean canCraft(Recipe<?> recipe, @Nullable StackedContents.Output<io.papermc.paper.inventory.recipe.ItemOrExact> output) { // Paper - Improve exact choice recipe ingredients
|
||||
return this.canCraft(recipe, 1, output);
|
||||
}
|
||||
|
||||
- public boolean canCraft(Recipe<?> recipe, int maxCount, @Nullable StackedContents.Output<Holder<Item>> output) {
|
||||
+ // Paper start - Improve exact choice recipe ingredients
|
||||
+ public void initializeExtras(final Recipe<?> recipe, @Nullable final net.minecraft.world.item.crafting.CraftingInput input) {
|
||||
+ if (this.extrasMap == null) {
|
||||
|
@ -309,70 +313,64 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ }
|
||||
+ // Paper end - Improve exact choice recipe ingredients
|
||||
+
|
||||
+ public boolean canCraft(Recipe<?> recipe, @Nullable StackedContents.Output<io.papermc.paper.inventory.recipe.ItemOrExact> itemCallback) { // Paper - Improve exact choice recipe ingredients
|
||||
return this.canCraft(recipe, 1, itemCallback);
|
||||
}
|
||||
|
||||
- public boolean canCraft(Recipe<?> recipe, int quantity, @Nullable StackedContents.Output<Holder<Item>> itemCallback) {
|
||||
+ public boolean canCraft(Recipe<?> recipe, int quantity, @Nullable StackedContents.Output<io.papermc.paper.inventory.recipe.ItemOrExact> itemCallback) { // Paper - Improve exact choice recipe ingredients
|
||||
+ public boolean canCraft(Recipe<?> recipe, int maxCount, @Nullable StackedContents.Output<io.papermc.paper.inventory.recipe.ItemOrExact> output) { // Paper - Improve exact choice recipe ingredients
|
||||
PlacementInfo placementInfo = recipe.placementInfo();
|
||||
return !placementInfo.isImpossibleToPlace() && this.canCraft(placementInfo.ingredients(), quantity, itemCallback);
|
||||
return !placementInfo.isImpossibleToPlace() && this.canCraft(placementInfo.ingredients(), maxCount, output);
|
||||
}
|
||||
|
||||
public boolean canCraft(
|
||||
- List<? extends StackedContents.IngredientInfo<Holder<Item>>> rawIngredients, @Nullable StackedContents.Output<Holder<Item>> itemCallback
|
||||
+ List<? extends StackedContents.IngredientInfo<io.papermc.paper.inventory.recipe.ItemOrExact>> rawIngredients, @Nullable StackedContents.Output<io.papermc.paper.inventory.recipe.ItemOrExact> itemCallback // Paper - Improve exact choice recipe ingredients
|
||||
) {
|
||||
return this.canCraft(rawIngredients, 1, itemCallback);
|
||||
- public boolean canCraft(List<? extends StackedContents.IngredientInfo<Holder<Item>>> ingredients, @Nullable StackedContents.Output<Holder<Item>> output) {
|
||||
+ public boolean canCraft(List<? extends StackedContents.IngredientInfo<io.papermc.paper.inventory.recipe.ItemOrExact>> ingredients, @Nullable StackedContents.Output<io.papermc.paper.inventory.recipe.ItemOrExact> output) { // Paper - Improve exact choice recipe ingredients
|
||||
return this.canCraft(ingredients, 1, output);
|
||||
}
|
||||
|
||||
private boolean canCraft(
|
||||
- List<? extends StackedContents.IngredientInfo<Holder<Item>>> rawIngredients, int quantity, @Nullable StackedContents.Output<Holder<Item>> itemCallback
|
||||
+ List<? extends StackedContents.IngredientInfo<io.papermc.paper.inventory.recipe.ItemOrExact>> rawIngredients, int quantity, @Nullable StackedContents.Output<io.papermc.paper.inventory.recipe.ItemOrExact> itemCallback // Paper - Improve exact choice recipe ingredients
|
||||
- List<? extends StackedContents.IngredientInfo<Holder<Item>>> ingredients, int maxCount, @Nullable StackedContents.Output<Holder<Item>> output
|
||||
+ List<? extends StackedContents.IngredientInfo<io.papermc.paper.inventory.recipe.ItemOrExact>> ingredients, int maxCount, @Nullable StackedContents.Output<io.papermc.paper.inventory.recipe.ItemOrExact> output // Paper - Improve exact choice recipe ingredients
|
||||
) {
|
||||
return this.raw.tryPick(rawIngredients, quantity, itemCallback);
|
||||
return this.raw.tryPick(ingredients, maxCount, output);
|
||||
}
|
||||
|
||||
- public int getBiggestCraftableStack(Recipe<?> recipe, @Nullable StackedContents.Output<Holder<Item>> itemCallback) {
|
||||
+ public int getBiggestCraftableStack(Recipe<?> recipe, @Nullable StackedContents.Output<io.papermc.paper.inventory.recipe.ItemOrExact> itemCallback) { // Paper - Improve exact choice recipe ingredients
|
||||
return this.getBiggestCraftableStack(recipe, Integer.MAX_VALUE, itemCallback);
|
||||
- public int getBiggestCraftableStack(Recipe<?> recipe, @Nullable StackedContents.Output<Holder<Item>> output) {
|
||||
+ public int getBiggestCraftableStack(Recipe<?> recipe, @Nullable StackedContents.Output<io.papermc.paper.inventory.recipe.ItemOrExact> output) { // Paper - Improve exact choice recipe ingredients
|
||||
return this.getBiggestCraftableStack(recipe, Integer.MAX_VALUE, output);
|
||||
}
|
||||
|
||||
- public int getBiggestCraftableStack(Recipe<?> recipe, int max, @Nullable StackedContents.Output<Holder<Item>> itemCallback) {
|
||||
+ public int getBiggestCraftableStack(Recipe<?> recipe, int max, @Nullable StackedContents.Output<io.papermc.paper.inventory.recipe.ItemOrExact> itemCallback) { // Paper - Improve exact choice recipe ingredients
|
||||
return this.raw.tryPickAll(recipe.placementInfo().ingredients(), max, itemCallback);
|
||||
- public int getBiggestCraftableStack(Recipe<?> recipe, int maxCount, @Nullable StackedContents.Output<Holder<Item>> output) {
|
||||
+ public int getBiggestCraftableStack(Recipe<?> recipe, int maxCount, @Nullable StackedContents.Output<io.papermc.paper.inventory.recipe.ItemOrExact> output) { // Paper - Improve exact choice recipe ingredients
|
||||
return this.raw.tryPickAll(recipe.placementInfo().ingredients(), maxCount, output);
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/item/crafting/Ingredient.java b/src/main/java/net/minecraft/world/item/crafting/Ingredient.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/item/crafting/Ingredient.java
|
||||
+++ b/src/main/java/net/minecraft/world/item/crafting/Ingredient.java
|
||||
@@ -0,0 +0,0 @@ import java.util.List;
|
||||
import javax.annotation.Nullable;
|
||||
// CraftBukkit end
|
||||
diff --git a/net/minecraft/world/item/crafting/Ingredient.java b/net/minecraft/world/item/crafting/Ingredient.java
|
||||
index e43641650d66a62b5b7b58c43833ce504970ab1e..879c8fe1f20decc793cfa39e686b61d521bd76ba 100644
|
||||
--- a/net/minecraft/world/item/crafting/Ingredient.java
|
||||
+++ b/net/minecraft/world/item/crafting/Ingredient.java
|
||||
@@ -21,7 +21,7 @@ import net.minecraft.world.item.Items;
|
||||
import net.minecraft.world.item.crafting.display.SlotDisplay;
|
||||
import net.minecraft.world.level.ItemLike;
|
||||
|
||||
-public final class Ingredient implements StackedContents.IngredientInfo<Holder<Item>>, Predicate<ItemStack> {
|
||||
+public final class Ingredient implements StackedContents.IngredientInfo<io.papermc.paper.inventory.recipe.ItemOrExact>, Predicate<ItemStack> { // Paper - Improve exact choice recipe ingredients
|
||||
|
||||
public static final StreamCodec<RegistryFriendlyByteBuf, Ingredient> CONTENTS_STREAM_CODEC = ByteBufCodecs.holderSet(Registries.ITEM).map(Ingredient::new, (recipeitemstack) -> {
|
||||
return recipeitemstack.values;
|
||||
@@ -0,0 +0,0 @@ public final class Ingredient implements StackedContents.IngredientInfo<Holder<I
|
||||
public static final StreamCodec<RegistryFriendlyByteBuf, Ingredient> CONTENTS_STREAM_CODEC = ByteBufCodecs.holderSet(Registries.ITEM)
|
||||
.map(Ingredient::new, ingredient -> ingredient.values);
|
||||
public static final StreamCodec<RegistryFriendlyByteBuf, Optional<Ingredient>> OPTIONAL_CONTENTS_STREAM_CODEC = ByteBufCodecs.holderSet(Registries.ITEM)
|
||||
@@ -35,20 +35,24 @@ public final class Ingredient implements StackedContents.IngredientInfo<Holder<I
|
||||
private final HolderSet<Item> values;
|
||||
// CraftBukkit start
|
||||
@Nullable
|
||||
- private List<ItemStack> itemStacks;
|
||||
@javax.annotation.Nullable
|
||||
- private java.util.List<ItemStack> itemStacks;
|
||||
+ private java.util.Set<ItemStack> itemStacks; // Paper - Improve exact choice recipe ingredients
|
||||
|
||||
public boolean isExact() {
|
||||
return this.itemStacks != null;
|
||||
}
|
||||
|
||||
- public List<ItemStack> itemStacks() {
|
||||
@javax.annotation.Nullable
|
||||
- public java.util.List<ItemStack> itemStacks() {
|
||||
+ public java.util.Set<ItemStack> itemStacks() { // Paper - Improve exact choice recipe ingredients
|
||||
return this.itemStacks;
|
||||
}
|
||||
|
||||
public static Ingredient ofStacks(List<ItemStack> stacks) {
|
||||
public static Ingredient ofStacks(java.util.List<ItemStack> stacks) {
|
||||
Ingredient recipe = Ingredient.of(stacks.stream().map(ItemStack::getItem));
|
||||
- recipe.itemStacks = stacks;
|
||||
+ // Paper start - Improve exact choice recipe ingredients
|
||||
|
@ -383,29 +381,29 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
return recipe;
|
||||
}
|
||||
// CraftBukkit end
|
||||
@@ -0,0 +0,0 @@ public final class Ingredient implements StackedContents.IngredientInfo<Holder<I
|
||||
public boolean test(ItemStack itemstack) {
|
||||
@@ -81,21 +85,22 @@ public final class Ingredient implements StackedContents.IngredientInfo<Holder<I
|
||||
public boolean test(ItemStack stack) {
|
||||
// CraftBukkit start
|
||||
if (this.isExact()) {
|
||||
- for (ItemStack itemstack1 : this.itemStacks()) {
|
||||
- if (itemstack1.getItem() == itemstack.getItem() && ItemStack.isSameItemSameComponents(itemstack, itemstack1)) {
|
||||
- if (itemstack1.getItem() == stack.getItem() && ItemStack.isSameItemSameComponents(stack, itemstack1)) {
|
||||
- return true;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- return false;
|
||||
+ return this.itemStacks.contains(itemstack); // Paper - Improve exact choice recipe ingredients (hashing FTW!)
|
||||
+ return this.itemStacks.contains(stack); // Paper - Improve exact choice recipe ingredients (hashing FTW!)
|
||||
}
|
||||
// CraftBukkit end
|
||||
return itemstack.is(this.values);
|
||||
return stack.is(this.values);
|
||||
}
|
||||
|
||||
- public boolean acceptsItem(Holder<Item> holder) {
|
||||
- return this.values.contains(holder);
|
||||
+ // Paper start - Improve exact choice recipe ingredients
|
||||
+ @Override
|
||||
+ public boolean acceptsItem(final io.papermc.paper.inventory.recipe.ItemOrExact holder) {
|
||||
+ return switch (holder) {
|
||||
@Override
|
||||
- public boolean acceptsItem(Holder<Item> item) {
|
||||
- return this.values.contains(item);
|
||||
+ public boolean acceptsItem(final io.papermc.paper.inventory.recipe.ItemOrExact itemOrExact) {
|
||||
+ return switch (itemOrExact) {
|
||||
+ case io.papermc.paper.inventory.recipe.ItemOrExact.Item(final Holder<Item> item) ->
|
||||
+ !this.isExact() && this.values.contains(item);
|
||||
+ case io.papermc.paper.inventory.recipe.ItemOrExact.Exact(final ItemStack exact) ->
|
||||
|
@ -414,8 +412,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ // Paper end - Improve exact choice recipe ingredients
|
||||
}
|
||||
|
||||
public boolean equals(Object object) {
|
||||
@@ -0,0 +0,0 @@ public final class Ingredient implements StackedContents.IngredientInfo<Holder<I
|
||||
@Override
|
||||
@@ -120,6 +125,11 @@ public final class Ingredient implements StackedContents.IngredientInfo<Holder<I
|
||||
}
|
||||
|
||||
public SlotDisplay display() {
|
||||
|
@ -424,22 +422,25 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ return new SlotDisplay.Composite(this.itemStacks().stream().<SlotDisplay>map(SlotDisplay.ItemStackSlotDisplay::new).toList());
|
||||
+ }
|
||||
+ // Paper end - show exact ingredients in recipe book
|
||||
return (SlotDisplay) this.values.unwrap().map(SlotDisplay.TagSlotDisplay::new, (list) -> {
|
||||
return new SlotDisplay.Composite(list.stream().map(Ingredient::displayForSingleItem).toList());
|
||||
});
|
||||
diff --git a/src/main/java/net/minecraft/world/item/crafting/ShapelessRecipe.java b/src/main/java/net/minecraft/world/item/crafting/ShapelessRecipe.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/item/crafting/ShapelessRecipe.java
|
||||
+++ b/src/main/java/net/minecraft/world/item/crafting/ShapelessRecipe.java
|
||||
@@ -0,0 +0,0 @@ public class ShapelessRecipe implements CraftingRecipe {
|
||||
}
|
||||
return (SlotDisplay)this.values
|
||||
.unwrap()
|
||||
.map(SlotDisplay.TagSlotDisplay::new, list -> new SlotDisplay.Composite(list.stream().map(Ingredient::displayForSingleItem).toList()));
|
||||
diff --git a/net/minecraft/world/item/crafting/ShapelessRecipe.java b/net/minecraft/world/item/crafting/ShapelessRecipe.java
|
||||
index fb317eafeed39adff793bffa8f6b21c37a32086c..d601b54b1de2f2ae44fe2b20c8116c71a6340e45 100644
|
||||
--- a/net/minecraft/world/item/crafting/ShapelessRecipe.java
|
||||
+++ b/net/minecraft/world/item/crafting/ShapelessRecipe.java
|
||||
@@ -72,13 +72,18 @@ public class ShapelessRecipe implements CraftingRecipe {
|
||||
|
||||
public boolean matches(CraftingInput input, Level world) {
|
||||
- return input.ingredientCount() != this.ingredients.size() ? false : (input.size() == 1 && this.ingredients.size() == 1 ? ((Ingredient) this.ingredients.getFirst()).test(input.getItem(0)) : input.stackedContents().canCraft((Recipe) this, (StackedContents.Output) null));
|
||||
@Override
|
||||
public boolean matches(CraftingInput input, Level level) {
|
||||
+ // Paper start - Improve exact choice recipe ingredients & unwrap ternary
|
||||
+ if (input.ingredientCount() != this.ingredients.size()) {
|
||||
+ return false;
|
||||
+ }
|
||||
if (input.ingredientCount() != this.ingredients.size()) {
|
||||
return false;
|
||||
- } else {
|
||||
- return input.size() == 1 && this.ingredients.size() == 1
|
||||
- ? this.ingredients.getFirst().test(input.getItem(0))
|
||||
- : input.stackedContents().canCraft(this, null);
|
||||
}
|
||||
+ if (input.size() == 1 && this.ingredients.size() == 1) {
|
||||
+ return this.ingredients.getFirst().test(input.getItem(0));
|
||||
+ }
|
||||
|
@ -450,4 +451,4 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ // Paper end - Improve exact choice recipe ingredients & unwrap ternary
|
||||
}
|
||||
|
||||
public ItemStack assemble(CraftingInput input, HolderLookup.Provider registries) {
|
||||
@Override
|
|
@ -7,22 +7,22 @@ Subject: [PATCH] Only write chunk data to disk if it serializes without
|
|||
This ensures at least a valid version of the chunk exists
|
||||
on disk, even if outdated
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||
@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
||||
diff --git a/net/minecraft/world/level/chunk/storage/RegionFile.java b/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||
index 7da388ffab162c282cad0f297bb7304f3c2abbaf..ff4fc280409f680f3879a495e37cf1925b1a38f1 100644
|
||||
--- a/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||
+++ b/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||
@@ -24,6 +24,7 @@ import org.slf4j.Logger;
|
||||
|
||||
}
|
||||
// Paper end
|
||||
public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patches.chunk_system.storage.ChunkSystemRegionFile { // Paper - rewrite chunk system
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
+ public static final int MAX_CHUNK_SIZE = 500 * 1024 * 1024; // Paper - don't write garbage data to disk if writing serialization fails
|
||||
private class ChunkBuffer extends ByteArrayOutputStream implements ca.spottedleaf.moonrise.patches.chunk_system.storage.ChunkSystemChunkBuffer { // Paper - rewrite chunk system
|
||||
|
||||
private final ChunkPos pos;
|
||||
@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
||||
super.write(RegionFile.this.version.getId());
|
||||
this.pos = chunkcoordintpair;
|
||||
private static final int SECTOR_BYTES = 4096;
|
||||
@VisibleForTesting
|
||||
protected static final int SECTOR_INTS = 1024;
|
||||
@@ -455,6 +456,24 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
||||
this.pos = pos;
|
||||
}
|
||||
|
||||
+ // Paper start - don't write garbage data to disk if writing serialization fails
|
||||
+ @Override
|
||||
+ public void write(final int b) {
|
||||
|
@ -40,23 +40,23 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ super.write(b, off, len);
|
||||
+ }
|
||||
+ // Paper end - don't write garbage data to disk if writing serialization fails
|
||||
|
||||
+
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
ByteBuffer bytebuffer = ByteBuffer.wrap(this.buf, 0, this.count);
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||
@@ -0,0 +0,0 @@ import net.minecraft.world.level.ChunkPos;
|
||||
ByteBuffer byteBuffer = ByteBuffer.wrap(this.buf, 0, this.count);
|
||||
diff --git a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||
index e35bb5534e2fbd2e30154a15ff6d39baa121608f..d263f78fa610ce6f6fb5a0f5e064e3d8335c2199 100644
|
||||
--- a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||
+++ b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||
@@ -15,6 +15,7 @@ import net.minecraft.util.ExceptionCollector;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
|
||||
public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise.patches.chunk_system.io.ChunkSystemRegionFileStorage { // Paper - rewrite chunk system
|
||||
|
||||
+ private static final org.slf4j.Logger LOGGER = com.mojang.logging.LogUtils.getLogger(); // Paper
|
||||
+
|
||||
public static final String ANVIL_EXTENSION = ".mca";
|
||||
private static final int MAX_CACHE_SIZE = 256;
|
||||
public final Long2ObjectLinkedOpenHashMap<RegionFile> regionCache = new Long2ObjectLinkedOpenHashMap();
|
||||
@@ -0,0 +0,0 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
public final Long2ObjectLinkedOpenHashMap<RegionFile> regionCache = new Long2ObjectLinkedOpenHashMap<>();
|
||||
@@ -119,11 +120,24 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
// (and, the regionfile parameter is unused for writing until the write call)
|
||||
final ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionDataController.WriteData writeData = ((ca.spottedleaf.moonrise.patches.chunk_system.storage.ChunkSystemRegionFile)regionFile).moonrise$startWrite(compound, pos);
|
||||
|
||||
|
@ -81,39 +81,26 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
|
||||
return writeData;
|
||||
}
|
||||
@@ -0,0 +0,0 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
try {
|
||||
NbtIo.write(nbt, (DataOutput) dataoutputstream);
|
||||
regionfile.setOversized(pos.x, pos.z, false); // Paper - We don't do this anymore, mojang stores differently, but clear old meta flag if it exists to get rid of our own meta file once last oversized is gone
|
||||
@@ -326,9 +340,17 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
if (chunkData == null) {
|
||||
regionFile.clear(chunkPos);
|
||||
} else {
|
||||
- try (DataOutputStream chunkDataOutputStream = regionFile.getChunkDataOutputStream(chunkPos)) {
|
||||
+ DataOutputStream chunkDataOutputStream = regionFile.getChunkDataOutputStream(chunkPos); // Paper - Only write if successful
|
||||
+ try { // Paper - Only write if successful
|
||||
NbtIo.write(chunkData, chunkDataOutputStream);
|
||||
regionFile.setOversized(chunkPos.x, chunkPos.z, false); // Paper - We don't do this anymore, mojang stores differently, but clear old meta flag if it exists to get rid of our own meta file once last oversized is gone
|
||||
+ // Paper start - don't write garbage data to disk if writing serialization fails
|
||||
+ dataoutputstream.close(); // Only write if successful
|
||||
+ chunkDataOutputStream.close();
|
||||
+ } catch (final RegionFileSizeException ex) {
|
||||
+ regionfile.clear(pos);
|
||||
+ regionFile.clear(chunkPos);
|
||||
+ final int maxSize = RegionFile.MAX_CHUNK_SIZE / (1024 * 1024);
|
||||
+ LOGGER.error("Chunk at (" + pos.x + "," + pos.z + ") in regionfile '" + regionfile.getPath().toString() + "' exceeds max size of " + maxSize + "MiB, it has been deleted from disk.");
|
||||
+ return;
|
||||
+ LOGGER.error("Chunk at (" + chunkPos.x + "," + chunkPos.z + ") in regionfile '" + regionFile.getPath().toString() + "' exceeds max size of " + maxSize + "MiB, it has been deleted from disk.");
|
||||
+ // Paper end - don't write garbage data to disk if writing serialization fails
|
||||
} catch (Throwable throwable) {
|
||||
if (dataoutputstream != null) {
|
||||
try {
|
||||
- dataoutputstream.close();
|
||||
+ //dataoutputstream.close(); // Paper - don't write garbage data to disk if writing serialization fails
|
||||
} catch (Throwable throwable1) {
|
||||
throwable.addSuppressed(throwable1);
|
||||
}
|
||||
@@ -0,0 +0,0 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
|
||||
throw throwable;
|
||||
}
|
||||
-
|
||||
- if (dataoutputstream != null) {
|
||||
- dataoutputstream.close();
|
||||
- }
|
||||
+ // Paper - don't write garbage data to disk if writing serialization fails; move into try block to only write if successfully serialized
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +0,0 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
@@ -370,4 +392,13 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
public RegionStorageInfo info() {
|
||||
return this.info;
|
||||
}
|
||||
|
@ -121,7 +108,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ // Paper start - don't write garbage data to disk if writing serialization fails
|
||||
+ public static final class RegionFileSizeException extends RuntimeException {
|
||||
+
|
||||
+ public RegionFileSizeException(String message) {
|
||||
+ public RegionFileSizeException(final String message) {
|
||||
+ super(message);
|
||||
+ }
|
||||
+ }
|
|
@ -8,11 +8,11 @@ to a chunk. The default values of -1 disable the limit. Although
|
|||
defaults are only included for certain entites, this allows setting
|
||||
limits for any entity type.
|
||||
|
||||
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java
|
||||
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java
|
||||
@@ -0,0 +0,0 @@ public final class ChunkEntitySlices {
|
||||
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java b/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java
|
||||
index 7aea4e343581b977d11af90f9f65eac3532eade1..d21ce54ebb5724c04eadf56a2cde701d5eeb5db2 100644
|
||||
--- a/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java
|
||||
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java
|
||||
@@ -104,7 +104,18 @@ public final class ChunkEntitySlices {
|
||||
}
|
||||
|
||||
final ListTag entitiesTag = new ListTag();
|
||||
|
@ -31,21 +31,21 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
CompoundTag compoundTag = new CompoundTag();
|
||||
if (entity.save(compoundTag)) {
|
||||
entitiesTag.add(compoundTag);
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/EntityType.java b/src/main/java/net/minecraft/world/entity/EntityType.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/EntityType.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/EntityType.java
|
||||
@@ -0,0 +0,0 @@ public class EntityType<T extends Entity> implements FeatureElement, EntityTypeT
|
||||
final Spliterator<? extends Tag> spliterator = entityNbtList.spliterator();
|
||||
|
||||
diff --git a/net/minecraft/world/entity/EntityType.java b/net/minecraft/world/entity/EntityType.java
|
||||
index 73cdfa5a315ed259b38dfa946a0b7955d9ac9f50..49201d6664656ebe34c84c1c84b5ea4878729062 100644
|
||||
--- a/net/minecraft/world/entity/EntityType.java
|
||||
+++ b/net/minecraft/world/entity/EntityType.java
|
||||
@@ -1420,9 +1420,20 @@ public class EntityType<T extends Entity> implements FeatureElement, EntityTypeT
|
||||
public static Stream<Entity> loadEntitiesRecursive(final List<? extends Tag> entityTags, final Level level, final EntitySpawnReason spawnReason) {
|
||||
final Spliterator<? extends Tag> spliterator = entityTags.spliterator();
|
||||
return StreamSupport.stream(new Spliterator<Entity>() {
|
||||
+ final java.util.Map<EntityType<?>, Integer> loadedEntityCounts = new java.util.HashMap<>(); // Paper - Entity load/save limit per chunk
|
||||
@Override
|
||||
public boolean tryAdvance(Consumer<? super Entity> consumer) {
|
||||
return spliterator.tryAdvance((nbtbase) -> {
|
||||
EntityType.loadEntityRecursive((CompoundTag) nbtbase, world, reason, (entity) -> {
|
||||
return spliterator.tryAdvance(tag -> EntityType.loadEntityRecursive((CompoundTag)tag, level, spawnReason, entity -> {
|
||||
+ // Paper start - Entity load/save limit per chunk
|
||||
+ final EntityType<?> entityType = entity.getType();
|
||||
+ final int saveLimit = world.paperConfig().chunks.entityPerChunkSaveLimit.getOrDefault(entityType, -1);
|
||||
+ final int saveLimit = level.paperConfig().chunks.entityPerChunkSaveLimit.getOrDefault(entityType, -1);
|
||||
+ if (saveLimit > -1) {
|
||||
+ if (this.loadedEntityCounts.getOrDefault(entityType, 0) >= saveLimit) {
|
||||
+ return null;
|
||||
|
@ -53,19 +53,19 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ this.loadedEntityCounts.merge(entityType, 1, Integer::sum);
|
||||
+ }
|
||||
+ // Paper end - Entity load/save limit per chunk
|
||||
consumer.accept(entity);
|
||||
return entity;
|
||||
});
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/EntityStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/EntityStorage.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/storage/EntityStorage.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/EntityStorage.java
|
||||
@@ -0,0 +0,0 @@ public class EntityStorage implements EntityPersistentStorage<Entity> {
|
||||
consumer.accept(entity);
|
||||
return entity;
|
||||
}));
|
||||
diff --git a/net/minecraft/world/level/chunk/storage/EntityStorage.java b/net/minecraft/world/level/chunk/storage/EntityStorage.java
|
||||
index da05fb780c55381a7a08ced51d01764a645740b2..2856206eafddfcbcc1b65408deda40357f43a6f8 100644
|
||||
--- a/net/minecraft/world/level/chunk/storage/EntityStorage.java
|
||||
+++ b/net/minecraft/world/level/chunk/storage/EntityStorage.java
|
||||
@@ -93,7 +93,18 @@ public class EntityStorage implements EntityPersistentStorage<Entity> {
|
||||
}
|
||||
} else {
|
||||
ListTag listTag = new ListTag();
|
||||
+ final java.util.Map<net.minecraft.world.entity.EntityType<?>, Integer> savedEntityCounts = new java.util.HashMap<>(); // Paper - Entity load/save limit per chunk
|
||||
dataList.getEntities().forEach(entity -> {
|
||||
entities.getEntities().forEach(entity -> {
|
||||
+ // Paper start - Entity load/save limit per chunk
|
||||
+ final EntityType<?> entityType = entity.getType();
|
||||
+ final int saveLimit = this.level.paperConfig().chunks.entityPerChunkSaveLimit.getOrDefault(entityType, -1);
|
||||
|
@ -76,6 +76,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ savedEntityCounts.merge(entityType, 1, Integer::sum);
|
||||
+ }
|
||||
+ // Paper end - Entity load/save limit per chunk
|
||||
CompoundTag compoundTagx = new CompoundTag();
|
||||
if (entity.save(compoundTagx)) {
|
||||
listTag.add(compoundTagx);
|
||||
CompoundTag compoundTag1 = new CompoundTag();
|
||||
if (entity.save(compoundTag1)) {
|
||||
listTag.add(compoundTag1);
|
|
@ -9,11 +9,11 @@ we instead drop the current regionfile header and recalculate -
|
|||
hoping that at least then we don't swap chunks, and maybe recover
|
||||
them all.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionBitmap.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionBitmap.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionBitmap.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionBitmap.java
|
||||
@@ -0,0 +0,0 @@ import java.util.BitSet;
|
||||
diff --git a/net/minecraft/world/level/chunk/storage/RegionBitmap.java b/net/minecraft/world/level/chunk/storage/RegionBitmap.java
|
||||
index 64a718c98f799c62a5bb28e1e8e5f66cc96c915d..666f2e967c99f78422c83fb20e1a3bf3efa7845e 100644
|
||||
--- a/net/minecraft/world/level/chunk/storage/RegionBitmap.java
|
||||
+++ b/net/minecraft/world/level/chunk/storage/RegionBitmap.java
|
||||
@@ -9,6 +9,27 @@ import java.util.BitSet;
|
||||
public class RegionBitmap {
|
||||
private final BitSet used = new BitSet();
|
||||
|
||||
|
@ -38,17 +38,17 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ }
|
||||
+ // Paper end - Attempt to recalculate regionfile header if it is corrupt
|
||||
+
|
||||
public void force(int start, int size) {
|
||||
this.used.set(start, start + size);
|
||||
public void force(int sectorOffset, int sectorCount) {
|
||||
this.used.set(sectorOffset, sectorOffset + sectorCount);
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||
@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
||||
private final IntBuffer timestamps;
|
||||
diff --git a/net/minecraft/world/level/chunk/storage/RegionFile.java b/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||
index ff4fc280409f680f3879a495e37cf1925b1a38f1..a4621c96fd456c5cdd1b6847931806e677b26b30 100644
|
||||
--- a/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||
+++ b/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||
@@ -46,6 +46,355 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
||||
@VisibleForTesting
|
||||
protected final RegionBitmap usedSectors;
|
||||
protected final RegionBitmap usedSectors = new RegionBitmap();
|
||||
|
||||
+ // Paper start - Attempt to recalculate regionfile header if it is corrupt
|
||||
+ private static long roundToSectors(long bytes) {
|
||||
+ long sectors = bytes >>> 12; // 4096 = 2^12
|
||||
|
@ -57,9 +57,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ return sectors + (sign >>> 63);
|
||||
+ }
|
||||
+
|
||||
+ private static final CompoundTag OVERSIZED_COMPOUND = new CompoundTag();
|
||||
+ private static final net.minecraft.nbt.CompoundTag OVERSIZED_COMPOUND = new net.minecraft.nbt.CompoundTag();
|
||||
+
|
||||
+ private CompoundTag attemptRead(long sector, int chunkDataLength, long fileLength) throws IOException {
|
||||
+ private @Nullable net.minecraft.nbt.CompoundTag attemptRead(long sector, int chunkDataLength, long fileLength) throws IOException {
|
||||
+ try {
|
||||
+ if (chunkDataLength < 0) {
|
||||
+ return null;
|
||||
|
@ -91,7 +91,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+
|
||||
+ InputStream input = compression.wrap(new ByteArrayInputStream(chunkData.array(), chunkData.position(), chunkDataLength - chunkData.position()));
|
||||
+
|
||||
+ return NbtIo.read(new DataInputStream(input));
|
||||
+ return net.minecraft.nbt.NbtIo.read(new DataInputStream(input));
|
||||
+ } catch (Exception ex) {
|
||||
+ return null;
|
||||
+ }
|
||||
|
@ -142,7 +142,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ // try to backup file so maybe it could be sent to us for further investigation
|
||||
+
|
||||
+ this.backupRegionFile();
|
||||
+ CompoundTag[] compounds = new CompoundTag[32 * 32]; // only in the regionfile (i.e exclude mojang/aikar oversized data)
|
||||
+ net.minecraft.nbt.CompoundTag[] compounds = new net.minecraft.nbt.CompoundTag[32 * 32]; // only in the regionfile (i.e exclude mojang/aikar oversized data)
|
||||
+ int[] rawLengths = new int[32 * 32]; // length of chunk data including 4 byte length field, bytes
|
||||
+ int[] sectorOffsets = new int[32 * 32]; // in sectors
|
||||
+ boolean[] hasAikarOversized = new boolean[32 * 32];
|
||||
|
@ -154,7 +154,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+
|
||||
+ for (long i = 2, maxSector = Math.min((long)(Integer.MAX_VALUE >>> 8), totalSectors); i < maxSector; ++i) { // first two sectors are header, skip
|
||||
+ int chunkDataLength = this.getLength(i);
|
||||
+ CompoundTag compound = this.attemptRead(i, chunkDataLength, fileLength);
|
||||
+ net.minecraft.nbt.CompoundTag compound = this.attemptRead(i, chunkDataLength, fileLength);
|
||||
+ if (compound == null || compound == OVERSIZED_COMPOUND) {
|
||||
+ continue;
|
||||
+ }
|
||||
|
@ -166,7 +166,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ }
|
||||
+ int location = (chunkPos.x & 31) | ((chunkPos.z & 31) << 5);
|
||||
+
|
||||
+ CompoundTag otherCompound = compounds[location];
|
||||
+ net.minecraft.nbt.CompoundTag otherCompound = compounds[location];
|
||||
+
|
||||
+ if (otherCompound != null && SerializableChunkData.getLastWorldSaveTime(otherCompound) > SerializableChunkData.getLastWorldSaveTime(compound)) {
|
||||
+ continue; // don't overwrite newer data.
|
||||
|
@ -177,7 +177,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ boolean isAikarOversized = false;
|
||||
+ if (Files.exists(aikarOversizedFile)) {
|
||||
+ try {
|
||||
+ CompoundTag aikarOversizedCompound = this.getOversizedData(chunkPos.x, chunkPos.z);
|
||||
+ net.minecraft.nbt.CompoundTag aikarOversizedCompound = this.getOversizedData(chunkPos.x, chunkPos.z);
|
||||
+ if (SerializableChunkData.getLastWorldSaveTime(compound) == SerializableChunkData.getLastWorldSaveTime(aikarOversizedCompound)) {
|
||||
+ // best we got for an id. hope it's good enough
|
||||
+ isAikarOversized = true;
|
||||
|
@ -236,14 +236,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ CompoundTag compound = null;
|
||||
+ net.minecraft.nbt.CompoundTag compound = null;
|
||||
+
|
||||
+ // We do not know the compression type, as it's stored in the regionfile. So we need to try all of them
|
||||
+ RegionFileVersion compression = null;
|
||||
+ for (RegionFileVersion compressionType : RegionFileVersion.VERSIONS.values()) {
|
||||
+ try {
|
||||
+ DataInputStream in = new DataInputStream(compressionType.wrap(new ByteArrayInputStream(chunkData))); // typical java
|
||||
+ compound = NbtIo.read((java.io.DataInput)in);
|
||||
+ compound = net.minecraft.nbt.NbtIo.read((java.io.DataInput)in);
|
||||
+ compression = compressionType;
|
||||
+ break; // reaches here iff readNBT does not throw
|
||||
+ } catch (Exception ex) {
|
||||
|
@ -397,63 +397,55 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+
|
||||
+ final boolean canRecalcHeader; // final forces compile fail on new constructor
|
||||
+ // Paper end - Attempt to recalculate regionfile header if it is corrupt
|
||||
|
||||
+
|
||||
// Paper start - rewrite chunk system
|
||||
@Override
|
||||
@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
||||
throw new IllegalArgumentException("Expected directory, got " + String.valueOf(directory.toAbsolutePath()));
|
||||
public final ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionDataController.WriteData moonrise$startWrite(final net.minecraft.nbt.CompoundTag data, final ChunkPos pos) throws IOException {
|
||||
@@ -74,6 +423,7 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
||||
throw new IllegalArgumentException("Expected directory, got " + externalFileDir.toAbsolutePath());
|
||||
} else {
|
||||
this.externalFileDir = directory;
|
||||
this.externalFileDir = externalFileDir;
|
||||
+ this.canRecalcHeader = RegionFileStorage.isChunkDataFolder(this.externalFileDir); // Paper - add can recalc flag
|
||||
this.offsets = this.header.asIntBuffer();
|
||||
((java.nio.Buffer) this.offsets).limit(1024); // CraftBukkit - decompile error
|
||||
((java.nio.Buffer) this.header).position(4096); // CraftBukkit - decompile error
|
||||
@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
||||
RegionFile.LOGGER.warn("Region file {} has truncated header: {}", path, i);
|
||||
}
|
||||
this.offsets.limit(1024);
|
||||
this.header.position(4096);
|
||||
@@ -94,11 +444,13 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
||||
|
||||
- long j = Files.size(path);
|
||||
+ final long j = Files.size(path); final long regionFileSize = j; // Paper - recalculate header on header corruption
|
||||
long size = Files.size(path);
|
||||
|
||||
- for (int k = 0; k < 1024; ++k) {
|
||||
- int l = this.offsets.get(k);
|
||||
- for (int i1 = 0; i1 < 1024; i1++) {
|
||||
+ boolean needsHeaderRecalc = false; // Paper - recalculate header on header corruption
|
||||
+ boolean hasBackedUp = false; // Paper - recalculate header on header corruption
|
||||
+ for (int k = 0; k < 1024; ++k) { final int headerLocation = k; // Paper - we expect this to be the header location
|
||||
+ final int l = this.offsets.get(k);
|
||||
|
||||
if (l != 0) {
|
||||
- int i1 = RegionFile.getSectorNumber(l);
|
||||
- int j1 = RegionFile.getNumSectors(l);
|
||||
+ final int i1 = RegionFile.getSectorNumber(l); final int offset = i1; // Paper - we expect this to be offset in file in sectors
|
||||
+ int j1 = RegionFile.getNumSectors(l); final int sectorLength; // Paper - diff on change, we expect this to be sector length of region - watch out for reassignments
|
||||
+ for (int i1 = 0; i1 < 1024; i1++) { final int headerLocation = i1; // Paper - we expect this to be the header location
|
||||
int i2 = this.offsets.get(i1);
|
||||
if (i2 != 0) {
|
||||
- int sectorNumber = getSectorNumber(i2);
|
||||
- int numSectors = getNumSectors(i2);
|
||||
+ final int sectorNumber = getSectorNumber(i2); // Paper - we expect this to be offset in file in sectors
|
||||
+ int numSectors = getNumSectors(i2); // Paper - diff on change, we expect this to be sector length of region - watch out for reassignments
|
||||
// Spigot start
|
||||
if (j1 == 255) {
|
||||
if (numSectors == 255) {
|
||||
// We're maxed out, so we need to read the proper length from the section
|
||||
@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
||||
j1 = (realLen.getInt(0) + 4) / 4096 + 1;
|
||||
}
|
||||
@@ -109,18 +461,62 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
||||
// Spigot end
|
||||
+ sectorLength = j1; // Paper - diff on change, we expect this to be sector length of region
|
||||
|
||||
if (i1 < 2) {
|
||||
RegionFile.LOGGER.warn("Region file {} has invalid sector at index: {}; sector {} overlaps with header", new Object[]{path, k, i1});
|
||||
- this.offsets.put(k, 0);
|
||||
+ //this.offsets.put(k, 0); // Paper - we catch this, but need it in the header for the summary change
|
||||
} else if (j1 == 0) {
|
||||
RegionFile.LOGGER.warn("Region file {} has an invalid sector at index: {}; size has to be > 0", path, k);
|
||||
- this.offsets.put(k, 0);
|
||||
+ //this.offsets.put(k, 0); // Paper - we catch this, but need it in the header for the summary change
|
||||
} else if ((long) i1 * 4096L > j) {
|
||||
RegionFile.LOGGER.warn("Region file {} has an invalid sector at index: {}; sector {} is out of bounds", new Object[]{path, k, i1});
|
||||
- this.offsets.put(k, 0);
|
||||
+ //this.offsets.put(k, 0); // Paper - we catch this, but need it in the header for the summary change
|
||||
if (sectorNumber < 2) {
|
||||
LOGGER.warn("Region file {} has invalid sector at index: {}; sector {} overlaps with header", path, i1, sectorNumber);
|
||||
- this.offsets.put(i1, 0);
|
||||
+ //this.offsets.put(i1, 0); // Paper - we catch this, but need it in the header for the summary change
|
||||
} else if (numSectors == 0) {
|
||||
LOGGER.warn("Region file {} has an invalid sector at index: {}; size has to be > 0", path, i1);
|
||||
- this.offsets.put(i1, 0);
|
||||
+ //this.offsets.put(i1, 0); // Paper - we catch this, but need it in the header for the summary change
|
||||
} else if (sectorNumber * 4096L > size) {
|
||||
LOGGER.warn("Region file {} has an invalid sector at index: {}; sector {} is out of bounds", path, i1, sectorNumber);
|
||||
- this.offsets.put(i1, 0);
|
||||
+ //this.offsets.put(i1, 0); // Paper - we catch this, but need it in the header for the summary change
|
||||
} else {
|
||||
- this.usedSectors.force(i1, j1);
|
||||
+ //this.usedSectors.force(i1, j1); // Paper - move this down so we can check if it fails to allocate
|
||||
- this.usedSectors.force(sectorNumber, numSectors);
|
||||
+ //this.usedSectors.force(sectorNumber, numSectors); // Paper - move this down so we can check if it fails to allocate
|
||||
+ }
|
||||
+ // Paper start - recalculate header on header corruption
|
||||
+ if (offset < 2 || sectorLength <= 0 || ((long)offset * 4096L) > regionFileSize) {
|
||||
+ if (sectorNumber < 2 || numSectors <= 0 || ((long)sectorNumber * 4096L) > size) {
|
||||
+ if (canRecalcHeader) {
|
||||
+ LOGGER.error("Detected invalid header for regionfile " + this.path.toAbsolutePath() + "! Recalculating header...");
|
||||
+ needsHeaderRecalc = true;
|
||||
|
@ -471,7 +463,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ continue;
|
||||
+ }
|
||||
+ }
|
||||
+ boolean failedToAllocate = !this.usedSectors.tryAllocate(offset, sectorLength);
|
||||
+ boolean failedToAllocate = !this.usedSectors.tryAllocate(sectorNumber, numSectors);
|
||||
+ if (failedToAllocate) {
|
||||
+ LOGGER.error("Overlapping allocation by local chunk (" + (headerLocation & 31) + "," + (headerLocation >>> 5) + ") in regionfile " + this.path.toAbsolutePath());
|
||||
}
|
||||
|
@ -499,20 +491,19 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
||||
}
|
||||
@@ -130,10 +526,35 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
||||
}
|
||||
|
||||
private Path getExternalChunkPath(ChunkPos chunkPos) {
|
||||
- String s = "c." + chunkPos.x + "." + chunkPos.z + ".mcc";
|
||||
+ String s = "c." + chunkPos.x + "." + chunkPos.z + ".mcc"; // Paper - diff on change
|
||||
|
||||
return this.externalFileDir.resolve(s);
|
||||
- String string = "c." + chunkPos.x + "." + chunkPos.z + ".mcc";
|
||||
+ String string = "c." + chunkPos.x + "." + chunkPos.z + ".mcc"; // Paper - diff on change
|
||||
return this.externalFileDir.resolve(string);
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ private static ChunkPos getOversizedChunkPair(Path file) {
|
||||
+ private static @Nullable ChunkPos getOversizedChunkPair(Path file) {
|
||||
+ String fileName = file.getFileName().toString();
|
||||
+
|
||||
+ if (!fileName.startsWith("c.") || !fileName.endsWith(".mcc")) {
|
||||
|
@ -537,81 +528,79 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ // Paper end
|
||||
+
|
||||
@Nullable
|
||||
public synchronized DataInputStream getChunkDataInputStream(ChunkPos pos) throws IOException {
|
||||
int i = this.getOffset(pos);
|
||||
@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
||||
((java.nio.Buffer) bytebuffer).flip(); // CraftBukkit - decompile error
|
||||
if (bytebuffer.remaining() < 5) {
|
||||
RegionFile.LOGGER.error("Chunk {} header is truncated: expected {} but read {}", new Object[]{pos, l, bytebuffer.remaining()});
|
||||
public synchronized DataInputStream getChunkDataInputStream(ChunkPos chunkPos) throws IOException {
|
||||
int offset = this.getOffset(chunkPos);
|
||||
@@ -155,30 +576,67 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
||||
byteBuffer.flip();
|
||||
if (byteBuffer.remaining() < 5) {
|
||||
LOGGER.error("Chunk {} header is truncated: expected {} but read {}", chunkPos, i, byteBuffer.remaining());
|
||||
+ // Paper start - recalculate header on regionfile corruption
|
||||
+ if (this.canRecalcHeader && this.recalculateHeader()) {
|
||||
+ return this.getChunkDataInputStream(pos);
|
||||
+ return this.getChunkDataInputStream(chunkPos);
|
||||
+ }
|
||||
+ // Paper end - recalculate header on regionfile corruption
|
||||
return null;
|
||||
} else {
|
||||
int i1 = bytebuffer.getInt();
|
||||
@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
||||
|
||||
if (i1 == 0) {
|
||||
RegionFile.LOGGER.warn("Chunk {} is allocated, but stream is missing", pos);
|
||||
int _int = byteBuffer.getInt();
|
||||
byte b = byteBuffer.get();
|
||||
if (_int == 0) {
|
||||
LOGGER.warn("Chunk {} is allocated, but stream is missing", chunkPos);
|
||||
+ // Paper start - recalculate header on regionfile corruption
|
||||
+ if (this.canRecalcHeader && this.recalculateHeader()) {
|
||||
+ return this.getChunkDataInputStream(pos);
|
||||
+ return this.getChunkDataInputStream(chunkPos);
|
||||
+ }
|
||||
+ // Paper end - recalculate header on regionfile corruption
|
||||
return null;
|
||||
} else {
|
||||
int j1 = i1 - 1;
|
||||
@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
||||
if (RegionFile.isExternalStreamChunk(b0)) {
|
||||
if (j1 != 0) {
|
||||
RegionFile.LOGGER.warn("Chunk has both internal and external streams");
|
||||
int i1 = _int - 1;
|
||||
if (isExternalStreamChunk(b)) {
|
||||
if (i1 != 0) {
|
||||
LOGGER.warn("Chunk has both internal and external streams");
|
||||
+ // Paper start - recalculate header on regionfile corruption
|
||||
+ if (this.canRecalcHeader && this.recalculateHeader()) {
|
||||
+ return this.getChunkDataInputStream(pos);
|
||||
+ return this.getChunkDataInputStream(chunkPos);
|
||||
+ }
|
||||
+ // Paper end - recalculate header on regionfile corruption
|
||||
}
|
||||
|
||||
- return this.createExternalChunkInputStream(pos, RegionFile.getExternalChunkVersion(b0));
|
||||
- return this.createExternalChunkInputStream(chunkPos, getExternalChunkVersion(b));
|
||||
+ // Paper start - recalculate header on regionfile corruption
|
||||
+ final DataInputStream ret = this.createExternalChunkInputStream(pos, RegionFile.getExternalChunkVersion(b0));
|
||||
+ final DataInputStream ret = this.createExternalChunkInputStream(chunkPos, getExternalChunkVersion(b));
|
||||
+ if (ret == null && this.canRecalcHeader && this.recalculateHeader()) {
|
||||
+ return this.getChunkDataInputStream(pos);
|
||||
+ return this.getChunkDataInputStream(chunkPos);
|
||||
+ }
|
||||
+ return ret;
|
||||
+ // Paper end - recalculate header on regionfile corruption
|
||||
} else if (j1 > bytebuffer.remaining()) {
|
||||
RegionFile.LOGGER.error("Chunk {} stream is truncated: expected {} but read {}", new Object[]{pos, j1, bytebuffer.remaining()});
|
||||
} else if (i1 > byteBuffer.remaining()) {
|
||||
LOGGER.error("Chunk {} stream is truncated: expected {} but read {}", chunkPos, i1, byteBuffer.remaining());
|
||||
+ // Paper start - recalculate header on regionfile corruption
|
||||
+ if (this.canRecalcHeader && this.recalculateHeader()) {
|
||||
+ return this.getChunkDataInputStream(pos);
|
||||
+ return this.getChunkDataInputStream(chunkPos);
|
||||
+ }
|
||||
+ // Paper end - recalculate header on regionfile corruption
|
||||
return null;
|
||||
} else if (j1 < 0) {
|
||||
RegionFile.LOGGER.error("Declared size {} of chunk {} is negative", i1, pos);
|
||||
} else if (i1 < 0) {
|
||||
LOGGER.error("Declared size {} of chunk {} is negative", _int, chunkPos);
|
||||
+ // Paper start - recalculate header on regionfile corruption
|
||||
+ if (this.canRecalcHeader && this.recalculateHeader()) {
|
||||
+ return this.getChunkDataInputStream(pos);
|
||||
+ return this.getChunkDataInputStream(chunkPos);
|
||||
+ }
|
||||
+ // Paper end - recalculate header on regionfile corruption
|
||||
return null;
|
||||
} else {
|
||||
JvmProfiler.INSTANCE.onRegionFileRead(this.info, pos, this.version, j1);
|
||||
- return this.createChunkInputStream(pos, b0, RegionFile.createStream(bytebuffer, j1));
|
||||
JvmProfiler.INSTANCE.onRegionFileRead(this.info, chunkPos, this.version, i1);
|
||||
- return this.createChunkInputStream(chunkPos, b, createStream(byteBuffer, i1));
|
||||
+ // Paper start - recalculate header on regionfile corruption
|
||||
+ final DataInputStream ret = this.createChunkInputStream(pos, b0, RegionFile.createStream(bytebuffer, j1));
|
||||
+ final DataInputStream ret = this.createChunkInputStream(chunkPos, b, createStream(byteBuffer, i1));
|
||||
+ if (ret == null && this.canRecalcHeader && this.recalculateHeader()) {
|
||||
+ return this.getChunkDataInputStream(pos);
|
||||
+ return this.getChunkDataInputStream(chunkPos);
|
||||
+ }
|
||||
+ return ret;
|
||||
+ // Paper end - recalculate header on regionfile corruption
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
||||
@@ -361,9 +819,14 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
||||
}
|
||||
|
||||
private ByteBuffer createExternalStub() {
|
||||
|
@ -620,22 +609,21 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ }
|
||||
+ private ByteBuffer createExternalStub(RegionFileVersion version) {
|
||||
+ // Paper end - add version param
|
||||
ByteBuffer bytebuffer = ByteBuffer.allocate(5);
|
||||
ByteBuffer byteBuffer = ByteBuffer.allocate(5);
|
||||
byteBuffer.putInt(1);
|
||||
- byteBuffer.put((byte)(this.version.getId() | 128));
|
||||
+ byteBuffer.put((byte)(version.getId() | 128));
|
||||
byteBuffer.flip();
|
||||
return byteBuffer;
|
||||
}
|
||||
diff --git a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||
index d263f78fa610ce6f6fb5a0f5e064e3d8335c2199..dad7f94b611cf0fc68b1a3878c458233f6bb6d61 100644
|
||||
--- a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||
+++ b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||
@@ -23,6 +23,36 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
private final Path folder;
|
||||
private final boolean sync;
|
||||
|
||||
bytebuffer.putInt(1);
|
||||
- bytebuffer.put((byte) (this.version.getId() | 128));
|
||||
+ bytebuffer.put((byte) (version.getId() | 128)); // Paper - replace with version param
|
||||
((java.nio.Buffer) bytebuffer).flip(); // CraftBukkit - decompile error
|
||||
return bytebuffer;
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||
@@ -0,0 +0,0 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
}
|
||||
}
|
||||
// Paper end - rewrite chunk system
|
||||
+ // Paper start - recalculate region file headers
|
||||
+ private final boolean isChunkData;
|
||||
+
|
||||
|
@ -666,40 +654,42 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
|
||||
protected RegionFileStorage(RegionStorageInfo storageKey, Path directory, boolean dsync) { // Paper - protected
|
||||
this.folder = directory;
|
||||
this.sync = dsync;
|
||||
this.info = storageKey;
|
||||
// Paper start - rewrite chunk system
|
||||
private static final int REGION_SHIFT = 5;
|
||||
private static final int MAX_NON_EXISTING_CACHE = 1024 * 4;
|
||||
@@ -216,6 +246,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
this.folder = folder;
|
||||
this.sync = sync;
|
||||
this.info = info;
|
||||
+ this.isChunkData = isChunkDataFolder(this.folder); // Paper - recalculate region file headers
|
||||
}
|
||||
|
||||
// Paper start - rewrite chunk system
|
||||
@@ -0,0 +0,0 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
try {
|
||||
if (datainputstream != null) {
|
||||
nbttagcompound = NbtIo.read((DataInput) datainputstream);
|
||||
+ // Paper start - recover from corrupt regionfile header
|
||||
+ if (this.isChunkData) {
|
||||
+ ChunkPos chunkPos = SerializableChunkData.getChunkCoordinate(nbttagcompound);
|
||||
+ if (!chunkPos.equals(pos)) {
|
||||
+ net.minecraft.server.MinecraftServer.LOGGER.error("Attempting to read chunk data at " + pos + " but got chunk data for " + chunkPos + " instead! Attempting regionfile recalculation for regionfile " + regionfile.getPath().toAbsolutePath());
|
||||
+ if (regionfile.recalculateHeader()) {
|
||||
+ return this.read(pos);
|
||||
+ }
|
||||
+ net.minecraft.server.MinecraftServer.LOGGER.error("Can't recalculate regionfile header, regenerating chunk " + pos + " for " + regionfile.getPath().toAbsolutePath());
|
||||
+ return null;
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - recover from corrupt regionfile header
|
||||
break label43;
|
||||
}
|
||||
@org.jetbrains.annotations.Contract("_, false -> !null") @Nullable private RegionFile getRegionFile(ChunkPos chunkPos, boolean existingOnly) throws IOException { // CraftBukkit
|
||||
@@ -309,6 +340,19 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileVersion.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileVersion.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileVersion.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileVersion.java
|
||||
@@ -0,0 +0,0 @@ import org.slf4j.Logger;
|
||||
var4 = NbtIo.read(chunkDataInputStream);
|
||||
+ // Paper start - recover from corrupt regionfile header
|
||||
+ if (this.isChunkData) {
|
||||
+ ChunkPos headerChunkPos = SerializableChunkData.getChunkCoordinate(var4);
|
||||
+ if (!headerChunkPos.equals(chunkPos)) {
|
||||
+ net.minecraft.server.MinecraftServer.LOGGER.error("Attempting to read chunk data at " + chunkPos + " but got chunk data for " + headerChunkPos + " instead! Attempting regionfile recalculation for regionfile " + regionFile.getPath().toAbsolutePath());
|
||||
+ if (regionFile.recalculateHeader()) {
|
||||
+ return this.read(chunkPos);
|
||||
+ }
|
||||
+ net.minecraft.server.MinecraftServer.LOGGER.error("Can't recalculate regionfile header, regenerating chunk " + chunkPos + " for " + regionFile.getPath().toAbsolutePath());
|
||||
+ return null;
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - recover from corrupt regionfile header
|
||||
}
|
||||
|
||||
return var4;
|
||||
diff --git a/net/minecraft/world/level/chunk/storage/RegionFileVersion.java b/net/minecraft/world/level/chunk/storage/RegionFileVersion.java
|
||||
index 0c739ca5b01ac0ec35a11fd01c5fc65de97c2852..de7deee4b79c969a7797bd57b657a16404c15303 100644
|
||||
--- a/net/minecraft/world/level/chunk/storage/RegionFileVersion.java
|
||||
+++ b/net/minecraft/world/level/chunk/storage/RegionFileVersion.java
|
||||
@@ -21,7 +21,7 @@ import org.slf4j.Logger;
|
||||
|
||||
public class RegionFileVersion {
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
|
@ -708,11 +698,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
private static final Object2ObjectMap<String, RegionFileVersion> VERSIONS_BY_NAME = new Object2ObjectOpenHashMap<>();
|
||||
public static final RegionFileVersion VERSION_GZIP = register(
|
||||
new RegionFileVersion(
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/SerializableChunkData.java b/src/main/java/net/minecraft/world/level/chunk/storage/SerializableChunkData.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/storage/SerializableChunkData.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/SerializableChunkData.java
|
||||
@@ -0,0 +0,0 @@ public record SerializableChunkData(Registry<Biome> biomeRegistry, ChunkPos chun
|
||||
diff --git a/net/minecraft/world/level/chunk/storage/SerializableChunkData.java b/net/minecraft/world/level/chunk/storage/SerializableChunkData.java
|
||||
index 70a9972252576e039ac126f6057a6ed66b80cdfc..d783c3580ea274a0a9cb07449eb8037bc5a04d76 100644
|
||||
--- a/net/minecraft/world/level/chunk/storage/SerializableChunkData.java
|
||||
+++ b/net/minecraft/world/level/chunk/storage/SerializableChunkData.java
|
||||
@@ -120,6 +120,18 @@ public record SerializableChunkData(
|
||||
}
|
||||
}
|
||||
// Paper end - guard against serializing mismatching coordinates
|
||||
|
@ -731,12 +721,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
|
||||
// Paper start - Do not let the server load chunks from newer versions
|
||||
private static final int CURRENT_DATA_VERSION = net.minecraft.SharedConstants.getCurrentVersion().getDataVersion().getVersion();
|
||||
@@ -0,0 +0,0 @@ public record SerializableChunkData(Registry<Biome> biomeRegistry, ChunkPos chun
|
||||
nbttagcompound.putInt("xPos", this.chunkPos.x);
|
||||
nbttagcompound.putInt("yPos", this.minSectionY);
|
||||
nbttagcompound.putInt("zPos", this.chunkPos.z);
|
||||
- nbttagcompound.putLong("LastUpdate", this.lastUpdateTime);
|
||||
+ nbttagcompound.putLong("LastUpdate", this.lastUpdateTime); // Paper - Diff on change
|
||||
nbttagcompound.putLong("InhabitedTime", this.inhabitedTime);
|
||||
nbttagcompound.putString("Status", BuiltInRegistries.CHUNK_STATUS.getKey(this.chunkStatus).toString());
|
||||
DataResult<Tag> dataresult; // CraftBukkit - decompile error
|
||||
@@ -604,7 +616,7 @@ public record SerializableChunkData(
|
||||
compoundTag.putInt("xPos", this.chunkPos.x);
|
||||
compoundTag.putInt("yPos", this.minSectionY);
|
||||
compoundTag.putInt("zPos", this.chunkPos.z);
|
||||
- compoundTag.putLong("LastUpdate", this.lastUpdateTime);
|
||||
+ compoundTag.putLong("LastUpdate", this.lastUpdateTime); // Paper - Diff on change
|
||||
compoundTag.putLong("InhabitedTime", this.inhabitedTime);
|
||||
compoundTag.putString("Status", BuiltInRegistries.CHUNK_STATUS.getKey(this.chunkStatus).toString());
|
||||
if (this.blendingData != null) {
|
|
@ -4,23 +4,23 @@ Date: Sun, 9 Jun 2019 03:53:22 +0100
|
|||
Subject: [PATCH] Incremental chunk and player saving
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
|
||||
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
|
||||
index d967d605c2e4227ae980c30f1c8b86edbc680d6d..6dbae12bbfd47cd4e75bc3089561e8e226e9e604 100644
|
||||
--- a/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/net/minecraft/server/MinecraftServer.java
|
||||
@@ -960,7 +960,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
boolean var4;
|
||||
try {
|
||||
this.isSaving = true;
|
||||
- this.getPlayerList().saveAll();
|
||||
+ this.getPlayerList().saveAll(); // Paper - Incremental chunk and player saving; diff on change
|
||||
flag3 = this.saveAllChunks(suppressLogs, flush, force);
|
||||
var4 = this.saveAllChunks(suppressLog, flush, forced);
|
||||
} finally {
|
||||
this.isSaving = false;
|
||||
@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
@@ -1533,9 +1533,29 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
}
|
||||
|
||||
--this.ticksUntilAutosave;
|
||||
this.ticksUntilAutosave--;
|
||||
- if (this.autosavePeriod > 0 && this.ticksUntilAutosave <= 0) { // CraftBukkit
|
||||
- this.autoSave();
|
||||
+ // Paper start - Incremental chunk and player saving
|
||||
|
@ -47,22 +47,20 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ profiler.pop();
|
||||
+ // Paper end - Incremental chunk and player saving
|
||||
|
||||
ProfilerFiller gameprofilerfiller = Profiler.get();
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
ProfilerFiller profilerFiller = Profiler.get();
|
||||
this.runAllTasks(); // Paper - move runAllTasks() into full server tick (previously for timings)
|
||||
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
||||
index 46dfaed12c998c219a20c711a06531aed2c68012..ebeeb63c3dca505a3ce8b88feaa5d2ca20ec24a2 100644
|
||||
--- a/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -1316,6 +1316,28 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
return !this.server.isUnderSpawnProtection(this, pos, player) && this.getWorldBorder().isWithinBounds(pos);
|
||||
}
|
||||
|
||||
+ // Paper start - Incremental chunk and player saving
|
||||
+ public void saveIncrementally(boolean doFull) {
|
||||
+ ServerChunkCache chunkproviderserver = this.getChunkSource();
|
||||
+
|
||||
+ if (doFull) {
|
||||
+ org.bukkit.Bukkit.getPluginManager().callEvent(new org.bukkit.event.world.WorldSaveEvent(getWorld()));
|
||||
+ org.bukkit.Bukkit.getPluginManager().callEvent(new org.bukkit.event.world.WorldSaveEvent(this.getWorld()));
|
||||
+ }
|
||||
+
|
||||
+ if (doFull) {
|
||||
|
@ -72,43 +70,43 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ // Copied from save()
|
||||
+ // CraftBukkit start - moved from MinecraftServer.saveChunks
|
||||
+ if (doFull) { // Paper
|
||||
+ ServerLevel worldserver1 = this;
|
||||
+ this.serverLevelData.setWorldBorder(worldserver1.getWorldBorder().createSettings());
|
||||
+ ServerLevel serverLevel1 = this;
|
||||
+ this.serverLevelData.setWorldBorder(serverLevel1.getWorldBorder().createSettings());
|
||||
+ this.serverLevelData.setCustomBossEvents(this.server.getCustomBossEvents().save(this.registryAccess()));
|
||||
+ this.convertable.saveDataTag(this.server.registryAccess(), this.serverLevelData, this.server.getPlayerList().getSingleplayerData());
|
||||
+ this.levelStorageAccess.saveDataTag(this.server.registryAccess(), this.serverLevelData, this.server.getPlayerList().getSingleplayerData());
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
+ }
|
||||
+ // Paper end - Incremental chunk and player saving
|
||||
+
|
||||
public void save(@Nullable ProgressListener progressListener, boolean flush, boolean savingDisabled) {
|
||||
public void save(@Nullable ProgressListener progress, boolean flush, boolean skipSave) {
|
||||
// Paper start - add close param
|
||||
this.save(progressListener, flush, savingDisabled, false);
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -0,0 +0,0 @@ import org.bukkit.inventory.MainHand;
|
||||
public class ServerPlayer extends net.minecraft.world.entity.player.Player implements ca.spottedleaf.moonrise.patches.chunk_system.player.ChunkSystemServerPlayer { // Paper - rewrite chunk system
|
||||
this.save(progress, flush, skipSave, false);
|
||||
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
|
||||
index e61fe83479f095e8addbd3e8f1d5179c998ae1eb..0a7e5106a1d39150326e7c323030df5d32ecef1e 100644
|
||||
--- a/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -180,6 +180,7 @@ import org.slf4j.Logger;
|
||||
|
||||
public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patches.chunk_system.player.ChunkSystemServerPlayer { // Paper - rewrite chunk system
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
+ public long lastSave = MinecraftServer.currentTick; // Paper - Incremental chunk and player saving
|
||||
private static final int NEUTRAL_MOB_DEATH_NOTIFICATION_RADII_XZ = 32;
|
||||
private static final int NEUTRAL_MOB_DEATH_NOTIFICATION_RADII_Y = 10;
|
||||
private static final int FLY_STAT_RECORDING_SPEED = 25;
|
||||
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
@@ -0,0 +0,0 @@ public abstract class PlayerList {
|
||||
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
|
||||
index 5e94dd9e26aa4fd6545dbaae2ae0cb51cb6f13e0..03feaf0adb8ee87e33744a4615dc2507a02f92d7 100644
|
||||
--- a/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/net/minecraft/server/players/PlayerList.java
|
||||
@@ -482,6 +482,7 @@ public abstract class PlayerList {
|
||||
|
||||
protected void save(ServerPlayer player) {
|
||||
if (!player.getBukkitEntity().isPersistent()) return; // CraftBukkit
|
||||
+ player.lastSave = MinecraftServer.currentTick; // Paper - Incremental chunk and player saving
|
||||
this.playerIo.save(player);
|
||||
ServerStatsCounter serverstatisticmanager = (ServerStatsCounter) player.getStats(); // CraftBukkit
|
||||
|
||||
@@ -0,0 +0,0 @@ public abstract class PlayerList {
|
||||
ServerStatsCounter serverStatsCounter = player.getStats(); // CraftBukkit
|
||||
if (serverStatsCounter != null) {
|
||||
@@ -1064,9 +1065,23 @@ public abstract class PlayerList {
|
||||
}
|
||||
|
||||
public void saveAll() {
|
||||
|
@ -116,18 +114,20 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ this.saveAll(-1);
|
||||
+ }
|
||||
+
|
||||
+ public void saveAll(int interval) {
|
||||
+ public void saveAll(final int interval) {
|
||||
io.papermc.paper.util.MCUtil.ensureMain("Save Players" , () -> { // Paper - Ensure main
|
||||
+ int numSaved = 0;
|
||||
+ long now = MinecraftServer.currentTick;
|
||||
for (int i = 0; i < this.players.size(); ++i) {
|
||||
- this.save((ServerPlayer) this.players.get(i));
|
||||
+ final long now = MinecraftServer.currentTick;
|
||||
for (int i = 0; i < this.players.size(); i++) {
|
||||
- this.save(this.players.get(i));
|
||||
+ final ServerPlayer player = this.players.get(i);
|
||||
+ if (interval == -1 || now - player.lastSave >= interval) {
|
||||
+ this.save(player);
|
||||
+ if (interval != -1 && ++numSaved >= io.papermc.paper.configuration.GlobalConfiguration.get().playerAutoSave.maxPerTick()) { break; }
|
||||
+ if (interval != -1 && ++numSaved >= io.papermc.paper.configuration.GlobalConfiguration.get().playerAutoSave.maxPerTick()) {
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - Incremental chunk and player saving
|
||||
}
|
||||
|
||||
return null; }); // Paper - ensure main
|
||||
}
|
|
@ -30,12 +30,12 @@ This patch also specifically optimises other areas of code to
|
|||
use PoiAccess. For example, some villager AI and portaling code
|
||||
had to be specifically modified.
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/util/PoiAccess.java b/src/main/java/io/papermc/paper/util/PoiAccess.java
|
||||
diff --git a/io/papermc/paper/util/PoiAccess.java b/io/papermc/paper/util/PoiAccess.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
|
||||
index 0000000000000000000000000000000000000000..f39294b1f83c4022be5ced4da781103a1eee2daf
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/util/PoiAccess.java
|
||||
@@ -0,0 +0,0 @@
|
||||
+++ b/io/papermc/paper/util/PoiAccess.java
|
||||
@@ -0,0 +1,806 @@
|
||||
+package io.papermc.paper.util;
|
||||
+
|
||||
+import ca.spottedleaf.moonrise.common.util.CoordinateUtils;
|
||||
|
@ -842,38 +842,38 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ throw new RuntimeException();
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/AcquirePoi.java b/src/main/java/net/minecraft/world/entity/ai/behavior/AcquirePoi.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/ai/behavior/AcquirePoi.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/AcquirePoi.java
|
||||
@@ -0,0 +0,0 @@ public class AcquirePoi {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
- Set<Pair<Holder<PoiType>, BlockPos>> set = poiManager.findAllClosestFirstWithType(
|
||||
- poiPredicate, predicate2, entity.blockPosition(), 48, PoiManager.Occupancy.HAS_SPACE
|
||||
- )
|
||||
- .limit(5L)
|
||||
- .filter(pairx -> worldPosBiPredicate.test(world, (BlockPos)pairx.getSecond()))
|
||||
- .collect(Collectors.toSet());
|
||||
+ // Paper start - optimise POI access
|
||||
+ final java.util.List<Pair<Holder<PoiType>, BlockPos>> poiposes = new java.util.ArrayList<>();
|
||||
+ io.papermc.paper.util.PoiAccess.findNearestPoiPositions(poiManager, poiPredicate, predicate2, entity.blockPosition(), 48, 48*48, PoiManager.Occupancy.HAS_SPACE, false, 5, poiposes);
|
||||
+ final Set<Pair<Holder<PoiType>, BlockPos>> set = new java.util.HashSet<>(poiposes.size());
|
||||
+ for (final Pair<Holder<PoiType>, BlockPos> poiPose : poiposes) {
|
||||
+ if (worldPosBiPredicate.test(world, poiPose.getSecond())) {
|
||||
+ set.add(poiPose);
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - optimise POI access
|
||||
Path path = findPathToPois(entity, set);
|
||||
if (path != null && path.canReach()) {
|
||||
BlockPos blockPos = path.getTarget();
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java b/src/main/java/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java
|
||||
@@ -0,0 +0,0 @@ public class NearestBedSensor extends Sensor<Mob> {
|
||||
diff --git a/net/minecraft/world/entity/ai/behavior/AcquirePoi.java b/net/minecraft/world/entity/ai/behavior/AcquirePoi.java
|
||||
index 9de13a78b2a8be181c02ab330bfa9abb936a83db..b9174ae7e3a3e2de2d570b95ab5012ac3c3a2eda 100644
|
||||
--- a/net/minecraft/world/entity/ai/behavior/AcquirePoi.java
|
||||
+++ b/net/minecraft/world/entity/ai/behavior/AcquirePoi.java
|
||||
@@ -84,12 +84,16 @@ public class AcquirePoi {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
- Set<Pair<Holder<PoiType>, BlockPos>> set = poiManager.findAllClosestFirstWithType(
|
||||
- acquirablePois, predicate1, mob.blockPosition(), 48, PoiManager.Occupancy.HAS_SPACE
|
||||
- )
|
||||
- .limit(5L)
|
||||
- .filter(pair1 -> predicate.test(level, pair1.getSecond()))
|
||||
- .collect(Collectors.toSet());
|
||||
+ // Paper start - optimise POI access
|
||||
+ final java.util.List<Pair<Holder<PoiType>, BlockPos>> poiposes = new java.util.ArrayList<>();
|
||||
+ io.papermc.paper.util.PoiAccess.findNearestPoiPositions(poiManager, acquirablePois, predicate1, mob.blockPosition(), 48, 48*48, PoiManager.Occupancy.HAS_SPACE, false, 5, poiposes);
|
||||
+ final Set<Pair<Holder<PoiType>, BlockPos>> set = new java.util.HashSet<>(poiposes.size());
|
||||
+ for (final Pair<Holder<PoiType>, BlockPos> poiPose : poiposes) {
|
||||
+ if (predicate.test(level, poiPose.getSecond())) {
|
||||
+ set.add(poiPose);
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - optimise POI access
|
||||
Path path = findPathToPois(mob, set);
|
||||
if (path != null && path.canReach()) {
|
||||
BlockPos target = path.getTarget();
|
||||
diff --git a/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java b/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java
|
||||
index 6e9325f0800a35637fdec5edb8a514ea03741762..066faa704338c573472381e1ebd063e0d52aaaa4 100644
|
||||
--- a/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java
|
||||
+++ b/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java
|
||||
@@ -53,11 +53,12 @@ public class NearestBedSensor extends Sensor<Mob> {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
@ -889,82 +889,82 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ Path path = AcquirePoi.findPathToPois(entity, new java.util.HashSet<>(poiposes));
|
||||
+ // Paper end - optimise POI access
|
||||
if (path != null && path.canReach()) {
|
||||
BlockPos blockPos = path.getTarget();
|
||||
Optional<Holder<PoiType>> optional = poiManager.getType(blockPos);
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java b/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java
|
||||
@@ -0,0 +0,0 @@ public class PoiManager extends SectionStorage<PoiSection, PoiSection.Packed> im
|
||||
BlockPos target = path.getTarget();
|
||||
Optional<Holder<PoiType>> type = poiManager.getType(target);
|
||||
diff --git a/net/minecraft/world/entity/ai/village/poi/PoiManager.java b/net/minecraft/world/entity/ai/village/poi/PoiManager.java
|
||||
index 5c5724f5e3ad640f55aecbc1d8f71d1f59ecdc62..618fc0eb4fe70e46e55f3aa28e8eac1d2d01b6d9 100644
|
||||
--- a/net/minecraft/world/entity/ai/village/poi/PoiManager.java
|
||||
+++ b/net/minecraft/world/entity/ai/village/poi/PoiManager.java
|
||||
@@ -254,36 +254,47 @@ public class PoiManager extends SectionStorage<PoiSection, PoiSection.Packed> im
|
||||
public Optional<BlockPos> find(
|
||||
Predicate<Holder<PoiType>> typePredicate, Predicate<BlockPos> posPredicate, BlockPos pos, int radius, PoiManager.Occupancy occupationStatus
|
||||
Predicate<Holder<PoiType>> typePredicate, Predicate<BlockPos> posPredicate, BlockPos pos, int distance, PoiManager.Occupancy status
|
||||
) {
|
||||
- return this.findAll(typePredicate, posPredicate, pos, radius, occupationStatus).findFirst();
|
||||
- return this.findAll(typePredicate, posPredicate, pos, distance, status).findFirst();
|
||||
+ // Paper start - re-route to faster logic
|
||||
+ BlockPos ret = io.papermc.paper.util.PoiAccess.findAnyPoiPosition(this, typePredicate, posPredicate, pos, radius, occupationStatus, false);
|
||||
+ BlockPos ret = io.papermc.paper.util.PoiAccess.findAnyPoiPosition(this, typePredicate, posPredicate, pos, distance, status, false);
|
||||
+ return Optional.ofNullable(ret);
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
public Optional<BlockPos> findClosest(Predicate<Holder<PoiType>> typePredicate, BlockPos pos, int radius, PoiManager.Occupancy occupationStatus) {
|
||||
- return this.getInRange(typePredicate, pos, radius, occupationStatus)
|
||||
- .map(PoiRecord::getPos)
|
||||
- .min(Comparator.comparingDouble(poiPos -> poiPos.distSqr(pos)));
|
||||
public Optional<BlockPos> findClosest(Predicate<Holder<PoiType>> typePredicate, BlockPos pos, int distance, PoiManager.Occupancy status) {
|
||||
- return this.getInRange(typePredicate, pos, distance, status).map(PoiRecord::getPos).min(Comparator.comparingDouble(blockPos -> blockPos.distSqr(pos)));
|
||||
+ // Paper start - re-route to faster logic
|
||||
+ BlockPos closestPos = io.papermc.paper.util.PoiAccess.findClosestPoiDataPosition(this, typePredicate, null, pos, radius, radius * radius, occupationStatus, false);
|
||||
+ BlockPos closestPos = io.papermc.paper.util.PoiAccess.findClosestPoiDataPosition(this, typePredicate, null, pos, distance, distance * distance, status, false);
|
||||
+ return Optional.ofNullable(closestPos);
|
||||
+ // Paper end - re-route to faster logic
|
||||
}
|
||||
|
||||
public Optional<Pair<Holder<PoiType>, BlockPos>> findClosestWithType(
|
||||
Predicate<Holder<PoiType>> typePredicate, BlockPos pos, int radius, PoiManager.Occupancy occupationStatus
|
||||
Predicate<Holder<PoiType>> typePredicate, BlockPos pos, int distance, PoiManager.Occupancy status
|
||||
) {
|
||||
- return this.getInRange(typePredicate, pos, radius, occupationStatus)
|
||||
- .min(Comparator.comparingDouble(poi -> poi.getPos().distSqr(pos)))
|
||||
- .map(poi -> Pair.of(poi.getPoiType(), poi.getPos()));
|
||||
- return this.getInRange(typePredicate, pos, distance, status)
|
||||
- .min(Comparator.comparingDouble(poiRecord -> poiRecord.getPos().distSqr(pos)))
|
||||
- .map(poiRecord -> Pair.of(poiRecord.getPoiType(), poiRecord.getPos()));
|
||||
+ // Paper start - re-route to faster logic
|
||||
+ return Optional.ofNullable(io.papermc.paper.util.PoiAccess.findClosestPoiDataTypeAndPosition(
|
||||
+ this, typePredicate, null, pos, radius, radius * radius, occupationStatus, false
|
||||
+ this, typePredicate, null, pos, distance, distance * distance, status, false
|
||||
+ ));
|
||||
+ // Paper end - re-route to faster logic
|
||||
}
|
||||
|
||||
public Optional<BlockPos> findClosest(
|
||||
Predicate<Holder<PoiType>> typePredicate, Predicate<BlockPos> posPredicate, BlockPos pos, int radius, PoiManager.Occupancy occupationStatus
|
||||
Predicate<Holder<PoiType>> typePredicate, Predicate<BlockPos> posPredicate, BlockPos pos, int distance, PoiManager.Occupancy status
|
||||
) {
|
||||
- return this.getInRange(typePredicate, pos, radius, occupationStatus)
|
||||
- return this.getInRange(typePredicate, pos, distance, status)
|
||||
- .map(PoiRecord::getPos)
|
||||
- .filter(posPredicate)
|
||||
- .min(Comparator.comparingDouble(poiPos -> poiPos.distSqr(pos)));
|
||||
- .min(Comparator.comparingDouble(blockPos -> blockPos.distSqr(pos)));
|
||||
+ // Paper start - re-route to faster logic
|
||||
+ BlockPos closestPos = io.papermc.paper.util.PoiAccess.findClosestPoiDataPosition(this, typePredicate, posPredicate, pos, radius, radius * radius, occupationStatus, false);
|
||||
+ BlockPos closestPos = io.papermc.paper.util.PoiAccess.findClosestPoiDataPosition(this, typePredicate, posPredicate, pos, distance, distance * distance, status, false);
|
||||
+ return Optional.ofNullable(closestPos);
|
||||
+ // Paper end - re-route to faster logic
|
||||
}
|
||||
|
||||
public Optional<BlockPos> take(Predicate<Holder<PoiType>> typePredicate, BiPredicate<Holder<PoiType>, BlockPos> posPredicate, BlockPos pos, int radius) {
|
||||
- return this.getInRange(typePredicate, pos, radius, PoiManager.Occupancy.HAS_SPACE)
|
||||
- .filter(poi -> posPredicate.test(poi.getPoiType(), poi.getPos()))
|
||||
public Optional<BlockPos> take(
|
||||
Predicate<Holder<PoiType>> typePredicate, BiPredicate<Holder<PoiType>, BlockPos> combinedTypePosPredicate, BlockPos pos, int distance
|
||||
) {
|
||||
- return this.getInRange(typePredicate, pos, distance, PoiManager.Occupancy.HAS_SPACE)
|
||||
- .filter(poiRecord -> combinedTypePosPredicate.test(poiRecord.getPoiType(), poiRecord.getPos()))
|
||||
- .findFirst()
|
||||
+ // Paper start - re-route to faster logic
|
||||
+ final @javax.annotation.Nullable PoiRecord closest = io.papermc.paper.util.PoiAccess.findClosestPoiDataRecord(
|
||||
+ this, typePredicate, posPredicate, pos, radius, radius * radius, Occupancy.HAS_SPACE, false
|
||||
+ this, typePredicate, combinedTypePosPredicate, pos, distance, distance * distance, Occupancy.HAS_SPACE, false
|
||||
+ );
|
||||
+ return Optional.ofNullable(closest)
|
||||
+ // Paper end - re-route to faster logic
|
||||
.map(poi -> {
|
||||
poi.acquireTicket();
|
||||
return poi.getPos();
|
||||
@@ -0,0 +0,0 @@ public class PoiManager extends SectionStorage<PoiSection, PoiSection.Packed> im
|
||||
int radius,
|
||||
.map(poiRecord -> {
|
||||
poiRecord.acquireTicket();
|
||||
return poiRecord.getPos();
|
||||
@@ -298,8 +309,21 @@ public class PoiManager extends SectionStorage<PoiSection, PoiSection.Packed> im
|
||||
int distance,
|
||||
RandomSource random
|
||||
) {
|
||||
- List<PoiRecord> list = Util.toShuffledList(this.getInRange(typePredicate, pos, radius, occupationStatus), random);
|
||||
- return list.stream().filter(poi -> positionPredicate.test(poi.getPos())).findFirst().map(PoiRecord::getPos);
|
||||
- List<PoiRecord> list = Util.toShuffledList(this.getInRange(typePredicate, pos, distance, status), random);
|
||||
- return list.stream().filter(poiRecord -> posPredicate.test(poiRecord.getPos())).findFirst().map(PoiRecord::getPos);
|
||||
+ // Paper start - re-route to faster logic
|
||||
+ List<PoiRecord> list = new java.util.ArrayList<>();
|
||||
+ io.papermc.paper.util.PoiAccess.findAnyPoiRecords(
|
||||
+ this, typePredicate, positionPredicate, pos, radius, occupationStatus, false, Integer.MAX_VALUE, list
|
||||
+ this, typePredicate, posPredicate, pos, distance, status, false, Integer.MAX_VALUE, list
|
||||
+ );
|
||||
+
|
||||
+ // the old method shuffled the list and then tried to find the first element in it that
|
||||
|
@ -979,11 +979,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
}
|
||||
|
||||
public boolean release(BlockPos pos) {
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiSection.java b/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiSection.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiSection.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiSection.java
|
||||
@@ -0,0 +0,0 @@ import org.slf4j.Logger;
|
||||
diff --git a/net/minecraft/world/entity/ai/village/poi/PoiSection.java b/net/minecraft/world/entity/ai/village/poi/PoiSection.java
|
||||
index 39cd1e3d8192d7077d6b7864d33933097cc6b986..b92ba4d194fd3af94c7af5d8e150fc4297c73ab8 100644
|
||||
--- a/net/minecraft/world/entity/ai/village/poi/PoiSection.java
|
||||
+++ b/net/minecraft/world/entity/ai/village/poi/PoiSection.java
|
||||
@@ -26,7 +26,7 @@ import org.slf4j.Logger;
|
||||
public class PoiSection implements ca.spottedleaf.moonrise.patches.chunk_system.level.poi.ChunkSystemPoiSection { // Paper - rewrite chunk system
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
private final Short2ObjectMap<PoiRecord> records = new Short2ObjectOpenHashMap<>();
|
||||
|
@ -992,48 +992,43 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
private final Runnable setDirty;
|
||||
private boolean isValid;
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java
|
||||
@@ -0,0 +0,0 @@ public class SectionStorage<R, P> implements AutoCloseable, ca.spottedleaf.moonr
|
||||
diff --git a/net/minecraft/world/level/chunk/storage/SectionStorage.java b/net/minecraft/world/level/chunk/storage/SectionStorage.java
|
||||
index 778bd73a938c94ecb85ca0f8b686ff4e1baee040..79d4ce7712f16995b0de3be86477fb43ab3961d7 100644
|
||||
--- a/net/minecraft/world/level/chunk/storage/SectionStorage.java
|
||||
+++ b/net/minecraft/world/level/chunk/storage/SectionStorage.java
|
||||
@@ -131,11 +131,11 @@ public class SectionStorage<R, P> implements AutoCloseable, ca.spottedleaf.moonr
|
||||
}
|
||||
|
||||
@Nullable
|
||||
- protected Optional<R> get(long pos) {
|
||||
+ public Optional<R> get(long pos) { // Paper - public
|
||||
return this.storage.get(pos);
|
||||
- protected Optional<R> get(long sectionKey) {
|
||||
+ public Optional<R> get(long sectionKey) { // Paper - public
|
||||
return this.storage.get(sectionKey);
|
||||
}
|
||||
|
||||
- protected Optional<R> getOrLoad(long pos) {
|
||||
+ public Optional<R> getOrLoad(long pos) { // Paper - public
|
||||
if (this.outsideStoredRange(pos)) {
|
||||
- protected Optional<R> getOrLoad(long sectionKey) {
|
||||
+ public Optional<R> getOrLoad(long sectionKey) { // Paper - public
|
||||
if (this.outsideStoredRange(sectionKey)) {
|
||||
return Optional.empty();
|
||||
} else {
|
||||
diff --git a/src/main/java/net/minecraft/world/level/portal/PortalForcer.java b/src/main/java/net/minecraft/world/level/portal/PortalForcer.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/portal/PortalForcer.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/portal/PortalForcer.java
|
||||
@@ -0,0 +0,0 @@ public class PortalForcer {
|
||||
// int i = flag ? 16 : 128;
|
||||
diff --git a/net/minecraft/world/level/portal/PortalForcer.java b/net/minecraft/world/level/portal/PortalForcer.java
|
||||
index ada2da62d3a40d67e64f5f8d7299f78b5c6f53cb..90ae71eb8cc7f925eb212f39731d70f3bff5ef0a 100644
|
||||
--- a/net/minecraft/world/level/portal/PortalForcer.java
|
||||
+++ b/net/minecraft/world/level/portal/PortalForcer.java
|
||||
@@ -48,13 +48,38 @@ public class PortalForcer {
|
||||
PoiManager poiManager = this.level.getPoiManager();
|
||||
// int i = isNether ? 16 : 128;
|
||||
// CraftBukkit end
|
||||
|
||||
- villageplace.ensureLoadedAndValid(this.level, blockposition, i);
|
||||
- Stream<BlockPos> stream = villageplace.getInSquare((holder) -> { // CraftBukkit - decompile error
|
||||
- return holder.is(PoiTypes.NETHER_PORTAL);
|
||||
- }, blockposition, i, PoiManager.Occupancy.ANY).map(PoiRecord::getPos);
|
||||
-
|
||||
- Objects.requireNonNull(worldborder);
|
||||
- return stream.filter(worldborder::isWithinBounds).filter(pos -> !(this.level.getTypeKey() == net.minecraft.world.level.dimension.LevelStem.NETHER && this.level.paperConfig().environment.netherCeilingVoidDamageHeight.test(v -> pos.getY() >= v))).filter((blockposition1) -> { // Paper - Configurable nether ceiling damage
|
||||
- return this.level.getBlockState(blockposition1).hasProperty(BlockStateProperties.HORIZONTAL_AXIS);
|
||||
- }).min(Comparator.comparingDouble((BlockPos blockposition1) -> { // CraftBukkit - decompile error
|
||||
- return blockposition1.distSqr(blockposition);
|
||||
- }).thenComparingInt(Vec3i::getY));
|
||||
- poiManager.ensureLoadedAndValid(this.level, exitPos, i);
|
||||
- return poiManager.getInSquare(holder -> holder.is(PoiTypes.NETHER_PORTAL), exitPos, i, PoiManager.Occupancy.ANY)
|
||||
- .map(PoiRecord::getPos)
|
||||
- .filter(worldBorder::isWithinBounds)
|
||||
- .filter(pos -> !(this.level.getTypeKey() == net.minecraft.world.level.dimension.LevelStem.NETHER && this.level.paperConfig().environment.netherCeilingVoidDamageHeight.test(v -> pos.getY() >= v))) // Paper - Configurable nether ceiling damage
|
||||
- .filter(blockPos -> this.level.getBlockState(blockPos).hasProperty(BlockStateProperties.HORIZONTAL_AXIS))
|
||||
- .min(Comparator.<BlockPos>comparingDouble(blockPos -> blockPos.distSqr(exitPos)).thenComparingInt(Vec3i::getY));
|
||||
+ // Paper start - optimise portals
|
||||
+ Optional<PoiRecord> optional;
|
||||
+ java.util.List<PoiRecord> records = new java.util.ArrayList<>();
|
||||
+ io.papermc.paper.util.PoiAccess.findClosestPoiDataRecords(
|
||||
+ villageplace,
|
||||
+ poiManager,
|
||||
+ type -> type.is(PoiTypes.NETHER_PORTAL),
|
||||
+ (BlockPos pos) -> {
|
||||
+ net.minecraft.world.level.chunk.ChunkAccess lowest = this.level.getChunk(pos.getX() >> 4, pos.getZ() >> 4, net.minecraft.world.level.chunk.status.ChunkStatus.EMPTY);
|
||||
|
@ -1042,12 +1037,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ // why would we generate the chunk?
|
||||
+ return false;
|
||||
+ }
|
||||
+ if (!worldborder.isWithinBounds(pos) || (this.level.getTypeKey() == net.minecraft.world.level.dimension.LevelStem.NETHER && this.level.paperConfig().environment.netherCeilingVoidDamageHeight.test(v -> pos.getY() >= v))) { // Paper - Configurable nether ceiling damage
|
||||
+ if (!worldBorder.isWithinBounds(pos) || (this.level.getTypeKey() == net.minecraft.world.level.dimension.LevelStem.NETHER && this.level.paperConfig().environment.netherCeilingVoidDamageHeight.test(v -> pos.getY() >= v))) { // Paper - Configurable nether ceiling damage
|
||||
+ return false;
|
||||
+ }
|
||||
+ return lowest.getBlockState(pos).hasProperty(BlockStateProperties.HORIZONTAL_AXIS);
|
||||
+ },
|
||||
+ blockposition, i, Double.MAX_VALUE, PoiManager.Occupancy.ANY, true, records
|
||||
+ exitPos, i, Double.MAX_VALUE, PoiManager.Occupancy.ANY, true, records
|
||||
+ );
|
||||
+
|
||||
+ // this gets us most of the way there, but we bias towards lower y values.
|
|
@ -0,0 +1,236 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: kickash32 <kickash32@gmail.com>
|
||||
Date: Mon, 19 Aug 2019 01:27:58 +0500
|
||||
Subject: [PATCH] Optional per player mob spawns
|
||||
|
||||
|
||||
diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java
|
||||
index ff6503bf8eb88d1264c3d848a89d0255b4b3ae68..9eed24939fc09f00a9dbce1be2ab9c34d024fd29 100644
|
||||
--- a/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -236,11 +236,29 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
// Paper - rewrite chunk system
|
||||
}
|
||||
|
||||
- // Paper start
|
||||
- public int getMobCountNear(final ServerPlayer player, final net.minecraft.world.entity.MobCategory mobCategory) {
|
||||
- return -1;
|
||||
+ // Paper start - Optional per player mob spawns
|
||||
+ public void updatePlayerMobTypeMap(final Entity entity) {
|
||||
+ if (!this.level.paperConfig().entities.spawning.perPlayerMobSpawns) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ final int index = entity.getType().getCategory().ordinal();
|
||||
+ final ca.spottedleaf.moonrise.common.list.ReferenceList<ServerPlayer> inRange =
|
||||
+ this.level.moonrise$getNearbyPlayers().getPlayers(entity.chunkPosition(), ca.spottedleaf.moonrise.common.misc.NearbyPlayers.NearbyMapType.TICK_VIEW_DISTANCE);
|
||||
+ if (inRange == null) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ final ServerPlayer[] backingSet = inRange.getRawDataUnchecked();
|
||||
+ for (int i = 0, len = inRange.size(); i < len; i++) {
|
||||
+ ++(backingSet[i].mobCounts[index]);
|
||||
+ }
|
||||
}
|
||||
- // Paper end
|
||||
+
|
||||
+ public int getMobCountNear(final ServerPlayer player, final net.minecraft.world.entity.MobCategory mobCategory) {
|
||||
+ return player.mobCounts[mobCategory.ordinal()];
|
||||
+ }
|
||||
+ // Paper end - Optional per player mob spawns
|
||||
|
||||
protected ChunkGenerator generator() {
|
||||
return this.worldGenContext.generator();
|
||||
diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java
|
||||
index 87d4291a3944f706a694536da6de0f28c548ab8d..5576bf1d1d70ab7a010653d3207909b5de867e70 100644
|
||||
--- a/net/minecraft/server/level/ServerChunkCache.java
|
||||
+++ b/net/minecraft/server/level/ServerChunkCache.java
|
||||
@@ -517,7 +517,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
||||
profilerFiller.popPush("shuffleChunks");
|
||||
// Paper start - chunk tick iteration optimisation
|
||||
this.shuffleRandom.setSeed(this.level.random.nextLong());
|
||||
- Util.shuffle(list, this.shuffleRandom);
|
||||
+ if (!this.level.paperConfig().entities.spawning.perPlayerMobSpawns) Util.shuffle(list, this.shuffleRandom); // Paper - Optional per player mob spawns; do not need this when per-player is enabled
|
||||
// Paper end - chunk tick iteration optimisation
|
||||
this.tickChunks(profilerFiller, l, list);
|
||||
profilerFiller.pop();
|
||||
@@ -571,9 +571,18 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
||||
private void tickChunks(ProfilerFiller profiler, long timeInhabited, List<LevelChunk> chunks) {
|
||||
profiler.popPush("naturalSpawnCount");
|
||||
int naturalSpawnChunkCount = this.distanceManager.getNaturalSpawnChunkCount();
|
||||
- NaturalSpawner.SpawnState spawnState = NaturalSpawner.createState(
|
||||
- naturalSpawnChunkCount, this.level.getAllEntities(), this::getFullChunk, new LocalMobCapCalculator(this.chunkMap)
|
||||
- );
|
||||
+ // Paper start - Optional per player mob spawns
|
||||
+ NaturalSpawner.SpawnState spawnState;
|
||||
+ if ((this.spawnFriendlies || this.spawnEnemies) && this.level.paperConfig().entities.spawning.perPlayerMobSpawns) { // don't count mobs when animals and monsters are disabled
|
||||
+ // re-set mob counts
|
||||
+ for (ServerPlayer player : this.level.players) {
|
||||
+ Arrays.fill(player.mobCounts, 0);
|
||||
+ }
|
||||
+ spawnState = NaturalSpawner.createState(naturalSpawnChunkCount, this.level.getAllEntities(), this::getFullChunk, null, true);
|
||||
+ } else {
|
||||
+ spawnState = NaturalSpawner.createState(naturalSpawnChunkCount, this.level.getAllEntities(), this::getFullChunk, !this.level.paperConfig().entities.spawning.perPlayerMobSpawns ? new LocalMobCapCalculator(this.chunkMap) : null, false);
|
||||
+ }
|
||||
+ // Paper end - Optional per player mob spawns
|
||||
this.lastSpawnState = spawnState;
|
||||
profiler.popPush("spawnAndTick");
|
||||
boolean _boolean = this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && !this.level.players().isEmpty(); // CraftBukkit
|
||||
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
|
||||
index 0a7e5106a1d39150326e7c323030df5d32ecef1e..a63702dd7e86fc8b9f78c2ae23e23b65b6b2ee24 100644
|
||||
--- a/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -368,6 +368,10 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
|
||||
public boolean queueHealthUpdatePacket;
|
||||
public net.minecraft.network.protocol.game.ClientboundSetHealthPacket queuedHealthUpdatePacket;
|
||||
// Paper end - cancellable death event
|
||||
+ // Paper start - Optional per player mob spawns
|
||||
+ public static final int MOBCATEGORY_TOTAL_ENUMS = net.minecraft.world.entity.MobCategory.values().length;
|
||||
+ public final int[] mobCounts = new int[MOBCATEGORY_TOTAL_ENUMS];
|
||||
+ // Paper end - Optional per player mob spawns
|
||||
// CraftBukkit start
|
||||
public org.bukkit.craftbukkit.entity.CraftPlayer.TransferCookieConnection transferCookieConnection;
|
||||
public String displayName;
|
||||
diff --git a/net/minecraft/world/level/NaturalSpawner.java b/net/minecraft/world/level/NaturalSpawner.java
|
||||
index 913ea92ace9d610c25bf28f703a3b227044aea63..ef8bacbbb43a9b80281a313ca43b7efff5a93e03 100644
|
||||
--- a/net/minecraft/world/level/NaturalSpawner.java
|
||||
+++ b/net/minecraft/world/level/NaturalSpawner.java
|
||||
@@ -72,6 +72,14 @@ public final class NaturalSpawner {
|
||||
public static NaturalSpawner.SpawnState createState(
|
||||
int spawnableChunkCount, Iterable<Entity> entities, NaturalSpawner.ChunkGetter chunkGetter, LocalMobCapCalculator calculator
|
||||
) {
|
||||
+ // Paper start - Optional per player mob spawns
|
||||
+ return createState(spawnableChunkCount, entities, chunkGetter, calculator, false);
|
||||
+ }
|
||||
+
|
||||
+ public static NaturalSpawner.SpawnState createState(
|
||||
+ int spawnableChunkCount, Iterable<Entity> entities, NaturalSpawner.ChunkGetter chunkGetter, LocalMobCapCalculator calculator, final boolean countMobs
|
||||
+ ) {
|
||||
+ // Paper end - Optional per player mob spawns
|
||||
PotentialCalculator potentialCalculator = new PotentialCalculator();
|
||||
Object2IntOpenHashMap<MobCategory> map = new Object2IntOpenHashMap<>();
|
||||
|
||||
@@ -93,11 +101,16 @@ public final class NaturalSpawner {
|
||||
potentialCalculator.addCharge(entity.blockPosition(), mobSpawnCost.charge());
|
||||
}
|
||||
|
||||
- if (entity instanceof Mob) {
|
||||
+ if (calculator != null && entity instanceof Mob) { // Paper - Optional per player mob spawns
|
||||
calculator.addMob(chunk.getPos(), category);
|
||||
}
|
||||
|
||||
map.addTo(category, 1);
|
||||
+ // Paper start - Optional per player mob spawns
|
||||
+ if (countMobs) {
|
||||
+ chunk.level.getChunkSource().chunkMap.updatePlayerMobTypeMap(entity);
|
||||
+ }
|
||||
+ // Paper end - Optional per player mob spawns
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -135,7 +148,7 @@ public final class NaturalSpawner {
|
||||
if ((spawnFriendlies || !mobCategory.isFriendly())
|
||||
&& (spawnEnemies || mobCategory.isFriendly())
|
||||
&& (spawnPassives || !mobCategory.isPersistent())
|
||||
- && spawnState.canSpawnForCategoryGlobal(mobCategory, limit)) { // Paper - Optional per player mob spawns; remove global check, check later during the local one
|
||||
+ && (level.paperConfig().entities.spawning.perPlayerMobSpawns || spawnState.canSpawnForCategoryGlobal(mobCategory, limit))) { // Paper - Optional per player mob spawns; remove global check, check later during the local one
|
||||
list.add(mobCategory);
|
||||
// CraftBukkit end
|
||||
}
|
||||
@@ -149,8 +162,37 @@ public final class NaturalSpawner {
|
||||
profilerFiller.push("spawner");
|
||||
|
||||
for (MobCategory mobCategory : categories) {
|
||||
- if (spawnState.canSpawnForCategoryLocal(mobCategory, chunk.getPos())) {
|
||||
- spawnCategoryForChunk(mobCategory, level, chunk, spawnState::canSpawn, spawnState::afterSpawn);
|
||||
+ // Paper start - Optional per player mob spawns
|
||||
+ final boolean canSpawn;
|
||||
+ int maxSpawns = Integer.MAX_VALUE;
|
||||
+ if (level.paperConfig().entities.spawning.perPlayerMobSpawns) {
|
||||
+ // Copied from getFilteredSpawningCategories
|
||||
+ int limit = mobCategory.getMaxInstancesPerChunk();
|
||||
+ SpawnCategory spawnCategory = CraftSpawnCategory.toBukkit(mobCategory);
|
||||
+ if (CraftSpawnCategory.isValidForLimits(spawnCategory)) {
|
||||
+ limit = level.getWorld().getSpawnLimit(spawnCategory);
|
||||
+ }
|
||||
+
|
||||
+ // Apply per-player limit
|
||||
+ int minDiff = Integer.MAX_VALUE;
|
||||
+ final ca.spottedleaf.moonrise.common.list.ReferenceList<net.minecraft.server.level.ServerPlayer> inRange =
|
||||
+ level.moonrise$getNearbyPlayers().getPlayers(chunk.getPos(), ca.spottedleaf.moonrise.common.misc.NearbyPlayers.NearbyMapType.TICK_VIEW_DISTANCE);
|
||||
+ if (inRange != null) {
|
||||
+ final net.minecraft.server.level.ServerPlayer[] backingSet = inRange.getRawDataUnchecked();
|
||||
+ for (int k = 0, len = inRange.size(); k < len; k++) {
|
||||
+ minDiff = Math.min(limit - level.getChunkSource().chunkMap.getMobCountNear(backingSet[k], mobCategory), minDiff);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ maxSpawns = (minDiff == Integer.MAX_VALUE) ? 0 : minDiff;
|
||||
+ canSpawn = maxSpawns > 0;
|
||||
+ } else {
|
||||
+ canSpawn = spawnState.canSpawnForCategoryLocal(mobCategory, chunk.getPos());
|
||||
+ }
|
||||
+ if (canSpawn) {
|
||||
+ spawnCategoryForChunk(mobCategory, level, chunk, spawnState::canSpawn, spawnState::afterSpawn,
|
||||
+ maxSpawns, level.paperConfig().entities.spawning.perPlayerMobSpawns ? level.getChunkSource().chunkMap::updatePlayerMobTypeMap : null);
|
||||
+ // Paper end - Optional per player mob spawns
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,9 +212,16 @@ public final class NaturalSpawner {
|
||||
public static void spawnCategoryForChunk(
|
||||
MobCategory category, ServerLevel level, LevelChunk chunk, NaturalSpawner.SpawnPredicate filter, NaturalSpawner.AfterSpawnCallback callback
|
||||
) {
|
||||
+ // Paper start - Optional per player mob spawns
|
||||
+ spawnCategoryForChunk(category, level, chunk, filter, callback, Integer.MAX_VALUE, null);
|
||||
+ }
|
||||
+ public static void spawnCategoryForChunk(
|
||||
+ MobCategory category, ServerLevel level, LevelChunk chunk, NaturalSpawner.SpawnPredicate filter, NaturalSpawner.AfterSpawnCallback callback, final int maxSpawns, final Consumer<Entity> trackEntity
|
||||
+ ) {
|
||||
+ // Paper end - Optional per player mob spawns
|
||||
BlockPos randomPosWithin = getRandomPosWithin(level, chunk);
|
||||
if (randomPosWithin.getY() >= level.getMinY() + 1) {
|
||||
- spawnCategoryForPosition(category, level, chunk, randomPosWithin, filter, callback);
|
||||
+ spawnCategoryForPosition(category, level, chunk, randomPosWithin, filter, callback, maxSpawns, trackEntity); // Paper - Optional per player mob spawns
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,6 +238,12 @@ public final class NaturalSpawner {
|
||||
NaturalSpawner.SpawnPredicate filter,
|
||||
NaturalSpawner.AfterSpawnCallback callback
|
||||
) {
|
||||
+ spawnCategoryForPosition(category, level, chunk, pos, filter, callback, Integer.MAX_VALUE, null);
|
||||
+ }
|
||||
+ public static void spawnCategoryForPosition(
|
||||
+ MobCategory category, ServerLevel level, ChunkAccess chunk, BlockPos pos, NaturalSpawner.SpawnPredicate filter, NaturalSpawner.AfterSpawnCallback callback, final int maxSpawns, final @Nullable Consumer<Entity> trackEntity
|
||||
+ ) {
|
||||
+ // Paper end - Optional per player mob spawns
|
||||
StructureManager structureManager = level.structureManager();
|
||||
ChunkGenerator generator = level.getChunkSource().getGenerator();
|
||||
int y = pos.getY();
|
||||
@@ -252,9 +307,14 @@ public final class NaturalSpawner {
|
||||
++i;
|
||||
++i3;
|
||||
callback.run(mobForSpawn, chunk);
|
||||
+ // Paper start - Optional per player mob spawns
|
||||
+ if (trackEntity != null) {
|
||||
+ trackEntity.accept(mobForSpawn);
|
||||
+ }
|
||||
+ // Paper end - Optional per player mob spawns
|
||||
}
|
||||
// CraftBukkit end
|
||||
- if (i >= mobForSpawn.getMaxSpawnClusterSize()) {
|
||||
+ if (i >= mobForSpawn.getMaxSpawnClusterSize() || i >= maxSpawns) { // Paper - Optional per player mob spawns
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -565,7 +625,7 @@ public final class NaturalSpawner {
|
||||
this.spawnPotential.addCharge(blockPos, d);
|
||||
MobCategory category = type.getCategory();
|
||||
this.mobCategoryCounts.addTo(category, 1);
|
||||
- this.localMobCapCalculator.addMob(new ChunkPos(blockPos), category);
|
||||
+ if (this.localMobCapCalculator != null) this.localMobCapCalculator.addMob(new ChunkPos(blockPos), category); // Paper - Optional per player mob spawns
|
||||
}
|
||||
|
||||
public int getSpawnableChunkCount() {
|
|
@ -0,0 +1,89 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: kickash32 <kickash32@gmail.com>
|
||||
Date: Mon, 5 Apr 2021 01:42:35 -0400
|
||||
Subject: [PATCH] Improve cancelling PreCreatureSpawnEvent with per player mob
|
||||
spawns
|
||||
|
||||
|
||||
diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java
|
||||
index 9eed24939fc09f00a9dbce1be2ab9c34d024fd29..b3f498558614243cf633dcd71e3c49c2c55e6e0f 100644
|
||||
--- a/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -255,8 +255,25 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
}
|
||||
}
|
||||
|
||||
+ // Paper start - per player mob count backoff
|
||||
+ public void updateFailurePlayerMobTypeMap(int chunkX, int chunkZ, net.minecraft.world.entity.MobCategory mobCategory) {
|
||||
+ if (!this.level.paperConfig().entities.spawning.perPlayerMobSpawns) {
|
||||
+ return;
|
||||
+ }
|
||||
+ int idx = mobCategory.ordinal();
|
||||
+ final ca.spottedleaf.moonrise.common.list.ReferenceList<ServerPlayer> inRange =
|
||||
+ this.level.moonrise$getNearbyPlayers().getPlayersByChunk(chunkX, chunkZ, ca.spottedleaf.moonrise.common.misc.NearbyPlayers.NearbyMapType.TICK_VIEW_DISTANCE);
|
||||
+ if (inRange == null) {
|
||||
+ return;
|
||||
+ }
|
||||
+ final ServerPlayer[] backingSet = inRange.getRawDataUnchecked();
|
||||
+ for (int i = 0, len = inRange.size(); i < len; i++) {
|
||||
+ ++(backingSet[i].mobBackoffCounts[idx]);
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - per player mob count backoff
|
||||
public int getMobCountNear(final ServerPlayer player, final net.minecraft.world.entity.MobCategory mobCategory) {
|
||||
- return player.mobCounts[mobCategory.ordinal()];
|
||||
+ return player.mobCounts[mobCategory.ordinal()] + player.mobBackoffCounts[mobCategory.ordinal()]; // Paper - per player mob count backoff
|
||||
}
|
||||
// Paper end - Optional per player mob spawns
|
||||
|
||||
diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java
|
||||
index 5576bf1d1d70ab7a010653d3207909b5de867e70..6540b2d6a1062d883811ce240c49d30d1925b291 100644
|
||||
--- a/net/minecraft/server/level/ServerChunkCache.java
|
||||
+++ b/net/minecraft/server/level/ServerChunkCache.java
|
||||
@@ -576,7 +576,17 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
||||
if ((this.spawnFriendlies || this.spawnEnemies) && this.level.paperConfig().entities.spawning.perPlayerMobSpawns) { // don't count mobs when animals and monsters are disabled
|
||||
// re-set mob counts
|
||||
for (ServerPlayer player : this.level.players) {
|
||||
- Arrays.fill(player.mobCounts, 0);
|
||||
+ // Paper start - per player mob spawning backoff
|
||||
+ for (int ii = 0; ii < ServerPlayer.MOBCATEGORY_TOTAL_ENUMS; ii++) {
|
||||
+ player.mobCounts[ii] = 0;
|
||||
+
|
||||
+ int newBackoff = player.mobBackoffCounts[ii] - 1; // TODO make configurable bleed // TODO use nonlinear algorithm?
|
||||
+ if (newBackoff < 0) {
|
||||
+ newBackoff = 0;
|
||||
+ }
|
||||
+ player.mobBackoffCounts[ii] = newBackoff;
|
||||
+ }
|
||||
+ // Paper end - per player mob spawning backoff
|
||||
}
|
||||
spawnState = NaturalSpawner.createState(naturalSpawnChunkCount, this.level.getAllEntities(), this::getFullChunk, null, true);
|
||||
} else {
|
||||
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
|
||||
index a63702dd7e86fc8b9f78c2ae23e23b65b6b2ee24..6d75a641431c7deb7e8ddbf02cdc919015a3a7dc 100644
|
||||
--- a/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -372,6 +372,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
|
||||
public static final int MOBCATEGORY_TOTAL_ENUMS = net.minecraft.world.entity.MobCategory.values().length;
|
||||
public final int[] mobCounts = new int[MOBCATEGORY_TOTAL_ENUMS];
|
||||
// Paper end - Optional per player mob spawns
|
||||
+ public final int[] mobBackoffCounts = new int[MOBCATEGORY_TOTAL_ENUMS]; // Paper - per player mob count backoff
|
||||
// CraftBukkit start
|
||||
public org.bukkit.craftbukkit.entity.CraftPlayer.TransferCookieConnection transferCookieConnection;
|
||||
public String displayName;
|
||||
diff --git a/net/minecraft/world/level/NaturalSpawner.java b/net/minecraft/world/level/NaturalSpawner.java
|
||||
index ef8bacbbb43a9b80281a313ca43b7efff5a93e03..17ce115e887cbbb06ad02ab7ddb488e27342c0e4 100644
|
||||
--- a/net/minecraft/world/level/NaturalSpawner.java
|
||||
+++ b/net/minecraft/world/level/NaturalSpawner.java
|
||||
@@ -285,6 +285,11 @@ public final class NaturalSpawner {
|
||||
|
||||
// Paper start - PreCreatureSpawnEvent
|
||||
PreSpawnStatus doSpawning = isValidSpawnPostitionForType(level, category, structureManager, generator, spawnerData, mutableBlockPos, d2);
|
||||
+ // Paper start - per player mob count backoff
|
||||
+ if (doSpawning == PreSpawnStatus.ABORT || doSpawning == PreSpawnStatus.CANCELLED) {
|
||||
+ level.getChunkSource().chunkMap.updateFailurePlayerMobTypeMap(mutableBlockPos.getX() >> 4, mutableBlockPos.getZ() >> 4, category);
|
||||
+ }
|
||||
+ // Paper end - per player mob count backoff
|
||||
if (doSpawning == PreSpawnStatus.ABORT) {
|
||||
return;
|
||||
}
|
683
paper-server/patches/features/0029-Optimize-Hoppers.patch
Normal file
683
paper-server/patches/features/0029-Optimize-Hoppers.patch
Normal file
|
@ -0,0 +1,683 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Wed, 27 Apr 2016 22:09:52 -0400
|
||||
Subject: [PATCH] Optimize Hoppers
|
||||
|
||||
* Removes unnecessary extra calls to .update() that are very expensive
|
||||
* Lots of itemstack cloning removed. Only clone if the item is actually moved
|
||||
* Return true when a plugin cancels inventory move item event instead of false, as false causes pulls to cycle through all items.
|
||||
However, pushes do not exhibit the same behavior, so this is not something plugins could of been relying on.
|
||||
* Add option (Default on) to cooldown hoppers when they fail to move an item due to full inventory
|
||||
* Skip subsequent InventoryMoveItemEvents if a plugin does not use the item after first event fire for an iteration by tracking changes to the event via an internal event implementation.
|
||||
* Don't check for Entities with Inventories if the block above us is also occluding (not just Inventoried)
|
||||
* Remove Streams from Item Suck In and restore restore 1.12 AABB checks which is simpler and no voxel allocations (was doing TWO Item Suck ins)
|
||||
|
||||
diff --git a/io/papermc/paper/event/inventory/PaperInventoryMoveItemEvent.java b/io/papermc/paper/event/inventory/PaperInventoryMoveItemEvent.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..24a2090e068ad3c0d08705050944abdfe19136a2
|
||||
--- /dev/null
|
||||
+++ b/io/papermc/paper/event/inventory/PaperInventoryMoveItemEvent.java
|
||||
@@ -0,0 +1,29 @@
|
||||
+package io.papermc.paper.event.inventory;
|
||||
+
|
||||
+import org.bukkit.event.inventory.InventoryMoveItemEvent;
|
||||
+import org.bukkit.inventory.Inventory;
|
||||
+import org.bukkit.inventory.ItemStack;
|
||||
+import org.jspecify.annotations.NullMarked;
|
||||
+
|
||||
+@NullMarked
|
||||
+public class PaperInventoryMoveItemEvent extends InventoryMoveItemEvent {
|
||||
+
|
||||
+ public boolean calledSetItem;
|
||||
+ public boolean calledGetItem;
|
||||
+
|
||||
+ public PaperInventoryMoveItemEvent(final Inventory sourceInventory, final ItemStack itemStack, final Inventory destinationInventory, final boolean didSourceInitiate) {
|
||||
+ super(sourceInventory, itemStack, destinationInventory, didSourceInitiate);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public ItemStack getItem() {
|
||||
+ this.calledGetItem = true;
|
||||
+ return super.getItem();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setItem(final ItemStack itemStack) {
|
||||
+ super.setItem(itemStack);
|
||||
+ this.calledSetItem = true;
|
||||
+ }
|
||||
+}
|
||||
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
|
||||
index 6dbae12bbfd47cd4e75bc3089561e8e226e9e604..9c859025302ddb2c20cf6457fa4e4eaf7fbafdd7 100644
|
||||
--- a/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/net/minecraft/server/MinecraftServer.java
|
||||
@@ -1707,6 +1707,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
serverLevel.hasPhysicsEvent = org.bukkit.event.block.BlockPhysicsEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - BlockPhysicsEvent
|
||||
serverLevel.hasEntityMoveEvent = io.papermc.paper.event.entity.EntityMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - Add EntityMoveEvent
|
||||
serverLevel.updateLagCompensationTick(); // Paper - lag compensation
|
||||
+ net.minecraft.world.level.block.entity.HopperBlockEntity.skipHopperEvents = serverLevel.paperConfig().hopper.disableMoveEvent || org.bukkit.event.inventory.InventoryMoveItemEvent.getHandlerList().getRegisteredListeners().length == 0; // Paper - Perf: Optimize Hoppers
|
||||
profilerFiller.push(() -> serverLevel + " " + serverLevel.dimension().location());
|
||||
/* Drop global time updates
|
||||
if (this.tickCount % 20 == 0) {
|
||||
diff --git a/net/minecraft/world/item/ItemStack.java b/net/minecraft/world/item/ItemStack.java
|
||||
index c255e11cb0981bd7e0456d4fd401beb5257be597..d6361863d6a1e364de262d6199373cbd68d1c699 100644
|
||||
--- a/net/minecraft/world/item/ItemStack.java
|
||||
+++ b/net/minecraft/world/item/ItemStack.java
|
||||
@@ -808,10 +808,16 @@ public final class ItemStack implements DataComponentHolder {
|
||||
}
|
||||
|
||||
public ItemStack copy() {
|
||||
- if (this.isEmpty()) {
|
||||
+ // Paper start - Perf: Optimize Hoppers
|
||||
+ return this.copy(false);
|
||||
+ }
|
||||
+
|
||||
+ public ItemStack copy(final boolean originalItem) {
|
||||
+ if (!originalItem && this.isEmpty()) {
|
||||
+ // Paper end - Perf: Optimize Hoppers
|
||||
return EMPTY;
|
||||
} else {
|
||||
- ItemStack itemStack = new ItemStack(this.getItem(), this.count, this.components.copy());
|
||||
+ ItemStack itemStack = new ItemStack(originalItem ? this.item : this.getItem(), this.count, this.components.copy()); // Paper - Perf: Optimize Hoppers
|
||||
itemStack.setPopTime(this.getPopTime());
|
||||
return itemStack;
|
||||
}
|
||||
diff --git a/net/minecraft/world/level/block/entity/BlockEntity.java b/net/minecraft/world/level/block/entity/BlockEntity.java
|
||||
index 2ebdf1ad323bb53dfe9eed319e25856b35a1443c..77618757c0e678532dbab814aceed83f7f1cd892 100644
|
||||
--- a/net/minecraft/world/level/block/entity/BlockEntity.java
|
||||
+++ b/net/minecraft/world/level/block/entity/BlockEntity.java
|
||||
@@ -26,6 +26,7 @@ import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
public abstract class BlockEntity {
|
||||
+ static boolean ignoreBlockEntityUpdates; // Paper - Perf: Optimize Hoppers
|
||||
// CraftBukkit start - data containers
|
||||
private static final org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry DATA_TYPE_REGISTRY = new org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry();
|
||||
public org.bukkit.craftbukkit.persistence.CraftPersistentDataContainer persistentDataContainer;
|
||||
@@ -196,6 +197,7 @@ public abstract class BlockEntity {
|
||||
|
||||
public void setChanged() {
|
||||
if (this.level != null) {
|
||||
+ if (ignoreBlockEntityUpdates) return; // Paper - Perf: Optimize Hoppers
|
||||
setChanged(this.level, this.worldPosition, this.blockState);
|
||||
}
|
||||
}
|
||||
diff --git a/net/minecraft/world/level/block/entity/HopperBlockEntity.java b/net/minecraft/world/level/block/entity/HopperBlockEntity.java
|
||||
index e58a32593e8b42bfc534d13457240860293dd3f4..5cd1326ad5d046c88b2b3449d610a78fa880b4cd 100644
|
||||
--- a/net/minecraft/world/level/block/entity/HopperBlockEntity.java
|
||||
+++ b/net/minecraft/world/level/block/entity/HopperBlockEntity.java
|
||||
@@ -139,18 +139,56 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
||||
}
|
||||
}
|
||||
|
||||
+ // Paper start - Perf: Optimize Hoppers
|
||||
+ private static final int HOPPER_EMPTY = 0;
|
||||
+ private static final int HOPPER_HAS_ITEMS = 1;
|
||||
+ private static final int HOPPER_IS_FULL = 2;
|
||||
+
|
||||
+ private static int getFullState(final HopperBlockEntity hopper) {
|
||||
+ hopper.unpackLootTable(null);
|
||||
+
|
||||
+ final List<ItemStack> hopperItems = hopper.items;
|
||||
+
|
||||
+ boolean empty = true;
|
||||
+ boolean full = true;
|
||||
+
|
||||
+ for (int i = 0, len = hopperItems.size(); i < len; ++i) {
|
||||
+ final ItemStack stack = hopperItems.get(i);
|
||||
+ if (stack.isEmpty()) {
|
||||
+ full = false;
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (!full) {
|
||||
+ // can't be full
|
||||
+ return HOPPER_HAS_ITEMS;
|
||||
+ }
|
||||
+
|
||||
+ empty = false;
|
||||
+
|
||||
+ if (stack.getCount() != stack.getMaxStackSize()) {
|
||||
+ // can't be full or empty
|
||||
+ return HOPPER_HAS_ITEMS;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return empty ? HOPPER_EMPTY : (full ? HOPPER_IS_FULL : HOPPER_HAS_ITEMS);
|
||||
+ }
|
||||
+ // Paper end - Perf: Optimize Hoppers
|
||||
+
|
||||
private static boolean tryMoveItems(Level level, BlockPos pos, BlockState state, HopperBlockEntity blockEntity, BooleanSupplier validator) {
|
||||
if (level.isClientSide) {
|
||||
return false;
|
||||
} else {
|
||||
if (!blockEntity.isOnCooldown() && state.getValue(HopperBlock.ENABLED)) {
|
||||
boolean flag = false;
|
||||
- if (!blockEntity.isEmpty()) {
|
||||
+ final int fullState = getFullState(blockEntity); // Paper - Perf: Optimize Hoppers
|
||||
+ if (fullState != HOPPER_EMPTY) { // Paper - Perf: Optimize Hoppers
|
||||
flag = ejectItems(level, pos, blockEntity);
|
||||
}
|
||||
|
||||
- if (!blockEntity.inventoryFull()) {
|
||||
- flag |= validator.getAsBoolean();
|
||||
+ if (fullState != HOPPER_IS_FULL || flag) { // Paper - Perf: Optimize Hoppers
|
||||
+ flag |= validator.getAsBoolean(); // Paper - note: this is not a validator, it's what adds/sucks in items
|
||||
}
|
||||
|
||||
if (flag) {
|
||||
@@ -174,6 +212,206 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
||||
return true;
|
||||
}
|
||||
|
||||
+ // Paper start - Perf: Optimize Hoppers
|
||||
+ public static boolean skipHopperEvents;
|
||||
+ private static boolean skipPullModeEventFire;
|
||||
+ private static boolean skipPushModeEventFire;
|
||||
+
|
||||
+ private static boolean hopperPush(final Level level, final Container destination, final Direction direction, final HopperBlockEntity hopper) {
|
||||
+ skipPushModeEventFire = skipHopperEvents;
|
||||
+ boolean foundItem = false;
|
||||
+ for (int i = 0; i < hopper.getContainerSize(); ++i) {
|
||||
+ final ItemStack item = hopper.getItem(i);
|
||||
+ if (!item.isEmpty()) {
|
||||
+ foundItem = true;
|
||||
+ ItemStack origItemStack = item;
|
||||
+ ItemStack movedItem = origItemStack;
|
||||
+
|
||||
+ final int originalItemCount = origItemStack.getCount();
|
||||
+ final int movedItemCount = Math.min(level.spigotConfig.hopperAmount, originalItemCount);
|
||||
+ origItemStack.setCount(movedItemCount);
|
||||
+
|
||||
+ // We only need to fire the event once to give protection plugins a chance to cancel this event
|
||||
+ // Because nothing uses getItem, every event call should end up the same result.
|
||||
+ if (!skipPushModeEventFire) {
|
||||
+ movedItem = callPushMoveEvent(destination, movedItem, hopper);
|
||||
+ if (movedItem == null) { // cancelled
|
||||
+ origItemStack.setCount(originalItemCount);
|
||||
+ return false;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ final ItemStack remainingItem = addItem(hopper, destination, movedItem, direction);
|
||||
+ final int remainingItemCount = remainingItem.getCount();
|
||||
+ if (remainingItemCount != movedItemCount) {
|
||||
+ origItemStack = origItemStack.copy(true);
|
||||
+ origItemStack.setCount(originalItemCount);
|
||||
+ if (!origItemStack.isEmpty()) {
|
||||
+ origItemStack.setCount(originalItemCount - movedItemCount + remainingItemCount);
|
||||
+ }
|
||||
+ hopper.setItem(i, origItemStack);
|
||||
+ destination.setChanged();
|
||||
+ return true;
|
||||
+ }
|
||||
+ origItemStack.setCount(originalItemCount);
|
||||
+ }
|
||||
+ }
|
||||
+ if (foundItem && level.paperConfig().hopper.cooldownWhenFull) { // Inventory was full - cooldown
|
||||
+ hopper.setCooldown(level.spigotConfig.hopperTransfer);
|
||||
+ }
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ private static boolean hopperPull(final Level level, final Hopper hopper, final Container container, ItemStack origItemStack, final int i) {
|
||||
+ ItemStack movedItem = origItemStack;
|
||||
+ final int originalItemCount = origItemStack.getCount();
|
||||
+ final int movedItemCount = Math.min(level.spigotConfig.hopperAmount, originalItemCount);
|
||||
+ container.setChanged(); // original logic always marks source inv as changed even if no move happens.
|
||||
+ movedItem.setCount(movedItemCount);
|
||||
+
|
||||
+ if (!skipPullModeEventFire) {
|
||||
+ movedItem = callPullMoveEvent(hopper, container, movedItem);
|
||||
+ if (movedItem == null) { // cancelled
|
||||
+ origItemStack.setCount(originalItemCount);
|
||||
+ // Drastically improve performance by returning true.
|
||||
+ // No plugin could have relied on the behavior of false as the other call
|
||||
+ // site for IMIE did not exhibit the same behavior
|
||||
+ return true;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ final ItemStack remainingItem = addItem(container, hopper, movedItem, null);
|
||||
+ final int remainingItemCount = remainingItem.getCount();
|
||||
+ if (remainingItemCount != movedItemCount) {
|
||||
+ origItemStack = origItemStack.copy(true);
|
||||
+ origItemStack.setCount(originalItemCount);
|
||||
+ if (!origItemStack.isEmpty()) {
|
||||
+ origItemStack.setCount(originalItemCount - movedItemCount + remainingItemCount);
|
||||
+ }
|
||||
+
|
||||
+ ignoreBlockEntityUpdates = true;
|
||||
+ container.setItem(i, origItemStack);
|
||||
+ ignoreBlockEntityUpdates = false;
|
||||
+ container.setChanged();
|
||||
+ return true;
|
||||
+ }
|
||||
+ origItemStack.setCount(originalItemCount);
|
||||
+
|
||||
+ if (level.paperConfig().hopper.cooldownWhenFull) {
|
||||
+ applyCooldown(hopper);
|
||||
+ }
|
||||
+
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ @Nullable
|
||||
+ private static ItemStack callPushMoveEvent(Container destination, ItemStack itemStack, HopperBlockEntity hopper) {
|
||||
+ final org.bukkit.inventory.Inventory destinationInventory = getInventory(destination);
|
||||
+ final io.papermc.paper.event.inventory.PaperInventoryMoveItemEvent event = new io.papermc.paper.event.inventory.PaperInventoryMoveItemEvent(
|
||||
+ hopper.getOwner(false).getInventory(),
|
||||
+ org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack),
|
||||
+ destinationInventory,
|
||||
+ true
|
||||
+ );
|
||||
+ final boolean result = event.callEvent();
|
||||
+ if (!event.calledGetItem && !event.calledSetItem) {
|
||||
+ skipPushModeEventFire = true;
|
||||
+ }
|
||||
+ if (!result) {
|
||||
+ applyCooldown(hopper);
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ if (event.calledSetItem) {
|
||||
+ return org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem());
|
||||
+ } else {
|
||||
+ return itemStack;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Nullable
|
||||
+ private static ItemStack callPullMoveEvent(final Hopper hopper, final Container container, final ItemStack itemstack) {
|
||||
+ final org.bukkit.inventory.Inventory sourceInventory = getInventory(container);
|
||||
+ final org.bukkit.inventory.Inventory destination = getInventory(hopper);
|
||||
+
|
||||
+ // Mirror is safe as no plugins ever use this item
|
||||
+ final io.papermc.paper.event.inventory.PaperInventoryMoveItemEvent event = new io.papermc.paper.event.inventory.PaperInventoryMoveItemEvent(sourceInventory, org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack), destination, false);
|
||||
+ final boolean result = event.callEvent();
|
||||
+ if (!event.calledGetItem && !event.calledSetItem) {
|
||||
+ skipPullModeEventFire = true;
|
||||
+ }
|
||||
+ if (!result) {
|
||||
+ applyCooldown(hopper);
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ if (event.calledSetItem) {
|
||||
+ return org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem());
|
||||
+ } else {
|
||||
+ return itemstack;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private static org.bukkit.inventory.Inventory getInventory(final Container container) {
|
||||
+ final org.bukkit.inventory.Inventory sourceInventory;
|
||||
+ if (container instanceof net.minecraft.world.CompoundContainer compoundContainer) {
|
||||
+ // Have to special-case large chests as they work oddly
|
||||
+ sourceInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest(compoundContainer);
|
||||
+ } else if (container instanceof BlockEntity blockEntity) {
|
||||
+ sourceInventory = blockEntity.getOwner(false).getInventory();
|
||||
+ } else if (container.getOwner() != null) {
|
||||
+ sourceInventory = container.getOwner().getInventory();
|
||||
+ } else {
|
||||
+ sourceInventory = new org.bukkit.craftbukkit.inventory.CraftInventory(container);
|
||||
+ }
|
||||
+ return sourceInventory;
|
||||
+ }
|
||||
+
|
||||
+ private static void applyCooldown(final Hopper hopper) {
|
||||
+ if (hopper instanceof HopperBlockEntity blockEntity && blockEntity.getLevel() != null) {
|
||||
+ blockEntity.setCooldown(blockEntity.getLevel().spigotConfig.hopperTransfer);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private static boolean allMatch(Container container, Direction direction, java.util.function.BiPredicate<ItemStack, Integer> test) {
|
||||
+ if (container instanceof WorldlyContainer) {
|
||||
+ for (int slot : ((WorldlyContainer) container).getSlotsForFace(direction)) {
|
||||
+ if (!test.test(container.getItem(slot), slot)) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ }
|
||||
+ } else {
|
||||
+ int size = container.getContainerSize();
|
||||
+ for (int slot = 0; slot < size; slot++) {
|
||||
+ if (!test.test(container.getItem(slot), slot)) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ private static boolean anyMatch(Container container, Direction direction, java.util.function.BiPredicate<ItemStack, Integer> test) {
|
||||
+ if (container instanceof WorldlyContainer) {
|
||||
+ for (int slot : ((WorldlyContainer) container).getSlotsForFace(direction)) {
|
||||
+ if (test.test(container.getItem(slot), slot)) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ }
|
||||
+ } else {
|
||||
+ int size = container.getContainerSize();
|
||||
+ for (int slot = 0; slot < size; slot++) {
|
||||
+ if (test.test(container.getItem(slot), slot)) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ return true;
|
||||
+ }
|
||||
+ private static final java.util.function.BiPredicate<ItemStack, Integer> STACK_SIZE_TEST = (itemStack, i) -> itemStack.getCount() >= itemStack.getMaxStackSize();
|
||||
+ private static final java.util.function.BiPredicate<ItemStack, Integer> IS_EMPTY_TEST = (itemStack, i) -> itemStack.isEmpty();
|
||||
+ // Paper end - Perf: Optimize Hoppers
|
||||
+
|
||||
private static boolean ejectItems(Level level, BlockPos pos, HopperBlockEntity blockEntity) {
|
||||
Container attachedContainer = getAttachedContainer(level, pos, blockEntity);
|
||||
if (attachedContainer == null) {
|
||||
@@ -183,57 +421,60 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
||||
if (isFullContainer(attachedContainer, opposite)) {
|
||||
return false;
|
||||
} else {
|
||||
- for (int i = 0; i < blockEntity.getContainerSize(); i++) {
|
||||
- ItemStack item = blockEntity.getItem(i);
|
||||
- if (!item.isEmpty()) {
|
||||
- int count = item.getCount();
|
||||
- // CraftBukkit start - Call event when pushing items into other inventories
|
||||
- ItemStack original = item.copy();
|
||||
- org.bukkit.craftbukkit.inventory.CraftItemStack oitemstack = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(
|
||||
- blockEntity.removeItem(i, level.spigotConfig.hopperAmount)
|
||||
- ); // Spigot
|
||||
-
|
||||
- org.bukkit.inventory.Inventory destinationInventory;
|
||||
- // Have to special case large chests as they work oddly
|
||||
- if (attachedContainer instanceof final net.minecraft.world.CompoundContainer compoundContainer) {
|
||||
- destinationInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest(compoundContainer);
|
||||
- } else if (attachedContainer.getOwner() != null) {
|
||||
- destinationInventory = attachedContainer.getOwner().getInventory();
|
||||
- } else {
|
||||
- destinationInventory = new org.bukkit.craftbukkit.inventory.CraftInventory(attachedContainer);
|
||||
- }
|
||||
-
|
||||
- org.bukkit.event.inventory.InventoryMoveItemEvent event = new org.bukkit.event.inventory.InventoryMoveItemEvent(
|
||||
- blockEntity.getOwner().getInventory(),
|
||||
- oitemstack,
|
||||
- destinationInventory,
|
||||
- true
|
||||
- );
|
||||
- if (!event.callEvent()) {
|
||||
- blockEntity.setItem(i, original);
|
||||
- blockEntity.setCooldown(level.spigotConfig.hopperTransfer); // Delay hopper checks // Spigot
|
||||
- return false;
|
||||
- }
|
||||
- int origCount = event.getItem().getAmount(); // Spigot
|
||||
- ItemStack itemStack = HopperBlockEntity.addItem(blockEntity, attachedContainer, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()), opposite);
|
||||
- // CraftBukkit end
|
||||
-
|
||||
- if (itemStack.isEmpty()) {
|
||||
- attachedContainer.setChanged();
|
||||
- return true;
|
||||
- }
|
||||
-
|
||||
- item.setCount(count);
|
||||
- // Spigot start
|
||||
- item.shrink(origCount - itemStack.getCount());
|
||||
- if (count <= level.spigotConfig.hopperAmount) {
|
||||
- // Spigot end
|
||||
- blockEntity.setItem(i, item);
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- return false;
|
||||
+ // Paper start - Perf: Optimize Hoppers
|
||||
+ return hopperPush(level, attachedContainer, opposite, blockEntity);
|
||||
+ //for (int i = 0; i < blockEntity.getContainerSize(); i++) {
|
||||
+ // ItemStack item = blockEntity.getItem(i);
|
||||
+ // if (!item.isEmpty()) {
|
||||
+ // int count = item.getCount();
|
||||
+ // // CraftBukkit start - Call event when pushing items into other inventories
|
||||
+ // ItemStack original = item.copy();
|
||||
+ // org.bukkit.craftbukkit.inventory.CraftItemStack oitemstack = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(
|
||||
+ // blockEntity.removeItem(i, level.spigotConfig.hopperAmount)
|
||||
+ // ); // Spigot
|
||||
+
|
||||
+ // org.bukkit.inventory.Inventory destinationInventory;
|
||||
+ // // Have to special case large chests as they work oddly
|
||||
+ // if (attachedContainer instanceof final net.minecraft.world.CompoundContainer compoundContainer) {
|
||||
+ // destinationInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest(compoundContainer);
|
||||
+ // } else if (attachedContainer.getOwner() != null) {
|
||||
+ // destinationInventory = attachedContainer.getOwner().getInventory();
|
||||
+ // } else {
|
||||
+ // destinationInventory = new org.bukkit.craftbukkit.inventory.CraftInventory(attachedContainer);
|
||||
+ // }
|
||||
+
|
||||
+ // org.bukkit.event.inventory.InventoryMoveItemEvent event = new org.bukkit.event.inventory.InventoryMoveItemEvent(
|
||||
+ // blockEntity.getOwner().getInventory(),
|
||||
+ // oitemstack,
|
||||
+ // destinationInventory,
|
||||
+ // true
|
||||
+ // );
|
||||
+ // if (!event.callEvent()) {
|
||||
+ // blockEntity.setItem(i, original);
|
||||
+ // blockEntity.setCooldown(level.spigotConfig.hopperTransfer); // Delay hopper checks // Spigot
|
||||
+ // return false;
|
||||
+ // }
|
||||
+ // int origCount = event.getItem().getAmount(); // Spigot
|
||||
+ // ItemStack itemStack = HopperBlockEntity.addItem(blockEntity, attachedContainer, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()), opposite);
|
||||
+ // // CraftBukkit end
|
||||
+
|
||||
+ // if (itemStack.isEmpty()) {
|
||||
+ // attachedContainer.setChanged();
|
||||
+ // return true;
|
||||
+ // }
|
||||
+
|
||||
+ // item.setCount(count);
|
||||
+ // // Spigot start
|
||||
+ // item.shrink(origCount - itemStack.getCount());
|
||||
+ // if (count <= level.spigotConfig.hopperAmount) {
|
||||
+ // // Spigot end
|
||||
+ // blockEntity.setItem(i, item);
|
||||
+ // }
|
||||
+ // }
|
||||
+ //}
|
||||
+
|
||||
+ //return false;
|
||||
+ // Paper end - Perf: Optimize Hoppers
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -288,6 +529,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
||||
Container sourceContainer = getSourceContainer(level, hopper, blockPos, blockState);
|
||||
if (sourceContainer != null) {
|
||||
Direction direction = Direction.DOWN;
|
||||
+ skipPullModeEventFire = skipHopperEvents; // Paper - Perf: Optimize Hoppers
|
||||
|
||||
for (int i : getSlots(sourceContainer, direction)) {
|
||||
if (tryTakeInItemFromSlot(hopper, sourceContainer, i, direction, level)) { // Spigot
|
||||
@@ -313,55 +555,58 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
||||
private static boolean tryTakeInItemFromSlot(Hopper hopper, Container container, int slot, Direction direction, Level level) { // Spigot
|
||||
ItemStack item = container.getItem(slot);
|
||||
if (!item.isEmpty() && canTakeItemFromContainer(hopper, container, item, slot, direction)) {
|
||||
- int count = item.getCount();
|
||||
- // CraftBukkit start - Call event on collection of items from inventories into the hopper
|
||||
- ItemStack original = item.copy();
|
||||
- org.bukkit.craftbukkit.inventory.CraftItemStack oitemstack = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(
|
||||
- container.removeItem(slot, level.spigotConfig.hopperAmount) // Spigot
|
||||
- );
|
||||
-
|
||||
- org.bukkit.inventory.Inventory sourceInventory;
|
||||
- // Have to special case large chests as they work oddly
|
||||
- if (container instanceof final net.minecraft.world.CompoundContainer compoundContainer) {
|
||||
- sourceInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest(compoundContainer);
|
||||
- } else if (container.getOwner() != null) {
|
||||
- sourceInventory = container.getOwner().getInventory();
|
||||
- } else {
|
||||
- sourceInventory = new org.bukkit.craftbukkit.inventory.CraftInventory(container);
|
||||
- }
|
||||
-
|
||||
- org.bukkit.event.inventory.InventoryMoveItemEvent event = new org.bukkit.event.inventory.InventoryMoveItemEvent(
|
||||
- sourceInventory,
|
||||
- oitemstack,
|
||||
- hopper.getOwner().getInventory(),
|
||||
- false
|
||||
- );
|
||||
-
|
||||
- if (!event.callEvent()) {
|
||||
- container.setItem(slot, original);
|
||||
-
|
||||
- if (hopper instanceof final HopperBlockEntity hopperBlockEntity) {
|
||||
- hopperBlockEntity.setCooldown(level.spigotConfig.hopperTransfer); // Spigot
|
||||
- }
|
||||
-
|
||||
- return false;
|
||||
- }
|
||||
- int origCount = event.getItem().getAmount(); // Spigot
|
||||
- ItemStack itemStack = HopperBlockEntity.addItem(container, hopper, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()), null);
|
||||
- // CraftBukkit end
|
||||
-
|
||||
- if (itemStack.isEmpty()) {
|
||||
- container.setChanged();
|
||||
- return true;
|
||||
- }
|
||||
-
|
||||
- item.setCount(count);
|
||||
- // Spigot start
|
||||
- item.shrink(origCount - itemStack.getCount());
|
||||
- if (count <= level.spigotConfig.hopperAmount) {
|
||||
- // Spigot end
|
||||
- container.setItem(slot, item);
|
||||
- }
|
||||
+ // Paper start - Perf: Optimize Hoppers
|
||||
+ return hopperPull(level, hopper, container, item, slot);
|
||||
+ //int count = item.getCount();
|
||||
+ //// CraftBukkit start - Call event on collection of items from inventories into the hopper
|
||||
+ //ItemStack original = item.copy();
|
||||
+ //org.bukkit.craftbukkit.inventory.CraftItemStack oitemstack = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(
|
||||
+ // container.removeItem(slot, level.spigotConfig.hopperAmount) // Spigot
|
||||
+ //);
|
||||
+
|
||||
+ //org.bukkit.inventory.Inventory sourceInventory;
|
||||
+ //// Have to special case large chests as they work oddly
|
||||
+ //if (container instanceof final net.minecraft.world.CompoundContainer compoundContainer) {
|
||||
+ // sourceInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest(compoundContainer);
|
||||
+ //} else if (container.getOwner() != null) {
|
||||
+ // sourceInventory = container.getOwner().getInventory();
|
||||
+ //} else {
|
||||
+ // sourceInventory = new org.bukkit.craftbukkit.inventory.CraftInventory(container);
|
||||
+ //}
|
||||
+
|
||||
+ //org.bukkit.event.inventory.InventoryMoveItemEvent event = new org.bukkit.event.inventory.InventoryMoveItemEvent(
|
||||
+ // sourceInventory,
|
||||
+ // oitemstack,
|
||||
+ // hopper.getOwner().getInventory(),
|
||||
+ // false
|
||||
+ //);
|
||||
+
|
||||
+ //if (!event.callEvent()) {
|
||||
+ // container.setItem(slot, original);
|
||||
+
|
||||
+ // if (hopper instanceof final HopperBlockEntity hopperBlockEntity) {
|
||||
+ // hopperBlockEntity.setCooldown(level.spigotConfig.hopperTransfer); // Spigot
|
||||
+ // }
|
||||
+
|
||||
+ // return false;
|
||||
+ //}
|
||||
+ //int origCount = event.getItem().getAmount(); // Spigot
|
||||
+ //ItemStack itemStack = HopperBlockEntity.addItem(container, hopper, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()), null);
|
||||
+ //// CraftBukkit end
|
||||
+
|
||||
+ //if (itemStack.isEmpty()) {
|
||||
+ // container.setChanged();
|
||||
+ // return true;
|
||||
+ //}
|
||||
+
|
||||
+ //item.setCount(count);
|
||||
+ //// Spigot start
|
||||
+ //item.shrink(origCount - itemStack.getCount());
|
||||
+ //if (count <= level.spigotConfig.hopperAmount) {
|
||||
+ // // Spigot end
|
||||
+ // container.setItem(slot, item);
|
||||
+ //}
|
||||
+ // Paper end - Perf: Optimize Hoppers
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -370,13 +615,15 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
||||
public static boolean addItem(Container container, ItemEntity item) {
|
||||
boolean flag = false;
|
||||
// CraftBukkit start
|
||||
+ if (org.bukkit.event.inventory.InventoryPickupItemEvent.getHandlerList().getRegisteredListeners().length > 0) { // Paper - optimize hoppers
|
||||
org.bukkit.event.inventory.InventoryPickupItemEvent event = new org.bukkit.event.inventory.InventoryPickupItemEvent(
|
||||
- container.getOwner().getInventory(), (org.bukkit.entity.Item) item.getBukkitEntity()
|
||||
+ getInventory(container), (org.bukkit.entity.Item) item.getBukkitEntity() // Paper - Perf: Optimize Hoppers; use getInventory() to avoid snapshot creation
|
||||
);
|
||||
if (!event.callEvent()) {
|
||||
return false;
|
||||
}
|
||||
// CraftBukkit end
|
||||
+ } // Paper - Perf: Optimize Hoppers
|
||||
ItemStack itemStack = item.getItem().copy();
|
||||
ItemStack itemStack1 = addItem(null, container, itemStack, null);
|
||||
if (itemStack1.isEmpty()) {
|
||||
@@ -431,7 +678,9 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
||||
stack = stack.split(destination.getMaxStackSize());
|
||||
}
|
||||
// Spigot end
|
||||
+ ignoreBlockEntityUpdates = true; // Paper - Perf: Optimize Hoppers
|
||||
destination.setItem(slot, stack);
|
||||
+ ignoreBlockEntityUpdates = false; // Paper - Perf: Optimize Hoppers
|
||||
stack = leftover; // Paper - Make hoppers respect inventory max stack size
|
||||
flag = true;
|
||||
} else if (canMergeItems(item, stack)) {
|
||||
@@ -519,13 +768,19 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
||||
|
||||
@Nullable
|
||||
public static Container getContainerAt(Level level, BlockPos pos) {
|
||||
- return getContainerAt(level, pos, level.getBlockState(pos), pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5);
|
||||
+ return getContainerAt(level, pos, level.getBlockState(pos), pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5, true); // Paper - Optimize hoppers
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Container getContainerAt(Level level, BlockPos pos, BlockState state, double x, double y, double z) {
|
||||
+ // Paper start - Perf: Optimize Hoppers
|
||||
+ return HopperBlockEntity.getContainerAt(level, pos, state, x, y, z, false);
|
||||
+ }
|
||||
+ @Nullable
|
||||
+ private static Container getContainerAt(Level level, BlockPos pos, BlockState state, double x, double y, double z, final boolean optimizeEntities) {
|
||||
+ // Paper end - Perf: Optimize Hoppers
|
||||
Container blockContainer = getBlockContainer(level, pos, state);
|
||||
- if (blockContainer == null) {
|
||||
+ if (blockContainer == null && (!optimizeEntities || !level.paperConfig().hopper.ignoreOccludingBlocks || !state.getBukkitMaterial().isOccluding())) { // Paper - Perf: Optimize Hoppers
|
||||
blockContainer = getEntityContainer(level, x, y, z);
|
||||
}
|
||||
|
||||
@@ -551,14 +806,14 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
||||
|
||||
@Nullable
|
||||
private static Container getEntityContainer(Level level, double x, double y, double z) {
|
||||
- List<Entity> entities = level.getEntities(
|
||||
- (Entity)null, new AABB(x - 0.5, y - 0.5, z - 0.5, x + 0.5, y + 0.5, z + 0.5), EntitySelector.CONTAINER_ENTITY_SELECTOR
|
||||
+ List<Entity> entities = level.getEntitiesOfClass(
|
||||
+ (Class) Container.class, new AABB(x - 0.5, y - 0.5, z - 0.5, x + 0.5, y + 0.5, z + 0.5), EntitySelector.CONTAINER_ENTITY_SELECTOR // Paper - Perf: Optimize hoppers
|
||||
);
|
||||
return !entities.isEmpty() ? (Container)entities.get(level.random.nextInt(entities.size())) : null;
|
||||
}
|
||||
|
||||
private static boolean canMergeItems(ItemStack stack1, ItemStack stack2) {
|
||||
- return stack1.getCount() <= stack1.getMaxStackSize() && ItemStack.isSameItemSameComponents(stack1, stack2);
|
||||
+ return stack1.getCount() < stack1.getMaxStackSize() && ItemStack.isSameItemSameComponents(stack1, stack2); // Paper - Perf: Optimize Hoppers; used to return true for full itemstacks?!
|
||||
}
|
||||
|
||||
@Override
|
||||
diff --git a/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java b/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java
|
||||
index 73b3ddb120d6b6f89e478960e78bed415baea205..f9c31da81d84033abfc1179fc643bceffe35da17 100644
|
||||
--- a/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java
|
||||
+++ b/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java
|
||||
@@ -53,7 +53,7 @@ public abstract class RandomizableContainerBlockEntity extends BaseContainerBloc
|
||||
|
||||
@Override
|
||||
public ItemStack getItem(int index) {
|
||||
- this.unpackLootTable(null);
|
||||
+ if (index == 0) this.unpackLootTable(null); // Paper - Perf: Optimize Hoppers
|
||||
return super.getItem(index);
|
||||
}
|
||||
|
|
@ -5,61 +5,62 @@ Subject: [PATCH] Optimise collision checking in player move packet handling
|
|||
|
||||
Move collision logic to just the hasNewCollision call instead of getCubes + hasNewCollision
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index 650126e6445c0458c6a6649c235908bfeea428cd..d248671b2e1c6256fc4d74320bdb29ca078bad0b 100644
|
||||
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -561,7 +561,7 @@ public class ServerGamePacketListenerImpl
|
||||
return;
|
||||
}
|
||||
|
||||
- boolean flag = worldserver.noCollision(entity, entity.getBoundingBox().deflate(0.0625D));
|
||||
+ AABB oldBox = entity.getBoundingBox(); // Paper - copy from player movement packet
|
||||
|
||||
d6 = d3 - this.vehicleLastGoodX; // Paper - diff on change, used for checking large move vectors above
|
||||
d7 = d4 - this.vehicleLastGoodY; // Paper - diff on change, used for checking large move vectors above
|
||||
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
- boolean flag = serverLevel.noCollision(rootVehicle, rootVehicle.getBoundingBox().deflate(0.0625));
|
||||
+ AABB oldBox = rootVehicle.getBoundingBox(); // Paper - copy from player movement packet
|
||||
d3 = d - this.vehicleLastGoodX; // Paper - diff on change, used for checking large move vectors above
|
||||
d4 = d1 - this.vehicleLastGoodY; // Paper - diff on change, used for checking large move vectors above
|
||||
d5 = d2 - this.vehicleLastGoodZ; // Paper - diff on change, used for checking large move vectors above
|
||||
@@ -571,6 +571,7 @@ public class ServerGamePacketListenerImpl
|
||||
}
|
||||
|
||||
entity.move(MoverType.PLAYER, new Vec3(d6, d7, d8));
|
||||
+ boolean didCollide = toX != entity.getX() || toY != entity.getY() || toZ != entity.getZ(); // Paper - needed here as the difference in Y can be reset - also note: this is only a guess at whether collisions took place, floating point errors can make this true when it shouldn't be...
|
||||
double d11 = d7;
|
||||
|
||||
d6 = d3 - entity.getX();
|
||||
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
rootVehicle.move(MoverType.PLAYER, new Vec3(d3, d4, d5));
|
||||
+ boolean didCollide = toX != rootVehicle.getX() || toY != rootVehicle.getY() || toZ != rootVehicle.getZ(); // Paper - needed here as the difference in Y can be reset - also note: this is only a guess at whether collisions took place, floating point errors can make this true when it shouldn't be...
|
||||
double verticalDelta = d4; // Paper - Decompile fix, was named d11 previously, is now gone in the source
|
||||
d3 = d - rootVehicle.getX();
|
||||
d4 = d1 - rootVehicle.getY();
|
||||
@@ -582,14 +583,22 @@ public class ServerGamePacketListenerImpl
|
||||
d7 = d3 * d3 + d4 * d4 + d5 * d5;
|
||||
boolean flag2 = false;
|
||||
|
||||
if (d10 > org.spigotmc.SpigotConfig.movedWronglyThreshold) { // Spigot
|
||||
if (d7 > org.spigotmc.SpigotConfig.movedWronglyThreshold) { // Spigot
|
||||
- flag2 = true;
|
||||
+ flag2 = true; // Paper - diff on change, this should be moved wrongly
|
||||
ServerGamePacketListenerImpl.LOGGER.warn("{} (vehicle of {}) moved wrongly! {}", new Object[]{entity.getName().getString(), this.player.getName().getString(), Math.sqrt(d10)});
|
||||
LOGGER.warn("{} (vehicle of {}) moved wrongly! {}", rootVehicle.getName().getString(), this.player.getName().getString(), Math.sqrt(d7));
|
||||
}
|
||||
|
||||
entity.absMoveTo(d3, d4, d5, f, f1);
|
||||
this.player.absMoveTo(d3, d4, d5, this.player.getYRot(), this.player.getXRot()); // CraftBukkit
|
||||
- boolean flag3 = worldserver.noCollision(entity, entity.getBoundingBox().deflate(0.0625D));
|
||||
|
||||
rootVehicle.absMoveTo(d, d1, d2, f, f1);
|
||||
this.player.absMoveTo(d, d1, d2, this.player.getYRot(), this.player.getXRot()); // CraftBukkit
|
||||
- boolean flag3 = serverLevel.noCollision(rootVehicle, rootVehicle.getBoundingBox().deflate(0.0625));
|
||||
- if (flag && (flag2 || !flag3)) {
|
||||
+ // Paper start - optimise out extra getCubes
|
||||
+ boolean teleportBack = flag2; // violating this is always a fail
|
||||
+ if (!teleportBack) {
|
||||
+ // note: only call after setLocation, or else getBoundingBox is wrong
|
||||
+ AABB newBox = entity.getBoundingBox();
|
||||
+ AABB newBox = rootVehicle.getBoundingBox();
|
||||
+ if (didCollide || !oldBox.equals(newBox)) {
|
||||
+ teleportBack = this.hasNewCollision(worldserver, entity, oldBox, newBox);
|
||||
+ teleportBack = this.hasNewCollision(serverLevel, rootVehicle, oldBox, newBox);
|
||||
+ } // else: no collision at all detected, why do we care?
|
||||
+ }
|
||||
+ if (teleportBack) { // Paper end - optimise out extra getCubes
|
||||
entity.absMoveTo(d0, d1, d2, f, f1);
|
||||
this.player.absMoveTo(d0, d1, d2, this.player.getYRot(), this.player.getXRot()); // CraftBukkit
|
||||
this.send(ClientboundMoveVehiclePacket.fromEntity(entity));
|
||||
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
rootVehicle.absMoveTo(x, y, z, f, f1);
|
||||
this.player.absMoveTo(x, y, z, this.player.getYRot(), this.player.getXRot()); // CraftBukkit
|
||||
this.send(ClientboundMoveVehiclePacket.fromEntity(rootVehicle));
|
||||
@@ -667,9 +676,32 @@ public class ServerGamePacketListenerImpl
|
||||
}
|
||||
|
||||
private boolean noBlocksAround(Entity entity) {
|
||||
- return entity.level().getBlockStates(entity.getBoundingBox().inflate(0.0625D).expandTowards(0.0D, -0.55D, 0.0D)).allMatch(BlockBehaviour.BlockStateBase::isAir);
|
||||
- return entity.level()
|
||||
- .getBlockStates(entity.getBoundingBox().inflate(0.0625).expandTowards(0.0, -0.55, 0.0))
|
||||
- .allMatch(BlockBehaviour.BlockStateBase::isAir);
|
||||
+ // Paper start - stop using streams, this is already a known fixed problem in Entity#move
|
||||
+ AABB box = entity.getBoundingBox().inflate(0.0625D).expandTowards(0.0D, -0.55D, 0.0D);
|
||||
+ AABB box = entity.getBoundingBox().inflate(0.0625).expandTowards(0.0, -0.55, 0.0);
|
||||
+ int minX = Mth.floor(box.minX);
|
||||
+ int minY = Mth.floor(box.minY);
|
||||
+ int minZ = Mth.floor(box.minZ);
|
||||
|
@ -67,15 +68,15 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ int maxY = Mth.floor(box.maxY);
|
||||
+ int maxZ = Mth.floor(box.maxZ);
|
||||
+
|
||||
+ Level world = entity.level();
|
||||
+ Level level = entity.level();
|
||||
+ BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos();
|
||||
+
|
||||
+ for (int y = minY; y <= maxY; ++y) {
|
||||
+ for (int z = minZ; z <= maxZ; ++z) {
|
||||
+ for (int x = minX; x <= maxX; ++x) {
|
||||
+ pos.set(x, y, z);
|
||||
+ BlockState type = world.getBlockStateIfLoaded(pos);
|
||||
+ if (type != null && !type.isAir()) {
|
||||
+ BlockState blockState = level.getBlockStateIfLoaded(pos);
|
||||
+ if (blockState != null && !blockState.isAir()) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ }
|
||||
|
@ -87,61 +88,61 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
}
|
||||
|
||||
@Override
|
||||
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
@@ -1361,7 +1393,7 @@ public class ServerGamePacketListenerImpl
|
||||
}
|
||||
}
|
||||
|
||||
- AABB axisalignedbb = this.player.getBoundingBox();
|
||||
+ AABB axisalignedbb = this.player.getBoundingBox(); // Paper - diff on change, should be old AABB
|
||||
|
||||
d6 = d0 - this.lastGoodX; // Paper - diff on change, used for checking large move vectors above
|
||||
d7 = d1 - this.lastGoodY; // Paper - diff on change, used for checking large move vectors above
|
||||
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
|
||||
this.player.move(MoverType.PLAYER, new Vec3(d6, d7, d8));
|
||||
- AABB boundingBox = this.player.getBoundingBox();
|
||||
+ AABB boundingBox = this.player.getBoundingBox(); // Paper - diff on change, should be old AABB
|
||||
d3 = d - this.lastGoodX; // Paper - diff on change, used for checking large move vectors above
|
||||
d4 = d1 - this.lastGoodY; // Paper - diff on change, used for checking large move vectors above
|
||||
d5 = d2 - this.lastGoodZ; // Paper - diff on change, used for checking large move vectors above
|
||||
@@ -1400,6 +1432,7 @@ public class ServerGamePacketListenerImpl
|
||||
boolean flag1 = this.player.verticalCollisionBelow;
|
||||
this.player.move(MoverType.PLAYER, new Vec3(d3, d4, d5));
|
||||
this.player.onGround = packet.isOnGround(); // CraftBukkit - SPIGOT-5810, SPIGOT-5835, SPIGOT-6828: reset by this.player.move
|
||||
+ boolean didCollide = toX != this.player.getX() || toY != this.player.getY() || toZ != this.player.getZ(); // Paper - needed here as the difference in Y can be reset - also note: this is only a guess at whether collisions took place, floating point errors can make this true when it shouldn't be...
|
||||
// Paper start - prevent position desync
|
||||
if (this.awaitingPositionFromClient != null) {
|
||||
return; // ... thanks Mojang for letting move calls teleport across dimensions.
|
||||
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
@@ -1432,7 +1465,17 @@ public class ServerGamePacketListenerImpl
|
||||
}
|
||||
|
||||
// Paper start - Add fail move event
|
||||
- boolean teleportBack = !this.player.noPhysics && !this.player.isSleeping() && (movedWrongly && worldserver.noCollision(this.player, axisalignedbb) || this.isPlayerCollidingWithAnythingNew(worldserver, axisalignedbb, d0, d1, d2));
|
||||
- boolean teleportBack = !this.player.noPhysics && !this.player.isSleeping() && (movedWrongly && serverLevel.noCollision(this.player, boundingBox) || this.isPlayerCollidingWithAnythingNew(serverLevel, boundingBox, d, d1, d2));
|
||||
+ // Paper start - optimise out extra getCubes
|
||||
+ boolean teleportBack = !this.player.noPhysics && !this.player.isSleeping() && movedWrongly;
|
||||
+ this.player.absMoveTo(d0, d1, d2, f, f1); // prevent desync by tping to the set position, dropped for unknown reasons by mojang
|
||||
+ this.player.absMoveTo(d, d1, d2, f, f1); // prevent desync by tping to the set position, dropped for unknown reasons by mojang
|
||||
+ if (!this.player.noPhysics && !this.player.isSleeping() && !teleportBack) {
|
||||
+ AABB newBox = this.player.getBoundingBox();
|
||||
+ if (didCollide || !axisalignedbb.equals(newBox)) {
|
||||
+ if (didCollide || !boundingBox.equals(newBox)) {
|
||||
+ // note: only call after setLocation, or else getBoundingBox is wrong
|
||||
+ teleportBack = this.hasNewCollision(worldserver, this.player, axisalignedbb, newBox);
|
||||
+ teleportBack = this.hasNewCollision(serverLevel, this.player, boundingBox, newBox);
|
||||
+ } // else: no collision at all detected, why do we care?
|
||||
+ }
|
||||
+ // Paper end - optimise out extra getCubes
|
||||
if (teleportBack) {
|
||||
io.papermc.paper.event.player.PlayerFailMoveEvent event = fireFailMove(io.papermc.paper.event.player.PlayerFailMoveEvent.FailReason.CLIPPED_INTO_BLOCK,
|
||||
toX, toY, toZ, toYaw, toPitch, false);
|
||||
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
@@ -1568,7 +1611,7 @@ public class ServerGamePacketListenerImpl
|
||||
|
||||
private boolean updateAwaitingTeleport() {
|
||||
if (this.awaitingPositionFromClient != null) {
|
||||
- if (this.tickCount - this.awaitingTeleportTime > 20) {
|
||||
+ if (false && this.tickCount - this.awaitingTeleportTime > 20) { // Paper - this will greatly screw with clients with > 1000ms RTT
|
||||
this.awaitingTeleportTime = this.tickCount;
|
||||
this.teleport(this.awaitingPositionFromClient.x, this.awaitingPositionFromClient.y, this.awaitingPositionFromClient.z, this.player.getYRot(), this.player.getXRot());
|
||||
}
|
||||
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
this.teleport(
|
||||
this.awaitingPositionFromClient.x,
|
||||
@@ -1587,6 +1630,33 @@ public class ServerGamePacketListenerImpl
|
||||
}
|
||||
}
|
||||
|
||||
+ // Paper start - optimise out extra getCubes
|
||||
+ private boolean hasNewCollision(final ServerLevel world, final Entity entity, final AABB oldBox, final AABB newBox) {
|
||||
+ private boolean hasNewCollision(final ServerLevel level, final Entity entity, final AABB oldBox, final AABB newBox) {
|
||||
+ final List<AABB> collisionsBB = new java.util.ArrayList<>();
|
||||
+ final List<VoxelShape> collisionsVoxel = new java.util.ArrayList<>();
|
||||
+ ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.getCollisions(
|
||||
+ world, entity, newBox, collisionsVoxel, collisionsBB,
|
||||
+ level, entity, newBox, collisionsVoxel, collisionsBB,
|
||||
+ ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_FLAG_COLLIDE_WITH_UNLOADED_CHUNKS | ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_FLAG_CHECK_BORDER,
|
||||
+ null, null
|
||||
+ );
|
||||
|
@ -163,6 +164,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
+ return false;
|
||||
+ }
|
||||
+ // Paper end - optimise out extra getCubes
|
||||
private boolean isPlayerCollidingWithAnythingNew(LevelReader world, AABB box, double newX, double newY, double newZ) {
|
||||
AABB axisalignedbb1 = this.player.getBoundingBox().move(newX - this.player.getX(), newY - this.player.getY(), newZ - this.player.getZ());
|
||||
Iterable<VoxelShape> iterable = world.getCollisions(this.player, axisalignedbb1.deflate(9.999999747378752E-6D));
|
||||
private boolean isPlayerCollidingWithAnythingNew(LevelReader level, AABB box, double x, double y, double z) {
|
||||
AABB aabb = this.player.getBoundingBox().move(x - this.player.getX(), y - this.player.getY(), z - this.player.getZ());
|
||||
Iterable<VoxelShape> collisions = level.getCollisions(this.player, aabb.deflate(1.0E-5F));
|
|
@ -1,6 +1,6 @@
|
|||
--- a/data/minecraft/loot_table/chests/trial_chambers/intersection_barrel.json
|
||||
+++ b/data/minecraft/loot_table/chests/trial_chambers/intersection_barrel.json
|
||||
@@ -70,15 +70,6 @@
|
||||
@@ -70,15 +_,6 @@
|
||||
"add": false,
|
||||
"count": 1.0,
|
||||
"function": "minecraft:set_count"
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
--- a/data/minecraft/worldgen/noise_settings/amplified.json
|
||||
+++ b/data/minecraft/worldgen/noise_settings/amplified.json
|
||||
@@ -389,7 +_,8 @@
|
||||
{
|
||||
"type": "minecraft:condition",
|
||||
"if_true": {
|
||||
- "type": "minecraft:vertical_gradient",
|
||||
+ "type": "paper:optionally_flat_bedrock_condition_source",
|
||||
+ "is_roof": false,
|
||||
"false_at_and_above": {
|
||||
"above_bottom": 5
|
||||
},
|
|
@ -0,0 +1,22 @@
|
|||
--- a/data/minecraft/worldgen/noise_settings/caves.json
|
||||
+++ b/data/minecraft/worldgen/noise_settings/caves.json
|
||||
@@ -110,7 +_,8 @@
|
||||
"if_true": {
|
||||
"type": "minecraft:not",
|
||||
"invert": {
|
||||
- "type": "minecraft:vertical_gradient",
|
||||
+ "type": "paper:optionally_flat_bedrock_condition_source",
|
||||
+ "is_roof": true,
|
||||
"false_at_and_above": {
|
||||
"below_top": 0
|
||||
},
|
||||
@@ -130,7 +_,8 @@
|
||||
{
|
||||
"type": "minecraft:condition",
|
||||
"if_true": {
|
||||
- "type": "minecraft:vertical_gradient",
|
||||
+ "type": "paper:optionally_flat_bedrock_condition_source",
|
||||
+ "is_roof": false,
|
||||
"false_at_and_above": {
|
||||
"above_bottom": 5
|
||||
},
|
|
@ -0,0 +1,12 @@
|
|||
--- a/data/minecraft/worldgen/noise_settings/large_biomes.json
|
||||
+++ b/data/minecraft/worldgen/noise_settings/large_biomes.json
|
||||
@@ -389,7 +_,8 @@
|
||||
{
|
||||
"type": "minecraft:condition",
|
||||
"if_true": {
|
||||
- "type": "minecraft:vertical_gradient",
|
||||
+ "type": "paper:optionally_flat_bedrock_condition_source",
|
||||
+ "is_roof": false,
|
||||
"false_at_and_above": {
|
||||
"above_bottom": 5
|
||||
},
|
|
@ -0,0 +1,22 @@
|
|||
--- a/data/minecraft/worldgen/noise_settings/nether.json
|
||||
+++ b/data/minecraft/worldgen/noise_settings/nether.json
|
||||
@@ -108,7 +_,8 @@
|
||||
{
|
||||
"type": "minecraft:condition",
|
||||
"if_true": {
|
||||
- "type": "minecraft:vertical_gradient",
|
||||
+ "type": "paper:optionally_flat_bedrock_condition_source",
|
||||
+ "is_roof": false,
|
||||
"false_at_and_above": {
|
||||
"above_bottom": 5
|
||||
},
|
||||
@@ -129,7 +_,8 @@
|
||||
"if_true": {
|
||||
"type": "minecraft:not",
|
||||
"invert": {
|
||||
- "type": "minecraft:vertical_gradient",
|
||||
+ "type": "paper:optionally_flat_bedrock_condition_source",
|
||||
+ "is_roof": true,
|
||||
"false_at_and_above": {
|
||||
"below_top": 0
|
||||
},
|
|
@ -0,0 +1,12 @@
|
|||
--- a/data/minecraft/worldgen/noise_settings/overworld.json
|
||||
+++ b/data/minecraft/worldgen/noise_settings/overworld.json
|
||||
@@ -389,7 +_,8 @@
|
||||
{
|
||||
"type": "minecraft:condition",
|
||||
"if_true": {
|
||||
- "type": "minecraft:vertical_gradient",
|
||||
+ "type": "paper:optionally_flat_bedrock_condition_source",
|
||||
+ "is_roof": false,
|
||||
"false_at_and_above": {
|
||||
"above_bottom": 5
|
||||
},
|
|
@ -0,0 +1,244 @@
|
|||
--- /dev/null
|
||||
+++ b/ca/spottedleaf/moonrise/paper/PaperHooks.java
|
||||
@@ -1,0 +_,241 @@
|
||||
+package ca.spottedleaf.moonrise.paper;
|
||||
+
|
||||
+import ca.spottedleaf.moonrise.common.PlatformHooks;
|
||||
+import ca.spottedleaf.moonrise.paper.util.BaseChunkSystemHooks;
|
||||
+import com.mojang.datafixers.DSL;
|
||||
+import com.mojang.datafixers.DataFixer;
|
||||
+import com.mojang.serialization.Dynamic;
|
||||
+import java.util.Collection;
|
||||
+import net.minecraft.core.BlockPos;
|
||||
+import net.minecraft.nbt.CompoundTag;
|
||||
+import net.minecraft.nbt.NbtOps;
|
||||
+import net.minecraft.server.level.ChunkHolder;
|
||||
+import net.minecraft.server.level.GenerationChunkHolder;
|
||||
+import net.minecraft.server.level.ServerLevel;
|
||||
+import net.minecraft.server.level.ServerPlayer;
|
||||
+import net.minecraft.world.entity.Entity;
|
||||
+import net.minecraft.world.entity.boss.EnderDragonPart;
|
||||
+import net.minecraft.world.level.BlockGetter;
|
||||
+import net.minecraft.world.level.ChunkPos;
|
||||
+import net.minecraft.world.level.Level;
|
||||
+import net.minecraft.world.level.block.state.BlockState;
|
||||
+import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
+import net.minecraft.world.level.chunk.LevelChunk;
|
||||
+import net.minecraft.world.level.chunk.ProtoChunk;
|
||||
+import net.minecraft.world.level.chunk.storage.SerializableChunkData;
|
||||
+import net.minecraft.world.level.entity.EntityTypeTest;
|
||||
+import net.minecraft.world.phys.AABB;
|
||||
+import java.util.List;
|
||||
+import java.util.function.Predicate;
|
||||
+
|
||||
+public final class PaperHooks extends BaseChunkSystemHooks implements PlatformHooks {
|
||||
+
|
||||
+ @Override
|
||||
+ public String getBrand() {
|
||||
+ return "Paper";
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int getLightEmission(final BlockState blockState, final BlockGetter world, final BlockPos pos) {
|
||||
+ return blockState.getLightEmission();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Predicate<BlockState> maybeHasLightEmission() {
|
||||
+ return (final BlockState state) -> {
|
||||
+ return state.getLightEmission() != 0;
|
||||
+ };
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean hasCurrentlyLoadingChunk() {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public LevelChunk getCurrentlyLoadingChunk(final GenerationChunkHolder holder) {
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setCurrentlyLoading(final GenerationChunkHolder holder, final LevelChunk levelChunk) {
|
||||
+
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void chunkFullStatusComplete(final LevelChunk newChunk, final ProtoChunk original) {
|
||||
+
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean allowAsyncTicketUpdates() {
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void onChunkHolderTicketChange(final ServerLevel world, final ChunkHolder holder, final int oldLevel, final int newLevel) {
|
||||
+
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void chunkUnloadFromWorld(final LevelChunk chunk) {
|
||||
+
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void chunkSyncSave(final ServerLevel world, final ChunkAccess chunk, final SerializableChunkData data) {
|
||||
+
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void onChunkWatch(final ServerLevel world, final LevelChunk chunk, final ServerPlayer player) {
|
||||
+
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void onChunkUnWatch(final ServerLevel world, final ChunkPos chunk, final ServerPlayer player) {
|
||||
+
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void addToGetEntities(final Level world, final Entity entity, final AABB boundingBox, final Predicate<? super Entity> predicate, final List<Entity> into) {
|
||||
+ final Collection<EnderDragonPart> parts = world.dragonParts();
|
||||
+ if (parts.isEmpty()) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ for (final EnderDragonPart part : parts) {
|
||||
+ if (part != entity && part.getBoundingBox().intersects(boundingBox) && (predicate == null || predicate.test(part))) {
|
||||
+ into.add(part);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public <T extends Entity> void addToGetEntities(final Level world, final EntityTypeTest<Entity, T> entityTypeTest, final AABB boundingBox, final Predicate<? super T> predicate, final List<? super T> into, final int maxCount) {
|
||||
+ if (into.size() >= maxCount) {
|
||||
+ // fix neoforge issue: do not add if list is already full
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ final Collection<EnderDragonPart> parts = world.dragonParts();
|
||||
+ if (parts.isEmpty()) {
|
||||
+ return;
|
||||
+ }
|
||||
+ for (final EnderDragonPart part : parts) {
|
||||
+ if (!part.getBoundingBox().intersects(boundingBox)) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ final T casted = (T)entityTypeTest.tryCast(part);
|
||||
+ if (casted != null && (predicate == null || predicate.test(casted))) {
|
||||
+ into.add(casted);
|
||||
+ if (into.size() >= maxCount) {
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void entityMove(final Entity entity, final long oldSection, final long newSection) {
|
||||
+
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean screenEntity(final ServerLevel world, final Entity entity, final boolean fromDisk, final boolean event) {
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean configFixMC224294() {
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean configAutoConfigSendDistance() {
|
||||
+ return io.papermc.paper.configuration.GlobalConfiguration.get().chunkLoadingAdvanced.autoConfigSendDistance;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public double configPlayerMaxLoadRate() {
|
||||
+ return io.papermc.paper.configuration.GlobalConfiguration.get().chunkLoadingBasic.playerMaxChunkLoadRate;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public double configPlayerMaxGenRate() {
|
||||
+ return io.papermc.paper.configuration.GlobalConfiguration.get().chunkLoadingBasic.playerMaxChunkGenerateRate;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public double configPlayerMaxSendRate() {
|
||||
+ return io.papermc.paper.configuration.GlobalConfiguration.get().chunkLoadingBasic.playerMaxChunkSendRate;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int configPlayerMaxConcurrentLoads() {
|
||||
+ return io.papermc.paper.configuration.GlobalConfiguration.get().chunkLoadingAdvanced.playerMaxConcurrentChunkLoads;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int configPlayerMaxConcurrentGens() {
|
||||
+ return io.papermc.paper.configuration.GlobalConfiguration.get().chunkLoadingAdvanced.playerMaxConcurrentChunkGenerates;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public long configAutoSaveInterval(final ServerLevel world) {
|
||||
+ return world.paperConfig().chunks.autoSaveInterval.value();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int configMaxAutoSavePerTick(final ServerLevel world) {
|
||||
+ return world.paperConfig().chunks.maxAutoSaveChunksPerTick;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean configFixMC159283() {
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean forceNoSave(final ChunkAccess chunk) {
|
||||
+ return chunk instanceof LevelChunk levelChunk && levelChunk.mustNotSave;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public CompoundTag convertNBT(final DSL.TypeReference type, final DataFixer dataFixer, final CompoundTag nbt,
|
||||
+ final int fromVersion, final int toVersion) {
|
||||
+ return (CompoundTag)dataFixer.update(
|
||||
+ type, new Dynamic<>(NbtOps.INSTANCE, nbt), fromVersion, toVersion
|
||||
+ ).getValue();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean hasMainChunkLoadHook() {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void mainChunkLoad(final ChunkAccess chunk, final SerializableChunkData chunkData) {
|
||||
+
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public List<Entity> modifySavedEntities(final ServerLevel world, final int chunkX, final int chunkZ, final List<Entity> entities) {
|
||||
+ return entities;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void unloadEntity(final Entity entity) {
|
||||
+ entity.setRemoved(Entity.RemovalReason.UNLOADED_TO_CHUNK, org.bukkit.event.entity.EntityRemoveEvent.Cause.UNLOAD);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void postLoadProtoChunk(final ServerLevel world, final ProtoChunk chunk) {
|
||||
+ net.minecraft.world.level.chunk.status.ChunkStatusTasks.postLoadProtoChunk(world, chunk.getEntities());
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int modifyEntityTrackingRange(final Entity entity, final int currentRange) {
|
||||
+ return org.spigotmc.TrackingRange.getEntityTrackingRange(entity, currentRange);
|
||||
+ }
|
||||
+}
|
|
@ -0,0 +1,335 @@
|
|||
--- /dev/null
|
||||
+++ b/ca/spottedleaf/moonrise/paper/util/BaseChunkSystemHooks.java
|
||||
@@ -1,0 +_,332 @@
|
||||
+package ca.spottedleaf.moonrise.paper.util;
|
||||
+
|
||||
+import ca.spottedleaf.concurrentutil.util.Priority;
|
||||
+import com.mojang.logging.LogUtils;
|
||||
+import net.minecraft.server.level.ChunkHolder;
|
||||
+import net.minecraft.server.level.ChunkResult;
|
||||
+import net.minecraft.server.level.FullChunkStatus;
|
||||
+import net.minecraft.server.level.ServerLevel;
|
||||
+import net.minecraft.server.level.ServerPlayer;
|
||||
+import net.minecraft.server.level.TicketType;
|
||||
+import net.minecraft.world.level.ChunkPos;
|
||||
+import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
+import net.minecraft.world.level.chunk.LevelChunk;
|
||||
+import net.minecraft.world.level.chunk.status.ChunkPyramid;
|
||||
+import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||
+import net.minecraft.world.level.chunk.status.ChunkStep;
|
||||
+import org.bukkit.Bukkit;
|
||||
+import org.slf4j.Logger;
|
||||
+import java.util.ArrayList;
|
||||
+import java.util.List;
|
||||
+import java.util.concurrent.CompletableFuture;
|
||||
+import java.util.function.Consumer;
|
||||
+
|
||||
+public abstract class BaseChunkSystemHooks implements ca.spottedleaf.moonrise.common.util.ChunkSystemHooks {
|
||||
+
|
||||
+ private static final Logger LOGGER = LogUtils.getLogger();
|
||||
+ private static final ChunkStep FULL_CHUNK_STEP = ChunkPyramid.GENERATION_PYRAMID.getStepTo(ChunkStatus.FULL);
|
||||
+ private static final TicketType<Long> CHUNK_LOAD = TicketType.create("chunk_load", Long::compareTo);
|
||||
+
|
||||
+ private long chunkLoadCounter = 0L;
|
||||
+
|
||||
+ private static int getDistance(final ChunkStatus status) {
|
||||
+ return FULL_CHUNK_STEP.getAccumulatedRadiusOf(status);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void scheduleChunkTask(final ServerLevel level, final int chunkX, final int chunkZ, final Runnable run) {
|
||||
+ this.scheduleChunkTask(level, chunkX, chunkZ, run, Priority.NORMAL);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void scheduleChunkTask(final ServerLevel level, final int chunkX, final int chunkZ, final Runnable run, final Priority priority) {
|
||||
+ level.chunkSource.mainThreadProcessor.execute(run);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void scheduleChunkLoad(final ServerLevel level, final int chunkX, final int chunkZ, final boolean gen,
|
||||
+ final ChunkStatus toStatus, final boolean addTicket, final Priority priority,
|
||||
+ final Consumer<ChunkAccess> onComplete) {
|
||||
+ if (gen) {
|
||||
+ this.scheduleChunkLoad(level, chunkX, chunkZ, toStatus, addTicket, priority, onComplete);
|
||||
+ return;
|
||||
+ }
|
||||
+ this.scheduleChunkLoad(level, chunkX, chunkZ, ChunkStatus.EMPTY, addTicket, priority, (final ChunkAccess chunk) -> {
|
||||
+ if (chunk == null) {
|
||||
+ if (onComplete != null) {
|
||||
+ onComplete.accept(null);
|
||||
+ }
|
||||
+ } else {
|
||||
+ if (chunk.getPersistedStatus().isOrAfter(toStatus)) {
|
||||
+ BaseChunkSystemHooks.this.scheduleChunkLoad(level, chunkX, chunkZ, toStatus, addTicket, priority, onComplete);
|
||||
+ } else {
|
||||
+ if (onComplete != null) {
|
||||
+ onComplete.accept(null);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ });
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void scheduleChunkLoad(final ServerLevel level, final int chunkX, final int chunkZ, final ChunkStatus toStatus,
|
||||
+ final boolean addTicket, final Priority priority, final Consumer<ChunkAccess> onComplete) {
|
||||
+ if (!Bukkit.isOwnedByCurrentRegion(level.getWorld(), chunkX, chunkZ)) {
|
||||
+ this.scheduleChunkTask(level, chunkX, chunkZ, () -> {
|
||||
+ BaseChunkSystemHooks.this.scheduleChunkLoad(level, chunkX, chunkZ, toStatus, addTicket, priority, onComplete);
|
||||
+ }, priority);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ final int minLevel = 33 + getDistance(toStatus);
|
||||
+ final Long chunkReference = addTicket ? Long.valueOf(++this.chunkLoadCounter) : null;
|
||||
+ final ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ);
|
||||
+
|
||||
+ if (addTicket) {
|
||||
+ level.chunkSource.addTicketAtLevel(CHUNK_LOAD, chunkPos, minLevel, chunkReference);
|
||||
+ }
|
||||
+ level.chunkSource.runDistanceManagerUpdates();
|
||||
+
|
||||
+ final Consumer<ChunkAccess> loadCallback = (final ChunkAccess chunk) -> {
|
||||
+ try {
|
||||
+ if (onComplete != null) {
|
||||
+ onComplete.accept(chunk);
|
||||
+ }
|
||||
+ } catch (final Throwable thr) {
|
||||
+ LOGGER.error("Exception handling chunk load callback", thr);
|
||||
+ com.destroystokyo.paper.util.SneakyThrow.sneaky(thr);
|
||||
+ } finally {
|
||||
+ if (addTicket) {
|
||||
+ level.chunkSource.addTicketAtLevel(net.minecraft.server.level.TicketType.UNKNOWN, chunkPos, minLevel, chunkPos);
|
||||
+ level.chunkSource.removeTicketAtLevel(CHUNK_LOAD, chunkPos, minLevel, chunkReference);
|
||||
+ }
|
||||
+ }
|
||||
+ };
|
||||
+
|
||||
+ final ChunkHolder holder = level.chunkSource.chunkMap.updatingChunkMap.get(ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey(chunkX, chunkZ));
|
||||
+
|
||||
+ if (holder == null || holder.getTicketLevel() > minLevel) {
|
||||
+ loadCallback.accept(null);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ final CompletableFuture<ChunkResult<ChunkAccess>> loadFuture = holder.scheduleChunkGenerationTask(toStatus, level.chunkSource.chunkMap);
|
||||
+
|
||||
+ if (loadFuture.isDone()) {
|
||||
+ loadCallback.accept(loadFuture.join().orElse(null));
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ loadFuture.whenCompleteAsync((final ChunkResult<ChunkAccess> result, final Throwable thr) -> {
|
||||
+ if (thr != null) {
|
||||
+ loadCallback.accept(null);
|
||||
+ return;
|
||||
+ }
|
||||
+ loadCallback.accept(result.orElse(null));
|
||||
+ }, (final Runnable r) -> {
|
||||
+ BaseChunkSystemHooks.this.scheduleChunkTask(level, chunkX, chunkZ, r, Priority.HIGHEST);
|
||||
+ });
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void scheduleTickingState(final ServerLevel level, final int chunkX, final int chunkZ,
|
||||
+ final FullChunkStatus toStatus, final boolean addTicket,
|
||||
+ final Priority priority, final Consumer<LevelChunk> onComplete) {
|
||||
+ // This method goes unused until the chunk system rewrite
|
||||
+ if (toStatus == FullChunkStatus.INACCESSIBLE) {
|
||||
+ throw new IllegalArgumentException("Cannot wait for INACCESSIBLE status");
|
||||
+ }
|
||||
+
|
||||
+ if (!Bukkit.isOwnedByCurrentRegion(level.getWorld(), chunkX, chunkZ)) {
|
||||
+ this.scheduleChunkTask(level, chunkX, chunkZ, () -> {
|
||||
+ BaseChunkSystemHooks.this.scheduleTickingState(level, chunkX, chunkZ, toStatus, addTicket, priority, onComplete);
|
||||
+ }, priority);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ final int minLevel = 33 - (toStatus.ordinal() - 1);
|
||||
+ final int radius = toStatus.ordinal() - 1;
|
||||
+ final Long chunkReference = addTicket ? Long.valueOf(++this.chunkLoadCounter) : null;
|
||||
+ final ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ);
|
||||
+
|
||||
+ if (addTicket) {
|
||||
+ level.chunkSource.addTicketAtLevel(CHUNK_LOAD, chunkPos, minLevel, chunkReference);
|
||||
+ }
|
||||
+ level.chunkSource.runDistanceManagerUpdates();
|
||||
+
|
||||
+ final Consumer<LevelChunk> loadCallback = (final LevelChunk chunk) -> {
|
||||
+ try {
|
||||
+ if (onComplete != null) {
|
||||
+ onComplete.accept(chunk);
|
||||
+ }
|
||||
+ } catch (final Throwable thr) {
|
||||
+ LOGGER.error("Exception handling chunk load callback", thr);
|
||||
+ com.destroystokyo.paper.util.SneakyThrow.sneaky(thr);
|
||||
+ } finally {
|
||||
+ if (addTicket) {
|
||||
+ level.chunkSource.addTicketAtLevel(TicketType.UNKNOWN, chunkPos, minLevel, chunkPos);
|
||||
+ level.chunkSource.removeTicketAtLevel(CHUNK_LOAD, chunkPos, minLevel, chunkReference);
|
||||
+ }
|
||||
+ }
|
||||
+ };
|
||||
+
|
||||
+ final ChunkHolder holder = level.chunkSource.chunkMap.updatingChunkMap.get(ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey(chunkX, chunkZ));
|
||||
+
|
||||
+ if (holder == null || holder.getTicketLevel() > minLevel) {
|
||||
+ loadCallback.accept(null);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ final CompletableFuture<ChunkResult<LevelChunk>> tickingState;
|
||||
+ switch (toStatus) {
|
||||
+ case FULL: {
|
||||
+ tickingState = holder.getFullChunkFuture();
|
||||
+ break;
|
||||
+ }
|
||||
+ case BLOCK_TICKING: {
|
||||
+ tickingState = holder.getTickingChunkFuture();
|
||||
+ break;
|
||||
+ }
|
||||
+ case ENTITY_TICKING: {
|
||||
+ tickingState = holder.getEntityTickingChunkFuture();
|
||||
+ break;
|
||||
+ }
|
||||
+ default: {
|
||||
+ throw new IllegalStateException("Cannot reach here");
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (tickingState.isDone()) {
|
||||
+ loadCallback.accept(tickingState.join().orElse(null));
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ tickingState.whenCompleteAsync((final ChunkResult<LevelChunk> result, final Throwable thr) -> {
|
||||
+ if (thr != null) {
|
||||
+ loadCallback.accept(null);
|
||||
+ return;
|
||||
+ }
|
||||
+ loadCallback.accept(result.orElse(null));
|
||||
+ }, (final Runnable r) -> {
|
||||
+ BaseChunkSystemHooks.this.scheduleChunkTask(level, chunkX, chunkZ, r, Priority.HIGHEST);
|
||||
+ });
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public List<ChunkHolder> getVisibleChunkHolders(final ServerLevel level) {
|
||||
+ return new ArrayList<>(level.chunkSource.chunkMap.visibleChunkMap.values());
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public List<ChunkHolder> getUpdatingChunkHolders(final ServerLevel level) {
|
||||
+ return new ArrayList<>(level.chunkSource.chunkMap.updatingChunkMap.values());
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int getVisibleChunkHolderCount(final ServerLevel level) {
|
||||
+ return level.chunkSource.chunkMap.visibleChunkMap.size();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int getUpdatingChunkHolderCount(final ServerLevel level) {
|
||||
+ return level.chunkSource.chunkMap.updatingChunkMap.size();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean hasAnyChunkHolders(final ServerLevel level) {
|
||||
+ return this.getUpdatingChunkHolderCount(level) != 0;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void onChunkHolderCreate(final ServerLevel level, final ChunkHolder holder) {
|
||||
+
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void onChunkHolderDelete(final ServerLevel level, final ChunkHolder holder) {
|
||||
+
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void onChunkPreBorder(final LevelChunk chunk, final ChunkHolder holder) {
|
||||
+
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void onChunkBorder(final LevelChunk chunk, final ChunkHolder holder) {
|
||||
+
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void onChunkNotBorder(final LevelChunk chunk, final ChunkHolder holder) {
|
||||
+
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void onChunkPostNotBorder(final LevelChunk chunk, final ChunkHolder holder) {
|
||||
+
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void onChunkTicking(final LevelChunk chunk, final ChunkHolder holder) {
|
||||
+
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void onChunkNotTicking(final LevelChunk chunk, final ChunkHolder holder) {
|
||||
+
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void onChunkEntityTicking(final LevelChunk chunk, final ChunkHolder holder) {
|
||||
+
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void onChunkNotEntityTicking(final LevelChunk chunk, final ChunkHolder holder) {
|
||||
+
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public ChunkHolder getUnloadingChunkHolder(final ServerLevel level, final int chunkX, final int chunkZ) {
|
||||
+ return level.chunkSource.chunkMap.getUnloadingChunkHolder(chunkX, chunkZ);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int getSendViewDistance(final ServerPlayer player) {
|
||||
+ return this.getViewDistance(player);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int getViewDistance(final ServerPlayer player) {
|
||||
+ final ServerLevel level = player.serverLevel();
|
||||
+ if (level == null) {
|
||||
+ return Bukkit.getViewDistance();
|
||||
+ }
|
||||
+ return level.chunkSource.chunkMap.serverViewDistance;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int getTickViewDistance(final ServerPlayer player) {
|
||||
+ final ServerLevel level = player.serverLevel();
|
||||
+ if (level == null) {
|
||||
+ return Bukkit.getSimulationDistance();
|
||||
+ }
|
||||
+ return level.chunkSource.chunkMap.distanceManager.simulationDistance;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void addPlayerToDistanceMaps(final ServerLevel world, final ServerPlayer player) {
|
||||
+
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void removePlayerFromDistanceMaps(final ServerLevel world, final ServerPlayer player) {
|
||||
+
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void updateMaps(final ServerLevel world, final ServerPlayer player) {
|
||||
+
|
||||
+ }
|
||||
+}
|
|
@ -1,6 +1,6 @@
|
|||
--- a/com/mojang/authlib/yggdrasil/YggdrasilGameProfileRepository.java
|
||||
+++ b/com/mojang/authlib/yggdrasil/YggdrasilGameProfileRepository.java
|
||||
@@ -44,6 +44,7 @@
|
||||
@@ -44,6 +_,7 @@
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
final int page = 0;
|
||||
|
@ -8,7 +8,7 @@
|
|||
|
||||
for (final List<String> request : Iterables.partition(criteria, ENTRIES_PER_PAGE)) {
|
||||
final List<String> normalizedRequest = request.stream().map(YggdrasilGameProfileRepository::normalizeName).toList();
|
||||
@@ -75,6 +76,12 @@
|
||||
@@ -75,6 +_,12 @@
|
||||
LOGGER.debug("Couldn't find profile {}", name);
|
||||
callback.onProfileLookupFailed(name, new ProfileNotFoundException("Server did not find the requested profile"));
|
||||
}
|
|
@ -1,14 +1,6 @@
|
|||
--- a/com/mojang/brigadier/CommandDispatcher.java
|
||||
+++ b/com/mojang/brigadier/CommandDispatcher.java
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
package com.mojang.brigadier;
|
||||
|
||||
+// CHECKSTYLE:OFF
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import com.mojang.brigadier.context.CommandContextBuilder;
|
||||
@@ -297,15 +298,21 @@
|
||||
@@ -297,15 +_,21 @@
|
||||
List<ParseResults<S>> potentials = null;
|
||||
final int cursor = originalReader.getCursor();
|
||||
|
||||
|
@ -31,7 +23,7 @@
|
|||
} catch (final RuntimeException ex) {
|
||||
throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherParseException().createWithContext(reader, ex.getMessage());
|
||||
}
|
||||
@@ -320,6 +327,7 @@
|
||||
@@ -320,6 +_,7 @@
|
||||
}
|
||||
errors.put(child, ex);
|
||||
reader.setCursor(cursor);
|
||||
|
@ -39,7 +31,7 @@
|
|||
continue;
|
||||
}
|
||||
|
||||
@@ -451,7 +459,7 @@
|
||||
@@ -451,7 +_,7 @@
|
||||
}
|
||||
|
||||
private String getSmartUsage(final CommandNode<S> node, final S source, final boolean optional, final boolean deep) {
|
||||
|
@ -48,16 +40,16 @@
|
|||
return null;
|
||||
}
|
||||
|
||||
@@ -465,7 +473,7 @@
|
||||
final String redirect = node.getRedirect() == this.root ? "..." : "-> " + node.getRedirect().getUsageText();
|
||||
return self + CommandDispatcher.ARGUMENT_SEPARATOR + redirect;
|
||||
@@ -465,7 +_,7 @@
|
||||
final String redirect = node.getRedirect() == root ? "..." : "-> " + node.getRedirect().getUsageText();
|
||||
return self + ARGUMENT_SEPARATOR + redirect;
|
||||
} else {
|
||||
- final Collection<CommandNode<S>> children = node.getChildren().stream().filter(c -> c.canUse(source)).collect(Collectors.toList());
|
||||
+ final Collection<CommandNode<S>> children = node.getChildren().stream().filter(c -> source == null || c.canUse(source)).collect(Collectors.toList()); // Paper
|
||||
if (children.size() == 1) {
|
||||
final String usage = this.getSmartUsage(children.iterator().next(), source, childOptional, childOptional);
|
||||
final String usage = getSmartUsage(children.iterator().next(), source, childOptional, childOptional);
|
||||
if (usage != null) {
|
||||
@@ -537,10 +545,14 @@
|
||||
@@ -537,10 +_,14 @@
|
||||
int i = 0;
|
||||
for (final CommandNode<S> node : parent.getChildren()) {
|
||||
CompletableFuture<Suggestions> future = Suggestions.empty();
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue