diff --git a/.gitmodules b/.gitmodules index 150bf03a..efe7dc32 100644 --- a/.gitmodules +++ b/.gitmodules @@ -32,3 +32,6 @@ [submodule "Yatopia-Server"] path = Yatopia-Server +[submodule "upstream/Purpur"] + path = upstream/Purpur + url = https://github.com/pl3xgaming/Purpur diff --git a/PATCHES.md b/PATCHES.md index 7a151e33..4e70e624 100644 --- a/PATCHES.md +++ b/PATCHES.md @@ -8,52 +8,185 @@ # Patches | Side | Patch | Author | CoAuthors | | ----- | ------------- |:-------------:| -----:| +| server | AFK API | William Blake Galbreath | | +| api | AFK API | William Blake Galbreath | | +| server | API for any mob to burn daylight | Ben Kerllenevich | | +| api | API for any mob to burn daylight | Ben Kerllenevich | | +| server | Ability to re-add farmland mechanics from Alpha | Yive | | | server | Actually unload POI data | Spottedleaf | | +| server | Add /ping command | William Blake Galbreath | | +| server | Add 5 second tps average in /tps | William Blake Galbreath | | +| server | Add EntityTeleportHinderedEvent | Mariell Hoversholm | | +| api | Add EntityTeleportHinderedEvent | Mariell Hoversholm | | | api | Add GameProfileLookupEvent | tr7zw | | | server | Add GameProfileLookupEvent | tr7zw | | | server | Add IntelliJ IDEA runnable | Zoe | | +| server | Add MC-4 fix back | BillyGalbreath | | | api | Add NBT API as a first-class lib | tr7zw | | | server | Add NBT API as a first-class lib | tr7zw | | +| server | Add StructureGenerateEvent | Nahuel | Mariell Hoversholm | +| api | Add StructureGenerateEvent | Nahuel | Mariell Hoversholm | | server | Add Velocity natives for encryption and compression | Andrew Steinborn | | +| server | Add adjustable breeding cooldown to config | montlikadani | | +| server | Add allow water in end world option | William Blake Galbreath | | +| server | Add boat fall damage config | BillyGalbreath | | +| server | Add canSaveToDisk to Entity | William Blake Galbreath | | +| server | Add config change multiplier critical damage value | DoctaEnkoda | | +| server | Add config for allowing Endermen to despawn even while | jmp | | +| server | Add config for snow on blue ice | BillyGalbreath | | +| server | Add config for villager trading | Ben Kerllenevich | | +| server | Add configurable snowball damage | BillyGalbreath | | +| server | Add credits command | Encode42 | | +| server | Add critical hit check to EntityDamagedByEntityEvent | BillyGalbreath | | +| api | Add critical hit check to EntityDamagedByEntityEvent | BillyGalbreath | | +| server | Add demo command | BillyGalbreath | | +| api | Add enchantment target for bows and crossbows | BillyGalbreath | | +| server | Add enderman and creeper griefing controls | William Blake Galbreath | | +| server | Add ghast allow-griefing option | BillyGalbreath | | | api | Add last tick time API | Ivan Pekov | tr7zw | | server | Add last tick time API | Ivan Pekov | tr7zw | +| server | Add mobGriefing bypass to everything affected | Encode42 | | +| server | Add no-random-tick block list | William Blake Galbreath | | | server | Add nspt command | Ivan Pekov | | +| server | Add obfhelpers for plugin use | William Blake Galbreath | | +| server | Add option for boats to eject players on land | William Blake Galbreath | | +| server | Add option to allow loyalty on tridents to work in the void | William Blake Galbreath | | +| server | Add option to disable certain block updates | William Blake Galbreath | | +| server | Add option to disable dolphin treasure searching | William Blake Galbreath | | | server | Add option to disable observer clocks | Phoenix616 | | +| server | Add option to disable zombie aggressiveness towards villagers | nitricspace | | +| api | Add option to disable zombie aggressiveness towards villagers | nitricspace | | +| server | Add option to set armorstand step height | William Blake Galbreath | | +| server | Add option to teleport to spawn if outside world border | William Blake Galbreath | | | server | Add packet limiter config | Spottedleaf | | +| server | Add permission for F3+N debug | William Blake Galbreath | | +| server | Add phantom spawning options | William Blake Galbreath | | +| server | Add player death exp control options | William Blake Galbreath | | +| server | Add predicate to recipe's ExactChoice ingredient | William Blake Galbreath | | +| api | Add predicate to recipe's ExactChoice ingredient | William Blake Galbreath | | | server | Add soft async catcher | Spottedleaf | | +| server | Add tablist suffix option for afk | montlikadani | | | server | Add timings for Behavior | Phoenix616 | | | server | Add timings for Pathfinder | MrIvanPlays | | +| server | Add toggle for end portal safe teleporting | BillyGalbreath | | +| server | Add toggle for sand duping fix | BillyGalbreath | | +| server | Add twisting and weeping vines growth rates | BillyGalbreath | | +| server | Add unsafe Entity serialization API | Mariell Hoversholm | | +| api | Add unsafe Entity serialization API | Mariell Hoversholm | | +| server | Add vindicator johnny spawn chance | William Blake Galbreath | | +| server | Add wither skeleton takes wither damage option | William Blake Galbreath | | +| server | Advancement API | William Blake Galbreath | | +| api | Advancement API | William Blake Galbreath | | | server | Airplane Configuration | Paul Sauve | | | server | Airplane MC Dev Fixes | Paul Sauve | | | server | Airplane Profiler | Paul Sauve | | | server | Allow Entities to be removed from a world while ticking | Spottedleaf | | +| server | Allow anvil colors | William Blake Galbreath | | +| server | Allow color codes in books | William Blake Galbreath | | | server | Allow controlled flushing for network manager | Spottedleaf | | +| server | Allow infinite and mending enchantments together | William Blake Galbreath | | +| server | Allow infinity on crossbows | Ben Kerllenevich | | +| api | Allow inventory resizing | William Blake Galbreath | | +| server | Allow leashing villagers | William Blake Galbreath | | +| server | Allow soil to moisten from water directly under it | William Blake Galbreath | | +| server | Allow toggling special MobSpawners per world | jmp | | +| server | Allows change broadcast message by player | DoctaEnkoda | | +| server | Allows you to change the thrust limit of a piston by World | DoctaEnkoda | | +| api | Alphabetize in-game /plugins list | BillyGalbreath | | +| server | Alternative Keepalive Handling | William Blake Galbreath | | +| server | Anvil API | William Blake Galbreath | | +| api | Anvil API | William Blake Galbreath | | +| server | Apply display names from item forms of entities to entities | jmp | | +| server | Arrows should not reset despawn counter | William Blake Galbreath | | | server | Attempt to recalculate regionfile header if it is corrupt | Spottedleaf | | | server | Avoid double I/O operation on load player file | ㄗㄠˋ ㄑㄧˊ | | +| server | Barrels and enderchests 6 rows | William Blake Galbreath | | | server | Be aware of entity teleports when chunk checking entities | Spottedleaf | | +| server | Beacon Activation Range Configurable | DoctaEnkoda | | +| server | Bee can work when raining or at night | DoctaEnkoda | | | server | Better checking for useless move packets | Paul Sauve | | | server | Brand changes | Spottedleaf | | | server | Brandings | YatopiaMC | | +| server | Break individual slabs when sneaking | BillyGalbreath | | +| server | Breedable Polar Bears | William Blake Galbreath | | +| server | Breedable parrots | BillyGalbreath | | +| server | Bring back server name | William Blake Galbreath | | +| api | Bring back server name | William Blake Galbreath | | | server | Cache climbing check for activation | Paul Sauve | | | server | Cache coordinate key for micro opt | Paul Sauve | | | server | Cache entityhuman display name | Paul Sauve | | | server | Cache palette array | Paul Sauve | | +| server | Cat spawning options | William Blake Galbreath | | | server | Change writes to use NORMAL priority rather than LOW | Spottedleaf | | +| server | Changeable Mob Left Handed Chance | Ben Kerllenevich | | +| server | Charged creeper naturally spawn | William Blake Galbreath | | +| api | ChatColor conveniences | William Blake Galbreath | | +| server | Chickens can retaliate | William Blake Galbreath | | +| server | Config MobEffect by world | DoctaEnkoda | | +| server | Config for Enderman to aggro spawned Endermites | Encode42 | | +| server | Config for changing the blocks that turn into paths | 12emin34 | | +| server | Config for health to impact Creeper explosion radius | Encode42 | | +| server | Config for powered rail activation distance | Encode42 | | +| server | Config for skipping night | Ben Kerllenevich | | +| server | Config for unverified username message | Ben Kerllenevich | | +| server | Config for wither explosion radius | Ben Kerllenevich | | +| server | Config migration: climbing should not bypass cramming | jmp | | +| server | Config migration: disable saving projectiles to disk -> | jmp | | +| server | Config to allow Note Block sounds when blocked | Encode42 | | +| server | Config to allow for unsafe enchants | Encode42 | | +| server | Config to always tame in Creative | Encode42 | | +| server | Config to change max number of bees | DoctaEnkoda | | +| server | Config to disable Llama caravans | Encode42 | | +| server | Config to disable hostile mob spawn on ice | Encode42 | | | server | Config to disable method profiler | Paul Sauve | | +| server | Config to ignore Dragon Head wearers and stare aggro | Encode42 | | +| server | Config to ignore nearby mobs when sleeping | Encode42 | | +| server | Config to make Creepers explode on death | Encode42 | | +| server | Config to show Armor Stand arms on spawn | Encode42 | | +| server | Config to use infinity bows without arrows | Encode42 | | +| server | Configs for if Wither/Ender Dragon can ride vehicles | jmp | | | server | Configurable BlockPhysicsEvent | Mykyta Komarnytskyy | | +| server | Configurable Ender Pearl cooldown, damage, and Endermite RNG | Encode42 | | +| server | Configurable TPS Catchup | William Blake Galbreath | | +| server | Configurable chance for wolves to spawn rabid | Encode42 | | | server | Configurable criterion triggers | Mykyta Komarnytskyy | | +| server | Configurable damage settings for magma blocks | Ben Kerllenevich | | +| server | Configurable daylight cycle | William Blake Galbreath | | +| server | Configurable default wolf collar color | Encode42 | | +| server | Configurable dungeon seed | William Blake Galbreath | | | server | Configurable enchanting table tick | Ivan Pekov | | +| server | Configurable end spike seed | William Blake Galbreath | | +| server | Configurable entity base attributes | BillyGalbreath | | | server | Configurable flight checks | l_MrBoom_l | | +| server | Configurable jockey options | William Blake Galbreath | | | server | Configurable movement checks | l_MrBoom_l | | +| api | Configurable permission message upgrades | William Blake Galbreath | | +| server | Configurable powered rail boost modifier | Callum Seabrook | | +| server | Configurable ravager griefable blocks list | BillyGalbreath | | +| server | Configurable server mod name | William Blake Galbreath | | +| server | Configurable sponge absorption | Encode42 | | +| server | Configurable villager brain ticks | William Blake Galbreath | | +| server | Configurable villager breeding | draycia | | +| server | Configurable void damage height and damage | William Blake Galbreath | | +| api | Conflict on change for adventure deprecations | BillyGalbreath | | | server | Consolidate flush calls for entity tracker packets | Spottedleaf | | | server | Copy passenger list in enderTeleportTo | Spottedleaf | | | server | Correctly handle recursion for chunkholder updates | Spottedleaf | | +| server | Cows eat mushrooms | William Blake Galbreath | | +| server | Crying obsidian valid for portal frames | William Blake Galbreath | | | server | Custom Locale Support | Zoe | | | server | Custom table implementation for blockstate state lookups | Spottedleaf | | +| server | Customizable wither health and healing | jmp | | +| api | Default permissions | William Blake Galbreath | | | server | Delay chunk unloads | Spottedleaf | | +| server | Despawn rate config options per projectile type | jmp | | | server | Detail more information in watchdog dumps | Spottedleaf | | +| server | Disable loot drops on death by cramming | William Blake Galbreath | | +| server | Disable outdated build check | William Blake Galbreath | | | api | Disable reload command | Ivan Pekov | | | server | Disable the Snooper | Sotr | | +| server | Dispenser curse of binding protection | William Blake Galbreath | | +| server | Dispensers place anvils option | William Blake Galbreath | | | server | Distance manager tick timings | Spottedleaf | | | server | Do not allow the server to unload chunks at request of | Spottedleaf | | | server | Do not allow ticket level changes while unloading | Spottedleaf | | @@ -69,49 +202,120 @@ # Patches | server | Don't read neighbour chunk data off disk when converting | Spottedleaf | | | server | Don't trigger Lootable Refresh for non player interaction | Aikar | | | server | Don't wake up entities when damage event is cancelled | Phoenix616 | | +| server | Dont run with scissors! | JustDoom | | +| server | Dont send useless entity packets | William Blake Galbreath | | +| server | Drowning Settings | Ben Kerllenevich | | | server | Dynamic activation range | Paul Sauve | | +| server | EMC - Configurable disable give dropping | Aikar | | +| server | EMC - MonsterEggSpawnEvent | Aikar | | +| api | EMC - MonsterEggSpawnEvent | Aikar | | | server | Early return optimization for target finding | Paul Sauve | | +| server | End crystal explosion options | Ben Kerllenevich | | +| server | End gateway should check if entity can use portal | William Blake Galbreath | | +| server | Ender dragon always drop full exp | William Blake Galbreath | | | server | Ensure pools create daemon threads | Ivan Pekov | | +| server | Entities can use portals configuration | William Blake Galbreath | | +| server | Entities pick up loot bypass mob-griefing gamerule | William Blake Galbreath | | +| server | Entity lifespan | William Blake Galbreath | | | server | Execute chunk tasks mid-tick | Spottedleaf | | +| api | ExecuteCommandEvent | William Blake Galbreath | | | api | Expose findClass for profiler | Paul Sauve | | +| server | Farmland trampling changes | Mariell Hoversholm | | +| server | Fix 'outdated server' showing in ping before server fully | William Blake Galbreath | | | server | Fix IndexOutOfBoundsException when sending too many changes | Ivan Pekov | | | server | Fix LightEngineThreaded memory leak | Ivan Pekov | | | server | Fix Log4j Warning | snoopdoooggyttv | | | server | Fix NPE in pickup logic for arrow | Spottedleaf | | +| server | Fix SPIGOT-6278 | BillyGalbreath | | +| server | Fix advancement triggers on entity death | BillyGalbreath | | | server | Fix chunks refusing to unload at low TPS | Spottedleaf | | +| server | Fix cow rotation when shearing mooshroom | William Blake Galbreath | | | server | Fix exp drop of zombie pigmen (MC-56653) | Phoenix616 | | | server | Fix incorrect isRealPlayer init | Spottedleaf | | +| api | Fix javadoc warnings (missing @param and @return) | BillyGalbreath | | | server | Fix lead fall dmg config | tr7zw | | +| server | Fix rotating UP/DOWN CW and CCW | BillyGalbreath | | +| server | Fix stuck in portals | BillyGalbreath | | | server | Fix swamp hut cat generation deadlock | Spottedleaf | | +| server | Fix the dead lagging the server | William Blake Galbreath | | +| server | Fix vanilla command permission handler | William Blake Galbreath | | +| server | Flying Fall Damage API | TreyRuffy | | +| api | Flying Fall Damage API | TreyRuffy | | +| server | Flying squids! Oh my! | William Blake Galbreath | | +| server | Full netherite armor grants fire resistance | BillyGalbreath | | +| api | Full netherite armor grants fire resistance | BillyGalbreath | | +| server | Gamemode extra permissions | BillyGalbreath | | +| server | Giants AI settings | William Blake Galbreath | | | server | Global Eula file | tr7zw | | | server | Heavily optimize furnance fuel and recipe lookups | tr7zw | Mykyta Komarn | | server | Heavily optimize recipe lookups in CraftingManager | Mykyta Komarn | Ivan Pekov, ishland | +| server | Hide hidden players from entity selector | BillyGalbreath | | | server | Highly optimise single and multi-AABB VoxelShapes and | Spottedleaf | | | server | Highly optimize VillagePlace filtering | Ivan Pekov | | +| server | Illusioners AI settings | William Blake Galbreath | | +| server | Implement Mob Blindness | Encode42 | | +| server | Implement TPSBar | BillyGalbreath | | +| server | Implement bed explosion options | William Blake Galbreath | | +| server | Implement configurable search radius for villagers to spawn | William Blake Galbreath | | +| server | Implement elytra settings | William Blake Galbreath | | +| server | Implement infinite lava | William Blake Galbreath | | +| server | Implement respawn anchor explosion options | William Blake Galbreath | | | server | Improve abnormal server shutdown process | Spottedleaf | | | server | Improve async tp to not load chunks when crossing worlds | Spottedleaf | | | server | Improve container checking with a bitset | Paul Sauve | | | server | Improve fluid direction caching | Paul Sauve | | | server | Improve paper prevent moving into unloaded chunk check | Spottedleaf | | +| server | Infinite fuel furnace | William Blake Galbreath | | +| server | Infinity bow settings | William Blake Galbreath | | +| server | Iron golem poppy calms anger | BillyGalbreath | | +| api | Iron golem poppy calms anger | BillyGalbreath | | +| server | Item entity immunities | William Blake Galbreath | | +| api | Item entity immunities | William Blake Galbreath | | | server | Item stuck sleep config | tr7zw | | +| server | ItemFactory#getMonsterEgg | William Blake Galbreath | | +| api | ItemFactory#getMonsterEgg | William Blake Galbreath | | +| api | ItemStack convenience methods | William Blake Galbreath | | +| server | Kelp weeping and twisting vines configurable max growth age | BillyGalbreath | | | server | Lag compensate block breaking | Spottedleaf | | +| server | Lagging threshold | William Blake Galbreath | | +| api | Lagging threshold | William Blake Galbreath | | +| server | Left handed API | BillyGalbreath | | +| api | Left handed API | BillyGalbreath | | | server | Lithium: CompactSineLUT | JellySquid | | +| server | LivingEntity safeFallDistance | William Blake Galbreath | | +| api | LivingEntity safeFallDistance | William Blake Galbreath | | +| server | LivingEntity#broadcastItemBreak | William Blake Galbreath | | +| api | LivingEntity#broadcastItemBreak | William Blake Galbreath | | +| server | Llama API | William Blake Galbreath | | +| api | Llama API | William Blake Galbreath | | +| server | Lobotomize stuck villagers | BillyGalbreath | | +| server | Logger settings (suppressing pointless logs) | William Blake Galbreath | | +| server | MC-147659 - Fix non black cats spawning in swamp huts | William Blake Galbreath | | +| server | MC-168772 Fix - Add turtle egg block options | William Blake Galbreath | | | server | MC-Dev fixes | Spottedleaf | | | server | Make CallbackExecutor strict again | Spottedleaf | | +| server | Make Iron Golems Swim | William Blake Galbreath | | | server | Make VoxelShapeCollisionEntity lazier | Paul Sauve | | +| server | Make anvil cumulative cost configurable | 12emin34 | | +| server | Make entity breeding times configurable | jmp | | | server | Make entity tracker use highest range of passengers | Spottedleaf | | +| server | Make lava flow speed configurable | William Blake Galbreath | | | server | Make sure inlined getChunkAt has inlined logic for loaded | Spottedleaf | | | server | Manually inline methods in BlockPosition | Spottedleaf | | +| server | Mending mends most damages equipment first | William Blake Galbreath | | +| server | Minecart settings and WASD controls | William Blake Galbreath | | | api | Modify POM | YatopiaMC | | | server | Modify POM | YatopiaMC | | | server | Modify default configs | tr7zw | | | server | More debug for plugins not shutting down tasks | Paul Sauve | | +| server | Movement options for armor stands | Mariell Hoversholm | | | server | Multi-Threaded Server Ticking Vanilla | Spottedleaf | | | server | Multi-Threaded ticking CraftBukkit | Spottedleaf | | | server | Name craft scheduler threads according to the plugin using | Spottedleaf | | | server | New nbt cache | Hugo Planque | ishland | | server | Nuke streams off BlockPosition | Ivan Pekov | | | server | Nuke streams off SectionPosition | Ivan Pekov | | +| server | One Punch Man! | Fourmisain | | | server | Oprimise map impl for tracked players | Spottedleaf | | | server | Optimise BlockSoil nearby water lookup | Spottedleaf | | | server | Optimise WorldServer#notify | Spottedleaf | | @@ -129,25 +333,55 @@ # Patches | server | Optimize TileEntity load/unload | tr7zw | | | server | Optimize Villagers | Ivan Pekov | | | server | Optimize advancement loading | Ivan Pekov | | +| server | Optimize collisions | DoctaEnkoda | | | server | Optimize inventory API item handling | Phoenix616 | | | server | Optimize random calls in chunk ticking | Paul Sauve | | | server | Optimize redundant calls | Paul Sauve | | | server | Optimize some stuff in WorldServer ticking | MrIvanPlays | | | server | Optimize whitelist command for multiple additions / removals | Ivan Pekov | | +| server | Option for Villager Clerics to farm Nether Wart | jmp | | +| server | Option for chests to open even with a solid block on top | jmp | | | server | Option for simpler Villagers | tr7zw | | +| server | Option to disable dragon egg teleporting | BillyGalbreath | | +| server | Option to make doors require redstone | BillyGalbreath | | +| server | Option to toggle milk curing bad omen | William Blake Galbreath | | +| server | Origami - Fix ProtocolLib issues on Java 15 | Phoenix616 | | | server | Origami Server Config | Phoenix616 | | +| server | PaperPR - Config option for Piglins guarding chests | jmp | | | server | Patch Paper to use fast item merge raytracing | Paul Sauve | | | server | Per World Spawn Limits | Chase Whipple | | | server | Per entity (type) collision settings | MrIvanPlays | tr7zw | | api | Per player viewdistances | Spottedleaf | | +| server | Persistent TileEntity Lore and DisplayName | jmp | | +| server | Phantom flames on swoop | BillyGalbreath | | +| server | Phantoms attracted to crystals and crystals shoot phantoms | William Blake Galbreath | | +| api | Phantoms attracted to crystals and crystals shoot phantoms | William Blake Galbreath | | +| server | Phantoms burn in light | draycia | | +| server | Piglin portal spawn modifier | BillyGalbreath | | +| server | Pigs give saddle back | William Blake Galbreath | | +| server | Player invulnerabilities | William Blake Galbreath | | +| api | Player invulnerabilities | William Blake Galbreath | | | api | PlayerAttackEntityEvent | Ivan Pekov | | | server | PlayerAttackEntityEvent | Ivan Pekov | | +| server | PlayerBookTooLargeEvent | BillyGalbreath | | +| api | PlayerBookTooLargeEvent | BillyGalbreath | | +| server | PlayerSetSpawnerTypeWithEggEvent | William Blake Galbreath | | +| api | PlayerSetSpawnerTypeWithEggEvent | William Blake Galbreath | | +| server | Players should not cram to death | William Blake Galbreath | | +| server | Populator seed controls | Spottedleaf | | | server | Port Cadmium | Lucy-t | | | server | Preload ProtocolLib EnumWrappers | ishland | | | server | Prevent long map entry creation in light engine | Spottedleaf | | | server | Prevent unload() calls removing tickets for sync loads | Spottedleaf | | +| server | Projectile offset config | YouHaveTrouble | | +| server | Purpur config files | William Blake Galbreath | | +| api | Purpur config files | William Blake Galbreath | | +| server | Rabbit naturally spawn toast and killer | William Blake Galbreath | | +| api | Rabid Wolf API | Encode42 | | +| server | Raid cooldown setting | jmp | | | server | Range check flag dirty calls in PlayerChunk | Spottedleaf | | | server | Redirect Configs | tr7zw | | +| server | Redstone deactivates spawners | draycia | | | server | Reduce allocation rate from crammed entities | Spottedleaf | | | server | Reduce allocs & improve perf of StructureManager | Paul Sauve | | | server | Reduce chunk loading & lookups | Paul Sauve | | @@ -167,38 +401,68 @@ # Patches | server | Revert getChunkAt(Async) retaining chunks for long periods of | Spottedleaf | | | server | Rework PlayerChunk main thread checks | Spottedleaf | | | server | Rewrite the light engine | Spottedleaf | | +| server | Ridables | William Blake Galbreath | | +| api | Ridables | William Blake Galbreath | | | server | Send full pos packets for hard colliding entities | Spottedleaf | | | server | Separate lookup locking from state access in UserCache | Spottedleaf | | +| server | Set name visible when using a Name Tag on an Armor Stand | jmp | | +| server | Short enderman height | William Blake Galbreath | | +| server | ShulkerBox allow oversized stacks | BillyGalbreath | | | server | Shutdown Bootstrap thread pool | foss-mc | | +| server | Signs allow color codes | William Blake Galbreath | | +| server | Signs editable on right click | William Blake Galbreath | | +| server | Silk touch spawners | William Blake Galbreath | | | server | Simple item block collision toggle | Paul Sauve | | | server | Simpler ShapelessRecipes comparison for Vanilla | Paul Sauve | | | server | Skip POI finding if stuck in vehicle | Paul Sauve | | | server | Skip copying unloading tile entities | Paul Sauve | | | server | Skip creating hashset for entity track range | Paul Sauve | | +| server | Skip events if there's no listeners | William Blake Galbreath | | | server | Smarter statistics ticking | Mykyta Komarnytskyy | | | server | Smol entity optimisations | Ivan Pekov | | +| server | Sneak to bulk process composter | BillyGalbreath | | +| server | Snow Golem rate of fire config | Simon Gardling | | +| server | Snowman drop and put back pumpkin | William Blake Galbreath | | +| api | Spigot - Improve output of plugins command | Parker Hawke | | +| server | Spread out and optimise player list ticks | James Lyne | | +| server | Squid EAR immunity | William Blake Galbreath | | +| server | Stonecutter damage | William Blake Galbreath | | | server | Stop large move vectors in player packet handling from | Spottedleaf | | +| server | Stop squids floating on top of water | William Blake Galbreath | | | server | Stop wasting resources on JsonList#get | Ivan Pekov | | +| server | Striders give saddle back | Ben Kerllenevich | | | server | Strip raytracing for EntityLiving#hasLineOfSight | Paul Sauve | | | api | Suspected plugins report | ishland | | | server | Suspected plugins report | ishland | | | server | Swap priority of checks in chunk ticking | Paul Sauve | | | server | Swaps the predicate order of collision | ㄗㄠˋ ㄑㄧˊ | | +| server | Tick fluids config | BillyGalbreath | | | server | Time scoreboard search | Spottedleaf | | +| server | Timings stuff | William Blake Galbreath | | +| server | Toggle for Zombified Piglin death always counting as player | jmp | | +| server | Toggle for water sensitive mob damage | YouHaveTrouble | | +| server | Totems work in inventory | draycia | | | api | Tuinity POM Changes | Spottedleaf | | | server | Tuinity POM Changes | Spottedleaf | | | server | Tuinity Server Config | Spottedleaf | | | api | Tuinity config | Spottedleaf | | +| server | Tulips change fox type | William Blake Galbreath | | | server | Update version fetcher repo | JRoy | | | server | Use array for gamerule storage | Paul Sauve | | +| server | Use configured height for nether surface builders | William Blake Galbreath | | | server | Use hash table for maintaing changed block set | Spottedleaf | | | server | Use list for fast iteration over pathfinder goals | Paul Sauve | | | server | Use raw iterator where possible | Paul Sauve | | | server | Use unmodifiableMap instead of making copy | Paul Sauve | | | server | Util patch | Spottedleaf | | | server | Utilities | YatopiaMC | Mykyta Komarnytskyy, Ivan Pekov | +| api | Villager#resetOffers | William Blake Galbreath | | +| server | Villagers farming can bypass mob-griefing gamerule | William Blake Galbreath | | +| server | Villagers follow emerald blocks | William Blake Galbreath | | | api | Yatopia Config & Redirect Config | YatopiaMC | | | server | Yatopia configuration | tr7zw | | +| server | Zombie break door minimum difficulty option | BillyGalbreath | | +| server | Zombie horse naturally spawn | William Blake Galbreath | | | server | add config for logging login location | Simon Gardling | | | server | dont load chunks for physics | Aikar | | | server | lithium DataTrackerMixin | JellySquid | tr7zw | diff --git a/patches/Airplane/patches/server/0001-Airplane-MC-Dev-Fixes.patch b/patches/Airplane/patches/server/0001-Airplane-MC-Dev-Fixes.patch index a154fadf..2eb394ce 100644 --- a/patches/Airplane/patches/server/0001-Airplane-MC-Dev-Fixes.patch +++ b/patches/Airplane/patches/server/0001-Airplane-MC-Dev-Fixes.patch @@ -19,44 +19,6 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . -diff --git a/src/main/java/net/minecraft/world/entity/monster/hoglin/EntityHoglin.java b/src/main/java/net/minecraft/world/entity/monster/hoglin/EntityHoglin.java -index 375409f4b72edc7990da90460b30486fb2980fb6..ab692de8a5b1411e37251fb545e6f579a9929f91 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/hoglin/EntityHoglin.java -+++ b/src/main/java/net/minecraft/world/entity/monster/hoglin/EntityHoglin.java -@@ -54,7 +54,7 @@ public class EntityHoglin extends EntityAnimal implements IMonster, IOglin { - public int conversionTicks = 0; - public boolean cannotBeHunted = false; - protected static final ImmutableList>> bo = ImmutableList.of(SensorType.c, SensorType.d, SensorType.n, SensorType.m); -- protected static final ImmutableList> bp = ImmutableList.of(MemoryModuleType.BREED_TARGET, MemoryModuleType.MOBS, MemoryModuleType.VISIBLE_MOBS, MemoryModuleType.NEAREST_VISIBLE_PLAYER, MemoryModuleType.NEAREST_VISIBLE_TARGETABLE_PLAYER, MemoryModuleType.LOOK_TARGET, MemoryModuleType.WALK_TARGET, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE, MemoryModuleType.PATH, MemoryModuleType.ATTACK_TARGET, MemoryModuleType.ATTACK_COOLING_DOWN, MemoryModuleType.NEAREST_VISIBLE_ADULT_PIGLIN, new MemoryModuleType[]{MemoryModuleType.AVOID_TARGET, MemoryModuleType.VISIBLE_ADULT_PIGLIN_COUNT, MemoryModuleType.VISIBLE_ADULT_HOGLIN_COUNT, MemoryModuleType.NEAREST_VISIBLE_ADULT_HOGLINS, MemoryModuleType.NEAREST_VISIBLE_ADULY, MemoryModuleType.NEAREST_REPELLENT, MemoryModuleType.PACIFIED}); -+ protected static final ImmutableList> bp = ImmutableList.of(MemoryModuleType.BREED_TARGET, MemoryModuleType.MOBS, MemoryModuleType.VISIBLE_MOBS, MemoryModuleType.NEAREST_VISIBLE_PLAYER, MemoryModuleType.NEAREST_VISIBLE_TARGETABLE_PLAYER, MemoryModuleType.LOOK_TARGET, MemoryModuleType.WALK_TARGET, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE, MemoryModuleType.PATH, MemoryModuleType.ATTACK_TARGET, MemoryModuleType.ATTACK_COOLING_DOWN, MemoryModuleType.NEAREST_VISIBLE_ADULT_PIGLIN, new MemoryModuleType[]{MemoryModuleType.AVOID_TARGET, MemoryModuleType.VISIBLE_ADULT_PIGLIN_COUNT, MemoryModuleType.VISIBLE_ADULT_HOGLIN_COUNT, MemoryModuleType.NEAREST_VISIBLE_ADULT_HOGLINS, MemoryModuleType.NEAREST_VISIBLE_ADULY, MemoryModuleType.NEAREST_REPELLENT, MemoryModuleType.PACIFIED}); // Airplane - decompile error - - public EntityHoglin(EntityTypes entitytypes, World world) { - super(entitytypes, world); -@@ -118,13 +118,13 @@ public class EntityHoglin extends EntityAnimal implements IMonster, IOglin { - - @Override - public BehaviorController getBehaviorController() { -- return super.getBehaviorController(); -+ return (BehaviorController) super.getBehaviorController(); // Airplane - decompile error - } - - @Override - protected void mobTick() { - this.world.getMethodProfiler().enter("hoglinBrain"); -- this.getBehaviorController().a((WorldServer) this.world, (EntityLiving) this); -+ this.getBehaviorController().a((WorldServer) this.world, (EntityHoglin) this); // Airplane - decompile error - this.world.getMethodProfiler().exit(); - HoglinAI.a(this); - if (this.isConverting()) { -@@ -300,7 +300,7 @@ public class EntityHoglin extends EntityAnimal implements IMonster, IOglin { - - @Override - protected SoundEffect getSoundAmbient() { -- return this.world.isClientSide ? null : (SoundEffect) HoglinAI.b(this).orElse((Object) null); -+ return this.world.isClientSide ? null : (SoundEffect) HoglinAI.b(this).orElse(null); // Airplane - decompile error - } - - @Override diff --git a/src/main/java/net/minecraft/world/level/storage/loot/LootTableInfo.java b/src/main/java/net/minecraft/world/level/storage/loot/LootTableInfo.java index 95d0c9f22d79194ca83ca6f6a8e6d91180a3c8da..5c712af849abf1e5f58a7760b19c543474559f77 100644 --- a/src/main/java/net/minecraft/world/level/storage/loot/LootTableInfo.java diff --git a/patches/Airplane/patches/server/0002-Airplane-Configuration.patch b/patches/Airplane/patches/server/0002-Airplane-Configuration.patch index 4af6eaab..3ea906d6 100644 --- a/patches/Airplane/patches/server/0002-Airplane-Configuration.patch +++ b/patches/Airplane/patches/server/0002-Airplane-Configuration.patch @@ -183,10 +183,10 @@ index 0000000000000000000000000000000000000000..807cf274619b8f7be839e249cb62b981 + } +} diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -index 3713a110a64fa686e785b9789c33dd09cacc2f48..0d27af452fc6a72646a4a168fc827fed5072fab9 100644 +index 9e4b83bc106acbc9d40a07ad7a47488325e4b4ed..d7e65fc294538bce09580ec1b9090538783c63ad 100644 --- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java +++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -@@ -216,6 +216,8 @@ public class DedicatedServer extends MinecraftServer implements IMinecraftServer +@@ -225,6 +225,8 @@ public class DedicatedServer extends MinecraftServer implements IMinecraftServer io.papermc.paper.brigadier.PaperBrigadierProviderImpl.INSTANCE.getClass(); // init PaperBrigadierProvider // Paper end com.tuinity.tuinity.config.TuinityConfig.init((java.io.File) options.valueOf("tuinity-settings")); // Tuinity - Server Config diff --git a/patches/Airplane/patches/server/0004-Strip-raytracing-for-EntityLiving-hasLineOfSight.patch b/patches/Airplane/patches/server/0004-Strip-raytracing-for-EntityLiving-hasLineOfSight.patch index ad1a5020..b59a8127 100644 --- a/patches/Airplane/patches/server/0004-Strip-raytracing-for-EntityLiving-hasLineOfSight.patch +++ b/patches/Airplane/patches/server/0004-Strip-raytracing-for-EntityLiving-hasLineOfSight.patch @@ -55,10 +55,10 @@ index cc566784c7dd21cc2c44e0f351347f657e57ddcf..e9e7fcf2b63febe2a7d055826fabb86b return d0 == 0.0D ? 0 : (d0 > 0.0D ? 1 : -1); } diff --git a/src/main/java/net/minecraft/world/entity/EntityLiving.java b/src/main/java/net/minecraft/world/entity/EntityLiving.java -index 2ff3297fb8c0e4f8c969ba2727eecb7fe06525c4..56812a96b57586d91c0f218f4720807e2d957627 100644 +index 158388410ea14b2df95635914844952bd52b8f87..84e1ef0716559f7de4ea580269fa7ca17894cf10 100644 --- a/src/main/java/net/minecraft/world/entity/EntityLiving.java +++ b/src/main/java/net/minecraft/world/entity/EntityLiving.java -@@ -111,6 +111,7 @@ import net.minecraft.world.phys.AxisAlignedBB; +@@ -112,6 +112,7 @@ import net.minecraft.world.phys.AxisAlignedBB; import net.minecraft.world.phys.MovingObjectPosition; import net.minecraft.world.phys.MovingObjectPositionEntity; import net.minecraft.world.phys.Vec3D; @@ -66,7 +66,7 @@ index 2ff3297fb8c0e4f8c969ba2727eecb7fe06525c4..56812a96b57586d91c0f218f4720807e import net.minecraft.world.scores.ScoreboardTeam; import org.apache.logging.log4j.Logger; -@@ -3102,7 +3103,10 @@ public abstract class EntityLiving extends Entity { +@@ -3225,7 +3226,10 @@ public abstract class EntityLiving extends Entity { Vec3D vec3d1 = new Vec3D(entity.locX(), entity.getHeadY(), entity.locZ()); // Paper - diff on change - used in CraftLivingEntity#hasLineOfSight(Location) and CraftWorld#lineOfSightExists @@ -112,10 +112,10 @@ index e612e1d30f76e217b1aa23488ab025adce048f57..6109d59c02d0c7877e213213c6aec6f8 default MovingObjectPositionBlock rayTraceBlock(RayTrace raytrace1, BlockPosition blockposition) { // Paper start - Prevent raytrace from loading chunks diff --git a/src/main/java/net/minecraft/world/level/World.java b/src/main/java/net/minecraft/world/level/World.java -index cb8064df7e9f1b8b4d4292486e2193680d83663c..37da32675f0c00c793cd137c9a7305932cefb705 100644 +index cb58d2635650c20da21583ead18e9f380323205b..904dfb7c337b1d583df80533ba5c59478f560c85 100644 --- a/src/main/java/net/minecraft/world/level/World.java +++ b/src/main/java/net/minecraft/world/level/World.java -@@ -69,6 +69,8 @@ import net.minecraft.world.level.saveddata.maps.WorldMap; +@@ -70,6 +70,8 @@ import net.minecraft.world.level.saveddata.maps.WorldMap; import net.minecraft.world.level.storage.WorldData; import net.minecraft.world.level.storage.WorldDataMutable; import net.minecraft.world.phys.AxisAlignedBB; @@ -124,7 +124,7 @@ index cb8064df7e9f1b8b4d4292486e2193680d83663c..37da32675f0c00c793cd137c9a730593 import net.minecraft.world.phys.shapes.OperatorBoolean; import net.minecraft.world.phys.shapes.VoxelShape; import net.minecraft.world.phys.shapes.VoxelShapeCollision; -@@ -385,6 +387,91 @@ public abstract class World implements GeneratorAccess, AutoCloseable { +@@ -431,6 +433,91 @@ public abstract class World implements GeneratorAccess, AutoCloseable { return null; } diff --git a/patches/Airplane/patches/server/0007-Swap-priority-of-checks-in-chunk-ticking.patch b/patches/Airplane/patches/server/0007-Swap-priority-of-checks-in-chunk-ticking.patch index 691e2c3e..e7a9a864 100644 --- a/patches/Airplane/patches/server/0007-Swap-priority-of-checks-in-chunk-ticking.patch +++ b/patches/Airplane/patches/server/0007-Swap-priority-of-checks-in-chunk-ticking.patch @@ -23,10 +23,10 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . diff --git a/src/main/java/net/minecraft/server/level/WorldServer.java b/src/main/java/net/minecraft/server/level/WorldServer.java -index 6fc215df5ed3aa6ef0c23a57e8444602ff9309e8..239af30d85bff561d14a96de97e1215378018f85 100644 +index fbc7f3e489be0ac5939af29a9aef75a56c38eb4a..ce13d159e9519e352e348fb064d7f6ca3f69bacb 100644 --- a/src/main/java/net/minecraft/server/level/WorldServer.java +++ b/src/main/java/net/minecraft/server/level/WorldServer.java -@@ -1212,7 +1212,7 @@ public class WorldServer extends World implements GeneratorAccessSeed { +@@ -1260,7 +1260,7 @@ public class WorldServer extends World implements GeneratorAccessSeed { gameprofilerfiller.enter("thunder"); final BlockPosition.MutableBlockPosition blockposition = this.chunkTickMutablePosition; // Paper - use mutable to reduce allocation rate, final to force compile fail on change diff --git a/patches/Airplane/patches/server/0009-Optimize-random-calls-in-chunk-ticking.patch b/patches/Airplane/patches/server/0009-Optimize-random-calls-in-chunk-ticking.patch index 1d4e91a8..8e4c4556 100644 --- a/patches/Airplane/patches/server/0009-Optimize-random-calls-in-chunk-ticking.patch +++ b/patches/Airplane/patches/server/0009-Optimize-random-calls-in-chunk-ticking.patch @@ -46,10 +46,10 @@ index 1b86c032fde3409cb89b849b9ba094af82cd9269..0718b80ac82a1cf00519c30c6d2ef78f boolean flag2 = world.ticksPerAnimalSpawns != 0L && worlddata.getTime() % world.ticksPerAnimalSpawns == 0L; // CraftBukkit diff --git a/src/main/java/net/minecraft/server/level/WorldServer.java b/src/main/java/net/minecraft/server/level/WorldServer.java -index 239af30d85bff561d14a96de97e1215378018f85..39b978c6e61e675249743d082699bb9882fd39ff 100644 +index ce13d159e9519e352e348fb064d7f6ca3f69bacb..d7a19e6c03b440bc46385868e83a00110dfdc0b1 100644 --- a/src/main/java/net/minecraft/server/level/WorldServer.java +++ b/src/main/java/net/minecraft/server/level/WorldServer.java -@@ -1202,6 +1202,8 @@ public class WorldServer extends World implements GeneratorAccessSeed { +@@ -1250,6 +1250,8 @@ public class WorldServer extends World implements GeneratorAccessSeed { private final BiomeBase[] biomeBaseCache = new BiomeBase[1]; // Tuinity end - optimise chunk ice snow ticking @@ -58,7 +58,7 @@ index 239af30d85bff561d14a96de97e1215378018f85..39b978c6e61e675249743d082699bb98 public void a(Chunk chunk, int i) { final int randomTickSpeed = i; // Paper ChunkCoordIntPair chunkcoordintpair = chunk.getPos(); boolean flag = this.isRaining(); -@@ -1212,7 +1214,7 @@ public class WorldServer extends World implements GeneratorAccessSeed { +@@ -1260,7 +1262,7 @@ public class WorldServer extends World implements GeneratorAccessSeed { gameprofilerfiller.enter("thunder"); final BlockPosition.MutableBlockPosition blockposition = this.chunkTickMutablePosition; // Paper - use mutable to reduce allocation rate, final to force compile fail on change @@ -67,7 +67,7 @@ index 239af30d85bff561d14a96de97e1215378018f85..39b978c6e61e675249743d082699bb98 blockposition.setValues(this.a(this.a(j, 0, k, 15))); // Paper if (this.isRainingAt(blockposition)) { DifficultyDamageScaler difficultydamagescaler = this.getDamageScaler(blockposition); -@@ -1236,7 +1238,7 @@ public class WorldServer extends World implements GeneratorAccessSeed { +@@ -1290,7 +1292,7 @@ public class WorldServer extends World implements GeneratorAccessSeed { } gameprofilerfiller.exitEnter("iceandsnow"); diff --git a/patches/Airplane/patches/server/0010-Don-t-get-entity-equipment-if-not-needed.patch b/patches/Airplane/patches/server/0010-Don-t-get-entity-equipment-if-not-needed.patch index 5288a0ae..0b47b726 100644 --- a/patches/Airplane/patches/server/0010-Don-t-get-entity-equipment-if-not-needed.patch +++ b/patches/Airplane/patches/server/0010-Don-t-get-entity-equipment-if-not-needed.patch @@ -20,10 +20,10 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . diff --git a/src/main/java/net/minecraft/world/entity/EntityLiving.java b/src/main/java/net/minecraft/world/entity/EntityLiving.java -index 56812a96b57586d91c0f218f4720807e2d957627..6b82dffa3d0938a94114ead277b42c71ea3bb52b 100644 +index 84e1ef0716559f7de4ea580269fa7ca17894cf10..59b85551533d332880b154039a5cc3683b17a962 100644 --- a/src/main/java/net/minecraft/world/entity/EntityLiving.java +++ b/src/main/java/net/minecraft/world/entity/EntityLiving.java -@@ -910,11 +910,13 @@ public abstract class EntityLiving extends Entity { +@@ -925,11 +925,13 @@ public abstract class EntityLiving extends Entity { } if (entity != null) { @@ -39,4 +39,4 @@ index 56812a96b57586d91c0f218f4720807e2d957627..6b82dffa3d0938a94114ead277b42c71 + // Airplane end d0 *= 0.5D; } - } + diff --git a/patches/Airplane/patches/server/0011-Dynamic-activation-range.patch b/patches/Airplane/patches/server/0011-Dynamic-activation-range.patch index 94747b34..4448ba26 100644 --- a/patches/Airplane/patches/server/0011-Dynamic-activation-range.patch +++ b/patches/Airplane/patches/server/0011-Dynamic-activation-range.patch @@ -69,7 +69,7 @@ index ab019b577002677a4ce788106f8e5a1d7757a2ae..5077e70e4f408814b1072ceb45c52a32 + } diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 89852779fd9cfd19058afe40feb0cf14ca8d2896..5fb3f2968f20e78d76382bec52c9236add4fc060 100644 +index 18e5110047f13c213e70d3e094b94fecb4408d18..6c898bf36edbc50018f4795b8c51fc3fbbcc5641 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java @@ -289,6 +289,9 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, ne @@ -83,7 +83,7 @@ index 89852779fd9cfd19058afe40feb0cf14ca8d2896..5fb3f2968f20e78d76382bec52c9236a public float getBukkitYaw() { return this.yaw; diff --git a/src/main/java/net/minecraft/world/entity/EntityInsentient.java b/src/main/java/net/minecraft/world/entity/EntityInsentient.java -index 7ba59ff9a7ed39bf69c46973a85f874c43134dc1..c67138e6a4dcbe823e894f6bb948742bfb8f9943 100644 +index b4afd71340a0c7e1b6aa2e3f01a6a4fc998f3f16..35a6a786474fb95082a2d1ca41697c2b1febe55a 100644 --- a/src/main/java/net/minecraft/world/entity/EntityInsentient.java +++ b/src/main/java/net/minecraft/world/entity/EntityInsentient.java @@ -201,10 +201,10 @@ public abstract class EntityInsentient extends EntityLiving { @@ -99,7 +99,7 @@ index 7ba59ff9a7ed39bf69c46973a85f874c43134dc1..c67138e6a4dcbe823e894f6bb948742b this.targetSelector.doTick(); } } -@@ -829,9 +829,11 @@ public abstract class EntityInsentient extends EntityLiving { +@@ -865,9 +865,11 @@ public abstract class EntityInsentient extends EntityLiving { this.bo.a(); this.world.getMethodProfiler().exit(); this.world.getMethodProfiler().enter("targetSelector"); @@ -135,20 +135,21 @@ index 637928664f8c7b1c694a234e507c20724294e450..502f710e1b04d186c539a04b43379bdc public boolean hasTasks() { for (PathfinderGoalWrapped task : getTasks()) { diff --git a/src/main/java/net/minecraft/world/entity/monster/hoglin/EntityHoglin.java b/src/main/java/net/minecraft/world/entity/monster/hoglin/EntityHoglin.java -index ab692de8a5b1411e37251fb545e6f579a9929f91..9aa4850e021076fde306eea7eec104c31086c57f 100644 +index e9b466bb3172fcae1dee81e7e1b8c069b0a23944..6d43c4679a6a27b03d128f4dd2671b33b7d8c6cf 100644 --- a/src/main/java/net/minecraft/world/entity/monster/hoglin/EntityHoglin.java +++ b/src/main/java/net/minecraft/world/entity/monster/hoglin/EntityHoglin.java -@@ -121,12 +121,17 @@ public class EntityHoglin extends EntityAnimal implements IMonster, IOglin { - return (BehaviorController) super.getBehaviorController(); // Airplane - decompile error +@@ -143,13 +143,18 @@ public class EntityHoglin extends EntityAnimal implements IMonster, IOglin { + return (BehaviorController) super.getBehaviorController(); // Purpur decompile error } + private int behaviorTick; // Airplane @Override protected void mobTick() { + this.world.getMethodProfiler().enter("hoglinBrain"); + if (getPurpurRider() == null) // Purpur - only use brain if no rider + // Airplane - dynamic tick + if (!gg.airplane.AirplaneConfig.dynamicHoglinBehavior || this.behaviorTick++ % this.activatedPriority == 0) { - this.world.getMethodProfiler().enter("hoglinBrain"); - this.getBehaviorController().a((WorldServer) this.world, (EntityHoglin) this); // Airplane - decompile error + this.getBehaviorController().a((WorldServer) this.world, this); // Purpour - decompile error this.world.getMethodProfiler().exit(); HoglinAI.a(this); + } @@ -157,19 +158,20 @@ index ab692de8a5b1411e37251fb545e6f579a9929f91..9aa4850e021076fde306eea7eec104c3 ++this.conversionTicks; if (this.conversionTicks > 300) { diff --git a/src/main/java/net/minecraft/world/entity/monster/piglin/EntityPiglin.java b/src/main/java/net/minecraft/world/entity/monster/piglin/EntityPiglin.java -index 9a7bebd77302dbfd07ac802acbe2b9cb80eec26f..99cdcc9a9a7e6227a165c4ef779f8e76a99ec56a 100644 +index 77af7152a2e5ff99e98a0063947427c0d18aabcb..220933e776504599e7ed68520ec433e74c9dd882 100644 --- a/src/main/java/net/minecraft/world/entity/monster/piglin/EntityPiglin.java +++ b/src/main/java/net/minecraft/world/entity/monster/piglin/EntityPiglin.java -@@ -272,12 +272,17 @@ public class EntityPiglin extends EntityPiglinAbstract implements ICrossbow { +@@ -289,13 +289,18 @@ public class EntityPiglin extends EntityPiglinAbstract implements ICrossbow { return !this.cannotHunt; } + private int behaviorTick; // Airplane @Override protected void mobTick() { + this.world.getMethodProfiler().enter("piglinBrain"); + if (getPurpurRider() == null) // Purpur - only use brain if no rider + // Airplane - dynamic tick + if (!gg.airplane.AirplaneConfig.dynamicPiglinBehavior || this.behaviorTick++ % this.activatedPriority == 0) { - this.world.getMethodProfiler().enter("piglinBrain"); this.getBehaviorController().a((WorldServer) this.world, (EntityPiglin) this); // CraftBukkit - decompile error this.world.getMethodProfiler().exit(); PiglinAI.b(this); @@ -179,33 +181,29 @@ index 9a7bebd77302dbfd07ac802acbe2b9cb80eec26f..99cdcc9a9a7e6227a165c4ef779f8e76 } diff --git a/src/main/java/net/minecraft/world/entity/npc/EntityVillager.java b/src/main/java/net/minecraft/world/entity/npc/EntityVillager.java -index 85374ac8f5460790de03b47d7c3ce19ed5596afe..ccb568a5e8501ac5e8901ef3a270cc87471d9ea1 100644 +index 66863b31687a41f84f722c611064f7ad31e02488..df29b574db306fd722d8470db4a5321230c837d5 100644 --- a/src/main/java/net/minecraft/world/entity/npc/EntityVillager.java +++ b/src/main/java/net/minecraft/world/entity/npc/EntityVillager.java -@@ -231,11 +231,17 @@ public class EntityVillager extends EntityVillagerAbstract implements Reputation - } - // Spigot End - -+ private int behaviorTick = 0; -+ - @Override - protected void mobTick() { mobTick(false); } - protected void mobTick(boolean inactive) { - this.world.getMethodProfiler().enter("villagerBrain"); +@@ -295,7 +295,13 @@ public class EntityVillager extends EntityVillagerAbstract implements Reputation + boolean tick = (world.getTime() + brainTickOffset) % world.purpurConfig.villagerBrainTicks == 0; + if (((WorldServer) world).getMinecraftServer().lagging ? tick : world.purpurConfig.villagerUseBrainTicksOnlyWhenLagging || tick) + // Purpur end - if (!inactive) this.getBehaviorController().a((WorldServer) this.world, this); // CraftBukkit - decompile error // Paper -+ if (!inactive) { -+ if (!gg.airplane.AirplaneConfig.dynamicVillagerBehavior || behaviorTick++ % this.activatedPriority == 0) { -+ this.getBehaviorController().a((WorldServer) this.world, this); // CraftBukkit - decompile error // Paper ++ // Airplane start ++ if (!inactive) { ++ if (!gg.airplane.AirplaneConfig.dynamicVillagerBehavior || behaviorTick++ % this.activatedPriority == 0) { ++ this.getBehaviorController().a((WorldServer) this.world, this); // CraftBukkit - decompile error // Paper ++ } + } -+ } ++ // Airplane end + else if (shouldRestock()) doRestock(); // Purpur this.world.getMethodProfiler().exit(); if (this.bF) { - this.bF = false; diff --git a/src/main/java/org/spigotmc/ActivationRange.java b/src/main/java/org/spigotmc/ActivationRange.java -index 5c2eaca0bc63c7880ee928aba6a24761737aa649..0c86a93a34fdbb65365e81915ac9f54df4dde88b 100644 +index 2fbc24a6907c06bbc12815a89b507d4479be6dc5..3a76d9d90531ed889a0fc92674bd1719aacdb159 100644 --- a/src/main/java/org/spigotmc/ActivationRange.java +++ b/src/main/java/org/spigotmc/ActivationRange.java -@@ -47,6 +47,9 @@ import net.minecraft.world.entity.schedule.Activity; +@@ -48,6 +48,9 @@ import net.minecraft.world.entity.schedule.Activity; import net.minecraft.world.entity.item.EntityFallingBlock; import net.minecraft.world.entity.projectile.EntityEnderSignal; // Paper end @@ -215,7 +213,7 @@ index 5c2eaca0bc63c7880ee928aba6a24761737aa649..0c86a93a34fdbb65365e81915ac9f54d public class ActivationRange { -@@ -227,7 +230,7 @@ public class ActivationRange +@@ -229,7 +232,7 @@ public class ActivationRange Chunk chunk = chunkProvider.getChunkAtIfLoadedMainThreadNoCache( i1, j1 ); // Paper if ( chunk != null ) { @@ -224,7 +222,7 @@ index 5c2eaca0bc63c7880ee928aba6a24761737aa649..0c86a93a34fdbb65365e81915ac9f54d } } } -@@ -240,7 +243,7 @@ public class ActivationRange +@@ -242,7 +245,7 @@ public class ActivationRange * * @param chunk */ @@ -233,7 +231,7 @@ index 5c2eaca0bc63c7880ee928aba6a24761737aa649..0c86a93a34fdbb65365e81915ac9f54d { // Paper start Entity[] rawData = chunk.entities.getRawData(); -@@ -249,6 +252,19 @@ public class ActivationRange +@@ -251,6 +254,19 @@ public class ActivationRange //for ( Entity entity : (Collection) slice ) // Paper end { diff --git a/patches/Airplane/patches/server/0013-Cache-palette-array.patch b/patches/Airplane/patches/server/0013-Cache-palette-array.patch index d59e9fde..6946160d 100644 --- a/patches/Airplane/patches/server/0013-Cache-palette-array.patch +++ b/patches/Airplane/patches/server/0013-Cache-palette-array.patch @@ -46,7 +46,7 @@ index a6937366cd9c9d708edb5cd1ab3ac096e7b2032e..a579c5bf9e20c74aa3bf8ef6bc005764 for (int j = 0; j < 4096; ++j) { T t1 = this.a(j); diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkRegionLoader.java b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkRegionLoader.java -index ec2b238480413ba9c123d9ddeaa787d9520e1b74..bf96f9e538fc29ca914536e8a7ce727ebe43a8b2 100644 +index 3fbeb01275a48b4173f98ae0c7f09e4c0e6445e7..5997f3e47f3d509c271f38eb2785f126066f5c6e 100644 --- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkRegionLoader.java +++ b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkRegionLoader.java @@ -468,6 +468,7 @@ public class ChunkRegionLoader { diff --git a/patches/Airplane/patches/server/0014-Reduce-chunk-loading-lookups.patch b/patches/Airplane/patches/server/0014-Reduce-chunk-loading-lookups.patch index 634571e7..37878ad5 100644 --- a/patches/Airplane/patches/server/0014-Reduce-chunk-loading-lookups.patch +++ b/patches/Airplane/patches/server/0014-Reduce-chunk-loading-lookups.patch @@ -20,10 +20,10 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityEnderman.java b/src/main/java/net/minecraft/world/entity/monster/EntityEnderman.java -index e993b1849beb60515c51ee4f37617faab63ca223..4d7b5d47ab6bd3b1408811c3b9c157b1eb5c30ae 100644 +index 3bb5b360be98ac2f20793c0eb126e39eb2201331..bd03e91861237eeda50e607af4e26c1ad2d71297 100644 --- a/src/main/java/net/minecraft/world/entity/monster/EntityEnderman.java +++ b/src/main/java/net/minecraft/world/entity/monster/EntityEnderman.java -@@ -57,6 +57,7 @@ import net.minecraft.world.level.World; +@@ -59,6 +59,7 @@ import net.minecraft.world.level.World; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.state.IBlockData; @@ -31,7 +31,7 @@ index e993b1849beb60515c51ee4f37617faab63ca223..4d7b5d47ab6bd3b1408811c3b9c157b1 import net.minecraft.world.level.pathfinder.PathType; import net.minecraft.world.phys.AxisAlignedBB; import net.minecraft.world.phys.MovingObjectPositionBlock; -@@ -314,11 +315,18 @@ public class EntityEnderman extends EntityMonster implements IEntityAngerable { +@@ -335,11 +336,18 @@ public class EntityEnderman extends EntityMonster implements IEntityAngerable { private boolean p(double d0, double d1, double d2) { BlockPosition.MutableBlockPosition blockposition_mutableblockposition = new BlockPosition.MutableBlockPosition(d0, d1, d2); @@ -53,7 +53,7 @@ index e993b1849beb60515c51ee4f37617faab63ca223..4d7b5d47ab6bd3b1408811c3b9c157b1 boolean flag1 = iblockdata.getFluid().a((Tag) TagsFluid.WATER); diff --git a/src/main/java/net/minecraft/world/level/SpawnerCreature.java b/src/main/java/net/minecraft/world/level/SpawnerCreature.java -index 9b55da1f4d40ae36b2d2b8e7b3b18989dc4f6006..ab6812698757c05c2e923006d4e3370a7d6c4e03 100644 +index 050651462390f0896f0629408d0f7d29d35bdb7f..0af062f54b8c5d1f8286a1e303ddaed14897aea8 100644 --- a/src/main/java/net/minecraft/world/level/SpawnerCreature.java +++ b/src/main/java/net/minecraft/world/level/SpawnerCreature.java @@ -415,7 +415,10 @@ public final class SpawnerCreature { diff --git a/patches/Airplane/patches/server/0015-Reduce-memory-allocations.patch b/patches/Airplane/patches/server/0015-Reduce-memory-allocations.patch index 40a51469..8cbbe1df 100644 --- a/patches/Airplane/patches/server/0015-Reduce-memory-allocations.patch +++ b/patches/Airplane/patches/server/0015-Reduce-memory-allocations.patch @@ -20,10 +20,10 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . diff --git a/src/main/java/net/minecraft/core/BlockPosition.java b/src/main/java/net/minecraft/core/BlockPosition.java -index 6a6381e85fef2ae2b9b5e6dff0b7917b92fa01e5..2685a395a2eff9083cd8c654c4b7e2141b0ca99b 100644 +index 17d63cd4ca152adc66ffe9ffd3227a0770738a29..c2706c752f6ff5c131b6db469ae85dd703d5d381 100644 --- a/src/main/java/net/minecraft/core/BlockPosition.java +++ b/src/main/java/net/minecraft/core/BlockPosition.java -@@ -438,12 +438,26 @@ public class BlockPosition extends BaseBlockPosition { +@@ -444,12 +444,26 @@ public class BlockPosition extends BaseBlockPosition { public BlockPosition b(int i, int j, int k) { return super.b(i, j, k).immutableCopy(); } @@ -51,7 +51,7 @@ index 6a6381e85fef2ae2b9b5e6dff0b7917b92fa01e5..2685a395a2eff9083cd8c654c4b7e214 public BlockPosition a(EnumDirection.EnumAxis enumdirection_enumaxis, int i) { return super.a(enumdirection_enumaxis, i).immutableCopy(); diff --git a/src/main/java/net/minecraft/core/EnumDirection.java b/src/main/java/net/minecraft/core/EnumDirection.java -index 7918d830a4aef09c9f517284e83a9376299116ad..0a40df2151bd388b6633a6f50b14f1f41ed4ce62 100644 +index 9f1ea11d0bc15b8b0069fcf46ea2f6751c5e3064..19bc37143140b4e3a06a87297205b702548b0fa3 100644 --- a/src/main/java/net/minecraft/core/EnumDirection.java +++ b/src/main/java/net/minecraft/core/EnumDirection.java @@ -30,7 +30,7 @@ public enum EnumDirection implements INamable { @@ -64,7 +64,7 @@ index 7918d830a4aef09c9f517284e83a9376299116ad..0a40df2151bd388b6633a6f50b14f1f4 return enumdirection; })); diff --git a/src/main/java/net/minecraft/server/level/PlayerChunkMap.java b/src/main/java/net/minecraft/server/level/PlayerChunkMap.java -index d827e18d8c3b9b5869dbb1e233f415ba0efb7c1b..fc687515fdfd47e90e11a2832de07d784edeef25 100644 +index d876c5037b4704a174606629c80ba1142c77a50c..92db19451317ed02fba526328f97dec1dbbf85bd 100644 --- a/src/main/java/net/minecraft/server/level/PlayerChunkMap.java +++ b/src/main/java/net/minecraft/server/level/PlayerChunkMap.java @@ -705,7 +705,9 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { @@ -141,10 +141,10 @@ index d827e18d8c3b9b5869dbb1e233f415ba0efb7c1b..fc687515fdfd47e90e11a2832de07d78 return this.a(i); } diff --git a/src/main/java/net/minecraft/server/level/WorldServer.java b/src/main/java/net/minecraft/server/level/WorldServer.java -index 39b978c6e61e675249743d082699bb9882fd39ff..b4d8fbbc421b3288ae66db2932825b3e2f9b8d98 100644 +index d7a19e6c03b440bc46385868e83a00110dfdc0b1..d80378780d1cb83b37124509d34344e323b828bb 100644 --- a/src/main/java/net/minecraft/server/level/WorldServer.java +++ b/src/main/java/net/minecraft/server/level/WorldServer.java -@@ -1107,7 +1107,28 @@ public class WorldServer extends World implements GeneratorAccessSeed { +@@ -1135,7 +1135,28 @@ public class WorldServer extends World implements GeneratorAccessSeed { gameprofilerfiller.enter("tick"); if (!entity.dead && !(entity instanceof EntityComplexPart)) { @@ -173,7 +173,7 @@ index 39b978c6e61e675249743d082699bb9882fd39ff..b4d8fbbc421b3288ae66db2932825b3e } gameprofilerfiller.exit(); -@@ -1451,9 +1472,14 @@ public class WorldServer extends World implements GeneratorAccessSeed { +@@ -1505,9 +1526,14 @@ public class WorldServer extends World implements GeneratorAccessSeed { ++entity.ticksLived; GameProfilerFiller gameprofilerfiller = this.getMethodProfiler(); @@ -189,12 +189,12 @@ index 39b978c6e61e675249743d082699bb9882fd39ff..b4d8fbbc421b3288ae66db2932825b3e if (isActive) { // Paper - EAR 2 TimingHistory.activatedEntityTicks++; // Paper diff --git a/src/main/java/net/minecraft/world/entity/EntityTypes.java b/src/main/java/net/minecraft/world/entity/EntityTypes.java -index 80c229c1852199fda85c03453d64cae33e413e89..7f70dda656ff9d802200f18139d2695e58c551c7 100644 +index c166e0a8e7eadb4f714078f764ef35f7afca543b..778c981d4458957533fc3ac44095051b279c74e3 100644 --- a/src/main/java/net/minecraft/world/entity/EntityTypes.java +++ b/src/main/java/net/minecraft/world/entity/EntityTypes.java -@@ -270,6 +270,8 @@ public class EntityTypes { - private MinecraftKey bq; - private final EntitySize br; +@@ -271,6 +271,8 @@ public class EntityTypes { + public void setEntitySize(EntitySize entitySize) { this.br = entitySize; } // Purpur - OBFHELPER + private EntitySize br; // Purpur - remove final + public java.util.function.Supplier getEntityName = () -> IRegistry.ENTITY_TYPE.getKey(this).toString(); // Airplane - create lambda ones + @@ -202,10 +202,10 @@ index 80c229c1852199fda85c03453d64cae33e413e89..7f70dda656ff9d802200f18139d2695e return (EntityTypes) IRegistry.a((IRegistry) IRegistry.ENTITY_TYPE, s, (Object) entitytypes_builder.a(s)); } diff --git a/src/main/java/net/minecraft/world/level/World.java b/src/main/java/net/minecraft/world/level/World.java -index 37da32675f0c00c793cd137c9a7305932cefb705..726d0aec2c40ac8e40dba3a12f17870abae6dca6 100644 +index 904dfb7c337b1d583df80533ba5c59478f560c85..d7ec4c6917433ef38b3460c6dae6b954d013890f 100644 --- a/src/main/java/net/minecraft/world/level/World.java +++ b/src/main/java/net/minecraft/world/level/World.java -@@ -1110,19 +1110,19 @@ public abstract class World implements GeneratorAccess, AutoCloseable { +@@ -1156,19 +1156,19 @@ public abstract class World implements GeneratorAccess, AutoCloseable { public void a(Consumer consumer, Entity entity) { try { diff --git a/patches/Airplane/patches/server/0016-Skip-POI-finding-if-stuck-in-vehicle.patch b/patches/Airplane/patches/server/0016-Skip-POI-finding-if-stuck-in-vehicle.patch index 244d3884..f090f182 100644 --- a/patches/Airplane/patches/server/0016-Skip-POI-finding-if-stuck-in-vehicle.patch +++ b/patches/Airplane/patches/server/0016-Skip-POI-finding-if-stuck-in-vehicle.patch @@ -32,10 +32,10 @@ index bc8786e2aaeab4dbae4e9c7666ad816bc5bfac3f..09133c5822bc1386bc3d8a5f3c941964 this.g.long2ObjectEntrySet().removeIf((entry) -> { diff --git a/src/main/java/net/minecraft/world/entity/ai/navigation/NavigationAbstract.java b/src/main/java/net/minecraft/world/entity/ai/navigation/NavigationAbstract.java -index 148bdbc2cffb002d8b6dd05e70854ab503804949..48e6a4c588ef39a4bde067d79b96a656c68750ce 100644 +index a1b7ba4f2cef36e9ac7e21c22060090944ba943b..ac7bad10697c6fde7d512753992d59710aa1e032 100644 --- a/src/main/java/net/minecraft/world/entity/ai/navigation/NavigationAbstract.java +++ b/src/main/java/net/minecraft/world/entity/ai/navigation/NavigationAbstract.java -@@ -433,6 +433,7 @@ public abstract class NavigationAbstract { +@@ -434,6 +434,7 @@ public abstract class NavigationAbstract { } } diff --git a/patches/Airplane/patches/server/0018-Skip-copying-unloading-tile-entities.patch b/patches/Airplane/patches/server/0018-Skip-copying-unloading-tile-entities.patch index 97039fed..a4d5cb95 100644 --- a/patches/Airplane/patches/server/0018-Skip-copying-unloading-tile-entities.patch +++ b/patches/Airplane/patches/server/0018-Skip-copying-unloading-tile-entities.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Skip copying unloading tile entities diff --git a/src/main/java/net/minecraft/world/level/World.java b/src/main/java/net/minecraft/world/level/World.java -index 726d0aec2c40ac8e40dba3a12f17870abae6dca6..334281d4cbdb2d82ca93e862498af961d9abfd31 100644 +index d7ec4c6917433ef38b3460c6dae6b954d013890f..bdedb30970d66fa1b75d185b9d1120de7718a706 100644 --- a/src/main/java/net/minecraft/world/level/World.java +++ b/src/main/java/net/minecraft/world/level/World.java -@@ -106,7 +106,7 @@ public abstract class World implements GeneratorAccess, AutoCloseable { +@@ -107,7 +107,7 @@ public abstract class World implements GeneratorAccess, AutoCloseable { //public final List tileEntityList = Lists.newArrayList(); // Paper - remove unused list public final List tileEntityListTick = Lists.newArrayList(); protected final List tileEntityListPending = Lists.newArrayList(); @@ -17,7 +17,7 @@ index 726d0aec2c40ac8e40dba3a12f17870abae6dca6..334281d4cbdb2d82ca93e862498af961 public final Thread serverThread; private final boolean debugWorld; private int d; -@@ -993,12 +993,17 @@ public abstract class World implements GeneratorAccess, AutoCloseable { +@@ -1039,12 +1039,17 @@ public abstract class World implements GeneratorAccess, AutoCloseable { gameprofilerfiller.enter("blockEntities"); timings.tileEntityTick.startTiming(); // Spigot if (!this.tileEntityListUnload.isEmpty()) { diff --git a/patches/Airplane/patches/server/0020-Cache-entityhuman-display-name.patch b/patches/Airplane/patches/server/0020-Cache-entityhuman-display-name.patch index a43a425c..20ae1673 100644 --- a/patches/Airplane/patches/server/0020-Cache-entityhuman-display-name.patch +++ b/patches/Airplane/patches/server/0020-Cache-entityhuman-display-name.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Cache entityhuman display name diff --git a/src/main/java/net/minecraft/world/entity/player/EntityHuman.java b/src/main/java/net/minecraft/world/entity/player/EntityHuman.java -index 5bce47fa8f191bc1d33c04c9865cb0efd492a9a2..5f9e64df007ebc40f7bcb50be495b10e51d5b87a 100644 +index be7c38c54311d6ea99a4ce2eec63863b649de3b2..176f092828a938c0d5036fbc594dbc26623b1713 100644 --- a/src/main/java/net/minecraft/world/entity/player/EntityHuman.java +++ b/src/main/java/net/minecraft/world/entity/player/EntityHuman.java -@@ -162,7 +162,8 @@ public abstract class EntityHuman extends EntityLiving { +@@ -161,7 +161,8 @@ public abstract class EntityHuman extends EntityLiving { protected int bG; protected final float bH = 0.02F; private int g; @@ -18,7 +18,7 @@ index 5bce47fa8f191bc1d33c04c9865cb0efd492a9a2..5f9e64df007ebc40f7bcb50be495b10e private ItemStack bL; private final ItemCooldown bM; @Nullable -@@ -1840,7 +1841,12 @@ public abstract class EntityHuman extends EntityLiving { +@@ -1877,7 +1878,12 @@ public abstract class EntityHuman extends EntityLiving { @Override public IChatBaseComponent getDisplayName() { diff --git a/patches/Airplane/patches/server/0022-More-debug-for-plugins-not-shutting-down-tasks.patch b/patches/Airplane/patches/server/0022-More-debug-for-plugins-not-shutting-down-tasks.patch index e5eed6e9..e882b52f 100644 --- a/patches/Airplane/patches/server/0022-More-debug-for-plugins-not-shutting-down-tasks.patch +++ b/patches/Airplane/patches/server/0022-More-debug-for-plugins-not-shutting-down-tasks.patch @@ -5,10 +5,10 @@ Subject: [PATCH] More debug for plugins not shutting down tasks diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 507c5255542ba1b958470b4db2c35b1b0b779f17..13b1eb353c22f2935cff7adbb4df725438a46d8f 100644 +index e7e75bc7aaa77c70530fd00f89777f35c614f792..b8727573d768cab51da07a370c606a798a022edb 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -994,6 +994,11 @@ public final class CraftServer implements Server { +@@ -997,6 +997,11 @@ public final class CraftServer implements Server { plugin.getDescription().getName(), "This plugin is not properly shutting down its async tasks when it is being shut down. This task may throw errors during the final shutdown logs and might not complete before process dies." )); diff --git a/patches/Airplane/patches/server/0023-Improve-fluid-direction-caching.patch b/patches/Airplane/patches/server/0023-Improve-fluid-direction-caching.patch index d52bac40..b2d164c6 100644 --- a/patches/Airplane/patches/server/0023-Improve-fluid-direction-caching.patch +++ b/patches/Airplane/patches/server/0023-Improve-fluid-direction-caching.patch @@ -150,10 +150,10 @@ index 0000000000000000000000000000000000000000..aa8467b9dda1f7707e41f50ac7b3e9d7 + } +} diff --git a/src/main/java/net/minecraft/world/level/block/Block.java b/src/main/java/net/minecraft/world/level/block/Block.java -index 7279893d599351785652279c8827fe0efbd72f12..96d7990c66bd569b1b5ee287c0238c7dbb4c503e 100644 +index f65201f8cbf6d402b4366d63bfa03aacf329860f..a835285d230ea0dffa1b28c2a7a006041f2e6b2a 100644 --- a/src/main/java/net/minecraft/world/level/block/Block.java +++ b/src/main/java/net/minecraft/world/level/block/Block.java -@@ -392,6 +392,7 @@ public class Block extends BlockBase implements IMaterial { +@@ -441,6 +441,7 @@ public class Block extends BlockBase implements IMaterial { return this.d; } @@ -162,7 +162,7 @@ index 7279893d599351785652279c8827fe0efbd72f12..96d7990c66bd569b1b5ee287c0238c7d return this.aA; } diff --git a/src/main/java/net/minecraft/world/level/material/FluidTypeFlowing.java b/src/main/java/net/minecraft/world/level/material/FluidTypeFlowing.java -index 6bb4ec00e40795ced73648fefcd1f5027e0113cd..3b8fa837db21c5f67eab2ff8752e906ea97c288d 100644 +index 963b7edab813cd32f04c51fd2c6c137988e2a754..c735bcea9e8b1fa5a77c5c247584b8007f52e0d3 100644 --- a/src/main/java/net/minecraft/world/level/material/FluidTypeFlowing.java +++ b/src/main/java/net/minecraft/world/level/material/FluidTypeFlowing.java @@ -45,6 +45,8 @@ public abstract class FluidTypeFlowing extends FluidType { diff --git a/patches/Airplane/patches/server/0025-Skip-creating-hashset-for-entity-track-range.patch b/patches/Airplane/patches/server/0025-Skip-creating-hashset-for-entity-track-range.patch index bd8eaec2..15685a5e 100644 --- a/patches/Airplane/patches/server/0025-Skip-creating-hashset-for-entity-track-range.patch +++ b/patches/Airplane/patches/server/0025-Skip-creating-hashset-for-entity-track-range.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Skip creating hashset for entity track range diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 5fb3f2968f20e78d76382bec52c9236add4fc060..7ddbc56eb2ea8491cd32987843801e9bee9dbe0b 100644 +index 6c898bf36edbc50018f4795b8c51fc3fbbcc5641..18cc6e729e092511369299c452716f4dbcd1e8dd 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java @@ -319,10 +319,39 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, ne diff --git a/patches/Airplane/patches/server/0026-Cache-climbing-check-for-activation.patch b/patches/Airplane/patches/server/0026-Cache-climbing-check-for-activation.patch index d38865e5..4cca8219 100644 --- a/patches/Airplane/patches/server/0026-Cache-climbing-check-for-activation.patch +++ b/patches/Airplane/patches/server/0026-Cache-climbing-check-for-activation.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Cache climbing check for activation diff --git a/src/main/java/net/minecraft/world/entity/EntityLiving.java b/src/main/java/net/minecraft/world/entity/EntityLiving.java -index 6b82dffa3d0938a94114ead277b42c71ea3bb52b..88fc16e49076cf5589e27660a388909291447fac 100644 +index 59b85551533d332880b154039a5cc3683b17a962..515268d0ce80759835669af16f1aafdb721b5b24 100644 --- a/src/main/java/net/minecraft/world/entity/EntityLiving.java +++ b/src/main/java/net/minecraft/world/entity/EntityLiving.java -@@ -1745,6 +1745,19 @@ public abstract class EntityLiving extends Entity { +@@ -1790,6 +1790,19 @@ public abstract class EntityLiving extends Entity { } } @@ -29,10 +29,10 @@ index 6b82dffa3d0938a94114ead277b42c71ea3bb52b..88fc16e49076cf5589e27660a3889092 return this.world.getType(this.getChunkCoordinates()); } diff --git a/src/main/java/org/spigotmc/ActivationRange.java b/src/main/java/org/spigotmc/ActivationRange.java -index 0c86a93a34fdbb65365e81915ac9f54df4dde88b..b9c675ecae8fd87cca3c7475f4901c9d5529ac6b 100644 +index 3a76d9d90531ed889a0fc92674bd1719aacdb159..2e22c06584c50e32497a2a65b03f5e96063dadc0 100644 --- a/src/main/java/org/spigotmc/ActivationRange.java +++ b/src/main/java/org/spigotmc/ActivationRange.java -@@ -313,7 +313,7 @@ public class ActivationRange +@@ -315,7 +315,7 @@ public class ActivationRange if ( entity instanceof EntityLiving ) { EntityLiving living = (EntityLiving) entity; diff --git a/patches/Airplane/patches/server/0027-Reduce-frequency-of-checking-for-entity-despawn.patch b/patches/Airplane/patches/server/0027-Reduce-frequency-of-checking-for-entity-despawn.patch index dc8c733b..b6581276 100644 --- a/patches/Airplane/patches/server/0027-Reduce-frequency-of-checking-for-entity-despawn.patch +++ b/patches/Airplane/patches/server/0027-Reduce-frequency-of-checking-for-entity-despawn.patch @@ -26,10 +26,10 @@ index 94c18e824695af69e39288195cc2fa83a13029d6..a673eaad4cd80287e8a357f8c45b2add + } diff --git a/src/main/java/net/minecraft/world/entity/EntityInsentient.java b/src/main/java/net/minecraft/world/entity/EntityInsentient.java -index c67138e6a4dcbe823e894f6bb948742bfb8f9943..0f0bf91a3d01c0eb841db81ac441cf5936a2cdfe 100644 +index 35a6a786474fb95082a2d1ca41697c2b1febe55a..409deae8b301b8cdcb38a498f69584f6b808748d 100644 --- a/src/main/java/net/minecraft/world/entity/EntityInsentient.java +++ b/src/main/java/net/minecraft/world/entity/EntityInsentient.java -@@ -774,8 +774,15 @@ public abstract class EntityInsentient extends EntityLiving { +@@ -809,8 +809,15 @@ public abstract class EntityInsentient extends EntityLiving { return false; } diff --git a/patches/Airplane/patches/server/0029-Config-to-disable-method-profiler.patch b/patches/Airplane/patches/server/0029-Config-to-disable-method-profiler.patch index a9842e0c..d872f2e7 100644 --- a/patches/Airplane/patches/server/0029-Config-to-disable-method-profiler.patch +++ b/patches/Airplane/patches/server/0029-Config-to-disable-method-profiler.patch @@ -23,10 +23,10 @@ index a673eaad4cd80287e8a357f8c45b2add156ff0b9..6fc23a85ddd66a69b83684cdb602b6a3 + } diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 6f90a4182e008b49a4b3328e569311382e4bec0d..1472bbdac9b545c97368df03672b975abf2dbcb4 100644 +index ee75fe091f7fd28426b9af329358ea0deb24d589..349a8b5682c09b93c675ac0275fe46125597aaa3 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -2200,7 +2200,11 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant 100) { // Spigot this.snooper.a(); } -@@ -1447,6 +1449,7 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant resourcekey, final DimensionManager dimensionmanager, Supplier supplier, boolean flag, boolean flag1, long i, org.bukkit.generator.ChunkGenerator gen, org.bukkit.World.Environment env, java.util.concurrent.Executor executor) { // Paper this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.WorldDataServer) worlddatamutable).getName()); // Spigot this.paperConfig = new com.destroystokyo.paper.PaperWorldConfig(((net.minecraft.world.level.storage.WorldDataServer) worlddatamutable).getName(), this.spigotConfig); // Paper + this.origamiConfig = new de.minebench.origami.OrigamiConfig.WorldConfig(((net.minecraft.world.level.storage.WorldDataServer) worlddatamutable).getName()); // Origami - World Config this.chunkPacketBlockController = this.paperConfig.antiXray ? new ChunkPacketBlockControllerAntiXray(this, executor) : ChunkPacketBlockController.NO_OPERATION_INSTANCE; // Paper - Anti-Xray this.tuinityConfig = new com.tuinity.tuinity.config.TuinityConfig.WorldConfig(((net.minecraft.world.level.storage.WorldDataServer)worlddatamutable).getName()); // Tuinity - Server Config - this.generator = gen; + this.purpurConfig = new net.pl3x.purpur.PurpurWorldConfig((((net.minecraft.world.level.storage.WorldDataServer)worlddatamutable).getName()), env); // Purpur diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 13b1eb353c22f2935cff7adbb4df725438a46d8f..ca2c46bb22d4aca818f2aad107da42ebe09f2d2f 100644 +index b8727573d768cab51da07a370c606a798a022edb..188365768dcaf0df6805eca065501572f7f9f501 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -881,6 +881,7 @@ public final class CraftServer implements Server { - org.spigotmc.SpigotConfig.init((File) console.options.valueOf("spigot-settings")); // Spigot +@@ -882,6 +882,7 @@ public final class CraftServer implements Server { com.destroystokyo.paper.PaperConfig.init((File) console.options.valueOf("paper-settings")); // Paper com.tuinity.tuinity.config.TuinityConfig.init((File) console.options.valueOf("tuinity-settings")); // Tuinity - Server Config + net.pl3x.purpur.PurpurConfig.init((File) console.options.valueOf("purpur-settings")); // Purpur + de.minebench.origami.OrigamiConfig.init((File) console.options.valueOf("origami-settings")); // Origami - Server Config for (WorldServer world : console.getWorlds()) { world.worldDataServer.setDifficulty(config.difficulty); world.setSpawnFlags(config.spawnMonsters, config.spawnAnimals); -@@ -916,6 +917,7 @@ public final class CraftServer implements Server { - world.spigotConfig.init(); // Spigot +@@ -918,6 +919,7 @@ public final class CraftServer implements Server { world.paperConfig.init(); // Paper world.tuinityConfig.init(); // Tuinity - Server Config + world.purpurConfig.init(); // Purpur + world.origamiConfig.init(); // Origami - World Config } Plugin[] pluginClone = pluginManager.getPlugins().clone(); // Paper diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java -index fbeca329f62325aa479f968e7f0f04cde341a009..1345ee267a61caf97e5b4f6ee641cadb10698fb6 100644 +index 73513638dd024cb1cdd49c705921f0bcf1935968..cbdcc06c03ea1a206e035a41c13242b00b5062a5 100644 --- a/src/main/java/org/bukkit/craftbukkit/Main.java +++ b/src/main/java/org/bukkit/craftbukkit/Main.java -@@ -154,6 +154,14 @@ public class Main { +@@ -162,6 +162,14 @@ public class Main { .describedAs("Yml file"); - /* Conctete End - Server Config */ + // Purpur end + // Origami Start - Server Config + acceptsAll(asList("origami", "origami-settings"), "File for origami settings") @@ -188,7 +188,7 @@ index fbeca329f62325aa479f968e7f0f04cde341a009..1345ee267a61caf97e5b4f6ee641cadb // Paper start acceptsAll(asList("server-name"), "Name of the server") .withRequiredArg() -@@ -292,6 +300,7 @@ public class Main { +@@ -300,6 +308,7 @@ public class Main { } // Paper end System.setProperty( "library.jansi.version", "Paper" ); // Paper - set meaningless jansi version to prevent git builds from crashing on Windows diff --git a/patches/Origami/patches/server/0002-Optimize-inventory-API-item-handling.patch b/patches/Origami/patches/server/0002-Optimize-inventory-API-item-handling.patch index b1c2572f..c7bde4cb 100644 --- a/patches/Origami/patches/server/0002-Optimize-inventory-API-item-handling.patch +++ b/patches/Origami/patches/server/0002-Optimize-inventory-API-item-handling.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Optimize inventory API item handling diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java -index f6001047ada8308cfa1d9b26677a7a5d7774de51..5efae1af23e7a52571bb18885bd45255fb68f1f4 100644 +index 922a15097bdfe64be657fdf157145d1e882b6a40..fe648a00d834410837c923ab3c15ecc33b808851 100644 --- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java @@ -274,11 +274,13 @@ public class CraftInventory implements Inventory { diff --git a/patches/Origami/patches/server/0006-Don-t-wake-up-entities-when-damage-event-is-cancelle.patch b/patches/Origami/patches/server/0006-Don-t-wake-up-entities-when-damage-event-is-cancelle.patch index ad30f534..566ecb49 100644 --- a/patches/Origami/patches/server/0006-Don-t-wake-up-entities-when-damage-event-is-cancelle.patch +++ b/patches/Origami/patches/server/0006-Don-t-wake-up-entities-when-damage-event-is-cancelle.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Don't wake up entities when damage event is cancelled diff --git a/src/main/java/net/minecraft/world/entity/EntityLiving.java b/src/main/java/net/minecraft/world/entity/EntityLiving.java -index 88fc16e49076cf5589e27660a388909291447fac..d8fb0edceba805b9359d02304751182cd0c5a79f 100644 +index 515268d0ce80759835669af16f1aafdb721b5b24..13f660bb60b539cba924b75342f9a4189d7b2d63 100644 --- a/src/main/java/net/minecraft/world/entity/EntityLiving.java +++ b/src/main/java/net/minecraft/world/entity/EntityLiving.java -@@ -1208,9 +1208,12 @@ public abstract class EntityLiving extends Entity { +@@ -1235,9 +1235,12 @@ public abstract class EntityLiving extends Entity { } else if (damagesource.isFire() && this.hasEffect(MobEffects.FIRE_RESISTANCE)) { return false; } else { @@ -24,7 +24,7 @@ index 88fc16e49076cf5589e27660a388909291447fac..d8fb0edceba805b9359d02304751182c this.ticksFarFromPlayer = 0; float f1 = f; -@@ -1961,6 +1964,11 @@ public abstract class EntityLiving extends Entity { +@@ -2006,6 +2009,11 @@ public abstract class EntityLiving extends Entity { if (event.isCancelled()) { return false; } diff --git a/patches/Origami/patches/server/0007-Fix-exp-drop-of-zombie-pigmen-MC-56653.patch b/patches/Origami/patches/server/0007-Fix-exp-drop-of-zombie-pigmen-MC-56653.patch index 3c2a1fca..bbfc885f 100644 --- a/patches/Origami/patches/server/0007-Fix-exp-drop-of-zombie-pigmen-MC-56653.patch +++ b/patches/Origami/patches/server/0007-Fix-exp-drop-of-zombie-pigmen-MC-56653.patch @@ -21,10 +21,10 @@ index f9762c7f40bbb850d14fb7b0c9ff4f3c09921155..9a008acd3e6dd5522d163dfbe09c611f } \ No newline at end of file diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityPigZombie.java b/src/main/java/net/minecraft/world/entity/monster/EntityPigZombie.java -index d10d1b768601236b9892461ee41d61c7239d1a07..1331b7525be64ecf5115dcafc6511837eff5b7ec 100644 +index dfe65943b3a2f744f06b4669590cc203e8419e60..190e37a1b3b5fdbc8bfaaeabb621311503bbc303 100644 --- a/src/main/java/net/minecraft/world/entity/monster/EntityPigZombie.java +++ b/src/main/java/net/minecraft/world/entity/monster/EntityPigZombie.java -@@ -88,7 +88,7 @@ public class EntityPigZombie extends EntityZombie implements IEntityAngerable { +@@ -124,7 +124,7 @@ public class EntityPigZombie extends EntityZombie implements IEntityAngerable { protected void mobTick() { AttributeModifiable attributemodifiable = this.getAttributeInstance(GenericAttributes.MOVEMENT_SPEED); diff --git a/patches/Purpur/patches/api/0001-Purpur-config-files.patch b/patches/Purpur/patches/api/0001-Purpur-config-files.patch new file mode 100644 index 00000000..fd9045d8 --- /dev/null +++ b/patches/Purpur/patches/api/0001-Purpur-config-files.patch @@ -0,0 +1,29 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Tue, 18 Feb 2020 20:30:03 -0600 +Subject: [PATCH] Purpur config files + + +diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java +index f55ae8275c297c4c86215fba8d7197ffe9715879..0888165f2327bad2125d9cbe9b72e3282d44e072 100644 +--- a/src/main/java/org/bukkit/Server.java ++++ b/src/main/java/org/bukkit/Server.java +@@ -1614,6 +1614,18 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi + } + // Tuinity end - add config to timings report + ++ // Purpur start ++ @NotNull ++ public org.bukkit.configuration.file.YamlConfiguration getPurpurConfig() { ++ throw new UnsupportedOperationException("Not supported yet."); ++ } ++ ++ @NotNull ++ public java.util.Properties getServerProperties() { ++ throw new UnsupportedOperationException("Not supported yet."); ++ } ++ // Purpur end ++ + /** + * Sends the component to the player + * diff --git a/patches/Purpur/patches/api/0002-Default-permissions.patch b/patches/Purpur/patches/api/0002-Default-permissions.patch new file mode 100644 index 00000000..777f0343 --- /dev/null +++ b/patches/Purpur/patches/api/0002-Default-permissions.patch @@ -0,0 +1,113 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Fri, 5 Jun 2020 23:32:38 -0500 +Subject: [PATCH] Default permissions + + +diff --git a/src/main/java/org/bukkit/util/permissions/CommandPermissions.java b/src/main/java/org/bukkit/util/permissions/CommandPermissions.java +index 7763d6101ac61900db1e2310966b99584539fd0e..d5a42707d365ffd72532bbb1a59a1ca7145f9918 100644 +--- a/src/main/java/org/bukkit/util/permissions/CommandPermissions.java ++++ b/src/main/java/org/bukkit/util/permissions/CommandPermissions.java +@@ -18,6 +18,7 @@ public final class CommandPermissions { + DefaultPermissions.registerPermission(PREFIX + "plugins", "Allows the user to view the list of plugins running on this server", PermissionDefault.TRUE, commands); + DefaultPermissions.registerPermission(PREFIX + "reload", "Allows the user to reload the server settings", PermissionDefault.OP, commands); + DefaultPermissions.registerPermission(PREFIX + "version", "Allows the user to view the version of the server", PermissionDefault.TRUE, commands); ++ DefaultPermissions.registerPermission(PREFIX + "purpur", "Allows the user to use the purpur command", PermissionDefault.OP, commands); // Purpur + + commands.recalculatePermissibles(); + return commands; +diff --git a/src/main/java/org/bukkit/util/permissions/DefaultPermissions.java b/src/main/java/org/bukkit/util/permissions/DefaultPermissions.java +index e1a4ddf2c07cdd242fa8054a0152522fe4039e85..8e481e3815f5645ee92f0d229e5ff25c8fc9a6c2 100644 +--- a/src/main/java/org/bukkit/util/permissions/DefaultPermissions.java ++++ b/src/main/java/org/bukkit/util/permissions/DefaultPermissions.java +@@ -89,6 +89,8 @@ public final class DefaultPermissions { + CommandPermissions.registerPermissions(parent); + BroadcastPermissions.registerPermissions(parent); + ++ PurpurPermissions.registerPermissions(); // Purpur ++ + parent.recalculatePermissibles(); + } + } +diff --git a/src/main/java/org/bukkit/util/permissions/PurpurPermissions.java b/src/main/java/org/bukkit/util/permissions/PurpurPermissions.java +new file mode 100644 +index 0000000000000000000000000000000000000000..deedffb4aca00a9ff27a47a09ec7087e5566ad29 +--- /dev/null ++++ b/src/main/java/org/bukkit/util/permissions/PurpurPermissions.java +@@ -0,0 +1,76 @@ ++package org.bukkit.util.permissions; ++ ++import org.bukkit.entity.Entity; ++import org.bukkit.entity.EntityType; ++import org.bukkit.entity.Mob; ++import org.bukkit.permissions.Permission; ++import org.bukkit.permissions.PermissionDefault; ++import org.jetbrains.annotations.NotNull; ++ ++import java.util.HashSet; ++import java.util.Set; ++ ++public final class PurpurPermissions { ++ private static final String ROOT = "purpur"; ++ private static final String PREFIX = ROOT + "."; ++ private static final Set mobs = new HashSet<>(); ++ ++ private PurpurPermissions() { ++ for (EntityType mob : EntityType.values()) { ++ Class clazz = mob.getEntityClass(); ++ if (clazz != null && clazz.isAssignableFrom(Mob.class)) { ++ mobs.add(mob.getName()); ++ } ++ } ++ } ++ ++ @NotNull ++ public static Permission registerPermissions() { ++ Permission purpur = DefaultPermissions.registerPermission(ROOT, "Gives the user the ability to use all Purpur utilities and commands"); ++ ++ DefaultPermissions.registerPermission(PREFIX + "enderchest.rows.six", "Gives the user six rows of enderchest space", org.bukkit.permissions.PermissionDefault.FALSE); ++ DefaultPermissions.registerPermission(PREFIX + "enderchest.rows.five", "Gives the user five rows of enderchest space", org.bukkit.permissions.PermissionDefault.FALSE); ++ DefaultPermissions.registerPermission(PREFIX + "enderchest.rows.four", "Gives the user four rows of enderchest space", org.bukkit.permissions.PermissionDefault.FALSE); ++ DefaultPermissions.registerPermission(PREFIX + "enderchest.rows.three", "Gives the user three rows of enderchest space", org.bukkit.permissions.PermissionDefault.FALSE); ++ DefaultPermissions.registerPermission(PREFIX + "enderchest.rows.two", "Gives the user two rows of enderchest space", org.bukkit.permissions.PermissionDefault.FALSE); ++ DefaultPermissions.registerPermission(PREFIX + "enderchest.rows.one", "Gives the user one row of enderchest space", org.bukkit.permissions.PermissionDefault.FALSE); ++ ++ DefaultPermissions.registerPermission(PREFIX + "debug.f3n", "Allows the user to use F3+N keybind to swap gamemodes", PermissionDefault.FALSE, purpur); ++ ++ DefaultPermissions.registerPermission(PREFIX + "drop.spawner", "Allows the user to drop spawner cage when broken with diamond pickaxe with silk touch", PermissionDefault.FALSE, purpur); ++ DefaultPermissions.registerPermission(PREFIX + "place.spawner", "Allows the user to place spawner cage in the world", PermissionDefault.FALSE, purpur); ++ ++ DefaultPermissions.registerPermission(PREFIX + "anvil.color", "Allows the user to use color codes on anvils", PermissionDefault.FALSE, purpur); ++ ++ Permission book = DefaultPermissions.registerPermission(PREFIX + "book", "Allows the user to use color codes on books", PermissionDefault.FALSE, purpur); ++ DefaultPermissions.registerPermission(PREFIX + "book.color.edit", "Allows the user to use color codes on books when editing", PermissionDefault.FALSE, book); ++ DefaultPermissions.registerPermission(PREFIX + "book.color.sign", "Allows the user to use color codes on books when signing", PermissionDefault.FALSE, book); ++ book.recalculatePermissibles(); ++ ++ Permission sign = DefaultPermissions.registerPermission(PREFIX + "sign", "Allows the user to use all sign abilities", PermissionDefault.FALSE, purpur); ++ DefaultPermissions.registerPermission(PREFIX + "sign.click.opens.editor", "Allows the user to click signs to open sign editor", PermissionDefault.FALSE, sign); ++ DefaultPermissions.registerPermission(PREFIX + "sign.color", "Allows the user to use color codes on signs", PermissionDefault.FALSE, sign); ++ DefaultPermissions.registerPermission(PREFIX + "sign.style", "Allows the user to use style codes on signs", PermissionDefault.FALSE, sign); ++ DefaultPermissions.registerPermission(PREFIX + "sign.magic", "Allows the user to use magic/obfuscate code on signs", PermissionDefault.FALSE, sign); ++ sign.recalculatePermissibles(); ++ ++ Permission ride = DefaultPermissions.registerPermission("allow.ride", "Allows the user to ride all mobs", PermissionDefault.FALSE); ++ for (String mob : mobs) { ++ DefaultPermissions.registerPermission("allow.ride." + mob, "Allows the user to ride " + mob, PermissionDefault.FALSE, ride); ++ } ++ ride.recalculatePermissibles(); ++ ++ Permission special = DefaultPermissions.registerPermission("allow.special", "Allows the user to use all mobs special abilities", PermissionDefault.FALSE); ++ for (String mob : mobs) { ++ DefaultPermissions.registerPermission("allow.special." + mob, "Allows the user to use " + mob + " special ability", PermissionDefault.FALSE, special); ++ } ++ special.recalculatePermissibles(); ++ ++ Permission powered = DefaultPermissions.registerPermission("allow.powered", "Allows the user to toggle all mobs powered state", PermissionDefault.FALSE); ++ DefaultPermissions.registerPermission("allow.powered.creeper", "Allows the user to toggle creeper powered state", PermissionDefault.FALSE, powered); ++ powered.recalculatePermissibles(); ++ ++ purpur.recalculatePermissibles(); ++ return purpur; ++ } ++} diff --git a/patches/Purpur/patches/api/0003-Allow-inventory-resizing.patch b/patches/Purpur/patches/api/0003-Allow-inventory-resizing.patch new file mode 100644 index 00000000..486bb37d --- /dev/null +++ b/patches/Purpur/patches/api/0003-Allow-inventory-resizing.patch @@ -0,0 +1,32 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Tue, 23 Jul 2019 06:50:55 -0500 +Subject: [PATCH] Allow inventory resizing + + +diff --git a/src/main/java/org/bukkit/event/inventory/InventoryType.java b/src/main/java/org/bukkit/event/inventory/InventoryType.java +index 090d22bd30f7947103771aaaf09a2398970ac337..ca660dde2010098e8c77141d05c2d4d5470adf81 100644 +--- a/src/main/java/org/bukkit/event/inventory/InventoryType.java ++++ b/src/main/java/org/bukkit/event/inventory/InventoryType.java +@@ -132,7 +132,7 @@ public enum InventoryType { + STONECUTTER(2, "Stonecutter") + ; + +- private final int size; ++ private int size; // Purpur - remove final + private final String title; + private final boolean isCreatable; + +@@ -159,6 +159,12 @@ public enum InventoryType { + this.defaultTitleComponent = net.kyori.adventure.text.Component.text(defaultTitle); // Paper - Adventure + } + ++ // Purpur start ++ public void setDefaultSize(int size) { ++ this.size = size; ++ } ++ // Purpur end ++ + public int getDefaultSize() { + return size; + } diff --git a/patches/Purpur/patches/api/0004-Advancement-API.patch b/patches/Purpur/patches/api/0004-Advancement-API.patch new file mode 100644 index 00000000..20af6e99 --- /dev/null +++ b/patches/Purpur/patches/api/0004-Advancement-API.patch @@ -0,0 +1,123 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Fri, 31 May 2019 21:24:21 -0500 +Subject: [PATCH] Advancement API + + +diff --git a/src/main/java/org/bukkit/advancement/Advancement.java b/src/main/java/org/bukkit/advancement/Advancement.java +index 7c5009974ac8d64d0e738e60cec45acb0d4ca89a..432caadba1b08bb94cdb4ccf552e42400e0db338 100644 +--- a/src/main/java/org/bukkit/advancement/Advancement.java ++++ b/src/main/java/org/bukkit/advancement/Advancement.java +@@ -3,6 +3,7 @@ package org.bukkit.advancement; + import java.util.Collection; + import org.bukkit.Keyed; + import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; + + /** + * Represents an advancement that may be awarded to a player. This class is not +@@ -17,4 +18,12 @@ public interface Advancement extends Keyed { + */ + @NotNull + Collection getCriteria(); ++ ++ /** ++ * Gets the display properties of this advancement ++ * ++ * @return The display properties ++ */ ++ @Nullable ++ AdvancementDisplay getDisplay(); + } +diff --git a/src/main/java/org/bukkit/advancement/AdvancementDisplay.java b/src/main/java/org/bukkit/advancement/AdvancementDisplay.java +new file mode 100644 +index 0000000000000000000000000000000000000000..bca3d112e2397b26ba6ccb6cd41e406caae27c5c +--- /dev/null ++++ b/src/main/java/org/bukkit/advancement/AdvancementDisplay.java +@@ -0,0 +1,53 @@ ++package org.bukkit.advancement; ++ ++import org.jetbrains.annotations.NotNull; ++ ++public interface AdvancementDisplay { ++ /** ++ * Get the title of this advancement ++ * ++ * @return Title text ++ */ ++ @NotNull ++ String getTitle(); ++ ++ /** ++ * Get the description of this advancement ++ * ++ * @return Description text ++ */ ++ @NotNull ++ String getDescription(); ++ ++ /** ++ * Get the frame type of this advancement ++ * ++ * @return Frame type ++ */ ++ @NotNull ++ FrameType getFrameType(); ++ ++ /** ++ * Get if this advancement should be announced in chat when completed ++ * ++ * @return True if should announce when completed ++ */ ++ boolean shouldAnnounceToChat(); ++ ++ /** ++ * Set if this advancement should be announced in chat when completed ++ * ++ * @param announce True or false ++ * ++ */ ++ void setShouldAnnounceToChat(boolean announce); ++ ++ /** ++ * Get if this advancement (and all it's children) is hidden from the advancement screen until it has been completed ++ *

++ * This has no effect on root advancements themselves, but will alter their children ++ * ++ * @return True if hidden until completed ++ */ ++ boolean isHidden(); ++} +diff --git a/src/main/java/org/bukkit/advancement/FrameType.java b/src/main/java/org/bukkit/advancement/FrameType.java +new file mode 100644 +index 0000000000000000000000000000000000000000..d1757f3d456ff9efce26ce8baa1d16d896908cc2 +--- /dev/null ++++ b/src/main/java/org/bukkit/advancement/FrameType.java +@@ -0,0 +1,27 @@ ++package org.bukkit.advancement; ++ ++import org.bukkit.ChatColor; ++import org.jetbrains.annotations.NotNull; ++ ++public enum FrameType { ++ TASK(ChatColor.GREEN), ++ CHALLENGE(ChatColor.DARK_PURPLE), ++ GOAL(ChatColor.GREEN); ++ ++ private final ChatColor color; ++ ++ FrameType(ChatColor color) { ++ this.color = color; ++ } ++ ++ @NotNull ++ public ChatColor getColor() { ++ return color; ++ } ++ ++ @NotNull ++ @Override ++ public String toString() { ++ return "FrameType[name=" + name() + ",color=" + color + "]"; ++ } ++} diff --git a/patches/Purpur/patches/api/0005-Llama-API.patch b/patches/Purpur/patches/api/0005-Llama-API.patch new file mode 100644 index 00000000..8b336a47 --- /dev/null +++ b/patches/Purpur/patches/api/0005-Llama-API.patch @@ -0,0 +1,191 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Fri, 18 Oct 2019 22:50:05 -0500 +Subject: [PATCH] Llama API + + +diff --git a/src/main/java/net/pl3x/purpur/event/entity/LlamaJoinCaravanEvent.java b/src/main/java/net/pl3x/purpur/event/entity/LlamaJoinCaravanEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..6e68c1399bf30eeef6ce0385867f0cf258698eae +--- /dev/null ++++ b/src/main/java/net/pl3x/purpur/event/entity/LlamaJoinCaravanEvent.java +@@ -0,0 +1,61 @@ ++package net.pl3x.purpur.event.entity; ++ ++import org.bukkit.entity.Llama; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.entity.EntityEvent; ++import org.jetbrains.annotations.NotNull; ++ ++/** ++ * Called when a Llama tries to join a caravan. ++ *

++ * Cancelling the event will not let the Llama join. To prevent future attempts ++ * at joining a caravan use {@link Llama#setShouldJoinCaravan(boolean)}. ++ */ ++public class LlamaJoinCaravanEvent extends EntityEvent implements Cancellable { ++ private static final HandlerList handlers = new HandlerList(); ++ private boolean canceled; ++ private final Llama head; ++ ++ public LlamaJoinCaravanEvent(@NotNull Llama llama, @NotNull Llama head) { ++ super(llama); ++ this.head = head; ++ } ++ ++ @Override ++ @NotNull ++ public Llama getEntity() { ++ return (Llama) entity; ++ } ++ ++ /** ++ * Get the Llama that this Llama is about to follow ++ * ++ * @return Llama about to be followed ++ */ ++ @NotNull ++ public Llama getHead() { ++ return head; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return canceled; ++ } ++ ++ @Override ++ public void setCancelled(boolean cancel) { ++ canceled = cancel; ++ } ++ ++ @Override ++ @NotNull ++ public HandlerList getHandlers() { ++ return handlers; ++ } ++ ++ @NotNull ++ public static HandlerList getHandlerList() { ++ return handlers; ++ } ++} +diff --git a/src/main/java/net/pl3x/purpur/event/entity/LlamaLeaveCaravanEvent.java b/src/main/java/net/pl3x/purpur/event/entity/LlamaLeaveCaravanEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..ec8d978c22835e2789ebaaeddf0d13588ed1122a +--- /dev/null ++++ b/src/main/java/net/pl3x/purpur/event/entity/LlamaLeaveCaravanEvent.java +@@ -0,0 +1,34 @@ ++package net.pl3x.purpur.event.entity; ++ ++import org.bukkit.entity.Llama; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.entity.EntityEvent; ++import org.jetbrains.annotations.NotNull; ++ ++/** ++ * Called when a Llama leaves a caravan ++ */ ++public class LlamaLeaveCaravanEvent extends EntityEvent { ++ private static final HandlerList handlers = new HandlerList(); ++ ++ public LlamaLeaveCaravanEvent(@NotNull Llama llama) { ++ super(llama); ++ } ++ ++ @Override ++ @NotNull ++ public Llama getEntity() { ++ return (Llama) entity; ++ } ++ ++ @Override ++ @NotNull ++ public HandlerList getHandlers() { ++ return handlers; ++ } ++ ++ @NotNull ++ public static HandlerList getHandlerList() { ++ return handlers; ++ } ++} +diff --git a/src/main/java/org/bukkit/entity/Llama.java b/src/main/java/org/bukkit/entity/Llama.java +index d23226ccb0f6c25028f000ce31346cd0a8898e6a..1ef9479c962b3f4f6fed46671a1209c34040d16d 100644 +--- a/src/main/java/org/bukkit/entity/Llama.java ++++ b/src/main/java/org/bukkit/entity/Llama.java +@@ -3,6 +3,7 @@ package org.bukkit.entity; + import com.destroystokyo.paper.entity.RangedEntity; + import org.bukkit.inventory.LlamaInventory; + import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; // Purpur + + /** + * Represents a Llama. +@@ -67,4 +68,65 @@ public interface Llama extends ChestedHorse, RangedEntity { // Paper + @NotNull + @Override + LlamaInventory getInventory(); ++ ++ // Purpur start ++ ++ /** ++ * Check if this Llama should attempt to join a caravan ++ * ++ * @return True if Llama is allowed to join a caravan ++ */ ++ boolean shouldJoinCaravan(); ++ ++ /** ++ * Set if this Llama should attempt to join a caravan ++ * ++ * @param shouldJoinCaravan True to allow joining a caravan ++ */ ++ void setShouldJoinCaravan(boolean shouldJoinCaravan); ++ ++ /** ++ * Check if Llama is in a caravan ++ * ++ * @return True if in caravan ++ */ ++ boolean inCaravan(); ++ ++ /** ++ * Join a caravan ++ * ++ * @param llama Head of caravan to join ++ */ ++ void joinCaravan(@NotNull Llama llama); ++ ++ /** ++ * Leave current caravan if in one ++ */ ++ void leaveCaravan(); ++ ++ /** ++ * Check if another Llama is following this Llama ++ * ++ * @return True if being followed in the caravan ++ */ ++ boolean hasCaravanTail(); ++ ++ /** ++ * Get the Llama that this Llama is following ++ *

++ * Does not necessarily mean the leader of the entire caravan ++ * ++ * @return The Llama being followed ++ */ ++ @Nullable ++ Llama getCaravanHead(); ++ ++ /** ++ * Get the Llama following this Llama, if any ++ * ++ * @return The Llama following this one ++ */ ++ @Nullable ++ Llama getCaravanTail(); ++ // Purpur end + } diff --git a/patches/Purpur/patches/api/0006-AFK-API.patch b/patches/Purpur/patches/api/0006-AFK-API.patch new file mode 100644 index 00000000..bc175666 --- /dev/null +++ b/patches/Purpur/patches/api/0006-AFK-API.patch @@ -0,0 +1,112 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sat, 10 Aug 2019 22:19:56 -0500 +Subject: [PATCH] AFK API + + +diff --git a/src/main/java/net/pl3x/purpur/event/PlayerAFKEvent.java b/src/main/java/net/pl3x/purpur/event/PlayerAFKEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0c8b3e5e4ba412624357ea5662a78862bd9fc4be +--- /dev/null ++++ b/src/main/java/net/pl3x/purpur/event/PlayerAFKEvent.java +@@ -0,0 +1,70 @@ ++package net.pl3x.purpur.event; ++ ++import org.bukkit.entity.Player; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.player.PlayerEvent; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++public class PlayerAFKEvent extends PlayerEvent implements Cancellable { ++ private static final HandlerList handlers = new HandlerList(); ++ private final boolean setAfk; ++ private boolean shouldKick; ++ private String broadcast; ++ private boolean cancel; ++ ++ public PlayerAFKEvent(@NotNull Player player, boolean setAfk, boolean shouldKick, @Nullable String broadcast, boolean async) { ++ super(player, async); ++ this.setAfk = setAfk; ++ this.shouldKick = shouldKick; ++ this.broadcast = broadcast; ++ } ++ ++ /** ++ * Whether player is going afk or coming back ++ * ++ * @return True if going afk. False is coming back ++ */ ++ public boolean isGoingAfk() { ++ return setAfk; ++ } ++ ++ public boolean shouldKick() { ++ return shouldKick; ++ } ++ ++ public void setShouldKick(boolean shouldKick) { ++ this.shouldKick = shouldKick; ++ } ++ ++ @Nullable ++ public String getBroadcastMsg() { ++ return broadcast; ++ } ++ ++ public void setBroadcastMsg(@Nullable String broadcast) { ++ this.broadcast = broadcast; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return cancel; ++ } ++ ++ @Override ++ public void setCancelled(boolean cancel) { ++ this.cancel = cancel; ++ } ++ ++ @Override ++ @NotNull ++ public HandlerList getHandlers() { ++ return handlers; ++ } ++ ++ @NotNull ++ public static HandlerList getHandlerList() { ++ return handlers; ++ } ++} +diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java +index 27848ad0eee667e515685a5f1cef3e9bfc7a3f53..09729abc27b6cb3458e19af24137bbbc6e5cb63e 100644 +--- a/src/main/java/org/bukkit/entity/Player.java ++++ b/src/main/java/org/bukkit/entity/Player.java +@@ -2139,4 +2139,25 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + @Override + Spigot spigot(); + // Spigot end ++ ++ // Purpur start ++ /** ++ * Check if player is AFK ++ * ++ * @return True if AFK ++ */ ++ boolean isAfk(); ++ ++ /** ++ * Set player as AFK ++ * ++ * @param setAfk Whether to set AFK or not ++ */ ++ void setAfk(boolean setAfk); ++ ++ /** ++ * Reset the idle timer back to 0 ++ */ ++ void resetIdleTimer(); ++ // Purpur end + } diff --git a/patches/Purpur/patches/api/0007-Bring-back-server-name.patch b/patches/Purpur/patches/api/0007-Bring-back-server-name.patch new file mode 100644 index 00000000..e49a4594 --- /dev/null +++ b/patches/Purpur/patches/api/0007-Bring-back-server-name.patch @@ -0,0 +1,44 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sun, 26 May 2019 15:18:40 -0500 +Subject: [PATCH] Bring back server name + + +diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java +index e8414592b3afeb1e5db2b817b8fb7c13e073b9aa..281c5a72cf59dd5cb3dee47541641483d434aeb0 100644 +--- a/src/main/java/org/bukkit/Bukkit.java ++++ b/src/main/java/org/bukkit/Bukkit.java +@@ -1963,4 +1963,15 @@ public final class Bukkit { + public static Server.Spigot spigot() { + return server.spigot(); + } ++ ++ // Purpur start ++ /** ++ * Get the name of this server ++ * @return the name of the server ++ */ ++ @NotNull ++ public static String getServerName() { ++ return server.getServerName(); ++ } ++ // Purpur end + } +diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java +index 0888165f2327bad2125d9cbe9b72e3282d44e072..eebaee3f3e01f39c0378cc89381eb97d95f31152 100644 +--- a/src/main/java/org/bukkit/Server.java ++++ b/src/main/java/org/bukkit/Server.java +@@ -1736,4 +1736,13 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi + @NotNull + io.papermc.paper.datapack.DatapackManager getDatapackManager(); + // Paper end ++ ++ // Purpur start ++ /** ++ * Get the name of this server ++ * @return the name of the server ++ */ ++ @NotNull ++ String getServerName(); ++ // Purpur end + } diff --git a/patches/Purpur/patches/api/0008-ExecuteCommandEvent.patch b/patches/Purpur/patches/api/0008-ExecuteCommandEvent.patch new file mode 100644 index 00000000..d5aca414 --- /dev/null +++ b/patches/Purpur/patches/api/0008-ExecuteCommandEvent.patch @@ -0,0 +1,175 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Fri, 31 May 2019 00:08:28 -0500 +Subject: [PATCH] ExecuteCommandEvent + + +diff --git a/src/main/java/net/pl3x/purpur/event/ExecuteCommandEvent.java b/src/main/java/net/pl3x/purpur/event/ExecuteCommandEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..3250bd4dc29a0cf79b08833d95a3321d1a6733f6 +--- /dev/null ++++ b/src/main/java/net/pl3x/purpur/event/ExecuteCommandEvent.java +@@ -0,0 +1,130 @@ ++package net.pl3x.purpur.event; ++ ++import org.apache.commons.lang.Validate; ++import org.bukkit.command.Command; ++import org.bukkit.command.CommandSender; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.Event; ++import org.bukkit.event.HandlerList; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++/** ++ * This event is called whenever someone runs a command ++ */ ++public class ExecuteCommandEvent extends Event implements Cancellable { ++ private static final HandlerList handlers = new HandlerList(); ++ private boolean cancel = false; ++ private CommandSender sender; ++ private Command command; ++ private String label; ++ private String[] args; ++ ++ public ExecuteCommandEvent(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @Nullable String[] args) { ++ this.sender = sender; ++ this.command = command; ++ this.label = label; ++ this.args = args; ++ } ++ ++ /** ++ * Gets the command that the player is attempting to execute. ++ * ++ * @return Command the player is attempting to execute ++ */ ++ @NotNull ++ public Command getCommand() { ++ return command; ++ } ++ ++ /** ++ * Sets the command that the player will execute. ++ * ++ * @param command New command that the player will execute ++ * @throws IllegalArgumentException if command is null or empty ++ */ ++ public void setCommand(@NotNull Command command) throws IllegalArgumentException { ++ Validate.notNull(command, "Command cannot be null"); ++ this.command = command; ++ } ++ ++ /** ++ * Gets the sender that this command will be executed as. ++ * ++ * @return Sender this command will be executed as ++ */ ++ @NotNull ++ public CommandSender getSender() { ++ return sender; ++ } ++ ++ /** ++ * Sets the sender that this command will be executed as. ++ * ++ * @param sender New sender which this event will execute as ++ * @throws IllegalArgumentException if the sender provided is null ++ */ ++ public void setSender(@NotNull final CommandSender sender) throws IllegalArgumentException { ++ Validate.notNull(sender, "Sender cannot be null"); ++ this.sender = sender; ++ } ++ ++ /** ++ * Get the label used to execute this command ++ * ++ * @return Label used to execute this command ++ */ ++ @NotNull ++ public String getLabel() { ++ return label; ++ } ++ ++ /** ++ * Set the label used to execute this command ++ * ++ * @param label Label used ++ */ ++ public void setLabel(@NotNull String label) { ++ this.label = label; ++ } ++ ++ /** ++ * Get the args passed to the command ++ * ++ * @return Args passed to the command ++ */ ++ @NotNull ++ public String[] getArgs() { ++ return args; ++ } ++ ++ /** ++ * Set the args passed to the command ++ * ++ * @param args Args passed to the command ++ */ ++ public void setArgs(@NotNull String[] args) { ++ this.args = args; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return cancel; ++ } ++ ++ @Override ++ public void setCancelled(boolean cancel) { ++ this.cancel = cancel; ++ } ++ ++ @NotNull ++ @Override ++ public HandlerList getHandlers() { ++ return handlers; ++ } ++ ++ @NotNull ++ public static HandlerList getHandlerList() { ++ return handlers; ++ } ++} +diff --git a/src/main/java/org/bukkit/command/SimpleCommandMap.java b/src/main/java/org/bukkit/command/SimpleCommandMap.java +index 460fda05a62b12db2edcfb7ea8b2a5dd8e4b110d..1e0eb099933dded131d3c4db8f3cca2b6ed8e064 100644 +--- a/src/main/java/org/bukkit/command/SimpleCommandMap.java ++++ b/src/main/java/org/bukkit/command/SimpleCommandMap.java +@@ -147,6 +147,19 @@ public class SimpleCommandMap implements CommandMap { + return false; + } + ++ // Purpur start ++ String[] parsedArgs = Arrays.copyOfRange(args, 1, args.length); ++ net.pl3x.purpur.event.ExecuteCommandEvent event = new net.pl3x.purpur.event.ExecuteCommandEvent(sender, target, sentCommandLabel, parsedArgs); ++ if (!event.callEvent()) { ++ return true; // cancelled ++ } ++ ++ sender = event.getSender(); ++ target = event.getCommand(); ++ sentCommandLabel = event.getLabel(); ++ parsedArgs = event.getArgs(); ++ // Purpur end ++ + // Paper start - Plugins do weird things to workaround normal registration + if (target.timings == null) { + target.timings = co.aikar.timings.TimingsManager.getCommandTiming(null, target); +@@ -156,7 +169,7 @@ public class SimpleCommandMap implements CommandMap { + try { + try (co.aikar.timings.Timing ignored = target.timings.startTiming()) { // Paper - use try with resources + // Note: we don't return the result of target.execute as thats success / failure, we return handled (true) or not handled (false) +- target.execute(sender, sentCommandLabel, Arrays.copyOfRange(args, 1, args.length)); ++ target.execute(sender, sentCommandLabel, parsedArgs); // Purpur + } // target.timings.stopTiming(); // Spigot // Paper + } catch (CommandException ex) { + server.getPluginManager().callEvent(new ServerExceptionEvent(new ServerCommandException(ex, target, sender, args))); // Paper diff --git a/patches/Purpur/patches/api/0009-LivingEntity-safeFallDistance.patch b/patches/Purpur/patches/api/0009-LivingEntity-safeFallDistance.patch new file mode 100644 index 00000000..7383c9a6 --- /dev/null +++ b/patches/Purpur/patches/api/0009-LivingEntity-safeFallDistance.patch @@ -0,0 +1,31 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sun, 5 May 2019 12:58:19 -0500 +Subject: [PATCH] LivingEntity safeFallDistance + + +diff --git a/src/main/java/org/bukkit/entity/LivingEntity.java b/src/main/java/org/bukkit/entity/LivingEntity.java +index ccb81ceee74fff50ec3ed88ae0a41f790c40ae87..b96edbf7e5a2bf66a9ebf9300368e8f6a8d561f9 100644 +--- a/src/main/java/org/bukkit/entity/LivingEntity.java ++++ b/src/main/java/org/bukkit/entity/LivingEntity.java +@@ -873,4 +873,20 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource + */ + void setHurtDirection(float hurtDirection); + // Paper end ++ ++ // Purpur start ++ /** ++ * Gets the distance (in blocks) this entity can safely fall without taking damage ++ * ++ * @return Safe fall distance ++ */ ++ float getSafeFallDistance(); ++ ++ /** ++ * Set the distance (in blocks) this entity can safely fall without taking damage ++ * ++ * @param safeFallDistance Safe fall distance ++ */ ++ void setSafeFallDistance(float safeFallDistance); ++ // Purpur end + } diff --git a/patches/Purpur/patches/api/0010-Lagging-threshold.patch b/patches/Purpur/patches/api/0010-Lagging-threshold.patch new file mode 100644 index 00000000..b5636be5 --- /dev/null +++ b/patches/Purpur/patches/api/0010-Lagging-threshold.patch @@ -0,0 +1,42 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Tue, 23 Jul 2019 10:07:24 -0500 +Subject: [PATCH] Lagging threshold + + +diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java +index 281c5a72cf59dd5cb3dee47541641483d434aeb0..a60c8bd89d14e47d3243307241458e907249a99b 100644 +--- a/src/main/java/org/bukkit/Bukkit.java ++++ b/src/main/java/org/bukkit/Bukkit.java +@@ -1973,5 +1973,14 @@ public final class Bukkit { + public static String getServerName() { + return server.getServerName(); + } ++ ++ /** ++ * Check if server is lagging according to laggy threshold setting ++ * ++ * @return True if lagging ++ */ ++ public static boolean isLagging() { ++ return server.isLagging(); ++ } + // Purpur end + } +diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java +index eebaee3f3e01f39c0378cc89381eb97d95f31152..f24d00951cd6951023f1ff34312ae0438107fc22 100644 +--- a/src/main/java/org/bukkit/Server.java ++++ b/src/main/java/org/bukkit/Server.java +@@ -1744,5 +1744,12 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi + */ + @NotNull + String getServerName(); ++ ++ /** ++ * Check if server is lagging according to laggy threshold setting ++ * ++ * @return True if lagging ++ */ ++ boolean isLagging(); + // Purpur end + } diff --git a/patches/Purpur/patches/api/0011-ItemFactory-getMonsterEgg.patch b/patches/Purpur/patches/api/0011-ItemFactory-getMonsterEgg.patch new file mode 100644 index 00000000..f426c80e --- /dev/null +++ b/patches/Purpur/patches/api/0011-ItemFactory-getMonsterEgg.patch @@ -0,0 +1,26 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Fri, 5 Jul 2019 16:37:04 -0500 +Subject: [PATCH] ItemFactory#getMonsterEgg + + +diff --git a/src/main/java/org/bukkit/inventory/ItemFactory.java b/src/main/java/org/bukkit/inventory/ItemFactory.java +index ec7c07564608386c3f7d4322d0af4cbb7d92bc74..39323b3151c733392333858a2dbf1f3f8637341e 100644 +--- a/src/main/java/org/bukkit/inventory/ItemFactory.java ++++ b/src/main/java/org/bukkit/inventory/ItemFactory.java +@@ -242,4 +242,15 @@ public interface ItemFactory { + @Deprecated + net.md_5.bungee.api.chat.hover.content.Content hoverContentOf(@NotNull org.bukkit.entity.Entity entity, @NotNull net.md_5.bungee.api.chat.BaseComponent[] customName); + // Paper end ++ ++ // Purpur start ++ /** ++ * Get a monster egg ItemStack from an EntityType ++ * ++ * @param type EntityType ++ * @return ItemStack spawner egg ++ */ ++ @Nullable ++ ItemStack getMonsterEgg(@Nullable org.bukkit.entity.EntityType type); ++ // Purpur end + } diff --git a/patches/Purpur/patches/api/0012-PlayerSetSpawnerTypeWithEggEvent.patch b/patches/Purpur/patches/api/0012-PlayerSetSpawnerTypeWithEggEvent.patch new file mode 100644 index 00000000..51843969 --- /dev/null +++ b/patches/Purpur/patches/api/0012-PlayerSetSpawnerTypeWithEggEvent.patch @@ -0,0 +1,97 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Fri, 5 Jul 2019 18:21:15 -0500 +Subject: [PATCH] PlayerSetSpawnerTypeWithEggEvent + + +diff --git a/src/main/java/net/pl3x/purpur/event/PlayerSetSpawnerTypeWithEggEvent.java b/src/main/java/net/pl3x/purpur/event/PlayerSetSpawnerTypeWithEggEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..c050b75e9a11ac728868fe95e3f89e6b99de6ad2 +--- /dev/null ++++ b/src/main/java/net/pl3x/purpur/event/PlayerSetSpawnerTypeWithEggEvent.java +@@ -0,0 +1,85 @@ ++package net.pl3x.purpur.event; ++ ++import org.bukkit.block.Block; ++import org.bukkit.block.CreatureSpawner; ++import org.bukkit.entity.EntityType; ++import org.bukkit.entity.Player; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.player.PlayerEvent; ++import org.jetbrains.annotations.NotNull; ++ ++public class PlayerSetSpawnerTypeWithEggEvent extends PlayerEvent implements Cancellable { ++ private static final HandlerList handlers = new HandlerList(); ++ private final Block block; ++ private final CreatureSpawner spawner; ++ private EntityType type; ++ private boolean cancel; ++ ++ public PlayerSetSpawnerTypeWithEggEvent(@NotNull Player player, @NotNull Block block, @NotNull CreatureSpawner spawner, @NotNull EntityType type) { ++ super(player); ++ this.block = block; ++ this.spawner = spawner; ++ this.type = type; ++ } ++ ++ /** ++ * Get the spawner Block in the world ++ * ++ * @return Spawner Block ++ */ ++ @NotNull ++ public Block getBlock() { ++ return block; ++ } ++ ++ /** ++ * Get the spawner state ++ * ++ * @return Spawner state ++ */ ++ @NotNull ++ public CreatureSpawner getSpawner() { ++ return spawner; ++ } ++ ++ /** ++ * Gets the EntityType being set on the spawner ++ * ++ * @return EntityType being set ++ */ ++ @NotNull ++ public EntityType getEntityType() { ++ return type; ++ } ++ ++ /** ++ * Sets the EntityType being set on the spawner ++ * ++ * @param type EntityType to set ++ */ ++ public void setEntityType(@NotNull EntityType type) { ++ this.type = type; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return cancel; ++ } ++ ++ @Override ++ public void setCancelled(boolean cancel) { ++ this.cancel = cancel; ++ } ++ ++ @Override ++ @NotNull ++ public HandlerList getHandlers() { ++ return handlers; ++ } ++ ++ @NotNull ++ public static HandlerList getHandlerList() { ++ return handlers; ++ } ++} diff --git a/patches/Purpur/patches/api/0013-EMC-MonsterEggSpawnEvent.patch b/patches/Purpur/patches/api/0013-EMC-MonsterEggSpawnEvent.patch new file mode 100644 index 00000000..74209f30 --- /dev/null +++ b/patches/Purpur/patches/api/0013-EMC-MonsterEggSpawnEvent.patch @@ -0,0 +1,79 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Mon, 21 Nov 2016 17:02:11 -0500 +Subject: [PATCH] EMC - MonsterEggSpawnEvent + + +diff --git a/src/main/java/net/pl3x/purpur/event/entity/MonsterEggSpawnEvent.java b/src/main/java/net/pl3x/purpur/event/entity/MonsterEggSpawnEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..8f1c9c421aeeb0ddf331f076a9b646c510ea4337 +--- /dev/null ++++ b/src/main/java/net/pl3x/purpur/event/entity/MonsterEggSpawnEvent.java +@@ -0,0 +1,67 @@ ++package net.pl3x.purpur.event.entity; ++ ++import org.bukkit.entity.Entity; ++import org.bukkit.entity.HumanEntity; ++import org.bukkit.entity.Player; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.Event; ++import org.bukkit.event.HandlerList; ++import org.bukkit.inventory.ItemStack; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++public class MonsterEggSpawnEvent extends Event implements Cancellable { ++ private static final HandlerList handlers = new HandlerList(); ++ private boolean canceled; ++ ++ private final Player player; ++ private Entity entity; ++ private final ItemStack item; ++ ++ public MonsterEggSpawnEvent(@Nullable HumanEntity player, @NotNull Entity entity, @NotNull ItemStack item) { ++ this.player = (Player) player; ++ this.entity = entity; ++ this.item = item; ++ } ++ ++ @Nullable ++ public Player getPlayer() { ++ return player; ++ } ++ ++ @NotNull ++ public Entity getEntity() { ++ return entity; ++ } ++ ++ public void setEntity(@Nullable Entity entity) { ++ if (entity == null) { ++ canceled = true; ++ return; ++ } ++ this.entity = entity; ++ } ++ ++ @NotNull ++ public ItemStack getItem() { ++ return item; ++ } ++ ++ public boolean isCancelled() { ++ return canceled; ++ } ++ ++ public void setCancelled(boolean cancel) { ++ canceled = cancel; ++ } ++ ++ @NotNull ++ public HandlerList getHandlers() { ++ return handlers; ++ } ++ ++ @NotNull ++ public static HandlerList getHandlerList() { ++ return handlers; ++ } ++} diff --git a/patches/Purpur/patches/api/0014-Villager-resetOffers.patch b/patches/Purpur/patches/api/0014-Villager-resetOffers.patch new file mode 100644 index 00000000..ae3bbedf --- /dev/null +++ b/patches/Purpur/patches/api/0014-Villager-resetOffers.patch @@ -0,0 +1,24 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Mon, 7 Oct 2019 00:15:28 -0500 +Subject: [PATCH] Villager#resetOffers + + +diff --git a/src/main/java/org/bukkit/entity/Villager.java b/src/main/java/org/bukkit/entity/Villager.java +index c8777a476e38ef5e72b6709761990a339eb43d2b..ed703af452cd7db5e47608b4ff6ec049f76ed03a 100644 +--- a/src/main/java/org/bukkit/entity/Villager.java ++++ b/src/main/java/org/bukkit/entity/Villager.java +@@ -113,6 +113,13 @@ public interface Villager extends AbstractVillager { + */ + public void wakeup(); + ++ // Purpur start ++ /** ++ * Reset this villager's trade offers ++ */ ++ public void resetOffers(); ++ // Purpur end ++ + /** + * Represents Villager type, usually corresponding to what biome they spawn + * in. diff --git a/patches/Purpur/patches/api/0015-Player-invulnerabilities.patch b/patches/Purpur/patches/api/0015-Player-invulnerabilities.patch new file mode 100644 index 00000000..d7c53b52 --- /dev/null +++ b/patches/Purpur/patches/api/0015-Player-invulnerabilities.patch @@ -0,0 +1,37 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sat, 2 May 2020 20:55:31 -0500 +Subject: [PATCH] Player invulnerabilities + + +diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java +index 09729abc27b6cb3458e19af24137bbbc6e5cb63e..d6b6508fd7ab245f657be262c54ae6dfa20415e7 100644 +--- a/src/main/java/org/bukkit/entity/Player.java ++++ b/src/main/java/org/bukkit/entity/Player.java +@@ -2159,5 +2159,26 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * Reset the idle timer back to 0 + */ + void resetIdleTimer(); ++ ++ /** ++ * Check if player is invulnerable from recently spawning or accepting a resource pack ++ * ++ * @return True if invulnerable ++ */ ++ boolean isSpawnInvulnerable(); ++ ++ /** ++ * Get invulnerable ticks remaining ++ * ++ * @return Invulnerable ticks ++ */ ++ int getSpawnInvulnerableTicks(); ++ ++ /** ++ * Set invulnerable ticks remaining ++ * ++ * @param invulnerableTicks Invulnerable ticks remaining ++ */ ++ void setSpawnInvulnerableTicks(int invulnerableTicks); + // Purpur end + } diff --git a/patches/Purpur/patches/api/0016-Anvil-API.patch b/patches/Purpur/patches/api/0016-Anvil-API.patch new file mode 100644 index 00000000..f660b4e7 --- /dev/null +++ b/patches/Purpur/patches/api/0016-Anvil-API.patch @@ -0,0 +1,124 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sun, 19 Apr 2020 00:25:09 -0500 +Subject: [PATCH] Anvil API + + +diff --git a/src/main/java/net/pl3x/purpur/event/inventory/AnvilTakeResultEvent.java b/src/main/java/net/pl3x/purpur/event/inventory/AnvilTakeResultEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..85663c0a44695f7b7f01a68693cac3d99f4b56ca +--- /dev/null ++++ b/src/main/java/net/pl3x/purpur/event/inventory/AnvilTakeResultEvent.java +@@ -0,0 +1,52 @@ ++package net.pl3x.purpur.event.inventory; ++ ++import org.bukkit.entity.HumanEntity; ++import org.bukkit.entity.Player; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.inventory.InventoryEvent; ++import org.bukkit.inventory.AnvilInventory; ++import org.bukkit.inventory.InventoryView; ++import org.bukkit.inventory.ItemStack; ++import org.jetbrains.annotations.NotNull; ++ ++/** ++ * Called when a player takes the result item out of an anvil ++ */ ++public class AnvilTakeResultEvent extends InventoryEvent { ++ private static final HandlerList handlers = new HandlerList(); ++ private final Player player; ++ private final ItemStack result; ++ ++ public AnvilTakeResultEvent(@NotNull HumanEntity player, @NotNull InventoryView view, @NotNull ItemStack result) { ++ super(view); ++ this.player = (Player) player; ++ this.result = result; ++ } ++ ++ @NotNull ++ public Player getPlayer() { ++ return player; ++ } ++ ++ @NotNull ++ public ItemStack getResult() { ++ return result; ++ } ++ ++ @NotNull ++ @Override ++ public AnvilInventory getInventory() { ++ return (AnvilInventory) super.getInventory(); ++ } ++ ++ @NotNull ++ @Override ++ public HandlerList getHandlers() { ++ return handlers; ++ } ++ ++ @NotNull ++ public static HandlerList getHandlerList() { ++ return handlers; ++ } ++} +diff --git a/src/main/java/net/pl3x/purpur/event/inventory/AnvilUpdateResultEvent.java b/src/main/java/net/pl3x/purpur/event/inventory/AnvilUpdateResultEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..2717ad82ccc0d39c5a69b8890303c245e9a17f83 +--- /dev/null ++++ b/src/main/java/net/pl3x/purpur/event/inventory/AnvilUpdateResultEvent.java +@@ -0,0 +1,35 @@ ++package net.pl3x.purpur.event.inventory; ++ ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.inventory.InventoryEvent; ++import org.bukkit.inventory.AnvilInventory; ++import org.bukkit.inventory.InventoryView; ++import org.jetbrains.annotations.NotNull; ++ ++/** ++ * Called when anvil slots change, triggering the result slot to be updated ++ */ ++public class AnvilUpdateResultEvent extends InventoryEvent { ++ private static final HandlerList handlers = new HandlerList(); ++ ++ public AnvilUpdateResultEvent(@NotNull InventoryView view) { ++ super(view); ++ } ++ ++ @NotNull ++ @Override ++ public AnvilInventory getInventory() { ++ return (AnvilInventory) super.getInventory(); ++ } ++ ++ @NotNull ++ @Override ++ public HandlerList getHandlers() { ++ return handlers; ++ } ++ ++ @NotNull ++ public static HandlerList getHandlerList() { ++ return handlers; ++ } ++} +diff --git a/src/main/java/org/bukkit/inventory/AnvilInventory.java b/src/main/java/org/bukkit/inventory/AnvilInventory.java +index b95e563b5454306a9188ae3295309ee86a756477..435026e533ea9edb8c1800d35c63543ca023a904 100644 +--- a/src/main/java/org/bukkit/inventory/AnvilInventory.java ++++ b/src/main/java/org/bukkit/inventory/AnvilInventory.java +@@ -109,4 +109,14 @@ public interface AnvilInventory extends Inventory { + setItem(2, result); + } + // Paper end ++ ++ // Purpur start ++ boolean canBypassCost(); ++ ++ void setBypassCost(boolean bypassCost); ++ ++ boolean canDoUnsafeEnchants(); ++ ++ void setDoUnsafeEnchants(boolean canDoUnsafeEnchants); ++ // Purpur end + } diff --git a/patches/Purpur/patches/api/0017-ItemStack-convenience-methods.patch b/patches/Purpur/patches/api/0017-ItemStack-convenience-methods.patch new file mode 100644 index 00000000..f7418988 --- /dev/null +++ b/patches/Purpur/patches/api/0017-ItemStack-convenience-methods.patch @@ -0,0 +1,701 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sun, 15 Mar 2020 20:52:12 -0500 +Subject: [PATCH] ItemStack convenience methods + + +diff --git a/src/main/java/org/bukkit/Material.java b/src/main/java/org/bukkit/Material.java +index e2b3470e3c9a97671723f5a67f722fb86fb07fbf..560b441ef35e507236e683b04f6a774c5949a078 100644 +--- a/src/main/java/org/bukkit/Material.java ++++ b/src/main/java/org/bukkit/Material.java +@@ -8731,4 +8731,40 @@ public enum Material implements Keyed { + // + } + } ++ ++ // Purpur start ++ public boolean isArmor() { ++ switch (this) { ++ // ++ case LEATHER_BOOTS: ++ case LEATHER_CHESTPLATE: ++ case LEATHER_HELMET: ++ case LEATHER_LEGGINGS: ++ case CHAINMAIL_BOOTS: ++ case CHAINMAIL_CHESTPLATE: ++ case CHAINMAIL_HELMET: ++ case CHAINMAIL_LEGGINGS: ++ case IRON_BOOTS: ++ case IRON_CHESTPLATE: ++ case IRON_HELMET: ++ case IRON_LEGGINGS: ++ case GOLDEN_BOOTS: ++ case GOLDEN_CHESTPLATE: ++ case GOLDEN_HELMET: ++ case GOLDEN_LEGGINGS: ++ case DIAMOND_BOOTS: ++ case DIAMOND_CHESTPLATE: ++ case DIAMOND_HELMET: ++ case DIAMOND_LEGGINGS: ++ case NETHERITE_BOOTS: ++ case NETHERITE_CHESTPLATE: ++ case NETHERITE_HELMET: ++ case NETHERITE_LEGGINGS: ++ case TURTLE_HELMET: ++ return true; ++ default: ++ return false; ++ } ++ } ++ // Purpur end + } +diff --git a/src/main/java/org/bukkit/inventory/ItemStack.java b/src/main/java/org/bukkit/inventory/ItemStack.java +index a7909406e9d54c1ab4789b984ed6b1da50837fce..ac2967eac165d74c8ee7e0e9ac63124a10851a0e 100644 +--- a/src/main/java/org/bukkit/inventory/ItemStack.java ++++ b/src/main/java/org/bukkit/inventory/ItemStack.java +@@ -17,6 +17,18 @@ import org.bukkit.inventory.meta.ItemMeta; + import org.bukkit.material.MaterialData; + import org.jetbrains.annotations.NotNull; + import org.jetbrains.annotations.Nullable; ++// Purpur start ++import com.google.common.collect.Multimap; ++import java.util.Collection; ++import org.bukkit.attribute.Attribute; ++import org.bukkit.attribute.AttributeModifier; ++import org.bukkit.block.data.BlockData; ++import org.bukkit.inventory.meta.BlockDataMeta; ++import org.bukkit.inventory.meta.Repairable; ++import org.bukkit.persistence.PersistentDataContainer; ++import org.bukkit.persistence.PersistentDataHolder; ++import com.destroystokyo.paper.Namespaced; ++// Purpur end + + /** + * Represents a stack of items. +@@ -921,4 +933,626 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, net.kyor + return Bukkit.getUnsafe().isValidRepairItemStack(toBeRepaired, this); + } + // Paper end ++ ++ // Purpur start ++ /** ++ * Gets the display name that is set. ++ *

++ * Plugins should check that hasDisplayName() returns true ++ * before calling this method. ++ * ++ * @return the display name that is set ++ */ ++ @NotNull ++ public String getDisplayName() { ++ return getItemMeta().getDisplayName(); ++ } ++ ++ /** ++ * Sets the display name. ++ * ++ * @param name the name to set ++ */ ++ public void setDisplayName(@Nullable String name) { ++ ItemMeta itemMeta = getItemMeta(); ++ itemMeta.setDisplayName(name); ++ setItemMeta(itemMeta); ++ } ++ ++ /** ++ * Checks for existence of a display name. ++ * ++ * @return true if this has a display name ++ */ ++ public boolean hasDisplayName() { ++ return hasItemMeta() && getItemMeta().hasDisplayName(); ++ } ++ ++ /** ++ * Gets the localized display name that is set. ++ *

++ * Plugins should check that hasLocalizedName() returns true ++ * before calling this method. ++ * ++ * @return the localized name that is set ++ */ ++ @NotNull ++ public String getLocalizedName() { ++ return getItemMeta().getLocalizedName(); ++ } ++ ++ /** ++ * Sets the localized name. ++ * ++ * @param name the name to set ++ */ ++ public void setLocalizedName(@Nullable String name) { ++ ItemMeta itemMeta = getItemMeta(); ++ itemMeta.setLocalizedName(name); ++ setItemMeta(itemMeta); ++ } ++ ++ /** ++ * Checks for existence of a localized name. ++ * ++ * @return true if this has a localized name ++ */ ++ public boolean hasLocalizedName() { ++ return hasItemMeta() && getItemMeta().hasLocalizedName(); ++ } ++ ++ /** ++ * Checks for existence of lore. ++ * ++ * @return true if this has lore ++ */ ++ public boolean hasLore() { ++ return hasItemMeta() && getItemMeta().hasLore(); ++ } ++ ++ /** ++ * Checks for existence of the specified enchantment. ++ * ++ * @param ench enchantment to check ++ * @return true if this enchantment exists for this meta ++ */ ++ public boolean hasEnchant(@NotNull Enchantment ench) { ++ return hasItemMeta() && getItemMeta().hasEnchant(ench); ++ } ++ ++ /** ++ * Checks for the level of the specified enchantment. ++ * ++ * @param ench enchantment to check ++ * @return The level that the specified enchantment has, or 0 if none ++ */ ++ public int getEnchantLevel(@NotNull Enchantment ench) { ++ return getItemMeta().getEnchantLevel(ench); ++ } ++ ++ /** ++ * Returns a copy the enchantments in this ItemMeta.
++ * Returns an empty map if none. ++ * ++ * @return An immutable copy of the enchantments ++ */ ++ @NotNull ++ public Map getEnchants() { ++ return getItemMeta().getEnchants(); ++ } ++ ++ /** ++ * Adds the specified enchantment to this item meta. ++ * ++ * @param ench Enchantment to add ++ * @param level Level for the enchantment ++ * @param ignoreLevelRestriction this indicates the enchantment should be ++ * applied, ignoring the level limit ++ * @return true if the item meta changed as a result of this call, false ++ * otherwise ++ */ ++ public boolean addEnchant(@NotNull Enchantment ench, int level, boolean ignoreLevelRestriction) { ++ ItemMeta itemMeta = getItemMeta(); ++ boolean result = itemMeta.addEnchant(ench, level, ignoreLevelRestriction); ++ setItemMeta(itemMeta); ++ return result; ++ } ++ ++ /** ++ * Removes the specified enchantment from this item meta. ++ * ++ * @param ench Enchantment to remove ++ * @return true if the item meta changed as a result of this call, false ++ * otherwise ++ */ ++ public boolean removeEnchant(@NotNull Enchantment ench) { ++ ItemMeta itemMeta = getItemMeta(); ++ boolean result = itemMeta.removeEnchant(ench); ++ setItemMeta(itemMeta); ++ return result; ++ } ++ ++ /** ++ * Checks for the existence of any enchantments. ++ * ++ * @return true if an enchantment exists on this meta ++ */ ++ public boolean hasEnchants() { ++ return hasItemMeta() && getItemMeta().hasEnchants(); ++ } ++ ++ /** ++ * Checks if the specified enchantment conflicts with any enchantments in ++ * this ItemMeta. ++ * ++ * @param ench enchantment to test ++ * @return true if the enchantment conflicts, false otherwise ++ */ ++ public boolean hasConflictingEnchant(@NotNull Enchantment ench) { ++ return hasItemMeta() && getItemMeta().hasConflictingEnchant(ench); ++ } ++ ++ /** ++ * Sets the custom model data. ++ *

++ * CustomModelData is an integer that may be associated client side with a ++ * custom item model. ++ * ++ * @param data the data to set, or null to clear ++ */ ++ public void setCustomModelData(@Nullable Integer data) { ++ ItemMeta itemMeta = getItemMeta(); ++ itemMeta.setCustomModelData(data); ++ setItemMeta(itemMeta); ++ } ++ ++ /** ++ * Gets the custom model data that is set. ++ *

++ * CustomModelData is an integer that may be associated client side with a ++ * custom item model. ++ *

++ * Plugins should check that hasCustomModelData() returns true ++ * before calling this method. ++ * ++ * @return the localized name that is set ++ */ ++ public int getCustomModelData() { ++ return getItemMeta().getCustomModelData(); ++ } ++ ++ /** ++ * Checks for existence of custom model data. ++ *

++ * CustomModelData is an integer that may be associated client side with a ++ * custom item model. ++ * ++ * @return true if this has custom model data ++ */ ++ public boolean hasCustomModelData() { ++ return hasItemMeta() && getItemMeta().hasCustomModelData(); ++ } ++ ++ /** ++ * Returns whether the item has block data currently attached to it. ++ * ++ * @return whether block data is already attached ++ */ ++ public boolean hasBlockData() { ++ return hasItemMeta() && ((BlockDataMeta) getItemMeta()).hasBlockData(); ++ } ++ ++ /** ++ * Returns the currently attached block data for this item or creates a new ++ * one if one doesn't exist. ++ * ++ * The state is a copy, it must be set back (or to another item) with ++ * {@link #setBlockData(BlockData)} ++ * ++ * @param material the material we wish to get this data in the context of ++ * @return the attached data or new data ++ */ ++ @NotNull ++ public BlockData getBlockData(@NotNull Material material) { ++ return ((BlockDataMeta) getItemMeta()).getBlockData(material); ++ } ++ ++ /** ++ * Attaches a copy of the passed block data to the item. ++ * ++ * @param blockData the block data to attach to the block. ++ * @throws IllegalArgumentException if the blockData is null or invalid for ++ * this item. ++ */ ++ public void setBlockData(@NotNull BlockData blockData) { ++ ItemMeta itemMeta = getItemMeta(); ++ ((BlockDataMeta) itemMeta).setBlockData(blockData); ++ setItemMeta(itemMeta); ++ } ++ ++ /** ++ * Gets the repair penalty ++ * ++ * @return the repair penalty ++ */ ++ public int getRepairCost() { ++ return ((Repairable) getItemMeta()).getRepairCost(); ++ } ++ ++ /** ++ * Sets the repair penalty ++ * ++ * @param cost repair penalty ++ */ ++ public void setRepairCost(int cost) { ++ ItemMeta itemMeta = getItemMeta(); ++ ((Repairable) itemMeta).setRepairCost(cost); ++ setItemMeta(itemMeta); ++ } ++ ++ /** ++ * Checks to see if this has a repair penalty ++ * ++ * @return true if this has a repair penalty ++ */ ++ public boolean hasRepairCost() { ++ return hasItemMeta() && ((Repairable) getItemMeta()).hasRepairCost(); ++ } ++ ++ /** ++ * Return if the unbreakable tag is true. An unbreakable item will not lose ++ * durability. ++ * ++ * @return true if the unbreakable tag is true ++ */ ++ public boolean isUnbreakable() { ++ return hasItemMeta() && getItemMeta().isUnbreakable(); ++ } ++ ++ /** ++ * Sets the unbreakable tag. An unbreakable item will not lose durability. ++ * ++ * @param unbreakable true if set unbreakable ++ */ ++ public void setUnbreakable(boolean unbreakable) { ++ ItemMeta itemMeta = getItemMeta(); ++ itemMeta.setUnbreakable(unbreakable); ++ setItemMeta(itemMeta); ++ } ++ ++ /** ++ * Checks for the existence of any AttributeModifiers. ++ * ++ * @return true if any AttributeModifiers exist ++ */ ++ public boolean hasAttributeModifiers() { ++ return hasItemMeta() && getItemMeta().hasAttributeModifiers(); ++ } ++ ++ /** ++ * Return an immutable copy of all Attributes and ++ * their modifiers in this ItemMeta.
++ * Returns null if none exist. ++ * ++ * @return an immutable {@link Multimap} of Attributes ++ * and their AttributeModifiers, or null if none exist ++ */ ++ @Nullable ++ public Multimap getAttributeModifiers() { ++ return getItemMeta().getAttributeModifiers(); ++ } ++ ++ /** ++ * Return an immutable copy of all {@link Attribute}s and their ++ * {@link AttributeModifier}s for a given {@link EquipmentSlot}.
++ * Any {@link AttributeModifier} that does have have a given ++ * {@link EquipmentSlot} will be returned. This is because ++ * AttributeModifiers without a slot are active in any slot.
++ * If there are no attributes set for the given slot, an empty map ++ * will be returned. ++ * ++ * @param slot the {@link EquipmentSlot} to check ++ * @return the immutable {@link Multimap} with the ++ * respective Attributes and modifiers, or an empty map ++ * if no attributes are set. ++ */ ++ @NotNull ++ public Multimap getAttributeModifiers(@Nullable EquipmentSlot slot) { ++ return getItemMeta().getAttributeModifiers(slot); ++ } ++ ++ /** ++ * Return an immutable copy of all {@link AttributeModifier}s ++ * for a given {@link Attribute} ++ * ++ * @param attribute the {@link Attribute} ++ * @return an immutable collection of {@link AttributeModifier}s ++ * or null if no AttributeModifiers exist for the Attribute. ++ * @throws NullPointerException if Attribute is null ++ */ ++ @Nullable ++ public Collection getAttributeModifiers(@NotNull Attribute attribute) { ++ return getItemMeta().getAttributeModifiers(attribute); ++ } ++ ++ /** ++ * Add an Attribute and it's Modifier. ++ * AttributeModifiers can now support {@link EquipmentSlot}s. ++ * If not set, the {@link AttributeModifier} will be active in ALL slots. ++ *
++ * Two {@link AttributeModifier}s that have the same {@link java.util.UUID} ++ * cannot exist on the same Attribute. ++ * ++ * @param attribute the {@link Attribute} to modify ++ * @param modifier the {@link AttributeModifier} specifying the modification ++ * @return true if the Attribute and AttributeModifier were ++ * successfully added ++ * @throws NullPointerException if Attribute is null ++ * @throws NullPointerException if AttributeModifier is null ++ * @throws IllegalArgumentException if AttributeModifier already exists ++ */ ++ public boolean addAttributeModifier(@NotNull Attribute attribute, @NotNull AttributeModifier modifier) { ++ ItemMeta itemMeta = getItemMeta(); ++ boolean result = itemMeta.addAttributeModifier(attribute, modifier); ++ setItemMeta(itemMeta); ++ return result; ++ } ++ ++ /** ++ * Set all {@link Attribute}s and their {@link AttributeModifier}s. ++ * To clear all currently set Attributes and AttributeModifiers use ++ * null or an empty Multimap. ++ * If not null nor empty, this will filter all entries that are not-null ++ * and add them to the ItemStack. ++ * ++ * @param attributeModifiers the new Multimap containing the Attributes ++ * and their AttributeModifiers ++ */ ++ public void setAttributeModifiers(@Nullable Multimap attributeModifiers) { ++ ItemMeta itemMeta = getItemMeta(); ++ itemMeta.setAttributeModifiers(attributeModifiers); ++ setItemMeta(itemMeta); ++ } ++ ++ /** ++ * Remove all {@link AttributeModifier}s associated with the given ++ * {@link Attribute}. ++ * This will return false if nothing was removed. ++ * ++ * @param attribute attribute to remove ++ * @return true if all modifiers were removed from a given ++ * Attribute. Returns false if no attributes were ++ * removed. ++ * @throws NullPointerException if Attribute is null ++ */ ++ public boolean removeAttributeModifier(@NotNull Attribute attribute) { ++ ItemMeta itemMeta = getItemMeta(); ++ boolean result = itemMeta.removeAttributeModifier(attribute); ++ setItemMeta(itemMeta); ++ return result; ++ } ++ ++ /** ++ * Remove all {@link Attribute}s and {@link AttributeModifier}s for a ++ * given {@link EquipmentSlot}.
++ * If the given {@link EquipmentSlot} is null, this will remove all ++ * {@link AttributeModifier}s that do not have an EquipmentSlot set. ++ * ++ * @param slot the {@link EquipmentSlot} to clear all Attributes and ++ * their modifiers for ++ * @return true if all modifiers were removed that match the given ++ * EquipmentSlot. ++ */ ++ public boolean removeAttributeModifier(@Nullable EquipmentSlot slot) { ++ ItemMeta itemMeta = getItemMeta(); ++ boolean result = itemMeta.removeAttributeModifier(slot); ++ setItemMeta(itemMeta); ++ return result; ++ } ++ ++ /** ++ * Remove a specific {@link Attribute} and {@link AttributeModifier}. ++ * AttributeModifiers are matched according to their {@link java.util.UUID}. ++ * ++ * @param attribute the {@link Attribute} to remove ++ * @param modifier the {@link AttributeModifier} to remove ++ * @return if any attribute modifiers were remove ++ * ++ * @throws NullPointerException if the Attribute is null ++ * @throws NullPointerException if the AttributeModifier is null ++ * ++ * @see AttributeModifier#getUniqueId() ++ */ ++ public boolean removeAttributeModifier(@NotNull Attribute attribute, @NotNull AttributeModifier modifier) { ++ ItemMeta itemMeta = getItemMeta(); ++ boolean result = itemMeta.removeAttributeModifier(attribute, modifier); ++ setItemMeta(itemMeta); ++ return result; ++ } ++ ++ /** ++ * Returns a custom tag container capable of storing tags on the object. ++ * ++ * Note that the tags stored on this container are all stored under their ++ * own custom namespace therefore modifying default tags using this ++ * {@link PersistentDataHolder} is impossible. ++ * ++ * @return the persistent metadata container ++ */ ++ @NotNull ++ public PersistentDataContainer getPersistentDataContainer() { ++ return getItemMeta().getPersistentDataContainer(); ++ } ++ ++ /** ++ * Checks to see if this item has damage ++ * ++ * @return true if this has damage ++ */ ++ public boolean hasDamage() { ++ return hasItemMeta() && ((Damageable) getItemMeta()).hasDamage(); ++ } ++ ++ /** ++ * Gets the damage ++ * ++ * @return the damage ++ */ ++ public int getDamage() { ++ return ((Damageable) getItemMeta()).getDamage(); ++ } ++ ++ /** ++ * Sets the damage ++ * ++ * @param damage item damage ++ */ ++ public void setDamage(int damage) { ++ ItemMeta itemMeta = getItemMeta(); ++ ((Damageable) itemMeta).setDamage(damage); ++ setItemMeta(itemMeta); ++ } ++ ++ /** ++ * Gets the collection of namespaced keys that the item can destroy in {@link org.bukkit.GameMode#ADVENTURE} ++ * ++ * @return Set of {@link com.destroystokyo.paper.Namespaced} ++ */ ++ @NotNull ++ public Set getDestroyableKeys() { ++ return getItemMeta().getDestroyableKeys(); ++ } ++ ++ /** ++ * Sets the collection of namespaced keys that the item can destroy in {@link org.bukkit.GameMode#ADVENTURE} ++ * ++ * @param canDestroy Collection of {@link com.destroystokyo.paper.Namespaced} ++ */ ++ public void setDestroyableKeys(@NotNull Collection canDestroy) { ++ ItemMeta itemMeta = getItemMeta(); ++ itemMeta.setDestroyableKeys(canDestroy); ++ setItemMeta(itemMeta); ++ } ++ ++ /** ++ * Gets the collection of namespaced keys that the item can be placed on in {@link org.bukkit.GameMode#ADVENTURE} ++ * ++ * @return Set of {@link com.destroystokyo.paper.Namespaced} ++ */ ++ @NotNull ++ public Set getPlaceableKeys() { ++ return getItemMeta().getPlaceableKeys(); ++ } ++ ++ /** ++ * Sets the set of namespaced keys that the item can be placed on in {@link org.bukkit.GameMode#ADVENTURE} ++ * ++ * @param canPlaceOn Collection of {@link com.destroystokyo.paper.Namespaced} ++ */ ++ @NotNull ++ public void setPlaceableKeys(@NotNull Collection canPlaceOn) { ++ ItemMeta itemMeta = getItemMeta(); ++ itemMeta.setPlaceableKeys(canPlaceOn); ++ setItemMeta(itemMeta); ++ } ++ ++ /** ++ * Checks for the existence of any keys that the item can be placed on ++ * ++ * @return true if this item has placeable keys ++ */ ++ public boolean hasPlaceableKeys() { ++ return hasItemMeta() && getItemMeta().hasPlaceableKeys(); ++ } ++ ++ /** ++ * Checks for the existence of any keys that the item can destroy ++ * ++ * @return true if this item has destroyable keys ++ */ ++ public boolean hasDestroyableKeys() { ++ return hasItemMeta() && getItemMeta().hasDestroyableKeys(); ++ } ++ ++ /** ++ * Repairs this item by 1 durability ++ */ ++ public void repair() { ++ repair(1); ++ } ++ ++ /** ++ * Damages this item by 1 durability ++ * ++ * @return True if damage broke the item ++ */ ++ public boolean damage() { ++ return damage(1); ++ } ++ ++ /** ++ * Repairs this item's durability by amount ++ * ++ * @param amount Amount of durability to repair ++ */ ++ public void repair(int amount) { ++ damage(-amount); ++ } ++ ++ /** ++ * Damages this item's durability by amount ++ * ++ * @param amount Amount of durability to damage ++ * @return True if damage broke the item ++ */ ++ public boolean damage(int amount) { ++ return damage(amount, false); ++ } ++ ++ /** ++ * Damages this item's durability by amount ++ * ++ * @param amount Amount of durability to damage ++ * @param ignoreUnbreaking Ignores unbreaking enchantment ++ * @return True if damage broke the item ++ */ ++ public boolean damage(int amount, boolean ignoreUnbreaking) { ++ Damageable damageable = (Damageable) getItemMeta(); ++ if (amount > 0) { ++ int unbreaking = getEnchantLevel(Enchantment.DURABILITY); ++ int reduce = 0; ++ for (int i = 0; unbreaking > 0 && i < amount; ++i) { ++ if (reduceDamage(java.util.concurrent.ThreadLocalRandom.current(), unbreaking)) { ++ ++reduce; ++ } ++ } ++ amount -= reduce; ++ if (amount <= 0) { ++ return isBroke(damageable.getDamage()); ++ } ++ } ++ int damage = damageable.getDamage() + amount; ++ damageable.setDamage(damage); ++ setItemMeta((ItemMeta) damageable); ++ return isBroke(damage); ++ } ++ ++ public boolean isBroke(int damage) { ++ if (damage > getType().getMaxDurability()) { ++ if (getAmount() > 0) { ++ // ensure it "breaks" ++ setAmount(0); ++ } ++ return true; ++ } ++ return false; ++ } ++ ++ private boolean reduceDamage(java.util.Random random, int unbreaking) { ++ if (getType().isArmor()) { ++ return random.nextFloat() < 0.6F; ++ } ++ return random.nextInt(unbreaking + 1) > 0; ++ } ++ // Purpur end + } diff --git a/patches/Purpur/patches/api/0018-Phantoms-attracted-to-crystals-and-crystals-shoot-ph.patch b/patches/Purpur/patches/api/0018-Phantoms-attracted-to-crystals-and-crystals-shoot-ph.patch new file mode 100644 index 00000000..bdaed9c0 --- /dev/null +++ b/patches/Purpur/patches/api/0018-Phantoms-attracted-to-crystals-and-crystals-shoot-ph.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sun, 28 Jun 2020 21:50:55 -0500 +Subject: [PATCH] Phantoms attracted to crystals and crystals shoot phantoms + + +diff --git a/src/main/java/com/destroystokyo/paper/entity/ai/VanillaGoal.java b/src/main/java/com/destroystokyo/paper/entity/ai/VanillaGoal.java +index b42091752981a1f309ab350e9a394092cb334824..83c51bb5e09549a8205d27a53ff0102f9439d60a 100644 +--- a/src/main/java/com/destroystokyo/paper/entity/ai/VanillaGoal.java ++++ b/src/main/java/com/destroystokyo/paper/entity/ai/VanillaGoal.java +@@ -206,4 +206,8 @@ public interface VanillaGoal extends Goal { + GoalKey ZOMBIE_ATTACK = GoalKey.of(Zombie.class, NamespacedKey.minecraft("zombie_attack")); + GoalKey STROLL_VILLAGE_GOLEM = GoalKey.of(Creature.class, NamespacedKey.minecraft("stroll_village_golem")); + GoalKey UNIVERSAL_ANGER_RESET = GoalKey.of(Mob.class, NamespacedKey.minecraft("universal_anger_reset")); ++ // Purpur start ++ GoalKey FIND_CRYSTAL_GOAL = GoalKey.of(Phantom.class, NamespacedKey.minecraft("find_crystal_goal")); ++ GoalKey ORBIT_CRYSTAL_GOAL = GoalKey.of(Phantom.class, NamespacedKey.minecraft("orbit_crystal_goal")); ++ // Purpur end + } diff --git a/patches/Purpur/patches/api/0019-ChatColor-conveniences.patch b/patches/Purpur/patches/api/0019-ChatColor-conveniences.patch new file mode 100644 index 00000000..9c0f19ba --- /dev/null +++ b/patches/Purpur/patches/api/0019-ChatColor-conveniences.patch @@ -0,0 +1,41 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Fri, 10 Jul 2020 12:43:25 -0500 +Subject: [PATCH] ChatColor conveniences + + +diff --git a/src/main/java/org/bukkit/ChatColor.java b/src/main/java/org/bukkit/ChatColor.java +index 4594701d77c5d0f744bece871b98d9f6f73eb5a7..499b222dee1f11d497a29a9a263a5596401ca1eb 100644 +--- a/src/main/java/org/bukkit/ChatColor.java ++++ b/src/main/java/org/bukkit/ChatColor.java +@@ -413,4 +413,30 @@ public enum ChatColor { + BY_CHAR.put(color.code, color); + } + } ++ ++ // Purpur start ++ public static final Pattern HEX_PATTERN = Pattern.compile("(#[A-Fa-f0-9]{6})"); ++ ++ @Nullable ++ public static String replaceHex(@Nullable String str) { ++ if (str != null) { ++ java.util.regex.Matcher matcher = HEX_PATTERN.matcher(str); ++ while (matcher.find()) { ++ String group = matcher.group(1); ++ str = str.replace(group, net.md_5.bungee.api.ChatColor.of(group).toString()); ++ } ++ } ++ return str; ++ } ++ ++ @Nullable ++ public static String color(@Nullable String str) { ++ return color(str, true); ++ } ++ ++ @Nullable ++ public static String color(@Nullable String str, boolean parseHex) { ++ return str != null ? net.md_5.bungee.api.ChatColor.translateAlternateColorCodes('&', parseHex ? replaceHex(str) : str) : str; ++ } ++ // Purpur end + } diff --git a/patches/Purpur/patches/api/0020-Ridables.patch b/patches/Purpur/patches/api/0020-Ridables.patch new file mode 100644 index 00000000..0031ab00 --- /dev/null +++ b/patches/Purpur/patches/api/0020-Ridables.patch @@ -0,0 +1,210 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sat, 4 May 2019 00:57:16 -0500 +Subject: [PATCH] Ridables + + +diff --git a/src/main/java/com/destroystokyo/paper/entity/ai/VanillaGoal.java b/src/main/java/com/destroystokyo/paper/entity/ai/VanillaGoal.java +index 83c51bb5e09549a8205d27a53ff0102f9439d60a..177143c9764e82981423879ed35625edd25d3ebf 100644 +--- a/src/main/java/com/destroystokyo/paper/entity/ai/VanillaGoal.java ++++ b/src/main/java/com/destroystokyo/paper/entity/ai/VanillaGoal.java +@@ -209,5 +209,7 @@ public interface VanillaGoal extends Goal { + // Purpur start + GoalKey FIND_CRYSTAL_GOAL = GoalKey.of(Phantom.class, NamespacedKey.minecraft("find_crystal_goal")); + GoalKey ORBIT_CRYSTAL_GOAL = GoalKey.of(Phantom.class, NamespacedKey.minecraft("orbit_crystal_goal")); ++ GoalKey HAS_RIDER = GoalKey.of(Mob.class, NamespacedKey.minecraft("has_rider")); ++ GoalKey HORSE_HAS_RIDER = GoalKey.of(AbstractHorse.class, NamespacedKey.minecraft("horse_has_rider")); + // Purpur end + } +diff --git a/src/main/java/net/pl3x/purpur/event/entity/RidableMoveEvent.java b/src/main/java/net/pl3x/purpur/event/entity/RidableMoveEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..48e7ac392fe5efac8a4ce549e31a05ed817417e4 +--- /dev/null ++++ b/src/main/java/net/pl3x/purpur/event/entity/RidableMoveEvent.java +@@ -0,0 +1,103 @@ ++package net.pl3x.purpur.event.entity; ++ ++import com.google.common.base.Preconditions; ++import org.bukkit.Location; ++import org.bukkit.entity.Mob; ++import org.bukkit.entity.Player; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.entity.EntityEvent; ++import org.jetbrains.annotations.NotNull; ++ ++/** ++ * Triggered when a ridable mob moves with a rider ++ */ ++public class RidableMoveEvent extends EntityEvent implements Cancellable { ++ private static final HandlerList handlers = new HandlerList(); ++ private boolean canceled; ++ private final Player rider; ++ private Location from; ++ private Location to; ++ ++ public RidableMoveEvent(@NotNull Mob entity, @NotNull Player rider, @NotNull Location from, @NotNull Location to) { ++ super(entity); ++ this.rider = rider; ++ this.from = from; ++ this.to = to; ++ } ++ ++ @Override ++ @NotNull ++ public Mob getEntity() { ++ return (Mob) entity; ++ } ++ ++ @NotNull ++ public Player getRider() { ++ return rider; ++ } ++ ++ public boolean isCancelled() { ++ return canceled; ++ } ++ ++ public void setCancelled(boolean cancel) { ++ canceled = cancel; ++ } ++ ++ /** ++ * Gets the location this entity moved from ++ * ++ * @return Location the entity moved from ++ */ ++ @NotNull ++ public Location getFrom() { ++ return from; ++ } ++ ++ /** ++ * Sets the location to mark as where the entity moved from ++ * ++ * @param from New location to mark as the entity's previous location ++ */ ++ public void setFrom(@NotNull Location from) { ++ validateLocation(from); ++ this.from = from; ++ } ++ ++ /** ++ * Gets the location this entity moved to ++ * ++ * @return Location the entity moved to ++ */ ++ @NotNull ++ public Location getTo() { ++ return to; ++ } ++ ++ /** ++ * Sets the location that this entity will move to ++ * ++ * @param to New Location this entity will move to ++ */ ++ public void setTo(@NotNull Location to) { ++ validateLocation(to); ++ this.to = to; ++ } ++ ++ private void validateLocation(@NotNull Location loc) { ++ Preconditions.checkArgument(loc != null, "Cannot use null location!"); ++ Preconditions.checkArgument(loc.getWorld() != null, "Cannot use null location with null world!"); ++ } ++ ++ @Override ++ @NotNull ++ public HandlerList getHandlers() { ++ return handlers; ++ } ++ ++ @NotNull ++ public static HandlerList getHandlerList() { ++ return handlers; ++ } ++} +diff --git a/src/main/java/net/pl3x/purpur/event/entity/RidableSpacebarEvent.java b/src/main/java/net/pl3x/purpur/event/entity/RidableSpacebarEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..c0ec5a130985e8da4cc9e596a6b70503d2550f77 +--- /dev/null ++++ b/src/main/java/net/pl3x/purpur/event/entity/RidableSpacebarEvent.java +@@ -0,0 +1,37 @@ ++package net.pl3x.purpur.event.entity; ++ ++import org.bukkit.entity.Entity; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.entity.EntityEvent; ++import org.jetbrains.annotations.NotNull; ++ ++public class RidableSpacebarEvent extends EntityEvent implements Cancellable { ++ private static final HandlerList handlers = new HandlerList(); ++ private boolean cancelled; ++ ++ public RidableSpacebarEvent(@NotNull Entity entity) { ++ super(entity); ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return cancelled; ++ } ++ ++ @Override ++ public void setCancelled(boolean cancel) { ++ cancelled = cancel; ++ } ++ ++ @Override ++ @NotNull ++ public HandlerList getHandlers() { ++ return handlers; ++ } ++ ++ @NotNull ++ public static HandlerList getHandlerList() { ++ return handlers; ++ } ++} +diff --git a/src/main/java/org/bukkit/entity/Entity.java b/src/main/java/org/bukkit/entity/Entity.java +index 46985eaea3d3b00d1dd88c2dd5a2bc53d518c64f..38c6ecba4a6090ee42180ff52db42bac8e7f95d7 100644 +--- a/src/main/java/org/bukkit/entity/Entity.java ++++ b/src/main/java/org/bukkit/entity/Entity.java +@@ -704,4 +704,35 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent + */ + public boolean isTicking(); + // Paper end ++ ++ // Purpur start ++ /** ++ * Get the riding player ++ * ++ * @return Riding player ++ */ ++ @Nullable ++ Player getRider(); ++ ++ /** ++ * Check if entity is being ridden ++ * ++ * @return True if being ridden ++ */ ++ boolean hasRider(); ++ ++ /** ++ * Check if entity is ridable ++ * ++ * @return True if ridable ++ */ ++ boolean isRidable(); ++ ++ /** ++ * Check if entity is ridable in water ++ * ++ * @return True if ridable in water ++ */ ++ boolean isRidableInWater(); ++ // Purpur end + } diff --git a/patches/Purpur/patches/api/0021-Configurable-permission-message-upgrades.patch b/patches/Purpur/patches/api/0021-Configurable-permission-message-upgrades.patch new file mode 100644 index 00000000..bda8c7b7 --- /dev/null +++ b/patches/Purpur/patches/api/0021-Configurable-permission-message-upgrades.patch @@ -0,0 +1,27 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sat, 15 Aug 2020 11:18:27 -0500 +Subject: [PATCH] Configurable permission message upgrades + +This allows the configurable permission message in paper.yml to be blank and also support newlines + +diff --git a/src/main/java/org/bukkit/command/Command.java b/src/main/java/org/bukkit/command/Command.java +index c10fc8d2386301bc2caddcdb1cd18566bcaa8689..882c565ac2be3df976e7bbeb4dc80c9ac474a8b1 100644 +--- a/src/main/java/org/bukkit/command/Command.java ++++ b/src/main/java/org/bukkit/command/Command.java +@@ -184,9 +184,13 @@ public abstract class Command { + return true; + } + ++ // Purpur start ++ String permissionMessage = this.permissionMessage; + if (permissionMessage == null) { +- target.sendMessage(Bukkit.getPermissionMessage()); // Paper +- } else if (permissionMessage.length() != 0) { ++ permissionMessage = Bukkit.getPermissionMessage(); ++ } ++ if (permissionMessage.length() != 0) { ++ // Purpur end + for (String line : permissionMessage.replace("", permission).split("\n")) { + target.sendMessage(line); + } diff --git a/patches/Purpur/patches/api/0022-LivingEntity-broadcastItemBreak.patch b/patches/Purpur/patches/api/0022-LivingEntity-broadcastItemBreak.patch new file mode 100644 index 00000000..ff7ac930 --- /dev/null +++ b/patches/Purpur/patches/api/0022-LivingEntity-broadcastItemBreak.patch @@ -0,0 +1,23 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Mon, 17 Aug 2020 21:50:32 -0500 +Subject: [PATCH] LivingEntity#broadcastItemBreak + + +diff --git a/src/main/java/org/bukkit/entity/LivingEntity.java b/src/main/java/org/bukkit/entity/LivingEntity.java +index b96edbf7e5a2bf66a9ebf9300368e8f6a8d561f9..f64cd3a467ccb4f773138542a6beb61ab2e1ae40 100644 +--- a/src/main/java/org/bukkit/entity/LivingEntity.java ++++ b/src/main/java/org/bukkit/entity/LivingEntity.java +@@ -888,5 +888,12 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource + * @param safeFallDistance Safe fall distance + */ + void setSafeFallDistance(float safeFallDistance); ++ ++ /** ++ * Play item break animation for the item in specified equipment slot ++ * ++ * @param slot Equipment slot to play break animation for ++ */ ++ void broadcastItemBreak(@NotNull org.bukkit.inventory.EquipmentSlot slot); + // Purpur end + } diff --git a/patches/Purpur/patches/api/0023-Item-entity-immunities.patch b/patches/Purpur/patches/api/0023-Item-entity-immunities.patch new file mode 100644 index 00000000..0d320bc5 --- /dev/null +++ b/patches/Purpur/patches/api/0023-Item-entity-immunities.patch @@ -0,0 +1,73 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sat, 22 Aug 2020 17:42:08 -0500 +Subject: [PATCH] Item entity immunities + + +diff --git a/src/main/java/org/bukkit/entity/Item.java b/src/main/java/org/bukkit/entity/Item.java +index 0ee072645ecf1bf5feb74de6960947ef76db366e..5b9a20e0695218f1239d2bf1d0368291e2a10c06 100644 +--- a/src/main/java/org/bukkit/entity/Item.java ++++ b/src/main/java/org/bukkit/entity/Item.java +@@ -120,4 +120,62 @@ public interface Item extends Entity { + */ + public void setWillAge(boolean willAge); + // Paper end ++ ++ // Purpur start ++ /** ++ * Set whether or not this item is immune to cactus ++ * ++ * @param immuneToCactus True to make immune to cactus ++ */ ++ void setImmuneToCactus(boolean immuneToCactus); ++ ++ /** ++ * Check if item is immune to cactus ++ * ++ * @return True if immune to cactus ++ */ ++ boolean isImmuneToCactus(); ++ ++ /** ++ * Set whether or not this item is immune to explosions ++ * ++ * @param immuneToExplosion True to make immune to explosions ++ */ ++ void setImmuneToExplosion(boolean immuneToExplosion); ++ ++ /** ++ * Check if item is immune to explosions ++ * ++ * @return True if immune to explosions ++ */ ++ boolean isImmuneToExplosion(); ++ ++ /** ++ * Set whether or not this item is immune to fire ++ * ++ * @param immuneToFire True to make immune to fire ++ */ ++ void setImmuneToFire(boolean immuneToFire); ++ ++ /** ++ * Check if item is immune to fire ++ * ++ * @return True if immune to fire ++ */ ++ boolean isImmuneToFire(); ++ ++ /** ++ * Set whether or not this item is immune to lightning ++ * ++ * @param immuneToLightning True to make immune to lightning ++ */ ++ void setImmuneToLightning(boolean immuneToLightning); ++ ++ /** ++ * Check if item is immune to lightning ++ * ++ * @return True if immune to lightning ++ */ ++ boolean isImmuneToLightning(); ++ // Purpur end + } diff --git a/patches/Purpur/patches/api/0024-Spigot-Improve-output-of-plugins-command.patch b/patches/Purpur/patches/api/0024-Spigot-Improve-output-of-plugins-command.patch new file mode 100644 index 00000000..bb371528 --- /dev/null +++ b/patches/Purpur/patches/api/0024-Spigot-Improve-output-of-plugins-command.patch @@ -0,0 +1,114 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Parker Hawke +Date: Sat, 27 Jun 2020 18:43:37 -0400 +Subject: [PATCH] Spigot - Improve output of plugins command + + +diff --git a/src/main/java/org/bukkit/command/defaults/PluginsCommand.java b/src/main/java/org/bukkit/command/defaults/PluginsCommand.java +index 1aa58c59e1e8738bbdc77752885ff3b18b29de42..4974fc518c3645e6e060ff52e71a47a86d52ec5c 100644 +--- a/src/main/java/org/bukkit/command/defaults/PluginsCommand.java ++++ b/src/main/java/org/bukkit/command/defaults/PluginsCommand.java +@@ -11,6 +11,15 @@ import org.bukkit.ChatColor; + import org.bukkit.command.CommandSender; + import org.bukkit.plugin.Plugin; + import org.jetbrains.annotations.NotNull; ++// Spigot start ++import net.md_5.bungee.api.chat.BaseComponent; ++import net.md_5.bungee.api.chat.ClickEvent; ++import net.md_5.bungee.api.chat.ComponentBuilder; ++import net.md_5.bungee.api.chat.HoverEvent; ++import net.md_5.bungee.api.chat.ComponentBuilder.FormatRetention; ++import org.bukkit.entity.Player; ++import org.bukkit.plugin.PluginDescriptionFile; ++// Spigot end + + public class PluginsCommand extends BukkitCommand { + public PluginsCommand(@NotNull String name) { +@@ -25,7 +34,13 @@ public class PluginsCommand extends BukkitCommand { + public boolean execute(@NotNull CommandSender sender, @NotNull String currentAlias, @NotNull String[] args) { + if (!testPermission(sender)) return true; + +- sender.sendMessage("Plugins " + getPluginList()); ++ // Spigot start ++ if (sender instanceof Player && sender.hasPermission("bukkit.command.version")) { ++ sender.spigot().sendMessage(getPluginListSpigot()); ++ } else { ++ sender.sendMessage("Plugins " + getPluginList()); ++ } ++ // Spigot end + return true; + } + +@@ -71,4 +86,72 @@ public class PluginsCommand extends BukkitCommand { + // Paper end + } + ++ // Spigot start ++ @NotNull ++ private BaseComponent[] getPluginListSpigot() { ++ Plugin[] plugins = Bukkit.getPluginManager().getPlugins(); ++ ComponentBuilder pluginList = new ComponentBuilder("Plugins (" + plugins.length + "): "); ++ ++ int index = 0; ++ for (Plugin plugin : plugins) { ++ if (index++ > 0) { ++ pluginList.append(", ", FormatRetention.NONE).color(net.md_5.bungee.api.ChatColor.WHITE); ++ } ++ ++ // Event components ++ PluginDescriptionFile description = plugin.getDescription(); ++ ComponentBuilder hoverEventComponents = new ComponentBuilder(); ++ hoverEventComponents.append("Version: ").color(net.md_5.bungee.api.ChatColor.WHITE).append(description.getVersion()).color(net.md_5.bungee.api.ChatColor.GREEN); ++ ++ if (description.getDescription() != null) { ++ hoverEventComponents.append("\nDescription: ").color(net.md_5.bungee.api.ChatColor.WHITE).append(description.getDescription()).color(net.md_5.bungee.api.ChatColor.GREEN); ++ } ++ ++ if (description.getWebsite() != null) { ++ hoverEventComponents.append("\nWebsite: ").color(net.md_5.bungee.api.ChatColor.WHITE).append(description.getWebsite()).color(net.md_5.bungee.api.ChatColor.GREEN); ++ } ++ ++ if (!description.getAuthors().isEmpty()) { ++ if (description.getAuthors().size() == 1) { ++ hoverEventComponents.append("\nAuthor: "); ++ } else { ++ hoverEventComponents.append("\nAuthors: "); ++ } ++ ++ hoverEventComponents.color(net.md_5.bungee.api.ChatColor.WHITE).append(getAuthors(description)); ++ } ++ ++ HoverEvent hoverEvent = new HoverEvent(HoverEvent.Action.SHOW_TEXT, hoverEventComponents.create()); ++ ClickEvent clickEvent = new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, "/version " + description.getName()); ++ ++ // Plugin list entry ++ pluginList.append(plugin.getDescription().getName()); ++ pluginList.color(plugin.isEnabled() ? net.md_5.bungee.api.ChatColor.GREEN : net.md_5.bungee.api.ChatColor.RED); ++ pluginList.event(hoverEvent).event(clickEvent); ++ ++ if (plugin.getDescription().getProvides().size() > 0) { ++ pluginList.append("( ", FormatRetention.NONE).color(net.md_5.bungee.api.ChatColor.WHITE).append(String.join(", ", plugin.getDescription().getProvides())).append(")"); ++ } ++ } ++ ++ return pluginList.create(); ++ } ++ ++ @NotNull ++ private BaseComponent[] getAuthors(@NotNull final PluginDescriptionFile description) { ++ ComponentBuilder result = new ComponentBuilder(); ++ List authors = description.getAuthors(); ++ ++ for (int i = 0; i < authors.size(); i++) { ++ if (i > 0) { ++ result.append(i < authors.size() - 1 ? ", " : " and ", FormatRetention.NONE); ++ result.color(net.md_5.bungee.api.ChatColor.WHITE); ++ } ++ ++ result.append(authors.get(i)).color(net.md_5.bungee.api.ChatColor.GREEN); ++ } ++ ++ return result.create(); ++ } ++ // Spigot end + } diff --git a/patches/Purpur/patches/api/0025-Add-option-to-disable-zombie-aggressiveness-towards-.patch b/patches/Purpur/patches/api/0025-Add-option-to-disable-zombie-aggressiveness-towards-.patch new file mode 100644 index 00000000..45b72c6b --- /dev/null +++ b/patches/Purpur/patches/api/0025-Add-option-to-disable-zombie-aggressiveness-towards-.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: nitricspace +Date: Wed, 23 Sep 2020 22:14:38 +0100 +Subject: [PATCH] Add option to disable zombie aggressiveness towards villagers + when lagging + + +diff --git a/src/main/java/com/destroystokyo/paper/entity/ai/VanillaGoal.java b/src/main/java/com/destroystokyo/paper/entity/ai/VanillaGoal.java +index 177143c9764e82981423879ed35625edd25d3ebf..da638f9745aceebe4f2ca90823308c6879c75ae7 100644 +--- a/src/main/java/com/destroystokyo/paper/entity/ai/VanillaGoal.java ++++ b/src/main/java/com/destroystokyo/paper/entity/ai/VanillaGoal.java +@@ -211,5 +211,7 @@ public interface VanillaGoal extends Goal { + GoalKey ORBIT_CRYSTAL_GOAL = GoalKey.of(Phantom.class, NamespacedKey.minecraft("orbit_crystal_goal")); + GoalKey HAS_RIDER = GoalKey.of(Mob.class, NamespacedKey.minecraft("has_rider")); + GoalKey HORSE_HAS_RIDER = GoalKey.of(AbstractHorse.class, NamespacedKey.minecraft("horse_has_rider")); ++ GoalKey DROWNED_ATTACK_VILLAGER = GoalKey.of(Drowned.class, NamespacedKey.minecraft("drowned_attack_villager")); ++ GoalKey ZOMBIE_ATTACK_VILLAGER = GoalKey.of(Zombie.class, NamespacedKey.minecraft("zombie_attack_villager")); + // Purpur end + } diff --git a/patches/Purpur/patches/api/0026-Add-predicate-to-recipe-s-ExactChoice-ingredient.patch b/patches/Purpur/patches/api/0026-Add-predicate-to-recipe-s-ExactChoice-ingredient.patch new file mode 100644 index 00000000..db153e66 --- /dev/null +++ b/patches/Purpur/patches/api/0026-Add-predicate-to-recipe-s-ExactChoice-ingredient.patch @@ -0,0 +1,52 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Fri, 2 Oct 2020 17:43:24 -0500 +Subject: [PATCH] Add predicate to recipe's ExactChoice ingredient + + +diff --git a/src/main/java/org/bukkit/inventory/RecipeChoice.java b/src/main/java/org/bukkit/inventory/RecipeChoice.java +index 90208bc96085f05a3b657b9467b1670d00b03104..c59d5e4ef9641fd73463b177239226866272745b 100644 +--- a/src/main/java/org/bukkit/inventory/RecipeChoice.java ++++ b/src/main/java/org/bukkit/inventory/RecipeChoice.java +@@ -10,6 +10,7 @@ import java.util.function.Predicate; + import org.bukkit.Material; + import org.bukkit.Tag; + import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; // Purpur + + /** + * Represents a potential item match within a recipe. All choices within a +@@ -152,6 +153,7 @@ public interface RecipeChoice extends Predicate, Cloneable { + public static class ExactChoice implements RecipeChoice { + + private List choices; ++ private Predicate predicate; // Purpur + + public ExactChoice(@NotNull ItemStack stack) { + this(Arrays.asList(stack)); +@@ -196,6 +198,7 @@ public interface RecipeChoice extends Predicate, Cloneable { + + @Override + public boolean test(@NotNull ItemStack t) { ++ if (predicate != null) return predicate.test(t); // Purpur + for (ItemStack match : choices) { + if (t.isSimilar(match)) { + return true; +@@ -205,6 +208,17 @@ public interface RecipeChoice extends Predicate, Cloneable { + return false; + } + ++ // Purpur start ++ @Nullable ++ public Predicate getPredicate() { ++ return predicate; ++ } ++ ++ public void setPredicate(@Nullable Predicate predicate) { ++ this.predicate = predicate; ++ } ++ // Purpur end ++ + @Override + public int hashCode() { + int hash = 7; diff --git a/patches/Purpur/patches/api/0027-Add-critical-hit-check-to-EntityDamagedByEntityEvent.patch b/patches/Purpur/patches/api/0027-Add-critical-hit-check-to-EntityDamagedByEntityEvent.patch new file mode 100644 index 00000000..ebfe2021 --- /dev/null +++ b/patches/Purpur/patches/api/0027-Add-critical-hit-check-to-EntityDamagedByEntityEvent.patch @@ -0,0 +1,56 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Tue, 24 Nov 2020 04:30:34 -0600 +Subject: [PATCH] Add critical hit check to EntityDamagedByEntityEvent + + +diff --git a/src/main/java/org/bukkit/event/entity/EntityDamageByEntityEvent.java b/src/main/java/org/bukkit/event/entity/EntityDamageByEntityEvent.java +index 869bad7405ec7fa67728e90d8b9f2e11b542611f..05fde759bbdf6068f140b4428bbcb355e22d6b28 100644 +--- a/src/main/java/org/bukkit/event/entity/EntityDamageByEntityEvent.java ++++ b/src/main/java/org/bukkit/event/entity/EntityDamageByEntityEvent.java +@@ -10,15 +10,28 @@ import org.jetbrains.annotations.NotNull; + */ + public class EntityDamageByEntityEvent extends EntityDamageEvent { + private final Entity damager; ++ private final boolean isCritical; // Purpur + + public EntityDamageByEntityEvent(@NotNull final Entity damager, @NotNull final Entity damagee, @NotNull final DamageCause cause, final double damage) { ++ // Purpur start ++ this(damager, damagee, cause, damage, false); ++ } ++ public EntityDamageByEntityEvent(@NotNull final Entity damager, @NotNull final Entity damagee, @NotNull final DamageCause cause, final double damage, boolean isCritical) { ++ // Purpur end + super(damagee, cause, damage); + this.damager = damager; ++ this.isCritical = isCritical; // Purpur + } + + public EntityDamageByEntityEvent(@NotNull final Entity damager, @NotNull final Entity damagee, @NotNull final DamageCause cause, @NotNull final Map modifiers, @NotNull final Map> modifierFunctions) { ++ // Purpur start ++ this(damager, damagee, cause, modifiers, modifierFunctions, false); ++ } ++ public EntityDamageByEntityEvent(@NotNull final Entity damager, @NotNull final Entity damagee, @NotNull final DamageCause cause, @NotNull final Map modifiers, @NotNull final Map> modifierFunctions, boolean isCritical) { ++ // Purpur end + super(damagee, cause, modifiers, modifierFunctions); + this.damager = damager; ++ this.isCritical = isCritical; // Purpur + } + + /** +@@ -30,4 +43,16 @@ public class EntityDamageByEntityEvent extends EntityDamageEvent { + public Entity getDamager() { + return damager; + } ++ ++ // Purpur start ++ ++ /** ++ * Whether this damage was done by a critical hit ++ * ++ * @return True if critical hit ++ */ ++ public boolean isCritical() { ++ return this.isCritical; ++ } ++ // Purpur end + } diff --git a/patches/Purpur/patches/api/0028-Left-handed-API.patch b/patches/Purpur/patches/api/0028-Left-handed-API.patch new file mode 100644 index 00000000..5e8b1e02 --- /dev/null +++ b/patches/Purpur/patches/api/0028-Left-handed-API.patch @@ -0,0 +1,31 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Mon, 30 Nov 2020 06:02:54 -0600 +Subject: [PATCH] Left handed API + + +diff --git a/src/main/java/org/bukkit/entity/Mob.java b/src/main/java/org/bukkit/entity/Mob.java +index 7d4ce660adb21e579e564796568945ee20f0ca59..4205dc5746dafd966f95103cdd2a1a55e79642f8 100644 +--- a/src/main/java/org/bukkit/entity/Mob.java ++++ b/src/main/java/org/bukkit/entity/Mob.java +@@ -146,4 +146,20 @@ public interface Mob extends LivingEntity, Lootable { + * @return whether the mob is aware + */ + public boolean isAware(); ++ ++ // Purpur start ++ /** ++ * Check if Mob is left-handed ++ * ++ * @return True if left-handed ++ */ ++ public boolean isLeftHanded(); ++ ++ /** ++ * Set if Mob is left-handed ++ * ++ * @param leftHanded True if left-handed ++ */ ++ public void setLeftHanded(boolean leftHanded); ++ // Purpur end + } diff --git a/patches/Purpur/patches/api/0029-Alphabetize-in-game-plugins-list.patch b/patches/Purpur/patches/api/0029-Alphabetize-in-game-plugins-list.patch new file mode 100644 index 00000000..0e1b879b --- /dev/null +++ b/patches/Purpur/patches/api/0029-Alphabetize-in-game-plugins-list.patch @@ -0,0 +1,27 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Tue, 8 Dec 2020 09:48:18 -0600 +Subject: [PATCH] Alphabetize in-game /plugins list + + +diff --git a/src/main/java/org/bukkit/command/defaults/PluginsCommand.java b/src/main/java/org/bukkit/command/defaults/PluginsCommand.java +index 4974fc518c3645e6e060ff52e71a47a86d52ec5c..37cc5d7e9db89e4ef7ab16da1b159bd19134a4ff 100644 +--- a/src/main/java/org/bukkit/command/defaults/PluginsCommand.java ++++ b/src/main/java/org/bukkit/command/defaults/PluginsCommand.java +@@ -2,6 +2,7 @@ package org.bukkit.command.defaults; + + import java.util.Arrays; + import java.util.Collections; ++import java.util.Comparator; + import java.util.List; + import java.util.Map; + import java.util.TreeMap; +@@ -89,7 +90,7 @@ public class PluginsCommand extends BukkitCommand { + // Spigot start + @NotNull + private BaseComponent[] getPluginListSpigot() { +- Plugin[] plugins = Bukkit.getPluginManager().getPlugins(); ++ Plugin[] plugins = Arrays.stream(Bukkit.getPluginManager().getPlugins()).sorted(Comparator.comparing(plugin -> plugin.getName().toLowerCase())).toArray(Plugin[]::new); // Purpur + ComponentBuilder pluginList = new ComponentBuilder("Plugins (" + plugins.length + "): "); + + int index = 0; diff --git a/patches/Purpur/patches/api/0030-Rabid-Wolf-API.patch b/patches/Purpur/patches/api/0030-Rabid-Wolf-API.patch new file mode 100644 index 00000000..a3c3a541 --- /dev/null +++ b/patches/Purpur/patches/api/0030-Rabid-Wolf-API.patch @@ -0,0 +1,42 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Encode42 +Date: Tue, 8 Dec 2020 17:15:15 -0500 +Subject: [PATCH] Rabid Wolf API + + +diff --git a/src/main/java/com/destroystokyo/paper/entity/ai/VanillaGoal.java b/src/main/java/com/destroystokyo/paper/entity/ai/VanillaGoal.java +index da638f9745aceebe4f2ca90823308c6879c75ae7..39f77041133228c4bd4cec2427ad0bae8e739d4a 100644 +--- a/src/main/java/com/destroystokyo/paper/entity/ai/VanillaGoal.java ++++ b/src/main/java/com/destroystokyo/paper/entity/ai/VanillaGoal.java +@@ -213,5 +213,6 @@ public interface VanillaGoal extends Goal { + GoalKey HORSE_HAS_RIDER = GoalKey.of(AbstractHorse.class, NamespacedKey.minecraft("horse_has_rider")); + GoalKey DROWNED_ATTACK_VILLAGER = GoalKey.of(Drowned.class, NamespacedKey.minecraft("drowned_attack_villager")); + GoalKey ZOMBIE_ATTACK_VILLAGER = GoalKey.of(Zombie.class, NamespacedKey.minecraft("zombie_attack_villager")); ++ GoalKey AVOID_RABID_WOLVES = GoalKey.of(Wolf.class, NamespacedKey.minecraft("avoid_rabid_wolves")); + // Purpur end + } +diff --git a/src/main/java/org/bukkit/entity/Wolf.java b/src/main/java/org/bukkit/entity/Wolf.java +index 0e5decadf31140d6cb121c298f935ccc12c7a7e7..c1fd30fe4cd4eec11eb8298f059d14584b7dd7ec 100644 +--- a/src/main/java/org/bukkit/entity/Wolf.java ++++ b/src/main/java/org/bukkit/entity/Wolf.java +@@ -39,4 +39,20 @@ public interface Wolf extends Tameable, Sittable { + * @param color the color to apply + */ + public void setCollarColor(@NotNull DyeColor color); ++ ++ // Purpur start ++ /** ++ * Checks if this wolf is rabid ++ * ++ * @return whether the wolf is rabid ++ */ ++ public boolean isRabid(); ++ ++ /** ++ * Sets this wolf to be rabid or not ++ * ++ * @param rabid whether the wolf should be rabid ++ */ ++ public void setRabid(boolean rabid); ++ // Purpur end + } diff --git a/patches/Purpur/patches/api/0031-Fix-javadoc-warnings-missing-param-and-return.patch b/patches/Purpur/patches/api/0031-Fix-javadoc-warnings-missing-param-and-return.patch new file mode 100644 index 00000000..b712f808 --- /dev/null +++ b/patches/Purpur/patches/api/0031-Fix-javadoc-warnings-missing-param-and-return.patch @@ -0,0 +1,1660 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Fri, 18 Dec 2020 21:21:48 -0600 +Subject: [PATCH] Fix javadoc warnings (missing @param and @return) + + +diff --git a/src/main/java/com/destroystokyo/paper/ClientOption.java b/src/main/java/com/destroystokyo/paper/ClientOption.java +index 9dad814cf51bc59ec5dfbf14474fea6557de38aa..7baf7ee3b62135eda8f0d9c1d761b79f596061f1 100644 +--- a/src/main/java/com/destroystokyo/paper/ClientOption.java ++++ b/src/main/java/com/destroystokyo/paper/ClientOption.java +@@ -4,6 +4,11 @@ import org.jetbrains.annotations.NotNull; + + import org.bukkit.inventory.MainHand; + ++/** ++ * Represents a client option ++ * ++ * @param Client option type ++ */ + public final class ClientOption { + + public static final ClientOption SKIN_PARTS = new ClientOption<>(SkinParts.class); +@@ -19,6 +24,11 @@ public final class ClientOption { + this.type = type; + } + ++ /** ++ * Get the option's type ++ * ++ * @return Option's type ++ */ + @NotNull + public Class getType() { + return type; +diff --git a/src/main/java/com/destroystokyo/paper/MaterialSetTag.java b/src/main/java/com/destroystokyo/paper/MaterialSetTag.java +index a02a02aa0c87e0f0ed9e509e4dcab01565b3d92a..6c99f4b4960f8f982557bb42717a2868d57ce4b7 100644 +--- a/src/main/java/com/destroystokyo/paper/MaterialSetTag.java ++++ b/src/main/java/com/destroystokyo/paper/MaterialSetTag.java +@@ -21,10 +21,14 @@ import java.util.stream.Stream; + import org.jetbrains.annotations.NotNull; + import org.jetbrains.annotations.Nullable; + ++/** ++ * Material set tag ++ */ + public class MaterialSetTag extends BaseTag { + + /** + * @deprecated Use NamespacedKey version of constructor ++ * @param filter Filter predicate + */ + @Deprecated + public MaterialSetTag(@NotNull Predicate filter) { +@@ -33,6 +37,7 @@ public class MaterialSetTag extends BaseTag { + + /** + * @deprecated Use NamespacedKey version of constructor ++ * @param materials Materials to include + */ + @Deprecated + public MaterialSetTag(@NotNull Collection materials) { +@@ -41,6 +46,7 @@ public class MaterialSetTag extends BaseTag { + + /** + * @deprecated Use NamespacedKey version of constructor ++ * @param materials Materials to include + */ + @Deprecated + public MaterialSetTag(@NotNull Material... materials) { +diff --git a/src/main/java/com/destroystokyo/paper/SkinParts.java b/src/main/java/com/destroystokyo/paper/SkinParts.java +index 4a0c39405d4fbed457787e3c6ded4cc6591bc8c2..9b269a51928bc5cc35431855c79bd33ce9031bf1 100644 +--- a/src/main/java/com/destroystokyo/paper/SkinParts.java ++++ b/src/main/java/com/destroystokyo/paper/SkinParts.java +@@ -1,5 +1,8 @@ + package com.destroystokyo.paper; + ++/** ++ * Skin parts ++ */ + public interface SkinParts { + + boolean hasCapeEnabled(); +diff --git a/src/main/java/com/destroystokyo/paper/block/TargetBlockInfo.java b/src/main/java/com/destroystokyo/paper/block/TargetBlockInfo.java +index 18a96dbb01d3b34476652264b2d6be3782a154ec..1bae8e5df78bb88deec212eedf855cc69bfbe913 100644 +--- a/src/main/java/com/destroystokyo/paper/block/TargetBlockInfo.java ++++ b/src/main/java/com/destroystokyo/paper/block/TargetBlockInfo.java +@@ -46,6 +46,9 @@ public class TargetBlockInfo { + return block.getRelative(blockFace); + } + ++ /** ++ * Fluid mode ++ */ + public enum FluidMode { + NEVER, + SOURCE_ONLY, +diff --git a/src/main/java/com/destroystokyo/paper/entity/RangedEntity.java b/src/main/java/com/destroystokyo/paper/entity/RangedEntity.java +index f2e3233a3d1744e32fb76d3731b9858ef0067e30..e66e8b28c673216dd1587582f44c26f6ca877c23 100644 +--- a/src/main/java/com/destroystokyo/paper/entity/RangedEntity.java ++++ b/src/main/java/com/destroystokyo/paper/entity/RangedEntity.java +@@ -4,6 +4,9 @@ import org.bukkit.entity.LivingEntity; + import org.bukkit.entity.Mob; + import org.jetbrains.annotations.NotNull; + ++/** ++ * Represents an entity with ranged attacks ++ */ + public interface RangedEntity extends Mob { + /** + * Attack the specified entity using a ranged attack. +diff --git a/src/main/java/com/destroystokyo/paper/event/block/TNTPrimeEvent.java b/src/main/java/com/destroystokyo/paper/event/block/TNTPrimeEvent.java +index 73dabb82c7fbea3f0cccade0a2944b11a80ede06..b065f8f8af6ed9cc7b1c8a671488a6424662d14c 100644 +--- a/src/main/java/com/destroystokyo/paper/event/block/TNTPrimeEvent.java ++++ b/src/main/java/com/destroystokyo/paper/event/block/TNTPrimeEvent.java +@@ -83,6 +83,9 @@ public class TNTPrimeEvent extends BlockEvent implements Cancellable { + return handlers; + } + ++ /** ++ * TnT prime reason ++ */ + public enum PrimeReason { + /** + * When TNT prime was caused by other explosion (chain reaction) +diff --git a/src/main/java/com/destroystokyo/paper/event/entity/EndermanEscapeEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/EndermanEscapeEvent.java +index 806112a8b5a7ce31166675f5b074ceaf42e364b6..a2635e3b76780a51f87f6329b0db3a08dd08b0e6 100644 +--- a/src/main/java/com/destroystokyo/paper/event/entity/EndermanEscapeEvent.java ++++ b/src/main/java/com/destroystokyo/paper/event/entity/EndermanEscapeEvent.java +@@ -8,6 +8,9 @@ import org.bukkit.event.HandlerList; + import org.bukkit.event.entity.EntityEvent; + import org.jetbrains.annotations.NotNull; + ++/** ++ * Called when an enderman tries to teleport to escape ++ */ + public class EndermanEscapeEvent extends EntityEvent implements Cancellable { + @NotNull private final Reason reason; + +@@ -62,6 +65,9 @@ public class EndermanEscapeEvent extends EntityEvent implements Cancellable { + cancelled = cancel; + } + ++ /** ++ * Escape reason ++ */ + public enum Reason { + /** + * The enderman has stopped attacking and ran away +diff --git a/src/main/java/com/destroystokyo/paper/event/entity/EntityTransformedEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/EntityTransformedEvent.java +index 12194f1fc7f03ca6785904b6187b3dfd03b16461..e974323d0193e6b5a6fe43979c6c24d78107a5cc 100644 +--- a/src/main/java/com/destroystokyo/paper/event/entity/EntityTransformedEvent.java ++++ b/src/main/java/com/destroystokyo/paper/event/entity/EntityTransformedEvent.java +@@ -66,6 +66,9 @@ public class EntityTransformedEvent extends EntityEvent implements Cancellable { + cancelled = cancel; + } + ++ /** ++ * Transformed reason ++ */ + public enum TransformedReason { + /** + * When a zombie drowns +diff --git a/src/main/java/com/destroystokyo/paper/event/entity/WitchReadyPotionEvent.java b/src/main/java/com/destroystokyo/paper/event/entity/WitchReadyPotionEvent.java +index 5351b523defa054ba56ae3fb591029283ca7510d..f00594fba37c8b6264f940c84ed5c40c09879d2f 100644 +--- a/src/main/java/com/destroystokyo/paper/event/entity/WitchReadyPotionEvent.java ++++ b/src/main/java/com/destroystokyo/paper/event/entity/WitchReadyPotionEvent.java +@@ -9,6 +9,9 @@ import org.bukkit.inventory.ItemStack; + import org.jetbrains.annotations.NotNull; + import org.jetbrains.annotations.Nullable; + ++/** ++ * Called when a witch prepares a potion ++ */ + public class WitchReadyPotionEvent extends EntityEvent implements Cancellable { + private ItemStack potion; + +diff --git a/src/main/java/com/destroystokyo/paper/event/executor/MethodHandleEventExecutor.java b/src/main/java/com/destroystokyo/paper/event/executor/MethodHandleEventExecutor.java +index 5b28e9b1daba7834af67dbc193dd656bedd9a994..dbda663489e82b89646975b56462c4ff38a5fde9 100644 +--- a/src/main/java/com/destroystokyo/paper/event/executor/MethodHandleEventExecutor.java ++++ b/src/main/java/com/destroystokyo/paper/event/executor/MethodHandleEventExecutor.java +@@ -11,6 +11,9 @@ import org.bukkit.event.Listener; + import org.bukkit.plugin.EventExecutor; + import org.jetbrains.annotations.NotNull; + ++/** ++ * Method handle event executor ++ */ + public class MethodHandleEventExecutor implements EventExecutor { + private final Class eventClass; + private final MethodHandle handle; +diff --git a/src/main/java/com/destroystokyo/paper/event/executor/StaticMethodHandleEventExecutor.java b/src/main/java/com/destroystokyo/paper/event/executor/StaticMethodHandleEventExecutor.java +index c83672427324bd068ed52916f700b68446a226f6..d28f8f0fb6dcf34453a75af9e9efd18a89b2b94f 100644 +--- a/src/main/java/com/destroystokyo/paper/event/executor/StaticMethodHandleEventExecutor.java ++++ b/src/main/java/com/destroystokyo/paper/event/executor/StaticMethodHandleEventExecutor.java +@@ -15,6 +15,9 @@ import org.bukkit.event.Listener; + import org.bukkit.plugin.EventExecutor; + import org.jetbrains.annotations.NotNull; + ++/** ++ * Static method handle event executor ++ */ + public class StaticMethodHandleEventExecutor implements EventExecutor { + private final Class eventClass; + private final MethodHandle handle; +diff --git a/src/main/java/com/destroystokyo/paper/event/executor/asm/ASMEventExecutorGenerator.java b/src/main/java/com/destroystokyo/paper/event/executor/asm/ASMEventExecutorGenerator.java +index b6e7d8ee8d903ebf975d60bec0e08603d9a49fdb..55770ba8a2461c782f311aeb8abc79ec5f53ea81 100644 +--- a/src/main/java/com/destroystokyo/paper/event/executor/asm/ASMEventExecutorGenerator.java ++++ b/src/main/java/com/destroystokyo/paper/event/executor/asm/ASMEventExecutorGenerator.java +@@ -11,6 +11,9 @@ import org.objectweb.asm.commons.GeneratorAdapter; + + import static org.objectweb.asm.Opcodes.*; + ++/** ++ * ASM event executor generator ++ */ + public class ASMEventExecutorGenerator { + @NotNull + public static byte[] generateEventExecutor(@NotNull Method m, @NotNull String name) { +diff --git a/src/main/java/com/destroystokyo/paper/event/executor/asm/ClassDefiner.java b/src/main/java/com/destroystokyo/paper/event/executor/asm/ClassDefiner.java +index f79685b48bb581277a6891927988b6f7a4389dc4..75810a098791b5f758a3fbb212d80643b1cb505b 100644 +--- a/src/main/java/com/destroystokyo/paper/event/executor/asm/ClassDefiner.java ++++ b/src/main/java/com/destroystokyo/paper/event/executor/asm/ClassDefiner.java +@@ -2,6 +2,9 @@ package com.destroystokyo.paper.event.executor.asm; + + import org.jetbrains.annotations.NotNull; + ++/** ++ * Class definer ++ */ + public interface ClassDefiner { + + /** +diff --git a/src/main/java/com/destroystokyo/paper/event/executor/asm/SafeClassDefiner.java b/src/main/java/com/destroystokyo/paper/event/executor/asm/SafeClassDefiner.java +index ac99477e9f2c08041aeff31abc1d1edee58d0a67..d2bd9211046dea646f0c0954a932859ba1d0fb15 100644 +--- a/src/main/java/com/destroystokyo/paper/event/executor/asm/SafeClassDefiner.java ++++ b/src/main/java/com/destroystokyo/paper/event/executor/asm/SafeClassDefiner.java +@@ -9,6 +9,9 @@ import com.google.common.collect.MapMaker; + import org.jetbrains.annotations.NotNull; + import org.objectweb.asm.Type; + ++/** ++ * Safe class definer ++ */ + public class SafeClassDefiner implements ClassDefiner { + /* default */ static final SafeClassDefiner INSTANCE = new SafeClassDefiner(); + +diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerArmorChangeEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerArmorChangeEvent.java +index e406ce639a2e88b78f82f25e71678a669d0a958b..4cc1012c33c6f76255ac075ace1d8ee638091eed 100644 +--- a/src/main/java/com/destroystokyo/paper/event/player/PlayerArmorChangeEvent.java ++++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerArmorChangeEvent.java +@@ -80,6 +80,9 @@ public class PlayerArmorChangeEvent extends PlayerEvent { + return HANDLERS; + } + ++ /** ++ * Armor slot type ++ */ + public enum SlotType { + HEAD(NETHERITE_HELMET, DIAMOND_HELMET, GOLDEN_HELMET, IRON_HELMET, CHAINMAIL_HELMET, LEATHER_HELMET, CARVED_PUMPKIN, PLAYER_HEAD, SKELETON_SKULL, ZOMBIE_HEAD, CREEPER_HEAD, WITHER_SKELETON_SKULL, TURTLE_HELMET), + CHEST(NETHERITE_CHESTPLATE, DIAMOND_CHESTPLATE, GOLDEN_CHESTPLATE, IRON_CHESTPLATE, CHAINMAIL_CHESTPLATE, LEATHER_CHESTPLATE, ELYTRA), +diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerConnectionCloseEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerConnectionCloseEvent.java +index 12c1c6fe9dc8dc5f5faf6dcf99f6857219ef22b8..1f623010d3eddc2bee8f4b8fb410a9509a57b5ae 100644 +--- a/src/main/java/com/destroystokyo/paper/event/player/PlayerConnectionCloseEvent.java ++++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerConnectionCloseEvent.java +@@ -59,7 +59,9 @@ public class PlayerConnectionCloseEvent extends Event { + } + + /** +- * Returns the {@code UUID} of the player disconnecting. ++ * Get the {@code UUID} of the player disconnecting. ++ * ++ * @return the {@code UUID} of the player disconnecting + */ + @NotNull + public UUID getPlayerUniqueId() { +@@ -67,7 +69,9 @@ public class PlayerConnectionCloseEvent extends Event { + } + + /** +- * Returns the name of the player disconnecting. ++ * Get the name of the player disconnecting. ++ * ++ * @return the name of the player disconnecting + */ + @NotNull + public String getPlayerName() { +@@ -75,7 +79,9 @@ public class PlayerConnectionCloseEvent extends Event { + } + + /** +- * Returns the player's IP address. ++ * Get the player's IP address. ++ * ++ * @return the player's IP address + */ + @NotNull + public InetAddress getIpAddress() { +diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerUseUnknownEntityEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerUseUnknownEntityEvent.java +index 09cfdf48ead8f03f3497646537292174241b0868..20f8201d2278f6fcac38913638510f33b0750b28 100644 +--- a/src/main/java/com/destroystokyo/paper/event/player/PlayerUseUnknownEntityEvent.java ++++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerUseUnknownEntityEvent.java +@@ -6,6 +6,9 @@ import org.bukkit.event.player.PlayerEvent; + import org.bukkit.inventory.EquipmentSlot; + import org.jetbrains.annotations.NotNull; + ++/** ++ * Called when a player uses (interacts with) an unknown entity ++ */ + public class PlayerUseUnknownEntityEvent extends PlayerEvent { + + private static final HandlerList handlers = new HandlerList(); +diff --git a/src/main/java/com/destroystokyo/paper/event/server/GS4QueryEvent.java b/src/main/java/com/destroystokyo/paper/event/server/GS4QueryEvent.java +index 77a19995f6792a182c5a43d6714e7bda0f42df5b..cb43359e012630b3126564c068d81e9b20845a80 100644 +--- a/src/main/java/com/destroystokyo/paper/event/server/GS4QueryEvent.java ++++ b/src/main/java/com/destroystokyo/paper/event/server/GS4QueryEvent.java +@@ -105,6 +105,9 @@ public final class GS4QueryEvent extends Event { + ; + } + ++ /** ++ * Query response ++ */ + public final static class QueryResponse { + private final String motd; + private final String gameVersion; +diff --git a/src/main/java/com/destroystokyo/paper/event/server/ServerTickStartEvent.java b/src/main/java/com/destroystokyo/paper/event/server/ServerTickStartEvent.java +index eac85f1f49088bb71afb01eff4d5f53887306461..3ae058eb9433885920715408ebbe303d02f99c47 100644 +--- a/src/main/java/com/destroystokyo/paper/event/server/ServerTickStartEvent.java ++++ b/src/main/java/com/destroystokyo/paper/event/server/ServerTickStartEvent.java +@@ -4,6 +4,9 @@ import org.bukkit.event.Event; + import org.bukkit.event.HandlerList; + import org.jetbrains.annotations.NotNull; + ++/** ++ * Called at the beginning of the server tick ++ */ + public class ServerTickStartEvent extends Event { + + private static final HandlerList handlers = new HandlerList(); +diff --git a/src/main/java/com/destroystokyo/paper/inventory/meta/ArmorStandMeta.java b/src/main/java/com/destroystokyo/paper/inventory/meta/ArmorStandMeta.java +index 7e4acfff16db80a75e1ff2fee1972b16955b0918..333812f322f1f0a06d654581103aeb0123daef60 100644 +--- a/src/main/java/com/destroystokyo/paper/inventory/meta/ArmorStandMeta.java ++++ b/src/main/java/com/destroystokyo/paper/inventory/meta/ArmorStandMeta.java +@@ -2,6 +2,9 @@ package com.destroystokyo.paper.inventory.meta; + + import org.bukkit.inventory.meta.ItemMeta; + ++/** ++ * Armor stand meta ++ */ + public interface ArmorStandMeta extends ItemMeta { + + /** +diff --git a/src/main/java/com/destroystokyo/paper/loottable/LootableInventoryReplenishEvent.java b/src/main/java/com/destroystokyo/paper/loottable/LootableInventoryReplenishEvent.java +index fd184f13f5e8ee5cf829fff4f44696e1f760430b..302059e9fc048a63fd9cd2e1ed5aa27ef5811637 100644 +--- a/src/main/java/com/destroystokyo/paper/loottable/LootableInventoryReplenishEvent.java ++++ b/src/main/java/com/destroystokyo/paper/loottable/LootableInventoryReplenishEvent.java +@@ -6,6 +6,9 @@ import org.bukkit.event.HandlerList; + import org.bukkit.event.player.PlayerEvent; + import org.jetbrains.annotations.NotNull; + ++/** ++ * Called when a lootable inventory replenishes it's contents ++ */ + public class LootableInventoryReplenishEvent extends PlayerEvent implements Cancellable { + @NotNull private final LootableInventory inventory; + +diff --git a/src/main/java/com/destroystokyo/paper/util/SneakyThrow.java b/src/main/java/com/destroystokyo/paper/util/SneakyThrow.java +index 9db0056ab94145819628b3ad8d8d26130d117fcf..680410d8404a6d3b0ac91aa5fc4cd9d7f5c8fa93 100644 +--- a/src/main/java/com/destroystokyo/paper/util/SneakyThrow.java ++++ b/src/main/java/com/destroystokyo/paper/util/SneakyThrow.java +@@ -2,6 +2,9 @@ package com.destroystokyo.paper.util; + + import org.jetbrains.annotations.NotNull; + ++/** ++ * Sneaky sneaky ++ */ + public class SneakyThrow { + + public static void sneaky(@NotNull Throwable exception) { +diff --git a/src/main/java/com/destroystokyo/paper/util/VersionFetcher.java b/src/main/java/com/destroystokyo/paper/util/VersionFetcher.java +index a736d7bcdc5861a01b66ba36158db1c716339346..4825c9ca2191d3bf1440b986827fc32e230a3280 100644 +--- a/src/main/java/com/destroystokyo/paper/util/VersionFetcher.java ++++ b/src/main/java/com/destroystokyo/paper/util/VersionFetcher.java +@@ -5,6 +5,9 @@ import net.kyori.adventure.text.format.NamedTextColor; + import org.bukkit.Bukkit; + import org.jetbrains.annotations.NotNull; + ++/** ++ * Version fetcher ++ */ + public interface VersionFetcher { + /** + * Amount of time to cache results for in milliseconds +@@ -26,6 +29,9 @@ public interface VersionFetcher { + @NotNull + Component getVersionMessage(@NotNull String serverVersion); + ++ /** ++ * Dummy version fetcher ++ */ + class DummyVersionFetcher implements VersionFetcher { + + @Override +diff --git a/src/main/java/com/destroystokyo/paper/utils/CachedSizeConcurrentLinkedQueue.java b/src/main/java/com/destroystokyo/paper/utils/CachedSizeConcurrentLinkedQueue.java +index 5bb677ce585b856b3d3e589e29786a29619c56a7..613f00fa387dcc5af3191e550dea9d4d76fda02f 100644 +--- a/src/main/java/com/destroystokyo/paper/utils/CachedSizeConcurrentLinkedQueue.java ++++ b/src/main/java/com/destroystokyo/paper/utils/CachedSizeConcurrentLinkedQueue.java +@@ -5,6 +5,11 @@ import java.util.concurrent.atomic.LongAdder; + import org.jetbrains.annotations.NotNull; + import org.jetbrains.annotations.Nullable; + ++/** ++ * Cached size concurrent linked queue ++ * ++ * @param Element type ++ */ + public class CachedSizeConcurrentLinkedQueue extends ConcurrentLinkedQueue { + private final LongAdder cachedSize = new LongAdder(); + +diff --git a/src/main/java/io/papermc/paper/event/player/AsyncChatEvent.java b/src/main/java/io/papermc/paper/event/player/AsyncChatEvent.java +index ee7ec316a2f814ec759e0a3e5dfe5efbee782b22..1bf28ec988aad12ede93fa508075811601c82d60 100644 +--- a/src/main/java/io/papermc/paper/event/player/AsyncChatEvent.java ++++ b/src/main/java/io/papermc/paper/event/player/AsyncChatEvent.java +@@ -53,6 +53,11 @@ public final class AsyncChatEvent extends AbstractChatEvent { + } + + /** ++ * @param async Async ++ * @param player Player ++ * @param recipients Recipients ++ * @param formatter Formatter ++ * @param message Message + * @deprecated for removal with 1.17, use {@link #AsyncChatEvent(boolean, Player, Set, ChatRenderer, Component, Component)} + */ + @Deprecated +diff --git a/src/main/java/io/papermc/paper/event/player/ChatEvent.java b/src/main/java/io/papermc/paper/event/player/ChatEvent.java +index c6bcf0dc3f77c631aa7eeb9b1e88b5bbfe445fc6..c1c6d45b10cac170e2a9b6ec7dc273d12f21163a 100644 +--- a/src/main/java/io/papermc/paper/event/player/ChatEvent.java ++++ b/src/main/java/io/papermc/paper/event/player/ChatEvent.java +@@ -50,6 +50,10 @@ public final class ChatEvent extends AbstractChatEvent { + } + + /** ++ * @param player Player ++ * @param recipients Recipients ++ * @param formatter Formatter ++ * @param message Message + * @deprecated for removal with 1.17, use {@link #ChatEvent(Player, Set, ChatRenderer, Component, Component)} + */ + @Deprecated +diff --git a/src/main/java/io/papermc/paper/inventory/ItemRarity.java b/src/main/java/io/papermc/paper/inventory/ItemRarity.java +index 74ef8395cc040ce488c2acaa416db20272cc2734..b974627a415cd6897b245275e953cc907a5929d8 100644 +--- a/src/main/java/io/papermc/paper/inventory/ItemRarity.java ++++ b/src/main/java/io/papermc/paper/inventory/ItemRarity.java +@@ -19,7 +19,7 @@ public enum ItemRarity { + + /** + * Gets the color formatting associated with the rarity. +- * @return ++ * @return TextColor + */ + @NotNull + public TextColor getColor() { +diff --git a/src/main/java/io/papermc/paper/world/MoonPhase.java b/src/main/java/io/papermc/paper/world/MoonPhase.java +index df05153397b42930cd53d37b30824c7e5f008f7e..ebf70fea04a9d37aa5f2ad8e7d6cef73cd3a4541 100644 +--- a/src/main/java/io/papermc/paper/world/MoonPhase.java ++++ b/src/main/java/io/papermc/paper/world/MoonPhase.java +@@ -5,6 +5,9 @@ import org.jetbrains.annotations.NotNull; + import java.util.HashMap; + import java.util.Map; + ++/** ++ * Moon phase ++ */ + public enum MoonPhase { + FULL_MOON(0L), + WANING_GIBBOUS(1L), +diff --git a/src/main/java/org/bukkit/Fluid.java b/src/main/java/org/bukkit/Fluid.java +index 525ede42137cc27cf20cf713478e85292455676e..a0279fcbfc76ad97a61fc191424e876d517acb46 100644 +--- a/src/main/java/org/bukkit/Fluid.java ++++ b/src/main/java/org/bukkit/Fluid.java +@@ -3,6 +3,9 @@ package org.bukkit; + import java.util.Locale; + import org.jetbrains.annotations.NotNull; + ++/** ++ * Represents a fluid ++ */ + public enum Fluid implements Keyed { + + WATER, +diff --git a/src/main/java/org/bukkit/Nameable.java b/src/main/java/org/bukkit/Nameable.java +index 2acdf2a6d3955923c721222b9da784f3278f6418..737c3b053060e38f6776a5a508948cc300bbe6f4 100644 +--- a/src/main/java/org/bukkit/Nameable.java ++++ b/src/main/java/org/bukkit/Nameable.java +@@ -2,6 +2,9 @@ package org.bukkit; + + import org.jetbrains.annotations.Nullable; + ++/** ++ * Represents something that can be named ++ */ + public interface Nameable { + + // Paper start +diff --git a/src/main/java/org/bukkit/OfflinePlayer.java b/src/main/java/org/bukkit/OfflinePlayer.java +index 3afd5f5c0208a4ee93b5dbfc2aab2b9d2e8a7544..7838731e0e16bdccfb79e74ceb64148f7c52db79 100644 +--- a/src/main/java/org/bukkit/OfflinePlayer.java ++++ b/src/main/java/org/bukkit/OfflinePlayer.java +@@ -9,6 +9,9 @@ import org.bukkit.permissions.ServerOperator; + import org.jetbrains.annotations.NotNull; + import org.jetbrains.annotations.Nullable; + ++/** ++ * Represents an offline player ++ */ + public interface OfflinePlayer extends ServerOperator, AnimalTamer, ConfigurationSerializable { + + /** +diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java +index f24d00951cd6951023f1ff34312ae0438107fc22..3ee71225eb67ec728b414a8cdc0570d48d5603e3 100644 +--- a/src/main/java/org/bukkit/Server.java ++++ b/src/main/java/org/bukkit/Server.java +@@ -1579,6 +1579,9 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi + UnsafeValues getUnsafe(); + + // Spigot start ++ /** ++ * Spigot stuffs ++ */ + public class Spigot { + + @NotNull +diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java +index 379acee1b5f2d06e6a96f3444783f4a29ca24095..ef3011d74ce9acf02d0ee857033816854134ec0e 100644 +--- a/src/main/java/org/bukkit/UnsafeValues.java ++++ b/src/main/java/org/bukkit/UnsafeValues.java +@@ -87,6 +87,8 @@ public interface UnsafeValues { + + /** + * Called once by the version command on first use, then cached. ++ * ++ * @return Paper's VersionFetcher + */ + default com.destroystokyo.paper.util.VersionFetcher getVersionFetcher() { + return new com.destroystokyo.paper.util.VersionFetcher.DummyVersionFetcher(); +@@ -105,6 +107,8 @@ public interface UnsafeValues { + /** + * Return the translation key for the Material, so the client can translate it into the active + * locale when using a {@link net.kyori.adventure.text.TranslatableComponent}. ++ * ++ * @param mat Material to check + * @return the translation key + */ + String getTranslationKey(Material mat); +@@ -112,6 +116,8 @@ public interface UnsafeValues { + /** + * Return the translation key for the Block, so the client can translate it into the active + * locale when using a {@link net.kyori.adventure.text.TranslatableComponent}. ++ * ++ * @param block Block to check + * @return the translation key + */ + String getTranslationKey(org.bukkit.block.Block block); +@@ -120,6 +126,8 @@ public interface UnsafeValues { + * Return the translation key for the EntityType, so the client can translate it into the active + * locale when using a {@link net.kyori.adventure.text.TranslatableComponent}.
+ * This is null, when the EntityType isn't known to NMS (custom entities) ++ * ++ * @param type EntityType to check + * @return the translation key + */ + String getTranslationKey(org.bukkit.entity.EntityType type); +@@ -135,6 +143,8 @@ public interface UnsafeValues { + * Creates and returns the next EntityId available. + *

+ * Use this when sending custom packets, so that there are no collisions on the client or server. ++ * ++ * @return the next available entity id + */ + public int nextEntityId(); + +diff --git a/src/main/java/org/bukkit/WorldBorder.java b/src/main/java/org/bukkit/WorldBorder.java +index afb7b136b461202026290624836446cff9f9e45d..087579fdff09237409c9f80446e7a15a78f9040c 100644 +--- a/src/main/java/org/bukkit/WorldBorder.java ++++ b/src/main/java/org/bukkit/WorldBorder.java +@@ -2,6 +2,9 @@ package org.bukkit; + + import org.jetbrains.annotations.NotNull; + ++/** ++ * Represents a world border ++ */ + public interface WorldBorder { + + /** +diff --git a/src/main/java/org/bukkit/WorldCreator.java b/src/main/java/org/bukkit/WorldCreator.java +index e6a83252f42da31ad38f8dc1beccc7aa2c3f54b8..f3b107210473f1707b051c15771ce3bf2a62f171 100644 +--- a/src/main/java/org/bukkit/WorldCreator.java ++++ b/src/main/java/org/bukkit/WorldCreator.java +@@ -71,6 +71,8 @@ public class WorldCreator { + * + * @param levelName LevelName of the world that will be created + * @param worldKey NamespacedKey of the world that will be created ++ * ++ * @return WorldCreator + */ + @NotNull + public static WorldCreator ofNameAndKey(@NotNull String levelName, @NotNull NamespacedKey worldKey) { +@@ -82,6 +84,8 @@ public class WorldCreator { + * LevelName will be the Key part of the NamespacedKey. + * + * @param worldKey NamespacedKey of the world that will be created ++ * ++ * @return WorldCreator + */ + @NotNull + public static WorldCreator ofKey(@NotNull NamespacedKey worldKey) { +@@ -293,11 +297,8 @@ public class WorldCreator { + * is as follows: + * {"structures": {"structures": {"village": {"salt": 8015723, "spacing": 32, "separation": 8}}}, "layers": [{"block": "stone", "height": 1}, {"block": "grass", "height": 1}], "biome":"plains"} + * +- * @see Custom +- * dimension (scroll to "When the generator ID type is +- * minecraft:flat)" +- * @param generatorSettings The settings that should be used by the +- * generator ++ * @see Custom dimension ++ * @param generatorSettings The settings that should be used by the generator + * @return This object, for chaining + */ + @NotNull +diff --git a/src/main/java/org/bukkit/advancement/AdvancementDisplay.java b/src/main/java/org/bukkit/advancement/AdvancementDisplay.java +index bca3d112e2397b26ba6ccb6cd41e406caae27c5c..f4e076d6f3b05c9de85dcd65b95c1088a094249c 100644 +--- a/src/main/java/org/bukkit/advancement/AdvancementDisplay.java ++++ b/src/main/java/org/bukkit/advancement/AdvancementDisplay.java +@@ -2,6 +2,9 @@ package org.bukkit.advancement; + + import org.jetbrains.annotations.NotNull; + ++/** ++ * Represents an advancement's display ++ */ + public interface AdvancementDisplay { + /** + * Get the title of this advancement +diff --git a/src/main/java/org/bukkit/advancement/FrameType.java b/src/main/java/org/bukkit/advancement/FrameType.java +index d1757f3d456ff9efce26ce8baa1d16d896908cc2..a5db52386e11e4b5511ae417a0e7ac92e001de71 100644 +--- a/src/main/java/org/bukkit/advancement/FrameType.java ++++ b/src/main/java/org/bukkit/advancement/FrameType.java +@@ -3,6 +3,9 @@ package org.bukkit.advancement; + import org.bukkit.ChatColor; + import org.jetbrains.annotations.NotNull; + ++/** ++ * Represents an advancement's display's frame type ++ */ + public enum FrameType { + TASK(ChatColor.GREEN), + CHALLENGE(ChatColor.DARK_PURPLE), +diff --git a/src/main/java/org/bukkit/block/Block.java b/src/main/java/org/bukkit/block/Block.java +index 08e6f1741685f54506c8a4ff29bbd30f62cf8e45..8efd2669bd5e3dfa47ff8fcb858333210eb5c201 100644 +--- a/src/main/java/org/bukkit/block/Block.java ++++ b/src/main/java/org/bukkit/block/Block.java +@@ -183,6 +183,9 @@ public interface Block extends Metadatable { + * {@code int z = (int) ((packed << 10) >> 37);} + *

+ * ++ * @param x X coordinate ++ * @param y Y coordinate ++ * @param z Z coordinate + * @return This block's x, y, and z coordinates packed into a long value + */ + public static long getBlockKey(int x, int y, int z) { +diff --git a/src/main/java/org/bukkit/block/Lidded.java b/src/main/java/org/bukkit/block/Lidded.java +index 30c7df0021df44a411e50636d906d4a1d30fd927..73930312accf6d8c5d71777caa8190a15c2f036d 100644 +--- a/src/main/java/org/bukkit/block/Lidded.java ++++ b/src/main/java/org/bukkit/block/Lidded.java +@@ -1,5 +1,8 @@ + package org.bukkit.block; + ++/** ++ * Represents something that has a lid ++ */ + public interface Lidded { + + /** +diff --git a/src/main/java/org/bukkit/boss/BarColor.java b/src/main/java/org/bukkit/boss/BarColor.java +index e191d9ffe8d6fdeaef77313535a697b6038a0550..2ce3201079701de65c434b8f1e390bed27364370 100644 +--- a/src/main/java/org/bukkit/boss/BarColor.java ++++ b/src/main/java/org/bukkit/boss/BarColor.java +@@ -1,5 +1,8 @@ + package org.bukkit.boss; + ++/** ++ * Bar color ++ */ + public enum BarColor { + PINK, + BLUE, +diff --git a/src/main/java/org/bukkit/boss/BarFlag.java b/src/main/java/org/bukkit/boss/BarFlag.java +index 69e02998d062f5b52ef4e5cdd4dbb29384eb9f3c..0d8f617dc33b828bdadf3e8112b4c545625a55b2 100644 +--- a/src/main/java/org/bukkit/boss/BarFlag.java ++++ b/src/main/java/org/bukkit/boss/BarFlag.java +@@ -1,5 +1,8 @@ + package org.bukkit.boss; + ++/** ++ * Bar flag ++ */ + public enum BarFlag { + + /** +diff --git a/src/main/java/org/bukkit/boss/BarStyle.java b/src/main/java/org/bukkit/boss/BarStyle.java +index 3e499eb77957851ca67ca37bd116c617b44b6478..6907889ba91a32583cf62749a3148d3d2cd93925 100644 +--- a/src/main/java/org/bukkit/boss/BarStyle.java ++++ b/src/main/java/org/bukkit/boss/BarStyle.java +@@ -1,5 +1,8 @@ + package org.bukkit.boss; + ++/** ++ * Boss bar style ++ */ + public enum BarStyle { + /** + * Makes the boss bar solid (no segments) +diff --git a/src/main/java/org/bukkit/boss/BossBar.java b/src/main/java/org/bukkit/boss/BossBar.java +index 70274f2e2a1d6f27c4febd9d5d5fa3ee1b49f100..3b98e6e3e6dea0df5fb9462c78e8c142fde64723 100644 +--- a/src/main/java/org/bukkit/boss/BossBar.java ++++ b/src/main/java/org/bukkit/boss/BossBar.java +@@ -5,6 +5,9 @@ import org.bukkit.entity.Player; + import org.jetbrains.annotations.NotNull; + import org.jetbrains.annotations.Nullable; + ++/** ++ * Represents a boss bar ++ */ + public interface BossBar { + + /** +diff --git a/src/main/java/org/bukkit/command/CommandSender.java b/src/main/java/org/bukkit/command/CommandSender.java +index fb0e608fa92dae99b9eee8fc1cbdf4b91a33e620..ca6d3afd6fa51c0822e289356025b51bc50f55a7 100644 +--- a/src/main/java/org/bukkit/command/CommandSender.java ++++ b/src/main/java/org/bukkit/command/CommandSender.java +@@ -62,6 +62,9 @@ public interface CommandSender extends net.kyori.adventure.audience.Audience, Pe + public String getName(); + + // Spigot start ++ /** ++ * Spigot stuffs ++ */ + public class Spigot { + + /** +diff --git a/src/main/java/org/bukkit/conversations/Conversation.java b/src/main/java/org/bukkit/conversations/Conversation.java +index bf2407c838bc20197802687c150d513f4e86ed2b..ae09abfe9fe2979e89cfb4bb5c9cc0e7760943e7 100644 +--- a/src/main/java/org/bukkit/conversations/Conversation.java ++++ b/src/main/java/org/bukkit/conversations/Conversation.java +@@ -295,6 +295,9 @@ public class Conversation { + } + } + ++ /** ++ * Conversation state ++ */ + public enum ConversationState { + UNSTARTED, + STARTED, +diff --git a/src/main/java/org/bukkit/entity/AbstractArrow.java b/src/main/java/org/bukkit/entity/AbstractArrow.java +index b1d8007eed489aa061c1a6813bcdafc101231e56..eb847e3bb110f73695ba9b4191e69e6ea8a6ffc8 100644 +--- a/src/main/java/org/bukkit/entity/AbstractArrow.java ++++ b/src/main/java/org/bukkit/entity/AbstractArrow.java +@@ -176,6 +176,9 @@ public interface AbstractArrow extends Projectile { + this.setPickupStatus(PickupStatus.valueOf(rule.name())); + } + ++ /** ++ * Pickup rule ++ */ + @Deprecated + enum PickupRule { + DISALLOWED, +diff --git a/src/main/java/org/bukkit/entity/AnimalTamer.java b/src/main/java/org/bukkit/entity/AnimalTamer.java +index 2e17b2d4f759531fbe9ee8e9b00c839186af09ca..9382234722792b5920a2456187e079581c2e2f2a 100644 +--- a/src/main/java/org/bukkit/entity/AnimalTamer.java ++++ b/src/main/java/org/bukkit/entity/AnimalTamer.java +@@ -4,6 +4,9 @@ import java.util.UUID; + import org.jetbrains.annotations.NotNull; + import org.jetbrains.annotations.Nullable; + ++/** ++ * Represents an animal tamer ++ */ + public interface AnimalTamer { + + /** +diff --git a/src/main/java/org/bukkit/entity/ArmorStand.java b/src/main/java/org/bukkit/entity/ArmorStand.java +index 2f0c6af7fa6688a98d6aa0bd3f0e6556af8330d0..b38c69482e3112e0cd626bcb17f4523c541b748f 100644 +--- a/src/main/java/org/bukkit/entity/ArmorStand.java ++++ b/src/main/java/org/bukkit/entity/ArmorStand.java +@@ -7,6 +7,9 @@ import org.bukkit.util.EulerAngle; + import org.jetbrains.annotations.NotNull; + import org.jetbrains.annotations.Nullable; + ++/** ++ * Represents an armor stand ++ */ + public interface ArmorStand extends LivingEntity { + + /** +diff --git a/src/main/java/org/bukkit/entity/Arrow.java b/src/main/java/org/bukkit/entity/Arrow.java +index ec8443b67014c0129256c9227cc89686422b9217..6b41e09d6ed075aae5455929b5b29efb2c6287f6 100644 +--- a/src/main/java/org/bukkit/entity/Arrow.java ++++ b/src/main/java/org/bukkit/entity/Arrow.java +@@ -8,6 +8,9 @@ import org.bukkit.potion.PotionEffectType; + import org.jetbrains.annotations.NotNull; + import org.jetbrains.annotations.Nullable; + ++/** ++ * Represents an arrow ++ */ + public interface Arrow extends AbstractArrow { + + /** +diff --git a/src/main/java/org/bukkit/entity/Dolphin.java b/src/main/java/org/bukkit/entity/Dolphin.java +index f00eaadcdde7ceef95def2d8ec6eb63a76c177bd..a4a645799d82c730e3280519facf1347d26a859f 100644 +--- a/src/main/java/org/bukkit/entity/Dolphin.java ++++ b/src/main/java/org/bukkit/entity/Dolphin.java +@@ -1,3 +1,6 @@ + package org.bukkit.entity; + ++/** ++ * Represents a dolphin ++ */ + public interface Dolphin extends WaterMob { } +diff --git a/src/main/java/org/bukkit/entity/DragonFireball.java b/src/main/java/org/bukkit/entity/DragonFireball.java +index 6c475a3723721b33bb7709d8c1bbf487a10f9bbe..210d955e9bbb669c8ce644c935c1607ae8e7419b 100644 +--- a/src/main/java/org/bukkit/entity/DragonFireball.java ++++ b/src/main/java/org/bukkit/entity/DragonFireball.java +@@ -1,3 +1,6 @@ + package org.bukkit.entity; + ++/** ++ * Represents a dragon's fireball ++ */ + public interface DragonFireball extends Fireball {} +diff --git a/src/main/java/org/bukkit/entity/Endermite.java b/src/main/java/org/bukkit/entity/Endermite.java +index d9be83961b28b927a587f6dbb339b531520e4865..1ff4c5e283ac05c405c09bd4b853066452614696 100644 +--- a/src/main/java/org/bukkit/entity/Endermite.java ++++ b/src/main/java/org/bukkit/entity/Endermite.java +@@ -1,5 +1,8 @@ + package org.bukkit.entity; + ++/** ++ * Represents an endermite ++ */ + public interface Endermite extends Monster { + + /** +diff --git a/src/main/java/org/bukkit/entity/Entity.java b/src/main/java/org/bukkit/entity/Entity.java +index 38c6ecba4a6090ee42180ff52db42bac8e7f95d7..b47e31d2b9b41b39b46892fe10bf36d82c5d8e1b 100644 +--- a/src/main/java/org/bukkit/entity/Entity.java ++++ b/src/main/java/org/bukkit/entity/Entity.java +@@ -622,6 +622,9 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent + Pose getPose(); + + // Spigot start ++ /** ++ * Spigot stuffs ++ */ + public class Spigot extends CommandSender.Spigot { + + } +@@ -671,36 +674,50 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent + + /** + * Check if entity is in rain ++ * ++ * @return True if entity is in rain + */ + public boolean isInRain(); + + /** + * Check if entity is in bubble column ++ * ++ * @return True if entity is in bubble column + */ + public boolean isInBubbleColumn(); + + /** + * Check if entity is in water or rain ++ * ++ * @return True if entity is in water or rain + */ + public boolean isInWaterOrRain(); + + /** + * Check if entity is in water or bubble column ++ * ++ * @return True if entity is in water or bubble column + */ + public boolean isInWaterOrBubbleColumn(); + + /** + * Check if entity is in water or rain or bubble column ++ * ++ * @return True if entity is in water or rain or bubble column + */ + public boolean isInWaterOrRainOrBubbleColumn(); + + /** + * Check if entity is in lava ++ * ++ * @return True if entity is in lava + */ + public boolean isInLava(); + + /** + * Check if entity is inside a ticking chunk ++ * ++ * @return True if entity is ticking + */ + public boolean isTicking(); + // Paper end +diff --git a/src/main/java/org/bukkit/entity/EntityType.java b/src/main/java/org/bukkit/entity/EntityType.java +index 692b75eb78405874077c850bfc72e247ccc80860..31fc511edc33635438e93d3c14292305ac30a38f 100644 +--- a/src/main/java/org/bukkit/entity/EntityType.java ++++ b/src/main/java/org/bukkit/entity/EntityType.java +@@ -20,6 +20,9 @@ import org.jetbrains.annotations.Contract; + import org.jetbrains.annotations.NotNull; + import org.jetbrains.annotations.Nullable; + ++/** ++ * Entity type ++ */ + public enum EntityType implements Keyed { + + // These strings MUST match the strings in nms.EntityTypes and are case sensitive. +diff --git a/src/main/java/org/bukkit/entity/Firework.java b/src/main/java/org/bukkit/entity/Firework.java +index d616d5941b3c7b85e350e845901da798601b9a3c..14bdddb7ced9c4cd92a8ad96d97a08a6ed4c25bf 100644 +--- a/src/main/java/org/bukkit/entity/Firework.java ++++ b/src/main/java/org/bukkit/entity/Firework.java +@@ -3,6 +3,9 @@ package org.bukkit.entity; + import org.bukkit.inventory.meta.FireworkMeta; + import org.jetbrains.annotations.NotNull; + ++/** ++ * Represents a firework ++ */ + public interface Firework extends Projectile { + + /** +diff --git a/src/main/java/org/bukkit/entity/Guardian.java b/src/main/java/org/bukkit/entity/Guardian.java +index 4da9f3c5f1423bf8f9eeb490736cabf027853e60..082e90859e6c965029606d7d395673a81bff2cb4 100644 +--- a/src/main/java/org/bukkit/entity/Guardian.java ++++ b/src/main/java/org/bukkit/entity/Guardian.java +@@ -1,5 +1,8 @@ + package org.bukkit.entity; + ++/** ++ * Represents a guardian ++ */ + public interface Guardian extends Monster { + + /** +diff --git a/src/main/java/org/bukkit/entity/LightningStrike.java b/src/main/java/org/bukkit/entity/LightningStrike.java +index 2c81a3f685588431a3c7675c84b35a28975232af..efb308c82580722e5106d5d1c7512d99c38e536a 100644 +--- a/src/main/java/org/bukkit/entity/LightningStrike.java ++++ b/src/main/java/org/bukkit/entity/LightningStrike.java +@@ -15,6 +15,9 @@ public interface LightningStrike extends Entity { + public boolean isEffect(); + + // Spigot start ++ /** ++ * Spigot stuffs ++ */ + public class Spigot extends Entity.Spigot { + + /* +diff --git a/src/main/java/org/bukkit/entity/Panda.java b/src/main/java/org/bukkit/entity/Panda.java +index a6a7429ed2e1eefb2b12b7480ed74fcc3963a864..e8027e1d505dda6effbb1698550016e87b2e581f 100644 +--- a/src/main/java/org/bukkit/entity/Panda.java ++++ b/src/main/java/org/bukkit/entity/Panda.java +@@ -37,6 +37,9 @@ public interface Panda extends Animals { + */ + void setHiddenGene(@NotNull Gene gene); + ++ /** ++ * Panda gene type ++ */ + public enum Gene { + + NORMAL(false), +diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java +index d6b6508fd7ab245f657be262c54ae6dfa20415e7..25252bad38ca35b81b225b57c4b6ce77ad6de166 100644 +--- a/src/main/java/org/bukkit/entity/Player.java ++++ b/src/main/java/org/bukkit/entity/Player.java +@@ -1961,6 +1961,8 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + void resetCooldown(); + + /** ++ * @param ClientOption type ++ * @param option ClientOption + * @return the client option value of the player + */ + @NotNull +@@ -2000,6 +2002,9 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + // Paper end + + // Spigot start ++ /** ++ * Spigot stuffs ++ */ + public class Spigot extends Entity.Spigot { + + /** +diff --git a/src/main/java/org/bukkit/entity/Rabbit.java b/src/main/java/org/bukkit/entity/Rabbit.java +index e88154283a8ef594e160d25005870053de15568a..24c81708dc6691e220e278e92c07b9d51072fb88 100644 +--- a/src/main/java/org/bukkit/entity/Rabbit.java ++++ b/src/main/java/org/bukkit/entity/Rabbit.java +@@ -2,6 +2,9 @@ package org.bukkit.entity; + + import org.jetbrains.annotations.NotNull; + ++/** ++ * Represents a rabbit ++ */ + public interface Rabbit extends Animals { + + /** +diff --git a/src/main/java/org/bukkit/entity/Raider.java b/src/main/java/org/bukkit/entity/Raider.java +index 9a99b8ca1ec9c3c88b29275c88b1221e1b22bcef..f1763f75d5f223ef70b968e4633616731b727df5 100644 +--- a/src/main/java/org/bukkit/entity/Raider.java ++++ b/src/main/java/org/bukkit/entity/Raider.java +@@ -3,6 +3,9 @@ package org.bukkit.entity; + import org.bukkit.block.Block; + import org.jetbrains.annotations.Nullable; + ++/** ++ * Represents a raider entity ++ */ + public interface Raider extends Monster { + + /** +diff --git a/src/main/java/org/bukkit/entity/Shulker.java b/src/main/java/org/bukkit/entity/Shulker.java +index 010e1f9c3567a2fe8297fe04fcf7b75df0279eca..bd40fdfbcd9a34c7cde5f4dc34cba53aec53c485 100644 +--- a/src/main/java/org/bukkit/entity/Shulker.java ++++ b/src/main/java/org/bukkit/entity/Shulker.java +@@ -4,6 +4,9 @@ import org.bukkit.block.BlockFace; + import org.bukkit.material.Colorable; + import org.jetbrains.annotations.NotNull; + ++/** ++ * Represents a shulker ++ */ + public interface Shulker extends Golem, Colorable { + + /** +diff --git a/src/main/java/org/bukkit/entity/ShulkerBullet.java b/src/main/java/org/bukkit/entity/ShulkerBullet.java +index 4623e0d767b343cbdc6fcf20b3b2ff7ff14863cf..ca3f98a8272bab3c9f57f59b077b206c6503de80 100644 +--- a/src/main/java/org/bukkit/entity/ShulkerBullet.java ++++ b/src/main/java/org/bukkit/entity/ShulkerBullet.java +@@ -2,6 +2,9 @@ package org.bukkit.entity; + + import org.jetbrains.annotations.Nullable; + ++/** ++ * Represents a shulker bullet ++ */ + public interface ShulkerBullet extends Projectile { + + /** +diff --git a/src/main/java/org/bukkit/entity/Skeleton.java b/src/main/java/org/bukkit/entity/Skeleton.java +index 684477b894e52ff33f9fce2edf76e58c292dd75e..581abc69290ca14b8e64f50fdf5a49c14be13940 100644 +--- a/src/main/java/org/bukkit/entity/Skeleton.java ++++ b/src/main/java/org/bukkit/entity/Skeleton.java +@@ -27,7 +27,9 @@ public interface Skeleton extends Monster, RangedEntity { // Paper + @Contract("_ -> fail") + public void setSkeletonType(SkeletonType type); + +- /* ++ /** ++ * Skeleton type ++ * + * @deprecated classes are different types + */ + @Deprecated +diff --git a/src/main/java/org/bukkit/entity/Tameable.java b/src/main/java/org/bukkit/entity/Tameable.java +index 65e68da98ab66ed781bce2f0dbe0913be48d2990..cb708ae66f60a36ac0f529614743e33511e4bd90 100644 +--- a/src/main/java/org/bukkit/entity/Tameable.java ++++ b/src/main/java/org/bukkit/entity/Tameable.java +@@ -3,6 +3,9 @@ package org.bukkit.entity; + import org.jetbrains.annotations.NotNull; + import org.jetbrains.annotations.Nullable; + ++/** ++ * Represents a tameable entity ++ */ + public interface Tameable extends Animals { + + /** +diff --git a/src/main/java/org/bukkit/entity/ThrowableProjectile.java b/src/main/java/org/bukkit/entity/ThrowableProjectile.java +index ceb3e2c5117740ce284e893fff8e41a002d78649..fab5c3c90f55c113cae2bca2354a94e88c1aaece 100644 +--- a/src/main/java/org/bukkit/entity/ThrowableProjectile.java ++++ b/src/main/java/org/bukkit/entity/ThrowableProjectile.java +@@ -3,6 +3,9 @@ package org.bukkit.entity; + import org.bukkit.inventory.ItemStack; + import org.jetbrains.annotations.NotNull; + ++/** ++ * Represents a throwable projectile ++ */ + public interface ThrowableProjectile extends Projectile { + + /** +diff --git a/src/main/java/org/bukkit/entity/minecart/CommandMinecart.java b/src/main/java/org/bukkit/entity/minecart/CommandMinecart.java +index 91cab8b13d5bba34007f124838b32a1df58c5ac7..078228106b299a8e38495f7f881d38de4f87bc95 100644 +--- a/src/main/java/org/bukkit/entity/minecart/CommandMinecart.java ++++ b/src/main/java/org/bukkit/entity/minecart/CommandMinecart.java +@@ -4,6 +4,9 @@ import org.bukkit.entity.Minecart; + import org.jetbrains.annotations.NotNull; + import org.jetbrains.annotations.Nullable; + ++/** ++ * Represents a minecart with command block ++ */ + public interface CommandMinecart extends Minecart { + + /** +diff --git a/src/main/java/org/bukkit/event/Cancellable.java b/src/main/java/org/bukkit/event/Cancellable.java +index 799b0b0f3cd842edd2bc1005c2e848f9a0b7b43c..7f02db9d1660b7b33d8c3825114b5040e5461696 100644 +--- a/src/main/java/org/bukkit/event/Cancellable.java ++++ b/src/main/java/org/bukkit/event/Cancellable.java +@@ -1,5 +1,8 @@ + package org.bukkit.event; + ++/** ++ * Represents a cancellable event ++ */ + public interface Cancellable { + + /** +diff --git a/src/main/java/org/bukkit/event/Event.java b/src/main/java/org/bukkit/event/Event.java +index 8ec56cd6b8e0f5c5dd8c7c88b4671e18dcf109d0..740bbce54140480039a637c9fee6ccb3f4da1027 100644 +--- a/src/main/java/org/bukkit/event/Event.java ++++ b/src/main/java/org/bukkit/event/Event.java +@@ -95,6 +95,9 @@ public abstract class Event { + return async; + } + ++ /** ++ * Event result ++ */ + public enum Result { + + /** +diff --git a/src/main/java/org/bukkit/event/EventException.java b/src/main/java/org/bukkit/event/EventException.java +index 84638e852501cc804c13c188c90c38b163657c36..a32f7d86407a36d34932101a8b46751c5bed0d75 100644 +--- a/src/main/java/org/bukkit/event/EventException.java ++++ b/src/main/java/org/bukkit/event/EventException.java +@@ -1,5 +1,8 @@ + package org.bukkit.event; + ++/** ++ * Event exception ++ */ + public class EventException extends Exception { + private static final long serialVersionUID = 3532808232324183999L; + private final Throwable cause; +diff --git a/src/main/java/org/bukkit/event/block/Action.java b/src/main/java/org/bukkit/event/block/Action.java +index 25d26e3fe713311e66d7e634a6c32af61f4cef59..2825263c102d3f9ed37f6884e09ec5efb8105fb9 100644 +--- a/src/main/java/org/bukkit/event/block/Action.java ++++ b/src/main/java/org/bukkit/event/block/Action.java +@@ -1,5 +1,8 @@ + package org.bukkit.event.block; + ++/** ++ * Block action ++ */ + public enum Action { + + /** +diff --git a/src/main/java/org/bukkit/event/block/CauldronLevelChangeEvent.java b/src/main/java/org/bukkit/event/block/CauldronLevelChangeEvent.java +index 4aaa78afdda2d2351f8c4ed46a52e0cf77ec437c..4d2d821003840b7fc1ca412d71b841341c7b51ec 100644 +--- a/src/main/java/org/bukkit/event/block/CauldronLevelChangeEvent.java ++++ b/src/main/java/org/bukkit/event/block/CauldronLevelChangeEvent.java +@@ -8,6 +8,9 @@ import org.bukkit.event.HandlerList; + import org.jetbrains.annotations.NotNull; + import org.jetbrains.annotations.Nullable; + ++/** ++ * Called when a cauldron changes fluid level ++ */ + public class CauldronLevelChangeEvent extends BlockEvent implements Cancellable { + + private static final HandlerList handlers = new HandlerList(); +@@ -75,6 +78,9 @@ public class CauldronLevelChangeEvent extends BlockEvent implements Cancellable + return handlers; + } + ++ /** ++ * Cauldron level change reason ++ */ + public enum ChangeReason { + /** + * Player emptying the cauldron by filling their bucket. +diff --git a/src/main/java/org/bukkit/event/entity/EntityTransformEvent.java b/src/main/java/org/bukkit/event/entity/EntityTransformEvent.java +index 76ad715961c1b373ba276c61ced728affd4dbec1..27ce18199100b181a0502bc6de12cc7dfc430f86 100644 +--- a/src/main/java/org/bukkit/event/entity/EntityTransformEvent.java ++++ b/src/main/java/org/bukkit/event/entity/EntityTransformEvent.java +@@ -79,6 +79,9 @@ public class EntityTransformEvent extends EntityEvent implements Cancellable { + return handlers; + } + ++ /** ++ * Entity transform reason ++ */ + public enum TransformReason { + /** + * When a zombie gets cured and a villager is spawned. +diff --git a/src/main/java/org/bukkit/event/entity/EntityUnleashEvent.java b/src/main/java/org/bukkit/event/entity/EntityUnleashEvent.java +index e0e068799a1868c8e561869015f41f553ef4fbdb..9fa0ba2f81a6724491c22446c87135841d099fb0 100644 +--- a/src/main/java/org/bukkit/event/entity/EntityUnleashEvent.java ++++ b/src/main/java/org/bukkit/event/entity/EntityUnleashEvent.java +@@ -66,6 +66,9 @@ public class EntityUnleashEvent extends EntityEvent { + return handlers; + } + ++ /** ++ * Entity unleash reason ++ */ + public enum UnleashReason { + /** + * When the entity's leashholder has died or logged out, and so is +diff --git a/src/main/java/org/bukkit/event/entity/ItemMergeEvent.java b/src/main/java/org/bukkit/event/entity/ItemMergeEvent.java +index e378cc29b47238fe12ae9aff5171edcff6b456f5..f5b9fd0b6f9512e425e1cc6103f80ba198c6db5b 100644 +--- a/src/main/java/org/bukkit/event/entity/ItemMergeEvent.java ++++ b/src/main/java/org/bukkit/event/entity/ItemMergeEvent.java +@@ -5,6 +5,9 @@ import org.bukkit.event.Cancellable; + import org.bukkit.event.HandlerList; + import org.jetbrains.annotations.NotNull; + ++/** ++ * Called when an item merges with another ++ */ + public class ItemMergeEvent extends EntityEvent implements Cancellable { + + private static final HandlerList handlers = new HandlerList(); +diff --git a/src/main/java/org/bukkit/event/entity/VillagerCareerChangeEvent.java b/src/main/java/org/bukkit/event/entity/VillagerCareerChangeEvent.java +index b550029cf3a7bc55137851eab734abab8965306d..d070baf9587edccdd95204771f59491f5c4ba10d 100644 +--- a/src/main/java/org/bukkit/event/entity/VillagerCareerChangeEvent.java ++++ b/src/main/java/org/bukkit/event/entity/VillagerCareerChangeEvent.java +@@ -6,6 +6,9 @@ import org.bukkit.event.Cancellable; + import org.bukkit.event.HandlerList; + import org.jetbrains.annotations.NotNull; + ++/** ++ * Called when a villager changes career ++ */ + public class VillagerCareerChangeEvent extends EntityEvent implements Cancellable { + + private static final HandlerList handlers = new HandlerList(); +diff --git a/src/main/java/org/bukkit/event/inventory/InventoryCloseEvent.java b/src/main/java/org/bukkit/event/inventory/InventoryCloseEvent.java +index 21ad8888c0e403bfc63518502577d651c02dda05..295cbe558ace7b55c80fc84256808d2f505ea734 100644 +--- a/src/main/java/org/bukkit/event/inventory/InventoryCloseEvent.java ++++ b/src/main/java/org/bukkit/event/inventory/InventoryCloseEvent.java +@@ -18,6 +18,9 @@ public class InventoryCloseEvent extends InventoryEvent { + return reason; + } + ++ /** ++ * Inventory close reason ++ */ + public enum Reason { + /** + * Unknown reason +diff --git a/src/main/java/org/bukkit/event/inventory/InventoryType.java b/src/main/java/org/bukkit/event/inventory/InventoryType.java +index ca660dde2010098e8c77141d05c2d4d5470adf81..129eac25da4f27489038fb15ab1aeecb172b60cc 100644 +--- a/src/main/java/org/bukkit/event/inventory/InventoryType.java ++++ b/src/main/java/org/bukkit/event/inventory/InventoryType.java +@@ -185,6 +185,9 @@ public enum InventoryType { + return isCreatable; + } + ++ /** ++ * Inventory slot type ++ */ + public enum SlotType { + /** + * A result slot in a furnace or crafting inventory. +diff --git a/src/main/java/org/bukkit/event/inventory/PrepareItemCraftEvent.java b/src/main/java/org/bukkit/event/inventory/PrepareItemCraftEvent.java +index efd29d198dd847e22988963f70ad57e1b810aeb7..b5de6e77a030057f923a5d82ea0054b9e138009d 100644 +--- a/src/main/java/org/bukkit/event/inventory/PrepareItemCraftEvent.java ++++ b/src/main/java/org/bukkit/event/inventory/PrepareItemCraftEvent.java +@@ -7,6 +7,9 @@ import org.bukkit.inventory.Recipe; + import org.jetbrains.annotations.NotNull; + import org.jetbrains.annotations.Nullable; + ++/** ++ * Prepare item craft event ++ */ + public class PrepareItemCraftEvent extends InventoryEvent { + private static final HandlerList handlers = new HandlerList(); + private boolean repair; +diff --git a/src/main/java/org/bukkit/event/player/PlayerQuitEvent.java b/src/main/java/org/bukkit/event/player/PlayerQuitEvent.java +index b6016aa1e91863efc252eecab69ade6f54c89f27..e43acfb570036adb73d195136573620378cc6a61 100644 +--- a/src/main/java/org/bukkit/event/player/PlayerQuitEvent.java ++++ b/src/main/java/org/bukkit/event/player/PlayerQuitEvent.java +@@ -94,6 +94,9 @@ public class PlayerQuitEvent extends PlayerEvent { + return this.reason; + } + ++ /** ++ * Player quit reason ++ */ + public enum QuitReason { + /** + * The player left on their own behalf. +diff --git a/src/main/java/org/bukkit/event/player/PlayerTeleportEvent.java b/src/main/java/org/bukkit/event/player/PlayerTeleportEvent.java +index 553d7740489fe729166c8ca8ef8c7834db3663ad..4a2d61912ffed137b2b3e4cc4d9b32a11207f6ba 100644 +--- a/src/main/java/org/bukkit/event/player/PlayerTeleportEvent.java ++++ b/src/main/java/org/bukkit/event/player/PlayerTeleportEvent.java +@@ -33,6 +33,9 @@ public class PlayerTeleportEvent extends PlayerMoveEvent { + return cause; + } + ++ /** ++ * Player teleport cause ++ */ + public enum TeleportCause { + /** + * Indicates the teleporation was caused by a player throwing an Ender +diff --git a/src/main/java/org/bukkit/event/raid/RaidStopEvent.java b/src/main/java/org/bukkit/event/raid/RaidStopEvent.java +index 9e852ac973d7a38c075249360be483ed0e5f5ac6..55db1a074144c709489d7f6a4e353b8fd94d312e 100644 +--- a/src/main/java/org/bukkit/event/raid/RaidStopEvent.java ++++ b/src/main/java/org/bukkit/event/raid/RaidStopEvent.java +@@ -40,6 +40,9 @@ public class RaidStopEvent extends RaidEvent { + return handlers; + } + ++ /** ++ * Raid stop reason ++ */ + public enum Reason { + + /** +diff --git a/src/main/java/org/bukkit/event/weather/LightningStrikeEvent.java b/src/main/java/org/bukkit/event/weather/LightningStrikeEvent.java +index 418f9391d86fff0d0a75da0574edccbb29aa9931..921d964d7e40e7710b5a5db18bd9329ca40c1ece 100644 +--- a/src/main/java/org/bukkit/event/weather/LightningStrikeEvent.java ++++ b/src/main/java/org/bukkit/event/weather/LightningStrikeEvent.java +@@ -67,6 +67,9 @@ public class LightningStrikeEvent extends WeatherEvent implements Cancellable { + return handlers; + } + ++ /** ++ * Lightning strike cause ++ */ + public enum Cause { + /** + * Triggered by the /summon command. +diff --git a/src/main/java/org/bukkit/help/HelpTopicComparator.java b/src/main/java/org/bukkit/help/HelpTopicComparator.java +index 75bb69283f509e8f4fec772714a509a51be9de19..e156847f5b7b86155a7a0a0b8cefd8ac1530171e 100644 +--- a/src/main/java/org/bukkit/help/HelpTopicComparator.java ++++ b/src/main/java/org/bukkit/help/HelpTopicComparator.java +@@ -31,6 +31,9 @@ public final class HelpTopicComparator implements Comparator { + return tnc.compare(lhs.getName(), rhs.getName()); + } + ++ /** ++ * Topic name comparator ++ */ + public static final class TopicNameComparator implements Comparator { + private TopicNameComparator(){} + +diff --git a/src/main/java/org/bukkit/inventory/ArmoredHorseInventory.java b/src/main/java/org/bukkit/inventory/ArmoredHorseInventory.java +index 163ffe8ff76ded6265d865901d5110fb6a56950d..36145294db34d273bb767cc928453b765a30e9db 100644 +--- a/src/main/java/org/bukkit/inventory/ArmoredHorseInventory.java ++++ b/src/main/java/org/bukkit/inventory/ArmoredHorseInventory.java +@@ -2,6 +2,9 @@ package org.bukkit.inventory; + + import org.jetbrains.annotations.Nullable; + ++/** ++ * Represents an armored horse's inventory ++ */ + public interface ArmoredHorseInventory extends AbstractHorseInventory { + + /** +diff --git a/src/main/java/org/bukkit/inventory/EquipmentSlot.java b/src/main/java/org/bukkit/inventory/EquipmentSlot.java +index 1e7d77118a55ca9db99eabb94894e6ef3409946b..ad7db4407c83b19bc8ecc9b849152af42d5c4ddb 100644 +--- a/src/main/java/org/bukkit/inventory/EquipmentSlot.java ++++ b/src/main/java/org/bukkit/inventory/EquipmentSlot.java +@@ -1,5 +1,8 @@ + package org.bukkit.inventory; + ++/** ++ * Equipment slot ++ */ + public enum EquipmentSlot { + + HAND, +diff --git a/src/main/java/org/bukkit/inventory/InventoryHolder.java b/src/main/java/org/bukkit/inventory/InventoryHolder.java +index c7b17eabf07b829a02afe7c1f27a5127b6bfea70..d4e2bcf8ce8fc2af851b471490147f0092ea456a 100644 +--- a/src/main/java/org/bukkit/inventory/InventoryHolder.java ++++ b/src/main/java/org/bukkit/inventory/InventoryHolder.java +@@ -2,6 +2,9 @@ package org.bukkit.inventory; + + import org.jetbrains.annotations.NotNull; + ++/** ++ * Represents an inventory holder ++ */ + public interface InventoryHolder { + + /** +diff --git a/src/main/java/org/bukkit/inventory/ItemFactory.java b/src/main/java/org/bukkit/inventory/ItemFactory.java +index 39323b3151c733392333858a2dbf1f3f8637341e..b2af5217a74266917365c3bf216a780b95c833bd 100644 +--- a/src/main/java/org/bukkit/inventory/ItemFactory.java ++++ b/src/main/java/org/bukkit/inventory/ItemFactory.java +@@ -148,6 +148,7 @@ public interface ItemFactory { + * Creates a hover event for the given item. + * + * @param item The item ++ * @param op Unary operator + * @return A hover event + */ + @NotNull +@@ -188,7 +189,7 @@ public interface ItemFactory { + /** + * Creates a {@link net.md_5.bungee.api.chat.hover.content.Content} of that ItemStack for displaying. + * +- * @param itemStack ++ * @param itemStack ItemStack to check + * @return the {@link net.md_5.bungee.api.chat.hover.content.Content} of that ItemStack + */ + @NotNull +diff --git a/src/main/java/org/bukkit/inventory/SaddledHorseInventory.java b/src/main/java/org/bukkit/inventory/SaddledHorseInventory.java +index 7944f26a3e2a92601c3be0e55c00c39cc16cf177..8e7bb66c96d34b73959c0653b2a8e7b422da35fe 100644 +--- a/src/main/java/org/bukkit/inventory/SaddledHorseInventory.java ++++ b/src/main/java/org/bukkit/inventory/SaddledHorseInventory.java +@@ -1,3 +1,6 @@ + package org.bukkit.inventory; + ++/** ++ * Represents a saddled horse's inventory ++ */ + public interface SaddledHorseInventory extends AbstractHorseInventory {} +diff --git a/src/main/java/org/bukkit/inventory/meta/BannerMeta.java b/src/main/java/org/bukkit/inventory/meta/BannerMeta.java +index 4739d2ecc26e7e4adc1b297013da98e12fe58783..45ebb3ca8d628b708419bd2beedd94ee4c819b8a 100644 +--- a/src/main/java/org/bukkit/inventory/meta/BannerMeta.java ++++ b/src/main/java/org/bukkit/inventory/meta/BannerMeta.java +@@ -6,6 +6,9 @@ import org.bukkit.block.banner.Pattern; + import org.jetbrains.annotations.NotNull; + import org.jetbrains.annotations.Nullable; + ++/** ++ * Represents metadata on a banner ++ */ + public interface BannerMeta extends ItemMeta { + + /** +diff --git a/src/main/java/org/bukkit/inventory/meta/BlockDataMeta.java b/src/main/java/org/bukkit/inventory/meta/BlockDataMeta.java +index 473c72dcd34d3f6be72e2ab87c5af51819a00e33..a73b59f40eb3c4d94074154591f9f6885fb287ca 100644 +--- a/src/main/java/org/bukkit/inventory/meta/BlockDataMeta.java ++++ b/src/main/java/org/bukkit/inventory/meta/BlockDataMeta.java +@@ -4,6 +4,9 @@ import org.bukkit.Material; + import org.bukkit.block.data.BlockData; + import org.jetbrains.annotations.NotNull; + ++/** ++ * Represents metadata on a block ++ */ + public interface BlockDataMeta extends ItemMeta { + + /** +diff --git a/src/main/java/org/bukkit/inventory/meta/BlockStateMeta.java b/src/main/java/org/bukkit/inventory/meta/BlockStateMeta.java +index e7d905b1146b2bdd2da5bdeb6bf3541fb181d59e..1fab68c9de96b0d362ebf85fd675cc19099aefa1 100644 +--- a/src/main/java/org/bukkit/inventory/meta/BlockStateMeta.java ++++ b/src/main/java/org/bukkit/inventory/meta/BlockStateMeta.java +@@ -4,6 +4,9 @@ package org.bukkit.inventory.meta; + import org.bukkit.block.BlockState; + import org.jetbrains.annotations.NotNull; + ++/** ++ * Represents metadata on a blockstate ++ */ + public interface BlockStateMeta extends ItemMeta { + + /** +diff --git a/src/main/java/org/bukkit/inventory/meta/BookMeta.java b/src/main/java/org/bukkit/inventory/meta/BookMeta.java +index 4947251f347d83fa326a67735293401c10d87ba4..248cd6faa72a91ceaf6f74d06c05d05bd26f5fbc 100644 +--- a/src/main/java/org/bukkit/inventory/meta/BookMeta.java ++++ b/src/main/java/org/bukkit/inventory/meta/BookMeta.java +@@ -315,6 +315,9 @@ public interface BookMeta extends ItemMeta, net.kyori.adventure.inventory.Book { + BookMeta clone(); + + // Spigot start ++ /** ++ * Spigot stuffs ++ */ + public class Spigot { + + /** +diff --git a/src/main/java/org/bukkit/inventory/meta/CrossbowMeta.java b/src/main/java/org/bukkit/inventory/meta/CrossbowMeta.java +index 35c6594fd1040a1af1029e7260e5e3a9307b107d..47975b24ffa01c9872f6e910d14e1c8e0d0481b9 100644 +--- a/src/main/java/org/bukkit/inventory/meta/CrossbowMeta.java ++++ b/src/main/java/org/bukkit/inventory/meta/CrossbowMeta.java +@@ -5,6 +5,9 @@ import org.bukkit.inventory.ItemStack; + import org.jetbrains.annotations.NotNull; + import org.jetbrains.annotations.Nullable; + ++/** ++ * Represents metadata on a crossbow ++ */ + public interface CrossbowMeta extends ItemMeta { + + /** +diff --git a/src/main/java/org/bukkit/inventory/meta/KnowledgeBookMeta.java b/src/main/java/org/bukkit/inventory/meta/KnowledgeBookMeta.java +index 736c60c71d112e8c017473a93091b4e5336a996f..88c7b311128d605c8d33e1b075795a3a1a434fa5 100644 +--- a/src/main/java/org/bukkit/inventory/meta/KnowledgeBookMeta.java ++++ b/src/main/java/org/bukkit/inventory/meta/KnowledgeBookMeta.java +@@ -4,6 +4,9 @@ import java.util.List; + import org.bukkit.NamespacedKey; + import org.jetbrains.annotations.NotNull; + ++/** ++ * Represents metadata on a knowledge book ++ */ + public interface KnowledgeBookMeta extends ItemMeta { + + /** +diff --git a/src/main/java/org/bukkit/material/CocoaPlant.java b/src/main/java/org/bukkit/material/CocoaPlant.java +index b1b1c729d182b676d8ea69a8d3c942c6820863dd..222c2ae29bc150bbc44c74885b6565911a666911 100644 +--- a/src/main/java/org/bukkit/material/CocoaPlant.java ++++ b/src/main/java/org/bukkit/material/CocoaPlant.java +@@ -12,6 +12,9 @@ import org.bukkit.block.BlockFace; + @Deprecated + public class CocoaPlant extends MaterialData implements Directional, Attachable { + ++ /** ++ * Cocoa plant size ++ */ + public enum CocoaPlantSize { + SMALL, + MEDIUM, +diff --git a/src/main/java/org/bukkit/material/Directional.java b/src/main/java/org/bukkit/material/Directional.java +index 8c1c7b0a258bd4e601955827c4f5a72b81a60db2..f188563dd0db1d7e1dab5e1cce5d76339061df3e 100644 +--- a/src/main/java/org/bukkit/material/Directional.java ++++ b/src/main/java/org/bukkit/material/Directional.java +@@ -3,6 +3,9 @@ package org.bukkit.material; + import org.bukkit.block.BlockFace; + import org.jetbrains.annotations.NotNull; + ++/** ++ * Represents something that can face a direction ++ */ + public interface Directional { + + /** +diff --git a/src/main/java/org/bukkit/material/Openable.java b/src/main/java/org/bukkit/material/Openable.java +index 0ae54f973d11df74abb3105cf9226afb130b4f33..6541bca9c6c4ccedf059d2297b54b738588a02dc 100644 +--- a/src/main/java/org/bukkit/material/Openable.java ++++ b/src/main/java/org/bukkit/material/Openable.java +@@ -1,5 +1,8 @@ + package org.bukkit.material; + ++/** ++ * Represents something that can be opened ++ */ + public interface Openable { + + /** +diff --git a/src/main/java/org/bukkit/material/PressureSensor.java b/src/main/java/org/bukkit/material/PressureSensor.java +index de20bd39c532e94a11536a67c1af71bea203aedc..aa14be496bfe05bf3882f8ac50ef88b8ad655302 100644 +--- a/src/main/java/org/bukkit/material/PressureSensor.java ++++ b/src/main/java/org/bukkit/material/PressureSensor.java +@@ -1,5 +1,8 @@ + package org.bukkit.material; + ++/** ++ * Represents a pressure sensor ++ */ + public interface PressureSensor { + public boolean isPressed(); + } +diff --git a/src/main/java/org/bukkit/metadata/MetadataStore.java b/src/main/java/org/bukkit/metadata/MetadataStore.java +index 29f86fa938c2758cbdf8dec22519a18c3e119818..8fca91925ce7d3fdcec838a3f1c9ba3e4ddc5a9c 100644 +--- a/src/main/java/org/bukkit/metadata/MetadataStore.java ++++ b/src/main/java/org/bukkit/metadata/MetadataStore.java +@@ -4,6 +4,11 @@ import java.util.List; + import org.bukkit.plugin.Plugin; + import org.jetbrains.annotations.NotNull; + ++/** ++ * Metadata store ++ * ++ * @param Type ++ */ + public interface MetadataStore { + /** + * Adds a metadata value to an object. +diff --git a/src/main/java/org/bukkit/metadata/MetadataStoreBase.java b/src/main/java/org/bukkit/metadata/MetadataStoreBase.java +index abbe545af572687a0399c2387434863cd2b70f68..81024450c3cf28657e2c38fd164dad034f47af22 100644 +--- a/src/main/java/org/bukkit/metadata/MetadataStoreBase.java ++++ b/src/main/java/org/bukkit/metadata/MetadataStoreBase.java +@@ -12,6 +12,11 @@ import org.apache.commons.lang.Validate; + import org.bukkit.plugin.Plugin; + import org.jetbrains.annotations.NotNull; + ++/** ++ * Metadata store base ++ * ++ * @param Type ++ */ + public abstract class MetadataStoreBase { + private Map> metadataMap = new java.util.concurrent.ConcurrentHashMap>(); // Paper + +diff --git a/src/main/java/org/bukkit/metadata/MetadataValue.java b/src/main/java/org/bukkit/metadata/MetadataValue.java +index 4b4d57924b8b2aecf4ebf92edc805334ffa53d0e..9df3d1c71a399c4d3f610bcd96aa401b4ea0c708 100644 +--- a/src/main/java/org/bukkit/metadata/MetadataValue.java ++++ b/src/main/java/org/bukkit/metadata/MetadataValue.java +@@ -4,6 +4,9 @@ import org.bukkit.plugin.Plugin; + import org.jetbrains.annotations.NotNull; + import org.jetbrains.annotations.Nullable; + ++/** ++ * Metadata value ++ */ + public interface MetadataValue { + + /** +diff --git a/src/main/java/org/bukkit/plugin/AuthorNagException.java b/src/main/java/org/bukkit/plugin/AuthorNagException.java +index 6565a441467e323b3e1871485a9e09e4cfbea050..20985f022afa077ba0907f3404175cb4500fa29f 100644 +--- a/src/main/java/org/bukkit/plugin/AuthorNagException.java ++++ b/src/main/java/org/bukkit/plugin/AuthorNagException.java +@@ -1,5 +1,8 @@ + package org.bukkit.plugin; + ++/** ++ * Author nag exception ++ */ + @SuppressWarnings("serial") + public class AuthorNagException extends RuntimeException { + private final String message; +diff --git a/src/main/java/org/bukkit/projectiles/BlockProjectileSource.java b/src/main/java/org/bukkit/projectiles/BlockProjectileSource.java +index 21a3d767baf9f76746b2a5f2b3af134fe1e96e8a..6d7a29554f337333f4cf6095d9d0ca9e275f8f4f 100644 +--- a/src/main/java/org/bukkit/projectiles/BlockProjectileSource.java ++++ b/src/main/java/org/bukkit/projectiles/BlockProjectileSource.java +@@ -3,6 +3,9 @@ package org.bukkit.projectiles; + import org.bukkit.block.Block; + import org.jetbrains.annotations.NotNull; + ++/** ++ * Represents a block projectile source ++ */ + public interface BlockProjectileSource extends ProjectileSource { + + /** diff --git a/patches/Purpur/patches/api/0032-PlayerBookTooLargeEvent.patch b/patches/Purpur/patches/api/0032-PlayerBookTooLargeEvent.patch new file mode 100644 index 00000000..dc89fde7 --- /dev/null +++ b/patches/Purpur/patches/api/0032-PlayerBookTooLargeEvent.patch @@ -0,0 +1,77 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Wed, 23 Dec 2020 00:43:27 -0600 +Subject: [PATCH] PlayerBookTooLargeEvent + + +diff --git a/src/main/java/net/pl3x/purpur/event/player/PlayerBookTooLargeEvent.java b/src/main/java/net/pl3x/purpur/event/player/PlayerBookTooLargeEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..39378ee2bfadf42ff358cc7b42dd75ac61615e15 +--- /dev/null ++++ b/src/main/java/net/pl3x/purpur/event/player/PlayerBookTooLargeEvent.java +@@ -0,0 +1,65 @@ ++package net.pl3x.purpur.event.player; ++ ++import org.bukkit.Bukkit; ++import org.bukkit.entity.Player; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.player.PlayerEvent; ++import org.bukkit.inventory.ItemStack; ++import org.jetbrains.annotations.NotNull; ++ ++/** ++ * Called when a player tries to bypass book limitations ++ */ ++public class PlayerBookTooLargeEvent extends PlayerEvent { ++ private static final HandlerList handlers = new HandlerList(); ++ private final ItemStack book; ++ private boolean kickPlayer = true; ++ ++ /** ++ * @param player The player ++ * @param book The book ++ */ ++ public PlayerBookTooLargeEvent(@NotNull Player player, @NotNull ItemStack book) { ++ super(player, !Bukkit.isPrimaryThread()); ++ this.book = book; ++ } ++ ++ /** ++ * Get the book containing the wanted edits ++ * ++ * @return The book ++ */ ++ @NotNull ++ public ItemStack getBook() { ++ return book; ++ } ++ ++ /** ++ * Whether server should kick the player or not ++ * ++ * @return True to kick player ++ */ ++ public boolean shouldKickPlayer() { ++ return kickPlayer; ++ } ++ ++ /** ++ * Whether server should kick the player or not ++ * ++ * @param kickPlayer True to kick player ++ */ ++ public void setShouldKickPlayer(boolean kickPlayer) { ++ this.kickPlayer = kickPlayer; ++ } ++ ++ @Override ++ @NotNull ++ public HandlerList getHandlers() { ++ return handlers; ++ } ++ ++ @NotNull ++ public static HandlerList getHandlerList() { ++ return handlers; ++ } ++} diff --git a/patches/Purpur/patches/api/0033-Full-netherite-armor-grants-fire-resistance.patch b/patches/Purpur/patches/api/0033-Full-netherite-armor-grants-fire-resistance.patch new file mode 100644 index 00000000..4cf6d1a0 --- /dev/null +++ b/patches/Purpur/patches/api/0033-Full-netherite-armor-grants-fire-resistance.patch @@ -0,0 +1,23 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Thu, 24 Dec 2020 11:00:04 -0600 +Subject: [PATCH] Full netherite armor grants fire resistance + + +diff --git a/src/main/java/org/bukkit/event/entity/EntityPotionEffectEvent.java b/src/main/java/org/bukkit/event/entity/EntityPotionEffectEvent.java +index 16b5fd279b0cb926900247618bcdb381a93f5a35..d592c62aadb3245396865c098c5979f2a162f868 100644 +--- a/src/main/java/org/bukkit/event/entity/EntityPotionEffectEvent.java ++++ b/src/main/java/org/bukkit/event/entity/EntityPotionEffectEvent.java +@@ -213,6 +213,12 @@ public class EntityPotionEffectEvent extends EntityEvent implements Cancellable + * When all effects are removed due to a bucket of milk. + */ + MILK, ++ // Purpur start ++ /** ++ * When a player wears full netherite armor ++ */ ++ NETHERITE_ARMOR, ++ // Purpur end + /** + * When a player gets bad omen after killing a patrol captain. + */ diff --git a/patches/Purpur/patches/api/0034-Add-EntityTeleportHinderedEvent.patch b/patches/Purpur/patches/api/0034-Add-EntityTeleportHinderedEvent.patch new file mode 100644 index 00000000..587b3f0e --- /dev/null +++ b/patches/Purpur/patches/api/0034-Add-EntityTeleportHinderedEvent.patch @@ -0,0 +1,141 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Mariell Hoversholm +Date: Sat, 9 Jan 2021 15:26:04 +0100 +Subject: [PATCH] Add EntityTeleportHinderedEvent + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +diff --git a/src/main/java/net/pl3x/purpur/event/entity/EntityTeleportHinderedEvent.java b/src/main/java/net/pl3x/purpur/event/entity/EntityTeleportHinderedEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..e6fcc4027cb70061b804460b39e00cca273d35ad +--- /dev/null ++++ b/src/main/java/net/pl3x/purpur/event/entity/EntityTeleportHinderedEvent.java +@@ -0,0 +1,117 @@ ++package net.pl3x.purpur.event.entity; ++ ++import org.bukkit.entity.Entity; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.entity.EntityEvent; ++import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++/** ++ * Fired when an entity is hindered from teleporting. ++ */ ++public class EntityTeleportHinderedEvent extends EntityEvent { ++ private static final HandlerList handlers = new HandlerList(); ++ ++ @NotNull ++ private final Reason reason; ++ ++ @Nullable ++ private final TeleportCause teleportCause; ++ ++ private boolean retry = false; ++ ++ public EntityTeleportHinderedEvent(@NotNull Entity what, @NotNull Reason reason, ++ @Nullable TeleportCause teleportCause) { ++ super(what); ++ this.reason = reason; ++ this.teleportCause = teleportCause; ++ } ++ ++ /** ++ * @return why the teleport was hindered. ++ */ ++ @NotNull ++ public Reason getReason() { ++ return reason; ++ } ++ ++ /** ++ * @return why the teleport occurred if cause was given, otherwise {@code null}. ++ */ ++ @Nullable ++ public TeleportCause getTeleportCause() { ++ return teleportCause; ++ } ++ ++ /** ++ * Whether the teleport should be retried. ++ *

++ * Note that this can put the server in a never-ending loop of trying to teleport someone resulting in a stack ++ * overflow. Do not retry more than necessary. ++ *

++ * ++ * @return whether the teleport should be retried. ++ */ ++ public boolean shouldRetry() { ++ return retry; ++ } ++ ++ /** ++ * Sets whether the teleport should be retried. ++ *

++ * Note that this can put the server in a never-ending loop of trying to teleport someone resulting in a stack ++ * overflow. Do not retry more than necessary. ++ *

++ * ++ * @param retry whether the teleport should be retried. ++ */ ++ public void setShouldRetry(boolean retry) { ++ this.retry = retry; ++ } ++ ++ /** ++ * Calls the event and tests if should retry. ++ * ++ * @return whether the teleport should be retried. ++ */ ++ @Override ++ public boolean callEvent() { ++ super.callEvent(); ++ return shouldRetry(); ++ } ++ ++ @Override ++ @NotNull ++ public HandlerList getHandlers() { ++ return handlers; ++ } ++ ++ @NotNull ++ public static HandlerList getHandlerList() { ++ return handlers; ++ } ++ ++ /** ++ * Reason for hindrance in teleports. ++ */ ++ public enum Reason { ++ /** ++ * The teleported entity is a passenger of another entity. ++ */ ++ IS_PASSENGER, ++ ++ /** ++ * The teleported entity has passengers. ++ */ ++ IS_VEHICLE, ++ ++ /** ++ * The teleport event was cancelled. ++ *

++ * This is only caused by players teleporting. ++ *

++ */ ++ EVENT_CANCELLED, ++ } ++} diff --git a/patches/Purpur/patches/api/0035-Add-StructureGenerateEvent.patch b/patches/Purpur/patches/api/0035-Add-StructureGenerateEvent.patch new file mode 100644 index 00000000..6ef11884 --- /dev/null +++ b/patches/Purpur/patches/api/0035-Add-StructureGenerateEvent.patch @@ -0,0 +1,112 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Nahuel +Date: Sat, 9 Jan 2021 15:33:52 +0100 +Subject: [PATCH] Add StructureGenerateEvent + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +Co-authored-by: Mariell Hoversholm + +diff --git a/src/main/java/net/pl3x/purpur/event/world/StructureGenerateEvent.java b/src/main/java/net/pl3x/purpur/event/world/StructureGenerateEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..e77f45f761368da9b230c425d975a717cf4d10fd +--- /dev/null ++++ b/src/main/java/net/pl3x/purpur/event/world/StructureGenerateEvent.java +@@ -0,0 +1,68 @@ ++package net.pl3x.purpur.event.world; ++ ++import org.bukkit.Bukkit; ++import org.bukkit.StructureType; ++import org.bukkit.World; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.world.WorldEvent; ++import org.jetbrains.annotations.NotNull; ++ ++public class StructureGenerateEvent extends WorldEvent implements Cancellable { ++ private static final HandlerList handlers = new HandlerList(); ++ ++ @NotNull ++ private final StructureType structureType; ++ private final int chunkX; ++ private final int chunkZ; ++ ++ private boolean cancel = false; ++ ++ public StructureGenerateEvent(@NotNull World world, ++ @NotNull StructureType structureType, int chunkX, int chunkZ) { ++ super(!Bukkit.isPrimaryThread(), world); // Structure generation is not necessarily on the main thread as of 1.16. ++ this.structureType = structureType; ++ this.chunkX = chunkX; ++ this.chunkZ = chunkZ; ++ } ++ ++ @NotNull ++ @Override ++ public World getWorld() { ++ return super.getWorld(); ++ } ++ ++ @NotNull ++ public StructureType getStructureType() { ++ return structureType; ++ } ++ ++ public int getChunkX() { ++ return chunkX; ++ } ++ ++ public int getChunkZ() { ++ return chunkZ; ++ } ++ ++ @Override ++ public void setCancelled(boolean cancel) { ++ this.cancel = cancel; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return this.cancel; ++ } ++ ++ @NotNull ++ @Override ++ public HandlerList getHandlers() { ++ return handlers; ++ } ++ ++ @NotNull ++ public static HandlerList getHandlerList() { ++ return handlers; ++ } ++} +diff --git a/src/main/java/org/bukkit/event/world/WorldEvent.java b/src/main/java/org/bukkit/event/world/WorldEvent.java +index cffeff33f007d3b03b7c862b25be453f705da739..1fa083d53dce161ef9e9f19407f230c94b2d7d15 100644 +--- a/src/main/java/org/bukkit/event/world/WorldEvent.java ++++ b/src/main/java/org/bukkit/event/world/WorldEvent.java +@@ -10,6 +10,13 @@ import org.jetbrains.annotations.NotNull; + public abstract class WorldEvent extends Event { + private final World world; + ++ // Purpur start ++ public WorldEvent(boolean isAsync, @NotNull final World world) { ++ super(isAsync); ++ this.world = world; ++ } ++ // Purpur end ++ + public WorldEvent(@NotNull final World world) { + this.world = world; + } diff --git a/patches/Purpur/patches/api/0036-Add-unsafe-Entity-serialization-API.patch b/patches/Purpur/patches/api/0036-Add-unsafe-Entity-serialization-API.patch new file mode 100644 index 00000000..db374eca --- /dev/null +++ b/patches/Purpur/patches/api/0036-Add-unsafe-Entity-serialization-API.patch @@ -0,0 +1,80 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Mariell Hoversholm +Date: Sat, 9 Jan 2021 21:21:27 +0100 +Subject: [PATCH] Add unsafe Entity serialization API + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java +index ef3011d74ce9acf02d0ee857033816854134ec0e..b2502aaab690b1414a1adffdf64e5a5456feb99c 100644 +--- a/src/main/java/org/bukkit/UnsafeValues.java ++++ b/src/main/java/org/bukkit/UnsafeValues.java +@@ -194,4 +194,28 @@ public interface UnsafeValues { + */ + int getProtocolVersion(); + // Paper end ++ ++ // Purpur start ++ ++ /** ++ * Serialize entity to byte array ++ * ++ * @param entity entity to serialize ++ * @return serialized entity ++ */ ++ byte[] serializeEntity(org.bukkit.entity.Entity entity); ++ ++ /** ++ * Deserialize an entity from byte array ++ *

++ * The entity is not automatically spawned in the world. You will have to spawn ++ * the entity yourself with {@link org.bukkit.entity.Entity#spawnAt(Location)} or ++ * {@link org.bukkit.entity.Entity#spawnAt(Location, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason)} ++ * ++ * @param data serialized entity ++ * @param world world entity belongs in ++ * @return deserialized entity ++ */ ++ org.bukkit.entity.Entity deserializeEntity(byte[] data, org.bukkit.World world); ++ // Purpur end + } +diff --git a/src/main/java/org/bukkit/entity/Entity.java b/src/main/java/org/bukkit/entity/Entity.java +index b47e31d2b9b41b39b46892fe10bf36d82c5d8e1b..7fa5242bd44c9b19648d79fa8fecbb7ee125288e 100644 +--- a/src/main/java/org/bukkit/entity/Entity.java ++++ b/src/main/java/org/bukkit/entity/Entity.java +@@ -751,5 +751,24 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent + * @return True if ridable in water + */ + boolean isRidableInWater(); ++ ++ /** ++ * Spawn this entity in the world at the given {@link Location} with the default spawn reason. ++ * ++ * @param location The location at which to spawn the entity. ++ * @return Whether the entity was successfully spawned. ++ */ ++ default boolean spawnAt(@NotNull Location location) { ++ return spawnAt(location, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT); ++ } ++ ++ /** ++ * Spawn this entity in the world at the given {@link Location} with the reason given. ++ * ++ * @param location The location at which to spawn the entity. ++ * @param spawnReason The reason for which the entity was spawned. ++ * @return Whether the entity was successfully spawned. ++ */ ++ boolean spawnAt(@NotNull Location location, @NotNull org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason spawnReason); + // Purpur end + } diff --git a/patches/Purpur/patches/api/0037-Conflict-on-change-for-adventure-deprecations.patch b/patches/Purpur/patches/api/0037-Conflict-on-change-for-adventure-deprecations.patch new file mode 100644 index 00000000..0cbe2e1b --- /dev/null +++ b/patches/Purpur/patches/api/0037-Conflict-on-change-for-adventure-deprecations.patch @@ -0,0 +1,867 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Wed, 17 Mar 2021 15:56:47 -0500 +Subject: [PATCH] Conflict on change for adventure deprecations + + +diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java +index a60c8bd89d14e47d3243307241458e907249a99b..194261bf20bb727d207a2429fa59abf0acf61b19 100644 +--- a/src/main/java/org/bukkit/Bukkit.java ++++ b/src/main/java/org/bukkit/Bukkit.java +@@ -303,7 +303,7 @@ public final class Bukkit { + * @return the number of players + * @deprecated in favour of {@link Server#broadcast(net.kyori.adventure.text.Component)} + */ +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + public static int broadcastMessage(@NotNull String message) { + return server.broadcastMessage(message); + } +@@ -947,7 +947,7 @@ public final class Bukkit { + * @return number of message recipients + * @deprecated in favour of {@link #broadcast(net.kyori.adventure.text.Component, String)} + */ +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + public static int broadcast(@NotNull String message, @NotNull String permission) { + return server.broadcast(message, permission); + } +@@ -1224,7 +1224,7 @@ public final class Bukkit { + * + * @see InventoryType#isCreatable() + */ +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + @NotNull + public static Inventory createInventory(@Nullable InventoryHolder owner, @NotNull InventoryType type, @NotNull String title) { + return server.createInventory(owner, type, title); +@@ -1274,7 +1274,7 @@ public final class Bukkit { + * @throws IllegalArgumentException if the size is not a multiple of 9 + * @deprecated in favour of {@link #createInventory(InventoryHolder, InventoryType, net.kyori.adventure.text.Component)} + */ +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + @NotNull + public static Inventory createInventory(@Nullable InventoryHolder owner, int size, @NotNull String title) throws IllegalArgumentException { + return server.createInventory(owner, size, title); +@@ -1301,7 +1301,7 @@ public final class Bukkit { + * @deprecated in favour of {@link #createMerchant(net.kyori.adventure.text.Component)} + */ + @NotNull +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + public static Merchant createMerchant(@Nullable String title) { + return server.createMerchant(title); + } +@@ -1390,7 +1390,7 @@ public final class Bukkit { + * @deprecated in favour of {@link #motd()} + */ + @NotNull +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + public static String getMotd() { + return server.getMotd(); + } +@@ -1412,7 +1412,7 @@ public final class Bukkit { + * @deprecated in favour of {@link #shutdownMessage()} + */ + @Nullable +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + public static String getShutdownMessage() { + return server.getShutdownMessage(); + } +diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java +index 3ee71225eb67ec728b414a8cdc0570d48d5603e3..a7fcd00ae37f9a2026759642562b1059c9dd9526 100644 +--- a/src/main/java/org/bukkit/Server.java ++++ b/src/main/java/org/bukkit/Server.java +@@ -250,7 +250,7 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi + * @return the number of players + * @deprecated use {@link #broadcast(net.kyori.adventure.text.Component)} + */ +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + public int broadcastMessage(@NotNull String message); + + // Paper start +@@ -773,7 +773,7 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi + * @return number of message recipients + * @deprecated in favour of {@link #broadcast(net.kyori.adventure.text.Component, String)} + */ +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + public int broadcast(@NotNull String message, @NotNull String permission); + // Paper start + /** +@@ -1035,7 +1035,7 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi + * + * @see InventoryType#isCreatable() + */ +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + @NotNull + Inventory createInventory(@Nullable InventoryHolder owner, @NotNull InventoryType type, @NotNull String title); + +@@ -1079,7 +1079,7 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi + * @throws IllegalArgumentException if the size is not a multiple of 9 + * @deprecated in favour of {@link #createInventory(InventoryHolder, int, net.kyori.adventure.text.Component)} + */ +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + @NotNull + Inventory createInventory(@Nullable InventoryHolder owner, int size, @NotNull String title) throws IllegalArgumentException; + +@@ -1102,7 +1102,7 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi + * @deprecated in favour of {@link #createMerchant(net.kyori.adventure.text.Component)} + */ + @NotNull +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + Merchant createMerchant(@Nullable String title); + + /** +@@ -1175,7 +1175,7 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi + * @deprecated in favour of {@link #motd()} + */ + @NotNull +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + String getMotd(); + + // Paper start +@@ -1193,7 +1193,7 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi + * @deprecated in favour of {@link #shutdownMessage()} + */ + @Nullable +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + String getShutdownMessage(); + + /** +diff --git a/src/main/java/org/bukkit/block/Sign.java b/src/main/java/org/bukkit/block/Sign.java +index 6ea9b54d95d80070c01a612c0ce2ab37f0b4ad41..fe9ec9cb7875df4a40d1c4155e13cca9b3628b30 100644 +--- a/src/main/java/org/bukkit/block/Sign.java ++++ b/src/main/java/org/bukkit/block/Sign.java +@@ -48,7 +48,7 @@ public interface Sign extends TileState, Colorable { + * @deprecated in favour of {@link #lines()} + */ + @NotNull +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + public String[] getLines(); + + /** +@@ -62,7 +62,7 @@ public interface Sign extends TileState, Colorable { + * @deprecated in favour of {@link #line(int)} + */ + @NotNull +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + public String getLine(int index) throws IndexOutOfBoundsException; + + /** +@@ -76,7 +76,7 @@ public interface Sign extends TileState, Colorable { + * @throws IndexOutOfBoundsException If the index is out of the range 0..3 + * @deprecated in favour of {@link #line(int, net.kyori.adventure.text.Component)} + */ +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + public void setLine(int index, @NotNull String line) throws IndexOutOfBoundsException; + + /** +diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java +index 25252bad38ca35b81b225b57c4b6ce77ad6de166..9f289576d97c3406d506d3f4fa7287bc74e5b425 100644 +--- a/src/main/java/org/bukkit/entity/Player.java ++++ b/src/main/java/org/bukkit/entity/Player.java +@@ -72,7 +72,7 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * @return the friendly name + * @deprecated in favour of {@link #displayName()} + */ +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + @NotNull + public String getDisplayName(); + +@@ -86,7 +86,7 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * @param name The new display name. + * @deprecated in favour of {@link #displayName(net.kyori.adventure.text.Component)} + */ +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + public void setDisplayName(@Nullable String name); + + // Paper start +@@ -127,7 +127,7 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * @deprecated in favour of {@link #playerListName()} + */ + @NotNull +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + public String getPlayerListName(); + + /** +@@ -138,7 +138,7 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * @param name new player list name + * @deprecated in favour of {@link #playerListName(net.kyori.adventure.text.Component)} + */ +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + public void setPlayerListName(@Nullable String name); + + /** +@@ -147,7 +147,7 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * @return player list header or null + * @deprecated in favour of {@link #playerListHeader()} + */ +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + @Nullable + public String getPlayerListHeader(); + +@@ -157,7 +157,7 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * @return player list header or null + * @deprecated in favour of {@link #playerListFooter()} + */ +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + @Nullable + public String getPlayerListFooter(); + +@@ -167,7 +167,7 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * @param header player list header, null for empty + * @deprecated in favour of {@link #sendPlayerListHeader(net.kyori.adventure.text.Component)} + */ +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + public void setPlayerListHeader(@Nullable String header); + + /** +@@ -176,7 +176,7 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * @param footer player list footer, null for empty + * @deprecated in favour of {@link #sendPlayerListFooter(net.kyori.adventure.text.Component)} + */ +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + public void setPlayerListFooter(@Nullable String footer); + + /** +@@ -187,7 +187,7 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * @param footer player list footer, null for empty + * @deprecated in favour of {@link #sendPlayerListHeaderAndFooter(net.kyori.adventure.text.Component, net.kyori.adventure.text.Component)} + */ +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + public void setPlayerListHeaderFooter(@Nullable String header, @Nullable String footer); + + /** +@@ -227,7 +227,7 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * @param message kick message + * @deprecated in favour of {@link #kick(net.kyori.adventure.text.Component)} + */ +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + public void kickPlayer(@Nullable String message); + + // Paper start +@@ -598,7 +598,7 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * @throws IllegalArgumentException if lines is non-null and has a length less than 4 + * @deprecated in favour of {@link #sendSignChange(org.bukkit.Location, java.util.List)} + */ +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + public void sendSignChange(@NotNull Location loc, @Nullable String[] lines) throws IllegalArgumentException; + + +@@ -620,7 +620,7 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * @throws IllegalArgumentException if lines is non-null and has a length less than 4 + * @deprecated in favour of {@link #sendSignChange(org.bukkit.Location, java.util.List, org.bukkit.DyeColor)} + */ +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + public void sendSignChange(@NotNull Location loc, @Nullable String[] lines, @NotNull DyeColor dyeColor) throws IllegalArgumentException; + + /** +@@ -1769,7 +1769,7 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * @deprecated in favour of {@link #locale()} + */ + @NotNull +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + public String getLocale(); + + // Paper start +diff --git a/src/main/java/org/bukkit/entity/minecart/CommandMinecart.java b/src/main/java/org/bukkit/entity/minecart/CommandMinecart.java +index 078228106b299a8e38495f7f881d38de4f87bc95..bd5b3142a88c31a676c08fa3e8175f81f4259835 100644 +--- a/src/main/java/org/bukkit/entity/minecart/CommandMinecart.java ++++ b/src/main/java/org/bukkit/entity/minecart/CommandMinecart.java +@@ -37,7 +37,7 @@ public interface CommandMinecart extends Minecart { + * @param name New name for this CommandMinecart. + * @deprecated in favour of {@link #customName(net.kyori.adventure.text.Component)} + */ +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + public void setName(@Nullable String name); + + } +diff --git a/src/main/java/org/bukkit/event/block/SignChangeEvent.java b/src/main/java/org/bukkit/event/block/SignChangeEvent.java +index 1f79f704abf339150df08900b8ea7da4cefef258..004106913655446774f875015cb79863d21263c8 100644 +--- a/src/main/java/org/bukkit/event/block/SignChangeEvent.java ++++ b/src/main/java/org/bukkit/event/block/SignChangeEvent.java +@@ -90,7 +90,7 @@ public class SignChangeEvent extends BlockEvent implements Cancellable { + * @deprecated in favour of {@link #lines()} + */ + @NotNull +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + public String[] getLines() { + return adventure$lines.stream().map(org.bukkit.Bukkit.getUnsafe().legacyComponentSerializer()::serialize).toArray(String[]::new); // Paper + } +@@ -106,7 +106,7 @@ public class SignChangeEvent extends BlockEvent implements Cancellable { + * @deprecated in favour of {@link #line(int)} + */ + @Nullable +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + public String getLine(int index) throws IndexOutOfBoundsException { + return org.bukkit.Bukkit.getUnsafe().legacyComponentSerializer().serialize(this.adventure$lines.get(index)); // Paper + } +@@ -120,7 +120,7 @@ public class SignChangeEvent extends BlockEvent implements Cancellable { + * or < 0} + * @deprecated in favour of {@link #line(int, net.kyori.adventure.text.Component)} + */ +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + public void setLine(int index, @Nullable String line) throws IndexOutOfBoundsException { + adventure$lines.set(index, line != null ? org.bukkit.Bukkit.getUnsafe().legacyComponentSerializer().deserialize(line) : null); // Paper + } +diff --git a/src/main/java/org/bukkit/event/entity/PlayerDeathEvent.java b/src/main/java/org/bukkit/event/entity/PlayerDeathEvent.java +index 3d45d2e41aad6992b40a22030f2a63baeec78757..3cecfe9f7c253ab474829c612cca2dc05fd5d111 100644 +--- a/src/main/java/org/bukkit/event/entity/PlayerDeathEvent.java ++++ b/src/main/java/org/bukkit/event/entity/PlayerDeathEvent.java +@@ -151,7 +151,7 @@ public class PlayerDeathEvent extends EntityDeathEvent { + * @param deathMessage Message to appear to other players on the server. + * @deprecated in favour of {@link #deathMessage(net.kyori.adventure.text.Component)} + */ +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + public void setDeathMessage(@Nullable String deathMessage) { + this.deathMessage = deathMessage; + this.adventure$deathMessage = deathMessage != null ? org.bukkit.Bukkit.getUnsafe().legacyComponentSerializer().deserialize(deathMessage) : net.kyori.adventure.text.Component.empty(); // Paper +@@ -164,7 +164,7 @@ public class PlayerDeathEvent extends EntityDeathEvent { + * @deprecated in favour of {@link #deathMessage()} + */ + @Nullable +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + public String getDeathMessage() { + return this.deathMessage != null ? this.deathMessage : (this.adventure$deathMessage != null ? getDeathMessageString(this.adventure$deathMessage) : null); // Paper + } +diff --git a/src/main/java/org/bukkit/event/inventory/InventoryType.java b/src/main/java/org/bukkit/event/inventory/InventoryType.java +index 129eac25da4f27489038fb15ab1aeecb172b60cc..670aca11bbaa2d155cd9d2105ac94c9df71d7d8d 100644 +--- a/src/main/java/org/bukkit/event/inventory/InventoryType.java ++++ b/src/main/java/org/bukkit/event/inventory/InventoryType.java +@@ -170,7 +170,7 @@ public enum InventoryType { + } + + @NotNull +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + public String getDefaultTitle() { + return title; + } +diff --git a/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java b/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java +index 77aefda5aac4602bf5bf71c29600e7450defdd4e..240552d61ae12fbec826f771f0f366500e72d941 100644 +--- a/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java ++++ b/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java +@@ -179,7 +179,7 @@ public class AsyncPlayerPreLoginEvent extends Event { + * @deprecated in favour of {@link #kickMessage()} + */ + @NotNull +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + public String getKickMessage() { + return org.bukkit.Bukkit.getUnsafe().legacyComponentSerializer().serialize(this.message); // Paper + } +@@ -190,7 +190,7 @@ public class AsyncPlayerPreLoginEvent extends Event { + * @param message New kick message + * @deprecated in favour of {@link #kickMessage(net.kyori.adventure.text.Component)} + */ +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + public void setKickMessage(@NotNull final String message) { + this.message = org.bukkit.Bukkit.getUnsafe().legacyComponentSerializer().deserialize(message); // Paper + } +@@ -210,7 +210,7 @@ public class AsyncPlayerPreLoginEvent extends Event { + * @param message Kick message to display to the user + * @deprecated in favour of {@link #disallow(org.bukkit.event.player.AsyncPlayerPreLoginEvent.Result, net.kyori.adventure.text.Component)} + */ +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + public void disallow(@NotNull final Result result, @NotNull final String message) { + this.result = result; + this.message = org.bukkit.Bukkit.getUnsafe().legacyComponentSerializer().deserialize(message); // Paper +diff --git a/src/main/java/org/bukkit/event/player/PlayerJoinEvent.java b/src/main/java/org/bukkit/event/player/PlayerJoinEvent.java +index 851a189d42e271679abc78f95049d8badf7a2b64..7057c2e95267ad32190c5666f20a0566f7fe32fa 100644 +--- a/src/main/java/org/bukkit/event/player/PlayerJoinEvent.java ++++ b/src/main/java/org/bukkit/event/player/PlayerJoinEvent.java +@@ -17,7 +17,7 @@ public class PlayerJoinEvent extends PlayerEvent { + this.joinMessage = joinMessage; + } + +- @Deprecated // Paper end ++ @Deprecated // Paper end // Purpur - conflict on change + public PlayerJoinEvent(@NotNull final Player playerJoined, @Nullable final String joinMessage) { + super(playerJoined); + this.joinMessage = joinMessage != null ? org.bukkit.Bukkit.getUnsafe().legacyComponentSerializer().deserialize(joinMessage) : null; // Paper end +@@ -50,7 +50,7 @@ public class PlayerJoinEvent extends PlayerEvent { + * @deprecated in favour of {@link #joinMessage()} + */ + @Nullable +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + public String getJoinMessage() { + return this.joinMessage == null ? null : org.bukkit.Bukkit.getUnsafe().legacyComponentSerializer().serialize(this.joinMessage); // Paper + } +@@ -61,7 +61,7 @@ public class PlayerJoinEvent extends PlayerEvent { + * @param joinMessage join message. If null, no message will be sent + * @deprecated in favour of {@link #joinMessage(net.kyori.adventure.text.Component)} + */ +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + public void setJoinMessage(@Nullable String joinMessage) { + this.joinMessage = joinMessage != null ? org.bukkit.Bukkit.getUnsafe().legacyComponentSerializer().deserialize(joinMessage) : null; // Paper + } +diff --git a/src/main/java/org/bukkit/event/player/PlayerKickEvent.java b/src/main/java/org/bukkit/event/player/PlayerKickEvent.java +index 02914c0743852e9e4fd2c085fd4b735e74d8875b..94688093671949551992a8c80904cd6042deb83b 100644 +--- a/src/main/java/org/bukkit/event/player/PlayerKickEvent.java ++++ b/src/main/java/org/bukkit/event/player/PlayerKickEvent.java +@@ -85,7 +85,7 @@ public class PlayerKickEvent extends PlayerEvent implements Cancellable { + * @deprecated in favour of {@link #reason()} + */ + @NotNull +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + public String getReason() { + return org.bukkit.Bukkit.getUnsafe().legacyComponentSerializer().serialize(this.kickReason); // Paper + } +@@ -97,7 +97,7 @@ public class PlayerKickEvent extends PlayerEvent implements Cancellable { + * @deprecated in favour of {@link #leaveMessage()} + */ + @NotNull +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + public String getLeaveMessage() { + return org.bukkit.Bukkit.getUnsafe().legacyComponentSerializer().serialize(this.leaveMessage); // Paper + } +@@ -118,7 +118,7 @@ public class PlayerKickEvent extends PlayerEvent implements Cancellable { + * @param kickReason kick reason + * @deprecated in favour of {@link #reason(net.kyori.adventure.text.Component)} + */ +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + public void setReason(@NotNull String kickReason) { + this.kickReason = org.bukkit.Bukkit.getUnsafe().legacyComponentSerializer().deserialize(kickReason); // Paper + } +@@ -129,7 +129,7 @@ public class PlayerKickEvent extends PlayerEvent implements Cancellable { + * @param leaveMessage leave message + * @deprecated in favour of {@link #leaveMessage(net.kyori.adventure.text.Component)} + */ +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + public void setLeaveMessage(@NotNull String leaveMessage) { + this.leaveMessage = org.bukkit.Bukkit.getUnsafe().legacyComponentSerializer().deserialize(leaveMessage); // Paper + } +diff --git a/src/main/java/org/bukkit/event/player/PlayerLocaleChangeEvent.java b/src/main/java/org/bukkit/event/player/PlayerLocaleChangeEvent.java +index 84521186404b8e43c81a2f9513dce2be40d27840..8c65e9e1476d27fc55419290fb53e46dee9b304d 100644 +--- a/src/main/java/org/bukkit/event/player/PlayerLocaleChangeEvent.java ++++ b/src/main/java/org/bukkit/event/player/PlayerLocaleChangeEvent.java +@@ -37,7 +37,7 @@ public class PlayerLocaleChangeEvent extends PlayerEvent { + * @deprecated in favour of {@link #locale()} + */ + @NotNull +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + public String getLocale() { + return locale; + } +diff --git a/src/main/java/org/bukkit/event/player/PlayerLoginEvent.java b/src/main/java/org/bukkit/event/player/PlayerLoginEvent.java +index 75cc54739ef841cd90568d74927d6002d4cfa7e0..712900c9afc3b79806d2b564c0734facf969a6fe 100644 +--- a/src/main/java/org/bukkit/event/player/PlayerLoginEvent.java ++++ b/src/main/java/org/bukkit/event/player/PlayerLoginEvent.java +@@ -139,7 +139,7 @@ public class PlayerLoginEvent extends PlayerEvent { + * @deprecated in favour of {@link #kickMessage()} + */ + @NotNull +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + public String getKickMessage() { + return org.bukkit.Bukkit.getUnsafe().legacyComponentSerializer().serialize(this.message); // Paper + } +@@ -150,7 +150,7 @@ public class PlayerLoginEvent extends PlayerEvent { + * @param message New kick message + * @deprecated in favour of {@link #kickMessage(net.kyori.adventure.text.Component)} + */ +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + public void setKickMessage(@NotNull final String message) { + this.message = org.bukkit.Bukkit.getUnsafe().legacyComponentSerializer().deserialize(message); // Paper + } +@@ -181,7 +181,7 @@ public class PlayerLoginEvent extends PlayerEvent { + * @param message Kick message to display to the user + * @deprecated in favour of {@link #disallow(Result, net.kyori.adventure.text.Component)} + */ +- @Deprecated // Paper start ++ @Deprecated // Paper start // Purpur - conflict on change + public void disallow(@NotNull final Result result, @NotNull final String message) { + this.result = result; + this.message = org.bukkit.Bukkit.getUnsafe().legacyComponentSerializer().deserialize(message); +diff --git a/src/main/java/org/bukkit/event/player/PlayerPreLoginEvent.java b/src/main/java/org/bukkit/event/player/PlayerPreLoginEvent.java +index 123979ed64939d615b061f91c19c630e1e1db8c7..5b85579964dc6a6150f0c0be650a4bf731414838 100644 +--- a/src/main/java/org/bukkit/event/player/PlayerPreLoginEvent.java ++++ b/src/main/java/org/bukkit/event/player/PlayerPreLoginEvent.java +@@ -95,7 +95,7 @@ public class PlayerPreLoginEvent extends Event { + * @return Current kick message + * @deprecated in favour of {@link #kickMessage()} + */ +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + @NotNull + public String getKickMessage() { + return org.bukkit.Bukkit.getUnsafe().legacyComponentSerializer().serialize(this.message); // Paper +@@ -107,7 +107,7 @@ public class PlayerPreLoginEvent extends Event { + * @param message New kick message + * @deprecated in favour of {@link #kickMessage(net.kyori.adventure.text.Component)} + */ +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + public void setKickMessage(@NotNull final String message) { + this.message = org.bukkit.Bukkit.getUnsafe().legacyComponentSerializer().deserialize(message); // Paper + } +@@ -127,7 +127,7 @@ public class PlayerPreLoginEvent extends Event { + * @param message Kick message to display to the user + * @deprecated in favour of {@link #disallow(org.bukkit.event.player.PlayerPreLoginEvent.Result, net.kyori.adventure.text.Component)} + */ +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + public void disallow(@NotNull final Result result, @NotNull final String message) { + this.result = result; + this.message = org.bukkit.Bukkit.getUnsafe().legacyComponentSerializer().deserialize(message); // Paper +diff --git a/src/main/java/org/bukkit/event/player/PlayerQuitEvent.java b/src/main/java/org/bukkit/event/player/PlayerQuitEvent.java +index e43acfb570036adb73d195136573620378cc6a61..1826d11d8b18702ee12c669b50df7f538c324582 100644 +--- a/src/main/java/org/bukkit/event/player/PlayerQuitEvent.java ++++ b/src/main/java/org/bukkit/event/player/PlayerQuitEvent.java +@@ -61,7 +61,7 @@ public class PlayerQuitEvent extends PlayerEvent { + * @deprecated in favour of {@link #quitMessage()} + */ + @Nullable +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + public String getQuitMessage() { + return this.quitMessage == null ? null : org.bukkit.Bukkit.getUnsafe().legacyComponentSerializer().serialize(this.quitMessage); // Paper + } +@@ -72,7 +72,7 @@ public class PlayerQuitEvent extends PlayerEvent { + * @param quitMessage quit message + * @deprecated in favour of {@link #quitMessage(net.kyori.adventure.text.Component)} + */ +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + public void setQuitMessage(@Nullable String quitMessage) { + this.quitMessage = quitMessage != null ? org.bukkit.Bukkit.getUnsafe().legacyComponentSerializer().deserialize(quitMessage) : null; // Paper + } +diff --git a/src/main/java/org/bukkit/event/server/BroadcastMessageEvent.java b/src/main/java/org/bukkit/event/server/BroadcastMessageEvent.java +index 4f8c85222c7bd33217c7db0ff5f47bf397f8f3e5..c18d6d979bd22814ebdc52b995d2cc7ed46dd87f 100644 +--- a/src/main/java/org/bukkit/event/server/BroadcastMessageEvent.java ++++ b/src/main/java/org/bukkit/event/server/BroadcastMessageEvent.java +@@ -73,7 +73,7 @@ public class BroadcastMessageEvent extends ServerEvent implements Cancellable { + * @deprecated in favour of {@link #message()} + */ + @NotNull +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + public String getMessage() { + return org.bukkit.Bukkit.getUnsafe().legacyComponentSerializer().serialize(this.message); // Paper + } +@@ -84,7 +84,7 @@ public class BroadcastMessageEvent extends ServerEvent implements Cancellable { + * @param message New message to broadcast + * @deprecated in favour of {@link #message(net.kyori.adventure.text.Component)} + */ +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + public void setMessage(@NotNull String message) { + this.message = org.bukkit.Bukkit.getUnsafe().legacyComponentSerializer().deserialize(message); // Paper + } +diff --git a/src/main/java/org/bukkit/event/server/ServerListPingEvent.java b/src/main/java/org/bukkit/event/server/ServerListPingEvent.java +index ede5a41bc071a9c9cea369b227b37a50222f295d..6c6501d73041a6c69e78f34d3bf2a96a7de5f690 100644 +--- a/src/main/java/org/bukkit/event/server/ServerListPingEvent.java ++++ b/src/main/java/org/bukkit/event/server/ServerListPingEvent.java +@@ -109,7 +109,7 @@ public class ServerListPingEvent extends ServerEvent implements Iterable + * @deprecated in favour of {@link #motd()} + */ + @NotNull +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + public String getMotd() { + return org.bukkit.Bukkit.getUnsafe().legacyComponentSerializer().serialize(this.motd); // Paper + } +@@ -120,7 +120,7 @@ public class ServerListPingEvent extends ServerEvent implements Iterable + * @param motd the message of the day + * @deprecated in favour of {@link #motd(net.kyori.adventure.text.Component)} + */ +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + public void setMotd(@NotNull String motd) { + this.motd = org.bukkit.Bukkit.getUnsafe().legacyComponentSerializer().deserialize(motd); // Paper + } +diff --git a/src/main/java/org/bukkit/inventory/InventoryView.java b/src/main/java/org/bukkit/inventory/InventoryView.java +index b06995aa57aa9cba0bb59f1d26d81015619a08e6..5e33fe46ab9bb034acc6a38a3c00c33c8f029ca6 100644 +--- a/src/main/java/org/bukkit/inventory/InventoryView.java ++++ b/src/main/java/org/bukkit/inventory/InventoryView.java +@@ -464,7 +464,7 @@ public abstract class InventoryView { + * @return The title. + * @deprecated in favour of {@link #title()} + */ +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + @NotNull + public abstract String getTitle(); + } +diff --git a/src/main/java/org/bukkit/inventory/meta/BookMeta.java b/src/main/java/org/bukkit/inventory/meta/BookMeta.java +index 248cd6faa72a91ceaf6f74d06c05d05bd26f5fbc..6ec728854333cd473528162b6381e7a5a83532d8 100644 +--- a/src/main/java/org/bukkit/inventory/meta/BookMeta.java ++++ b/src/main/java/org/bukkit/inventory/meta/BookMeta.java +@@ -244,7 +244,7 @@ public interface BookMeta extends ItemMeta, net.kyori.adventure.inventory.Book { + * @deprecated in favour of {@link #page(int)} + */ + @NotNull +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + String getPage(int page); + + /** +@@ -260,7 +260,7 @@ public interface BookMeta extends ItemMeta, net.kyori.adventure.inventory.Book { + * @param data the data to set for that page + * @deprecated in favour of {@link #page(int, net.kyori.adventure.text.Component)} + */ +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + void setPage(int page, @NotNull String data); + + /** +@@ -270,7 +270,7 @@ public interface BookMeta extends ItemMeta, net.kyori.adventure.inventory.Book { + * @deprecated in favour of {@link #pages()} + */ + @NotNull +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + List getPages(); + + /** +@@ -280,7 +280,7 @@ public interface BookMeta extends ItemMeta, net.kyori.adventure.inventory.Book { + * @param pages A list of pages to set the book to use + * @deprecated in favour of {@link #pages(List)} + */ +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + void setPages(@NotNull List pages); + + /** +@@ -290,7 +290,7 @@ public interface BookMeta extends ItemMeta, net.kyori.adventure.inventory.Book { + * @param pages A list of strings, each being a page + * @deprecated in favour of {@link #pages(net.kyori.adventure.text.Component...)} + */ +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + void setPages(@NotNull String... pages); + + /** +@@ -300,7 +300,7 @@ public interface BookMeta extends ItemMeta, net.kyori.adventure.inventory.Book { + * @param pages A list of strings, each being a page + * @deprecated in favour of {@link #addPages(net.kyori.adventure.text.Component...)} + */ +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + void addPage(@NotNull String... pages); + + /** +diff --git a/src/main/java/org/bukkit/inventory/meta/ItemMeta.java b/src/main/java/org/bukkit/inventory/meta/ItemMeta.java +index f093f991f1fedd20fcef041b093398250b7fb286..49d8b1bdad79f452c863f83557ffde7e8f4749c6 100644 +--- a/src/main/java/org/bukkit/inventory/meta/ItemMeta.java ++++ b/src/main/java/org/bukkit/inventory/meta/ItemMeta.java +@@ -59,7 +59,7 @@ public interface ItemMeta extends Cloneable, ConfigurationSerializable, Persiste + * @return the display name that is set + * @deprecated in favour of {@link #displayName()} + */ +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + @NotNull + String getDisplayName(); + +@@ -83,7 +83,7 @@ public interface ItemMeta extends Cloneable, ConfigurationSerializable, Persiste + * @param name the name to set + * @deprecated in favour of {@link #displayName(net.kyori.adventure.text.Component)} + */ +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + void setDisplayName(@Nullable String name); + + // Paper start +@@ -155,7 +155,7 @@ public interface ItemMeta extends Cloneable, ConfigurationSerializable, Persiste + * @return a list of lore that is set + * @deprecated in favour of {@link #lore()} + */ +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + @Nullable + List getLore(); + +@@ -179,7 +179,7 @@ public interface ItemMeta extends Cloneable, ConfigurationSerializable, Persiste + * @param lore the lore that will be set + * @deprecated in favour of {@link #lore(List)} + */ +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + void setLore(@Nullable List lore); + + /** +diff --git a/src/main/java/org/bukkit/map/MapCursor.java b/src/main/java/org/bukkit/map/MapCursor.java +index ed0bc2024a0bb85837e25f75ae89d1fe257b2e60..f6e831f844e1fe99a2617bd64c2290d1f2e96d81 100644 +--- a/src/main/java/org/bukkit/map/MapCursor.java ++++ b/src/main/java/org/bukkit/map/MapCursor.java +@@ -259,7 +259,7 @@ public final class MapCursor { + * @deprecated in favour of {@link #caption()} + */ + @Nullable +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + public String getCaption() { + return this.caption == null ? null : org.bukkit.Bukkit.getUnsafe().legacyComponentSerializer().serialize(this.caption); // Paper + } +@@ -270,7 +270,7 @@ public final class MapCursor { + * @param caption new caption + * @deprecated in favour of {@link #caption(net.kyori.adventure.text.Component)} + */ +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + public void setCaption(@Nullable String caption) { + this.caption = caption == null ? null : org.bukkit.Bukkit.getUnsafe().legacyComponentSerializer().deserialize(caption); // Paper + } +diff --git a/src/main/java/org/bukkit/scoreboard/Objective.java b/src/main/java/org/bukkit/scoreboard/Objective.java +index 58bddb11fd534e7c33a4ffd7b72b055ba92c767a..a1b6b1123808378d58c855cacac391ce97df6f19 100644 +--- a/src/main/java/org/bukkit/scoreboard/Objective.java ++++ b/src/main/java/org/bukkit/scoreboard/Objective.java +@@ -47,7 +47,7 @@ public interface Objective { + * @deprecated in favour of {@link #displayName()} + */ + @NotNull +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + String getDisplayName() throws IllegalStateException; + + /** +@@ -60,7 +60,7 @@ public interface Objective { + * characters. + * @deprecated in favour of {@link #displayName(net.kyori.adventure.text.Component)} + */ +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + void setDisplayName(@NotNull String displayName) throws IllegalStateException, IllegalArgumentException; + + /** +diff --git a/src/main/java/org/bukkit/scoreboard/Scoreboard.java b/src/main/java/org/bukkit/scoreboard/Scoreboard.java +index f09ff32cc3ffc16af379a378b1948991435393e8..e9db79d10522895e6f119c0cc87eec1cbc45ba6e 100644 +--- a/src/main/java/org/bukkit/scoreboard/Scoreboard.java ++++ b/src/main/java/org/bukkit/scoreboard/Scoreboard.java +@@ -89,7 +89,7 @@ public interface Scoreboard { + * @deprecated in favour of {@link #registerNewObjective(String, String, net.kyori.adventure.text.Component)} + */ + @NotNull +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + Objective registerNewObjective(@NotNull String name, @NotNull String criteria, @NotNull String displayName) throws IllegalArgumentException; + + /** +@@ -113,7 +113,7 @@ public interface Scoreboard { + * @deprecated in favour of {@link #registerNewObjective(String, String, net.kyori.adventure.text.Component, RenderType)} + */ + @NotNull +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + Objective registerNewObjective(@NotNull String name, @NotNull String criteria, @NotNull String displayName, @NotNull RenderType renderType) throws IllegalArgumentException; + + /** +diff --git a/src/main/java/org/bukkit/scoreboard/Team.java b/src/main/java/org/bukkit/scoreboard/Team.java +index f0af10a5b9ad048be197ed5ec6c8ed2672eb3dd5..705b2268b1c227b34852c14601381230dc626a08 100644 +--- a/src/main/java/org/bukkit/scoreboard/Team.java ++++ b/src/main/java/org/bukkit/scoreboard/Team.java +@@ -110,7 +110,7 @@ public interface Team { + * @deprecated in favour of {@link #displayName()} + */ + @NotNull +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + String getDisplayName() throws IllegalStateException; + + /** +@@ -122,7 +122,7 @@ public interface Team { + * @throws IllegalStateException if this team has been unregistered + * @deprecated in favour of {@link #displayName(net.kyori.adventure.text.Component)} + */ +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + void setDisplayName(@NotNull String displayName) throws IllegalStateException, IllegalArgumentException; + + /** +@@ -133,7 +133,7 @@ public interface Team { + * @deprecated in favour of {@link #prefix()} + */ + @NotNull +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + String getPrefix() throws IllegalStateException; + + /** +@@ -146,7 +146,7 @@ public interface Team { + * @throws IllegalStateException if this team has been unregistered + * @deprecated in favour of {@link #prefix(net.kyori.adventure.text.Component)} + */ +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + void setPrefix(@NotNull String prefix) throws IllegalStateException, IllegalArgumentException; + + /** +@@ -157,7 +157,7 @@ public interface Team { + * @deprecated in favour of {@link #suffix()} + */ + @NotNull +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + String getSuffix() throws IllegalStateException; + + /** +@@ -170,7 +170,7 @@ public interface Team { + * @throws IllegalStateException if this team has been unregistered + * @deprecated in favour of {@link #suffix(net.kyori.adventure.text.Component)} + */ +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + void setSuffix(@NotNull String suffix) throws IllegalStateException, IllegalArgumentException; + + /** +@@ -184,7 +184,7 @@ public interface Team { + * @deprecated in favour of {@link #color()} + */ + @NotNull +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + ChatColor getColor() throws IllegalStateException; + + /** +@@ -197,7 +197,7 @@ public interface Team { + * no color + * @deprecated in favour of {@link #color(net.kyori.adventure.text.format.NamedTextColor)} + */ +- @Deprecated // Paper ++ @Deprecated // Paper // Purpur - conflict on change + void setColor(@NotNull ChatColor color); + + /** diff --git a/patches/Purpur/patches/api/0038-Add-enchantment-target-for-bows-and-crossbows.patch b/patches/Purpur/patches/api/0038-Add-enchantment-target-for-bows-and-crossbows.patch new file mode 100644 index 00000000..d30cd004 --- /dev/null +++ b/patches/Purpur/patches/api/0038-Add-enchantment-target-for-bows-and-crossbows.patch @@ -0,0 +1,29 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Tue, 23 Mar 2021 15:01:03 -0500 +Subject: [PATCH] Add enchantment target for bows and crossbows + + +diff --git a/src/main/java/org/bukkit/enchantments/EnchantmentTarget.java b/src/main/java/org/bukkit/enchantments/EnchantmentTarget.java +index 635e07a6b0e255c4fdad58ba9d281c807af4e229..93d5fad641c5afa679b59dc712f0d0faaddcfe2e 100644 +--- a/src/main/java/org/bukkit/enchantments/EnchantmentTarget.java ++++ b/src/main/java/org/bukkit/enchantments/EnchantmentTarget.java +@@ -226,6 +226,18 @@ public enum EnchantmentTarget { + public boolean includes(@NotNull Material item) { + return BREAKABLE.includes(item) || (WEARABLE.includes(item) && !item.equals(Material.ELYTRA)) || item.equals(Material.COMPASS); + } ++ // Purpur start ++ }, ++ ++ /** ++ * Allow the Enchantment to be placed on bows and crossbows. ++ */ ++ BOW_AND_CROSSBOW { ++ @Override ++ public boolean includes(@NotNull Material item) { ++ return item.equals(Material.BOW) || item.equals(Material.CROSSBOW); ++ } ++ // Purpur end + }; + + /** diff --git a/patches/Purpur/patches/api/0039-Iron-golem-poppy-calms-anger.patch b/patches/Purpur/patches/api/0039-Iron-golem-poppy-calms-anger.patch new file mode 100644 index 00000000..0287a30a --- /dev/null +++ b/patches/Purpur/patches/api/0039-Iron-golem-poppy-calms-anger.patch @@ -0,0 +1,17 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Thu, 13 May 2021 21:38:01 -0500 +Subject: [PATCH] Iron golem poppy calms anger + + +diff --git a/src/main/java/com/destroystokyo/paper/entity/ai/VanillaGoal.java b/src/main/java/com/destroystokyo/paper/entity/ai/VanillaGoal.java +index 39f77041133228c4bd4cec2427ad0bae8e739d4a..29144c0e325a3efbef05670a6fb2e849bbed6bba 100644 +--- a/src/main/java/com/destroystokyo/paper/entity/ai/VanillaGoal.java ++++ b/src/main/java/com/destroystokyo/paper/entity/ai/VanillaGoal.java +@@ -214,5 +214,6 @@ public interface VanillaGoal extends Goal { + GoalKey DROWNED_ATTACK_VILLAGER = GoalKey.of(Drowned.class, NamespacedKey.minecraft("drowned_attack_villager")); + GoalKey ZOMBIE_ATTACK_VILLAGER = GoalKey.of(Zombie.class, NamespacedKey.minecraft("zombie_attack_villager")); + GoalKey AVOID_RABID_WOLVES = GoalKey.of(Wolf.class, NamespacedKey.minecraft("avoid_rabid_wolves")); ++ GoalKey RECEIVE_FLOWER = GoalKey.of(IronGolem.class, NamespacedKey.minecraft("receive_flower")); + // Purpur end + } diff --git a/patches/Purpur/patches/api/0040-API-for-any-mob-to-burn-daylight.patch b/patches/Purpur/patches/api/0040-API-for-any-mob-to-burn-daylight.patch new file mode 100644 index 00000000..edec35d7 --- /dev/null +++ b/patches/Purpur/patches/api/0040-API-for-any-mob-to-burn-daylight.patch @@ -0,0 +1,48 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ben Kerllenevich +Date: Tue, 25 May 2021 16:30:30 -0400 +Subject: [PATCH] API for any mob to burn daylight + +Co-authored by: Encode42 + +diff --git a/src/main/java/org/bukkit/entity/Entity.java b/src/main/java/org/bukkit/entity/Entity.java +index 7fa5242bd44c9b19648d79fa8fecbb7ee125288e..62d8d7dbd4d602ca8cb00ff0cf1331583b398323 100644 +--- a/src/main/java/org/bukkit/entity/Entity.java ++++ b/src/main/java/org/bukkit/entity/Entity.java +@@ -770,5 +770,12 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent + * @return Whether the entity was successfully spawned. + */ + boolean spawnAt(@NotNull Location location, @NotNull org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason spawnReason); ++ ++ /** ++ * Checks if the entity is in daylight ++ * ++ * @return True if in daylight ++ */ ++ boolean isInDaylight(); + // Purpur end + } +diff --git a/src/main/java/org/bukkit/entity/LivingEntity.java b/src/main/java/org/bukkit/entity/LivingEntity.java +index f64cd3a467ccb4f773138542a6beb61ab2e1ae40..41f91ab59e34b2b15432d3941e4ee5658b24f10e 100644 +--- a/src/main/java/org/bukkit/entity/LivingEntity.java ++++ b/src/main/java/org/bukkit/entity/LivingEntity.java +@@ -895,5 +895,19 @@ public interface LivingEntity extends Attributable, Damageable, ProjectileSource + * @param slot Equipment slot to play break animation for + */ + void broadcastItemBreak(@NotNull org.bukkit.inventory.EquipmentSlot slot); ++ ++ /** ++ * If this mob will burn in the sunlight ++ * ++ * @return True if mob will burn in sunlight ++ */ ++ boolean shouldBurnInDay(); ++ ++ /** ++ * Set if this mob should burn in the sunlight ++ * ++ * @param shouldBurnInDay True to burn in sunlight ++ */ ++ void setShouldBurnInDay(boolean shouldBurnInDay); + // Purpur end + } diff --git a/patches/Purpur/patches/api/0041-Flying-Fall-Damage-API.patch b/patches/Purpur/patches/api/0041-Flying-Fall-Damage-API.patch new file mode 100644 index 00000000..890534c3 --- /dev/null +++ b/patches/Purpur/patches/api/0041-Flying-Fall-Damage-API.patch @@ -0,0 +1,30 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: TreyRuffy +Date: Wed, 9 Jun 2021 16:31:15 -0600 +Subject: [PATCH] Flying Fall Damage API + + +diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java +index 9f289576d97c3406d506d3f4fa7287bc74e5b425..df1da8a7dec072ddc33a884973bcad67152576fe 100644 +--- a/src/main/java/org/bukkit/entity/Player.java ++++ b/src/main/java/org/bukkit/entity/Player.java +@@ -2185,5 +2185,19 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * @param invulnerableTicks Invulnerable ticks remaining + */ + void setSpawnInvulnerableTicks(int invulnerableTicks); ++ ++ /** ++ * Allows you to enable fall damage while {@link #getAllowFlight()} is {@code true} ++ * ++ * @param flyingFallDamage Enables fall damage when {@link #getAllowFlight()} is true ++ */ ++ public void setFlyingFallDamage(boolean flyingFallDamage); ++ ++ /** ++ * Allows you get if fall damage is enabled while {@link #getAllowFlight()} is {@code true} ++ * ++ * @return True if fall damage is enabled when {@link #getAllowFlight()} is true ++ */ ++ public boolean hasFlyingFallDamage(); + // Purpur end + } diff --git a/patches/Purpur/patches/server/0001-Purpur-config-files.patch b/patches/Purpur/patches/server/0001-Purpur-config-files.patch new file mode 100644 index 00000000..f3650811 --- /dev/null +++ b/patches/Purpur/patches/server/0001-Purpur-config-files.patch @@ -0,0 +1,424 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Thu, 9 May 2019 18:09:43 -0500 +Subject: [PATCH] Purpur config files + + +diff --git a/src/main/java/com/destroystokyo/paper/Metrics.java b/src/main/java/com/destroystokyo/paper/Metrics.java +index 52c0ab1ce46e1f3233ef746d9bc699356fa9fae4..4d8740678049aa749b42618470e9cc838555528d 100644 +--- a/src/main/java/com/destroystokyo/paper/Metrics.java ++++ b/src/main/java/com/destroystokyo/paper/Metrics.java +@@ -593,7 +593,7 @@ public class Metrics { + boolean logFailedRequests = config.getBoolean("logFailedRequests", false); + // Only start Metrics, if it's enabled in the config + if (config.getBoolean("enabled", true)) { +- Metrics metrics = new Metrics("Tuinity", serverUUID, logFailedRequests, Bukkit.getLogger()); // Tuinity - we have our own bstats page ++ Metrics metrics = new Metrics("Purpur", serverUUID, logFailedRequests, Bukkit.getLogger()); // Purpur + + metrics.addCustomChart(new Metrics.SimplePie("minecraft_version", () -> { + String minecraftVersion = Bukkit.getVersion(); +@@ -602,8 +602,8 @@ public class Metrics { + })); + + metrics.addCustomChart(new Metrics.SingleLineChart("players", () -> Bukkit.getOnlinePlayers().size())); +- metrics.addCustomChart(new Metrics.SimplePie("online_mode", () -> Bukkit.getOnlineMode() || PaperConfig.isProxyOnlineMode() ? "online" : "offline")); +- metrics.addCustomChart(new Metrics.SimplePie("tuinity_version", () -> (Metrics.class.getPackage().getImplementationVersion() != null) ? Metrics.class.getPackage().getImplementationVersion() : "unknown")); // Tuinity - we have our own bstats page ++ metrics.addCustomChart(new Metrics.SimplePie("online_mode", () -> Bukkit.getOnlineMode() ? "online" : (PaperConfig.isProxyOnlineMode() ? "bungee" : "offline"))); // Purpur ++ metrics.addCustomChart(new Metrics.SimplePie("purpur_version", () -> (Metrics.class.getPackage().getImplementationVersion() != null) ? Metrics.class.getPackage().getImplementationVersion() : "unknown")); // Purpur + + metrics.addCustomChart(new Metrics.DrilldownPie("java_version", () -> { + Map> map = new HashMap<>(); +diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java +index 7acf077bc131af718c7548cc29deef558c04e463..10126cb1c3efa2e6c84f20c0da701a131a5dd4cb 100644 +--- a/src/main/java/com/destroystokyo/paper/PaperConfig.java ++++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java +@@ -118,6 +118,11 @@ public class PaperConfig { + } + } + ++ // Purpur start - public save method for config migration ++ saveConfig(); ++ } ++ public static void saveConfig() { ++ // Purpur end + try { + config.save(CONFIG_FILE); + } catch (IOException ex) { +diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java +index 3713a110a64fa686e785b9789c33dd09cacc2f48..8db809fdaf1e18a54a21812ff5688095f6ffd6f4 100644 +--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java ++++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java +@@ -212,6 +212,15 @@ public class DedicatedServer extends MinecraftServer implements IMinecraftServer + return false; + } + com.destroystokyo.paper.PaperConfig.registerCommands(); ++ // Purpur start ++ try { ++ net.pl3x.purpur.PurpurConfig.init((java.io.File) options.valueOf("purpur-settings")); ++ } catch (Exception e) { ++ DedicatedServer.LOGGER.error("Unable to load server configuration", e); ++ return false; ++ } ++ net.pl3x.purpur.PurpurConfig.registerCommands(); ++ // Purpur end + com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // load version history now + io.papermc.paper.brigadier.PaperBrigadierProviderImpl.INSTANCE.getClass(); // init PaperBrigadierProvider + // Paper end +diff --git a/src/main/java/net/minecraft/world/level/World.java b/src/main/java/net/minecraft/world/level/World.java +index cb8064df7e9f1b8b4d4292486e2193680d83663c..22d91a970c7376aa6349bb6cd9cb174e89bc8a09 100644 +--- a/src/main/java/net/minecraft/world/level/World.java ++++ b/src/main/java/net/minecraft/world/level/World.java +@@ -155,6 +155,7 @@ public abstract class World implements GeneratorAccess, AutoCloseable { + public final ChunkPacketBlockController chunkPacketBlockController; // Paper - Anti-Xray + + public final com.tuinity.tuinity.config.TuinityConfig.WorldConfig tuinityConfig; // Tuinity - Server Config ++ public final net.pl3x.purpur.PurpurWorldConfig purpurConfig; // Purpur + + public final co.aikar.timings.WorldTimingsHandler timings; // Paper + public static BlockPosition lastPhysicsProblem; // Spigot +@@ -254,6 +255,7 @@ public abstract class World implements GeneratorAccess, AutoCloseable { + this.paperConfig = new com.destroystokyo.paper.PaperWorldConfig(((net.minecraft.world.level.storage.WorldDataServer) worlddatamutable).getName(), this.spigotConfig); // Paper + this.chunkPacketBlockController = this.paperConfig.antiXray ? new ChunkPacketBlockControllerAntiXray(this, executor) : ChunkPacketBlockController.NO_OPERATION_INSTANCE; // Paper - Anti-Xray + this.tuinityConfig = new com.tuinity.tuinity.config.TuinityConfig.WorldConfig(((net.minecraft.world.level.storage.WorldDataServer)worlddatamutable).getName()); // Tuinity - Server Config ++ this.purpurConfig = new net.pl3x.purpur.PurpurWorldConfig((((net.minecraft.world.level.storage.WorldDataServer)worlddatamutable).getName())); // Purpur + this.generator = gen; + this.world = new CraftWorld((WorldServer) this, gen, env); + this.ticksPerAnimalSpawns = this.getServer().getTicksPerAnimalSpawns(); // CraftBukkit +diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java +new file mode 100644 +index 0000000000000000000000000000000000000000..74fc4fc2216cf82e1546ef3d567f2750b1240df1 +--- /dev/null ++++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java +@@ -0,0 +1,130 @@ ++package net.pl3x.purpur; ++ ++import com.google.common.base.Throwables; ++import net.minecraft.server.MinecraftServer; ++import net.pl3x.purpur.command.PurpurCommand; ++import org.bukkit.Bukkit; ++import org.bukkit.command.Command; ++import org.bukkit.configuration.InvalidConfigurationException; ++import org.bukkit.configuration.file.YamlConfiguration; ++ ++import java.io.File; ++import java.io.IOException; ++import java.lang.reflect.InvocationTargetException; ++import java.lang.reflect.Method; ++import java.lang.reflect.Modifier; ++import java.util.HashMap; ++import java.util.List; ++import java.util.Map; ++import java.util.logging.Level; ++ ++public class PurpurConfig { ++ private static final String HEADER = "This is the main configuration file for Purpur.\n" ++ + "As you can see, there's tons to configure. Some options may impact gameplay, so use\n" ++ + "with caution, and make sure you know what each option does before configuring.\n" ++ + "\n" ++ + "If you need help with the configuration or have any questions related to Purpur,\n" ++ + "join us in our Discord guild.\n" ++ + "\n" ++ + "Website: https://github.com/pl3xgaming/Purpur \n" ++ + "Wiki: https://github.com/pl3xgaming/Purpur/wiki \n"; ++ private static File CONFIG_FILE; ++ public static YamlConfiguration config; ++ ++ private static Map commands; ++ ++ static int version; ++ static boolean verbose; ++ ++ public static void init(File configFile) { ++ CONFIG_FILE = configFile; ++ config = new YamlConfiguration(); ++ try { ++ config.load(CONFIG_FILE); ++ } catch (IOException ignore) { ++ } catch (InvalidConfigurationException ex) { ++ Bukkit.getLogger().log(Level.SEVERE, "Could not load purpur.yml, please correct your syntax errors", ex); ++ throw Throwables.propagate(ex); ++ } ++ config.options().header(HEADER); ++ config.options().copyDefaults(true); ++ verbose = getBoolean("verbose", false); ++ ++ commands = new HashMap<>(); ++ commands.put("purpur", new PurpurCommand("purpur")); ++ ++ version = getInt("config-version", 13); ++ set("config-version", 13); ++ ++ readConfig(PurpurConfig.class, null); ++ } ++ ++ protected static void log(String s) { ++ if (verbose) { ++ log(Level.INFO, s); ++ } ++ } ++ ++ protected static void log(Level level, String s) { ++ Bukkit.getLogger().log(level, s); ++ } ++ ++ public static void registerCommands() { ++ for (Map.Entry entry : commands.entrySet()) { ++ MinecraftServer.getServer().server.getCommandMap().register(entry.getKey(), "Purpur", entry.getValue()); ++ } ++ } ++ ++ static void readConfig(Class clazz, Object instance) { ++ for (Method method : clazz.getDeclaredMethods()) { ++ if (Modifier.isPrivate(method.getModifiers())) { ++ if (method.getParameterTypes().length == 0 && method.getReturnType() == Void.TYPE) { ++ try { ++ method.setAccessible(true); ++ method.invoke(instance); ++ } catch (InvocationTargetException ex) { ++ throw Throwables.propagate(ex.getCause()); ++ } catch (Exception ex) { ++ Bukkit.getLogger().log(Level.SEVERE, "Error invoking " + method, ex); ++ } ++ } ++ } ++ } ++ ++ try { ++ config.save(CONFIG_FILE); ++ } catch (IOException ex) { ++ Bukkit.getLogger().log(Level.SEVERE, "Could not save " + CONFIG_FILE, ex); ++ } ++ } ++ ++ private static void set(String path, Object val) { ++ config.addDefault(path, val); ++ config.set(path, val); ++ } ++ ++ private static boolean getBoolean(String path, boolean def) { ++ config.addDefault(path, def); ++ return config.getBoolean(path, config.getBoolean(path)); ++ } ++ ++ private static double getDouble(String path, double def) { ++ config.addDefault(path, def); ++ return config.getDouble(path, config.getDouble(path)); ++ } ++ ++ private static int getInt(String path, int def) { ++ config.addDefault(path, def); ++ return config.getInt(path, config.getInt(path)); ++ } ++ ++ private static List getList(String path, T def) { ++ config.addDefault(path, def); ++ return config.getList(path, config.getList(path)); ++ } ++ ++ private static String getString(String path, String def) { ++ config.addDefault(path, def); ++ return config.getString(path, config.getString(path)); ++ } ++} +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +new file mode 100644 +index 0000000000000000000000000000000000000000..361f7857e461578e90cb71e15027dadaf794cb69 +--- /dev/null ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -0,0 +1,59 @@ ++package net.pl3x.purpur; ++ ++import org.bukkit.configuration.ConfigurationSection; ++import java.util.List; ++import static net.pl3x.purpur.PurpurConfig.log; ++ ++public class PurpurWorldConfig { ++ ++ private final String worldName; ++ ++ public PurpurWorldConfig(String worldName) { ++ this.worldName = worldName; ++ init(); ++ } ++ ++ public void init() { ++ log("-------- World Settings For [" + worldName + "] --------"); ++ PurpurConfig.readConfig(PurpurWorldConfig.class, this); ++ } ++ ++ private void set(String path, Object val) { ++ PurpurConfig.config.addDefault("world-settings.default." + path, val); ++ PurpurConfig.config.set("world-settings.default." + path, val); ++ if (PurpurConfig.config.get("world-settings." + worldName + "." + path) != null) { ++ PurpurConfig.config.addDefault("world-settings." + worldName + "." + path, val); ++ PurpurConfig.config.set("world-settings." + worldName + "." + path, val); ++ } ++ } ++ ++ private ConfigurationSection getConfigurationSection(String path) { ++ ConfigurationSection section = PurpurConfig.config.getConfigurationSection("world-settings." + worldName + "." + path); ++ return section != null ? section : PurpurConfig.config.getConfigurationSection("world-settings.default." + path); ++ } ++ ++ private boolean getBoolean(String path, boolean def) { ++ PurpurConfig.config.addDefault("world-settings.default." + path, def); ++ return PurpurConfig.config.getBoolean("world-settings." + worldName + "." + path, PurpurConfig.config.getBoolean("world-settings.default." + path)); ++ } ++ ++ private double getDouble(String path, double def) { ++ PurpurConfig.config.addDefault("world-settings.default." + path, def); ++ return PurpurConfig.config.getDouble("world-settings." + worldName + "." + path, PurpurConfig.config.getDouble("world-settings.default." + path)); ++ } ++ ++ private int getInt(String path, int def) { ++ PurpurConfig.config.addDefault("world-settings.default." + path, def); ++ return PurpurConfig.config.getInt("world-settings." + worldName + "." + path, PurpurConfig.config.getInt("world-settings.default." + path)); ++ } ++ ++ private List getList(String path, T def) { ++ PurpurConfig.config.addDefault("world-settings.default." + path, def); ++ return PurpurConfig.config.getList("world-settings." + worldName + "." + path, PurpurConfig.config.getList("world-settings.default." + path)); ++ } ++ ++ private String getString(String path, String def) { ++ PurpurConfig.config.addDefault("world-settings.default." + path, def); ++ return PurpurConfig.config.getString("world-settings." + worldName + "." + path, PurpurConfig.config.getString("world-settings.default." + path)); ++ } ++} +diff --git a/src/main/java/net/pl3x/purpur/command/PurpurCommand.java b/src/main/java/net/pl3x/purpur/command/PurpurCommand.java +new file mode 100644 +index 0000000000000000000000000000000000000000..536955124afaec5c8a070249c7432cb99bf43d67 +--- /dev/null ++++ b/src/main/java/net/pl3x/purpur/command/PurpurCommand.java +@@ -0,0 +1,65 @@ ++package net.pl3x.purpur.command; ++ ++import net.minecraft.server.MinecraftServer; ++import net.minecraft.server.level.WorldServer; ++import net.pl3x.purpur.PurpurConfig; ++import org.bukkit.ChatColor; ++import org.bukkit.Location; ++import org.bukkit.command.Command; ++import org.bukkit.command.CommandSender; ++ ++import java.io.File; ++import java.util.Collections; ++import java.util.List; ++import java.util.stream.Collectors; ++import java.util.stream.Stream; ++ ++public class PurpurCommand extends Command { ++ public PurpurCommand(String name) { ++ super(name); ++ this.description = "Purpur related commands"; ++ this.usageMessage = "/purpur [reload | version]"; ++ this.setPermission("bukkit.command.purpur"); ++ } ++ ++ @Override ++ public List tabComplete(CommandSender sender, String alias, String[] args, Location location) throws IllegalArgumentException { ++ if (args.length == 1) { ++ return Stream.of("reload", "version") ++ .filter(arg -> arg.startsWith(args[0].toLowerCase())) ++ .collect(Collectors.toList()); ++ } ++ return Collections.emptyList(); ++ } ++ ++ @Override ++ public boolean execute(CommandSender sender, String commandLabel, String[] args) { ++ if (!testPermission(sender)) return true; ++ ++ if (args.length != 1) { ++ sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); ++ return false; ++ } ++ ++ if (args[0].equalsIgnoreCase("reload")) { ++ Command.broadcastCommandMessage(sender, ChatColor.RED + "Please note that this command is not supported and may cause issues."); ++ Command.broadcastCommandMessage(sender, ChatColor.RED + "If you encounter any issues please use the /stop command to restart your server."); ++ ++ MinecraftServer console = MinecraftServer.getServer(); ++ PurpurConfig.init((File) console.options.valueOf("purpur-settings")); ++ for (WorldServer world : console.getWorlds()) { ++ world.purpurConfig.init(); ++ } ++ console.server.reloadCount++; ++ ++ Command.broadcastCommandMessage(sender, ChatColor.GREEN + "Purpur config reload complete."); ++ } else if (args[0].equalsIgnoreCase("version")) { ++ Command verCmd = org.bukkit.Bukkit.getServer().getCommandMap().getCommand("version"); ++ if (verCmd != null) { ++ return verCmd.execute(sender, commandLabel, new String[0]); ++ } ++ } ++ ++ return true; ++ } ++} +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +index 507c5255542ba1b958470b4db2c35b1b0b779f17..04f81eafed1af281222e961f9fa8a4b2736cc2e3 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +@@ -881,6 +881,7 @@ public final class CraftServer implements Server { + org.spigotmc.SpigotConfig.init((File) console.options.valueOf("spigot-settings")); // Spigot + com.destroystokyo.paper.PaperConfig.init((File) console.options.valueOf("paper-settings")); // Paper + com.tuinity.tuinity.config.TuinityConfig.init((File) console.options.valueOf("tuinity-settings")); // Tuinity - Server Config ++ net.pl3x.purpur.PurpurConfig.init((File) console.options.valueOf("purpur-settings")); // Purpur + for (WorldServer world : console.getWorlds()) { + world.worldDataServer.setDifficulty(config.difficulty); + world.setSpawnFlags(config.spawnMonsters, config.spawnAnimals); +@@ -916,6 +917,7 @@ public final class CraftServer implements Server { + world.spigotConfig.init(); // Spigot + world.paperConfig.init(); // Paper + world.tuinityConfig.init(); // Tuinity - Server Config ++ world.purpurConfig.init(); // Purpur + } + + Plugin[] pluginClone = pluginManager.getPlugins().clone(); // Paper +@@ -934,6 +936,7 @@ public final class CraftServer implements Server { + reloadData(); + org.spigotmc.SpigotConfig.registerCommands(); // Spigot + com.destroystokyo.paper.PaperConfig.registerCommands(); // Paper ++ net.pl3x.purpur.PurpurConfig.registerCommands(); // Purpur + overrideAllCommandBlockCommands = commandsConfiguration.getStringList("command-block-overrides").contains("*"); + ignoreVanillaPermissions = commandsConfiguration.getBoolean("ignore-vanilla-permissions"); + +@@ -2384,6 +2387,18 @@ public final class CraftServer implements Server { + } + // Tuinity end - add config to timings report + ++ // Purpur start ++ @Override ++ public YamlConfiguration getPurpurConfig() { ++ return net.pl3x.purpur.PurpurConfig.config; ++ } ++ ++ @Override ++ public java.util.Properties getServerProperties() { ++ return getProperties().properties; ++ } ++ // Purpur end ++ + @Override + public void restart() { + org.spigotmc.RestartCommand.restart(); +diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java +index fbeca329f62325aa479f968e7f0f04cde341a009..424d55f51a36d9033db3dfbf2f7a86749b0e3b91 100644 +--- a/src/main/java/org/bukkit/craftbukkit/Main.java ++++ b/src/main/java/org/bukkit/craftbukkit/Main.java +@@ -154,6 +154,14 @@ public class Main { + .describedAs("Yml file"); + /* Conctete End - Server Config */ + ++ // Purpur Start ++ acceptsAll(asList("purpur", "purpur-settings"), "File for purpur settings") ++ .withRequiredArg() ++ .ofType(File.class) ++ .defaultsTo(new File("purpur.yml")) ++ .describedAs("Yml file"); ++ // Purpur end ++ + // Paper start + acceptsAll(asList("server-name"), "Name of the server") + .withRequiredArg() diff --git a/patches/Purpur/patches/server/0002-Timings-stuff.patch b/patches/Purpur/patches/server/0002-Timings-stuff.patch new file mode 100644 index 00000000..7919aa80 --- /dev/null +++ b/patches/Purpur/patches/server/0002-Timings-stuff.patch @@ -0,0 +1,73 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Fri, 5 Jun 2020 21:30:19 -0500 +Subject: [PATCH] Timings stuff + + +diff --git a/src/main/java/co/aikar/timings/TimingsExport.java b/src/main/java/co/aikar/timings/TimingsExport.java +index 35810f42d7a0cd50a4cbe90e8d698fe57914c889..5e672a0660d0aceffcdb26d185590ca18aa4f023 100644 +--- a/src/main/java/co/aikar/timings/TimingsExport.java ++++ b/src/main/java/co/aikar/timings/TimingsExport.java +@@ -227,10 +227,14 @@ public class TimingsExport extends Thread { + // Information on the users Config + + parent.put("config", createObject( +- pair("spigot", mapAsJSON(Bukkit.spigot().getSpigotConfig(), null)), +- pair("bukkit", mapAsJSON(Bukkit.spigot().getBukkitConfig(), null)), +- pair("paper", mapAsJSON(Bukkit.spigot().getPaperConfig(), null)), // Tuinity - add config to timings report +- pair("tuinity", mapAsJSON(Bukkit.spigot().getTuinityConfig(), null)) // Tuinity - add config to timings report ++ // Purpur start ++ pair("server.properties", mapAsJSON(Bukkit.spigot().getServerProperties())), ++ pair("bukkit", mapAsJSON(Bukkit.spigot().getBukkitConfig(), null)), ++ pair("spigot", mapAsJSON(Bukkit.spigot().getSpigotConfig(), null)), ++ pair("paper", mapAsJSON(Bukkit.spigot().getPaperConfig(), null)), ++ pair("tuinity", mapAsJSON(Bukkit.spigot().getTuinityConfig(), null)), // Tuinity - add config to timings report ++ pair("purpur", mapAsJSON(Bukkit.spigot().getPurpurConfig(), null)) ++ // Purpur end + )); + + new TimingsExport(listeners, parent, history).start(); +@@ -271,6 +275,19 @@ public class TimingsExport extends Thread { + return timingsCost; + } + ++ // Purpur start ++ private static JSONObject mapAsJSON(java.util.Properties properties) { ++ JSONObject object = new JSONObject(); ++ for (String key : properties.stringPropertyNames()) { ++ if (key.startsWith("rcon") || key.startsWith("query") || key.equals("level-seed") || TimingsManager.hiddenConfigs.contains(key)) { ++ continue; ++ } ++ object.put(key, valAsJSON(properties.get(key), key)); ++ } ++ return object; ++ } ++ // Purpur end ++ + private static JSONObject mapAsJSON(ConfigurationSection config, String parentKey) { + + JSONObject object = new JSONObject(); +@@ -307,7 +324,7 @@ public class TimingsExport extends Thread { + String response = null; + String timingsURL = null; + try { +- HttpURLConnection con = (HttpURLConnection) new URL("http://timings.aikar.co/post").openConnection(); ++ HttpURLConnection con = (HttpURLConnection) new URL(net.pl3x.purpur.PurpurConfig.timingsUrl + "/post").openConnection(); // Purpur + con.setDoOutput(true); + String hostName = "BrokenHost"; + try { +diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java +index 74fc4fc2216cf82e1546ef3d567f2750b1240df1..108be36fc37c04eece6ccb93d19e58a31326ceb0 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java +@@ -127,4 +127,10 @@ public class PurpurConfig { + config.addDefault(path, def); + return config.getString(path, config.getString(path)); + } ++ ++ public static String timingsUrl = "https://timings.pl3x.net"; ++ private static void timingsSettings() { ++ timingsUrl = getString("settings.timings.url", timingsUrl); ++ if (!TimingsManager.hiddenConfigs.contains("server-ip")) TimingsManager.hiddenConfigs.add("server-ip"); ++ } + } diff --git a/patches/Purpur/patches/server/0003-Barrels-and-enderchests-6-rows.patch b/patches/Purpur/patches/server/0003-Barrels-and-enderchests-6-rows.patch new file mode 100644 index 00000000..aceec8b1 --- /dev/null +++ b/patches/Purpur/patches/server/0003-Barrels-and-enderchests-6-rows.patch @@ -0,0 +1,189 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Thu, 23 May 2019 21:50:37 -0500 +Subject: [PATCH] Barrels and enderchests 6 rows + + +diff --git a/src/main/java/net/minecraft/world/inventory/InventoryEnderChest.java b/src/main/java/net/minecraft/world/inventory/InventoryEnderChest.java +index 85b9eba1dba3de69ab65b0e1c5ebb8740ce6e9e5..97f6ba97a4b2a35c0b8a003e1e27ad38831d859d 100644 +--- a/src/main/java/net/minecraft/world/inventory/InventoryEnderChest.java ++++ b/src/main/java/net/minecraft/world/inventory/InventoryEnderChest.java +@@ -28,11 +28,34 @@ public class InventoryEnderChest extends InventorySubcontainer { + } + + public InventoryEnderChest(EntityHuman owner) { +- super(27); ++ super(net.pl3x.purpur.PurpurConfig.enderChestSixRows ? 54 : 27); // Purpur + this.owner = owner; + // CraftBukkit end + } + ++ // Purpur start ++ @Override ++ public int getSize() { ++ if (net.pl3x.purpur.PurpurConfig.enderChestSixRows && net.pl3x.purpur.PurpurConfig.enderChestPermissionRows && owner != null && owner.getProfile() != null) { ++ org.bukkit.craftbukkit.entity.CraftHumanEntity bukkit = owner.getBukkitEntity(); ++ if (bukkit.hasPermission("purpur.enderchest.rows.six")) { ++ return 54; ++ } else if (bukkit.hasPermission("purpur.enderchest.rows.five")) { ++ return 45; ++ } else if (bukkit.hasPermission("purpur.enderchest.rows.four")) { ++ return 36; ++ } else if (bukkit.hasPermission("purpur.enderchest.rows.three")) { ++ return 27; ++ } else if (bukkit.hasPermission("purpur.enderchest.rows.two")) { ++ return 18; ++ } else if (bukkit.hasPermission("purpur.enderchest.rows.one")) { ++ return 9; ++ } ++ } ++ return super.getSize(); ++ } ++ // Purpur end ++ + public void a(TileEntityEnderChest tileentityenderchest) { + this.a = tileentityenderchest; + } +diff --git a/src/main/java/net/minecraft/world/level/block/BlockEnderChest.java b/src/main/java/net/minecraft/world/level/block/BlockEnderChest.java +index 70d10c492b6ba893d56a463c0e71ac6aa8707f81..34ea9d2aeb9d606d487be796283c9d5ed614a6af 100644 +--- a/src/main/java/net/minecraft/world/level/block/BlockEnderChest.java ++++ b/src/main/java/net/minecraft/world/level/block/BlockEnderChest.java +@@ -11,6 +11,7 @@ import net.minecraft.world.TileInventory; + import net.minecraft.world.entity.monster.piglin.PiglinAI; + import net.minecraft.world.entity.player.EntityHuman; + import net.minecraft.world.inventory.ContainerChest; ++import net.minecraft.world.inventory.Containers; + import net.minecraft.world.inventory.InventoryEnderChest; + import net.minecraft.world.item.context.BlockActionContext; + import net.minecraft.world.level.GeneratorAccess; +@@ -81,6 +82,27 @@ public class BlockEnderChest extends BlockChestAbstract im + + inventoryenderchest.a(tileentityenderchest); + entityhuman.openContainer(new TileInventory((i, playerinventory, entityhuman1) -> { ++ // Purpur start ++ if (net.pl3x.purpur.PurpurConfig.enderChestSixRows) { ++ if (net.pl3x.purpur.PurpurConfig.enderChestPermissionRows) { ++ org.bukkit.craftbukkit.entity.CraftHumanEntity player = entityhuman.getBukkitEntity(); ++ if (player.hasPermission("purpur.enderchest.rows.six")) { ++ return new ContainerChest(Containers.GENERIC_9X6, i, playerinventory, inventoryenderchest, 6); ++ } else if (player.hasPermission("purpur.enderchest.rows.five")) { ++ return new ContainerChest(Containers.GENERIC_9X5, i, playerinventory, inventoryenderchest, 5); ++ } else if (player.hasPermission("purpur.enderchest.rows.four")) { ++ return new ContainerChest(Containers.GENERIC_9X4, i, playerinventory, inventoryenderchest, 4); ++ } else if (player.hasPermission("purpur.enderchest.rows.three")) { ++ return new ContainerChest(Containers.GENERIC_9X3, i, playerinventory, inventoryenderchest, 3); ++ } else if (player.hasPermission("purpur.enderchest.rows.two")) { ++ return new ContainerChest(Containers.GENERIC_9X2, i, playerinventory, inventoryenderchest, 2); ++ } else if (player.hasPermission("purpur.enderchest.rows.one")) { ++ return new ContainerChest(Containers.GENERIC_9X1, i, playerinventory, inventoryenderchest, 1); ++ } ++ } ++ return new ContainerChest(Containers.GENERIC_9X6, i, playerinventory, inventoryenderchest, 6); ++ } ++ // Purpur end + return ContainerChest.a(i, playerinventory, inventoryenderchest); + }, BlockEnderChest.e)); + entityhuman.a(StatisticList.OPEN_ENDERCHEST); +diff --git a/src/main/java/net/minecraft/world/level/block/entity/TileEntityBarrel.java b/src/main/java/net/minecraft/world/level/block/entity/TileEntityBarrel.java +index 7a6f150490bc3ef8a5ed43c401fd70bcc67f40f0..449d2c38abdd35b782a6732006eebb381815bcba 100644 +--- a/src/main/java/net/minecraft/world/level/block/entity/TileEntityBarrel.java ++++ b/src/main/java/net/minecraft/world/level/block/entity/TileEntityBarrel.java +@@ -14,6 +14,7 @@ import net.minecraft.world.entity.player.EntityHuman; + import net.minecraft.world.entity.player.PlayerInventory; + import net.minecraft.world.inventory.Container; + import net.minecraft.world.inventory.ContainerChest; ++import net.minecraft.world.inventory.Containers; + import net.minecraft.world.item.ItemStack; + import net.minecraft.world.level.block.BlockBarrel; + import net.minecraft.world.level.block.Blocks; +@@ -68,7 +69,7 @@ public class TileEntityBarrel extends TileEntityLootable { + + private TileEntityBarrel(TileEntityTypes tileentitytypes) { + super(tileentitytypes); +- this.items = NonNullList.a(27, ItemStack.b); ++ this.items = NonNullList.a(net.pl3x.purpur.PurpurConfig.barrelSixRows ? 54 : 27, ItemStack.b); // Purpur + } + + public TileEntityBarrel() { +@@ -97,7 +98,7 @@ public class TileEntityBarrel extends TileEntityLootable { + + @Override + public int getSize() { +- return 27; ++ return net.pl3x.purpur.PurpurConfig.barrelSixRows ? 54 : 27; // Purpur + } + + @Override +@@ -117,6 +118,7 @@ public class TileEntityBarrel extends TileEntityLootable { + + @Override + protected Container createContainer(int i, PlayerInventory playerinventory) { ++ if (net.pl3x.purpur.PurpurConfig.barrelSixRows) return new ContainerChest(Containers.GENERIC_9X6, i, playerinventory, this, 6); // Purpur + return ContainerChest.a(i, playerinventory, this); + } + +diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java +index 108be36fc37c04eece6ccb93d19e58a31326ceb0..2f329bae9f09d0ed21a4538fba6b95919ec35887 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java +@@ -7,6 +7,7 @@ import org.bukkit.Bukkit; + import org.bukkit.command.Command; + import org.bukkit.configuration.InvalidConfigurationException; + import org.bukkit.configuration.file.YamlConfiguration; ++import org.bukkit.event.inventory.InventoryType; + + import java.io.File; + import java.io.IOException; +@@ -133,4 +134,23 @@ public class PurpurConfig { + timingsUrl = getString("settings.timings.url", timingsUrl); + if (!TimingsManager.hiddenConfigs.contains("server-ip")) TimingsManager.hiddenConfigs.add("server-ip"); + } ++ ++ public static boolean barrelSixRows = false; ++ public static boolean enderChestSixRows = false; ++ public static boolean enderChestPermissionRows = false; ++ private static void blockSettings() { ++ if (version < 3) { ++ boolean oldValue = getBoolean("settings.barrel.packed-barrels", true); ++ set("settings.blocks.barrel.six-rows", oldValue); ++ set("settings.packed-barrels", null); ++ oldValue = getBoolean("settings.large-ender-chests", true); ++ set("settings.blocks.ender_chest.six-rows", oldValue); ++ set("settings.large-ender-chests", null); ++ } ++ barrelSixRows = getBoolean("settings.blocks.barrel.six-rows", barrelSixRows); ++ InventoryType.BARREL.setDefaultSize(barrelSixRows ? 54 : 27); ++ enderChestSixRows = getBoolean("settings.blocks.ender_chest.six-rows", enderChestSixRows); ++ InventoryType.ENDER_CHEST.setDefaultSize(enderChestSixRows ? 54 : 27); ++ enderChestPermissionRows = getBoolean("settings.blocks.ender_chest.use-permissions-for-rows", enderChestPermissionRows); ++ } + } +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftContainer.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftContainer.java +index 614ab2d73db2293116f2272f6cd5c16da446132d..2885dc250f171917393c0356a005b476b23f9c5f 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftContainer.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftContainer.java +@@ -212,8 +212,10 @@ public class CraftContainer extends Container { + case PLAYER: + case CHEST: + case ENDER_CHEST: ++ delegate = new ContainerChest(net.pl3x.purpur.PurpurConfig.enderChestSixRows ? Containers.GENERIC_9X6 : Containers.GENERIC_9X3, windowId, bottom, top, top.getSize() / 9); // Purpur ++ break; // Purpur + case BARREL: +- delegate = new ContainerChest(Containers.GENERIC_9X3, windowId, bottom, top, top.getSize() / 9); ++ delegate = new ContainerChest(net.pl3x.purpur.PurpurConfig.barrelSixRows ? Containers.GENERIC_9X6 : Containers.GENERIC_9X3, windowId, bottom, top, top.getSize() / 9); // Purpur + break; + case DISPENSER: + case DROPPER: +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java +index f6001047ada8308cfa1d9b26677a7a5d7774de51..922a15097bdfe64be657fdf157145d1e882b6a40 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java +@@ -82,7 +82,7 @@ public class CraftInventory implements Inventory { + + @Override + public void setContents(ItemStack[] items) { +- if (getSize() < items.length) { ++ if (false && getSize() < items.length) { // Purpur + throw new IllegalArgumentException("Invalid inventory size; expected " + getSize() + " or less"); + } + diff --git a/patches/Purpur/patches/server/0004-Advancement-API.patch b/patches/Purpur/patches/server/0004-Advancement-API.patch new file mode 100644 index 00000000..40477e4e --- /dev/null +++ b/patches/Purpur/patches/server/0004-Advancement-API.patch @@ -0,0 +1,180 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Fri, 31 May 2019 21:24:33 -0500 +Subject: [PATCH] Advancement API + + +diff --git a/src/main/java/net/minecraft/advancements/Advancement.java b/src/main/java/net/minecraft/advancements/Advancement.java +index 2f3d9e5b849093027d3c2ef434494cd600f52a31..23567430901284ab9d4d4873e53a1c8a06da6862 100644 +--- a/src/main/java/net/minecraft/advancements/Advancement.java ++++ b/src/main/java/net/minecraft/advancements/Advancement.java +@@ -78,7 +78,7 @@ public class Advancement { + + public final @Nullable AdvancementDisplay getAdvancementDisplay() { return this.c(); } // Paper - OBFHELPER + @Nullable +- public AdvancementDisplay c() { ++ public AdvancementDisplay c() { return getDisplay(); } public AdvancementDisplay getDisplay() { // Purpur + return this.display; + } + +diff --git a/src/main/java/net/minecraft/advancements/AdvancementDisplay.java b/src/main/java/net/minecraft/advancements/AdvancementDisplay.java +index adc6779e53e7b2ee04a80e2ea714e3378b8e6f39..3335c96ec15eb8d8f0b67f51846038f728f6f9fc 100644 +--- a/src/main/java/net/minecraft/advancements/AdvancementDisplay.java ++++ b/src/main/java/net/minecraft/advancements/AdvancementDisplay.java +@@ -25,10 +25,11 @@ public class AdvancementDisplay { + private final MinecraftKey d; + private final AdvancementFrameType e; + private final boolean f; +- private final boolean g; +- private final boolean h; ++ private boolean g; // Purpur - un-finalize ++ private boolean h; // Purpur - un-finalize + private float i; + private float j; ++ public final org.bukkit.advancement.AdvancementDisplay bukkit = new org.bukkit.craftbukkit.advancement.CraftAdvancementDisplay(this); // Purpur + + public AdvancementDisplay(ItemStack itemstack, IChatBaseComponent ichatbasecomponent, IChatBaseComponent ichatbasecomponent1, @Nullable MinecraftKey minecraftkey, AdvancementFrameType advancementframetype, boolean flag, boolean flag1, boolean flag2) { + this.a = ichatbasecomponent; +@@ -46,10 +47,12 @@ public class AdvancementDisplay { + this.j = f1; + } + ++ public IChatBaseComponent getTitle() { return a(); } // Purpur - OBFHELPER + public IChatBaseComponent a() { + return this.a; + } + ++ public IChatBaseComponent getDescription() { return b(); } // Purpur - OBFHELPER + public IChatBaseComponent b() { + return this.b; + } +@@ -59,11 +62,14 @@ public class AdvancementDisplay { + return this.e; + } + ++ public final void setShouldAnnounceToChat(boolean announce) { this.g = announce; } // Purpur - OBFHELPER + public final boolean shouldAnnounceToChat() { return this.i(); } // Paper - OBFHELPER + public boolean i() { + return this.g; + } + ++ public void setHidden(boolean hidden) { this.h = hidden; } // Purpur - OBFHELPER ++ public boolean isHidden() { return j(); } // Purpur - OBFHELPER + public boolean j() { + return this.h; + } +diff --git a/src/main/java/net/minecraft/advancements/AdvancementFrameType.java b/src/main/java/net/minecraft/advancements/AdvancementFrameType.java +index 32380346555e194227423999a79f1ebcbbe38d3b..173266c81be66f85db06dd28d9c9d720e21f8bc4 100644 +--- a/src/main/java/net/minecraft/advancements/AdvancementFrameType.java ++++ b/src/main/java/net/minecraft/advancements/AdvancementFrameType.java +@@ -4,16 +4,27 @@ import net.minecraft.EnumChatFormat; + import net.minecraft.network.chat.ChatMessage; + import net.minecraft.network.chat.IChatBaseComponent; + ++import org.bukkit.advancement.FrameType; // Purpur ++ + public enum AdvancementFrameType { + +- TASK("task", 0, EnumChatFormat.GREEN), CHALLENGE("challenge", 26, EnumChatFormat.DARK_PURPLE), GOAL("goal", 52, EnumChatFormat.GREEN); ++ // Purpur start ++ TASK("task", 0, EnumChatFormat.GREEN, FrameType.TASK), ++ CHALLENGE("challenge", 26, EnumChatFormat.DARK_PURPLE, FrameType.CHALLENGE), ++ GOAL("goal", 52, EnumChatFormat.GREEN, FrameType.GOAL); ++ // Purpur end + + private final String d; + private final int e; + private final EnumChatFormat f; + private final IChatBaseComponent g; + +- private AdvancementFrameType(String s, int i, EnumChatFormat enumchatformat) { ++ // Purpur start ++ public final FrameType bukkit; ++ ++ AdvancementFrameType(String s, int i, EnumChatFormat enumchatformat, FrameType bukkit) { ++ this.bukkit = bukkit; ++ // Purpur end + this.d = s; + this.e = i; + this.f = enumchatformat; +diff --git a/src/main/java/net/minecraft/advancements/CriterionTrigger.java b/src/main/java/net/minecraft/advancements/CriterionTrigger.java +index f2d74473caf96ca6e871311ef87afa128cd4d0bf..851e69a2f5155d9fa2e5652abdea9aee59e4b20a 100644 +--- a/src/main/java/net/minecraft/advancements/CriterionTrigger.java ++++ b/src/main/java/net/minecraft/advancements/CriterionTrigger.java +@@ -29,6 +29,7 @@ public interface CriterionTrigger { + this.c = s; + } + ++ public T getInstance() { return a(); } // Purpur - OBFHELPER + public T a() { + return this.a; + } +diff --git a/src/main/java/org/bukkit/craftbukkit/advancement/CraftAdvancement.java b/src/main/java/org/bukkit/craftbukkit/advancement/CraftAdvancement.java +index 77abcd6de43302985cdbb2085abece4f621068d4..c859fc16c263e0c50cb01fc722b6f6723d682481 100644 +--- a/src/main/java/org/bukkit/craftbukkit/advancement/CraftAdvancement.java ++++ b/src/main/java/org/bukkit/craftbukkit/advancement/CraftAdvancement.java +@@ -27,4 +27,11 @@ public class CraftAdvancement implements org.bukkit.advancement.Advancement { + public Collection getCriteria() { + return Collections.unmodifiableCollection(handle.getCriteria().keySet()); + } ++ ++ // Purpur start ++ @Override ++ public org.bukkit.advancement.AdvancementDisplay getDisplay() { ++ return getHandle().getDisplay() == null ? null : getHandle().getDisplay().bukkit; ++ } ++ // Purpur end + } +diff --git a/src/main/java/org/bukkit/craftbukkit/advancement/CraftAdvancementDisplay.java b/src/main/java/org/bukkit/craftbukkit/advancement/CraftAdvancementDisplay.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0b4ff544e04ec314e78a7a48b5bf90ee699b2ad6 +--- /dev/null ++++ b/src/main/java/org/bukkit/craftbukkit/advancement/CraftAdvancementDisplay.java +@@ -0,0 +1,47 @@ ++package org.bukkit.craftbukkit.advancement; ++ ++import net.minecraft.advancements.AdvancementDisplay; ++import org.bukkit.advancement.FrameType; ++import org.bukkit.craftbukkit.util.CraftChatMessage; ++ ++public class CraftAdvancementDisplay implements org.bukkit.advancement.AdvancementDisplay { ++ private final AdvancementDisplay handle; ++ ++ public CraftAdvancementDisplay(AdvancementDisplay handle) { ++ this.handle = handle; ++ } ++ ++ public AdvancementDisplay getHandle() { ++ return handle; ++ } ++ ++ @Override ++ public String getTitle() { ++ return CraftChatMessage.fromComponent(handle.getTitle()); ++ } ++ ++ @Override ++ public String getDescription() { ++ return CraftChatMessage.fromComponent(handle.getDescription()); ++ } ++ ++ @Override ++ public FrameType getFrameType() { ++ return handle.getFrameType().bukkit; ++ } ++ ++ @Override ++ public boolean shouldAnnounceToChat() { ++ return handle.shouldAnnounceToChat(); ++ } ++ ++ @Override ++ public void setShouldAnnounceToChat(boolean announce) { ++ handle.setShouldAnnounceToChat(announce); ++ } ++ ++ @Override ++ public boolean isHidden() { ++ return handle.isHidden(); ++ } ++} diff --git a/patches/Purpur/patches/server/0005-Llama-API.patch b/patches/Purpur/patches/server/0005-Llama-API.patch new file mode 100644 index 00000000..dd9d6492 --- /dev/null +++ b/patches/Purpur/patches/server/0005-Llama-API.patch @@ -0,0 +1,156 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Fri, 18 Oct 2019 22:50:12 -0500 +Subject: [PATCH] Llama API + + +diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoalLlamaFollow.java b/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoalLlamaFollow.java +index 4fd1744f13b87c79ae3f46b28a56daeaba343aa6..34a854131dd939693a6df4d52103714ebe373dc3 100644 +--- a/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoalLlamaFollow.java ++++ b/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoalLlamaFollow.java +@@ -11,7 +11,7 @@ import net.minecraft.world.phys.Vec3D; + + public class PathfinderGoalLlamaFollow extends PathfinderGoal { + +- public final EntityLlama a; ++ public final EntityLlama a; public EntityLlama getLlama() { return a; } // Purpur + private double b; + private int c; + +@@ -23,6 +23,7 @@ public class PathfinderGoalLlamaFollow extends PathfinderGoal { + + @Override + public boolean a() { ++ if (!getLlama().shouldJoinCaravan) return false; // Purpur + if (!this.a.isLeashed() && !this.a.fC()) { + List list = this.a.world.getEntities(this.a, this.a.getBoundingBox().grow(9.0D, 4.0D, 9.0D), (entity) -> { + EntityTypes entitytypes = entity.getEntityType(); +@@ -82,6 +83,7 @@ public class PathfinderGoalLlamaFollow extends PathfinderGoal { + + @Override + public boolean b() { ++ if (!getLlama().shouldJoinCaravan) return false; // Purpur + if (this.a.fC() && this.a.fD().isAlive() && this.a(this.a, 0)) { + double d0 = this.a.h((Entity) this.a.fD()); + +diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/EntityLlama.java b/src/main/java/net/minecraft/world/entity/animal/horse/EntityLlama.java +index 2005cb484ba6b5929ad81d3d120521f247f3d4cf..1c6435bf2cd870b795f87368057d8dfc1e1c938a 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/horse/EntityLlama.java ++++ b/src/main/java/net/minecraft/world/entity/animal/horse/EntityLlama.java +@@ -63,7 +63,8 @@ public class EntityLlama extends EntityHorseChestedAbstract implements IRangedEn + @Nullable + private EntityLlama bB; + @Nullable +- private EntityLlama bC; ++ private EntityLlama bC; public EntityLlama getCaravanTail() { return bC; } // Purpur - OBFHELPER ++ public boolean shouldJoinCaravan = true; // Purpur + + public EntityLlama(EntityTypes entitytypes, World world) { + super(entitytypes, world); +@@ -92,6 +93,7 @@ public class EntityLlama extends EntityHorseChestedAbstract implements IRangedEn + nbttagcompound.set("DecorItem", this.inventoryChest.getItem(1).save(new NBTTagCompound())); + } + ++ nbttagcompound.setBoolean("Purpur.ShouldJoinCaravan", shouldJoinCaravan); // Purpur + } + + @Override +@@ -103,6 +105,11 @@ public class EntityLlama extends EntityHorseChestedAbstract implements IRangedEn + this.inventoryChest.setItem(1, ItemStack.a(nbttagcompound.getCompound("DecorItem"))); + } + ++ // Purpur start ++ if (nbttagcompound.hasKey("Purpur.ShouldJoinCaravan")) { ++ nbttagcompound.setBoolean("Purpur.ShouldJoinCaravan", shouldJoinCaravan); ++ } ++ // Purpur end + this.fe(); + } + +@@ -437,19 +444,24 @@ public class EntityLlama extends EntityHorseChestedAbstract implements IRangedEn + } + } + ++ public void leaveCaravan() { fA(); } // Purpur - OBFHELPER + public void fA() { + if (this.bB != null) { ++ new net.pl3x.purpur.event.entity.LlamaLeaveCaravanEvent((org.bukkit.entity.Llama) getBukkitEntity()).callEvent(); // Purpur + this.bB.bC = null; + } + + this.bB = null; + } + ++ public void joinCaravan(EntityLlama entitiyllama) { a(entitiyllama); } // Purpur - OBFHELPER + public void a(EntityLlama entityllama) { ++ if (!shouldJoinCaravan || !new net.pl3x.purpur.event.entity.LlamaJoinCaravanEvent((org.bukkit.entity.Llama) getBukkitEntity(), (org.bukkit.entity.Llama) entityllama.getBukkitEntity()).callEvent()) return; // Purpur + this.bB = entityllama; + this.bB.bC = this; + } + ++ public boolean hasCaravanTail() { return fB(); } // Purpur - OBFHELPER + public boolean fB() { + return this.bC != null; + } +@@ -460,7 +472,7 @@ public class EntityLlama extends EntityHorseChestedAbstract implements IRangedEn + } + + @Nullable +- public EntityLlama fD() { ++ public EntityLlama fD() { return getCaravanHead(); } public EntityLlama getCaravanHead() { // Purpur - OBFHELPER + return this.bB; + } + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLlama.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLlama.java +index 818034c62893a71808e3af0aa33393605611acdd..71536b6ae6a423e33667efcf584a0020f36fb189 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLlama.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLlama.java +@@ -66,4 +66,48 @@ public class CraftLlama extends CraftChestedHorse implements Llama, CraftRangedE + public EntityType getType() { + return EntityType.LLAMA; + } ++ ++ // Purpur start ++ @Override ++ public boolean shouldJoinCaravan() { ++ return getHandle().shouldJoinCaravan; ++ } ++ ++ @Override ++ public void setShouldJoinCaravan(boolean shouldJoinCaravan) { ++ getHandle().shouldJoinCaravan = shouldJoinCaravan; ++ } ++ ++ @Override ++ public boolean inCaravan() { ++ return getHandle().inCaravan(); ++ } ++ ++ @Override ++ public void joinCaravan(Llama llama) { ++ if (llama != null) { ++ getHandle().joinCaravan(((CraftLlama) llama).getHandle()); ++ } ++ } ++ ++ @Override ++ public void leaveCaravan() { ++ getHandle().leaveCaravan(); ++ } ++ ++ @Override ++ public boolean hasCaravanTail() { ++ return getHandle().hasCaravanTail(); ++ } ++ ++ @Override ++ public Llama getCaravanHead() { ++ return getHandle().getCaravanHead() == null ? null : (Llama) getHandle().getCaravanHead().getBukkitEntity(); ++ } ++ ++ @Override ++ public Llama getCaravanTail() { ++ return getHandle().getCaravanTail() == null ? null : (Llama) getHandle().getCaravanTail().getBukkitEntity(); ++ } ++ // Purpur end + } diff --git a/patches/Purpur/patches/server/0006-AFK-API.patch b/patches/Purpur/patches/server/0006-AFK-API.patch new file mode 100644 index 00000000..ee37cbcd --- /dev/null +++ b/patches/Purpur/patches/server/0006-AFK-API.patch @@ -0,0 +1,302 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Thu, 8 Aug 2019 15:29:15 -0500 +Subject: [PATCH] AFK API + + +diff --git a/src/main/java/net/minecraft/server/level/EntityPlayer.java b/src/main/java/net/minecraft/server/level/EntityPlayer.java +index c813077455a463dd558076d1d7474829f76b905a..b302d1f7c86a8df2ede46871397189f6f2e6b912 100644 +--- a/src/main/java/net/minecraft/server/level/EntityPlayer.java ++++ b/src/main/java/net/minecraft/server/level/EntityPlayer.java +@@ -2103,8 +2103,54 @@ public class EntityPlayer extends EntityHuman implements ICrafting { + + public void resetIdleTimer() { + this.ca = SystemUtils.getMonotonicMillis(); ++ setAfk(false); // Purpur + } + ++ // Purpur start ++ private boolean isAfk = false; ++ ++ @Override ++ public void setAfk(boolean setAfk) { ++ if (this.isAfk == setAfk) { ++ return; ++ } ++ ++ String msg = setAfk ? net.pl3x.purpur.PurpurConfig.afkBroadcastAway : net.pl3x.purpur.PurpurConfig.afkBroadcastBack; ++ ++ net.pl3x.purpur.event.PlayerAFKEvent event = new net.pl3x.purpur.event.PlayerAFKEvent(getBukkitEntity(), setAfk, world.purpurConfig.idleTimeoutKick, msg, !Bukkit.isPrimaryThread()); ++ if (!event.callEvent() || event.shouldKick()) { ++ return; ++ } ++ ++ this.isAfk = setAfk; ++ ++ if (!setAfk) { ++ resetIdleTimer(); ++ } ++ ++ msg = event.getBroadcastMsg(); ++ if (msg != null && !msg.isEmpty()) { ++ server.getPlayerList().sendMessage(org.bukkit.craftbukkit.util.CraftChatMessage.fromStringOrNull(String.format(msg, getProfile().getName()))); ++ } ++ ++ if (world.purpurConfig.idleTimeoutUpdateTabList) { ++ getBukkitEntity().setPlayerListName((setAfk ? net.pl3x.purpur.PurpurConfig.afkTabListPrefix : "") + getName()); ++ } ++ ++ ((WorldServer) world).everyoneSleeping(); ++ } ++ ++ @Override ++ public boolean isAfk() { ++ return isAfk; ++ } ++ ++ @Override ++ public boolean isCollidable() { ++ return !isAfk() && super.isCollidable(); ++ } ++ // Purpur end ++ + public ServerStatisticManager getStatisticManager() { + return this.serverStatisticManager; + } +diff --git a/src/main/java/net/minecraft/server/level/WorldServer.java b/src/main/java/net/minecraft/server/level/WorldServer.java +index 6fc215df5ed3aa6ef0c23a57e8444602ff9309e8..a97b8d8116920237964cc3a887525f8c3804c640 100644 +--- a/src/main/java/net/minecraft/server/level/WorldServer.java ++++ b/src/main/java/net/minecraft/server/level/WorldServer.java +@@ -1002,7 +1002,7 @@ public class WorldServer extends World implements GeneratorAccessSeed { + // CraftBukkit end + + if (this.everyoneSleeping && this.players.stream().noneMatch((entityplayer) -> { +- return !entityplayer.isSpectator() && !entityplayer.isDeeplySleeping() && !entityplayer.fauxSleeping; // CraftBukkit ++ return !entityplayer.isSpectator() && !entityplayer.isDeeplySleeping() && !entityplayer.fauxSleeping && !(purpurConfig.idleTimeoutCountAsSleeping && entityplayer.isAfk()); // CraftBukkit // Purpur + })) { + // CraftBukkit start + long l = this.worldData.getDayTime() + 24000L; +@@ -1345,7 +1345,7 @@ public class WorldServer extends World implements GeneratorAccessSeed { + while (iterator.hasNext()) { + EntityPlayer entityplayer = (EntityPlayer) iterator.next(); + +- if (entityplayer.isSpectator() || (entityplayer.fauxSleeping && !entityplayer.isSleeping())) { // CraftBukkit ++ if (entityplayer.isSpectator() || (entityplayer.fauxSleeping && !entityplayer.isSleeping()) || (purpurConfig.idleTimeoutCountAsSleeping && entityplayer.isAfk())) { // CraftBukkit // Purpur + ++i; + } else if (entityplayer.isSleeping()) { + ++j; +diff --git a/src/main/java/net/minecraft/server/network/PlayerConnection.java b/src/main/java/net/minecraft/server/network/PlayerConnection.java +index 8513795943497ca80232e7d47066a6944c2f45ec..de72ebb94052efe8c63bf28f6741a4645b3ee721 100644 +--- a/src/main/java/net/minecraft/server/network/PlayerConnection.java ++++ b/src/main/java/net/minecraft/server/network/PlayerConnection.java +@@ -399,6 +399,12 @@ public class PlayerConnection implements PacketListenerPlayIn { + } + + if (this.player.F() > 0L && this.minecraftServer.getIdleTimeout() > 0 && SystemUtils.getMonotonicMillis() - this.player.F() > (long) (this.minecraftServer.getIdleTimeout() * 1000 * 60)) { ++ // Purpur start ++ this.player.setAfk(true); ++ if (!this.player.world.purpurConfig.idleTimeoutKick) { ++ return; ++ } ++ // Purpur end + this.player.resetIdleTimer(); // CraftBukkit - SPIGOT-854 + this.disconnect(new ChatMessage("multiplayer.disconnect.idling"), org.bukkit.event.player.PlayerKickEvent.Cause.IDLING); // Paper - kick event cause + } +@@ -682,6 +688,8 @@ public class PlayerConnection implements PacketListenerPlayIn { + this.lastYaw = to.getYaw(); + this.lastPitch = to.getPitch(); + ++ if (!to.getWorld().getUID().equals(from.getWorld().getUID()) || to.getBlockX() != from.getBlockX() || to.getBlockY() != from.getBlockY() || to.getBlockZ() != from.getBlockZ() || to.getYaw() != from.getYaw() || to.getPitch() != from.getPitch()) this.player.resetIdleTimer(); // Purpur ++ + // Skip the first time we do this + if (true) { // Spigot - don't skip any move events + Location oldTo = to.clone(); +@@ -1429,7 +1437,7 @@ public class PlayerConnection implements PacketListenerPlayIn { + + if (!this.player.H() && d11 > org.spigotmc.SpigotConfig.movedWronglyThreshold && !this.player.isSleeping() && !this.player.playerInteractManager.isCreative() && this.player.playerInteractManager.getGameMode() != EnumGamemode.SPECTATOR) { // Spigot + flag1 = true; // Tuinity - diff on change, this should be moved wrongly +- PlayerConnection.LOGGER.warn("{} moved wrongly!", this.player.getDisplayName().getString()); ++ PlayerConnection.LOGGER.warn("{} moved wrongly! ({})", this.player.getDisplayName().getString(), d11); // Purpur + } + + this.player.setLocation(d4, d5, d6, f, f1); +@@ -1479,6 +1487,8 @@ public class PlayerConnection implements PacketListenerPlayIn { + this.lastYaw = to.getYaw(); + this.lastPitch = to.getPitch(); + ++ if (!to.getWorld().getUID().equals(from.getWorld().getUID()) || to.getBlockX() != from.getBlockX() || to.getBlockY() != from.getBlockY() || to.getBlockZ() != from.getBlockZ() || to.getYaw() != from.getYaw() || to.getPitch() != from.getPitch()) this.player.resetIdleTimer(); // Purpur ++ + // Skip the first time we do this + if (from.getX() != Double.MAX_VALUE) { + Location oldTo = to.clone(); +diff --git a/src/main/java/net/minecraft/world/entity/IEntitySelector.java b/src/main/java/net/minecraft/world/entity/IEntitySelector.java +index f5e32faeb6d937cf90b1f3ea251b5cfc91f2338d..f9908fb7cc27a8947030c2100dccf1dc1a4e24f7 100644 +--- a/src/main/java/net/minecraft/world/entity/IEntitySelector.java ++++ b/src/main/java/net/minecraft/world/entity/IEntitySelector.java +@@ -15,6 +15,7 @@ import net.minecraft.world.scores.ScoreboardTeamBase; + public final class IEntitySelector { + + public static final Predicate a = Entity::isAlive; ++ public static Predicate isLivingAlive() { return b; } // Purpur - OBFHELPER + public static final Predicate b = EntityLiving::isAlive; + public static final Predicate c = (entity) -> { + return entity.isAlive() && !entity.isVehicle() && !entity.isPassenger(); +@@ -35,6 +36,7 @@ public final class IEntitySelector { + return !entity.isSpectator(); + }; + public static Predicate isInsomniac = (player) -> MathHelper.clamp(((EntityPlayer) player).getStatisticManager().getStatisticValue(StatisticList.CUSTOM.get(StatisticList.TIME_SINCE_REST)), 1, Integer.MAX_VALUE) >= 72000; // Paper ++ public static Predicate notAfk = (player) -> !player.isAfk(); // Purpur + + // Paper start + public static final Predicate affectsSpawning = (entity) -> { +diff --git a/src/main/java/net/minecraft/world/entity/player/EntityHuman.java b/src/main/java/net/minecraft/world/entity/player/EntityHuman.java +index 5bce47fa8f191bc1d33c04c9865cb0efd492a9a2..afa14eddb6a21d4747689af6d70551f10d304be7 100644 +--- a/src/main/java/net/minecraft/world/entity/player/EntityHuman.java ++++ b/src/main/java/net/minecraft/world/entity/player/EntityHuman.java +@@ -181,6 +181,15 @@ public abstract class EntityHuman extends EntityLiving { + } + // CraftBukkit end + ++ // Purpur start ++ public void setAfk(boolean setAfk){ ++ } ++ ++ public boolean isAfk() { ++ return false; ++ } ++ // Purpur end ++ + public EntityHuman(World world, BlockPosition blockposition, float f, GameProfile gameprofile) { + super(EntityTypes.PLAYER, world); + this.bL = ItemStack.b; +diff --git a/src/main/java/net/minecraft/world/level/IEntityAccess.java b/src/main/java/net/minecraft/world/level/IEntityAccess.java +index a7f2304acf8ee0a15d6eae8c42060e003be13ae7..fd56b2f15e570f266a79c25823a3b3530a693510 100644 +--- a/src/main/java/net/minecraft/world/level/IEntityAccess.java ++++ b/src/main/java/net/minecraft/world/level/IEntityAccess.java +@@ -183,28 +183,18 @@ public interface IEntityAccess { + } + // Paper end + +- default boolean isPlayerNearby(double d0, double d1, double d2, double d3) { +- Iterator iterator = this.getPlayers().iterator(); +- +- double d4; +- +- do { +- EntityHuman entityhuman; +- +- do { +- do { +- if (!iterator.hasNext()) { +- return false; +- } +- +- entityhuman = (EntityHuman) iterator.next(); +- } while (!IEntitySelector.g.test(entityhuman)); +- } while (!IEntitySelector.b.test(entityhuman)); +- +- d4 = entityhuman.h(d0, d1, d2); +- } while (d3 >= 0.0D && d4 >= d3 * d3); +- +- return true; ++ // Purpur start ++ default boolean isPlayerNearby(double x, double y, double z, double distance) { ++ double distanceSq = distance * distance; ++ for (EntityHuman player : getPlayers()) { ++ if (IEntitySelector.notSpectator().test(player) && IEntitySelector.isLivingAlive().test(player) && IEntitySelector.notAfk.test(player)) { ++ if (distance < 0.0D || player.getDistanceSquared(x, y, z) < distanceSq) { ++ return true; ++ } ++ } ++ } ++ return false; ++ // Purpur end + } + + @Nullable +diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java +index 2f329bae9f09d0ed21a4538fba6b95919ec35887..95b55fb93049c6686e13aab78ba1ae2b2fd5785b 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java +@@ -1,6 +1,7 @@ + package net.pl3x.purpur; + + import com.google.common.base.Throwables; ++import net.minecraft.locale.LocaleLanguage; + import net.minecraft.server.MinecraftServer; + import net.pl3x.purpur.command.PurpurCommand; + import org.bukkit.Bukkit; +@@ -129,6 +130,15 @@ public class PurpurConfig { + return config.getString(path, config.getString(path)); + } + ++ public static String afkBroadcastAway = "§e§o%s is now AFK"; ++ public static String afkBroadcastBack = "§e§o%s is no longer AFK"; ++ public static String afkTabListPrefix = "[AFK] "; ++ private static void messages() { ++ afkBroadcastAway = getString("settings.messages.afk-broadcast-away", afkBroadcastAway); ++ afkBroadcastBack = getString("settings.messages.afk-broadcast-back", afkBroadcastBack); ++ afkTabListPrefix = getString("settings.messages.afk-tab-list-prefix", afkTabListPrefix); ++ } ++ + public static String timingsUrl = "https://timings.pl3x.net"; + private static void timingsSettings() { + timingsUrl = getString("settings.timings.url", timingsUrl); +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 361f7857e461578e90cb71e15027dadaf794cb69..2578a4677d1ee060f687be531e696b7c7be89e84 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -56,4 +56,15 @@ public class PurpurWorldConfig { + PurpurConfig.config.addDefault("world-settings.default." + path, def); + return PurpurConfig.config.getString("world-settings." + worldName + "." + path, PurpurConfig.config.getString("world-settings.default." + path)); + } ++ ++ public boolean idleTimeoutKick = true; ++ public boolean idleTimeoutTickNearbyEntities = true; ++ public boolean idleTimeoutCountAsSleeping = false; ++ public boolean idleTimeoutUpdateTabList = false; ++ private void playerIdleTimeoutSettings() { ++ idleTimeoutKick = getBoolean("gameplay-mechanics.player.idle-timeout.kick-if-idle", idleTimeoutKick); ++ idleTimeoutTickNearbyEntities = getBoolean("gameplay-mechanics.player.idle-timeout.tick-nearby-entities", idleTimeoutTickNearbyEntities); ++ idleTimeoutCountAsSleeping = getBoolean("gameplay-mechanics.player.idle-timeout.count-as-sleeping", idleTimeoutCountAsSleeping); ++ idleTimeoutUpdateTabList = getBoolean("gameplay-mechanics.player.idle-timeout.update-tab-list", idleTimeoutUpdateTabList); ++ } + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +index ed1bb89ae7b85bf4017315d6189d6cbf595aefe5..f3fb405c92a35796baa30cafcd96df2d8bf162e6 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +@@ -2499,4 +2499,21 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + return spigot; + } + // Spigot end ++ ++ // Purpur start ++ @Override ++ public boolean isAfk() { ++ return getHandle().isAfk(); ++ } ++ ++ @Override ++ public void setAfk(boolean setAfk) { ++ getHandle().setAfk(setAfk); ++ } ++ ++ @Override ++ public void resetIdleTimer() { ++ getHandle().resetIdleTimer(); ++ } ++ // Purpur end + } +diff --git a/src/main/java/org/spigotmc/ActivationRange.java b/src/main/java/org/spigotmc/ActivationRange.java +index 5c2eaca0bc63c7880ee928aba6a24761737aa649..2bbbd4a7ae87c2ead3dc2fd5520adfaefe2776b8 100644 +--- a/src/main/java/org/spigotmc/ActivationRange.java ++++ b/src/main/java/org/spigotmc/ActivationRange.java +@@ -204,6 +204,7 @@ public class ActivationRange + { + + player.activatedTick = MinecraftServer.currentTick; ++ if (!player.world.purpurConfig.idleTimeoutTickNearbyEntities && player.isAfk()) continue; // Purpur + maxBB = player.getBoundingBox().grow( maxRange, 256, maxRange ); + ActivationType.MISC.boundingBox = player.getBoundingBox().grow( miscActivationRange, 256, miscActivationRange ); + ActivationType.RAIDER.boundingBox = player.getBoundingBox().grow( raiderActivationRange, 256, raiderActivationRange ); diff --git a/patches/Purpur/patches/server/0007-Bring-back-server-name.patch b/patches/Purpur/patches/server/0007-Bring-back-server-name.patch new file mode 100644 index 00000000..8327ce0d --- /dev/null +++ b/patches/Purpur/patches/server/0007-Bring-back-server-name.patch @@ -0,0 +1,34 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sun, 26 May 2019 15:19:14 -0500 +Subject: [PATCH] Bring back server name + + +diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java +index 1fab9b9c7d41a0d2a551096c2c15f741a887fa2d..f33309f4c1ad92960d0634f3f5b8105c284f26a2 100644 +--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java ++++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java +@@ -20,6 +20,7 @@ public class DedicatedServerProperties extends PropertyManager +Date: Sat, 21 Mar 2020 11:47:39 -0500 +Subject: [PATCH] Configurable server mod name + + +diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java +index 6f90a4182e008b49a4b3328e569311382e4bec0d..2f3d6acf497b6fa6b497a1b94ba96977ce2e6008 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -1650,7 +1650,7 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant // Spigot - Spigot > // CraftBukkit - cb > vanilla! ++ return net.pl3x.purpur.PurpurConfig.serverModName; // Purpur // Tuinity // Paper // Spigot // CraftBukkit + } + + public CrashReport b(CrashReport crashreport) { +diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java +index 95b55fb93049c6686e13aab78ba1ae2b2fd5785b..2442309843bb62e08ae13c46d335c65f7d072510 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java +@@ -139,6 +139,11 @@ public class PurpurConfig { + afkTabListPrefix = getString("settings.messages.afk-tab-list-prefix", afkTabListPrefix); + } + ++ public static String serverModName = "Purpur"; ++ private static void serverModName() { ++ serverModName = getString("settings.server-mod-name", serverModName); ++ } ++ + public static String timingsUrl = "https://timings.pl3x.net"; + private static void timingsSettings() { + timingsUrl = getString("settings.timings.url", timingsUrl); diff --git a/patches/Purpur/patches/server/0009-LivingEntity-safeFallDistance.patch b/patches/Purpur/patches/server/0009-LivingEntity-safeFallDistance.patch new file mode 100644 index 00000000..8b82ecae --- /dev/null +++ b/patches/Purpur/patches/server/0009-LivingEntity-safeFallDistance.patch @@ -0,0 +1,84 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sun, 5 May 2019 12:58:45 -0500 +Subject: [PATCH] LivingEntity safeFallDistance + + +diff --git a/src/main/java/net/minecraft/world/entity/EntityLiving.java b/src/main/java/net/minecraft/world/entity/EntityLiving.java +index 2ff3297fb8c0e4f8c969ba2727eecb7fe06525c4..7d0bb706fb106709432c3fae8758d2cea1d14db8 100644 +--- a/src/main/java/net/minecraft/world/entity/EntityLiving.java ++++ b/src/main/java/net/minecraft/world/entity/EntityLiving.java +@@ -227,6 +227,7 @@ public abstract class EntityLiving extends Entity { + // CraftBukkit start + public int expToDrop; + public int maxAirTicks = 300; ++ public float safeFallDistance = 3.0F; // Purpur + public boolean forceDrops; + public ArrayList drops = new ArrayList(); + public final org.bukkit.craftbukkit.attribute.CraftAttributeMap craftAttributes; +@@ -321,8 +322,8 @@ public abstract class EntityLiving extends Entity { + this.cR(); + } + +- if (!this.world.isClientSide && this.fallDistance > 3.0F && flag) { +- float f = (float) MathHelper.f(this.fallDistance - 3.0F); ++ if (!this.world.isClientSide && this.fallDistance > this.safeFallDistance && flag) { // Purpur ++ float f = (float) MathHelper.f(this.fallDistance - this.safeFallDistance); // Purpur + + if (!iblockdata.isAir()) { + double d1 = Math.min((double) (0.2F + f / 15.0F), 2.5D); +@@ -1787,7 +1788,7 @@ public abstract class EntityLiving extends Entity { + MobEffect mobeffect = this.getEffect(MobEffects.JUMP); + float f2 = mobeffect == null ? 0.0F : (float) (mobeffect.getAmplifier() + 1); + +- return MathHelper.f((f - 3.0F - f2) * f1); ++ return MathHelper.f((f - this.safeFallDistance - f2) * f1); // Purpur + } + + protected void playBlockStepSound() { +diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseAbstract.java b/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseAbstract.java +index 1e41c45af6dbcf097d7d6104e63db637f199301a..cb6e2053d1315b65812e7bff8a17988b5b8ab0e4 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseAbstract.java ++++ b/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseAbstract.java +@@ -272,7 +272,7 @@ public abstract class EntityHorseAbstract extends EntityAnimal implements IInven + + @Override + protected int e(float f, float f1) { +- return MathHelper.f((f * 0.5F - 3.0F) * f1); ++ return MathHelper.f((f * 0.5F - this.safeFallDistance) * f1); // Purpur + } + + protected int getChestSlots() { +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityGiantZombie.java b/src/main/java/net/minecraft/world/entity/monster/EntityGiantZombie.java +index 3b004160da9a2aed440a3ccda538d78f91c61e87..5e6a92dcdbca686d5a8cfc4aaff72b70b81b111f 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityGiantZombie.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityGiantZombie.java +@@ -13,6 +13,7 @@ public class EntityGiantZombie extends EntityMonster { + + public EntityGiantZombie(EntityTypes entitytypes, World world) { + super(entitytypes, world); ++ this.safeFallDistance = 10.0F; // Purpur + } + + @Override +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +index 592dacf8cc924caac339a8810ba5b0d85448ed90..75af4d5385d4366e562a53716e020ba20ccbea94 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +@@ -875,4 +875,16 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { + throw new IllegalArgumentException(entityCategory + " is an unrecognized entity category"); + } + // Paper end ++ ++ // Purpur start ++ @Override ++ public float getSafeFallDistance() { ++ return getHandle().safeFallDistance; ++ } ++ ++ @Override ++ public void setSafeFallDistance(float safeFallDistance) { ++ getHandle().safeFallDistance = safeFallDistance; ++ } ++ // Purpur end + } diff --git a/patches/Purpur/patches/server/0010-Lagging-threshold.patch b/patches/Purpur/patches/server/0010-Lagging-threshold.patch new file mode 100644 index 00000000..934b245c --- /dev/null +++ b/patches/Purpur/patches/server/0010-Lagging-threshold.patch @@ -0,0 +1,57 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Tue, 23 Jul 2019 10:07:16 -0500 +Subject: [PATCH] Lagging threshold + + +diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java +index 2f3d6acf497b6fa6b497a1b94ba96977ce2e6008..991ac5baf3f10631edb0e60d17c714af1f406a29 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -280,6 +280,7 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant +Date: Fri, 5 Jul 2019 16:36:55 -0500 +Subject: [PATCH] ItemFactory#getMonsterEgg + + +diff --git a/src/main/java/net/minecraft/world/item/ItemMonsterEgg.java b/src/main/java/net/minecraft/world/item/ItemMonsterEgg.java +index 4d965e504a40eb52777575df839856c825a0900a..addddb64956c63563fc072b35cc511d31c9afd45 100644 +--- a/src/main/java/net/minecraft/world/item/ItemMonsterEgg.java ++++ b/src/main/java/net/minecraft/world/item/ItemMonsterEgg.java +@@ -35,7 +35,7 @@ import net.minecraft.world.phys.Vec3D; + + public class ItemMonsterEgg extends Item { + +- private static final Map, ItemMonsterEgg> a = Maps.newIdentityHashMap(); ++ public static final Map, ItemMonsterEgg> a = Maps.newIdentityHashMap(); // Purpur - private -> public + private final int b; + private final int c; + private final EntityTypes d; +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java +index 347c23d4b7d47198f214c3f95354e8abb660b191..4ec0e93d93936080d876ffa017ebe181d2896b22 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java +@@ -401,4 +401,18 @@ public final class CraftItemFactory implements ItemFactory { + new net.md_5.bungee.api.chat.TextComponent(customName)); + } + // Paper end ++ ++ // Purpur start ++ @Override ++ public ItemStack getMonsterEgg(org.bukkit.entity.EntityType type) { ++ if (type == null) { ++ return null; ++ } ++ String name = type.getKey().toString(); ++ net.minecraft.resources.MinecraftKey key = new net.minecraft.resources.MinecraftKey(name); ++ net.minecraft.world.entity.EntityTypes types = net.minecraft.world.entity.EntityTypes.getFromKey(key); ++ net.minecraft.world.item.ItemMonsterEgg egg = net.minecraft.world.item.ItemMonsterEgg.a.get(types); ++ return new net.minecraft.world.item.ItemStack(egg).asBukkitMirror(); ++ } ++ // Purpur end + } diff --git a/patches/Purpur/patches/server/0012-PlayerSetSpawnerTypeWithEggEvent.patch b/patches/Purpur/patches/server/0012-PlayerSetSpawnerTypeWithEggEvent.patch new file mode 100644 index 00000000..c40126d0 --- /dev/null +++ b/patches/Purpur/patches/server/0012-PlayerSetSpawnerTypeWithEggEvent.patch @@ -0,0 +1,86 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Fri, 5 Jul 2019 18:21:00 -0500 +Subject: [PATCH] PlayerSetSpawnerTypeWithEggEvent + + +diff --git a/src/main/java/net/minecraft/world/entity/EntityTypes.java b/src/main/java/net/minecraft/world/entity/EntityTypes.java +index 80c229c1852199fda85c03453d64cae33e413e89..6335e9046a6288f7bcf945ad8c381e080744653d 100644 +--- a/src/main/java/net/minecraft/world/entity/EntityTypes.java ++++ b/src/main/java/net/minecraft/world/entity/EntityTypes.java +@@ -274,6 +274,16 @@ public class EntityTypes { + return (EntityTypes) IRegistry.a((IRegistry) IRegistry.ENTITY_TYPE, s, (Object) entitytypes_builder.a(s)); + } + ++ // Purpur start ++ public static EntityTypes getFromBukkitType(org.bukkit.entity.EntityType bukkitType) { ++ return getFromKey(new MinecraftKey(bukkitType.getKey().toString())); ++ } ++ ++ public static EntityTypes getFromKey(MinecraftKey key) { ++ return IRegistry.ENTITY_TYPE.get(key); ++ } ++ // Purpur end ++ + public static MinecraftKey getName(EntityTypes entitytypes) { + return IRegistry.ENTITY_TYPE.getKey(entitytypes); + } +@@ -439,6 +449,16 @@ public class EntityTypes { + return this.bg; + } + ++ // Purpur start ++ public String getName() { ++ return IRegistry.ENTITY_TYPE.getKey(this).getKey(); ++ } ++ ++ public String getTranslatedName() { ++ return getNameComponent().getString(); ++ } ++ // Purpur end ++ + public String getDescriptionId() { return f(); } // Paper - OBFHELPER + public String f() { + if (this.bo == null) { +@@ -448,6 +468,7 @@ public class EntityTypes { + return this.bo; + } + ++ public IChatBaseComponent getNameComponent() { return g(); } // Purpur - OBFHELPER + public IChatBaseComponent g() { + if (this.bp == null) { + this.bp = new ChatMessage(this.f()); +diff --git a/src/main/java/net/minecraft/world/item/ItemMonsterEgg.java b/src/main/java/net/minecraft/world/item/ItemMonsterEgg.java +index addddb64956c63563fc072b35cc511d31c9afd45..5e2d0246146af8bf1de1038f6a1953451b99f0f5 100644 +--- a/src/main/java/net/minecraft/world/item/ItemMonsterEgg.java ++++ b/src/main/java/net/minecraft/world/item/ItemMonsterEgg.java +@@ -33,6 +33,13 @@ import net.minecraft.world.phys.MovingObjectPosition; + import net.minecraft.world.phys.MovingObjectPositionBlock; + import net.minecraft.world.phys.Vec3D; + ++// Purpur start ++import net.pl3x.purpur.event.PlayerSetSpawnerTypeWithEggEvent; ++import org.bukkit.block.CreatureSpawner; ++import org.bukkit.entity.EntityType; ++import org.bukkit.entity.Player; ++// Purpur end ++ + public class ItemMonsterEgg extends Item { + + public static final Map, ItemMonsterEgg> a = Maps.newIdentityHashMap(); // Purpur - private -> public +@@ -67,6 +74,15 @@ public class ItemMonsterEgg extends Item { + MobSpawnerAbstract mobspawnerabstract = ((TileEntityMobSpawner) tileentity).getSpawner(); + EntityTypes entitytypes = this.a(itemstack.getTag()); + ++ // Purpur start ++ org.bukkit.block.Block bukkitBlock = world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()); ++ PlayerSetSpawnerTypeWithEggEvent event = new PlayerSetSpawnerTypeWithEggEvent((Player) itemactioncontext.getEntity().getBukkitEntity(), bukkitBlock, (CreatureSpawner) bukkitBlock.getState(), EntityType.fromName(entitytypes.getName())); ++ if (!event.callEvent()) { ++ return EnumInteractionResult.FAIL; ++ } ++ entitytypes = EntityTypes.getFromBukkitType(event.getEntityType()); ++ // Purpur end ++ + mobspawnerabstract.setMobName(entitytypes); + tileentity.update(); + world.notify(blockposition, iblockdata, iblockdata, 3); diff --git a/patches/Purpur/patches/server/0013-EMC-MonsterEggSpawnEvent.patch b/patches/Purpur/patches/server/0013-EMC-MonsterEggSpawnEvent.patch new file mode 100644 index 00000000..86429a61 --- /dev/null +++ b/patches/Purpur/patches/server/0013-EMC-MonsterEggSpawnEvent.patch @@ -0,0 +1,63 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Sat, 20 Jul 2013 22:40:56 -0400 +Subject: [PATCH] EMC - MonsterEggSpawnEvent + + +diff --git a/src/main/java/net/minecraft/world/entity/EntityTypes.java b/src/main/java/net/minecraft/world/entity/EntityTypes.java +index 6335e9046a6288f7bcf945ad8c381e080744653d..1bfde4cfc0f27705238abf7852ad9bb7997e23e6 100644 +--- a/src/main/java/net/minecraft/world/entity/EntityTypes.java ++++ b/src/main/java/net/minecraft/world/entity/EntityTypes.java +@@ -318,13 +318,20 @@ public class EntityTypes { + + @Nullable + public Entity spawnCreature(WorldServer worldserver, @Nullable ItemStack itemstack, @Nullable EntityHuman entityhuman, BlockPosition blockposition, EnumMobSpawn enummobspawn, boolean flag, boolean flag1) { +- return this.spawnCreature(worldserver, itemstack == null ? null : itemstack.getTag(), itemstack != null && itemstack.hasName() ? itemstack.getName() : null, entityhuman, blockposition, enummobspawn, flag, flag1); ++ return this.spawnCreature(worldserver, itemstack, itemstack == null ? null : itemstack.getTag(), itemstack != null && itemstack.hasName() ? itemstack.getName() : null, entityhuman, blockposition, enummobspawn, flag, flag1); // Purpur + } + + @Nullable + public T spawnCreature(WorldServer worldserver, @Nullable NBTTagCompound nbttagcompound, @Nullable IChatBaseComponent ichatbasecomponent, @Nullable EntityHuman entityhuman, BlockPosition blockposition, EnumMobSpawn enummobspawn, boolean flag, boolean flag1) { ++ // Purpur start ++ return spawnCreature(worldserver, null, nbttagcompound, ichatbasecomponent, entityhuman, blockposition, enummobspawn, flag, flag1); ++ } ++ ++ @Nullable ++ public T spawnCreature(WorldServer worldserver, @Nullable ItemStack itemstack, @Nullable NBTTagCompound nbttagcompound, @Nullable IChatBaseComponent ichatbasecomponent, @Nullable EntityHuman entityhuman, BlockPosition blockposition, EnumMobSpawn enummobspawn, boolean flag, boolean flag1) { ++ // Purpur end + // CraftBukkit start +- return this.spawnCreature(worldserver, nbttagcompound, ichatbasecomponent, entityhuman, blockposition, enummobspawn, flag, flag1, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SPAWNER_EGG); ++ return this.spawnCreature(worldserver, itemstack, nbttagcompound, ichatbasecomponent, entityhuman, blockposition, enummobspawn, flag, flag1, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SPAWNER_EGG, null); // Purpur + } + + @Nullable +@@ -349,9 +356,29 @@ public class EntityTypes { + } + } + // Paper end ++ // Purpur start ++ return spawnCreature(worldserver, null, nbttagcompound, ichatbasecomponent, entityhuman, blockposition, enummobspawn, flag, flag1, spawnReason, op); ++ } ++ ++ @Nullable ++ public T spawnCreature(WorldServer worldserver, @Nullable ItemStack itemstack, @Nullable NBTTagCompound nbttagcompound, @Nullable IChatBaseComponent ichatbasecomponent, @Nullable EntityHuman entityhuman, BlockPosition blockposition, EnumMobSpawn enummobspawn, boolean flag, boolean flag1, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason spawnReason, @Nullable java.util.function.Consumer op) { ++ // Purpur end + T t0 = this.createCreature(worldserver, nbttagcompound, ichatbasecomponent, entityhuman, blockposition, enummobspawn, flag, flag1); + if (t0 != null && op != null) op.accept(t0); // Paper + ++ // Purpur start ++ if (spawnReason == org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SPAWNER_EGG && itemstack != null && t0 != null) { ++ final net.pl3x.purpur.event.entity.MonsterEggSpawnEvent event = new net.pl3x.purpur.event.entity.MonsterEggSpawnEvent(entityhuman != null ? entityhuman.getBukkitEntity() : null, t0.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack)); ++ if (!event.callEvent()) { ++ worldserver.removeEntity(t0); ++ return null; ++ } ++ if (event.getEntity().getEntityId() != t0.getId()) { ++ return (T) ((org.bukkit.craftbukkit.entity.CraftEntity) event.getEntity()).getHandle(); ++ } ++ } ++ // Purpur end ++ + if (t0 != null) { + worldserver.addAllEntities(t0, spawnReason); + return !t0.dead ? t0 : null; // Don't return an entity when CreatureSpawnEvent is canceled diff --git a/patches/Purpur/patches/server/0014-Player-invulnerabilities.patch b/patches/Purpur/patches/server/0014-Player-invulnerabilities.patch new file mode 100644 index 00000000..84f8b042 --- /dev/null +++ b/patches/Purpur/patches/server/0014-Player-invulnerabilities.patch @@ -0,0 +1,134 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sat, 2 May 2020 20:55:44 -0500 +Subject: [PATCH] Player invulnerabilities + + +diff --git a/src/main/java/net/minecraft/server/level/EntityPlayer.java b/src/main/java/net/minecraft/server/level/EntityPlayer.java +index b302d1f7c86a8df2ede46871397189f6f2e6b912..79ff69f9e2dc92ffb4880cf1e059cd1d6a7bdc8a 100644 +--- a/src/main/java/net/minecraft/server/level/EntityPlayer.java ++++ b/src/main/java/net/minecraft/server/level/EntityPlayer.java +@@ -285,6 +285,8 @@ public class EntityPlayer extends EntityHuman implements ICrafting { + this.canPickUpLoot = true; + this.maxHealthCache = this.getMaxHealth(); + this.cachedSingleMobDistanceMap = new com.destroystokyo.paper.util.PooledHashSets.PooledObjectLinkedOpenHashSet<>(this); // Paper ++ ++ this.invulnerableTicks = world.purpurConfig.playerSpawnInvulnerableTicks; // Purpur + } + // Paper start + public BlockPosition getPointInFront(double inFront) { +@@ -1129,6 +1131,12 @@ public class EntityPlayer extends EntityHuman implements ICrafting { + + } + ++ // Purpur start ++ public boolean isSpawnInvulnerable() { ++ return invulnerableTicks > 0 || frozen; ++ } ++ // Purpur end ++ + @Override + public boolean damageEntity(DamageSource damagesource, float f) { + if (this.isInvulnerable(damagesource)) { +@@ -1136,7 +1144,7 @@ public class EntityPlayer extends EntityHuman implements ICrafting { + } else { + boolean flag = this.server.j() && this.canPvP() && "fall".equals(damagesource.translationIndex); + +- if (!flag && this.invulnerableTicks > 0 && damagesource != DamageSource.OUT_OF_WORLD) { ++ if (!flag && isSpawnInvulnerable() && damagesource != DamageSource.OUT_OF_WORLD) { // Purpur + return false; + } else { + if (damagesource instanceof EntityDamageSource) { +@@ -1313,6 +1321,7 @@ public class EntityPlayer extends EntityHuman implements ICrafting { + } + // Paper end + ++ this.invulnerableTicks = worldserver.purpurConfig.playerSpawnInvulnerableTicks; // Purpur + return this; + } + } +@@ -2521,9 +2530,17 @@ public class EntityPlayer extends EntityHuman implements ICrafting { + + @Override + public boolean isFrozen() { // Paper - protected > public +- return super.isFrozen() || (this.playerConnection != null && this.playerConnection.isDisconnected()); // Paper ++ return super.isFrozen() || frozen || (this.playerConnection != null && this.playerConnection.isDisconnected()); // Paper // Purpur + } + ++ // Purpur start ++ private boolean frozen = false; ++ ++ public void setFrozen(boolean frozen) { ++ this.frozen = frozen; ++ } ++ // Purpur end ++ + @Override + public Scoreboard getScoreboard() { + return getBukkitEntity().getScoreboard().getHandle(); +diff --git a/src/main/java/net/minecraft/server/network/PlayerConnection.java b/src/main/java/net/minecraft/server/network/PlayerConnection.java +index de72ebb94052efe8c63bf28f6741a4645b3ee721..d1fe1242272a422b7b528876da0d76e1aa6f3eaa 100644 +--- a/src/main/java/net/minecraft/server/network/PlayerConnection.java ++++ b/src/main/java/net/minecraft/server/network/PlayerConnection.java +@@ -1910,6 +1910,7 @@ public class PlayerConnection implements PacketListenerPlayIn { + PlayerConnectionUtils.ensureMainThread(packetplayinresourcepackstatus, this, this.player.getWorldServer()); + // Paper start + PlayerResourcePackStatusEvent.Status packStatus = PlayerResourcePackStatusEvent.Status.values()[packetplayinresourcepackstatus.status.ordinal()]; ++ if (player.world.purpurConfig.playerInvulnerableWhileAcceptingResourcePack) player.setFrozen(packStatus == PlayerResourcePackStatusEvent.Status.ACCEPTED); // Purpur + player.getBukkitEntity().setResourcePackStatus(packStatus); + this.server.getPluginManager().callEvent(new PlayerResourcePackStatusEvent(getPlayer(), packStatus)); + // Paper end +diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java +index 5936075251ef3d6dda3e93866009d0e996598698..5897e4e02dad470174a31d3710520d04d4b87fb4 100644 +--- a/src/main/java/net/minecraft/server/players/PlayerList.java ++++ b/src/main/java/net/minecraft/server/players/PlayerList.java +@@ -1015,6 +1015,8 @@ public abstract class PlayerList { + } + // Paper end + ++ entityplayer1.invulnerableTicks = entityplayer1.world.purpurConfig.playerSpawnInvulnerableTicks; // Purpur ++ + // CraftBukkit end + return entityplayer1; + } +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 2578a4677d1ee060f687be531e696b7c7be89e84..c441fcea9b2b5a77b801c8a69541cf42050927dc 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -67,4 +67,11 @@ public class PurpurWorldConfig { + idleTimeoutCountAsSleeping = getBoolean("gameplay-mechanics.player.idle-timeout.count-as-sleeping", idleTimeoutCountAsSleeping); + idleTimeoutUpdateTabList = getBoolean("gameplay-mechanics.player.idle-timeout.update-tab-list", idleTimeoutUpdateTabList); + } ++ ++ public int playerSpawnInvulnerableTicks = 60; ++ public boolean playerInvulnerableWhileAcceptingResourcePack = false; ++ private void playerInvulnerabilities() { ++ playerSpawnInvulnerableTicks = getInt("gameplay-mechanics.player.spawn-invulnerable-ticks", playerSpawnInvulnerableTicks); ++ playerInvulnerableWhileAcceptingResourcePack = getBoolean("gameplay-mechanics.player.invulnerable-while-accepting-resource-pack", playerInvulnerableWhileAcceptingResourcePack); ++ } + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +index f3fb405c92a35796baa30cafcd96df2d8bf162e6..b7180dea1d71a68e4025388916600093dfd000c7 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +@@ -2515,5 +2515,20 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + public void resetIdleTimer() { + getHandle().resetIdleTimer(); + } ++ ++ @Override ++ public boolean isSpawnInvulnerable() { ++ return getHandle().isSpawnInvulnerable(); ++ } ++ ++ @Override ++ public int getSpawnInvulnerableTicks() { ++ return getHandle().invulnerableTicks; ++ } ++ ++ @Override ++ public void setSpawnInvulnerableTicks(int invulnerableTicks) { ++ getHandle().invulnerableTicks = invulnerableTicks; ++ } + // Purpur end + } diff --git a/patches/Purpur/patches/server/0015-Anvil-API.patch b/patches/Purpur/patches/server/0015-Anvil-API.patch new file mode 100644 index 00000000..8465320b --- /dev/null +++ b/patches/Purpur/patches/server/0015-Anvil-API.patch @@ -0,0 +1,147 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sun, 19 Apr 2020 00:17:56 -0500 +Subject: [PATCH] Anvil API + + +diff --git a/src/main/java/net/minecraft/world/inventory/ContainerAnvil.java b/src/main/java/net/minecraft/world/inventory/ContainerAnvil.java +index ae5674ae9c539720a657838a640050cd3b4dc5b5..1b2d633f3d5d735039f18f27fb1387bd5a74f0d8 100644 +--- a/src/main/java/net/minecraft/world/inventory/ContainerAnvil.java ++++ b/src/main/java/net/minecraft/world/inventory/ContainerAnvil.java +@@ -2,8 +2,13 @@ package net.minecraft.world.inventory; + + import java.util.Iterator; + import java.util.Map; ++ ++import net.minecraft.nbt.NBTTagInt; + import net.minecraft.network.chat.ChatComponentText; + import net.minecraft.network.chat.IChatBaseComponent; ++import net.minecraft.network.protocol.game.PacketPlayOutSetSlot; ++import net.minecraft.network.protocol.game.PacketPlayOutWindowData; ++import net.minecraft.server.level.EntityPlayer; + import net.minecraft.tags.Tag; + import net.minecraft.tags.TagsBlock; + import net.minecraft.world.entity.player.EntityHuman; +@@ -33,6 +38,8 @@ public class ContainerAnvil extends ContainerAnvilAbstract { + public int maximumRepairCost = 40; + private CraftInventoryView bukkitEntity; + // CraftBukkit end ++ public boolean bypassCost = false; // Purpur ++ public boolean canDoUnsafeEnchants = false; // Purpur + + public ContainerAnvil(int i, PlayerInventory playerinventory) { + this(i, playerinventory, ContainerAccess.a); +@@ -51,12 +58,14 @@ public class ContainerAnvil extends ContainerAnvilAbstract { + + @Override + protected boolean b(EntityHuman entityhuman, boolean flag) { +- return (entityhuman.abilities.canInstantlyBuild || entityhuman.expLevel >= this.levelCost.get()) && this.levelCost.get() > 0; ++ return (entityhuman.abilities.canInstantlyBuild || entityhuman.expLevel >= this.levelCost.get()) && (bypassCost || this.levelCost.get() > 0); // Purpur + } + + @Override + protected ItemStack a(EntityHuman entityhuman, ItemStack itemstack) { ++ if (net.pl3x.purpur.event.inventory.AnvilTakeResultEvent.getHandlerList().getRegisteredListeners().length > 0) new net.pl3x.purpur.event.inventory.AnvilTakeResultEvent(entityhuman.getBukkitEntity(), getBukkitView(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack)).callEvent(); // Purpur + if (!entityhuman.abilities.canInstantlyBuild) { ++ if (bypassCost) ((EntityPlayer) entityhuman).lastSentExp = -1; else // Purpur + entityhuman.levelDown(-this.levelCost.get()); + } + +@@ -107,6 +116,12 @@ public class ContainerAnvil extends ContainerAnvilAbstract { + + @Override + public void e() { ++ // Purpur start ++ bypassCost = false; ++ canDoUnsafeEnchants = false; ++ if (net.pl3x.purpur.event.inventory.AnvilUpdateResultEvent.getHandlerList().getRegisteredListeners().length > 0) new net.pl3x.purpur.event.inventory.AnvilUpdateResultEvent(getBukkitView()).callEvent(); ++ // Purpur end ++ + ItemStack itemstack = this.repairInventory.getItem(0); + + this.levelCost.set(1); +@@ -183,7 +198,7 @@ public class ContainerAnvil extends ContainerAnvilAbstract { + int i2 = (Integer) map1.get(enchantment); + + i2 = l1 == i2 ? i2 + 1 : Math.max(i2, l1); +- boolean flag3 = enchantment.canEnchant(itemstack); ++ boolean flag3 = canDoUnsafeEnchants || enchantment.canEnchant(itemstack); // Purpur + + if (this.player.abilities.canInstantlyBuild || itemstack.getItem() == Items.ENCHANTED_BOOK) { + flag3 = true; +@@ -195,7 +210,7 @@ public class ContainerAnvil extends ContainerAnvilAbstract { + Enchantment enchantment1 = (Enchantment) iterator1.next(); + + if (enchantment1 != enchantment && !enchantment.isCompatible(enchantment1)) { +- flag3 = false; ++ flag3 = canDoUnsafeEnchants; // Purpur + ++i; + } + } +@@ -266,6 +281,13 @@ public class ContainerAnvil extends ContainerAnvilAbstract { + this.levelCost.set(maximumRepairCost - 1); // CraftBukkit + } + ++ // Purpur start ++ if (bypassCost && levelCost.get() >= maximumRepairCost) { ++ itemstack.getOrCreateTagAndSet("Purpur.realCost", NBTTagInt.a(levelCost.get())); ++ levelCost.set(maximumRepairCost - 1); ++ } ++ // Purpur end ++ + if (this.levelCost.get() >= maximumRepairCost && !this.player.abilities.canInstantlyBuild) { // CraftBukkit + itemstack1 = ItemStack.b; + } +@@ -287,6 +309,12 @@ public class ContainerAnvil extends ContainerAnvilAbstract { + + org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareAnvilEvent(getBukkitView(), itemstack1); // CraftBukkit + this.c(); ++ // Purpur start ++ if (canDoUnsafeEnchants && itemstack1 != ItemStack.NULL_ITEM) { ++ ((EntityPlayer) player).playerConnection.sendPacket(new PacketPlayOutSetSlot(windowId, 2, itemstack1)); ++ ((EntityPlayer) player).playerConnection.sendPacket(new PacketPlayOutWindowData(windowId, 0, levelCost.get())); ++ } ++ // Purpur end + } + } + +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryAnvil.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryAnvil.java +index fd59f77d78a97898657919a77405b39ca24cddc9..151c478c6cb19d88000da46b6fbb952e97e58c95 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryAnvil.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryAnvil.java +@@ -9,7 +9,7 @@ import org.bukkit.inventory.AnvilInventory; + public class CraftInventoryAnvil extends CraftResultInventory implements AnvilInventory { + + private final Location location; +- private final ContainerAnvil container; ++ public final ContainerAnvil container; // Purpur - private -> public + + public CraftInventoryAnvil(Location location, IInventory inventory, IInventory resultInventory, ContainerAnvil container) { + super(inventory, resultInventory); +@@ -47,4 +47,26 @@ public class CraftInventoryAnvil extends CraftResultInventory implements AnvilIn + Preconditions.checkArgument(levels >= 0, "Maximum repair cost must be positive (or 0)"); + container.maximumRepairCost = levels; + } ++ ++ // Purpur start ++ @Override ++ public boolean canBypassCost() { ++ return container.bypassCost; ++ } ++ ++ @Override ++ public void setBypassCost(boolean bypassCost) { ++ container.bypassCost = bypassCost; ++ } ++ ++ @Override ++ public boolean canDoUnsafeEnchants() { ++ return container.canDoUnsafeEnchants; ++ } ++ ++ @Override ++ public void setDoUnsafeEnchants(boolean canDoUnsafeEnchants) { ++ container.canDoUnsafeEnchants = canDoUnsafeEnchants; ++ } ++ // Purpur end + } diff --git a/patches/Purpur/patches/server/0016-Configurable-villager-brain-ticks.patch b/patches/Purpur/patches/server/0016-Configurable-villager-brain-ticks.patch new file mode 100644 index 00000000..60d84945 --- /dev/null +++ b/patches/Purpur/patches/server/0016-Configurable-villager-brain-ticks.patch @@ -0,0 +1,53 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Tue, 23 Jul 2019 08:28:21 -0500 +Subject: [PATCH] Configurable villager brain ticks + + +diff --git a/src/main/java/net/minecraft/world/entity/npc/EntityVillager.java b/src/main/java/net/minecraft/world/entity/npc/EntityVillager.java +index 85374ac8f5460790de03b47d7c3ce19ed5596afe..c45e6ae3f912ac582c6ba693517e05cd8fbf33e2 100644 +--- a/src/main/java/net/minecraft/world/entity/npc/EntityVillager.java ++++ b/src/main/java/net/minecraft/world/entity/npc/EntityVillager.java +@@ -127,6 +127,7 @@ public class EntityVillager extends EntityVillagerAbstract implements Reputation + }, MemoryModuleType.MEETING_POINT, (entityvillager, villageplacetype) -> { + return villageplacetype == VillagePlaceType.s; + }); ++ private final int brainTickOffset; // Purpur + + public EntityVillager(EntityTypes entitytypes, World world) { + this(entitytypes, world, VillagerType.PLAINS); +@@ -139,6 +140,7 @@ public class EntityVillager extends EntityVillagerAbstract implements Reputation + this.getNavigation().d(true); + this.setCanPickupLoot(true); + this.setVillagerData(this.getVillagerData().withType(villagertype).withProfession(VillagerProfession.NONE)); ++ this.brainTickOffset = getRandom().nextInt(100); // Purpur + } + + @Override +@@ -235,6 +237,10 @@ public class EntityVillager extends EntityVillagerAbstract implements Reputation + protected void mobTick() { mobTick(false); } + protected void mobTick(boolean inactive) { + this.world.getMethodProfiler().enter("villagerBrain"); ++ // Purpur start ++ boolean tick = (world.getTime() + brainTickOffset) % world.purpurConfig.villagerBrainTicks == 0; ++ if (((WorldServer) world).getMinecraftServer().lagging ? tick : world.purpurConfig.villagerUseBrainTicksOnlyWhenLagging || tick) ++ // Purpur end + if (!inactive) this.getBehaviorController().a((WorldServer) this.world, this); // CraftBukkit - decompile error // Paper + this.world.getMethodProfiler().exit(); + if (this.bF) { +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index c441fcea9b2b5a77b801c8a69541cf42050927dc..c7fb5a737cab0083c39732247acb8f4e87562894 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -74,4 +74,11 @@ public class PurpurWorldConfig { + playerSpawnInvulnerableTicks = getInt("gameplay-mechanics.player.spawn-invulnerable-ticks", playerSpawnInvulnerableTicks); + playerInvulnerableWhileAcceptingResourcePack = getBoolean("gameplay-mechanics.player.invulnerable-while-accepting-resource-pack", playerInvulnerableWhileAcceptingResourcePack); + } ++ ++ public int villagerBrainTicks = 1; ++ public boolean villagerUseBrainTicksOnlyWhenLagging = true; ++ private void villagerSettings() { ++ villagerBrainTicks = getInt("mobs.villager.brain-ticks", villagerBrainTicks); ++ villagerUseBrainTicksOnlyWhenLagging = getBoolean("mobs.villager.use-brain-ticks-only-when-lagging", villagerUseBrainTicksOnlyWhenLagging); ++ } + } diff --git a/patches/Purpur/patches/server/0017-Alternative-Keepalive-Handling.patch b/patches/Purpur/patches/server/0017-Alternative-Keepalive-Handling.patch new file mode 100644 index 00000000..e6342adf --- /dev/null +++ b/patches/Purpur/patches/server/0017-Alternative-Keepalive-Handling.patch @@ -0,0 +1,85 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Fri, 11 Oct 2019 00:17:39 -0500 +Subject: [PATCH] Alternative Keepalive Handling + + +diff --git a/src/main/java/net/minecraft/network/protocol/game/PacketPlayInKeepAlive.java b/src/main/java/net/minecraft/network/protocol/game/PacketPlayInKeepAlive.java +index b4c37287362907b8507d156b978ba5b9d961bb7b..9e6e6636539702507abb78515e002819661027af 100644 +--- a/src/main/java/net/minecraft/network/protocol/game/PacketPlayInKeepAlive.java ++++ b/src/main/java/net/minecraft/network/protocol/game/PacketPlayInKeepAlive.java +@@ -24,6 +24,7 @@ public class PacketPlayInKeepAlive implements Packet { + packetdataserializer.writeLong(this.a); + } + ++ public long getId() { return b(); } // Purpur - OBFHELPER + public long b() { + return this.a; + } +diff --git a/src/main/java/net/minecraft/server/network/PlayerConnection.java b/src/main/java/net/minecraft/server/network/PlayerConnection.java +index d1fe1242272a422b7b528876da0d76e1aa6f3eaa..8856ee8e0e7a3efda7921c0c8df9a2eb4213b1ce 100644 +--- a/src/main/java/net/minecraft/server/network/PlayerConnection.java ++++ b/src/main/java/net/minecraft/server/network/PlayerConnection.java +@@ -233,6 +233,7 @@ public class PlayerConnection implements PacketListenerPlayIn { + private long lastKeepAlive = SystemUtils.getMonotonicMillis(); private void setLastPing(long lastPing) { this.lastKeepAlive = lastPing;}; private long getLastPing() { return this.lastKeepAlive;}; // Paper - OBFHELPER + private boolean awaitingKeepAlive; private void setPendingPing(boolean isPending) { this.awaitingKeepAlive = isPending;}; private boolean isPendingPing() { return this.awaitingKeepAlive;}; // Paper - OBFHELPER + private long h; private void setKeepAliveID(long keepAliveID) { this.h = keepAliveID;}; private long getKeepAliveID() {return this.h; }; // Paper - OBFHELPER ++ private java.util.List keepAlives = new java.util.ArrayList<>(); // Purpur + // CraftBukkit start - multithreaded fields + private volatile int chatThrottle; + private static final AtomicIntegerFieldUpdater chatSpamField = AtomicIntegerFieldUpdater.newUpdater(PlayerConnection.class, "chatThrottle"); +@@ -367,6 +368,21 @@ public class PlayerConnection implements PacketListenerPlayIn { + long currentTime = SystemUtils.getMonotonicMillis(); + long elapsedTime = currentTime - this.getLastPing(); + ++ // Purpur start ++ if (net.pl3x.purpur.PurpurConfig.useAlternateKeepAlive) { ++ if (elapsedTime >= 1000L) { // 1 second ++ if (!processedDisconnect && keepAlives.size() > KEEPALIVE_LIMIT) { ++ PlayerConnection.LOGGER.warn("{} was kicked due to keepalive timeout!", player.getName()); ++ disconnect(new ChatMessage("disconnect.timeout")); ++ } else { ++ setLastPing(currentTime); // hijack this field for 1 second intervals ++ keepAlives.add(currentTime); // currentTime is ID ++ sendPacket(new PacketPlayOutKeepAlive(currentTime)); ++ } ++ } ++ } else ++ // Purpur end ++ + if (this.isPendingPing()) { + if (!this.processedDisconnect && elapsedTime >= KEEPALIVE_LIMIT) { // check keepalive limit, don't fire if already disconnected + PlayerConnection.LOGGER.warn("{} was kicked due to keepalive timeout!", this.player.getName()); // more info +@@ -3093,6 +3109,16 @@ public class PlayerConnection implements PacketListenerPlayIn { + + @Override + public void a(PacketPlayInKeepAlive packetplayinkeepalive) { ++ // Purpur start ++ if (net.pl3x.purpur.PurpurConfig.useAlternateKeepAlive) { ++ long id = packetplayinkeepalive.getId(); ++ if (keepAlives.size() > 0 && keepAlives.contains(id)) { ++ int ping = (int) (SystemUtils.getMonotonicMillis() - id); ++ player.ping = (player.ping * 3 + ping) / 4; ++ keepAlives.clear(); // we got a valid response, lets roll with it and forget the rest ++ } ++ } else ++ // Purpur end + //PlayerConnectionUtils.ensureMainThread(packetplayinkeepalive, this, this.player.getWorldServer()); // CraftBukkit // Paper - This shouldn't be on the main thread + if (this.awaitingKeepAlive && packetplayinkeepalive.b() == this.h) { + int i = (int) (SystemUtils.getMonotonicMillis() - this.lastKeepAlive); +diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java +index 089ae62c2189fe774796ecc6caf9961d3edb5ea3..afd0c577069f2a856caf41bd2dd5187db4866fa3 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java +@@ -155,6 +155,11 @@ public class PurpurConfig { + laggingThreshold = getDouble("settings.lagging-threshold", laggingThreshold); + } + ++ public static boolean useAlternateKeepAlive = false; ++ private static void useAlternateKeepAlive() { ++ useAlternateKeepAlive = getBoolean("settings.use-alternate-keepalive", useAlternateKeepAlive); ++ } ++ + public static boolean barrelSixRows = false; + public static boolean enderChestSixRows = false; + public static boolean enderChestPermissionRows = false; diff --git a/patches/Purpur/patches/server/0018-Silk-touch-spawners.patch b/patches/Purpur/patches/server/0018-Silk-touch-spawners.patch new file mode 100644 index 00000000..65b904c4 --- /dev/null +++ b/patches/Purpur/patches/server/0018-Silk-touch-spawners.patch @@ -0,0 +1,235 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Thu, 9 May 2019 14:27:37 -0500 +Subject: [PATCH] Silk touch spawners + + +diff --git a/src/main/java/io/papermc/paper/adventure/PaperAdventure.java b/src/main/java/io/papermc/paper/adventure/PaperAdventure.java +index 7b14b3c2486f03778d4673cf9684aa576dc2724a..822ffa8e4b554fd6aa7ce1b2bb68c198c863d86c 100644 +--- a/src/main/java/io/papermc/paper/adventure/PaperAdventure.java ++++ b/src/main/java/io/papermc/paper/adventure/PaperAdventure.java +@@ -81,6 +81,7 @@ public final class PaperAdventure { + }) + .build(); + public static final LegacyComponentSerializer LEGACY_SECTION_UXRC = LegacyComponentSerializer.builder().flattener(FLATTENER).hexColors().useUnusualXRepeatedCharacterHexFormat().build(); ++ public static final LegacyComponentSerializer LEGACY_AMPERSAND = LegacyComponentSerializer.builder().character(LegacyComponentSerializer.AMPERSAND_CHAR).hexColors().build(); // Purpur + public static final PlainComponentSerializer PLAIN = PlainComponentSerializer.builder().flattener(FLATTENER).build(); + public static final GsonComponentSerializer GSON = GsonComponentSerializer.builder() + .legacyHoverEventSerializer(NBTLegacyHoverEventSerializer.INSTANCE) +diff --git a/src/main/java/net/minecraft/server/ItemSpawner.java b/src/main/java/net/minecraft/server/ItemSpawner.java +new file mode 100644 +index 0000000000000000000000000000000000000000..599672ed4d0fc412ad3c0fa2e9d9df7035694fa2 +--- /dev/null ++++ b/src/main/java/net/minecraft/server/ItemSpawner.java +@@ -0,0 +1,35 @@ ++package net.minecraft.server; ++ ++import net.minecraft.core.BlockPosition; ++import net.minecraft.nbt.NBTTagCompound; ++import net.minecraft.world.entity.EntityTypes; ++import net.minecraft.world.entity.player.EntityHuman; ++import net.minecraft.world.item.ItemBlock; ++import net.minecraft.world.item.ItemStack; ++import net.minecraft.world.level.World; ++import net.minecraft.world.level.block.Block; ++import net.minecraft.world.level.block.entity.TileEntity; ++import net.minecraft.world.level.block.entity.TileEntityMobSpawner; ++import net.minecraft.world.level.block.state.IBlockData; ++ ++public class ItemSpawner extends ItemBlock { ++ public ItemSpawner(Block block, Info info) { ++ super(block, info); ++ } ++ ++ @Override ++ protected boolean a(BlockPosition blockposition, World world, EntityHuman entityhuman, ItemStack itemstack, IBlockData iblockdata) { ++ boolean handled = super.a(blockposition, world, entityhuman, itemstack, iblockdata); ++ if (world.purpurConfig.silkTouchEnabled && entityhuman.getBukkitEntity().hasPermission("purpur.place.spawners")) { ++ TileEntity spawner = world.getTileEntity(blockposition); ++ if (spawner instanceof TileEntityMobSpawner && itemstack.hasTag()) { ++ NBTTagCompound tag = itemstack.getTag(); ++ if (tag.hasKey("Purpur.mob_type")) { ++ EntityTypes.getByName(tag.getString("Purpur.mob_type")).ifPresent(type -> ++ ((TileEntityMobSpawner) spawner).getSpawner().setMobName(type)); ++ } ++ } ++ } ++ return handled; ++ } ++} +diff --git a/src/main/java/net/minecraft/world/item/Items.java b/src/main/java/net/minecraft/world/item/Items.java +index fc5cc610e7ea584ce72600b9d9f47543265725bb..8e9a25495d76251a86268d3059e2960a86dc46b3 100644 +--- a/src/main/java/net/minecraft/world/item/Items.java ++++ b/src/main/java/net/minecraft/world/item/Items.java +@@ -2,6 +2,7 @@ package net.minecraft.world.item; + + import net.minecraft.core.IRegistry; + import net.minecraft.resources.MinecraftKey; ++import net.minecraft.server.ItemSpawner; + import net.minecraft.sounds.SoundEffects; + import net.minecraft.world.entity.EntityTypes; + import net.minecraft.world.entity.EnumItemSlot; +@@ -193,7 +194,7 @@ public class Items { + public static final Item ct = a(Blocks.PURPUR_BLOCK, CreativeModeTab.b); + public static final Item cu = a(Blocks.PURPUR_PILLAR, CreativeModeTab.b); + public static final Item cv = a(Blocks.PURPUR_STAIRS, CreativeModeTab.b); +- public static final Item cw = a(Blocks.SPAWNER); ++ public static final Item cw = a(Blocks.SPAWNER, new ItemSpawner(Blocks.SPAWNER, new Item.Info().a(EnumItemRarity.EPIC))); // Purpur + public static final Item cx = a(Blocks.OAK_STAIRS, CreativeModeTab.b); + public static final Item cy = a(Blocks.CHEST, CreativeModeTab.c); + public static final Item cz = a(Blocks.DIAMOND_ORE, CreativeModeTab.b); +diff --git a/src/main/java/net/minecraft/world/level/block/BlockMobSpawner.java b/src/main/java/net/minecraft/world/level/block/BlockMobSpawner.java +index 287dd5f1b2b913df4029966860cd1a426947b187..af3c1a6307fb9e244226794508382d2ffa2aeb4b 100644 +--- a/src/main/java/net/minecraft/world/level/block/BlockMobSpawner.java ++++ b/src/main/java/net/minecraft/world/level/block/BlockMobSpawner.java +@@ -1,14 +1,35 @@ + package net.minecraft.world.level.block; + + import net.minecraft.core.BlockPosition; ++import net.minecraft.nbt.NBTTagCompound; ++import net.minecraft.nbt.NBTTagList; ++import net.minecraft.nbt.NBTTagString; ++import net.minecraft.resources.MinecraftKey; + import net.minecraft.server.level.WorldServer; ++import net.minecraft.world.entity.EntityTypes; ++import net.minecraft.world.entity.player.EntityHuman; + import net.minecraft.world.item.ItemStack; ++import net.minecraft.world.item.enchantment.EnchantmentManager; ++import net.minecraft.world.item.enchantment.Enchantments; + import net.minecraft.world.level.IBlockAccess; ++import net.minecraft.world.level.World; + import net.minecraft.world.level.block.entity.TileEntity; + import net.minecraft.world.level.block.entity.TileEntityMobSpawner; + import net.minecraft.world.level.block.state.BlockBase; + import net.minecraft.world.level.block.state.IBlockData; + ++// Purpur start ++import io.papermc.paper.adventure.PaperAdventure; ++import net.kyori.adventure.text.Component; ++import net.kyori.adventure.text.TextReplacementConfig; ++import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; ++import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; ++ ++import java.util.List; ++ ++import static net.kyori.adventure.text.format.TextDecoration.ITALIC; ++// Purpur end ++ + public class BlockMobSpawner extends BlockTileEntity { + + protected BlockMobSpawner(BlockBase.Info blockbase_info) { +@@ -20,6 +41,59 @@ public class BlockMobSpawner extends BlockTileEntity { + return new TileEntityMobSpawner(); + } + ++ // Purpur start ++ @Override ++ public void a(World world, EntityHuman entityhuman, BlockPosition blockposition, IBlockData iblockdata, TileEntity tileentity, ItemStack itemstack) { ++ if (world.purpurConfig.silkTouchEnabled && entityhuman.getBukkitEntity().hasPermission("purpur.drop.spawners") && isSilkTouch(world, itemstack)) { ++ MinecraftKey type = ((TileEntityMobSpawner) tileentity).getSpawner().getMobName(); ++ if (type != null) { ++ final Component mobName = PaperAdventure.asAdventure(EntityTypes.getFromKey(type).getNameComponent()); ++ final TextReplacementConfig config = TextReplacementConfig.builder() ++ .matchLiteral("{mob}") ++ .replacement(mobName) ++ .build(); ++ ++ NBTTagCompound display = new NBTTagCompound(); ++ boolean customDisplay = false; ++ ++ String name = world.purpurConfig.silkTouchSpawnerName; ++ if (name != null && !name.isEmpty() && !name.equals("Spawner")) { ++ final Component displayName = PaperAdventure.LEGACY_AMPERSAND.deserialize(name).replaceText(config).decoration(ITALIC, false); ++ display.set("Name", NBTTagString.create(GsonComponentSerializer.gson().serialize(displayName))); ++ customDisplay = true; ++ } ++ ++ List lore = world.purpurConfig.silkTouchSpawnerLore; ++ if (lore != null && !lore.isEmpty()) { ++ NBTTagList list = new NBTTagList(); ++ for (String line : lore) { ++ final Component lineComponent = PaperAdventure.LEGACY_AMPERSAND.deserialize(line).replaceText(config).decoration(ITALIC, false); ++ list.add(NBTTagString.create(GsonComponentSerializer.gson().serialize(lineComponent))); ++ } ++ display.set("Lore", list); ++ customDisplay = true; ++ } ++ ++ NBTTagCompound tag = new NBTTagCompound(); ++ if (customDisplay) { ++ tag.set("display", display); ++ } ++ tag.setString("Purpur.mob_type", type.toString()); ++ ++ ItemStack item = new ItemStack(Blocks.SPAWNER.getItem()); ++ item.setTag(tag); ++ ++ dropItem(world, blockposition, item); ++ } ++ } ++ super.a(world, entityhuman, blockposition, iblockdata, tileentity, itemstack); ++ } ++ ++ private boolean isSilkTouch(World world, ItemStack itemstack) { ++ return itemstack != null && world.purpurConfig.silkTouchTools.contains(itemstack.getItem()) && EnchantmentManager.getEnchantmentLevel(Enchantments.SILK_TOUCH, itemstack) > 0; ++ } ++ // Purpur end ++ + @Override + public void dropNaturally(IBlockData iblockdata, WorldServer worldserver, BlockPosition blockposition, ItemStack itemstack) { + super.dropNaturally(iblockdata, worldserver, blockposition, itemstack); +@@ -32,6 +106,7 @@ public class BlockMobSpawner extends BlockTileEntity { + + @Override + public int getExpDrop(IBlockData iblockdata, WorldServer worldserver, BlockPosition blockposition, ItemStack itemstack) { ++ if (isSilkTouch(worldserver, itemstack)) return 0; // Purpur + int i = 15 + worldserver.random.nextInt(15) + worldserver.random.nextInt(15); + + return i; +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index c7fb5a737cab0083c39732247acb8f4e87562894..10a6fcd70869719ed2b2d1442a83ab912e00c898 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -1,6 +1,12 @@ + package net.pl3x.purpur; + ++import net.minecraft.core.IRegistry; ++import net.minecraft.world.item.Item; ++import net.minecraft.world.item.Items; ++import net.minecraft.resources.MinecraftKey; + import org.bukkit.configuration.ConfigurationSection; ++ ++import java.util.ArrayList; + import java.util.List; + import static net.pl3x.purpur.PurpurConfig.log; + +@@ -75,6 +81,29 @@ public class PurpurWorldConfig { + playerInvulnerableWhileAcceptingResourcePack = getBoolean("gameplay-mechanics.player.invulnerable-while-accepting-resource-pack", playerInvulnerableWhileAcceptingResourcePack); + } + ++ public boolean silkTouchEnabled = false; ++ public String silkTouchSpawnerName = "Spawner"; ++ public List silkTouchSpawnerLore = new ArrayList<>(); ++ public List silkTouchTools = new ArrayList<>(); ++ private void silkTouchSettings() { ++ silkTouchEnabled = getBoolean("gameplay-mechanics.silk-touch.enabled", silkTouchEnabled); ++ silkTouchSpawnerName = getString("gameplay-mechanics.silk-touch.spawner-name", silkTouchSpawnerName); ++ silkTouchSpawnerLore.clear(); ++ getList("gameplay-mechanics.silk-touch.spawner-lore", new ArrayList(){{ ++ add("Spawns a {mob}"); ++ }}).forEach(line -> silkTouchSpawnerLore.add(line.toString())); ++ silkTouchTools.clear(); ++ getList("gameplay-mechanics.silk-touch.tools", new ArrayList(){{ ++ add("minecraft:iron_pickaxe"); ++ add("minecraft:golden_pickaxe"); ++ add("minecraft:diamond_pickaxe"); ++ add("minecraft:netherite_pickaxe"); ++ }}).forEach(key -> { ++ Item item = IRegistry.ITEM.get(new MinecraftKey(key.toString())); ++ if (item != Items.AIR) silkTouchTools.add(item); ++ }); ++ } ++ + public int villagerBrainTicks = 1; + public boolean villagerUseBrainTicksOnlyWhenLagging = true; + private void villagerSettings() { diff --git a/patches/Purpur/patches/server/0019-MC-168772-Fix-Add-turtle-egg-block-options.patch b/patches/Purpur/patches/server/0019-MC-168772-Fix-Add-turtle-egg-block-options.patch new file mode 100644 index 00000000..ae221310 --- /dev/null +++ b/patches/Purpur/patches/server/0019-MC-168772-Fix-Add-turtle-egg-block-options.patch @@ -0,0 +1,71 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Thu, 6 Jun 2019 22:15:46 -0500 +Subject: [PATCH] MC-168772 Fix - Add turtle egg block options + + +diff --git a/src/main/java/net/minecraft/world/level/block/BlockTurtleEgg.java b/src/main/java/net/minecraft/world/level/block/BlockTurtleEgg.java +index 6093d4c7431a286477c9be97163ea8d64168c3b0..04504901b1933ed760b34b8abb994de8ec340a4e 100644 +--- a/src/main/java/net/minecraft/world/level/block/BlockTurtleEgg.java ++++ b/src/main/java/net/minecraft/world/level/block/BlockTurtleEgg.java +@@ -9,12 +9,15 @@ import net.minecraft.sounds.SoundEffects; + import net.minecraft.tags.Tag; + import net.minecraft.tags.TagsBlock; + import net.minecraft.world.entity.Entity; ++import net.minecraft.world.entity.EntityExperienceOrb; + import net.minecraft.world.entity.EntityLiving; + import net.minecraft.world.entity.EntityTypes; + import net.minecraft.world.entity.ambient.EntityBat; + import net.minecraft.world.entity.animal.EntityTurtle; ++import net.minecraft.world.entity.item.EntityItem; + import net.minecraft.world.entity.monster.EntityZombie; + import net.minecraft.world.entity.player.EntityHuman; ++import net.minecraft.world.entity.vehicle.EntityMinecartAbstract; + import net.minecraft.world.item.ItemStack; + import net.minecraft.world.item.context.BlockActionContext; + import net.minecraft.world.level.GameRules; +@@ -189,6 +192,23 @@ public class BlockTurtleEgg extends Block { + } + + private boolean a(World world, Entity entity) { +- return !(entity instanceof EntityTurtle) && !(entity instanceof EntityBat) ? (!(entity instanceof EntityLiving) ? false : entity instanceof EntityHuman || world.getGameRules().getBoolean(GameRules.MOB_GRIEFING)) : false; ++ // Purpur start - fix MC-168772 ++ if (entity instanceof EntityTurtle) { ++ return false; ++ } ++ if (!world.purpurConfig.turtleEggsBreakFromExpOrbs && entity instanceof EntityExperienceOrb) { ++ return false; ++ } ++ if (!world.purpurConfig.turtleEggsBreakFromItems && entity instanceof EntityItem) { ++ return false; ++ } ++ if (!world.purpurConfig.turtleEggsBreakFromMinecarts && entity instanceof EntityMinecartAbstract) { ++ return false; ++ } ++ if (entity instanceof EntityLiving && !(entity instanceof EntityHuman)) { ++ return world.getGameRules().getBoolean(GameRules.MOB_GRIEFING); ++ } ++ return true; ++ // Purpur end + } + } +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 10a6fcd70869719ed2b2d1442a83ab912e00c898..2f18ca7ae23e913155f25fd07627f376e401ab0f 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -104,6 +104,15 @@ public class PurpurWorldConfig { + }); + } + ++ public boolean turtleEggsBreakFromExpOrbs = true; ++ public boolean turtleEggsBreakFromItems = true; ++ public boolean turtleEggsBreakFromMinecarts = true; ++ private void turtleEggSettings() { ++ turtleEggsBreakFromExpOrbs = getBoolean("blocks.turtle_egg.break-from-exp-orbs", turtleEggsBreakFromExpOrbs); ++ turtleEggsBreakFromItems = getBoolean("blocks.turtle_egg.break-from-items", turtleEggsBreakFromItems); ++ turtleEggsBreakFromMinecarts = getBoolean("blocks.turtle_egg.break-from-minecarts", turtleEggsBreakFromMinecarts); ++ } ++ + public int villagerBrainTicks = 1; + public boolean villagerUseBrainTicksOnlyWhenLagging = true; + private void villagerSettings() { diff --git a/patches/Purpur/patches/server/0020-Fix-vanilla-command-permission-handler.patch b/patches/Purpur/patches/server/0020-Fix-vanilla-command-permission-handler.patch new file mode 100644 index 00000000..06216b6d --- /dev/null +++ b/patches/Purpur/patches/server/0020-Fix-vanilla-command-permission-handler.patch @@ -0,0 +1,30 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sat, 28 Mar 2020 01:51:32 -0500 +Subject: [PATCH] Fix vanilla command permission handler + + +diff --git a/src/main/java/com/mojang/brigadier/tree/CommandNode.java b/src/main/java/com/mojang/brigadier/tree/CommandNode.java +index c0fac7369b111e65b896a15848ae22457e5e8914..5278997e522b495b83e53cac5968388d6eca45e4 100644 +--- a/src/main/java/com/mojang/brigadier/tree/CommandNode.java ++++ b/src/main/java/com/mojang/brigadier/tree/CommandNode.java +@@ -35,6 +35,7 @@ public abstract class CommandNode implements Comparable> { + private final RedirectModifier modifier; + private final boolean forks; + private Command command; ++ private String permission = null; public String getPermission() { return permission; } public void setPermission(String permission) { this.permission = permission; } // Purpur + // CraftBukkit start + public void removeCommand(String name) { + children.remove(name); +diff --git a/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java b/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java +index 56a0665127c7c55049b8438c91e72b6881ed11e0..575bc7d8a433cd6d4755757d82fe3a18da184d5a 100644 +--- a/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java ++++ b/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java +@@ -87,6 +87,7 @@ public final class VanillaCommandWrapper extends BukkitCommand { + } + + public static String getPermission(CommandNode vanillaCommand) { ++ if (vanillaCommand.getPermission() != null) return vanillaCommand.getPermission(); // Purpur + return "minecraft.command." + ((vanillaCommand.getRedirect() == null) ? vanillaCommand.getName() : vanillaCommand.getRedirect().getName()); + } + diff --git a/patches/Purpur/patches/server/0021-Logger-settings-suppressing-pointless-logs.patch b/patches/Purpur/patches/server/0021-Logger-settings-suppressing-pointless-logs.patch new file mode 100644 index 00000000..2819f1b7 --- /dev/null +++ b/patches/Purpur/patches/server/0021-Logger-settings-suppressing-pointless-logs.patch @@ -0,0 +1,46 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sat, 19 Oct 2019 00:52:12 -0500 +Subject: [PATCH] Logger settings (suppressing pointless logs) + + +diff --git a/src/main/java/net/minecraft/server/AdvancementDataPlayer.java b/src/main/java/net/minecraft/server/AdvancementDataPlayer.java +index dfdbc028f68ced197ad179248ed3b1e9d70ba057..a1ee1066108985a95abddb03ff447b5a14f4f85f 100644 +--- a/src/main/java/net/minecraft/server/AdvancementDataPlayer.java ++++ b/src/main/java/net/minecraft/server/AdvancementDataPlayer.java +@@ -190,6 +190,7 @@ public class AdvancementDataPlayer { + if (advancement == null) { + // CraftBukkit start + if (entry.getKey().getNamespace().equals("minecraft")) { ++ if (!net.pl3x.purpur.PurpurConfig.loggerSuppressIgnoredAdvancementWarnings) // Purpur + AdvancementDataPlayer.LOGGER.warn("Ignored advancement '{}' in progress file {} - it doesn't exist anymore?", entry.getKey(), this.f); + } + // CraftBukkit end +diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java +index afd0c577069f2a856caf41bd2dd5187db4866fa3..c7755cea5e8337af7acc96c6a34afa547b391035 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java +@@ -178,4 +178,11 @@ public class PurpurConfig { + InventoryType.ENDER_CHEST.setDefaultSize(enderChestSixRows ? 54 : 27); + enderChestPermissionRows = getBoolean("settings.blocks.ender_chest.use-permissions-for-rows", enderChestPermissionRows); + } ++ ++ public static boolean loggerSuppressInitLegacyMaterialError = false; ++ public static boolean loggerSuppressIgnoredAdvancementWarnings = false; ++ private static void loggerSettings() { ++ loggerSuppressInitLegacyMaterialError = getBoolean("settings.logger.suppress-init-legacy-material-errors", loggerSuppressInitLegacyMaterialError); ++ loggerSuppressIgnoredAdvancementWarnings = getBoolean("settings.logger.suppress-ignored-advancement-warnings", loggerSuppressIgnoredAdvancementWarnings); ++ } + } +diff --git a/src/main/java/org/bukkit/craftbukkit/legacy/CraftLegacy.java b/src/main/java/org/bukkit/craftbukkit/legacy/CraftLegacy.java +index b86604cbf3543b978df000d8f74c6185aa2ae7ec..5df82b0409278bd298e837aa43941247de3f94fe 100644 +--- a/src/main/java/org/bukkit/craftbukkit/legacy/CraftLegacy.java ++++ b/src/main/java/org/bukkit/craftbukkit/legacy/CraftLegacy.java +@@ -254,6 +254,7 @@ public final class CraftLegacy { + } + + static { ++ if (!net.pl3x.purpur.PurpurConfig.loggerSuppressInitLegacyMaterialError) // Purpur + System.err.println("Initializing Legacy Material Support. Unless you have legacy plugins and/or data this is a bug!"); + if (MinecraftServer.getServer() != null && MinecraftServer.getServer().isDebugging()) { + new Exception().printStackTrace(); diff --git a/patches/Purpur/patches/server/0022-Disable-outdated-build-check.patch b/patches/Purpur/patches/server/0022-Disable-outdated-build-check.patch new file mode 100644 index 00000000..4fed75af --- /dev/null +++ b/patches/Purpur/patches/server/0022-Disable-outdated-build-check.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sun, 15 Dec 2019 12:53:59 -0600 +Subject: [PATCH] Disable outdated build check + + +diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java +index 424d55f51a36d9033db3dfbf2f7a86749b0e3b91..73513638dd024cb1cdd49c705921f0bcf1935968 100644 +--- a/src/main/java/org/bukkit/craftbukkit/Main.java ++++ b/src/main/java/org/bukkit/craftbukkit/Main.java +@@ -272,7 +272,7 @@ public class Main { + System.setProperty(TerminalConsoleAppender.JLINE_OVERRIDE_PROPERTY, "false"); // Paper + } + +- if (false && Main.class.getPackage().getImplementationVendor() != null && System.getProperty("IReallyKnowWhatIAmDoingISwear") == null) { ++ if (false && Main.class.getPackage().getImplementationVendor() != null && System.getProperty("IReallyKnowWhatIAmDoingISwear") == null) { // Purpur - break on change + Date buildDate = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'").parse(Main.class.getPackage().getImplementationVendor()); // Paper + + Calendar deadline = Calendar.getInstance(); diff --git a/patches/Purpur/patches/server/0023-Giants-AI-settings.patch b/patches/Purpur/patches/server/0023-Giants-AI-settings.patch new file mode 100644 index 00000000..afa44eae --- /dev/null +++ b/patches/Purpur/patches/server/0023-Giants-AI-settings.patch @@ -0,0 +1,215 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sun, 12 May 2019 00:43:12 -0500 +Subject: [PATCH] Giants AI settings + + +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index 89852779fd9cfd19058afe40feb0cf14ca8d2896..611a2c34c80462826564705eb5a079bd6fdda4e1 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -228,7 +228,7 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, ne + public double D; + public double E; + public double F; +- public float G; public final float getStepHeight() { return this.G; } // Tuinity - OBFHELPER ++ public float G; public final float getStepHeight() { return this.G; } public void setStepHeight(float stepHeight) { this.G = stepHeight; } // Tuinity - OBFHELPER // Purpur - OBFHELPER + public boolean noclip; + public float I; + protected final Random random; +diff --git a/src/main/java/net/minecraft/world/entity/EntityInsentient.java b/src/main/java/net/minecraft/world/entity/EntityInsentient.java +index 7ba59ff9a7ed39bf69c46973a85f874c43134dc1..46e9a232ca5df81cafd4c3fc6af43b933c95d04f 100644 +--- a/src/main/java/net/minecraft/world/entity/EntityInsentient.java ++++ b/src/main/java/net/minecraft/world/entity/EntityInsentient.java +@@ -1021,6 +1021,7 @@ public abstract class EntityInsentient extends EntityLiving { + return f; + } + ++ protected void setEquipmentBasedOnDifficulty(DifficultyDamageScaler difficultydamagescaler) { a(difficultydamagescaler); } // Purpur - OBFHELPER + protected void a(DifficultyDamageScaler difficultydamagescaler) { + if (this.random.nextFloat() < 0.15F * difficultydamagescaler.d()) { + int i = this.random.nextInt(2); +@@ -1128,6 +1129,7 @@ public abstract class EntityInsentient extends EntityLiving { + } + } + ++ protected void setEnchantmentBasedOnDifficulty(DifficultyDamageScaler difficultydamagescaler) { b(difficultydamagescaler); } // Purpur - OBFHELPER + protected void b(DifficultyDamageScaler difficultydamagescaler) { + float f = difficultydamagescaler.d(); + +diff --git a/src/main/java/net/minecraft/world/entity/EntityLiving.java b/src/main/java/net/minecraft/world/entity/EntityLiving.java +index 7d0bb706fb106709432c3fae8758d2cea1d14db8..032b1a519de56583990fe47a216665ce71cf93ab 100644 +--- a/src/main/java/net/minecraft/world/entity/EntityLiving.java ++++ b/src/main/java/net/minecraft/world/entity/EntityLiving.java +@@ -260,6 +260,7 @@ public abstract class EntityLiving extends Entity { + this.activeItem = ItemStack.b; + this.by = Optional.empty(); + this.attributeMap = new AttributeMapBase(AttributeDefaults.a(entitytypes)); ++ this.initAttributes(); // Purpur + this.craftAttributes = new CraftAttributeMap(attributeMap); // CraftBukkit + // CraftBukkit - setHealth(getMaxHealth()) inlined and simplified to skip the instanceof check for EntityPlayer, as getBukkitEntity() is not initialized in constructor + this.datawatcher.set(EntityLiving.HEALTH, (float) this.getAttributeInstance(GenericAttributes.MAX_HEALTH).getValue()); +@@ -275,6 +276,8 @@ public abstract class EntityLiving extends Entity { + this.bg = this.a(new Dynamic(dynamicopsnbt, dynamicopsnbt.createMap((Map) ImmutableMap.of(dynamicopsnbt.createString("memories"), dynamicopsnbt.emptyMap())))); + } + ++ protected void initAttributes() {} // Purpur ++ + public BehaviorController getBehaviorController() { + return this.bg; + } +@@ -2273,7 +2276,7 @@ public abstract class EntityLiving extends Entity { + this.enderTeleportTo(vec3d.x, vec3d.y, vec3d.z); + } + +- protected float dJ() { ++ protected float dJ() { return getJumpHeight(); } public float getJumpHeight() { // Purpur - OBFHELPER + return 0.42F * this.getBlockJumpFactor(); + } + +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityGiantZombie.java b/src/main/java/net/minecraft/world/entity/monster/EntityGiantZombie.java +index 5e6a92dcdbca686d5a8cfc4aaff72b70b81b111f..a188a89143cb1b0243dacdec33c446ca4120219f 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityGiantZombie.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityGiantZombie.java +@@ -1,21 +1,99 @@ + package net.minecraft.world.entity.monster; + + import net.minecraft.core.BlockPosition; ++import net.minecraft.nbt.NBTTagCompound; ++import net.minecraft.world.DifficultyDamageScaler; ++import net.minecraft.world.EnumDifficulty; + import net.minecraft.world.entity.EntityPose; + import net.minecraft.world.entity.EntitySize; + import net.minecraft.world.entity.EntityTypes; ++import net.minecraft.world.entity.EnumItemSlot; ++import net.minecraft.world.entity.EnumMobSpawn; ++import net.minecraft.world.entity.GroupDataEntity; + import net.minecraft.world.entity.ai.attributes.AttributeProvider; + import net.minecraft.world.entity.ai.attributes.GenericAttributes; ++import net.minecraft.world.entity.ai.goal.PathfinderGoalFloat; ++import net.minecraft.world.entity.ai.goal.PathfinderGoalLookAtPlayer; ++import net.minecraft.world.entity.ai.goal.PathfinderGoalMeleeAttack; ++import net.minecraft.world.entity.ai.goal.PathfinderGoalMoveTowardsRestriction; ++import net.minecraft.world.entity.ai.goal.PathfinderGoalRandomLookaround; ++import net.minecraft.world.entity.ai.goal.PathfinderGoalRandomStrollLand; ++import net.minecraft.world.entity.ai.goal.target.PathfinderGoalHurtByTarget; ++import net.minecraft.world.entity.ai.goal.target.PathfinderGoalNearestAttackableTarget; ++import net.minecraft.world.entity.animal.EntityIronGolem; ++import net.minecraft.world.entity.animal.EntityTurtle; ++import net.minecraft.world.entity.npc.EntityVillager; ++import net.minecraft.world.entity.player.EntityHuman; ++import net.minecraft.world.item.ItemStack; ++import net.minecraft.world.item.Items; + import net.minecraft.world.level.IWorldReader; + import net.minecraft.world.level.World; ++import net.minecraft.world.level.WorldAccess; + + public class EntityGiantZombie extends EntityMonster { + + public EntityGiantZombie(EntityTypes entitytypes, World world) { + super(entitytypes, world); +- this.safeFallDistance = 10.0F; // Purpur ++ // Purpur start ++ this.safeFallDistance = 10.0F; ++ setStepHeight(world.purpurConfig.giantStepHeight); ++ // Purpur end + } + ++ // Purpur start ++ @Override ++ protected void initPathfinder() { ++ if (world.purpurConfig.giantHaveAI) { ++ this.goalSelector.a(0, new PathfinderGoalFloat(this)); ++ this.goalSelector.a(7, new PathfinderGoalRandomStrollLand(this, 1.0D)); ++ this.goalSelector.a(8, new PathfinderGoalLookAtPlayer(this, EntityHuman.class, 16.0F)); ++ this.goalSelector.a(8, new PathfinderGoalRandomLookaround(this)); ++ this.goalSelector.a(5, new PathfinderGoalMoveTowardsRestriction(this, 1.0D)); ++ if (world.purpurConfig.giantHaveHostileAI) { ++ this.goalSelector.a(2, new PathfinderGoalMeleeAttack(this, 1.0D, false)); ++ this.targetSelector.a(1, new PathfinderGoalHurtByTarget(this).a(EntityPigZombie.class)); ++ this.targetSelector.a(2, new PathfinderGoalNearestAttackableTarget<>(this, EntityHuman.class, true)); ++ this.targetSelector.a(3, new PathfinderGoalNearestAttackableTarget<>(this, EntityVillager.class, false)); ++ this.targetSelector.a(4, new PathfinderGoalNearestAttackableTarget<>(this, EntityIronGolem.class, true)); ++ this.targetSelector.a(5, new PathfinderGoalNearestAttackableTarget<>(this, EntityTurtle.class, true)); ++ } ++ } ++ } ++ ++ @Override ++ protected void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.giantMaxHealth); ++ this.getAttributeInstance(GenericAttributes.MOVEMENT_SPEED).setValue(this.world.purpurConfig.giantMovementSpeed); ++ this.getAttributeInstance(GenericAttributes.ATTACK_DAMAGE).setValue(this.world.purpurConfig.giantAttackDamage); ++ } ++ ++ @Override ++ public GroupDataEntity prepare(WorldAccess worldaccess, DifficultyDamageScaler difficultydamagescaler, EnumMobSpawn enummobspawn, @javax.annotation.Nullable GroupDataEntity groupdataentity, @javax.annotation.Nullable NBTTagCompound nbttagcompound) { ++ GroupDataEntity groupData = super.prepare(worldaccess, difficultydamagescaler, enummobspawn, groupdataentity, nbttagcompound); ++ if (groupData == null) { ++ setEquipmentBasedOnDifficulty(difficultydamagescaler); ++ setEnchantmentBasedOnDifficulty(difficultydamagescaler); ++ } ++ return groupData; ++ } ++ ++ @Override ++ protected void setEquipmentBasedOnDifficulty(DifficultyDamageScaler difficulty) { ++ super.setEquipmentBasedOnDifficulty(difficulty); ++ // TODO make configurable ++ if (random.nextFloat() < (world.getDifficulty() == EnumDifficulty.HARD ? 0.1F : 0.05F)) { ++ setSlot(EnumItemSlot.MAINHAND, new ItemStack(Items.IRON_SWORD)); ++ } ++ } ++ ++ @Override ++ public float getJumpHeight() { ++ // make giants jump as high as everything else relative to their size ++ // 1.0 makes bottom of feet about as high as their waist when they jump ++ return world.purpurConfig.giantJumpHeight; ++ } ++ // Purpur end ++ + @Override + protected float b(EntityPose entitypose, EntitySize entitysize) { + return 10.440001F; +@@ -27,6 +105,6 @@ public class EntityGiantZombie extends EntityMonster { + + @Override + public float a(BlockPosition blockposition, IWorldReader iworldreader) { +- return iworldreader.y(blockposition) - 0.5F; ++ return super.a(blockposition, iworldreader); // Purpur - fix light requirements for natural spawns + } + } +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 2f18ca7ae23e913155f25fd07627f376e401ab0f..1c87c929aaae17631100d1aa30b3e7ecce52686f 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -113,6 +113,28 @@ public class PurpurWorldConfig { + turtleEggsBreakFromMinecarts = getBoolean("blocks.turtle_egg.break-from-minecarts", turtleEggsBreakFromMinecarts); + } + ++ public float giantStepHeight = 2.0F; ++ public float giantJumpHeight = 1.0F; ++ public double giantMovementSpeed = 0.5D; ++ public double giantAttackDamage = 50.0D; ++ public boolean giantHaveAI = false; ++ public boolean giantHaveHostileAI = false; ++ public double giantMaxHealth = 100.0D; ++ private void giantSettings() { ++ giantStepHeight = (float) getDouble("mobs.giant.step-height", giantStepHeight); ++ giantJumpHeight = (float) getDouble("mobs.giant.jump-height", giantJumpHeight); ++ giantMovementSpeed = getDouble("mobs.giant.movement-speed", giantMovementSpeed); ++ giantAttackDamage = getDouble("mobs.giant.attack-damage", giantAttackDamage); ++ giantHaveAI = getBoolean("mobs.giant.have-ai", giantHaveAI); ++ giantHaveHostileAI = getBoolean("mobs.giant.have-hostile-ai", giantHaveHostileAI); ++ if (PurpurConfig.version < 8) { ++ double oldValue = getDouble("mobs.giant.max-health", giantMaxHealth); ++ set("mobs.giant.attributes.max-health", oldValue); ++ set("mobs.giant.max-health", null); ++ } ++ giantMaxHealth = getDouble("mobs.giant.attributes.max-health", giantMaxHealth); ++ } ++ + public int villagerBrainTicks = 1; + public boolean villagerUseBrainTicksOnlyWhenLagging = true; + private void villagerSettings() { diff --git a/patches/Purpur/patches/server/0024-Illusioners-AI-settings.patch b/patches/Purpur/patches/server/0024-Illusioners-AI-settings.patch new file mode 100644 index 00000000..ffcf44ac --- /dev/null +++ b/patches/Purpur/patches/server/0024-Illusioners-AI-settings.patch @@ -0,0 +1,51 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Fri, 5 Jul 2019 11:09:25 -0500 +Subject: [PATCH] Illusioners AI settings + + +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityIllagerIllusioner.java b/src/main/java/net/minecraft/world/entity/monster/EntityIllagerIllusioner.java +index fee9a5140f097225b5da58b18bfbd528dffdc77b..cb092bee9d6827d4b0276bfa9b033cf7ca86ead4 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityIllagerIllusioner.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityIllagerIllusioner.java +@@ -56,6 +56,15 @@ public class EntityIllagerIllusioner extends EntityIllagerWizard implements IRan + + } + ++ // Purpur start ++ @Override ++ protected void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MOVEMENT_SPEED).setValue(this.world.purpurConfig.illusionerMovementSpeed); ++ this.getAttributeInstance(GenericAttributes.FOLLOW_RANGE).setValue(this.world.purpurConfig.illusionerFollowRange); ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.illusionerMaxHealth); ++ } ++ // Purpur end ++ + @Override + protected void initPathfinder() { + super.initPathfinder(); +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 1c87c929aaae17631100d1aa30b3e7ecce52686f..d6bd971a62af7341f8dc8b3afe32786ced6fcd41 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -135,6 +135,20 @@ public class PurpurWorldConfig { + giantMaxHealth = getDouble("mobs.giant.attributes.max-health", giantMaxHealth); + } + ++ public double illusionerMovementSpeed = 0.5D; ++ public double illusionerFollowRange = 18.0D; ++ public double illusionerMaxHealth = 32.0D; ++ private void illusionerSettings() { ++ illusionerMovementSpeed = getDouble("mobs.illusioner.movement-speed", illusionerMovementSpeed); ++ illusionerFollowRange = getDouble("mobs.illusioner.follow-range", illusionerFollowRange); ++ if (PurpurConfig.version < 8) { ++ double oldValue = getDouble("mobs.illusioner.max-health", illusionerMaxHealth); ++ set("mobs.illusioner.attributes.max-health", oldValue); ++ set("mobs.illusioner.max-health", null); ++ } ++ illusionerMaxHealth = getDouble("mobs.illusioner.attributes.max-health", illusionerMaxHealth); ++ } ++ + public int villagerBrainTicks = 1; + public boolean villagerUseBrainTicksOnlyWhenLagging = true; + private void villagerSettings() { diff --git a/patches/Purpur/patches/server/0025-Zombie-horse-naturally-spawn.patch b/patches/Purpur/patches/server/0025-Zombie-horse-naturally-spawn.patch new file mode 100644 index 00000000..24f10369 --- /dev/null +++ b/patches/Purpur/patches/server/0025-Zombie-horse-naturally-spawn.patch @@ -0,0 +1,57 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sun, 7 Jul 2019 19:52:16 -0500 +Subject: [PATCH] Zombie horse naturally spawn + + +diff --git a/src/main/java/net/minecraft/server/level/WorldServer.java b/src/main/java/net/minecraft/server/level/WorldServer.java +index a97b8d8116920237964cc3a887525f8c3804c640..a0c731af6dffa30832b321f8fd86cef76ec06522 100644 +--- a/src/main/java/net/minecraft/server/level/WorldServer.java ++++ b/src/main/java/net/minecraft/server/level/WorldServer.java +@@ -96,6 +96,7 @@ import net.minecraft.world.entity.ai.village.poi.VillagePlace; + import net.minecraft.world.entity.ai.village.poi.VillagePlaceType; + import net.minecraft.world.entity.animal.EntityAnimal; + import net.minecraft.world.entity.animal.EntityWaterAnimal; ++import net.minecraft.world.entity.animal.horse.EntityHorseAbstract; + import net.minecraft.world.entity.animal.horse.EntityHorseSkeleton; + import net.minecraft.world.entity.boss.EntityComplexPart; + import net.minecraft.world.entity.boss.enderdragon.EntityEnderDragon; +@@ -1219,12 +1220,18 @@ public class WorldServer extends World implements GeneratorAccessSeed { + boolean flag1 = this.getGameRules().getBoolean(GameRules.DO_MOB_SPAWNING) && this.random.nextDouble() < (double) difficultydamagescaler.b() * paperConfig.skeleHorseSpawnChance; // Paper + + if (flag1) { +- EntityHorseSkeleton entityhorseskeleton = (EntityHorseSkeleton) EntityTypes.SKELETON_HORSE.a((World) this); +- +- entityhorseskeleton.t(true); +- entityhorseskeleton.setAgeRaw(0); +- entityhorseskeleton.setPosition((double) blockposition.getX(), (double) blockposition.getY(), (double) blockposition.getZ()); +- this.addEntity(entityhorseskeleton, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.LIGHTNING); // CraftBukkit ++ // Purpur start ++ EntityHorseAbstract horse; ++ if (purpurConfig.zombieHorseSpawnChance > 0D && random.nextDouble() <= purpurConfig.zombieHorseSpawnChance) { ++ horse = EntityTypes.ZOMBIE_HORSE.create(this); ++ } else { ++ horse = EntityTypes.SKELETON_HORSE.create(this); ++ ((EntityHorseSkeleton) horse).setTrap(true); ++ } ++ horse.setAgeRaw(0); ++ horse.setPosition(blockposition.getX(), blockposition.getY(), blockposition.getZ()); ++ addEntity(horse, CreatureSpawnEvent.SpawnReason.LIGHTNING); // CraftBukkit ++ // Purpur end + } + + EntityLightning entitylightning = (EntityLightning) EntityTypes.LIGHTNING_BOLT.a((World) this); +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index d6bd971a62af7341f8dc8b3afe32786ced6fcd41..81b0e17a4bc5022ea757f03c2546808148d6e957 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -155,4 +155,9 @@ public class PurpurWorldConfig { + villagerBrainTicks = getInt("mobs.villager.brain-ticks", villagerBrainTicks); + villagerUseBrainTicksOnlyWhenLagging = getBoolean("mobs.villager.use-brain-ticks-only-when-lagging", villagerUseBrainTicksOnlyWhenLagging); + } ++ ++ public double zombieHorseSpawnChance = 0.0D; ++ private void zombieHorseSettings() { ++ zombieHorseSpawnChance = getDouble("mobs.zombie_horse.spawn-chance", zombieHorseSpawnChance); ++ } + } diff --git a/patches/Purpur/patches/server/0026-Charged-creeper-naturally-spawn.patch b/patches/Purpur/patches/server/0026-Charged-creeper-naturally-spawn.patch new file mode 100644 index 00000000..306f6851 --- /dev/null +++ b/patches/Purpur/patches/server/0026-Charged-creeper-naturally-spawn.patch @@ -0,0 +1,69 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Fri, 29 Nov 2019 22:37:44 -0600 +Subject: [PATCH] Charged creeper naturally spawn + + +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityCreeper.java b/src/main/java/net/minecraft/world/entity/monster/EntityCreeper.java +index b47f71ca1f1c8bbd1a521836d9cb5d676a33ec76..63a6b1820f60db9eea49a3a589dd50ad25a3c0a2 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityCreeper.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityCreeper.java +@@ -9,6 +9,7 @@ import net.minecraft.network.syncher.DataWatcherRegistry; + import net.minecraft.server.level.WorldServer; + import net.minecraft.sounds.SoundEffect; + import net.minecraft.sounds.SoundEffects; ++import net.minecraft.world.DifficultyDamageScaler; + import net.minecraft.world.EnumHand; + import net.minecraft.world.EnumInteractionResult; + import net.minecraft.world.damagesource.DamageSource; +@@ -17,6 +18,8 @@ import net.minecraft.world.entity.Entity; + import net.minecraft.world.entity.EntityAreaEffectCloud; + import net.minecraft.world.entity.EntityLightning; + import net.minecraft.world.entity.EntityTypes; ++import net.minecraft.world.entity.EnumMobSpawn; ++import net.minecraft.world.entity.GroupDataEntity; + import net.minecraft.world.entity.ai.attributes.AttributeProvider; + import net.minecraft.world.entity.ai.attributes.GenericAttributes; + import net.minecraft.world.entity.ai.goal.PathfinderGoalAvoidTarget; +@@ -39,6 +42,7 @@ import net.minecraft.world.level.IMaterial; + import net.minecraft.world.level.World; + + // CraftBukkit start ++import net.minecraft.world.level.WorldAccess; + import org.bukkit.craftbukkit.event.CraftEventFactory; + import org.bukkit.event.entity.CreatureSpawnEvent; + import org.bukkit.event.entity.ExplosionPrimeEvent; +@@ -59,6 +63,17 @@ public class EntityCreeper extends EntityMonster { + super(entitytypes, world); + } + ++ // Purpur start ++ @Override ++ public GroupDataEntity prepare(WorldAccess worldaccess, DifficultyDamageScaler difficultydamagescaler, EnumMobSpawn enummobspawn, @javax.annotation.Nullable GroupDataEntity groupdataentity, @javax.annotation.Nullable NBTTagCompound nbttagcompound) { ++ double chance = worldaccess.getMinecraftWorld().purpurConfig.creeperChargedChance; ++ if (chance > 0D && random.nextDouble() <= chance) { ++ setPowered(true); ++ } ++ return super.prepare(worldaccess, difficultydamagescaler, enummobspawn, groupdataentity, nbttagcompound); ++ } ++ // Purpur end ++ + @Override + protected void initPathfinder() { + this.goalSelector.a(1, new PathfinderGoalFloat(this)); +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 81b0e17a4bc5022ea757f03c2546808148d6e957..638ee71a78d9e75de6ddd7f0aec67a023bb8c06a 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -113,6 +113,11 @@ public class PurpurWorldConfig { + turtleEggsBreakFromMinecarts = getBoolean("blocks.turtle_egg.break-from-minecarts", turtleEggsBreakFromMinecarts); + } + ++ public double creeperChargedChance = 0.0D; ++ private void creeperSettings() { ++ creeperChargedChance = getDouble("mobs.creeper.naturally-charged-chance", creeperChargedChance); ++ } ++ + public float giantStepHeight = 2.0F; + public float giantJumpHeight = 1.0F; + public double giantMovementSpeed = 0.5D; diff --git a/patches/Purpur/patches/server/0027-Rabbit-naturally-spawn-toast-and-killer.patch b/patches/Purpur/patches/server/0027-Rabbit-naturally-spawn-toast-and-killer.patch new file mode 100644 index 00000000..53243413 --- /dev/null +++ b/patches/Purpur/patches/server/0027-Rabbit-naturally-spawn-toast-and-killer.patch @@ -0,0 +1,56 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sat, 31 Aug 2019 17:47:11 -0500 +Subject: [PATCH] Rabbit naturally spawn toast and killer + + +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityRabbit.java b/src/main/java/net/minecraft/world/entity/animal/EntityRabbit.java +index dcbb07fb6ab799d4526a2da0614c193c7abba715..180fc927074dc683ad4d482a00dd4e04ff7923d0 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityRabbit.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityRabbit.java +@@ -352,6 +352,10 @@ public class EntityRabbit extends EntityAnimal { + if (!this.hasCustomName()) { + this.setCustomName(new ChatMessage(SystemUtils.a("entity", EntityRabbit.bp))); + } ++ // Purpur start ++ } else if (i == 98) { ++ setCustomName(new ChatMessage("Toast")); ++ // Purpur end + } + + this.datawatcher.set(EntityRabbit.bo, i); +@@ -373,6 +377,16 @@ public class EntityRabbit extends EntityAnimal { + } + + private int a(GeneratorAccess generatoraccess) { ++ // Purpur start ++ World world = generatoraccess.getMinecraftWorld(); ++ if (world.purpurConfig.rabbitNaturalKiller > 0D && random.nextDouble() <= world.purpurConfig.rabbitNaturalKiller) { ++ return 99; ++ } ++ if (world.purpurConfig.rabbitNaturalToast > 0D && random.nextDouble() <= world.purpurConfig.rabbitNaturalToast) { ++ return 98; ++ } ++ // Purpur end ++ + BiomeBase biomebase = generatoraccess.getBiome(this.getChunkCoordinates()); + int i = this.random.nextInt(100); + +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 638ee71a78d9e75de6ddd7f0aec67a023bb8c06a..6dcfbebd850d71587da5a78a3acf09d8ae413072 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -154,6 +154,13 @@ public class PurpurWorldConfig { + illusionerMaxHealth = getDouble("mobs.illusioner.attributes.max-health", illusionerMaxHealth); + } + ++ public double rabbitNaturalToast = 0.0D; ++ public double rabbitNaturalKiller = 0.0D; ++ private void rabbitSettings() { ++ rabbitNaturalToast = getDouble("mobs.rabbit.spawn-toast-chance", rabbitNaturalToast); ++ rabbitNaturalKiller = getDouble("mobs.rabbit.spawn-killer-rabbit-chance", rabbitNaturalKiller); ++ } ++ + public int villagerBrainTicks = 1; + public boolean villagerUseBrainTicksOnlyWhenLagging = true; + private void villagerSettings() { diff --git a/patches/Purpur/patches/server/0028-Fix-outdated-server-showing-in-ping-before-server-fu.patch b/patches/Purpur/patches/server/0028-Fix-outdated-server-showing-in-ping-before-server-fu.patch new file mode 100644 index 00000000..fecb9d6b --- /dev/null +++ b/patches/Purpur/patches/server/0028-Fix-outdated-server-showing-in-ping-before-server-fu.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Tue, 4 Jun 2019 15:50:08 -0500 +Subject: [PATCH] Fix 'outdated server' showing in ping before server fully + boots + + +diff --git a/src/main/java/net/minecraft/server/network/PacketStatusListener.java b/src/main/java/net/minecraft/server/network/PacketStatusListener.java +index e1997563984540e6edf5d3b697d029dc5f3c40e1..847c91305d23b99e612b9e5f988df14d3fb84a8c 100644 +--- a/src/main/java/net/minecraft/server/network/PacketStatusListener.java ++++ b/src/main/java/net/minecraft/server/network/PacketStatusListener.java +@@ -146,6 +146,7 @@ public class PacketStatusListener implements PacketStatusInListener { + + this.networkManager.sendPacket(new PacketStatusOutServerInfo(ping)); + */ ++ if (this.minecraftServer.getServerPing().getServerData() == null) return; // Purpur - do not respond to pings before we know the protocol version + com.destroystokyo.paper.network.StandardPaperServerListPingEventImpl.processRequest(this.minecraftServer, this.networkManager); + // Paper end + } diff --git a/patches/Purpur/patches/server/0029-Make-Iron-Golems-Swim.patch b/patches/Purpur/patches/server/0029-Make-Iron-Golems-Swim.patch new file mode 100644 index 00000000..13b90cad --- /dev/null +++ b/patches/Purpur/patches/server/0029-Make-Iron-Golems-Swim.patch @@ -0,0 +1,42 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sat, 15 Jun 2019 03:12:15 -0500 +Subject: [PATCH] Make Iron Golems Swim + + +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityIronGolem.java b/src/main/java/net/minecraft/world/entity/animal/EntityIronGolem.java +index 5e2b49d120b724cb5a7ae00940ded4f4875ea8a1..62cff5faafa076d05ebc59ad5c4fb020bea0509e 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityIronGolem.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityIronGolem.java +@@ -30,6 +30,7 @@ import net.minecraft.world.entity.EntityTypes; + import net.minecraft.world.entity.IEntityAngerable; + import net.minecraft.world.entity.ai.attributes.AttributeProvider; + import net.minecraft.world.entity.ai.attributes.GenericAttributes; ++import net.minecraft.world.entity.ai.goal.PathfinderGoalFloat; + import net.minecraft.world.entity.ai.goal.PathfinderGoalLookAtPlayer; + import net.minecraft.world.entity.ai.goal.PathfinderGoalMeleeAttack; + import net.minecraft.world.entity.ai.goal.PathfinderGoalMoveTowardsTarget; +@@ -70,6 +71,7 @@ public class EntityIronGolem extends EntityGolem implements IEntityAngerable { + + @Override + protected void initPathfinder() { ++ if (world.purpurConfig.ironGolemCanSwim) this.goalSelector.a(0, new PathfinderGoalFloat(this)); // Purpur + this.goalSelector.a(1, new PathfinderGoalMeleeAttack(this, 1.0D, true)); + this.goalSelector.a(2, new PathfinderGoalMoveTowardsTarget(this, 0.9D, 32.0F)); + this.goalSelector.a(2, new PathfinderGoalStrollVillage(this, 0.6D, false)); +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 6dcfbebd850d71587da5a78a3acf09d8ae413072..decd0e755deede2b092866a8f7f6b46520435bbe 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -154,6 +154,11 @@ public class PurpurWorldConfig { + illusionerMaxHealth = getDouble("mobs.illusioner.attributes.max-health", illusionerMaxHealth); + } + ++ public boolean ironGolemCanSwim = false; ++ private void ironGolemSettings() { ++ ironGolemCanSwim = getBoolean("mobs.iron_golem.can-swim", ironGolemCanSwim); ++ } ++ + public double rabbitNaturalToast = 0.0D; + public double rabbitNaturalKiller = 0.0D; + private void rabbitSettings() { diff --git a/patches/Purpur/patches/server/0030-Dont-send-useless-entity-packets.patch b/patches/Purpur/patches/server/0030-Dont-send-useless-entity-packets.patch new file mode 100644 index 00000000..609fff06 --- /dev/null +++ b/patches/Purpur/patches/server/0030-Dont-send-useless-entity-packets.patch @@ -0,0 +1,78 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sat, 6 Jul 2019 17:00:04 -0500 +Subject: [PATCH] Dont send useless entity packets + + +diff --git a/src/main/java/net/minecraft/network/protocol/game/PacketPlayOutEntity.java b/src/main/java/net/minecraft/network/protocol/game/PacketPlayOutEntity.java +index 0eed10a6c4e0c7245f219d19ed1e2e5c94364db9..2b54a5f3347f788b751892105f888663bb349629 100644 +--- a/src/main/java/net/minecraft/network/protocol/game/PacketPlayOutEntity.java ++++ b/src/main/java/net/minecraft/network/protocol/game/PacketPlayOutEntity.java +@@ -9,11 +9,11 @@ import net.minecraft.world.phys.Vec3D; + public class PacketPlayOutEntity implements Packet { + + protected int a; +- protected short b; +- protected short c; +- protected short d; +- protected byte e; +- protected byte f; ++ protected short b; public short getX() { return b; } // Purpur - OBFHELPER ++ protected short c; public short getY() { return c; } // Purpur - OBFHELPER ++ protected short d; public short getZ() { return d; } // Purpur - OBFHELPER ++ protected byte e; public byte getYaw() { return e; } // Purpur - OBFHELPER ++ protected byte f; public byte getPitch() { return f; } // Purpur - OBFHELPER + protected boolean g; + protected boolean h; + protected boolean i; +diff --git a/src/main/java/net/minecraft/server/level/EntityTrackerEntry.java b/src/main/java/net/minecraft/server/level/EntityTrackerEntry.java +index 67ca28463f5add7c18f7f16b918c3f36f8feeeda..53e773c14689967d5b12467bf209eefb05f7a812 100644 +--- a/src/main/java/net/minecraft/server/level/EntityTrackerEntry.java ++++ b/src/main/java/net/minecraft/server/level/EntityTrackerEntry.java +@@ -200,6 +200,7 @@ public class EntityTrackerEntry { + this.o = 0; + packet1 = new PacketPlayOutEntityTeleport(this.tracker); + } ++ if (net.pl3x.purpur.PurpurConfig.dontSendUselessEntityPackets && isUselessPacket(packet1)) packet1 = null; // Purpur + } + + if ((this.e || this.tracker.impulse || this.tracker instanceof EntityLiving && ((EntityLiving) this.tracker).isGliding()) && this.tickCounter > 0) { +@@ -286,6 +287,22 @@ public class EntityTrackerEntry { + + } + ++ // Purpur start ++ private boolean isUselessPacket(Packet possibleUselessPacket) { ++ if (possibleUselessPacket instanceof PacketPlayOutEntity) { ++ PacketPlayOutEntity packet = (PacketPlayOutEntity) possibleUselessPacket; ++ if (possibleUselessPacket instanceof PacketPlayOutEntity.PacketPlayOutRelEntityMove) { ++ return packet.getX() == 0 && packet.getY() == 0 && packet.getZ() == 0; ++ } else if (possibleUselessPacket instanceof PacketPlayOutEntity.PacketPlayOutRelEntityMoveLook) { ++ return packet.getX() == 0 && packet.getY() == 0 && packet.getZ() == 0 && packet.getYaw() == 0 && packet.getPitch() == 0; ++ } else if (possibleUselessPacket instanceof PacketPlayOutEntity.PacketPlayOutEntityLook) { ++ return packet.getYaw() == 0 && packet.getPitch() == 0; ++ } ++ } ++ return false; ++ } ++ // Purpur end ++ + public void a(EntityPlayer entityplayer) { + this.tracker.c(entityplayer); + entityplayer.c(this.tracker); +diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java +index c7755cea5e8337af7acc96c6a34afa547b391035..6d5c2f469e4a7a13a69ac3f7a1dadeac6aabb531 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java +@@ -179,6 +179,11 @@ public class PurpurConfig { + enderChestPermissionRows = getBoolean("settings.blocks.ender_chest.use-permissions-for-rows", enderChestPermissionRows); + } + ++ public static boolean dontSendUselessEntityPackets = false; ++ private static void dontSendUselessEntityPackets() { ++ dontSendUselessEntityPackets = getBoolean("settings.dont-send-useless-entity-packets", dontSendUselessEntityPackets); ++ } ++ + public static boolean loggerSuppressInitLegacyMaterialError = false; + public static boolean loggerSuppressIgnoredAdvancementWarnings = false; + private static void loggerSettings() { diff --git a/patches/Purpur/patches/server/0031-Tulips-change-fox-type.patch b/patches/Purpur/patches/server/0031-Tulips-change-fox-type.patch new file mode 100644 index 00000000..0a18c286 --- /dev/null +++ b/patches/Purpur/patches/server/0031-Tulips-change-fox-type.patch @@ -0,0 +1,111 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sat, 13 Jul 2019 15:56:22 -0500 +Subject: [PATCH] Tulips change fox type + + +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityFox.java b/src/main/java/net/minecraft/world/entity/animal/EntityFox.java +index b7fa24318ef43918b6b10ff4ea8acb960527296e..19a9affdaba52d8e7dc1c4c20d5c0d52829f4989 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityFox.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityFox.java +@@ -30,6 +30,8 @@ import net.minecraft.tags.Tag; + import net.minecraft.tags.TagsFluid; + import net.minecraft.util.MathHelper; + import net.minecraft.world.DifficultyDamageScaler; ++import net.minecraft.world.EnumHand; ++import net.minecraft.world.EnumInteractionResult; + import net.minecraft.world.damagesource.DamageSource; + import net.minecraft.world.entity.Entity; + import net.minecraft.world.entity.EntityAgeable; +@@ -107,9 +109,9 @@ public class EntityFox extends EntityAnimal { + private static final Predicate bv = (entity) -> { + return !entity.bx() && IEntitySelector.e.test(entity); + }; +- private PathfinderGoal bw; +- private PathfinderGoal bx; +- private PathfinderGoal by; ++ private PathfinderGoal bw; private PathfinderGoal attackAnimalGoal() { return bw; } // Purpur - OBFHELPER ++ private PathfinderGoal bx; private PathfinderGoal attackTurtleGoal() { return bx; } // Purpur - OBFHELPER ++ private PathfinderGoal by; private PathfinderGoal attackFishGoal() { return by; } // Purpur - OBFHELPER + private float bz; + private float bA; + private float bB; +@@ -297,6 +299,11 @@ public class EntityFox extends EntityAnimal { + } + + private void initializePathFinderGoals() { ++ // Purpur start - do not add duplicate goals ++ this.targetSelector.a(attackAnimalGoal()); ++ this.targetSelector.a(attackTurtleGoal()); ++ this.targetSelector.a(attackFishGoal()); ++ // Purpur end + if (this.getFoxType() == EntityFox.Type.RED) { + this.targetSelector.a(4, this.bw); + this.targetSelector.a(4, this.bx); +@@ -329,6 +336,7 @@ public class EntityFox extends EntityAnimal { + + public void setFoxType(EntityFox.Type entityfox_type) { + this.datawatcher.set(EntityFox.bo, entityfox_type.b()); ++ initializePathFinderGoals(); // Purpur - fix API bug not updating pathfinders on type change + } + + private List fa() { +@@ -646,6 +654,27 @@ public class EntityFox extends EntityAnimal { + return this.fa().contains(uuid); + } + ++ @Override ++ public EnumInteractionResult b(EntityHuman entityhuman, EnumHand enumhand) { ++ if (world.purpurConfig.foxTypeChangesWithTulips) { ++ ItemStack itemstack = entityhuman.b(enumhand); ++ if (getFoxType() == Type.RED && itemstack.getItem() == Items.whiteTulip()) { ++ setFoxType(Type.SNOW); ++ if (!entityhuman.abilities.canInstantlyBuild) { ++ itemstack.subtract(1); ++ } ++ return EnumInteractionResult.SUCCESS; ++ } else if (getFoxType() == Type.SNOW && itemstack.getItem() == Items.orangeTulip()) { ++ setFoxType(Type.RED); ++ if (!entityhuman.abilities.canInstantlyBuild) { ++ itemstack.subtract(1); ++ } ++ return EnumInteractionResult.SUCCESS; ++ } ++ } ++ return super.b(entityhuman, enumhand); ++ } ++ + @Override + protected org.bukkit.event.entity.EntityDeathEvent d(DamageSource damagesource) { // Paper + ItemStack itemstack = this.getEquipment(EnumItemSlot.MAINHAND).cloneItemStack(); // Paper +diff --git a/src/main/java/net/minecraft/world/item/Items.java b/src/main/java/net/minecraft/world/item/Items.java +index 8e9a25495d76251a86268d3059e2960a86dc46b3..993a88a5937417016821ef9d7cd58e4ee097491c 100644 +--- a/src/main/java/net/minecraft/world/item/Items.java ++++ b/src/main/java/net/minecraft/world/item/Items.java +@@ -133,8 +133,8 @@ public class Items { + public static final Item bk = a(Blocks.ALLIUM, CreativeModeTab.c); + public static final Item bl = a(Blocks.AZURE_BLUET, CreativeModeTab.c); + public static final Item bm = a(Blocks.RED_TULIP, CreativeModeTab.c); +- public static final Item bn = a(Blocks.ORANGE_TULIP, CreativeModeTab.c); +- public static final Item bo = a(Blocks.WHITE_TULIP, CreativeModeTab.c); ++ public static final Item bn = a(Blocks.ORANGE_TULIP, CreativeModeTab.c); public static Item orangeTulip() { return bn; } // Purpur - OBFHELPER ++ public static final Item bo = a(Blocks.WHITE_TULIP, CreativeModeTab.c); public static Item whiteTulip() { return bo; } // Purpur - OBFHELPER + public static final Item bp = a(Blocks.PINK_TULIP, CreativeModeTab.c); + public static final Item bq = a(Blocks.OXEYE_DAISY, CreativeModeTab.c); + public static final Item br = a(Blocks.CORNFLOWER, CreativeModeTab.c); +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index decd0e755deede2b092866a8f7f6b46520435bbe..081675005077c5070f7745e24fd2ee7400fe2320 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -118,6 +118,11 @@ public class PurpurWorldConfig { + creeperChargedChance = getDouble("mobs.creeper.naturally-charged-chance", creeperChargedChance); + } + ++ public boolean foxTypeChangesWithTulips = false; ++ private void foxSettings() { ++ foxTypeChangesWithTulips = getBoolean("mobs.fox.tulips-change-type", foxTypeChangesWithTulips); ++ } ++ + public float giantStepHeight = 2.0F; + public float giantJumpHeight = 1.0F; + public double giantMovementSpeed = 0.5D; diff --git a/patches/Purpur/patches/server/0032-Breedable-Polar-Bears.patch b/patches/Purpur/patches/server/0032-Breedable-Polar-Bears.patch new file mode 100644 index 00000000..4a2ecee2 --- /dev/null +++ b/patches/Purpur/patches/server/0032-Breedable-Polar-Bears.patch @@ -0,0 +1,117 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Thu, 26 Mar 2020 19:46:44 -0500 +Subject: [PATCH] Breedable Polar Bears + + +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityPolarBear.java b/src/main/java/net/minecraft/world/entity/animal/EntityPolarBear.java +index 49f26d487229a732902d5bf48d305b0864e90d63..f25f5ced218555af0d62844a78842cfc7599d608 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityPolarBear.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityPolarBear.java +@@ -34,6 +34,7 @@ import net.minecraft.world.entity.GroupDataEntity; + import net.minecraft.world.entity.IEntityAngerable; + import net.minecraft.world.entity.ai.attributes.AttributeProvider; + import net.minecraft.world.entity.ai.attributes.GenericAttributes; ++import net.minecraft.world.entity.ai.goal.PathfinderGoalBreed; + import net.minecraft.world.entity.ai.goal.PathfinderGoalFloat; + import net.minecraft.world.entity.ai.goal.PathfinderGoalFollowParent; + import net.minecraft.world.entity.ai.goal.PathfinderGoalLookAtPlayer; +@@ -41,11 +42,13 @@ import net.minecraft.world.entity.ai.goal.PathfinderGoalMeleeAttack; + import net.minecraft.world.entity.ai.goal.PathfinderGoalPanic; + import net.minecraft.world.entity.ai.goal.PathfinderGoalRandomLookaround; + import net.minecraft.world.entity.ai.goal.PathfinderGoalRandomStroll; ++import net.minecraft.world.entity.ai.goal.PathfinderGoalTempt; + import net.minecraft.world.entity.ai.goal.target.PathfinderGoalHurtByTarget; + import net.minecraft.world.entity.ai.goal.target.PathfinderGoalNearestAttackableTarget; + import net.minecraft.world.entity.ai.goal.target.PathfinderGoalUniversalAngerReset; + import net.minecraft.world.entity.player.EntityHuman; + import net.minecraft.world.item.ItemStack; ++import net.minecraft.world.item.crafting.RecipeItemStack; + import net.minecraft.world.level.GeneratorAccess; + import net.minecraft.world.level.World; + import net.minecraft.world.level.WorldAccess; +@@ -68,6 +71,30 @@ public class EntityPolarBear extends EntityAnimal implements IEntityAngerable { + super(entitytypes, world); + } + ++ // Purpur start ++ @Override ++ public boolean mate(EntityAnimal entityanimal) { ++ if (entityanimal == this) { ++ return false; ++ } else if (this.isStanding()) { ++ return false; ++ } else if (this.getGoalTarget() != null) { ++ return false; ++ } else if (!(entityanimal instanceof EntityPolarBear)) { ++ return false; ++ } else { ++ EntityPolarBear polarbear = (EntityPolarBear) entityanimal; ++ if (polarbear.isStanding()) { ++ return false; ++ } ++ if (polarbear.getGoalTarget() != null) { ++ return false; ++ } ++ return this.isInLove() && polarbear.isInLove(); ++ } ++ } ++ // Purpur end ++ + @Override + public EntityAgeable createChild(WorldServer worldserver, EntityAgeable entityageable) { + return (EntityAgeable) EntityTypes.POLAR_BEAR.a((World) worldserver); +@@ -75,7 +102,7 @@ public class EntityPolarBear extends EntityAnimal implements IEntityAngerable { + + @Override + public boolean k(ItemStack itemstack) { +- return false; ++ return world.purpurConfig.polarBearBreedableItem != null && itemstack.getItem() == world.purpurConfig.polarBearBreedableItem; // Purpur; + } + + @Override +@@ -84,6 +111,12 @@ public class EntityPolarBear extends EntityAnimal implements IEntityAngerable { + this.goalSelector.a(0, new PathfinderGoalFloat(this)); + this.goalSelector.a(1, new EntityPolarBear.c()); + this.goalSelector.a(1, new EntityPolarBear.d()); ++ // Purpur start ++ if (world.purpurConfig.polarBearBreedableItem != null) { ++ this.goalSelector.a(2, new PathfinderGoalBreed(this, 1.0D)); ++ this.goalSelector.a(3, new PathfinderGoalTempt(this, 1.0D, RecipeItemStack.a(world.purpurConfig.polarBearBreedableItem), false)); ++ } ++ // Purpur end + this.goalSelector.a(4, new PathfinderGoalFollowParent(this, 1.25D)); + this.goalSelector.a(5, new PathfinderGoalRandomStroll(this, 1.0D)); + this.goalSelector.a(6, new PathfinderGoalLookAtPlayer(this, EntityHuman.class, 6.0F)); +@@ -225,10 +258,12 @@ public class EntityPolarBear extends EntityAnimal implements IEntityAngerable { + return flag; + } + ++ public boolean isStanding() { return eM(); } // Purpur - OBFHELPER + public boolean eM() { + return (Boolean) this.datawatcher.get(EntityPolarBear.bo); + } + ++ public void setStanding(boolean standing) { t(standing); } // Purpur - OBFHELPER + public void t(boolean flag) { + this.datawatcher.set(EntityPolarBear.bo, flag); + } +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 081675005077c5070f7745e24fd2ee7400fe2320..fa43c015976aabaae8843983976c9c939a49016f 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -164,6 +164,14 @@ public class PurpurWorldConfig { + ironGolemCanSwim = getBoolean("mobs.iron_golem.can-swim", ironGolemCanSwim); + } + ++ public String polarBearBreedableItemString = ""; ++ public Item polarBearBreedableItem = null; ++ private void polarBearSettings() { ++ polarBearBreedableItemString = getString("mobs.polar_bear.breedable-item", polarBearBreedableItemString); ++ Item item = IRegistry.ITEM.get(new MinecraftKey(polarBearBreedableItemString)); ++ if (item != Items.AIR) polarBearBreedableItem = item; ++ } ++ + public double rabbitNaturalToast = 0.0D; + public double rabbitNaturalKiller = 0.0D; + private void rabbitSettings() { diff --git a/patches/Purpur/patches/server/0033-Chickens-can-retaliate.patch b/patches/Purpur/patches/server/0033-Chickens-can-retaliate.patch new file mode 100644 index 00000000..3fa2e23d --- /dev/null +++ b/patches/Purpur/patches/server/0033-Chickens-can-retaliate.patch @@ -0,0 +1,83 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sun, 12 Apr 2020 13:19:34 -0500 +Subject: [PATCH] Chickens can retaliate + + +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityChicken.java b/src/main/java/net/minecraft/world/entity/animal/EntityChicken.java +index cd6fb8efb20a2d32de59d479b1dbf5ee69d5df37..600d6ebdf554dbaa8ca46a22a12d8b4e3255d987 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityChicken.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityChicken.java +@@ -20,10 +20,12 @@ import net.minecraft.world.entity.ai.goal.PathfinderGoalBreed; + import net.minecraft.world.entity.ai.goal.PathfinderGoalFloat; + import net.minecraft.world.entity.ai.goal.PathfinderGoalFollowParent; + import net.minecraft.world.entity.ai.goal.PathfinderGoalLookAtPlayer; ++import net.minecraft.world.entity.ai.goal.PathfinderGoalMeleeAttack; + import net.minecraft.world.entity.ai.goal.PathfinderGoalPanic; + import net.minecraft.world.entity.ai.goal.PathfinderGoalRandomLookaround; + import net.minecraft.world.entity.ai.goal.PathfinderGoalRandomStrollLand; + import net.minecraft.world.entity.ai.goal.PathfinderGoalTempt; ++import net.minecraft.world.entity.ai.goal.target.PathfinderGoalHurtByTarget; + import net.minecraft.world.entity.player.EntityHuman; + import net.minecraft.world.item.ItemStack; + import net.minecraft.world.item.Items; +@@ -51,16 +53,33 @@ public class EntityChicken extends EntityAnimal { + this.a(PathType.WATER, 0.0F); + } + ++ // Purpur start ++ @Override ++ protected void initAttributes() { ++ if (world.purpurConfig.chickenRetaliate) { ++ this.getAttributeInstance(GenericAttributes.ATTACK_DAMAGE).setValue(2.0D); ++ } ++ } ++ // Purpur end ++ + @Override + protected void initPathfinder() { + this.goalSelector.a(0, new PathfinderGoalFloat(this)); +- this.goalSelector.a(1, new PathfinderGoalPanic(this, 1.4D)); ++ //this.goalSelector.a(1, new PathfinderGoalPanic(this, 1.4D)); // Purpur - moved down + this.goalSelector.a(2, new PathfinderGoalBreed(this, 1.0D)); + this.goalSelector.a(3, new PathfinderGoalTempt(this, 1.0D, false, EntityChicken.bv)); + this.goalSelector.a(4, new PathfinderGoalFollowParent(this, 1.1D)); + this.goalSelector.a(5, new PathfinderGoalRandomStrollLand(this, 1.0D)); + this.goalSelector.a(6, new PathfinderGoalLookAtPlayer(this, EntityHuman.class, 6.0F)); + this.goalSelector.a(7, new PathfinderGoalRandomLookaround(this)); ++ // Purpur start ++ if (world.purpurConfig.chickenRetaliate) { ++ this.goalSelector.a(1, new PathfinderGoalMeleeAttack(this, 1.0D, false)); ++ this.targetSelector.a(1, new PathfinderGoalHurtByTarget(this)); ++ } else { ++ this.goalSelector.a(1, new PathfinderGoalPanic(this, 1.4D)); ++ } ++ // Purpur end + } + + @Override +@@ -69,7 +88,7 @@ public class EntityChicken extends EntityAnimal { + } + + public static AttributeProvider.Builder eK() { +- return EntityInsentient.p().a(GenericAttributes.MAX_HEALTH, 4.0D).a(GenericAttributes.MOVEMENT_SPEED, 0.25D); ++ return EntityInsentient.p().a(GenericAttributes.MAX_HEALTH, 4.0D).a(GenericAttributes.MOVEMENT_SPEED, 0.25D).a(GenericAttributes.ATTACK_DAMAGE, 0.0D); // Purpur + } + + @Override +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index fa43c015976aabaae8843983976c9c939a49016f..78218f2d59203b8f2b286fd09b3f6bdebb47565c 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -113,6 +113,11 @@ public class PurpurWorldConfig { + turtleEggsBreakFromMinecarts = getBoolean("blocks.turtle_egg.break-from-minecarts", turtleEggsBreakFromMinecarts); + } + ++ public boolean chickenRetaliate = false; ++ private void chickenSettings() { ++ chickenRetaliate = getBoolean("mobs.chicken.retaliate", chickenRetaliate); ++ } ++ + public double creeperChargedChance = 0.0D; + private void creeperSettings() { + creeperChargedChance = getDouble("mobs.creeper.naturally-charged-chance", creeperChargedChance); diff --git a/patches/Purpur/patches/server/0034-Add-option-to-set-armorstand-step-height.patch b/patches/Purpur/patches/server/0034-Add-option-to-set-armorstand-step-height.patch new file mode 100644 index 00000000..0a3d1916 --- /dev/null +++ b/patches/Purpur/patches/server/0034-Add-option-to-set-armorstand-step-height.patch @@ -0,0 +1,34 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sun, 6 Oct 2019 12:46:35 -0500 +Subject: [PATCH] Add option to set armorstand step height + + +diff --git a/src/main/java/net/minecraft/world/entity/decoration/EntityArmorStand.java b/src/main/java/net/minecraft/world/entity/decoration/EntityArmorStand.java +index c0e0750adef0ae6aff7635c84f6585f06c5fc38d..89d3734489b65245e815376edf4e2d9baea1563a 100644 +--- a/src/main/java/net/minecraft/world/entity/decoration/EntityArmorStand.java ++++ b/src/main/java/net/minecraft/world/entity/decoration/EntityArmorStand.java +@@ -660,6 +660,7 @@ public class EntityArmorStand extends EntityLiving { + + @Override + public void tick() { ++ setStepHeight(world.purpurConfig.armorstandStepHeight); // Purpur + // Paper start + if (!this.canTick) { + if (this.noTickPoseDirty) { +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 78218f2d59203b8f2b286fd09b3f6bdebb47565c..90f367f2f04f9bf66b7f54ffe784db16c7ca868b 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -63,6 +63,11 @@ public class PurpurWorldConfig { + return PurpurConfig.config.getString("world-settings." + worldName + "." + path, PurpurConfig.config.getString("world-settings.default." + path)); + } + ++ public float armorstandStepHeight = 0.0F; ++ private void armorstandSettings() { ++ armorstandStepHeight = (float) getDouble("gameplay-mechanics.armorstand.step-height", armorstandStepHeight); ++ } ++ + public boolean idleTimeoutKick = true; + public boolean idleTimeoutTickNearbyEntities = true; + public boolean idleTimeoutCountAsSleeping = false; diff --git a/patches/Purpur/patches/server/0035-Cat-spawning-options.patch b/patches/Purpur/patches/server/0035-Cat-spawning-options.patch new file mode 100644 index 00000000..5ba975a9 --- /dev/null +++ b/patches/Purpur/patches/server/0035-Cat-spawning-options.patch @@ -0,0 +1,116 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Thu, 26 Dec 2019 18:52:55 -0600 +Subject: [PATCH] Cat spawning options + + +diff --git a/src/main/java/net/minecraft/world/entity/ai/village/poi/VillagePlace.java b/src/main/java/net/minecraft/world/entity/ai/village/poi/VillagePlace.java +index 13d94ecd703b3cd0412e138532d2dd74e5bf250d..6082eed2d28f3be65daa7e7eb6f2c2a89bb28ff1 100644 +--- a/src/main/java/net/minecraft/world/entity/ai/village/poi/VillagePlace.java ++++ b/src/main/java/net/minecraft/world/entity/ai/village/poi/VillagePlace.java +@@ -191,6 +191,7 @@ public class VillagePlace extends RegionFileSection { + ((VillagePlaceSection) this.e(SectionPosition.a(blockposition).s())).a(blockposition); + } + ++ public long count(Predicate predicate, BlockPosition blockposition, int i, VillagePlace.Occupancy villageplace_occupancy) { return a(predicate, blockposition, i, villageplace_occupancy); } // Purpur - OBFHELPER + public long a(Predicate predicate, BlockPosition blockposition, int i, VillagePlace.Occupancy villageplace_occupancy) { + return this.c(predicate, blockposition, i, villageplace_occupancy).count(); + } +diff --git a/src/main/java/net/minecraft/world/entity/ai/village/poi/VillagePlaceType.java b/src/main/java/net/minecraft/world/entity/ai/village/poi/VillagePlaceType.java +index db1ddce5774754891dc8a3ea5b66951ebc3a07a8..6a45ab049a4beeeaf7b3b5acf2946767f6e1198f 100644 +--- a/src/main/java/net/minecraft/world/entity/ai/village/poi/VillagePlaceType.java ++++ b/src/main/java/net/minecraft/world/entity/ai/village/poi/VillagePlaceType.java +@@ -53,7 +53,7 @@ public class VillagePlaceType { + public static final VillagePlaceType o = a("shepherd", a(Blocks.LOOM), 1, 1); + public static final VillagePlaceType p = a("toolsmith", a(Blocks.SMITHING_TABLE), 1, 1); + public static final VillagePlaceType q = a("weaponsmith", a(Blocks.GRINDSTONE), 1, 1); +- public static final VillagePlaceType r = a("home", VillagePlaceType.z, 1, 1); ++ public static final VillagePlaceType r = a("home", VillagePlaceType.z, 1, 1); public static VillagePlaceType home() { return r; } // Purpur - OBFHELPER + public static final VillagePlaceType s = a("meeting", a(Blocks.BELL), 32, 6); + public static final VillagePlaceType t = a("beehive", a(Blocks.BEEHIVE), 0, 1); + public static final VillagePlaceType u = a("bee_nest", a(Blocks.BEE_NEST), 0, 1); +@@ -92,6 +92,7 @@ public class VillagePlaceType { + return this.D; + } + ++ public Predicate predicate() { return c(); } // Purpur - OBFHELPER + public Predicate c() { + return this.E; + } +diff --git a/src/main/java/net/minecraft/world/entity/npc/MobSpawnerCat.java b/src/main/java/net/minecraft/world/entity/npc/MobSpawnerCat.java +index 7a495cf88d723790ee3f63645cb4792052284f32..2f54c26151c049df9d071c887dd33e48df041437 100644 +--- a/src/main/java/net/minecraft/world/entity/npc/MobSpawnerCat.java ++++ b/src/main/java/net/minecraft/world/entity/npc/MobSpawnerCat.java +@@ -34,7 +34,7 @@ public class MobSpawnerCat implements MobSpawner { + if (this.a > 0) { + return 0; + } else { +- this.a = 1200; ++ this.a = worldserver.purpurConfig.catSpawnDelay; // Purpur; + EntityPlayer entityplayer = worldserver.q_(); + + if (entityplayer == null) { +@@ -68,10 +68,12 @@ public class MobSpawnerCat implements MobSpawner { + } + + private int a(WorldServer worldserver, BlockPosition blockposition) { +- boolean flag = true; +- +- if (worldserver.y().a(VillagePlaceType.r.c(), blockposition, 48, VillagePlace.Occupancy.IS_OCCUPIED) > 4L) { +- List list = worldserver.a(EntityCat.class, (new AxisAlignedBB(blockposition)).grow(48.0D, 8.0D, 48.0D)); ++ // Purpur start ++ int range = worldserver.purpurConfig.catSpawnVillageScanRange; ++ if (range <= 0) return 0; ++ if (worldserver.getPoiStorage().count(VillagePlaceType.home().predicate(), blockposition, range, VillagePlace.Occupancy.IS_OCCUPIED) > 4L) { ++ List list = worldserver.getEntitiesInAABB(EntityCat.class, (new AxisAlignedBB(blockposition)).grow(range, 8.0D, range)); ++ // Purpur end + + if (list.size() < 5) { + return this.a(blockposition, worldserver); +@@ -82,9 +84,11 @@ public class MobSpawnerCat implements MobSpawner { + } + + private int b(WorldServer worldserver, BlockPosition blockposition) { +- boolean flag = true; +- List list = worldserver.a(EntityCat.class, (new AxisAlignedBB(blockposition)).grow(16.0D, 8.0D, 16.0D)); +- ++ // Purpur start ++ int range = worldserver.purpurConfig.catSpawnSwampHutScanRange; ++ if (range <= 0) return 0; ++ List list = worldserver.getEntitiesInAABB(EntityCat.class, (new AxisAlignedBB(blockposition)).grow(range, 8.0D, range)); ++ // Purpur end + return list.size() < 1 ? this.a(blockposition, worldserver) : 0; + } + +diff --git a/src/main/java/net/minecraft/world/level/IEntityAccess.java b/src/main/java/net/minecraft/world/level/IEntityAccess.java +index fd56b2f15e570f266a79c25823a3b3530a693510..18a5d11cce748695c8f03be565d2ea37a276a981 100644 +--- a/src/main/java/net/minecraft/world/level/IEntityAccess.java ++++ b/src/main/java/net/minecraft/world/level/IEntityAccess.java +@@ -56,6 +56,7 @@ public interface IEntityAccess { + } + } + ++ default List getEntitiesInAABB(Class oclass, AxisAlignedBB axisalignedbb) { return a(oclass, axisalignedbb); } // Purpur - OBFHELPER + default List a(Class oclass, AxisAlignedBB axisalignedbb) { + return this.a(oclass, axisalignedbb, IEntitySelector.g); + } +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 90f367f2f04f9bf66b7f54ffe784db16c7ca868b..9e935668147d1cd822f33c9e8d41e9541022aa8a 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -118,6 +118,15 @@ public class PurpurWorldConfig { + turtleEggsBreakFromMinecarts = getBoolean("blocks.turtle_egg.break-from-minecarts", turtleEggsBreakFromMinecarts); + } + ++ public int catSpawnDelay = 1200; ++ public int catSpawnSwampHutScanRange = 16; ++ public int catSpawnVillageScanRange = 48; ++ private void catSettings() { ++ catSpawnDelay = getInt("mobs.cat.spawn-delay", catSpawnDelay); ++ catSpawnSwampHutScanRange = getInt("mobs.cat.scan-range-for-other-cats.swamp-hut", catSpawnSwampHutScanRange); ++ catSpawnVillageScanRange = getInt("mobs.cat.scan-range-for-other-cats.village", catSpawnVillageScanRange); ++ } ++ + public boolean chickenRetaliate = false; + private void chickenSettings() { + chickenRetaliate = getBoolean("mobs.chicken.retaliate", chickenRetaliate); diff --git a/patches/Purpur/patches/server/0036-MC-147659-Fix-non-black-cats-spawning-in-swamp-huts.patch b/patches/Purpur/patches/server/0036-MC-147659-Fix-non-black-cats-spawning-in-swamp-huts.patch new file mode 100644 index 00000000..d57feb8e --- /dev/null +++ b/patches/Purpur/patches/server/0036-MC-147659-Fix-non-black-cats-spawning-in-swamp-huts.patch @@ -0,0 +1,21 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Thu, 2 Jan 2020 01:23:22 -0600 +Subject: [PATCH] MC-147659 - Fix non black cats spawning in swamp huts + + +diff --git a/src/main/java/net/minecraft/world/entity/npc/MobSpawnerCat.java b/src/main/java/net/minecraft/world/entity/npc/MobSpawnerCat.java +index 2f54c26151c049df9d071c887dd33e48df041437..5d0da07970bfe304debe244e5df39981f90161f6 100644 +--- a/src/main/java/net/minecraft/world/entity/npc/MobSpawnerCat.java ++++ b/src/main/java/net/minecraft/world/entity/npc/MobSpawnerCat.java +@@ -98,8 +98,9 @@ public class MobSpawnerCat implements MobSpawner { + if (entitycat == null) { + return 0; + } else { ++ entitycat.setPositionRotation(blockposition, 0.0F, 0.0F); // Purpur + entitycat.prepare(worldserver, worldserver.getDamageScaler(blockposition), EnumMobSpawn.NATURAL, (GroupDataEntity) null, (NBTTagCompound) null); +- entitycat.setPositionRotation(blockposition, 0.0F, 0.0F); ++ //entitycat.setPositionRotation(blockposition, 0.0F, 0.0F); // Purpur - move up - fixes non black cat types spawning inside swamp huts + worldserver.addAllEntities(entitycat); + return 1; + } diff --git a/patches/Purpur/patches/server/0037-Cows-eat-mushrooms.patch b/patches/Purpur/patches/server/0037-Cows-eat-mushrooms.patch new file mode 100644 index 00000000..bafcfc31 --- /dev/null +++ b/patches/Purpur/patches/server/0037-Cows-eat-mushrooms.patch @@ -0,0 +1,156 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sat, 4 May 2019 01:10:30 -0500 +Subject: [PATCH] Cows eat mushrooms + + +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index 611a2c34c80462826564705eb5a079bd6fdda4e1..0f11984743ba49fc6f094c8fa6c563febf0ab7d6 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -2920,6 +2920,7 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, ne + this.invulnerable = flag; + } + ++ public void copyPositionRotation(Entity entity) { this.u(entity); } // Purpur - OBFHELPER + public void u(Entity entity) { + this.setPositionRotation(entity.locX(), entity.locY(), entity.locZ(), entity.yaw, entity.pitch); + } +diff --git a/src/main/java/net/minecraft/world/entity/EntityLiving.java b/src/main/java/net/minecraft/world/entity/EntityLiving.java +index 032b1a519de56583990fe47a216665ce71cf93ab..9d950f5d5d6b9d686bd3bbaa12a8d933fd1e2ec2 100644 +--- a/src/main/java/net/minecraft/world/entity/EntityLiving.java ++++ b/src/main/java/net/minecraft/world/entity/EntityLiving.java +@@ -175,7 +175,7 @@ public abstract class EntityLiving extends Entity { + public int maxNoDamageTicks; + public final float ay; + public final float az; +- public float aA; ++ public float aA; public float getRenderYawOffset() { return this.aA; } public void setRenderYawOffset(float f) { this.aA = f; } // Purpur - OBFHELPER + public float aB; + public float aC; + public float aD; +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityCow.java b/src/main/java/net/minecraft/world/entity/animal/EntityCow.java +index 1b43688ad232620410aa924cef02b54630ab1313..962dde5fcc617bc39b7d06a1e295370b9d60696c 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityCow.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityCow.java +@@ -1,6 +1,7 @@ + package net.minecraft.world.entity.animal; + + import net.minecraft.core.BlockPosition; ++import net.minecraft.core.particles.Particles; + import net.minecraft.server.level.WorldServer; + import net.minecraft.sounds.SoundEffect; + import net.minecraft.sounds.SoundEffects; +@@ -28,6 +29,7 @@ import net.minecraft.world.item.ItemStack; + import net.minecraft.world.item.Items; + import net.minecraft.world.item.crafting.RecipeItemStack; + import net.minecraft.world.level.World; ++import net.minecraft.world.level.block.Blocks; + import net.minecraft.world.level.block.state.IBlockData; + + // CraftBukkit start +@@ -46,6 +48,7 @@ public class EntityCow extends EntityAnimal { + this.goalSelector.a(0, new PathfinderGoalFloat(this)); + this.goalSelector.a(1, new PathfinderGoalPanic(this, 2.0D)); + this.goalSelector.a(2, new PathfinderGoalBreed(this, 1.0D)); ++ if (world.purpurConfig.cowFeedMushrooms > 0) this.goalSelector.a(3, new PathfinderGoalTempt(this, 1.25D, RecipeItemStack.a(Items.WHEAT, Blocks.RED_MUSHROOM.getItem(), Blocks.BROWN_MUSHROOM.getItem()), false)); else // Purpur + this.goalSelector.a(3, new PathfinderGoalTempt(this, 1.25D, RecipeItemStack.a(Items.WHEAT), false)); + this.goalSelector.a(4, new PathfinderGoalFollowParent(this, 1.25D)); + this.goalSelector.a(5, new PathfinderGoalRandomStrollLand(this, 1.0D)); +@@ -100,11 +103,80 @@ public class EntityCow extends EntityAnimal { + + entityhuman.a(enumhand, itemstack1); + return EnumInteractionResult.a(this.world.isClientSide); ++ // Purpur start - feed mushroom to change to mooshroom ++ } else if (world.purpurConfig.cowFeedMushrooms > 0 && getEntityType() != EntityTypes.MOOSHROOM && isMushroom(itemstack)) { ++ return feedMushroom(entityhuman, itemstack); ++ // Purpur end + } else { + return super.b(entityhuman, enumhand); + } + } + ++ // Purpur start - feed mushroom to change to mooshroom ++ private int redMushroomsFed = 0; ++ private int brownMushroomsFed = 0; ++ ++ private boolean isMushroom(ItemStack itemstack) { ++ return itemstack.getItem() == Blocks.RED_MUSHROOM.getItem() || itemstack.getItem() == Blocks.BROWN_MUSHROOM.getItem(); ++ } ++ ++ private int incrementFeedCount(ItemStack itemstack) { ++ if (itemstack.getItem() == Blocks.RED_MUSHROOM.getItem()) { ++ return ++redMushroomsFed; ++ } else { ++ return ++brownMushroomsFed; ++ } ++ } ++ ++ private EnumInteractionResult feedMushroom(EntityHuman entityhuman, ItemStack itemstack) { ++ world.broadcastEntityEffect(this, (byte) 18); // hearts ++ playSound(SoundEffects.ENTITY_COW_MILK, 1.0F, 1.0F); ++ if (incrementFeedCount(itemstack) < world.purpurConfig.cowFeedMushrooms) { ++ if (!entityhuman.abilities.canInstantlyBuild) { ++ itemstack.subtract(1); ++ } ++ return EnumInteractionResult.CONSUME; // require 5 mushrooms to transform (prevents mushroom duping) ++ } ++ EntityMushroomCow mooshroom = EntityTypes.MOOSHROOM.create(world); ++ if (mooshroom == null) { ++ return EnumInteractionResult.PASS; ++ } ++ if (itemstack.getItem() == Blocks.BROWN_MUSHROOM.getItem()) { ++ mooshroom.setVariant(EntityMushroomCow.Type.BROWN); ++ } else { ++ mooshroom.setVariant(EntityMushroomCow.Type.RED); ++ } ++ mooshroom.setPositionRotation(this.locX(), this.locY(), this.locZ(), this.yaw, this.pitch); ++ mooshroom.setHealth(this.getHealth()); ++ mooshroom.setAge(getAge()); ++ mooshroom.copyPositionRotation(this); ++ mooshroom.setRenderYawOffset(this.getRenderYawOffset()); ++ mooshroom.setHeadRotation(this.getHeadRotation()); ++ mooshroom.lastYaw = this.lastYaw; ++ mooshroom.lastPitch = this.lastPitch; ++ if (this.hasCustomName()) { ++ mooshroom.setCustomName(this.getCustomName()); ++ } ++ if (CraftEventFactory.callEntityTransformEvent(this, mooshroom, org.bukkit.event.entity.EntityTransformEvent.TransformReason.INFECTION).isCancelled()) { ++ return EnumInteractionResult.PASS; ++ } ++ if (!new com.destroystokyo.paper.event.entity.EntityTransformedEvent(this.getBukkitEntity(), mooshroom.getBukkitEntity(), com.destroystokyo.paper.event.entity.EntityTransformedEvent.TransformedReason.INFECTED).callEvent()) { ++ return EnumInteractionResult.PASS; ++ } ++ this.world.addEntity(mooshroom); ++ this.die(); ++ if (!entityhuman.abilities.canInstantlyBuild) { ++ itemstack.subtract(1); ++ } ++ for (int i = 0; i < 15; ++i) { ++ ((WorldServer) world).sendParticles(((WorldServer) world).players, null, Particles.HAPPY_VILLAGER, ++ locX() + random.nextFloat(), locY() + (random.nextFloat() * 2), locZ() + random.nextFloat(), 1, ++ random.nextGaussian() * 0.05D, random.nextGaussian() * 0.05D, random.nextGaussian() * 0.05D, 0, true); ++ } ++ return EnumInteractionResult.SUCCESS; ++ } ++ // Purpur end ++ + @Override + public EntityCow createChild(WorldServer worldserver, EntityAgeable entityageable) { + return (EntityCow) EntityTypes.COW.a((World) worldserver); +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 9e935668147d1cd822f33c9e8d41e9541022aa8a..277cc8361e8faf54b95be1e9f1467a97de14ecc4 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -132,6 +132,11 @@ public class PurpurWorldConfig { + chickenRetaliate = getBoolean("mobs.chicken.retaliate", chickenRetaliate); + } + ++ public int cowFeedMushrooms = 0; ++ private void cowSettings() { ++ cowFeedMushrooms = getInt("mobs.cow.feed-mushrooms-for-mooshroom", cowFeedMushrooms); ++ } ++ + public double creeperChargedChance = 0.0D; + private void creeperSettings() { + creeperChargedChance = getDouble("mobs.creeper.naturally-charged-chance", creeperChargedChance); diff --git a/patches/Purpur/patches/server/0038-Fix-cow-rotation-when-shearing-mooshroom.patch b/patches/Purpur/patches/server/0038-Fix-cow-rotation-when-shearing-mooshroom.patch new file mode 100644 index 00000000..6f213940 --- /dev/null +++ b/patches/Purpur/patches/server/0038-Fix-cow-rotation-when-shearing-mooshroom.patch @@ -0,0 +1,25 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Fri, 3 May 2019 23:53:16 -0500 +Subject: [PATCH] Fix cow rotation when shearing mooshroom + + +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityMushroomCow.java b/src/main/java/net/minecraft/world/entity/animal/EntityMushroomCow.java +index 9face4480dcc89d9106ebe596020c1888350ef2d..d28d4d2c1eff2c130f49c2bce3c19da212dba5dc 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityMushroomCow.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityMushroomCow.java +@@ -172,7 +172,13 @@ public class EntityMushroomCow extends EntityCow implements IShearable { + + entitycow.setPositionRotation(this.locX(), this.locY(), this.locZ(), this.yaw, this.pitch); + entitycow.setHealth(this.getHealth()); +- entitycow.aA = this.aA; ++ // Purpur start - correctly copy rotation ++ entitycow.copyPositionRotation(this); ++ entitycow.setRenderYawOffset(this.getRenderYawOffset()); ++ entitycow.setHeadRotation(this.getHeadRotation()); ++ entitycow.lastYaw = this.lastYaw; ++ entitycow.lastPitch = this.lastPitch; ++ // Purpur end + if (this.hasCustomName()) { + entitycow.setCustomName(this.getCustomName()); + entitycow.setCustomNameVisible(this.getCustomNameVisible()); diff --git a/patches/Purpur/patches/server/0039-Pigs-give-saddle-back.patch b/patches/Purpur/patches/server/0039-Pigs-give-saddle-back.patch new file mode 100644 index 00000000..4645c333 --- /dev/null +++ b/patches/Purpur/patches/server/0039-Pigs-give-saddle-back.patch @@ -0,0 +1,45 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sun, 12 May 2019 01:14:46 -0500 +Subject: [PATCH] Pigs give saddle back + + +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityPig.java b/src/main/java/net/minecraft/world/entity/animal/EntityPig.java +index 676ca381a5e111fc15f319e73504e4e60dbf0d2b..1a540e41e6161d011ca4ed30c68ae9df4567b8db 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityPig.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityPig.java +@@ -156,6 +156,18 @@ public class EntityPig extends EntityAnimal implements ISteerable, ISaddleable { + + if (!flag && this.hasSaddle() && !this.isVehicle() && !entityhuman.eq()) { + if (!this.world.isClientSide) { ++ // Purpur start ++ if (world.purpurConfig.pigGiveSaddleBack && entityhuman.isSneaking()) { ++ this.saddleStorage.setSaddle(false); ++ if (!entityhuman.abilities.canInstantlyBuild) { ++ ItemStack saddle = new ItemStack(Items.SADDLE); ++ if (!entityhuman.inventory.pickup(saddle)) { ++ entityhuman.drop(saddle, false); ++ } ++ } ++ return EnumInteractionResult.SUCCESS; ++ } ++ // Purpur end + entityhuman.startRiding(this); + } + +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 277cc8361e8faf54b95be1e9f1467a97de14ecc4..5ac1aba522151c42255caf9d29c5b780218ccd32 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -188,6 +188,11 @@ public class PurpurWorldConfig { + ironGolemCanSwim = getBoolean("mobs.iron_golem.can-swim", ironGolemCanSwim); + } + ++ public boolean pigGiveSaddleBack = false; ++ private void pigSettings() { ++ pigGiveSaddleBack = getBoolean("mobs.pig.give-saddle-back", pigGiveSaddleBack); ++ } ++ + public String polarBearBreedableItemString = ""; + public Item polarBearBreedableItem = null; + private void polarBearSettings() { diff --git a/patches/Purpur/patches/server/0040-Snowman-drop-and-put-back-pumpkin.patch b/patches/Purpur/patches/server/0040-Snowman-drop-and-put-back-pumpkin.patch new file mode 100644 index 00000000..42df6eae --- /dev/null +++ b/patches/Purpur/patches/server/0040-Snowman-drop-and-put-back-pumpkin.patch @@ -0,0 +1,51 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Fri, 3 May 2019 23:58:44 -0500 +Subject: [PATCH] Snowman drop and put back pumpkin + + +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntitySnowman.java b/src/main/java/net/minecraft/world/entity/animal/EntitySnowman.java +index b1e2892c7c9f0e35f69332e93917593d97c304a8..44119f52a4f169ffcea53fb69393bfedfd1a62a7 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntitySnowman.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntitySnowman.java +@@ -160,6 +160,14 @@ public class EntitySnowman extends EntityGolem implements IShearable, IRangedEnt + } + + return EnumInteractionResult.a(this.world.isClientSide); ++ // Purpur start ++ } else if (world.purpurConfig.snowGolemPutPumpkinBack && !hasPumpkin() && itemstack.getItem() == Blocks.CARVED_PUMPKIN.getItem()) { ++ setHasPumpkin(true); ++ if (!entityhuman.abilities.canInstantlyBuild) { ++ itemstack.subtract(1); ++ } ++ return EnumInteractionResult.SUCCESS; ++ // Purpur end + } else { + return EnumInteractionResult.PASS; + } +@@ -170,6 +178,7 @@ public class EntitySnowman extends EntityGolem implements IShearable, IRangedEnt + this.world.playSound((EntityHuman) null, (Entity) this, SoundEffects.ENTITY_SNOW_GOLEM_SHEAR, soundcategory, 1.0F, 1.0F); + if (!this.world.s_()) { + this.setHasPumpkin(false); ++ if (world.purpurConfig.snowGolemDropsPumpkin) // Purpur + this.a(new ItemStack(Items.dj), 1.7F); + } + +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 5ac1aba522151c42255caf9d29c5b780218ccd32..fa01ef3c0cc723acaaf348066cddf91f1deb3c72 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -208,6 +208,13 @@ public class PurpurWorldConfig { + rabbitNaturalKiller = getDouble("mobs.rabbit.spawn-killer-rabbit-chance", rabbitNaturalKiller); + } + ++ public boolean snowGolemDropsPumpkin = true; ++ public boolean snowGolemPutPumpkinBack = false; ++ private void snowGolemSettings() { ++ snowGolemDropsPumpkin = getBoolean("mobs.snow_golem.drop-pumpkin-when-sheared", snowGolemDropsPumpkin); ++ snowGolemPutPumpkinBack = getBoolean("mobs.snow_golem.pumpkin-can-be-added-back", snowGolemPutPumpkinBack); ++ } ++ + public int villagerBrainTicks = 1; + public boolean villagerUseBrainTicksOnlyWhenLagging = true; + private void villagerSettings() { diff --git a/patches/Purpur/patches/server/0041-Ender-dragon-always-drop-full-exp.patch b/patches/Purpur/patches/server/0041-Ender-dragon-always-drop-full-exp.patch new file mode 100644 index 00000000..9dd6fd48 --- /dev/null +++ b/patches/Purpur/patches/server/0041-Ender-dragon-always-drop-full-exp.patch @@ -0,0 +1,35 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sat, 24 Aug 2019 14:42:54 -0500 +Subject: [PATCH] Ender dragon always drop full exp + + +diff --git a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EntityEnderDragon.java b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EntityEnderDragon.java +index 07160de8725787551df327c0790b2d6e0876524f..3fff101637708a1a12f9a457bd3512ae94a8f884 100644 +--- a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EntityEnderDragon.java ++++ b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EntityEnderDragon.java +@@ -613,7 +613,7 @@ public class EntityEnderDragon extends EntityInsentient implements IMonster { + boolean flag = this.world.getGameRules().getBoolean(GameRules.DO_MOB_LOOT); + short short0 = 500; + +- if (this.bF != null && !this.bF.isPreviouslyKilled()) { ++ if (getEnderDragonBattle() != null && (world.purpurConfig.enderDragonAlwaysDropsFullExp || !getEnderDragonBattle().isPreviouslyKilled())) { // Purpur + short0 = 12000; + } + +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index fa01ef3c0cc723acaaf348066cddf91f1deb3c72..bab91f0416f31a8273593bb7725658674eb41621 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -142,6 +142,11 @@ public class PurpurWorldConfig { + creeperChargedChance = getDouble("mobs.creeper.naturally-charged-chance", creeperChargedChance); + } + ++ public boolean enderDragonAlwaysDropsFullExp = false; ++ private void enderDragonSettings() { ++ enderDragonAlwaysDropsFullExp = getBoolean("mobs.ender_dragon.always-drop-full-exp", enderDragonAlwaysDropsFullExp); ++ } ++ + public boolean foxTypeChangesWithTulips = false; + private void foxSettings() { + foxTypeChangesWithTulips = getBoolean("mobs.fox.tulips-change-type", foxTypeChangesWithTulips); diff --git a/patches/Purpur/patches/server/0042-Signs-editable-on-right-click.patch b/patches/Purpur/patches/server/0042-Signs-editable-on-right-click.patch new file mode 100644 index 00000000..706c4e9a --- /dev/null +++ b/patches/Purpur/patches/server/0042-Signs-editable-on-right-click.patch @@ -0,0 +1,64 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Fri, 24 May 2019 02:39:25 -0500 +Subject: [PATCH] Signs editable on right click + + +diff --git a/src/main/java/net/minecraft/world/level/block/BlockSign.java b/src/main/java/net/minecraft/world/level/block/BlockSign.java +index 6b461080439dd9ce5b8d34b79d446558bbd5c1f1..19f4403b9f1142c71e7b2c7c0fd5a78027d4ffe4 100644 +--- a/src/main/java/net/minecraft/world/level/block/BlockSign.java ++++ b/src/main/java/net/minecraft/world/level/block/BlockSign.java +@@ -6,6 +6,7 @@ import net.minecraft.world.EnumHand; + import net.minecraft.world.EnumInteractionResult; + import net.minecraft.world.entity.player.EntityHuman; + import net.minecraft.world.item.ItemDye; ++import net.minecraft.world.item.ItemSign; + import net.minecraft.world.item.ItemStack; + import net.minecraft.world.level.GeneratorAccess; + import net.minecraft.world.level.IBlockAccess; +@@ -80,6 +81,17 @@ public abstract class BlockSign extends BlockTileEntity implements IBlockWaterlo + } + } + ++ // Purpur start - right click to open sign editor ++ if (world.purpurConfig.signRightClickEdit && itemstack.getItem() instanceof ItemSign && ++ !entityhuman.isSneaking() && entityhuman.abilities.mayBuild && ++ entityhuman.getBukkitEntity().hasPermission("purpur.sign.edit")) { ++ tileentitysign.isEditable = true; ++ tileentitysign.a(entityhuman); ++ entityhuman.openSign(tileentitysign); ++ return EnumInteractionResult.SUCCESS; ++ } ++ // Purpur end ++ + return tileentitysign.b(entityhuman) ? EnumInteractionResult.SUCCESS : EnumInteractionResult.PASS; + } else { + return EnumInteractionResult.PASS; +diff --git a/src/main/java/net/minecraft/world/level/block/entity/TileEntitySign.java b/src/main/java/net/minecraft/world/level/block/entity/TileEntitySign.java +index 7f78f388584899b13ff983f0dc37c679bfb1507e..96d0524482281f8570464962c0fd5319199440d7 100644 +--- a/src/main/java/net/minecraft/world/level/block/entity/TileEntitySign.java ++++ b/src/main/java/net/minecraft/world/level/block/entity/TileEntitySign.java +@@ -132,6 +132,7 @@ public class TileEntitySign extends TileEntity implements ICommandListener { // + return this.isEditable; + } + ++ public void setEditor(EntityHuman entityhuman) { a(entityhuman); } // Purpur - OBFHELPER + public void a(EntityHuman entityhuman) { + // Paper start + //this.c = entityhuman; +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index bab91f0416f31a8273593bb7725658674eb41621..ea95a4116371d58eb36be51093af7f0fa28e3dfd 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -109,6 +109,11 @@ public class PurpurWorldConfig { + }); + } + ++ public boolean signRightClickEdit = false; ++ private void signSettings() { ++ signRightClickEdit = getBoolean("blocks.sign.right-click-edit", signRightClickEdit); ++ } ++ + public boolean turtleEggsBreakFromExpOrbs = true; + public boolean turtleEggsBreakFromItems = true; + public boolean turtleEggsBreakFromMinecarts = true; diff --git a/patches/Purpur/patches/server/0043-Signs-allow-color-codes.patch b/patches/Purpur/patches/server/0043-Signs-allow-color-codes.patch new file mode 100644 index 00000000..21db1113 --- /dev/null +++ b/patches/Purpur/patches/server/0043-Signs-allow-color-codes.patch @@ -0,0 +1,84 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Thu, 6 Jun 2019 17:40:30 -0500 +Subject: [PATCH] Signs allow color codes + + +diff --git a/src/main/java/net/minecraft/server/level/EntityPlayer.java b/src/main/java/net/minecraft/server/level/EntityPlayer.java +index 79ff69f9e2dc92ffb4880cf1e059cd1d6a7bdc8a..1ce550ecae370e9e5247d653b259436592b072ab 100644 +--- a/src/main/java/net/minecraft/server/level/EntityPlayer.java ++++ b/src/main/java/net/minecraft/server/level/EntityPlayer.java +@@ -1604,6 +1604,7 @@ public class EntityPlayer extends EntityHuman implements ICrafting { + + @Override + public void openSign(TileEntitySign tileentitysign) { ++ if (world.purpurConfig.signAllowColors) this.playerConnection.sendPacket(tileentitysign.getTranslatedUpdatePacket()); // Purpur + tileentitysign.a((EntityHuman) this); + this.playerConnection.sendPacket(new PacketPlayOutOpenSignEditor(tileentitysign.getPosition())); + } +diff --git a/src/main/java/net/minecraft/server/network/PlayerConnection.java b/src/main/java/net/minecraft/server/network/PlayerConnection.java +index 8856ee8e0e7a3efda7921c0c8df9a2eb4213b1ce..e8a9c8a7fc4089e48e09afc1638cf1ccde7b0fab 100644 +--- a/src/main/java/net/minecraft/server/network/PlayerConnection.java ++++ b/src/main/java/net/minecraft/server/network/PlayerConnection.java +@@ -3087,6 +3087,15 @@ public class PlayerConnection implements PacketListenerPlayIn { + } + } + // Paper end ++ // Purpur start ++ if (worldserver.purpurConfig.signAllowColors) { ++ final org.bukkit.entity.Player bukkitPlayer = player.getBukkitEntity(); ++ if (bukkitPlayer.hasPermission("purpur.sign.color")) currentLine = currentLine.replaceAll("(?i)&([0-9a-fr])", "\u00a7$1"); ++ if (bukkitPlayer.hasPermission("purpur.sign.style")) currentLine = currentLine.replaceAll("(?i)&([l-or])", "\u00a7$1"); ++ if (bukkitPlayer.hasPermission("purpur.sign.magic")) currentLine = currentLine.replaceAll("(?i)&([kr])", "\u00a7$1"); ++ lines.add(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(currentLine)); ++ } else ++ // Purpur end + lines.add(net.kyori.adventure.text.Component.text(SharedConstants.filterAllowedChatCharacters(currentLine))); // Paper - Replaced with anvil color stripping method to stop exploits that allow colored signs to be created. + } + SignChangeEvent event = new SignChangeEvent(org.bukkit.craftbukkit.block.CraftBlock.at(worldserver, blockposition), this.getPlayer(), lines); +diff --git a/src/main/java/net/minecraft/world/level/block/entity/TileEntitySign.java b/src/main/java/net/minecraft/world/level/block/entity/TileEntitySign.java +index 96d0524482281f8570464962c0fd5319199440d7..a87a2fa507dc3bd6d9979db5868e7ef6ea1eddbd 100644 +--- a/src/main/java/net/minecraft/world/level/block/entity/TileEntitySign.java ++++ b/src/main/java/net/minecraft/world/level/block/entity/TileEntitySign.java +@@ -1,6 +1,7 @@ + package net.minecraft.world.level.block.entity; + + import com.mojang.brigadier.exceptions.CommandSyntaxException; ++import io.papermc.paper.adventure.PaperAdventure; // Purpur + import javax.annotation.Nullable; + import net.minecraft.commands.CommandListenerWrapper; + import net.minecraft.commands.ICommandListener; +@@ -112,6 +113,18 @@ public class TileEntitySign extends TileEntity implements ICommandListener { // + this.g[i] = null; + } + ++ // Purpur start ++ public PacketPlayOutTileEntityData getTranslatedUpdatePacket() { ++ NBTTagCompound nbt = save(new NBTTagCompound()); ++ for (int i = 0; i < 4; ++i) { ++ String line = PaperAdventure.LEGACY_AMPERSAND.serialize(PaperAdventure.asAdventure(lines[i])); ++ nbt.setString("Text" + (i + 1), net.kyori.adventure.text.serializer.gson.GsonComponentSerializer.gson().serialize(net.kyori.adventure.text.Component.text(line))); ++ } ++ nbt.setString("PurpurEditor", "true"); ++ return new PacketPlayOutTileEntityData(position, 9, nbt); ++ } ++ // Purpur end ++ + @Nullable + @Override + public PacketPlayOutTileEntityData getUpdatePacket() { +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index ea95a4116371d58eb36be51093af7f0fa28e3dfd..b67f87f38d0ff99ff62d2103ecc737317a435102 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -109,8 +109,10 @@ public class PurpurWorldConfig { + }); + } + ++ public boolean signAllowColors = false; + public boolean signRightClickEdit = false; + private void signSettings() { ++ signAllowColors = getBoolean("blocks.sign.allow-colors", signAllowColors); + signRightClickEdit = getBoolean("blocks.sign.right-click-edit", signRightClickEdit); + } + diff --git a/patches/Purpur/patches/server/0044-Allow-soil-to-moisten-from-water-directly-under-it.patch b/patches/Purpur/patches/server/0044-Allow-soil-to-moisten-from-water-directly-under-it.patch new file mode 100644 index 00000000..73f44531 --- /dev/null +++ b/patches/Purpur/patches/server/0044-Allow-soil-to-moisten-from-water-directly-under-it.patch @@ -0,0 +1,35 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Fri, 21 Jun 2019 14:37:10 -0500 +Subject: [PATCH] Allow soil to moisten from water directly under it + + +diff --git a/src/main/java/net/minecraft/world/level/block/BlockSoil.java b/src/main/java/net/minecraft/world/level/block/BlockSoil.java +index ac830ea21e639652908fe82a253853b26b412e4d..50cf0f3a67a32fe221afaee095189de87135f355 100644 +--- a/src/main/java/net/minecraft/world/level/block/BlockSoil.java ++++ b/src/main/java/net/minecraft/world/level/block/BlockSoil.java +@@ -159,7 +159,7 @@ public class BlockSoil extends Block { + } + } + +- return false; ++ return ((WorldServer) iworldreader).purpurConfig.farmlandGetsMoistFromBelow && iworldreader.getFluid(blockposition.shift(EnumDirection.DOWN)).isTagged(TagsFluid.WATER); // Purpur + // Tuinity end - remove abstract block iteration + } + +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index b67f87f38d0ff99ff62d2103ecc737317a435102..2e4a928a3e88fb3d961d9530695cd7154321c79b 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -109,6 +109,11 @@ public class PurpurWorldConfig { + }); + } + ++ public boolean farmlandGetsMoistFromBelow = false; ++ private void farmlandSettings() { ++ farmlandGetsMoistFromBelow = getBoolean("blocks.farmland.gets-moist-from-below", farmlandGetsMoistFromBelow); ++ } ++ + public boolean signAllowColors = false; + public boolean signRightClickEdit = false; + private void signSettings() { diff --git a/patches/Purpur/patches/server/0045-Minecart-settings-and-WASD-controls.patch b/patches/Purpur/patches/server/0045-Minecart-settings-and-WASD-controls.patch new file mode 100644 index 00000000..1d04085b --- /dev/null +++ b/patches/Purpur/patches/server/0045-Minecart-settings-and-WASD-controls.patch @@ -0,0 +1,275 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sat, 29 Jun 2019 02:32:40 -0500 +Subject: [PATCH] Minecart settings and WASD controls + + +diff --git a/src/main/java/net/minecraft/core/BlockPosition.java b/src/main/java/net/minecraft/core/BlockPosition.java +index 6a6381e85fef2ae2b9b5e6dff0b7917b92fa01e5..17d63cd4ca152adc66ffe9ffd3227a0770738a29 100644 +--- a/src/main/java/net/minecraft/core/BlockPosition.java ++++ b/src/main/java/net/minecraft/core/BlockPosition.java +@@ -42,6 +42,12 @@ public class BlockPosition extends BaseBlockPosition { + private static final int m = 38; + // Paper end + ++ // Purpur start ++ public BlockPosition(net.minecraft.world.entity.Entity entity) { ++ super(entity.locX(), entity.locY(), entity.locZ()); ++ } ++ // Purpur end ++ + public BlockPosition(int i, int j, int k) { + super(i, j, k); + } +diff --git a/src/main/java/net/minecraft/server/level/EntityPlayer.java b/src/main/java/net/minecraft/server/level/EntityPlayer.java +index 1ce550ecae370e9e5247d653b259436592b072ab..9746ade740ab36e68f24e0ee09d24e23f9e6a68f 100644 +--- a/src/main/java/net/minecraft/server/level/EntityPlayer.java ++++ b/src/main/java/net/minecraft/server/level/EntityPlayer.java +@@ -1142,6 +1142,7 @@ public class EntityPlayer extends EntityHuman implements ICrafting { + if (this.isInvulnerable(damagesource)) { + return false; + } else { ++ if (damagesource == DamageSource.FALL && getRootVehicle() instanceof net.minecraft.world.entity.vehicle.EntityMinecartAbstract && world.purpurConfig.minecartControllable && !world.purpurConfig.minecartControllableFallDamage) return false; // Purpur + boolean flag = this.server.j() && this.canPvP() && "fall".equals(damagesource.translationIndex); + + if (!flag && isSpawnInvulnerable() && damagesource != DamageSource.OUT_OF_WORLD) { // Purpur +diff --git a/src/main/java/net/minecraft/world/entity/EntityLiving.java b/src/main/java/net/minecraft/world/entity/EntityLiving.java +index 9d950f5d5d6b9d686bd3bbaa12a8d933fd1e2ec2..f940a5460fe443bb97f23f29cff12827adb2eca4 100644 +--- a/src/main/java/net/minecraft/world/entity/EntityLiving.java ++++ b/src/main/java/net/minecraft/world/entity/EntityLiving.java +@@ -193,9 +193,9 @@ public abstract class EntityLiving extends Entity { + protected int aO;protected int getKillCount() { return this.aO; } // Paper - OBFHELPER + public float lastDamage; + public boolean jumping; // Paper protected -> public +- public float aR; +- public float aS; +- public float aT; ++ public float aR; public float getStrafe() { return aR; } public void setStrafe(float strafe) { aR = strafe; } // Purpur - OBFHELPER ++ public float aS; public float getVertical() { return aS; } public void setVertical(float vertical) { aS = vertical; } // Purpur - OBFHELPER ++ public float aT; public float getForward() { return aT; } public void setForward(float forward) { aT = forward; } // Purpur - OBFHELPER + protected int aU; + protected double aV; + protected double aW; +diff --git a/src/main/java/net/minecraft/world/entity/vehicle/EntityMinecartAbstract.java b/src/main/java/net/minecraft/world/entity/vehicle/EntityMinecartAbstract.java +index 75a88ab5d5b0fdb98ea8d61bb6b82049b21101f3..7b49544210d087f5006a83c2a0d5c47c785c567f 100644 +--- a/src/main/java/net/minecraft/world/entity/vehicle/EntityMinecartAbstract.java ++++ b/src/main/java/net/minecraft/world/entity/vehicle/EntityMinecartAbstract.java +@@ -105,11 +105,13 @@ public abstract class EntityMinecartAbstract extends Entity { + private double flyingY = 0.949999988079071D; // Paper - restore vanilla precision + private double flyingZ = 0.949999988079071D; // Paper - restore vanilla precision + public double maxSpeed = 0.4D; ++ public double storedMaxSpeed; // Purpur + // CraftBukkit end + + protected EntityMinecartAbstract(EntityTypes entitytypes, World world) { + super(entitytypes, world); + this.i = true; ++ if (world != null) maxSpeed = storedMaxSpeed = world.purpurConfig.minecartMaxSpeed; // Purpur + } + + protected EntityMinecartAbstract(EntityTypes entitytypes, World world, double d0, double d1, double d2) { +@@ -315,6 +317,12 @@ public abstract class EntityMinecartAbstract extends Entity { + + @Override + public void tick() { ++ // Purpur start ++ if (storedMaxSpeed != world.purpurConfig.minecartMaxSpeed) { ++ maxSpeed = storedMaxSpeed = world.purpurConfig.minecartMaxSpeed; ++ } ++ // Purpur end ++ + // CraftBukkit start + double prevX = this.locX(); + double prevY = this.locY(); +@@ -484,16 +492,62 @@ public abstract class EntityMinecartAbstract extends Entity { + + public void a(int i, int j, int k, boolean flag) {} + ++ // Purpur start ++ private Double lastSpeed; ++ ++ public double getControllableSpeed() { ++ BlockPosition position = new BlockPosition(this); ++ Block block = world.getType(position).getBlock(); ++ if (!block.getMaterial().isSolid()) { ++ block = world.getType(position.shift(EnumDirection.DOWN)).getBlock(); ++ } ++ Double speed = world.purpurConfig.minecartControllableBlockSpeeds.get(block); ++ if (!block.getMaterial().isSolid()) { ++ speed = lastSpeed; ++ } else if (speed == null) { ++ speed = world.purpurConfig.minecartControllableBaseSpeed; ++ } ++ return lastSpeed = speed; ++ } ++ // Purpur end ++ + protected void h() { + double d0 = this.getMaxSpeed(); + Vec3D vec3d = this.getMot(); + + this.setMot(MathHelper.a(vec3d.x, -d0, d0), vec3d.y, MathHelper.a(vec3d.z, -d0, d0)); ++ ++ // Purpur start ++ if (world.purpurConfig.minecartControllable && !isInWater() && !isInLava() && !passengers.isEmpty()) { ++ Entity passenger = passengers.get(0); ++ if (passenger instanceof EntityHuman) { ++ EntityHuman entityhuman = (EntityHuman) passenger; ++ if (entityhuman.jumping && this.onGround) { ++ setMot(new Vec3D(getMot().x, world.purpurConfig.minecartControllableHopBoost, getMot().z)); ++ } ++ if (entityhuman.getForward() != 0.0F) { ++ Vector velocity = entityhuman.getBukkitEntity().getEyeLocation().getDirection().normalize().multiply(getControllableSpeed()); ++ if (entityhuman.getForward() < 0.0) { ++ velocity.multiply(-0.5); ++ } ++ setMot(new Vec3D(velocity.getX(), getMot().y, velocity.getZ())); ++ } ++ this.yaw = passenger.yaw - 90; ++ setStepHeight(world.purpurConfig.minecartControllableStepHeight); ++ } else { ++ setStepHeight(0.0F); ++ } ++ } else { ++ setStepHeight(0.0F); ++ } ++ // Purpur end ++ + if (this.onGround) { + // CraftBukkit start - replace magic numbers with our variables + this.setMot(new Vec3D(this.getMot().x * this.derailedX, this.getMot().y * this.derailedY, this.getMot().z * this.derailedZ)); + // CraftBukkit end + } ++ else if (world.purpurConfig.minecartControllable) setMot(new Vec3D(getMot().x * derailedX, getMot().y, getMot().z * derailedZ)); // Purpur + + this.move(EnumMoveType.SELF, this.getMot()); + if (!this.onGround) { +diff --git a/src/main/java/net/minecraft/world/item/ItemMinecart.java b/src/main/java/net/minecraft/world/item/ItemMinecart.java +index 527f3ed664854cdd938c34f00a064bc2f77148cc..1a1de9491a50e9e746e714fcb35633c22674f042 100644 +--- a/src/main/java/net/minecraft/world/item/ItemMinecart.java ++++ b/src/main/java/net/minecraft/world/item/ItemMinecart.java +@@ -121,8 +121,10 @@ public class ItemMinecart extends Item { + IBlockData iblockdata = world.getType(blockposition); + + if (!iblockdata.a((Tag) TagsBlock.RAILS)) { +- return EnumInteractionResult.FAIL; +- } else { ++ // Purpur start - place minecarts anywhere ++ if (!world.purpurConfig.minecartPlaceAnywhere) return EnumInteractionResult.FAIL; ++ if (iblockdata.getMaterial().isSolid()) blockposition = blockposition.shift(itemactioncontext.getClickedFace()); ++ } //else { // Purpur end - place minecarts anywhere + ItemStack itemstack = itemactioncontext.getItemStack(); + + if (!world.isClientSide) { +@@ -149,6 +151,6 @@ public class ItemMinecart extends Item { + + itemstack.subtract(1); + return EnumInteractionResult.a(world.isClientSide); +- } ++ //} // Purpur - place minecarts anywhere + } + } +diff --git a/src/main/java/net/minecraft/world/level/block/Block.java b/src/main/java/net/minecraft/world/level/block/Block.java +index 7279893d599351785652279c8827fe0efbd72f12..cfdc602947548970b3fde00dd9fddf4e82c28841 100644 +--- a/src/main/java/net/minecraft/world/level/block/Block.java ++++ b/src/main/java/net/minecraft/world/level/block/Block.java +@@ -83,6 +83,7 @@ public class Block extends BlockBase implements IMaterial { + return timing; + } + // Paper end ++ public net.minecraft.world.level.material.Material getMaterial() { return material; } // Purpur - OBFHELPER + @Nullable + private String name; + @Nullable +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 2e4a928a3e88fb3d961d9530695cd7154321c79b..ee4b36f1aad78bcd7e9cc45acb4ca5b957d0d5c5 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -1,13 +1,18 @@ + package net.pl3x.purpur; + + import net.minecraft.core.IRegistry; ++import net.minecraft.world.level.block.Block; ++import net.minecraft.world.level.block.Blocks; + import net.minecraft.world.item.Item; + import net.minecraft.world.item.Items; + import net.minecraft.resources.MinecraftKey; + import org.bukkit.configuration.ConfigurationSection; + + import java.util.ArrayList; ++import java.util.HashMap; + import java.util.List; ++import java.util.Map; ++ + import static net.pl3x.purpur.PurpurConfig.log; + + public class PurpurWorldConfig { +@@ -68,6 +73,68 @@ public class PurpurWorldConfig { + armorstandStepHeight = (float) getDouble("gameplay-mechanics.armorstand.step-height", armorstandStepHeight); + } + ++ public double minecartMaxSpeed = 0.4D; ++ public boolean minecartPlaceAnywhere = false; ++ public boolean minecartControllable = false; ++ public float minecartControllableStepHeight = 1.0F; ++ public double minecartControllableHopBoost = 0.5D; ++ public boolean minecartControllableFallDamage = true; ++ public double minecartControllableBaseSpeed = 0.1D; ++ public Map minecartControllableBlockSpeeds = new HashMap<>(); ++ private void minecartSettings() { ++ if (PurpurConfig.version < 12) { ++ boolean oldBool = getBoolean("gameplay-mechanics.controllable-minecarts.place-anywhere", minecartPlaceAnywhere); ++ set("gameplay-mechanics.controllable-minecarts.place-anywhere", null); ++ set("gameplay-mechanics.minecart.place-anywhere", oldBool); ++ oldBool = getBoolean("gameplay-mechanics.controllable-minecarts.enabled", minecartControllable); ++ set("gameplay-mechanics.controllable-minecarts.enabled", null); ++ set("gameplay-mechanics.minecart.controllable.enabled", oldBool); ++ double oldDouble = getDouble("gameplay-mechanics.controllable-minecarts.step-height", minecartControllableStepHeight); ++ set("gameplay-mechanics.controllable-minecarts.step-height", null); ++ set("gameplay-mechanics.minecart.controllable.step-height", oldDouble); ++ oldDouble = getDouble("gameplay-mechanics.controllable-minecarts.hop-boost", minecartControllableHopBoost); ++ set("gameplay-mechanics.controllable-minecarts.hop-boost", null); ++ set("gameplay-mechanics.minecart.controllable.hop-boost", oldDouble); ++ oldBool = getBoolean("gameplay-mechanics.controllable-minecarts.fall-damage", minecartControllableFallDamage); ++ set("gameplay-mechanics.controllable-minecarts.fall-damage", null); ++ set("gameplay-mechanics.minecart.controllable.fall-damage", oldBool); ++ oldDouble = getDouble("gameplay-mechanics.controllable-minecarts.base-speed", minecartControllableBaseSpeed); ++ set("gameplay-mechanics.controllable-minecarts.base-speed", null); ++ set("gameplay-mechanics.minecart.controllable.base-speed", oldDouble); ++ ConfigurationSection section = getConfigurationSection("gameplay-mechanics.controllable-minecarts.block-speed"); ++ if (section != null) { ++ for (String key : section.getKeys(false)) { ++ if ("grass-block".equals(key)) key = "grass_block"; // oopsie ++ oldDouble = section.getDouble(key, minecartControllableBaseSpeed); ++ set("gameplay-mechanics.controllable-minecarts.block-speed." + key, null); ++ set("gameplay-mechanics.minecart.controllable.block-speed." + key, oldDouble); ++ } ++ set("gameplay-mechanics.controllable-minecarts.block-speed", null); ++ } ++ set("gameplay-mechanics.controllable-minecarts", null); ++ } ++ ++ minecartMaxSpeed = getDouble("gameplay-mechanics.minecart.max-speed", minecartMaxSpeed); ++ minecartPlaceAnywhere = getBoolean("gameplay-mechanics.minecart.place-anywhere", minecartPlaceAnywhere); ++ minecartControllable = getBoolean("gameplay-mechanics.minecart.controllable.enabled", minecartControllable); ++ minecartControllableStepHeight = (float) getDouble("gameplay-mechanics.minecart.controllable.step-height", minecartControllableStepHeight); ++ minecartControllableHopBoost = getDouble("gameplay-mechanics.minecart.controllable.hop-boost", minecartControllableHopBoost); ++ minecartControllableFallDamage = getBoolean("gameplay-mechanics.minecart.controllable.fall-damage", minecartControllableFallDamage); ++ minecartControllableBaseSpeed = getDouble("gameplay-mechanics.minecart.controllable.base-speed", minecartControllableBaseSpeed); ++ ConfigurationSection section = getConfigurationSection("gameplay-mechanics.minecart.controllable.block-speed"); ++ if (section != null) { ++ for (String key : section.getKeys(false)) { ++ Block block = IRegistry.BLOCK.get(new MinecraftKey(key)); ++ if (block != Blocks.AIR) { ++ minecartControllableBlockSpeeds.put(block, section.getDouble(key, minecartControllableBaseSpeed)); ++ } ++ } ++ } else { ++ set("gameplay-mechanics.minecart.controllable.block-speed.grass_block", 0.3D); ++ set("gameplay-mechanics.minecart.controllable.block-speed.stone", 0.5D); ++ } ++ } ++ + public boolean idleTimeoutKick = true; + public boolean idleTimeoutTickNearbyEntities = true; + public boolean idleTimeoutCountAsSleeping = false; diff --git a/patches/Purpur/patches/server/0046-Disable-loot-drops-on-death-by-cramming.patch b/patches/Purpur/patches/server/0046-Disable-loot-drops-on-death-by-cramming.patch new file mode 100644 index 00000000..0645ab30 --- /dev/null +++ b/patches/Purpur/patches/server/0046-Disable-loot-drops-on-death-by-cramming.patch @@ -0,0 +1,37 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Wed, 3 Jul 2019 23:58:31 -0500 +Subject: [PATCH] Disable loot drops on death by cramming + + +diff --git a/src/main/java/net/minecraft/world/entity/EntityLiving.java b/src/main/java/net/minecraft/world/entity/EntityLiving.java +index f940a5460fe443bb97f23f29cff12827adb2eca4..871286b2f26f49aa49611503053cb6b1f0a064dc 100644 +--- a/src/main/java/net/minecraft/world/entity/EntityLiving.java ++++ b/src/main/java/net/minecraft/world/entity/EntityLiving.java +@@ -1595,8 +1595,10 @@ public abstract class EntityLiving extends Entity { + + this.dropInventory(); // CraftBukkit - from below + if (this.cW() && this.world.getGameRules().getBoolean(GameRules.DO_MOB_LOOT)) { ++ if (!(damagesource == DamageSource.CRAMMING && world.purpurConfig.disableDropsOnCrammingDeath)) { // Purpur + this.a(damagesource, flag); + this.dropDeathLoot(damagesource, i, flag); ++ } // Purpur + } + // CraftBukkit start - Call death event + org.bukkit.event.entity.EntityDeathEvent deathEvent = CraftEventFactory.callEntityDeathEvent(this, this.drops); // Paper +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index ee4b36f1aad78bcd7e9cc45acb4ca5b957d0d5c5..e2f49196642a325ac24f9245d5576547f20a044f 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -146,6 +146,11 @@ public class PurpurWorldConfig { + idleTimeoutUpdateTabList = getBoolean("gameplay-mechanics.player.idle-timeout.update-tab-list", idleTimeoutUpdateTabList); + } + ++ public boolean disableDropsOnCrammingDeath = false; ++ private void miscGameplayMechanicsSettings() { ++ disableDropsOnCrammingDeath = getBoolean("gameplay-mechanics.disable-drops-on-cramming-death", disableDropsOnCrammingDeath); ++ } ++ + public int playerSpawnInvulnerableTicks = 60; + public boolean playerInvulnerableWhileAcceptingResourcePack = false; + private void playerInvulnerabilities() { diff --git a/patches/Purpur/patches/server/0047-Players-should-not-cram-to-death.patch b/patches/Purpur/patches/server/0047-Players-should-not-cram-to-death.patch new file mode 100644 index 00000000..70350e73 --- /dev/null +++ b/patches/Purpur/patches/server/0047-Players-should-not-cram-to-death.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sun, 21 Jul 2019 18:01:46 -0500 +Subject: [PATCH] Players should not cram to death + + +diff --git a/src/main/java/net/minecraft/server/level/EntityPlayer.java b/src/main/java/net/minecraft/server/level/EntityPlayer.java +index 9746ade740ab36e68f24e0ee09d24e23f9e6a68f..4ce97052092c4b5f0fa59de7442654f7025febb6 100644 +--- a/src/main/java/net/minecraft/server/level/EntityPlayer.java ++++ b/src/main/java/net/minecraft/server/level/EntityPlayer.java +@@ -1581,7 +1581,7 @@ public class EntityPlayer extends EntityHuman implements ICrafting { + + @Override + public boolean isInvulnerable(DamageSource damagesource) { +- return super.isInvulnerable(damagesource) || this.H() || this.abilities.isInvulnerable && damagesource == DamageSource.WITHER; ++ return super.isInvulnerable(damagesource) || this.H() || damagesource == DamageSource.CRAMMING || this.abilities.isInvulnerable && damagesource == DamageSource.WITHER; // Purpur + } + + @Override diff --git a/patches/Purpur/patches/server/0048-Option-to-toggle-milk-curing-bad-omen.patch b/patches/Purpur/patches/server/0048-Option-to-toggle-milk-curing-bad-omen.patch new file mode 100644 index 00000000..8d19f9ae --- /dev/null +++ b/patches/Purpur/patches/server/0048-Option-to-toggle-milk-curing-bad-omen.patch @@ -0,0 +1,44 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Wed, 10 Jul 2019 20:43:05 -0500 +Subject: [PATCH] Option to toggle milk curing bad omen + + +diff --git a/src/main/java/net/minecraft/world/item/ItemMilkBucket.java b/src/main/java/net/minecraft/world/item/ItemMilkBucket.java +index 6085c5f75bd85cca3462613c18c2e2bf26205d1b..e20452f55c531f76ecaae9ba5d0ea3f8edf96127 100644 +--- a/src/main/java/net/minecraft/world/item/ItemMilkBucket.java ++++ b/src/main/java/net/minecraft/world/item/ItemMilkBucket.java +@@ -5,6 +5,8 @@ import net.minecraft.server.level.EntityPlayer; + import net.minecraft.stats.StatisticList; + import net.minecraft.world.EnumHand; + import net.minecraft.world.InteractionResultWrapper; ++import net.minecraft.world.effect.MobEffect; ++import net.minecraft.world.effect.MobEffects; + import net.minecraft.world.entity.EntityLiving; + import net.minecraft.world.entity.player.EntityHuman; + import net.minecraft.world.level.World; +@@ -29,7 +31,9 @@ public class ItemMilkBucket extends Item { + } + + if (!world.isClientSide) { ++ MobEffect badOmen = entityliving.getEffect(MobEffects.BAD_OMEN); // Purpur + entityliving.removeAllEffects(org.bukkit.event.entity.EntityPotionEffectEvent.Cause.MILK); // CraftBukkit ++ if (!world.purpurConfig.milkCuresBadOmen && badOmen != null) entityliving.addEffect(badOmen); // Purpur + } + + return itemstack.isEmpty() ? new ItemStack(Items.BUCKET) : itemstack; +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index e2f49196642a325ac24f9245d5576547f20a044f..7274008b7ff43f82574c748bac3566564792d05b 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -147,8 +147,10 @@ public class PurpurWorldConfig { + } + + public boolean disableDropsOnCrammingDeath = false; ++ public boolean milkCuresBadOmen = true; + private void miscGameplayMechanicsSettings() { + disableDropsOnCrammingDeath = getBoolean("gameplay-mechanics.disable-drops-on-cramming-death", disableDropsOnCrammingDeath); ++ milkCuresBadOmen = getBoolean("gameplay-mechanics.milk-cures-bad-omen", milkCuresBadOmen); + } + + public int playerSpawnInvulnerableTicks = 60; diff --git a/patches/Purpur/patches/server/0049-End-gateway-should-check-if-entity-can-use-portal.patch b/patches/Purpur/patches/server/0049-End-gateway-should-check-if-entity-can-use-portal.patch new file mode 100644 index 00000000..b1cf7f92 --- /dev/null +++ b/patches/Purpur/patches/server/0049-End-gateway-should-check-if-entity-can-use-portal.patch @@ -0,0 +1,18 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sat, 21 Mar 2020 18:33:05 -0500 +Subject: [PATCH] End gateway should check if entity can use portal + + +diff --git a/src/main/java/net/minecraft/world/level/block/entity/TileEntityEndGateway.java b/src/main/java/net/minecraft/world/level/block/entity/TileEntityEndGateway.java +index 855c49164277ca96ca08fb204d851a5ad6789990..d918194e45953764fa3fd286b715714330a60941 100644 +--- a/src/main/java/net/minecraft/world/level/block/entity/TileEntityEndGateway.java ++++ b/src/main/java/net/minecraft/world/level/block/entity/TileEntityEndGateway.java +@@ -153,6 +153,7 @@ public class TileEntityEndGateway extends TileEntityEnderPortal implements ITick + + public void b(Entity entity) { + if (this.world instanceof WorldServer && !this.f()) { ++ if (!entity.canPortal()) return; // Purpur + this.c = 100; + if (this.exitPortal == null && this.world.getTypeKey() == DimensionManager.THE_END) { // CraftBukkit - work in alternate worlds + this.a((WorldServer) this.world); diff --git a/patches/Purpur/patches/server/0050-Fix-the-dead-lagging-the-server.patch b/patches/Purpur/patches/server/0050-Fix-the-dead-lagging-the-server.patch new file mode 100644 index 00000000..a5ef0600 --- /dev/null +++ b/patches/Purpur/patches/server/0050-Fix-the-dead-lagging-the-server.patch @@ -0,0 +1,31 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Fri, 6 Mar 2020 13:37:26 -0600 +Subject: [PATCH] Fix the dead lagging the server + + +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index 0f11984743ba49fc6f094c8fa6c563febf0ab7d6..e458be6377595efed8dfb6527ab0b7a0f0f87d84 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -1659,6 +1659,7 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, ne + this.pitch = MathHelper.a(f1, -90.0F, 90.0F) % 360.0F; + this.lastYaw = this.yaw; + this.lastPitch = this.pitch; ++ if (valid && !dead) world.getChunkAt((int) Math.floor(this.locX()) >> 4, (int) Math.floor(this.locZ()) >> 4); // CraftBukkit // Paper // Purpur + } + + public void f(double d0, double d1, double d2) { +diff --git a/src/main/java/net/minecraft/world/entity/EntityLiving.java b/src/main/java/net/minecraft/world/entity/EntityLiving.java +index 871286b2f26f49aa49611503053cb6b1f0a064dc..efca085c5db03242b471db811c44224ca49eb305 100644 +--- a/src/main/java/net/minecraft/world/entity/EntityLiving.java ++++ b/src/main/java/net/minecraft/world/entity/EntityLiving.java +@@ -2594,7 +2594,7 @@ public abstract class EntityLiving extends Entity { + } + } + +- this.movementTick(); ++ if (!dead) this.movementTick(); // Purpur + double d0 = this.locX() - this.lastX; + double d1 = this.locZ() - this.lastZ; + float f = (float) (d0 * d0 + d1 * d1); diff --git a/patches/Purpur/patches/server/0051-Skip-events-if-there-s-no-listeners.patch b/patches/Purpur/patches/server/0051-Skip-events-if-there-s-no-listeners.patch new file mode 100644 index 00000000..df7dfa6e --- /dev/null +++ b/patches/Purpur/patches/server/0051-Skip-events-if-there-s-no-listeners.patch @@ -0,0 +1,26 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sat, 4 Apr 2020 03:07:59 -0500 +Subject: [PATCH] Skip events if there's no listeners + + +diff --git a/src/main/java/net/minecraft/commands/CommandDispatcher.java b/src/main/java/net/minecraft/commands/CommandDispatcher.java +index 7e30ec9a08d919d2ae9218ee0a11f77719129f07..b1bfc42b4153b225243ba65e7f937c0314cb39a5 100644 +--- a/src/main/java/net/minecraft/commands/CommandDispatcher.java ++++ b/src/main/java/net/minecraft/commands/CommandDispatcher.java +@@ -368,6 +368,7 @@ public class CommandDispatcher { + } + + private void runSync(EntityPlayer entityplayer, Collection bukkit, RootCommandNode rootcommandnode) { ++ if (PlayerCommandSendEvent.getHandlerList().getRegisteredListeners().length > 0) { // Purpur - skip all this crap if there's nothing listening + // Paper end - Async command map building + new com.destroystokyo.paper.event.brigadier.AsyncPlayerSendCommandsEvent(entityplayer.getBukkitEntity(), (RootCommandNode) rootcommandnode, false).callEvent(); // Paper + PlayerCommandSendEvent event = new PlayerCommandSendEvent(entityplayer.getBukkitEntity(), new LinkedHashSet<>(bukkit)); +@@ -380,6 +381,7 @@ public class CommandDispatcher { + } + } + // CraftBukkit end ++ } // Purpur - skip event + entityplayer.playerConnection.sendPacket(new PacketPlayOutCommands(rootcommandnode)); + } + diff --git a/patches/Purpur/patches/server/0052-Add-permission-for-F3-N-debug.patch b/patches/Purpur/patches/server/0052-Add-permission-for-F3-N-debug.patch new file mode 100644 index 00000000..f4652197 --- /dev/null +++ b/patches/Purpur/patches/server/0052-Add-permission-for-F3-N-debug.patch @@ -0,0 +1,18 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sat, 28 Dec 2019 04:21:54 -0600 +Subject: [PATCH] Add permission for F3+N debug + + +diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java +index 5897e4e02dad470174a31d3710520d04d4b87fb4..80f6a4e7204bceca3f312fe5c8d572f971a7fa4b 100644 +--- a/src/main/java/net/minecraft/server/players/PlayerList.java ++++ b/src/main/java/net/minecraft/server/players/PlayerList.java +@@ -1174,6 +1174,7 @@ public abstract class PlayerList { + } else { + b0 = (byte) (24 + i); + } ++ if (b0 < 28 && entityplayer.getBukkitEntity().hasPermission("purpur.debug.f3n")) b0 = 28; // Purpur + + entityplayer.playerConnection.sendPacket(new PacketPlayOutEntityStatus(entityplayer, b0)); + } diff --git a/patches/Purpur/patches/server/0053-Add-wither-skeleton-takes-wither-damage-option.patch b/patches/Purpur/patches/server/0053-Add-wither-skeleton-takes-wither-damage-option.patch new file mode 100644 index 00000000..919f48ce --- /dev/null +++ b/patches/Purpur/patches/server/0053-Add-wither-skeleton-takes-wither-damage-option.patch @@ -0,0 +1,34 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Tue, 14 Jan 2020 19:43:40 -0600 +Subject: [PATCH] Add wither skeleton takes wither damage option + + +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntitySkeletonWither.java b/src/main/java/net/minecraft/world/entity/monster/EntitySkeletonWither.java +index 85ba95615963fd6b28c454b25992e7c5b7019ae5..a90ac635ef7aef5289d21f948db7b170b23160d3 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntitySkeletonWither.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntitySkeletonWither.java +@@ -122,6 +122,6 @@ public class EntitySkeletonWither extends EntitySkeletonAbstract { + + @Override + public boolean d(MobEffect mobeffect) { +- return mobeffect.getMobEffect() == MobEffects.WITHER ? false : super.d(mobeffect); ++ return (world.purpurConfig.witherSkeletonTakesWitherDamage || mobeffect.getMobEffect() != MobEffects.WITHER) && super.d(mobeffect); // Purpur + } + } +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 7274008b7ff43f82574c748bac3566564792d05b..6b65a81bc54cc7c795885cc860346d4a0ed64125 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -313,6 +313,11 @@ public class PurpurWorldConfig { + villagerUseBrainTicksOnlyWhenLagging = getBoolean("mobs.villager.use-brain-ticks-only-when-lagging", villagerUseBrainTicksOnlyWhenLagging); + } + ++ public boolean witherSkeletonTakesWitherDamage = false; ++ private void witherSkeletonSettings() { ++ witherSkeletonTakesWitherDamage = getBoolean("mobs.wither_skeleton.takes-wither-damage", witherSkeletonTakesWitherDamage); ++ } ++ + public double zombieHorseSpawnChance = 0.0D; + private void zombieHorseSettings() { + zombieHorseSpawnChance = getDouble("mobs.zombie_horse.spawn-chance", zombieHorseSpawnChance); diff --git a/patches/Purpur/patches/server/0054-Configurable-TPS-Catchup.patch b/patches/Purpur/patches/server/0054-Configurable-TPS-Catchup.patch new file mode 100644 index 00000000..13e6a643 --- /dev/null +++ b/patches/Purpur/patches/server/0054-Configurable-TPS-Catchup.patch @@ -0,0 +1,39 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Thu, 26 Mar 2020 19:06:22 -0500 +Subject: [PATCH] Configurable TPS Catchup + + +diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java +index 991ac5baf3f10631edb0e60d17c714af1f406a29..d93ecf4b3451b1c3c309aadfe2ec287a68df0713 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -1136,7 +1136,13 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant +Date: Thu, 19 Mar 2020 19:39:34 -0500 +Subject: [PATCH] Add option to allow loyalty on tridents to work in the void + + +diff --git a/src/main/java/net/minecraft/world/entity/projectile/EntityThrownTrident.java b/src/main/java/net/minecraft/world/entity/projectile/EntityThrownTrident.java +index 646043987e1102ae8e9becc9820e6c6d86ef844d..7aadfe6598f0d3d41b94cfc003fcc9d075ee6ae5 100644 +--- a/src/main/java/net/minecraft/world/entity/projectile/EntityThrownTrident.java ++++ b/src/main/java/net/minecraft/world/entity/projectile/EntityThrownTrident.java +@@ -60,7 +60,7 @@ public class EntityThrownTrident extends EntityArrow { + + Entity entity = this.getShooter(); + +- if ((this.ai || this.t()) && entity != null) { ++ if ((this.ai || this.t() || (world.purpurConfig.tridentLoyaltyVoidReturnHeight < 0.0D && locY() < world.purpurConfig.tridentLoyaltyVoidReturnHeight)) && entity != null) { // Purpur + byte b0 = (Byte) this.datawatcher.get(EntityThrownTrident.g); + + if (b0 > 0 && !this.z()) { +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 6b65a81bc54cc7c795885cc860346d4a0ed64125..0a6255422a5d22e84cc1048caf7ca964a168b7fe 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -148,9 +148,11 @@ public class PurpurWorldConfig { + + public boolean disableDropsOnCrammingDeath = false; + public boolean milkCuresBadOmen = true; ++ public double tridentLoyaltyVoidReturnHeight = 0.0D; + private void miscGameplayMechanicsSettings() { + disableDropsOnCrammingDeath = getBoolean("gameplay-mechanics.disable-drops-on-cramming-death", disableDropsOnCrammingDeath); + milkCuresBadOmen = getBoolean("gameplay-mechanics.milk-cures-bad-omen", milkCuresBadOmen); ++ tridentLoyaltyVoidReturnHeight = getDouble("gameplay-mechanics.trident-loyalty-void-return-height", tridentLoyaltyVoidReturnHeight); + } + + public int playerSpawnInvulnerableTicks = 60; diff --git a/patches/Purpur/patches/server/0056-Add-enderman-and-creeper-griefing-controls.patch b/patches/Purpur/patches/server/0056-Add-enderman-and-creeper-griefing-controls.patch new file mode 100644 index 00000000..6db4dfdf --- /dev/null +++ b/patches/Purpur/patches/server/0056-Add-enderman-and-creeper-griefing-controls.patch @@ -0,0 +1,75 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sun, 26 Apr 2020 16:28:38 -0500 +Subject: [PATCH] Add enderman and creeper griefing controls + + +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityCreeper.java b/src/main/java/net/minecraft/world/entity/monster/EntityCreeper.java +index 63a6b1820f60db9eea49a3a589dd50ad25a3c0a2..09df2bd3b523072de0e9858e6e707e3721474422 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityCreeper.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityCreeper.java +@@ -255,7 +255,7 @@ public class EntityCreeper extends EntityMonster { + + public void explode() { + if (!this.world.isClientSide) { +- Explosion.Effect explosion_effect = this.world.getGameRules().getBoolean(GameRules.MOB_GRIEFING) ? Explosion.Effect.DESTROY : Explosion.Effect.NONE; ++ Explosion.Effect explosion_effect = this.world.getGameRules().getBoolean(GameRules.MOB_GRIEFING) && world.purpurConfig.creeperAllowGriefing ? Explosion.Effect.DESTROY : Explosion.Effect.NONE; // Purpur + float f = this.isPowered() ? 2.0F : 1.0F; + + // CraftBukkit start +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityEnderman.java b/src/main/java/net/minecraft/world/entity/monster/EntityEnderman.java +index e993b1849beb60515c51ee4f37617faab63ca223..6a5593ff735a9e0486d7ed9b3afb4f44ad156b34 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityEnderman.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityEnderman.java +@@ -423,6 +423,7 @@ public class EntityEnderman extends EntityMonster implements IEntityAngerable { + + @Override + public boolean a() { ++ if (!enderman.world.purpurConfig.endermanAllowGriefing) return false; // Purpur + return this.enderman.getCarried() != null ? false : (!this.enderman.world.getGameRules().getBoolean(GameRules.MOB_GRIEFING) ? false : this.enderman.getRandom().nextInt(20) == 0); + } + +@@ -456,7 +457,7 @@ public class EntityEnderman extends EntityMonster implements IEntityAngerable { + + static class PathfinderGoalEndermanPlaceBlock extends PathfinderGoal { + +- private final EntityEnderman a; ++ private final EntityEnderman a; public EntityEnderman getEnderman() { return a; } // Purpur - OBFHELPER + + public PathfinderGoalEndermanPlaceBlock(EntityEnderman entityenderman) { + this.a = entityenderman; +@@ -464,6 +465,7 @@ public class EntityEnderman extends EntityMonster implements IEntityAngerable { + + @Override + public boolean a() { ++ if (!getEnderman().world.purpurConfig.endermanAllowGriefing) return false; // Purpur + return this.a.getCarried() == null ? false : (!this.a.world.getGameRules().getBoolean(GameRules.MOB_GRIEFING) ? false : this.a.getRandom().nextInt(2000) == 0); + } + +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 0a6255422a5d22e84cc1048caf7ca964a168b7fe..8033348257c0fcc6f3c1c376b6fb343c414618c5 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -225,8 +225,10 @@ public class PurpurWorldConfig { + cowFeedMushrooms = getInt("mobs.cow.feed-mushrooms-for-mooshroom", cowFeedMushrooms); + } + ++ public boolean creeperAllowGriefing = true; + public double creeperChargedChance = 0.0D; + private void creeperSettings() { ++ creeperAllowGriefing = getBoolean("mobs.creeper.allow-griefing", creeperAllowGriefing); + creeperChargedChance = getDouble("mobs.creeper.naturally-charged-chance", creeperChargedChance); + } + +@@ -235,6 +237,11 @@ public class PurpurWorldConfig { + enderDragonAlwaysDropsFullExp = getBoolean("mobs.ender_dragon.always-drop-full-exp", enderDragonAlwaysDropsFullExp); + } + ++ public boolean endermanAllowGriefing = true; ++ private void endermanSettings() { ++ endermanAllowGriefing = getBoolean("mobs.enderman.allow-griefing", endermanAllowGriefing); ++ } ++ + public boolean foxTypeChangesWithTulips = false; + private void foxSettings() { + foxTypeChangesWithTulips = getBoolean("mobs.fox.tulips-change-type", foxTypeChangesWithTulips); diff --git a/patches/Purpur/patches/server/0057-Entities-pick-up-loot-bypass-mob-griefing-gamerule.patch b/patches/Purpur/patches/server/0057-Entities-pick-up-loot-bypass-mob-griefing-gamerule.patch new file mode 100644 index 00000000..97789828 --- /dev/null +++ b/patches/Purpur/patches/server/0057-Entities-pick-up-loot-bypass-mob-griefing-gamerule.patch @@ -0,0 +1,36 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Fri, 24 Apr 2020 09:33:11 -0500 +Subject: [PATCH] Entities pick up loot bypass mob-griefing gamerule + + +diff --git a/src/main/java/net/minecraft/world/entity/EntityInsentient.java b/src/main/java/net/minecraft/world/entity/EntityInsentient.java +index 46e9a232ca5df81cafd4c3fc6af43b933c95d04f..efd8126844d5b5cd93ef465744c8d512924c8885 100644 +--- a/src/main/java/net/minecraft/world/entity/EntityInsentient.java ++++ b/src/main/java/net/minecraft/world/entity/EntityInsentient.java +@@ -614,7 +614,7 @@ public abstract class EntityInsentient extends EntityLiving { + public void movementTick() { + super.movementTick(); + this.world.getMethodProfiler().enter("looting"); +- if (!this.world.isClientSide && this.canPickupLoot() && this.isAlive() && !this.killed && this.world.getGameRules().getBoolean(GameRules.MOB_GRIEFING)) { ++ if (!this.world.isClientSide && this.canPickupLoot() && this.isAlive() && !this.killed && (this.world.getGameRules().getBoolean(GameRules.MOB_GRIEFING) || world.purpurConfig.entitiesPickUpLootBypassMobGriefing)) { // Purpur + List list = this.world.a(EntityItem.class, this.getBoundingBox().grow(1.0D, 0.0D, 1.0D)); + Iterator iterator = list.iterator(); + +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 8033348257c0fcc6f3c1c376b6fb343c414618c5..3198f65bff04015babe7e529ad66588ef28e52be 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -147,10 +147,12 @@ public class PurpurWorldConfig { + } + + public boolean disableDropsOnCrammingDeath = false; ++ public boolean entitiesPickUpLootBypassMobGriefing = false; + public boolean milkCuresBadOmen = true; + public double tridentLoyaltyVoidReturnHeight = 0.0D; + private void miscGameplayMechanicsSettings() { + disableDropsOnCrammingDeath = getBoolean("gameplay-mechanics.disable-drops-on-cramming-death", disableDropsOnCrammingDeath); ++ entitiesPickUpLootBypassMobGriefing = getBoolean("gameplay-mechanics.entities-pick-up-loot-bypass-mob-griefing", entitiesPickUpLootBypassMobGriefing); + milkCuresBadOmen = getBoolean("gameplay-mechanics.milk-cures-bad-omen", milkCuresBadOmen); + tridentLoyaltyVoidReturnHeight = getDouble("gameplay-mechanics.trident-loyalty-void-return-height", tridentLoyaltyVoidReturnHeight); + } diff --git a/patches/Purpur/patches/server/0058-Villagers-farming-can-bypass-mob-griefing-gamerule.patch b/patches/Purpur/patches/server/0058-Villagers-farming-can-bypass-mob-griefing-gamerule.patch new file mode 100644 index 00000000..3019392f --- /dev/null +++ b/patches/Purpur/patches/server/0058-Villagers-farming-can-bypass-mob-griefing-gamerule.patch @@ -0,0 +1,35 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Fri, 24 Apr 2020 09:37:29 -0500 +Subject: [PATCH] Villagers farming can bypass mob-griefing gamerule + + +diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/BehaviorFarm.java b/src/main/java/net/minecraft/world/entity/ai/behavior/BehaviorFarm.java +index bd998ea93d7e8748b0a938f0a76b4ccf388c7b27..42c70a6c2972ac38e889a6d42fe2d7d4f6017d57 100644 +--- a/src/main/java/net/minecraft/world/entity/ai/behavior/BehaviorFarm.java ++++ b/src/main/java/net/minecraft/world/entity/ai/behavior/BehaviorFarm.java +@@ -38,7 +38,7 @@ public class BehaviorFarm extends Behavior { + } + + protected boolean a(WorldServer worldserver, EntityVillager entityvillager) { +- if (!worldserver.getGameRules().getBoolean(GameRules.MOB_GRIEFING)) { ++ if (!worldserver.getGameRules().getBoolean(GameRules.MOB_GRIEFING) && !worldserver.purpurConfig.villagerFarmingBypassMobGriefing) { // Purpur + return false; + } else if (entityvillager.getVillagerData().getProfession() != VillagerProfession.FARMER) { + return false; +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 3198f65bff04015babe7e529ad66588ef28e52be..e82485ee1270ce83ccc93825d795743d4ead23a1 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -319,9 +319,11 @@ public class PurpurWorldConfig { + + public int villagerBrainTicks = 1; + public boolean villagerUseBrainTicksOnlyWhenLagging = true; ++ public boolean villagerFarmingBypassMobGriefing = false; + private void villagerSettings() { + villagerBrainTicks = getInt("mobs.villager.brain-ticks", villagerBrainTicks); + villagerUseBrainTicksOnlyWhenLagging = getBoolean("mobs.villager.use-brain-ticks-only-when-lagging", villagerUseBrainTicksOnlyWhenLagging); ++ villagerFarmingBypassMobGriefing = getBoolean("mobs.villager.bypass-mob-griefing", villagerFarmingBypassMobGriefing); + } + + public boolean witherSkeletonTakesWitherDamage = false; diff --git a/patches/Purpur/patches/server/0059-Villagers-follow-emerald-blocks.patch b/patches/Purpur/patches/server/0059-Villagers-follow-emerald-blocks.patch new file mode 100644 index 00000000..4cb54ce8 --- /dev/null +++ b/patches/Purpur/patches/server/0059-Villagers-follow-emerald-blocks.patch @@ -0,0 +1,101 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Fri, 29 Nov 2019 22:10:12 -0600 +Subject: [PATCH] Villagers follow emerald blocks + + +diff --git a/src/main/java/net/minecraft/world/entity/npc/EntityVillager.java b/src/main/java/net/minecraft/world/entity/npc/EntityVillager.java +index c45e6ae3f912ac582c6ba693517e05cd8fbf33e2..284401de0e8f4e4cf6df64a8f2b619c10e937130 100644 +--- a/src/main/java/net/minecraft/world/entity/npc/EntityVillager.java ++++ b/src/main/java/net/minecraft/world/entity/npc/EntityVillager.java +@@ -59,6 +59,7 @@ import net.minecraft.world.entity.ai.BehaviorController; + import net.minecraft.world.entity.ai.attributes.AttributeProvider; + import net.minecraft.world.entity.ai.attributes.GenericAttributes; + import net.minecraft.world.entity.ai.behavior.Behaviors; ++import net.minecraft.world.entity.ai.goal.PathfinderGoalTempt; + import net.minecraft.world.entity.ai.gossip.Reputation; + import net.minecraft.world.entity.ai.gossip.ReputationType; + import net.minecraft.world.entity.ai.memory.MemoryModuleType; +@@ -143,6 +144,13 @@ public class EntityVillager extends EntityVillagerAbstract implements Reputation + this.brainTickOffset = getRandom().nextInt(100); // Purpur + } + ++ // Purpur start ++ @Override ++ protected void initPathfinder() { ++ if (world.purpurConfig.villagerFollowEmeraldBlock) this.goalSelector.a(3, new PathfinderGoalTempt(this, 1.0D, false, TEMPT_ITEMS)); ++ } ++ // Purpur end ++ + @Override + public BehaviorController getBehaviorController() { + return (BehaviorController) super.getBehaviorController(); // CraftBukkit - decompile error +diff --git a/src/main/java/net/minecraft/world/entity/npc/EntityVillagerAbstract.java b/src/main/java/net/minecraft/world/entity/npc/EntityVillagerAbstract.java +index 49821f0f26864c35be84a4a4288857a04668fbba..91142526187f96615b5cbd3ed3b68d9175cb9f8b 100644 +--- a/src/main/java/net/minecraft/world/entity/npc/EntityVillagerAbstract.java ++++ b/src/main/java/net/minecraft/world/entity/npc/EntityVillagerAbstract.java +@@ -25,11 +25,13 @@ import net.minecraft.world.entity.EnumMobSpawn; + import net.minecraft.world.entity.GroupDataEntity; + import net.minecraft.world.entity.player.EntityHuman; + import net.minecraft.world.item.ItemStack; ++import net.minecraft.world.item.crafting.RecipeItemStack; + import net.minecraft.world.item.trading.IMerchant; + import net.minecraft.world.item.trading.MerchantRecipe; + import net.minecraft.world.item.trading.MerchantRecipeList; + import net.minecraft.world.level.World; + import net.minecraft.world.level.WorldAccess; ++import net.minecraft.world.level.block.Blocks; + import net.minecraft.world.level.pathfinder.PathType; + + // CraftBukkit start +@@ -45,6 +47,8 @@ import io.papermc.paper.event.player.PlayerTradeEvent; + + public abstract class EntityVillagerAbstract extends EntityAgeable implements NPC, IMerchant { + ++ static final RecipeItemStack TEMPT_ITEMS = RecipeItemStack.a(Blocks.EMERALD_BLOCK.getItem()); // Purpur ++ + // CraftBukkit start + private CraftMerchant craftMerchant; + +diff --git a/src/main/java/net/minecraft/world/entity/npc/EntityVillagerTrader.java b/src/main/java/net/minecraft/world/entity/npc/EntityVillagerTrader.java +index 69044827ed6b34924ffd89a977afa06df0dcefc3..6fab69bf5800ef8a37f29c3b6b2103051f36fedf 100644 +--- a/src/main/java/net/minecraft/world/entity/npc/EntityVillagerTrader.java ++++ b/src/main/java/net/minecraft/world/entity/npc/EntityVillagerTrader.java +@@ -26,6 +26,7 @@ import net.minecraft.world.entity.ai.goal.PathfinderGoalLookAtTradingPlayer; + import net.minecraft.world.entity.ai.goal.PathfinderGoalMoveTowardsRestriction; + import net.minecraft.world.entity.ai.goal.PathfinderGoalPanic; + import net.minecraft.world.entity.ai.goal.PathfinderGoalRandomStrollLand; ++import net.minecraft.world.entity.ai.goal.PathfinderGoalTempt; + import net.minecraft.world.entity.ai.goal.PathfinderGoalTradeWithPlayer; + import net.minecraft.world.entity.ai.goal.PathfinderGoalUseItem; + import net.minecraft.world.entity.monster.EntityEvoker; +@@ -89,6 +90,7 @@ public class EntityVillagerTrader extends EntityVillagerAbstract { + this.goalSelector.a(1, new PathfinderGoalPanic(this, 0.5D)); + this.goalSelector.a(1, new PathfinderGoalLookAtTradingPlayer(this)); + this.goalSelector.a(2, new EntityVillagerTrader.a(this, 2.0D, 0.35D)); ++ if (world.purpurConfig.villagerTraderFollowEmeraldBlock) this.goalSelector.a(3, new PathfinderGoalTempt(this, 1.0D, false, TEMPT_ITEMS)); // Purpur + this.goalSelector.a(4, new PathfinderGoalMoveTowardsRestriction(this, 0.35D)); + this.goalSelector.a(8, new PathfinderGoalRandomStrollLand(this, 0.35D)); + this.goalSelector.a(9, new PathfinderGoalInteract(this, EntityHuman.class, 3.0F, 1.0F)); +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index e82485ee1270ce83ccc93825d795743d4ead23a1..2eaef857f474c05ef1b4aac4870222d2464da949 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -320,10 +320,17 @@ public class PurpurWorldConfig { + public int villagerBrainTicks = 1; + public boolean villagerUseBrainTicksOnlyWhenLagging = true; + public boolean villagerFarmingBypassMobGriefing = false; ++ public boolean villagerFollowEmeraldBlock = false; + private void villagerSettings() { + villagerBrainTicks = getInt("mobs.villager.brain-ticks", villagerBrainTicks); + villagerUseBrainTicksOnlyWhenLagging = getBoolean("mobs.villager.use-brain-ticks-only-when-lagging", villagerUseBrainTicksOnlyWhenLagging); + villagerFarmingBypassMobGriefing = getBoolean("mobs.villager.bypass-mob-griefing", villagerFarmingBypassMobGriefing); ++ villagerFollowEmeraldBlock = getBoolean("mobs.villager.follow-emerald-blocks", villagerFollowEmeraldBlock); ++ } ++ ++ public boolean villagerTraderFollowEmeraldBlock = false; ++ private void villagerTraderSettings() { ++ villagerTraderFollowEmeraldBlock = getBoolean("mobs.wandering_trader.follow-emerald-blocks", villagerTraderFollowEmeraldBlock); + } + + public boolean witherSkeletonTakesWitherDamage = false; diff --git a/patches/Purpur/patches/server/0060-Allow-leashing-villagers.patch b/patches/Purpur/patches/server/0060-Allow-leashing-villagers.patch new file mode 100644 index 00000000..c9c1fddb --- /dev/null +++ b/patches/Purpur/patches/server/0060-Allow-leashing-villagers.patch @@ -0,0 +1,86 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Thu, 3 Oct 2019 18:08:03 -0500 +Subject: [PATCH] Allow leashing villagers + + +diff --git a/src/main/java/net/minecraft/world/entity/EntityInsentient.java b/src/main/java/net/minecraft/world/entity/EntityInsentient.java +index efd8126844d5b5cd93ef465744c8d512924c8885..864b9bf8f41476e876fd386cdbfb007898584ad6 100644 +--- a/src/main/java/net/minecraft/world/entity/EntityInsentient.java ++++ b/src/main/java/net/minecraft/world/entity/EntityInsentient.java +@@ -49,6 +49,7 @@ import net.minecraft.world.entity.item.EntityItem; + import net.minecraft.world.entity.monster.EntityBlaze; + import net.minecraft.world.entity.monster.EntityEnderman; + import net.minecraft.world.entity.monster.IMonster; ++import net.minecraft.world.entity.npc.EntityVillagerAbstract; + import net.minecraft.world.entity.player.EntityHuman; + import net.minecraft.world.entity.vehicle.EntityBoat; + import net.minecraft.world.item.Item; +@@ -1218,6 +1219,7 @@ public abstract class EntityInsentient extends EntityLiving { + if (!this.isAlive()) { + return EnumInteractionResult.PASS; + } else if (this.getLeashHolder() == entityhuman) { ++ if (enumhand == EnumHand.OFF_HAND && (world.purpurConfig.villagerCanBeLeashed || world.purpurConfig.villagerTraderCanBeLeashed) && this instanceof EntityVillagerAbstract) return EnumInteractionResult.CONSUME; // Purpur + // CraftBukkit start - fire PlayerUnleashEntityEvent + // Paper start - drop leash variable + PlayerUnleashEntityEvent event = CraftEventFactory.callPlayerUnleashEntityEvent(this, entityhuman, !entityhuman.abilities.canInstantlyBuild); +diff --git a/src/main/java/net/minecraft/world/entity/npc/EntityVillager.java b/src/main/java/net/minecraft/world/entity/npc/EntityVillager.java +index 284401de0e8f4e4cf6df64a8f2b619c10e937130..007e5c7ef9b5eaf5cbf262197f3d73d2a33741ea 100644 +--- a/src/main/java/net/minecraft/world/entity/npc/EntityVillager.java ++++ b/src/main/java/net/minecraft/world/entity/npc/EntityVillager.java +@@ -149,6 +149,11 @@ public class EntityVillager extends EntityVillagerAbstract implements Reputation + protected void initPathfinder() { + if (world.purpurConfig.villagerFollowEmeraldBlock) this.goalSelector.a(3, new PathfinderGoalTempt(this, 1.0D, false, TEMPT_ITEMS)); + } ++ ++ @Override ++ public boolean a(EntityHuman entityhuman) { ++ return world.purpurConfig.villagerCanBeLeashed && !this.isLeashed(); ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/npc/EntityVillagerTrader.java b/src/main/java/net/minecraft/world/entity/npc/EntityVillagerTrader.java +index 6fab69bf5800ef8a37f29c3b6b2103051f36fedf..8df4d985e3124ddc1643da8385b15348937bc320 100644 +--- a/src/main/java/net/minecraft/world/entity/npc/EntityVillagerTrader.java ++++ b/src/main/java/net/minecraft/world/entity/npc/EntityVillagerTrader.java +@@ -97,6 +97,13 @@ public class EntityVillagerTrader extends EntityVillagerAbstract { + this.goalSelector.a(10, new PathfinderGoalLookAtPlayer(this, EntityInsentient.class, 8.0F)); + } + ++ // Purpur - start ++ @Override ++ public boolean a(EntityHuman entityhuman) { ++ return world.purpurConfig.villagerTraderCanBeLeashed && !this.isLeashed(); ++ } ++ // Purpur - end ++ + @Nullable + @Override + public EntityAgeable createChild(WorldServer worldserver, EntityAgeable entityageable) { +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 2eaef857f474c05ef1b4aac4870222d2464da949..9922ca6bd7d856eea182b8dd3c210e5f726ef180 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -319,17 +319,21 @@ public class PurpurWorldConfig { + + public int villagerBrainTicks = 1; + public boolean villagerUseBrainTicksOnlyWhenLagging = true; ++ public boolean villagerCanBeLeashed = false; + public boolean villagerFarmingBypassMobGriefing = false; + public boolean villagerFollowEmeraldBlock = false; + private void villagerSettings() { + villagerBrainTicks = getInt("mobs.villager.brain-ticks", villagerBrainTicks); + villagerUseBrainTicksOnlyWhenLagging = getBoolean("mobs.villager.use-brain-ticks-only-when-lagging", villagerUseBrainTicksOnlyWhenLagging); ++ villagerCanBeLeashed = getBoolean("mobs.villager.can-be-leashed", villagerCanBeLeashed); + villagerFarmingBypassMobGriefing = getBoolean("mobs.villager.bypass-mob-griefing", villagerFarmingBypassMobGriefing); + villagerFollowEmeraldBlock = getBoolean("mobs.villager.follow-emerald-blocks", villagerFollowEmeraldBlock); + } + ++ public boolean villagerTraderCanBeLeashed = false; + public boolean villagerTraderFollowEmeraldBlock = false; + private void villagerTraderSettings() { ++ villagerTraderCanBeLeashed = getBoolean("mobs.wandering_trader.can-be-leashed", villagerTraderCanBeLeashed); + villagerTraderFollowEmeraldBlock = getBoolean("mobs.wandering_trader.follow-emerald-blocks", villagerTraderFollowEmeraldBlock); + } + diff --git a/patches/Purpur/patches/server/0061-Implement-configurable-search-radius-for-villagers-t.patch b/patches/Purpur/patches/server/0061-Implement-configurable-search-radius-for-villagers-t.patch new file mode 100644 index 00000000..b3102630 --- /dev/null +++ b/patches/Purpur/patches/server/0061-Implement-configurable-search-radius-for-villagers-t.patch @@ -0,0 +1,40 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Mon, 22 Jul 2019 17:32:17 -0500 +Subject: [PATCH] Implement configurable search radius for villagers to spawn + iron golems + + +diff --git a/src/main/java/net/minecraft/world/entity/npc/EntityVillager.java b/src/main/java/net/minecraft/world/entity/npc/EntityVillager.java +index 007e5c7ef9b5eaf5cbf262197f3d73d2a33741ea..aaf8d2cd3089adba69c873c4ea62b0e8837b21d6 100644 +--- a/src/main/java/net/minecraft/world/entity/npc/EntityVillager.java ++++ b/src/main/java/net/minecraft/world/entity/npc/EntityVillager.java +@@ -975,6 +975,7 @@ public class EntityVillager extends EntityVillagerAbstract implements Reputation + + @Nullable + private EntityIronGolem d(WorldServer worldserver) { ++ if (world.purpurConfig.villagerSpawnIronGolemRadius > 0 && world.a(EntityIronGolem.class, getBoundingBox().grow(world.purpurConfig.villagerSpawnIronGolemRadius)).size() > world.purpurConfig.villagerSpawnIronGolemLimit) return null; // Purpur + BlockPosition blockposition = this.getChunkCoordinates(); + + for (int i = 0; i < 10; ++i) { +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 9922ca6bd7d856eea182b8dd3c210e5f726ef180..f3c9a06be653a0fbd462677866134b634b8611b6 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -322,12 +322,16 @@ public class PurpurWorldConfig { + public boolean villagerCanBeLeashed = false; + public boolean villagerFarmingBypassMobGriefing = false; + public boolean villagerFollowEmeraldBlock = false; ++ public int villagerSpawnIronGolemRadius = 0; ++ public int villagerSpawnIronGolemLimit = 0; + private void villagerSettings() { + villagerBrainTicks = getInt("mobs.villager.brain-ticks", villagerBrainTicks); + villagerUseBrainTicksOnlyWhenLagging = getBoolean("mobs.villager.use-brain-ticks-only-when-lagging", villagerUseBrainTicksOnlyWhenLagging); + villagerCanBeLeashed = getBoolean("mobs.villager.can-be-leashed", villagerCanBeLeashed); + villagerFarmingBypassMobGriefing = getBoolean("mobs.villager.bypass-mob-griefing", villagerFarmingBypassMobGriefing); + villagerFollowEmeraldBlock = getBoolean("mobs.villager.follow-emerald-blocks", villagerFollowEmeraldBlock); ++ villagerSpawnIronGolemRadius = getInt("mobs.villager.spawn-iron-golem.radius", villagerSpawnIronGolemRadius); ++ villagerSpawnIronGolemLimit = getInt("mobs.villager.spawn-iron-golem.limit", villagerSpawnIronGolemLimit); + } + + public boolean villagerTraderCanBeLeashed = false; diff --git a/patches/Purpur/patches/server/0062-Implement-infinite-lava.patch b/patches/Purpur/patches/server/0062-Implement-infinite-lava.patch new file mode 100644 index 00000000..f152316c --- /dev/null +++ b/patches/Purpur/patches/server/0062-Implement-infinite-lava.patch @@ -0,0 +1,78 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sat, 23 Nov 2019 17:55:42 -0600 +Subject: [PATCH] Implement infinite lava + + +diff --git a/src/main/java/net/minecraft/world/level/material/FluidTypeFlowing.java b/src/main/java/net/minecraft/world/level/material/FluidTypeFlowing.java +index 6bb4ec00e40795ced73648fefcd1f5027e0113cd..963b7edab813cd32f04c51fd2c6c137988e2a754 100644 +--- a/src/main/java/net/minecraft/world/level/material/FluidTypeFlowing.java ++++ b/src/main/java/net/minecraft/world/level/material/FluidTypeFlowing.java +@@ -217,7 +217,7 @@ public abstract class FluidTypeFlowing extends FluidType { + } + } + +- if (this.f() && j >= 2) { ++ if (infinite(iworldreader) && j >= getRequiredSources(iworldreader)) { // Purpur + IBlockData iblockdata2 = iworldreader.getType(blockposition.down()); + Fluid fluid1 = iblockdata2.getFluid(); + +@@ -288,6 +288,17 @@ public abstract class FluidTypeFlowing extends FluidType { + return (Fluid) this.e().h().set(FluidTypeFlowing.FALLING, flag); + } + ++ // Purpur start ++ protected boolean infinite(IWorldReader iworldreader) { ++ return infinite(); ++ } ++ ++ protected int getRequiredSources(IWorldReader iworldreader) { ++ return 2; ++ } ++ // Purpur end ++ ++ protected boolean infinite() { return f(); } // Purpur - OBFHELPER + protected abstract boolean f(); + + protected void a(GeneratorAccess generatoraccess, BlockPosition blockposition, IBlockData iblockdata, EnumDirection enumdirection, Fluid fluid) { +diff --git a/src/main/java/net/minecraft/world/level/material/FluidTypeLava.java b/src/main/java/net/minecraft/world/level/material/FluidTypeLava.java +index b362a728b5d17256768847ab09e2505a9cc1918b..86f2e969d98c833700f0f48baf7610ad95b3f8a1 100644 +--- a/src/main/java/net/minecraft/world/level/material/FluidTypeLava.java ++++ b/src/main/java/net/minecraft/world/level/material/FluidTypeLava.java +@@ -163,6 +163,18 @@ public abstract class FluidTypeLava extends FluidTypeFlowing { + generatoraccess.triggerEffect(1501, blockposition, 0); + } + ++ // Purpur start ++ @Override ++ protected boolean infinite(IWorldReader iworldreader) { ++ return iworldreader.getWorldBorder().world.purpurConfig.lavaInfinite; ++ } ++ ++ @Override ++ protected int getRequiredSources(IWorldReader iworldreader) { ++ return iworldreader.getWorldBorder().world.purpurConfig.lavaInfiniteRequiredSources; ++ } ++ // Purpur end ++ + @Override + protected boolean f() { + return false; +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index f3c9a06be653a0fbd462677866134b634b8611b6..95605436c7d2d8e8b30217dc59d28ce2658d0e26 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -192,6 +192,13 @@ public class PurpurWorldConfig { + farmlandGetsMoistFromBelow = getBoolean("blocks.farmland.gets-moist-from-below", farmlandGetsMoistFromBelow); + } + ++ public boolean lavaInfinite = false; ++ public int lavaInfiniteRequiredSources = 2; ++ private void lavaSettings() { ++ lavaInfinite = getBoolean("blocks.lava.infinite-source", lavaInfinite); ++ lavaInfiniteRequiredSources = getInt("blocks.lava.infinite-required-sources", lavaInfiniteRequiredSources); ++ } ++ + public boolean signAllowColors = false; + public boolean signRightClickEdit = false; + private void signSettings() { diff --git a/patches/Purpur/patches/server/0063-Make-lava-flow-speed-configurable.patch b/patches/Purpur/patches/server/0063-Make-lava-flow-speed-configurable.patch new file mode 100644 index 00000000..9caee967 --- /dev/null +++ b/patches/Purpur/patches/server/0063-Make-lava-flow-speed-configurable.patch @@ -0,0 +1,37 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Thu, 2 Jan 2020 11:31:36 -0600 +Subject: [PATCH] Make lava flow speed configurable + + +diff --git a/src/main/java/net/minecraft/world/level/material/FluidTypeLava.java b/src/main/java/net/minecraft/world/level/material/FluidTypeLava.java +index 86f2e969d98c833700f0f48baf7610ad95b3f8a1..e706695d42d7557f818595aa30fb3cfc35ba9f6b 100644 +--- a/src/main/java/net/minecraft/world/level/material/FluidTypeLava.java ++++ b/src/main/java/net/minecraft/world/level/material/FluidTypeLava.java +@@ -145,7 +145,7 @@ public abstract class FluidTypeLava extends FluidTypeFlowing { + + @Override + public int a(IWorldReader iworldreader) { +- return iworldreader.getDimensionManager().isNether() ? 10 : 30; ++ return iworldreader.getDimensionManager().isNether() ? iworldreader.getWorldBorder().world.purpurConfig.lavaSpeedNether : iworldreader.getWorldBorder().world.purpurConfig.lavaSpeedNotNether; // Purpur + } + + @Override +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 95605436c7d2d8e8b30217dc59d28ce2658d0e26..21ecfc0a1ee6d39e0b824aa3ce146a8833bd20ce 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -194,9 +194,13 @@ public class PurpurWorldConfig { + + public boolean lavaInfinite = false; + public int lavaInfiniteRequiredSources = 2; ++ public int lavaSpeedNether = 10; ++ public int lavaSpeedNotNether = 30; + private void lavaSettings() { + lavaInfinite = getBoolean("blocks.lava.infinite-source", lavaInfinite); + lavaInfiniteRequiredSources = getInt("blocks.lava.infinite-required-sources", lavaInfiniteRequiredSources); ++ lavaSpeedNether = getInt("blocks.lava.speed.nether", lavaSpeedNether); ++ lavaSpeedNotNether = getInt("blocks.lava.speed.not-nether", lavaSpeedNotNether); + } + + public boolean signAllowColors = false; diff --git a/patches/Purpur/patches/server/0064-Add-player-death-exp-control-options.patch b/patches/Purpur/patches/server/0064-Add-player-death-exp-control-options.patch new file mode 100644 index 00000000..88084b0b --- /dev/null +++ b/patches/Purpur/patches/server/0064-Add-player-death-exp-control-options.patch @@ -0,0 +1,59 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Thu, 26 Dec 2019 22:08:37 -0600 +Subject: [PATCH] Add player death exp control options + + +diff --git a/src/main/java/net/minecraft/world/entity/player/EntityHuman.java b/src/main/java/net/minecraft/world/entity/player/EntityHuman.java +index afa14eddb6a21d4747689af6d70551f10d304be7..f9ce15aa4a2b1ee07f9c31b793410a4ff27ec829 100644 +--- a/src/main/java/net/minecraft/world/entity/player/EntityHuman.java ++++ b/src/main/java/net/minecraft/world/entity/player/EntityHuman.java +@@ -182,6 +182,8 @@ public abstract class EntityHuman extends EntityLiving { + // CraftBukkit end + + // Purpur start ++ private javax.script.ScriptEngine scriptEngine = new javax.script.ScriptEngineManager().getEngineByName("rhino"); ++ + public void setAfk(boolean setAfk){ + } + +@@ -1825,9 +1827,18 @@ public abstract class EntityHuman extends EntityLiving { + @Override + protected int getExpValue(EntityHuman entityhuman) { + if (!this.world.getGameRules().getBoolean(GameRules.KEEP_INVENTORY) && !this.isSpectator()) { +- int i = this.expLevel * 7; +- +- return i > 100 ? 100 : i; ++ // Purpur start ++ int toDrop; ++ try { ++ scriptEngine.eval("expLevel = " + expLevel); ++ scriptEngine.eval("expTotal = " + expTotal); ++ scriptEngine.eval("exp = " + exp); ++ toDrop = (int) Math.round((Double) scriptEngine.eval(world.purpurConfig.playerDeathExpDropEquation)); ++ } catch (Exception ignore) { ++ toDrop = expLevel * 7; ++ } ++ return Math.min(toDrop, world.purpurConfig.playerDeathExpDropMax); ++ // Purpur end + } else { + return 0; + } +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 21ecfc0a1ee6d39e0b824aa3ce146a8833bd20ce..32087bcc02c20448988c76e04dbc0dcc3db48641 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -157,6 +157,13 @@ public class PurpurWorldConfig { + tridentLoyaltyVoidReturnHeight = getDouble("gameplay-mechanics.trident-loyalty-void-return-height", tridentLoyaltyVoidReturnHeight); + } + ++ public String playerDeathExpDropEquation = "expLevel * 7"; ++ public int playerDeathExpDropMax = 100; ++ private void playerDeathExpSettings() { ++ playerDeathExpDropEquation = getString("gameplay-mechanics.player.exp-dropped-on-death.equation", playerDeathExpDropEquation); ++ playerDeathExpDropMax = getInt("gameplay-mechanics.player.exp-dropped-on-death.maximum", playerDeathExpDropMax); ++ } ++ + public int playerSpawnInvulnerableTicks = 60; + public boolean playerInvulnerableWhileAcceptingResourcePack = false; + private void playerInvulnerabilities() { diff --git a/patches/Purpur/patches/server/0065-Add-canSaveToDisk-to-Entity.patch b/patches/Purpur/patches/server/0065-Add-canSaveToDisk-to-Entity.patch new file mode 100644 index 00000000..83c0fc8f --- /dev/null +++ b/patches/Purpur/patches/server/0065-Add-canSaveToDisk-to-Entity.patch @@ -0,0 +1,35 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Tue, 18 Feb 2020 20:07:08 -0600 +Subject: [PATCH] Add canSaveToDisk to Entity + + +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index e458be6377595efed8dfb6527ab0b7a0f0f87d84..cfe6a52fa45c8dfcb2136978456b6abf7a32258c 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -444,6 +444,12 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, ne + this.headHeight = this.getHeadHeight(EntityPose.STANDING, this.size); + } + ++ // Purpur start ++ public boolean canSaveToDisk() { ++ return true; ++ } ++ // Purpur end ++ + public boolean isSpectator() { + return false; + } +diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkRegionLoader.java b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkRegionLoader.java +index ec2b238480413ba9c123d9ddeaa787d9520e1b74..3fbeb01275a48b4173f98ae0c7f09e4c0e6445e7 100644 +--- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkRegionLoader.java ++++ b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkRegionLoader.java +@@ -580,6 +580,7 @@ public class ChunkRegionLoader { + + while (iterator1.hasNext()) { + Entity entity = (Entity) iterator1.next(); ++ if (!entity.canSaveToDisk()) continue; // Purpur + final EntityTypes entityType = entity.getEntityType(); + final int saveLimit = worldserver.paperConfig.entityPerChunkSaveLimits.getOrDefault(entityType, -1); + if (saveLimit > -1) { diff --git a/patches/Purpur/patches/server/0066-Configurable-void-damage-height-and-damage.patch b/patches/Purpur/patches/server/0066-Configurable-void-damage-height-and-damage.patch new file mode 100644 index 00000000..ff217825 --- /dev/null +++ b/patches/Purpur/patches/server/0066-Configurable-void-damage-height-and-damage.patch @@ -0,0 +1,52 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Thu, 27 Feb 2020 21:42:19 -0600 +Subject: [PATCH] Configurable void damage height and damage + + +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index cfe6a52fa45c8dfcb2136978456b6abf7a32258c..b3618e2100404d1b13d2930d463b8e283ea62f64 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -747,7 +747,7 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, ne + + // Paper start + protected void performVoidDamage() { +- if (this.locY() < -64.0D || (this.world.getWorld().getEnvironment() == org.bukkit.World.Environment.NETHER ++ if (this.locY() < world.purpurConfig.voidDamageHeight || (this.world.getWorld().getEnvironment() == org.bukkit.World.Environment.NETHER // Purpur + && world.paperConfig.doNetherTopVoidDamage() + && this.locY() >= world.paperConfig.netherVoidTopDamageHeight)) { + this.doVoidDamage(); +diff --git a/src/main/java/net/minecraft/world/entity/EntityLiving.java b/src/main/java/net/minecraft/world/entity/EntityLiving.java +index efca085c5db03242b471db811c44224ca49eb305..e0b42e8db2e48f7327abfbb643ce4f14cc13a7af 100644 +--- a/src/main/java/net/minecraft/world/entity/EntityLiving.java ++++ b/src/main/java/net/minecraft/world/entity/EntityLiving.java +@@ -2113,7 +2113,7 @@ public abstract class EntityLiving extends Entity { + + @Override + protected void an() { +- this.damageEntity(DamageSource.OUT_OF_WORLD, 4.0F); ++ this.damageEntity(DamageSource.OUT_OF_WORLD, (float) world.purpurConfig.voidDamageDealt); + } + + protected void dA() { +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 32087bcc02c20448988c76e04dbc0dcc3db48641..0e715362fcfb3d26825b51f4fd96d8cba810bf55 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -150,11 +150,15 @@ public class PurpurWorldConfig { + public boolean entitiesPickUpLootBypassMobGriefing = false; + public boolean milkCuresBadOmen = true; + public double tridentLoyaltyVoidReturnHeight = 0.0D; ++ public double voidDamageHeight = -64.0D; ++ public double voidDamageDealt = 4.0D; + private void miscGameplayMechanicsSettings() { + disableDropsOnCrammingDeath = getBoolean("gameplay-mechanics.disable-drops-on-cramming-death", disableDropsOnCrammingDeath); + entitiesPickUpLootBypassMobGriefing = getBoolean("gameplay-mechanics.entities-pick-up-loot-bypass-mob-griefing", entitiesPickUpLootBypassMobGriefing); + milkCuresBadOmen = getBoolean("gameplay-mechanics.milk-cures-bad-omen", milkCuresBadOmen); + tridentLoyaltyVoidReturnHeight = getDouble("gameplay-mechanics.trident-loyalty-void-return-height", tridentLoyaltyVoidReturnHeight); ++ voidDamageHeight = getDouble("gameplay-mechanics.void-damage-height", voidDamageHeight); ++ voidDamageDealt = getDouble("gameplay-mechanics.void-damage-dealt", voidDamageDealt); + } + + public String playerDeathExpDropEquation = "expLevel * 7"; diff --git a/patches/Purpur/patches/server/0067-Dispenser-curse-of-binding-protection.patch b/patches/Purpur/patches/server/0067-Dispenser-curse-of-binding-protection.patch new file mode 100644 index 00000000..64be7324 --- /dev/null +++ b/patches/Purpur/patches/server/0067-Dispenser-curse-of-binding-protection.patch @@ -0,0 +1,69 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sun, 25 Aug 2019 00:09:52 -0500 +Subject: [PATCH] Dispenser curse of binding protection + + +diff --git a/src/main/java/net/minecraft/world/entity/EntityInsentient.java b/src/main/java/net/minecraft/world/entity/EntityInsentient.java +index 864b9bf8f41476e876fd386cdbfb007898584ad6..b70120c32027a456037daac363d420d2edd4bdfe 100644 +--- a/src/main/java/net/minecraft/world/entity/EntityInsentient.java ++++ b/src/main/java/net/minecraft/world/entity/EntityInsentient.java +@@ -65,6 +65,7 @@ import net.minecraft.world.item.ItemSword; + import net.minecraft.world.item.ItemTool; + import net.minecraft.world.item.Items; + import net.minecraft.world.item.enchantment.EnchantmentManager; ++import net.minecraft.world.item.enchantment.Enchantments; + import net.minecraft.world.level.GameRules; + import net.minecraft.world.level.GeneratorAccess; + import net.minecraft.world.level.IBlockAccess; +@@ -1068,6 +1069,13 @@ public abstract class EntityInsentient extends EntityLiving { + + } + ++ // Purpur start ++ public static EnumItemSlot getSlotForDispenser(ItemStack itemstack) { ++ return EnchantmentManager.getEnchantmentLevel(Enchantments.BINDING_CURSE, itemstack) > 0 ? EnumItemSlot.MAINHAND : getSlotForItemStack(itemstack); ++ } ++ // Purpur end ++ ++ public static EnumItemSlot getSlotForItemStack(ItemStack itemstack) { return j(itemstack); } // Purpur - OBFHELPER + public static EnumItemSlot j(ItemStack itemstack) { + Item item = itemstack.getItem(); + +diff --git a/src/main/java/net/minecraft/world/item/ItemArmor.java b/src/main/java/net/minecraft/world/item/ItemArmor.java +index 7962808aebf67cf9bc1dc4c1e106e943536fdced..d072b604a1cd8835c1fe658831cdaf9f27d02cd5 100644 +--- a/src/main/java/net/minecraft/world/item/ItemArmor.java ++++ b/src/main/java/net/minecraft/world/item/ItemArmor.java +@@ -54,7 +54,7 @@ public class ItemArmor extends Item implements ItemWearable { + return false; + } else { + EntityLiving entityliving = (EntityLiving) list.get(0); +- EnumItemSlot enumitemslot = EntityInsentient.j(itemstack); ++ EnumItemSlot enumitemslot = isourceblock.getWorld().purpurConfig.dispenserApplyCursedArmor ? EntityInsentient.getSlotForItemStack(itemstack) : EntityInsentient.getSlotForDispenser(itemstack); // Purpur + ItemStack itemstack1 = itemstack.cloneAndSubtract(1); + // CraftBukkit start + World world = isourceblock.getWorld(); +@@ -113,6 +113,7 @@ public class ItemArmor extends Item implements ItemWearable { + this.m = builder.build(); + } + ++ public EnumItemSlot getEquipmentSlot() { return b(); } // Purpur - OBFHELPER + public EnumItemSlot b() { + return this.b; + } +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 0e715362fcfb3d26825b51f4fd96d8cba810bf55..d5095a9b20118bf9c35346fce95a446254872832 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -198,6 +198,11 @@ public class PurpurWorldConfig { + }); + } + ++ public boolean dispenserApplyCursedArmor = true; ++ private void dispenserSettings() { ++ dispenserApplyCursedArmor = getBoolean("blocks.dispenser.apply-cursed-to-armor-slots", dispenserApplyCursedArmor); ++ } ++ + public boolean farmlandGetsMoistFromBelow = false; + private void farmlandSettings() { + farmlandGetsMoistFromBelow = getBoolean("blocks.farmland.gets-moist-from-below", farmlandGetsMoistFromBelow); diff --git a/patches/Purpur/patches/server/0068-Add-option-for-boats-to-eject-players-on-land.patch b/patches/Purpur/patches/server/0068-Add-option-for-boats-to-eject-players-on-land.patch new file mode 100644 index 00000000..ffcc4658 --- /dev/null +++ b/patches/Purpur/patches/server/0068-Add-option-for-boats-to-eject-players-on-land.patch @@ -0,0 +1,38 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sat, 7 Sep 2019 22:47:59 -0500 +Subject: [PATCH] Add option for boats to eject players on land + + +diff --git a/src/main/java/net/minecraft/world/entity/vehicle/EntityBoat.java b/src/main/java/net/minecraft/world/entity/vehicle/EntityBoat.java +index 5e2c13bd6e52ffe182ef034e05ba6fe1cb301005..01839c7319e175477ded7001e00e5937734ff516 100644 +--- a/src/main/java/net/minecraft/world/entity/vehicle/EntityBoat.java ++++ b/src/main/java/net/minecraft/world/entity/vehicle/EntityBoat.java +@@ -487,6 +487,7 @@ public class EntityBoat extends Entity { + + if (f > 0.0F) { + this.aw = f; ++ if (world.purpurConfig.boatEjectPlayersOnLand) ejectPassengers(); // Purpur + return EntityBoat.EnumStatus.ON_LAND; + } else { + return EntityBoat.EnumStatus.IN_AIR; +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index d5095a9b20118bf9c35346fce95a446254872832..06c6e181b753a840e0060539b6b0387a7a1511dc 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -146,6 +146,7 @@ public class PurpurWorldConfig { + idleTimeoutUpdateTabList = getBoolean("gameplay-mechanics.player.idle-timeout.update-tab-list", idleTimeoutUpdateTabList); + } + ++ public boolean boatEjectPlayersOnLand = false; + public boolean disableDropsOnCrammingDeath = false; + public boolean entitiesPickUpLootBypassMobGriefing = false; + public boolean milkCuresBadOmen = true; +@@ -153,6 +154,7 @@ public class PurpurWorldConfig { + public double voidDamageHeight = -64.0D; + public double voidDamageDealt = 4.0D; + private void miscGameplayMechanicsSettings() { ++ boatEjectPlayersOnLand = getBoolean("gameplay-mechanics.boat.eject-players-on-land", boatEjectPlayersOnLand); + disableDropsOnCrammingDeath = getBoolean("gameplay-mechanics.disable-drops-on-cramming-death", disableDropsOnCrammingDeath); + entitiesPickUpLootBypassMobGriefing = getBoolean("gameplay-mechanics.entities-pick-up-loot-bypass-mob-griefing", entitiesPickUpLootBypassMobGriefing); + milkCuresBadOmen = getBoolean("gameplay-mechanics.milk-cures-bad-omen", milkCuresBadOmen); diff --git a/patches/Purpur/patches/server/0069-Add-obfhelpers-for-plugin-use.patch b/patches/Purpur/patches/server/0069-Add-obfhelpers-for-plugin-use.patch new file mode 100644 index 00000000..3bfcad3a --- /dev/null +++ b/patches/Purpur/patches/server/0069-Add-obfhelpers-for-plugin-use.patch @@ -0,0 +1,18 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Wed, 1 Jan 2020 20:12:39 -0600 +Subject: [PATCH] Add obfhelpers for plugin use + + +diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java +index 366ceb65d40c685117d1c79a933864ab91d8aa11..a342174cf35ee6ac1f10028b60c5a19e1b547ef4 100644 +--- a/src/main/java/net/minecraft/world/item/ItemStack.java ++++ b/src/main/java/net/minecraft/world/item/ItemStack.java +@@ -694,6 +694,7 @@ public final class ItemStack { + return this.tag; + } + ++ public NBTTagCompound getOrCreateSubTag(String s) { return a(s); } // Purpur - OBFHELPER + public NBTTagCompound a(String s) { + if (this.tag != null && this.tag.hasKeyOfType(s, 10)) { + return this.tag.getCompound(s); diff --git a/patches/Purpur/patches/server/0070-Mending-mends-most-damages-equipment-first.patch b/patches/Purpur/patches/server/0070-Mending-mends-most-damages-equipment-first.patch new file mode 100644 index 00000000..67fe1f72 --- /dev/null +++ b/patches/Purpur/patches/server/0070-Mending-mends-most-damages-equipment-first.patch @@ -0,0 +1,99 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sun, 14 Jul 2019 19:52:47 -0500 +Subject: [PATCH] Mending mends most damages equipment first + + +diff --git a/src/main/java/net/minecraft/world/entity/EntityExperienceOrb.java b/src/main/java/net/minecraft/world/entity/EntityExperienceOrb.java +index a7551e95185895a290be70d501496279eaf884ae..31d36ead273e8397ba2c826b791a2cf59306ff7f 100644 +--- a/src/main/java/net/minecraft/world/entity/EntityExperienceOrb.java ++++ b/src/main/java/net/minecraft/world/entity/EntityExperienceOrb.java +@@ -236,7 +236,7 @@ public class EntityExperienceOrb extends Entity { + if (this.d == 0 && entityhuman.bu == 0 && new com.destroystokyo.paper.event.player.PlayerPickupExperienceEvent(((EntityPlayer) entityhuman).getBukkitEntity(), (org.bukkit.entity.ExperienceOrb) this.getBukkitEntity()).callEvent()) { // Paper + entityhuman.bu = 2; + entityhuman.receive(this, 1); +- Entry entry = EnchantmentManager.a(Enchantments.MENDING, (EntityLiving) entityhuman, ItemStack::f); ++ Entry entry = world.purpurConfig.useBetterMending ? EnchantmentManager.getMostDamagedEquipment(Enchantments.MENDING, entityhuman) : EnchantmentManager.a(Enchantments.MENDING, entityhuman, ItemStack::isDamaged); // Purpur + + if (entry != null) { + ItemStack itemstack = (ItemStack) entry.getValue(); +diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java +index a342174cf35ee6ac1f10028b60c5a19e1b547ef4..72400425d6177ba938057ec145f9499eb1160288 100644 +--- a/src/main/java/net/minecraft/world/item/ItemStack.java ++++ b/src/main/java/net/minecraft/world/item/ItemStack.java +@@ -468,10 +468,19 @@ public final class ItemStack { + } + } + ++ public boolean isDamaged() { return f(); } // Purpur - OBFHELPER + public boolean f() { + return this.e() && this.getDamage() > 0; + } + ++ public float getDamagePercent() { ++ if (isDamaged()) { ++ return (float) getDamage() / (float) getItem().getMaxDurability(); ++ } else { ++ return 0F; ++ } ++ } ++ + public int getDamage() { + return this.tag == null ? 0 : this.tag.getInt("Damage"); + } +diff --git a/src/main/java/net/minecraft/world/item/enchantment/EnchantmentManager.java b/src/main/java/net/minecraft/world/item/enchantment/EnchantmentManager.java +index 72afbf8f537770540e90a2880ea81de137ea10f5..b2d28c2bf0a9e93d38583e2d734c12fed4f63d5d 100644 +--- a/src/main/java/net/minecraft/world/item/enchantment/EnchantmentManager.java ++++ b/src/main/java/net/minecraft/world/item/enchantment/EnchantmentManager.java +@@ -269,7 +269,30 @@ public class EnchantmentManager { + return getEnchantmentLevel(Enchantments.CHANNELING, itemstack) > 0; + } + +- public static @javax.annotation.Nonnull ItemStack getRandomEquippedItemWithEnchant(Enchantment enchantment, EntityLiving entityliving) { Entry entry = b(enchantment, entityliving); return entry != null ? entry.getValue() : ItemStack.NULL_ITEM; } // Paper - OBFHELPER ++ // Purpur start ++ @Nullable ++ public static Entry getMostDamagedEquipment(Enchantment enchantment, EntityLiving entityliving) { ++ Map map = enchantment.a(entityliving); ++ if (map.isEmpty()) { ++ return null; ++ } ++ Entry item = null; ++ float maxPercent = 0F; ++ for (Entry entry : map.entrySet()) { ++ ItemStack itemstack = entry.getValue(); ++ if (!itemstack.isEmpty() && itemstack.isDamaged() && getEnchantmentLevel(enchantment, itemstack) > 0) { ++ float percent = itemstack.getDamagePercent(); ++ if (item == null || percent > maxPercent) { ++ item = entry; ++ maxPercent = percent; ++ } ++ } ++ } ++ return item; ++ } ++ // Purpur end ++ ++ public static @javax.annotation.Nonnull ItemStack getRandomEquippedItemWithEnchant(Enchantment enchantment, EntityLiving entityliving) { Entry entry = enchantment == Enchantments.MENDING && entityliving.world.purpurConfig.useBetterMending ? getMostDamagedEquipment(enchantment, entityliving) : b(enchantment, entityliving); return entry != null ? entry.getValue() : ItemStack.NULL_ITEM; } // Paper - OBFHELPER + @Nullable public static Entry b(Enchantment enchantment, EntityLiving entityliving) { + return a(enchantment, entityliving, (itemstack) -> { + return true; +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 06c6e181b753a840e0060539b6b0387a7a1511dc..ce1d33315a7999fb304d6f7d843ab3d1f415eb17 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -146,6 +146,7 @@ public class PurpurWorldConfig { + idleTimeoutUpdateTabList = getBoolean("gameplay-mechanics.player.idle-timeout.update-tab-list", idleTimeoutUpdateTabList); + } + ++ public boolean useBetterMending = false; + public boolean boatEjectPlayersOnLand = false; + public boolean disableDropsOnCrammingDeath = false; + public boolean entitiesPickUpLootBypassMobGriefing = false; +@@ -154,6 +155,7 @@ public class PurpurWorldConfig { + public double voidDamageHeight = -64.0D; + public double voidDamageDealt = 4.0D; + private void miscGameplayMechanicsSettings() { ++ useBetterMending = getBoolean("gameplay-mechanics.use-better-mending", useBetterMending); + boatEjectPlayersOnLand = getBoolean("gameplay-mechanics.boat.eject-players-on-land", boatEjectPlayersOnLand); + disableDropsOnCrammingDeath = getBoolean("gameplay-mechanics.disable-drops-on-cramming-death", disableDropsOnCrammingDeath); + entitiesPickUpLootBypassMobGriefing = getBoolean("gameplay-mechanics.entities-pick-up-loot-bypass-mob-griefing", entitiesPickUpLootBypassMobGriefing); diff --git a/patches/Purpur/patches/server/0071-Add-5-second-tps-average-in-tps.patch b/patches/Purpur/patches/server/0071-Add-5-second-tps-average-in-tps.patch new file mode 100644 index 00000000..64ddd371 --- /dev/null +++ b/patches/Purpur/patches/server/0071-Add-5-second-tps-average-in-tps.patch @@ -0,0 +1,95 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sun, 28 Jul 2019 01:27:37 -0500 +Subject: [PATCH] Add 5 second tps average in /tps + + +diff --git a/src/main/java/com/destroystokyo/paper/gui/RAMDetails.java b/src/main/java/com/destroystokyo/paper/gui/RAMDetails.java +index dc6bc1910ad0f9b27144d5750078c3ca607d03d3..e8be35f836ede2630d44902e99a21489a7bad61f 100644 +--- a/src/main/java/com/destroystokyo/paper/gui/RAMDetails.java ++++ b/src/main/java/com/destroystokyo/paper/gui/RAMDetails.java +@@ -58,7 +58,7 @@ public class RAMDetails extends JList { + GraphData data = RAMGraph.DATA.peekLast(); + Vector vector = new Vector<>(); + +- double[] tps = new double[] {server.tps1.getAverage(), server.tps5.getAverage(), server.tps15.getAverage()}; ++ double[] tps = new double[] {server.tps5s.getAverage(), server.tps1.getAverage(), server.tps5.getAverage(), server.tps15.getAverage()}; // Purpur + String[] tpsAvg = new String[tps.length]; + + for ( int g = 0; g < tps.length; g++) { +@@ -67,7 +67,7 @@ public class RAMDetails extends JList { + vector.add("Memory use: " + (data.getUsedMem() / 1024L / 1024L) + " mb (" + (data.getFree() * 100L / data.getMax()) + "% free)"); + vector.add("Heap: " + (data.getTotal() / 1024L / 1024L) + " / " + (data.getMax() / 1024L / 1024L) + " mb"); + vector.add("Avg tick: " + DECIMAL_FORMAT.format(getAverage(server.getTickTimes())) + " ms"); +- vector.add("TPS from last 1m, 5m, 15m: " + String.join(", ", tpsAvg)); ++ vector.add("TPS from last 5s, 1m, 5m, 15m: " + String.join(", ", tpsAvg)); // Purpur + + setListData(vector); + } +diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java +index d93ecf4b3451b1c3c309aadfe2ec287a68df0713..afe3c53252354760b22901f7f109fd5d265928e0 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -279,7 +279,7 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant 0 && args[0].equals("mem") && sender.hasPermission("bukkit.command.tpsmemory")) { + sender.sendMessage(ChatColor.GOLD + "Current Memory Usage: " + ChatColor.GREEN + ((Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / (1024 * 1024)) + "/" + (Runtime.getRuntime().totalMemory() / (1024 * 1024)) + " mb (Max: " + (Runtime.getRuntime().maxMemory() / (1024 * 1024)) + " mb)"); + if (!hasShownMemoryWarning) { diff --git a/patches/Purpur/patches/server/0072-Implement-elytra-settings.patch b/patches/Purpur/patches/server/0072-Implement-elytra-settings.patch new file mode 100644 index 00000000..b70b2a87 --- /dev/null +++ b/patches/Purpur/patches/server/0072-Implement-elytra-settings.patch @@ -0,0 +1,126 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Thu, 25 Jul 2019 18:07:37 -0500 +Subject: [PATCH] Implement elytra settings + + +diff --git a/src/main/java/net/minecraft/world/entity/EntityLiving.java b/src/main/java/net/minecraft/world/entity/EntityLiving.java +index e0b42e8db2e48f7327abfbb643ce4f14cc13a7af..4bac98718f67699433fdd89307c20438f3ee6425 100644 +--- a/src/main/java/net/minecraft/world/entity/EntityLiving.java ++++ b/src/main/java/net/minecraft/world/entity/EntityLiving.java +@@ -2952,7 +2952,16 @@ public abstract class EntityLiving extends Entity { + if (itemstack.getItem() == Items.ELYTRA && ItemElytra.d(itemstack)) { + flag = true; + if (!this.world.isClientSide && (this.be + 1) % 20 == 0) { +- itemstack.damage(1, this, (entityliving) -> { ++ // Purpur start ++ int damage = world.purpurConfig.elytraDamagePerSecond; ++ if (world.purpurConfig.elytraDamageMultiplyBySpeed > 0) { ++ double speed = getMot().magnitudeSquared(); ++ if (speed > world.purpurConfig.elytraDamageMultiplyBySpeed) { ++ damage *= (int) speed; ++ } ++ } ++ itemstack.damage(damage, this, (entityliving) -> { ++ // Purpur end + entityliving.broadcastItemBreak(EnumItemSlot.CHEST); + }); + } +diff --git a/src/main/java/net/minecraft/world/item/ItemFireworks.java b/src/main/java/net/minecraft/world/item/ItemFireworks.java +index e7f958d137257da912ce9b83db017b4423959943..210b95f1d67ec12566d6fc93b8234e11ad132d1a 100644 +--- a/src/main/java/net/minecraft/world/item/ItemFireworks.java ++++ b/src/main/java/net/minecraft/world/item/ItemFireworks.java +@@ -7,6 +7,7 @@ import net.minecraft.server.level.EntityPlayer; + import net.minecraft.world.EnumHand; + import net.minecraft.world.EnumInteractionResult; + import net.minecraft.world.InteractionResultWrapper; ++import net.minecraft.world.entity.EnumItemSlot; + import net.minecraft.world.entity.player.EntityHuman; + import net.minecraft.world.entity.projectile.EntityFireworks; + import net.minecraft.world.item.context.ItemActionContext; +@@ -53,6 +54,14 @@ public class ItemFireworks extends Item { + // Paper start + com.destroystokyo.paper.event.player.PlayerElytraBoostEvent event = new com.destroystokyo.paper.event.player.PlayerElytraBoostEvent((org.bukkit.entity.Player) entityhuman.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack), (org.bukkit.entity.Firework) entityfireworks.getBukkitEntity()); + if (event.callEvent() && world.addEntity(entityfireworks)) { ++ // Purpur start ++ if (world.purpurConfig.elytraDamagePerFireworkBoost > 0) { ++ ItemStack chestItem = entityhuman.getEquipment(EnumItemSlot.CHEST); ++ if (chestItem.getItem() == Items.ELYTRA) { ++ chestItem.damage(world.purpurConfig.elytraDamagePerFireworkBoost, entityhuman, (entityliving) -> entityliving.broadcastItemBreak(EnumItemSlot.CHEST)); ++ } ++ } ++ // Purpur end + if (event.shouldConsume() && !entityhuman.abilities.canInstantlyBuild) { + itemstack.subtract(1); + } else ((EntityPlayer) entityhuman).getBukkitEntity().updateInventory(); +diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java +index 72400425d6177ba938057ec145f9499eb1160288..2aa761656ce75f78732c502fd4ce65034b6c2919 100644 +--- a/src/main/java/net/minecraft/world/item/ItemStack.java ++++ b/src/main/java/net/minecraft/world/item/ItemStack.java +@@ -500,7 +500,7 @@ public final class ItemStack { + int j; + + if (i > 0) { +- j = EnchantmentManager.getEnchantmentLevel(Enchantments.DURABILITY, this); ++ j = (getItem() == Items.ELYTRA && entityplayer != null && entityplayer.world.purpurConfig.elytraIgnoreUnbreaking) ? 0 : EnchantmentManager.getEnchantmentLevel(Enchantments.DURABILITY, this); // Purpur + int k = 0; + + for (int l = 0; j > 0 && l < i; ++l) { +@@ -546,6 +546,12 @@ public final class ItemStack { + if (this.isDamaged(i, t0.getRandom(), t0 instanceof EntityPlayer ? (EntityPlayer) t0 : null)) { + consumer.accept(t0); + Item item = this.getItem(); ++ // Purpur start ++ if (item == Items.ELYTRA) { ++ setDamage(item.getMaxDurability() - 1); ++ return; ++ } ++ // Purpur end + // CraftBukkit start - Check for item breaking + if (this.count == 1 && t0 instanceof EntityHuman) { + org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerItemBreakEvent((EntityHuman) t0, this); +diff --git a/src/main/java/net/minecraft/world/item/ItemTrident.java b/src/main/java/net/minecraft/world/item/ItemTrident.java +index 9896477b54cf91a88bdfc3d85018a59193b32859..0711d195c654edef5875f587e391bacfdea096da 100644 +--- a/src/main/java/net/minecraft/world/item/ItemTrident.java ++++ b/src/main/java/net/minecraft/world/item/ItemTrident.java +@@ -123,6 +123,16 @@ public class ItemTrident extends Item implements ItemVanishable { + f2 *= f6 / f5; + f3 *= f6 / f5; + f4 *= f6 / f5; ++ ++ // Purpur start ++ ItemStack chestItem = entityhuman.getEquipment(EnumItemSlot.CHEST); ++ if (chestItem.getItem() == Items.ELYTRA && world.purpurConfig.elytraDamagePerTridentBoost > 0) { ++ chestItem.damage(world.purpurConfig.elytraDamagePerTridentBoost, entityhuman, (entity) -> { ++ entity.broadcastItemBreak(EnumItemSlot.CHEST); ++ }); ++ } ++ // Purpur end ++ + entityhuman.i((double) f2, (double) f3, (double) f4); + entityhuman.r(20); + if (entityhuman.isOnGround()) { +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index ce1d33315a7999fb304d6f7d843ab3d1f415eb17..5e577cd97df14463f590919b2931a5065ac37033 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -165,6 +165,19 @@ public class PurpurWorldConfig { + voidDamageDealt = getDouble("gameplay-mechanics.void-damage-dealt", voidDamageDealt); + } + ++ public int elytraDamagePerSecond = 1; ++ public double elytraDamageMultiplyBySpeed = 0; ++ public boolean elytraIgnoreUnbreaking = false; ++ public int elytraDamagePerFireworkBoost = 0; ++ public int elytraDamagePerTridentBoost = 0; ++ private void elytraSettings() { ++ elytraDamagePerSecond = getInt("gameplay-mechanics.elytra.damage-per-second", elytraDamagePerSecond); ++ elytraDamageMultiplyBySpeed = getDouble("gameplay-mechanics.elytra.damage-multiplied-by-speed", elytraDamageMultiplyBySpeed); ++ elytraIgnoreUnbreaking = getBoolean("gameplay-mechanics.elytra.ignore-unbreaking", elytraIgnoreUnbreaking); ++ elytraDamagePerFireworkBoost = getInt("gameplay-mechanics.elytra.damage-per-boost.firework", elytraDamagePerFireworkBoost); ++ elytraDamagePerTridentBoost = getInt("gameplay-mechanics.elytra.damage-per-boost.trident", elytraDamagePerTridentBoost); ++ } ++ + public String playerDeathExpDropEquation = "expLevel * 7"; + public int playerDeathExpDropMax = 100; + private void playerDeathExpSettings() { diff --git a/patches/Purpur/patches/server/0073-Item-entity-immunities.patch b/patches/Purpur/patches/server/0073-Item-entity-immunities.patch new file mode 100644 index 00000000..7296829a --- /dev/null +++ b/patches/Purpur/patches/server/0073-Item-entity-immunities.patch @@ -0,0 +1,212 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sat, 22 Feb 2020 15:54:08 -0600 +Subject: [PATCH] Item entity immunities + + +diff --git a/src/main/java/net/minecraft/server/level/EntityTrackerEntry.java b/src/main/java/net/minecraft/server/level/EntityTrackerEntry.java +index 53e773c14689967d5b12467bf209eefb05f7a812..b8f9238c598a55ba796951cb775cd35f3a401fa8 100644 +--- a/src/main/java/net/minecraft/server/level/EntityTrackerEntry.java ++++ b/src/main/java/net/minecraft/server/level/EntityTrackerEntry.java +@@ -67,7 +67,7 @@ public class EntityTrackerEntry { + private boolean q; + private boolean r; + // CraftBukkit start +- final Set trackedPlayers; // Paper - private -> package ++ public final Set trackedPlayers; // Paper - private -> public + // Paper start + private java.util.Map trackedPlayerMap = null; + +diff --git a/src/main/java/net/minecraft/server/level/PlayerChunkMap.java b/src/main/java/net/minecraft/server/level/PlayerChunkMap.java +index d827e18d8c3b9b5869dbb1e233f415ba0efb7c1b..d876c5037b4704a174606629c80ba1142c77a50c 100644 +--- a/src/main/java/net/minecraft/server/level/PlayerChunkMap.java ++++ b/src/main/java/net/minecraft/server/level/PlayerChunkMap.java +@@ -2431,7 +2431,7 @@ Sections go from 0..16. Now whenever a section is not empty, it can potentially + + public class EntityTracker { + +- final EntityTrackerEntry trackerEntry; // Paper - private -> package private ++ public final EntityTrackerEntry trackerEntry; // Paper - private -> package private // Purpur -> public + private final Entity tracker; + private final int trackingDistance; + private SectionPosition e; +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index b3618e2100404d1b13d2930d463b8e283ea62f64..d5882cac0dd43cea6e7184487e6d25fa34ebafc2 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -1608,6 +1608,7 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, ne + + } + ++ public boolean isInLiquid(Tag tag) { return a(tag); } // Purpur - OBFHELPER + public boolean a(Tag tag) { + return this.O == tag; + } +diff --git a/src/main/java/net/minecraft/world/entity/item/EntityItem.java b/src/main/java/net/minecraft/world/entity/item/EntityItem.java +index 077990f1d95ded2c8b89c38978ec25a56df3a984..be46b8fcbfed932ba96a34c94eee0b237c783bd4 100644 +--- a/src/main/java/net/minecraft/world/entity/item/EntityItem.java ++++ b/src/main/java/net/minecraft/world/entity/item/EntityItem.java +@@ -50,6 +50,12 @@ public class EntityItem extends Entity { + public final float b; + private int lastTick = MinecraftServer.currentTick - 1; // CraftBukkit + public boolean canMobPickup = true; // Paper ++ // Purpur start ++ public boolean immuneToCactus = false; ++ public boolean immuneToExplosion = false; ++ public boolean immuneToFire = false; ++ public boolean immuneToLightning = false; ++ // Purpur end + + public EntityItem(EntityTypes entitytypes, World world) { + super(entitytypes, world); +@@ -309,6 +315,16 @@ public class EntityItem extends Entity { + return false; + } else if (!this.getItemStack().getItem().a(damagesource)) { + return false; ++ // Purpur start ++ } else if ( ++ (immuneToCactus && damagesource == DamageSource.CACTUS) || ++ (immuneToFire && (damagesource.isFire() || damagesource == DamageSource.FIRE)) || ++ (immuneToLightning && damagesource == DamageSource.LIGHTNING) || ++ (immuneToExplosion && damagesource.isExplosion()) ++ ) { ++ respawnOnClient(); ++ return false; ++ // Purpur end + } else { + // CraftBukkit start + if (org.bukkit.craftbukkit.event.CraftEventFactory.handleNonLivingEntityDamageEvent(this, damagesource, f)) { +@@ -489,6 +505,12 @@ public class EntityItem extends Entity { + com.google.common.base.Preconditions.checkArgument(!itemstack.isEmpty(), "Cannot drop air"); // CraftBukkit + this.getDataWatcher().set(EntityItem.ITEM, itemstack); + this.getDataWatcher().markDirty(EntityItem.ITEM); // CraftBukkit - SPIGOT-4591, must mark dirty ++ // Purpur start ++ if (world.purpurConfig.itemImmuneToCactus.contains(itemstack.getItem())) immuneToCactus = true; ++ if (world.purpurConfig.itemImmuneToExplosion.contains(itemstack.getItem())) immuneToExplosion = true; ++ if (world.purpurConfig.itemImmuneToFire.contains(itemstack.getItem())) immuneToFire = true; ++ if (world.purpurConfig.itemImmuneToLightning.contains(itemstack.getItem())) immuneToLightning = true; ++ // Purpur end + } + + @Override +@@ -570,4 +592,15 @@ public class EntityItem extends Entity { + super.setPositionRaw(x, y, z); + } + // Paper end - fix MC-4 ++ ++ // Purpur start ++ public void respawnOnClient() { ++ Packet spawnPacket = new PacketPlayOutSpawnEntity(this); ++ Packet metadataPacket = new net.minecraft.network.protocol.game.PacketPlayOutEntityMetadata(getId(), getDataWatcher(), true); ++ for (net.minecraft.server.level.EntityPlayer entityplayer : this.tracker.trackerEntry.trackedPlayers) { ++ entityplayer.playerConnection.sendPacket(spawnPacket); ++ entityplayer.playerConnection.sendPacket(metadataPacket); ++ } ++ } ++ // Purpur end + } +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 5e577cd97df14463f590919b2931a5065ac37033..dfcceebc9fbfa62fc14f3c53217af8e39025307d 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -135,6 +135,49 @@ public class PurpurWorldConfig { + } + } + ++ public List itemImmuneToCactus = new ArrayList<>(); ++ public List itemImmuneToExplosion = new ArrayList<>(); ++ public List itemImmuneToFire = new ArrayList<>(); ++ public List itemImmuneToLightning = new ArrayList<>(); ++ private void itemSettings() { ++ itemImmuneToCactus.clear(); ++ getList("gameplay-mechanics.item.immune.cactus", new ArrayList<>()).forEach(key -> { ++ if (key.toString().equals("*")) { ++ IRegistry.ITEM.g().filter(item -> item != Items.AIR).forEach((item) -> itemImmuneToCactus.add(item)); ++ return; ++ } ++ Item item = IRegistry.ITEM.get(new MinecraftKey(key.toString())); ++ if (item != Items.AIR) itemImmuneToCactus.add(item); ++ }); ++ itemImmuneToExplosion.clear(); ++ getList("gameplay-mechanics.item.immune.explosion", new ArrayList<>()).forEach(key -> { ++ if (key.toString().equals("*")) { ++ IRegistry.ITEM.g().filter(item -> item != Items.AIR).forEach((item) -> itemImmuneToExplosion.add(item)); ++ return; ++ } ++ Item item = IRegistry.ITEM.get(new MinecraftKey(key.toString())); ++ if (item != Items.AIR) itemImmuneToExplosion.add(item); ++ }); ++ itemImmuneToFire.clear(); ++ getList("gameplay-mechanics.item.immune.fire", new ArrayList<>()).forEach(key -> { ++ if (key.toString().equals("*")) { ++ IRegistry.ITEM.g().filter(item -> item != Items.AIR).forEach((item) -> itemImmuneToFire.add(item)); ++ return; ++ } ++ Item item = IRegistry.ITEM.get(new MinecraftKey(key.toString())); ++ if (item != Items.AIR) itemImmuneToFire.add(item); ++ }); ++ itemImmuneToLightning.clear(); ++ getList("gameplay-mechanics.item.immune.lightning", new ArrayList<>()).forEach(key -> { ++ if (key.toString().equals("*")) { ++ IRegistry.ITEM.g().filter(item -> item != Items.AIR).forEach((item) -> itemImmuneToLightning.add(item)); ++ return; ++ } ++ Item item = IRegistry.ITEM.get(new MinecraftKey(key.toString())); ++ if (item != Items.AIR) itemImmuneToLightning.add(item); ++ }); ++ } ++ + public boolean idleTimeoutKick = true; + public boolean idleTimeoutTickNearbyEntities = true; + public boolean idleTimeoutCountAsSleeping = false; +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java +index 7a78ef2f6f673568c0528fa46168c69d21f51a66..f91a04abe39f9a75530a213cd84e5024059752d1 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java +@@ -114,4 +114,46 @@ public class CraftItem extends CraftEntity implements Item { + public EntityType getType() { + return EntityType.DROPPED_ITEM; + } ++ ++ // Purpur start ++ @Override ++ public void setImmuneToCactus(boolean immuneToCactus) { ++ item.immuneToCactus = immuneToCactus; ++ } ++ ++ @Override ++ public boolean isImmuneToCactus() { ++ return item.immuneToCactus; ++ } ++ ++ @Override ++ public void setImmuneToExplosion(boolean immuneToExplosion) { ++ item.immuneToExplosion = immuneToExplosion; ++ } ++ ++ @Override ++ public boolean isImmuneToExplosion() { ++ return item.immuneToExplosion; ++ } ++ ++ @Override ++ public void setImmuneToFire(boolean immuneToFire) { ++ item.immuneToFire = immuneToFire; ++ } ++ ++ @Override ++ public boolean isImmuneToFire() { ++ return item.immuneToFire; ++ } ++ ++ @Override ++ public void setImmuneToLightning(boolean immuneToLightning) { ++ item.immuneToLightning = immuneToLightning; ++ } ++ ++ @Override ++ public boolean isImmuneToLightning() { ++ return item.immuneToLightning; ++ } ++ // Purpur end + } diff --git a/patches/Purpur/patches/server/0074-Add-ping-command.patch b/patches/Purpur/patches/server/0074-Add-ping-command.patch new file mode 100644 index 00000000..41c2e37e --- /dev/null +++ b/patches/Purpur/patches/server/0074-Add-ping-command.patch @@ -0,0 +1,128 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Fri, 13 Mar 2020 22:29:10 -0500 +Subject: [PATCH] Add /ping command + + +diff --git a/src/main/java/net/minecraft/commands/CommandDispatcher.java b/src/main/java/net/minecraft/commands/CommandDispatcher.java +index b1bfc42b4153b225243ba65e7f937c0314cb39a5..185dee82b86aa3abb04809ddcf31c81e29664c62 100644 +--- a/src/main/java/net/minecraft/commands/CommandDispatcher.java ++++ b/src/main/java/net/minecraft/commands/CommandDispatcher.java +@@ -191,6 +191,7 @@ public class CommandDispatcher { + CommandIdleTimeout.a(this.b); + CommandStop.a(this.b); + CommandWhitelist.a(this.b); ++ net.pl3x.purpur.command.PingCommand.register(getDispatcher()); // Purpur + } + + if (commanddispatcher_servertype.d) { +@@ -428,10 +429,12 @@ public class CommandDispatcher { + + } + ++ public static LiteralArgumentBuilder literal(String s) { return a(s); } // Purpur - OBFHELPER + public static LiteralArgumentBuilder a(String s) { + return LiteralArgumentBuilder.literal(s); + } + ++ public static RequiredArgumentBuilder argument(String s, ArgumentType argumenttype) { return a(s, argumenttype); } // Purpur - OBFHELPER + public static RequiredArgumentBuilder a(String s, ArgumentType argumenttype) { + return RequiredArgumentBuilder.argument(s, argumenttype); + } +@@ -447,6 +450,7 @@ public class CommandDispatcher { + }; + } + ++ public com.mojang.brigadier.CommandDispatcher getDispatcher() { return a(); } // Purpur - OBFHELPER + public com.mojang.brigadier.CommandDispatcher a() { return this.dispatcher(); } public com.mojang.brigadier.CommandDispatcher dispatcher() { // Paper - OBFHELPER + return this.b; + } +diff --git a/src/main/java/net/minecraft/commands/CommandListenerWrapper.java b/src/main/java/net/minecraft/commands/CommandListenerWrapper.java +index 8402af32cc476d7f468842eb4f34c7521d72bcc8..4480fe75cfad35a5104b5116c5ec2c80d18f15f5 100644 +--- a/src/main/java/net/minecraft/commands/CommandListenerWrapper.java ++++ b/src/main/java/net/minecraft/commands/CommandListenerWrapper.java +@@ -211,6 +211,7 @@ public class CommandListenerWrapper implements ICompletionProvider, com.destroys + } + } + ++ public EntityPlayer getPlayerOrException() throws CommandSyntaxException { return h(); } // Purpur - OBFHELPER + public EntityPlayer h() throws CommandSyntaxException { + if (!(this.k instanceof EntityPlayer)) { + throw CommandListenerWrapper.a.create(); +diff --git a/src/main/java/net/minecraft/commands/arguments/ArgumentEntity.java b/src/main/java/net/minecraft/commands/arguments/ArgumentEntity.java +index bbad2b1399d9d2e16bfa77563bd564f7c6f640d7..a85c4525335fa46bc23a6dd57cfaea1f697b3daa 100644 +--- a/src/main/java/net/minecraft/commands/arguments/ArgumentEntity.java ++++ b/src/main/java/net/minecraft/commands/arguments/ArgumentEntity.java +@@ -78,10 +78,12 @@ public class ArgumentEntity implements ArgumentType { + return ((EntitySelector) commandcontext.getArgument(s, EntitySelector.class)).c((CommandListenerWrapper) commandcontext.getSource()); + } + ++ public static ArgumentEntity players() { return d(); } // Purpur - OBFHELPER + public static ArgumentEntity d() { + return new ArgumentEntity(false, true); + } + ++ public static Collection getPlayers(CommandContext commandcontext, String s) throws CommandSyntaxException { return f(commandcontext, s); } // Purpur - OBFHELPER + public static Collection f(CommandContext commandcontext, String s) throws CommandSyntaxException { + List list = ((EntitySelector) commandcontext.getArgument(s, EntitySelector.class)).d((CommandListenerWrapper) commandcontext.getSource()); + +diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java +index 8d27fff773b74014351bfbfeed0197272234be4a..b1b12a46f0b662aff24357b407b65124428ecfaa 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java +@@ -133,10 +133,12 @@ public class PurpurConfig { + public static String afkBroadcastAway = "§e§o%s is now AFK"; + public static String afkBroadcastBack = "§e§o%s is no longer AFK"; + public static String afkTabListPrefix = "[AFK] "; ++ public static String pingCommandOutput = "§a%s's ping is %sms"; + private static void messages() { + afkBroadcastAway = getString("settings.messages.afk-broadcast-away", afkBroadcastAway); + afkBroadcastBack = getString("settings.messages.afk-broadcast-back", afkBroadcastBack); + afkTabListPrefix = getString("settings.messages.afk-tab-list-prefix", afkTabListPrefix); ++ pingCommandOutput = getString("settings.messages.ping-command-output", pingCommandOutput); + } + + public static String serverModName = "Purpur"; +diff --git a/src/main/java/net/pl3x/purpur/command/PingCommand.java b/src/main/java/net/pl3x/purpur/command/PingCommand.java +new file mode 100644 +index 0000000000000000000000000000000000000000..1d636d7c541d127a473d5be2509e5db29936e8ad +--- /dev/null ++++ b/src/main/java/net/pl3x/purpur/command/PingCommand.java +@@ -0,0 +1,37 @@ ++package net.pl3x.purpur.command; ++ ++import net.minecraft.commands.arguments.ArgumentEntity; ++import net.minecraft.commands.CommandDispatcher; ++import net.minecraft.commands.CommandListenerWrapper; ++import net.minecraft.server.level.EntityPlayer; ++import net.pl3x.purpur.PurpurConfig; ++import org.bukkit.craftbukkit.util.CraftChatMessage; ++ ++import java.util.Collection; ++import java.util.Collections; ++ ++public class PingCommand { ++ public static void register(com.mojang.brigadier.CommandDispatcher dispatcher) { ++ dispatcher.register(CommandDispatcher.literal("ping") ++ .requires((listener) -> { ++ return listener.hasPermission(2); ++ }) ++ .executes((context) -> { ++ return execute(context.getSource(), Collections.singleton(context.getSource().getPlayerOrException())); ++ }) ++ .then(CommandDispatcher.argument("targets", ArgumentEntity.players()) ++ .executes((context) -> { ++ return execute(context.getSource(), ArgumentEntity.getPlayers(context, "targets")); ++ }) ++ ) ++ ).setPermission("bukkit.command.ping"); ++ } ++ ++ private static int execute(CommandListenerWrapper sender, Collection targets) { ++ for (EntityPlayer player : targets) { ++ String output = String.format(PurpurConfig.pingCommandOutput, player.getProfile().getName(), player.ping); ++ sender.sendMessage(CraftChatMessage.fromStringOrNull(output), false); ++ } ++ return targets.size(); ++ } ++} diff --git a/patches/Purpur/patches/server/0075-Configurable-jockey-options.patch b/patches/Purpur/patches/server/0075-Configurable-jockey-options.patch new file mode 100644 index 00000000..fae4b907 --- /dev/null +++ b/patches/Purpur/patches/server/0075-Configurable-jockey-options.patch @@ -0,0 +1,266 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Thu, 26 Mar 2020 21:39:32 -0500 +Subject: [PATCH] Configurable jockey options + + +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityDrowned.java b/src/main/java/net/minecraft/world/entity/monster/EntityDrowned.java +index e4794760fc918cccbdc3f8d10ab21dd9b6f29e8e..ea776755767f29e49de2792afa30f79420d0fa4c 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityDrowned.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityDrowned.java +@@ -72,6 +72,23 @@ public class EntityDrowned extends EntityZombie implements IRangedEntity { + this.navigationLand = new Navigation(this, world); + } + ++ // Purpur start ++ @Override ++ public boolean jockeyOnlyBaby() { ++ return world.purpurConfig.drownedJockeyOnlyBaby; ++ } ++ ++ @Override ++ public double jockeyChance() { ++ return world.purpurConfig.drownedJockeyChance; ++ } ++ ++ @Override ++ public boolean jockeyTryExistingChickens() { ++ return world.purpurConfig.drownedJockeyTryExistingChickens; ++ } ++ // Purpur end ++ + @Override + protected void m() { + this.goalSelector.a(1, new EntityDrowned.c(this, 1.0D)); +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityPigZombie.java b/src/main/java/net/minecraft/world/entity/monster/EntityPigZombie.java +index d10d1b768601236b9892461ee41d61c7239d1a07..ee17e62d996d81ea149a5c0eae2e29404e363dcf 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityPigZombie.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityPigZombie.java +@@ -56,6 +56,23 @@ public class EntityPigZombie extends EntityZombie implements IEntityAngerable { + this.a(PathType.LAVA, 8.0F); + } + ++ // Purpur start ++ @Override ++ public boolean jockeyOnlyBaby() { ++ return world.purpurConfig.zombifiedPiglinJockeyOnlyBaby; ++ } ++ ++ @Override ++ public double jockeyChance() { ++ return world.purpurConfig.zombifiedPiglinJockeyChance; ++ } ++ ++ @Override ++ public boolean jockeyTryExistingChickens() { ++ return world.purpurConfig.zombifiedPiglinJockeyTryExistingChickens; ++ } ++ // Purpur end ++ + @Override + public void setAngerTarget(@Nullable UUID uuid) { + this.br = uuid; +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityZombie.java b/src/main/java/net/minecraft/world/entity/monster/EntityZombie.java +index 634416c354184bc6a2348c27c55e9868009ccd28..5ac950614fc90d02a568bb38f71faee124584c16 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityZombie.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityZombie.java +@@ -3,6 +3,7 @@ package net.minecraft.world.entity.monster; + import com.mojang.serialization.DynamicOps; + import java.time.LocalDate; + import java.time.temporal.ChronoField; ++import java.util.Collections; + import java.util.List; + import java.util.Random; + import java.util.UUID; +@@ -106,6 +107,20 @@ public class EntityZombie extends EntityMonster { + this(EntityTypes.ZOMBIE, world); + } + ++ // Purpur start ++ public boolean jockeyOnlyBaby() { ++ return world.purpurConfig.zombieJockeyOnlyBaby; ++ } ++ ++ public double jockeyChance() { ++ return world.purpurConfig.zombieJockeyChance; ++ } ++ ++ public boolean jockeyTryExistingChickens() { ++ return world.purpurConfig.zombieJockeyTryExistingChickens; ++ } ++ // Purpur end ++ + @Override + protected void initPathfinder() { + if (world.paperConfig.zombiesTargetTurtleEggs) this.goalSelector.a(4, new EntityZombie.a(this, 1.0D, 3)); // Paper +@@ -506,19 +521,19 @@ public class EntityZombie extends EntityMonster { + if (object instanceof EntityZombie.GroupDataZombie) { + EntityZombie.GroupDataZombie entityzombie_groupdatazombie = (EntityZombie.GroupDataZombie) object; + +- if (entityzombie_groupdatazombie.a) { +- this.setBaby(true); ++ // Purpur start ++ if (!jockeyOnlyBaby() || entityzombie_groupdatazombie.isBaby()) { ++ this.setBaby(entityzombie_groupdatazombie.isBaby()); + if (entityzombie_groupdatazombie.b) { +- if ((double) worldaccess.getRandom().nextFloat() < 0.05D) { +- List list = worldaccess.a(EntityChicken.class, this.getBoundingBox().grow(5.0D, 3.0D, 5.0D), IEntitySelector.c); ++ if ((double) worldaccess.getRandom().nextFloat() < jockeyChance()) { ++ List list = jockeyTryExistingChickens() ? worldaccess.a(EntityChicken.class, this.getBoundingBox().grow(5.0D, 3.0D, 5.0D), IEntitySelector.c) : Collections.emptyList(); + + if (!list.isEmpty()) { + EntityChicken entitychicken = (EntityChicken) list.get(0); + + entitychicken.setChickenJockey(true); + this.startRiding(entitychicken); +- } +- } else if ((double) worldaccess.getRandom().nextFloat() < 0.05D) { ++ } else { // Purpur + EntityChicken entitychicken1 = (EntityChicken) EntityTypes.CHICKEN.a(this.world); + + entitychicken1.setPositionRotation(this.locX(), this.locY(), this.locZ(), this.yaw, 0.0F); +@@ -526,6 +541,7 @@ public class EntityZombie extends EntityMonster { + entitychicken1.setChickenJockey(true); + this.startRiding(entitychicken1); + worldaccess.addEntity(entitychicken1, CreatureSpawnEvent.SpawnReason.MOUNT); // CraftBukkit ++ } // Purpur + } + } + } +@@ -628,7 +644,7 @@ public class EntityZombie extends EntityMonster { + + public static class GroupDataZombie implements GroupDataEntity { + +- public final boolean a; ++ public final boolean a; public boolean isBaby() { return a; } // Purpur - OBFHELPER + public final boolean b; + + public GroupDataZombie(boolean flag, boolean flag1) { +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityZombieHusk.java b/src/main/java/net/minecraft/world/entity/monster/EntityZombieHusk.java +index ce08413134de6101420ccb957da925ea1e3b0884..5d3e5873f19aaf8389eb5525693b9378ea9f94ee 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityZombieHusk.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityZombieHusk.java +@@ -22,6 +22,23 @@ public class EntityZombieHusk extends EntityZombie { + super(entitytypes, world); + } + ++ // Purpur start ++ @Override ++ public boolean jockeyOnlyBaby() { ++ return world.purpurConfig.huskJockeyOnlyBaby; ++ } ++ ++ @Override ++ public double jockeyChance() { ++ return world.purpurConfig.huskJockeyChance; ++ } ++ ++ @Override ++ public boolean jockeyTryExistingChickens() { ++ return world.purpurConfig.huskJockeyTryExistingChickens; ++ } ++ // Purpur end ++ + public static boolean a(EntityTypes entitytypes, WorldAccess worldaccess, EnumMobSpawn enummobspawn, BlockPosition blockposition, Random random) { + return b(entitytypes, worldaccess, enummobspawn, blockposition, random) && (enummobspawn == EnumMobSpawn.SPAWNER || worldaccess.e(blockposition)); + } +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityZombieVillager.java b/src/main/java/net/minecraft/world/entity/monster/EntityZombieVillager.java +index f341759f6110b51c856de09248d2f523c58aa712..99d0932e5352589cfbcc48a5e789651d0d77edde 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityZombieVillager.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityZombieVillager.java +@@ -70,6 +70,23 @@ public class EntityZombieVillager extends EntityZombie implements VillagerDataHo + this.setVillagerData(this.getVillagerData().withProfession((VillagerProfession) IRegistry.VILLAGER_PROFESSION.a(this.random))); + } + ++ // Purpur start ++ @Override ++ public boolean jockeyOnlyBaby() { ++ return world.purpurConfig.zombieVillagerJockeyOnlyBaby; ++ } ++ ++ @Override ++ public double jockeyChance() { ++ return world.purpurConfig.zombieVillagerJockeyChance; ++ } ++ ++ @Override ++ public boolean jockeyTryExistingChickens() { ++ return world.purpurConfig.zombieVillagerJockeyTryExistingChickens; ++ } ++ // Purpur end ++ + @Override + protected void initDatawatcher() { + super.initDatawatcher(); +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index dfcceebc9fbfa62fc14f3c53217af8e39025307d..a12c2ae8291114f17bbb05761272bf724f848b1c 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -321,6 +321,15 @@ public class PurpurWorldConfig { + creeperChargedChance = getDouble("mobs.creeper.naturally-charged-chance", creeperChargedChance); + } + ++ public boolean drownedJockeyOnlyBaby = true; ++ public double drownedJockeyChance = 0.05D; ++ public boolean drownedJockeyTryExistingChickens = true; ++ private void drownedSettings() { ++ drownedJockeyOnlyBaby = getBoolean("mobs.drowned.jockey.only-babies", drownedJockeyOnlyBaby); ++ drownedJockeyChance = getDouble("mobs.drowned.jockey.chance", drownedJockeyChance); ++ drownedJockeyTryExistingChickens = getBoolean("mobs.drowned.jockey.try-existing-chickens", drownedJockeyTryExistingChickens); ++ } ++ + public boolean enderDragonAlwaysDropsFullExp = false; + private void enderDragonSettings() { + enderDragonAlwaysDropsFullExp = getBoolean("mobs.ender_dragon.always-drop-full-exp", enderDragonAlwaysDropsFullExp); +@@ -358,6 +367,15 @@ public class PurpurWorldConfig { + giantMaxHealth = getDouble("mobs.giant.attributes.max-health", giantMaxHealth); + } + ++ public boolean huskJockeyOnlyBaby = true; ++ public double huskJockeyChance = 0.05D; ++ public boolean huskJockeyTryExistingChickens = true; ++ private void huskSettings() { ++ huskJockeyOnlyBaby = getBoolean("mobs.husk.jockey.only-babies", huskJockeyOnlyBaby); ++ huskJockeyChance = getDouble("mobs.husk.jockey.chance", huskJockeyChance); ++ huskJockeyTryExistingChickens = getBoolean("mobs.husk.jockey.try-existing-chickens", huskJockeyTryExistingChickens); ++ } ++ + public double illusionerMovementSpeed = 0.5D; + public double illusionerFollowRange = 18.0D; + public double illusionerMaxHealth = 32.0D; +@@ -433,8 +451,35 @@ public class PurpurWorldConfig { + witherSkeletonTakesWitherDamage = getBoolean("mobs.wither_skeleton.takes-wither-damage", witherSkeletonTakesWitherDamage); + } + ++ public boolean zombieJockeyOnlyBaby = true; ++ public double zombieJockeyChance = 0.05D; ++ public boolean zombieJockeyTryExistingChickens = true; ++ private void zombieSettings() { ++ zombieJockeyOnlyBaby = getBoolean("mobs.zombie.jockey.only-babies", zombieJockeyOnlyBaby); ++ zombieJockeyChance = getDouble("mobs.zombie.jockey.chance", zombieJockeyChance); ++ zombieJockeyTryExistingChickens = getBoolean("mobs.zombie.jockey.try-existing-chickens", zombieJockeyTryExistingChickens); ++ } ++ + public double zombieHorseSpawnChance = 0.0D; + private void zombieHorseSettings() { + zombieHorseSpawnChance = getDouble("mobs.zombie_horse.spawn-chance", zombieHorseSpawnChance); + } ++ ++ public boolean zombifiedPiglinJockeyOnlyBaby = true; ++ public double zombifiedPiglinJockeyChance = 0.05D; ++ public boolean zombifiedPiglinJockeyTryExistingChickens = true; ++ private void zombifiedPiglinSettings() { ++ zombifiedPiglinJockeyOnlyBaby = getBoolean("mobs.zombified_piglin.jockey.only-babies", zombifiedPiglinJockeyOnlyBaby); ++ zombifiedPiglinJockeyChance = getDouble("mobs.zombified_piglin.jockey.chance", zombifiedPiglinJockeyChance); ++ zombifiedPiglinJockeyTryExistingChickens = getBoolean("mobs.zombified_piglin.jockey.try-existing-chickens", zombifiedPiglinJockeyTryExistingChickens); ++ } ++ ++ public boolean zombieVillagerJockeyOnlyBaby = true; ++ public double zombieVillagerJockeyChance = 0.05D; ++ public boolean zombieVillagerJockeyTryExistingChickens = true; ++ private void zombieVillagerSettings() { ++ zombieVillagerJockeyOnlyBaby = getBoolean("mobs.zombie_villager.jockey.only-babies", zombieVillagerJockeyOnlyBaby); ++ zombieVillagerJockeyChance = getDouble("mobs.zombie_villager.jockey.chance", zombieVillagerJockeyChance); ++ zombieVillagerJockeyTryExistingChickens = getBoolean("mobs.zombie_villager.jockey.try-existing-chickens", zombieVillagerJockeyTryExistingChickens); ++ } + } diff --git a/patches/Purpur/patches/server/0076-Phantoms-attracted-to-crystals-and-crystals-shoot-ph.patch b/patches/Purpur/patches/server/0076-Phantoms-attracted-to-crystals-and-crystals-shoot-ph.patch new file mode 100644 index 00000000..7936c330 --- /dev/null +++ b/patches/Purpur/patches/server/0076-Phantoms-attracted-to-crystals-and-crystals-shoot-ph.patch @@ -0,0 +1,359 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Thu, 9 May 2019 18:26:06 -0500 +Subject: [PATCH] Phantoms attracted to crystals and crystals shoot phantoms + + +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index d5882cac0dd43cea6e7184487e6d25fa34ebafc2..6dc051e0da0a97bcd9e4cba94c2cabc411ebb86f 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -2279,8 +2279,8 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, ne + return this.a(new ItemStack(imaterial), (float) i); + } + +- @Nullable +- public EntityItem a(ItemStack itemstack) { ++ @Nullable public EntityItem dropItem(ItemStack itemstack) { return this.a(itemstack); } // Purpur - OBFHELPER ++ @Nullable public EntityItem a(ItemStack itemstack) { + return this.a(itemstack, 0.0F); + } + +diff --git a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EntityEnderCrystal.java b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EntityEnderCrystal.java +index 5d48c2640f776c9e29598e19afe779ed6997acfc..4cd5d2de76e785e839c3b3a78d55f2304d9aa4c3 100644 +--- a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EntityEnderCrystal.java ++++ b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EntityEnderCrystal.java +@@ -14,6 +14,7 @@ import net.minecraft.server.level.WorldServer; + import net.minecraft.world.damagesource.DamageSource; + import net.minecraft.world.entity.Entity; + import net.minecraft.world.entity.EntityTypes; ++import net.minecraft.world.entity.monster.EntityPhantom; + import net.minecraft.world.level.Explosion; + import net.minecraft.world.level.IBlockAccess; + import net.minecraft.world.level.World; +@@ -31,6 +32,12 @@ public class EntityEnderCrystal extends Entity { + private static final DataWatcherObject d = DataWatcher.a(EntityEnderCrystal.class, DataWatcherRegistry.i); + public int b; + public boolean generatedByDragonFight = false; // Paper - Fix invulnerable end crystals ++ // Purpur start ++ private EntityPhantom targetPhantom; ++ private int phantomBeamTicks = 0; ++ private int phantomDamageCooldown = 0; ++ private int idleCooldown = 0; ++ // Purpur end + + public EntityEnderCrystal(EntityTypes entitytypes, World world) { + super(entitytypes, world); +@@ -80,7 +87,50 @@ public class EntityEnderCrystal extends Entity { + // Paper end + } + ++ // Purpur start ++ if (world.purpurConfig.phantomAttackedByCrystalRadius <= 0 || --idleCooldown > 0) { ++ return; // on cooldown ++ } ++ ++ if (targetPhantom == null) { ++ for (EntityPhantom phantom : world.getEntitiesInAABB(EntityPhantom.class, getBoundingBox().grow(world.purpurConfig.phantomAttackedByCrystalRadius))) { ++ if (phantom.hasLineOfSight(this)) { ++ attackPhantom(phantom); ++ break; ++ } ++ } ++ } else { ++ setBeamTarget(new BlockPosition(targetPhantom).add(0, -2, 0)); ++ if (--phantomBeamTicks > 0 && targetPhantom.isAlive()) { ++ phantomDamageCooldown--; ++ if (targetPhantom.hasLineOfSight(this)) { ++ if (phantomDamageCooldown <= 0) { ++ phantomDamageCooldown = 20; ++ targetPhantom.damageEntity(DamageSource.indirectMagic(this, this), world.purpurConfig.phantomAttackedByCrystalDamage); ++ } ++ } else { ++ forgetPhantom(); // no longer in sight ++ } ++ } else { ++ forgetPhantom(); // attacked long enough ++ } ++ } ++ } ++ ++ private void attackPhantom(EntityPhantom phantom) { ++ phantomDamageCooldown = 0; ++ phantomBeamTicks = 60; ++ targetPhantom = phantom; ++ } ++ ++ private void forgetPhantom() { ++ targetPhantom = null; ++ setBeamTarget(null); ++ phantomBeamTicks = 0; ++ phantomDamageCooldown = 0; ++ idleCooldown = 60; + } ++ // Purpur end + + @Override + protected void saveData(NBTTagCompound nbttagcompound) { +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityPhantom.java b/src/main/java/net/minecraft/world/entity/monster/EntityPhantom.java +index 16c0c960aa1e4d35093b810c7648b5638175e106..e20b26ae0435c593218541eba6c68ef297fea7c8 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityPhantom.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityPhantom.java +@@ -12,6 +12,7 @@ import net.minecraft.nbt.NBTTagCompound; + import net.minecraft.network.syncher.DataWatcher; + import net.minecraft.network.syncher.DataWatcherObject; + import net.minecraft.network.syncher.DataWatcherRegistry; ++import net.minecraft.server.level.WorldServer; + import net.minecraft.sounds.SoundCategory; + import net.minecraft.sounds.SoundEffect; + import net.minecraft.sounds.SoundEffects; +@@ -36,18 +37,23 @@ import net.minecraft.world.entity.ai.control.EntityAIBodyControl; + import net.minecraft.world.entity.ai.goal.PathfinderGoal; + import net.minecraft.world.entity.ai.targeting.PathfinderTargetCondition; + import net.minecraft.world.entity.animal.EntityCat; ++import net.minecraft.world.entity.boss.enderdragon.EntityEnderCrystal; + import net.minecraft.world.entity.player.EntityHuman; ++import net.minecraft.world.item.ItemStack; ++import net.minecraft.world.item.Items; + import net.minecraft.world.level.World; + import net.minecraft.world.level.WorldAccess; + import net.minecraft.world.level.levelgen.HeightMap; ++import net.minecraft.world.level.storage.loot.LootTableInfo; + import net.minecraft.world.phys.Vec3D; + + public class EntityPhantom extends EntityFlying implements IMonster { + + private static final DataWatcherObject b = DataWatcher.a(EntityPhantom.class, DataWatcherRegistry.b); +- private Vec3D c; +- private BlockPosition d; +- private EntityPhantom.AttackPhase bo; ++ private Vec3D c; public void setHomeOffset(Vec3D offset) { this.c = offset; } public Vec3D getHomeOffset() { return this.c; } // Purpur - OBFHELPER ++ private BlockPosition d; public void setHome(BlockPosition home) { this.d = home; } public BlockPosition getHome() { return this.d; } // Purpur - OBFHELPER ++ private EntityPhantom.AttackPhase bo; public AttackPhase getAttackPhase() { return this.bo; } // Purpur - OBFHELPER ++ private Vec3D crystalPosition; // Purpur + + public EntityPhantom(EntityTypes entitytypes, World world) { + super(entitytypes, world); +@@ -66,11 +72,37 @@ public class EntityPhantom extends EntityFlying implements IMonster { + + @Override + protected void initPathfinder() { +- this.goalSelector.a(1, new EntityPhantom.c()); +- this.goalSelector.a(2, new EntityPhantom.i()); +- this.goalSelector.a(3, new EntityPhantom.e()); +- this.targetSelector.a(1, new EntityPhantom.b()); ++ // Purpur start ++ if (world.purpurConfig.phantomOrbitCrystalRadius > 0) { ++ this.goalSelector.a(1, new FindCrystalGoal(this)); ++ this.goalSelector.a(2, new OrbitCrystalGoal(this)); ++ } ++ this.goalSelector.a(3, new EntityPhantom.c()); // PickAttackGoal ++ this.goalSelector.a(4, new EntityPhantom.i()); // SweepAttackGoal ++ this.goalSelector.a(5, new EntityPhantom.e()); // OrbitPointGoal ++ this.targetSelector.a(1, new EntityPhantom.b()); // AttackPlayer Goal ++ // Purpur end ++ } ++ ++ // Purpur start ++ @Override ++ protected LootTableInfo.Builder a(boolean wasRecentlyHit, DamageSource damagesource) { // dropLoot ++ boolean dropped = false; ++ if (killer == null && damagesource.getEntity() instanceof EntityEnderCrystal) { ++ if (random.nextInt(5) < 1) { // 1 out of 5 chance (20%) ++ dropped = dropItem(new ItemStack(Items.PHANTOM_MEMBRANE)) != null; ++ } ++ } ++ if (!dropped) { ++ return super.a(wasRecentlyHit, damagesource); // dropLoot ++ } ++ return new LootTableInfo.Builder((WorldServer) world); ++ } ++ ++ public boolean isCirclingCrystal() { ++ return crystalPosition != null; + } ++ // Purpur end + + @Override + protected void initDatawatcher() { +@@ -241,6 +273,136 @@ public class EntityPhantom extends EntityFlying implements IMonster { + public void setShouldBurnInDay(boolean shouldBurnInDay) { this.shouldBurnInDay = shouldBurnInDay; } + // Paper end + ++ // Purpur start ++ class FindCrystalGoal extends PathfinderGoal { ++ private final EntityPhantom phantom; ++ private EntityEnderCrystal crystal; ++ private java.util.Comparator comparator; ++ ++ FindCrystalGoal(EntityPhantom phantom) { ++ this.phantom = phantom; ++ comparator = java.util.Comparator.comparingDouble(phantom::h); ++ this.a(EnumSet.of(PathfinderGoal.Type.LOOK)); ++ } ++ ++ @Override ++ public boolean a() { // shouldExecute ++ double range = maxTargetRange(); ++ List crystals = world.getEntitiesInAABB(EntityEnderCrystal.class, phantom.getBoundingBox().grow(range)); ++ if (crystals.isEmpty()) { ++ return false; ++ } ++ crystals.sort(comparator); ++ crystal = crystals.get(0); ++ if (phantom.getDistanceSquared(crystal) > range * range) { ++ crystal = null; ++ return false; ++ } ++ return true; ++ } ++ ++ @Override ++ public boolean b() { // shouldContinueExecuting ++ if (crystal == null || !crystal.isAlive()) { ++ return false; ++ } ++ double range = maxTargetRange(); ++ return phantom.getDistanceSquared(crystal) <= (range * range) * 2; ++ } ++ ++ @Override ++ public void c() { // startExecuting ++ phantom.crystalPosition = new Vec3D(crystal.locX(), crystal.locY() + (phantom.getRandom().nextInt(10) + 10), crystal.locZ()); ++ } ++ ++ @Override ++ public void d() { // resetTask ++ crystal = null; ++ phantom.crystalPosition = null; ++ super.d(); ++ } ++ ++ private double maxTargetRange() { ++ return phantom.world.purpurConfig.phantomOrbitCrystalRadius; ++ } ++ ++ class DistanceComparator implements java.util.Comparator { ++ private final Entity entity; ++ ++ public DistanceComparator(Entity entity) { ++ this.entity = entity; ++ } ++ ++ public int compare(Entity entity1, Entity entity2) { ++ return Double.compare(entity.getDistanceSquared(entity1), entity.getDistanceSquared(entity2)); ++ } ++ } ++ } ++ ++ class OrbitCrystalGoal extends PathfinderGoal { ++ private final EntityPhantom phantom; ++ private float offset; ++ private float radius; ++ private float verticalChange; ++ private float direction; ++ ++ OrbitCrystalGoal(EntityPhantom phantom) { ++ this.phantom = phantom; ++ this.a(EnumSet.of(PathfinderGoal.Type.MOVE)); ++ } ++ ++ @Override ++ public boolean a() { // shouldExecute ++ return phantom.isCirclingCrystal(); ++ } ++ ++ @Override ++ public void c() { // startExecuting ++ this.radius = 5.0F + phantom.random.nextFloat() * 10.0F; ++ this.verticalChange = -4.0F + phantom.random.nextFloat() * 9.0F; ++ this.direction = phantom.random.nextBoolean() ? 1.0F : -1.0F; ++ updateOffset(); ++ } ++ ++ @Override ++ public void e() { // tick ++ if (phantom.random.nextInt(350) == 0) { ++ this.verticalChange = -4.0F + phantom.random.nextFloat() * 9.0F; ++ } ++ if (phantom.random.nextInt(250) == 0) { ++ ++this.radius; ++ if (this.radius > 15.0F) { ++ this.radius = 5.0F; ++ this.direction = -this.direction; ++ } ++ } ++ if (phantom.random.nextInt(450) == 0) { ++ this.offset = phantom.random.nextFloat() * 2.0F * 3.1415927F; ++ updateOffset(); ++ } ++ if (phantom.getHomeOffset().c(phantom.locX(), phantom.locY(), phantom.locZ()) < 4.0D) { ++ updateOffset(); ++ } ++ if (phantom.getHomeOffset().y < phantom.locY() && !phantom.world.isEmpty((new BlockPosition(phantom)).down(1))) { ++ this.verticalChange = Math.max(1.0F, this.verticalChange); ++ updateOffset(); ++ } ++ if (phantom.getHomeOffset().y > phantom.locY() && !phantom.world.isEmpty((new BlockPosition(phantom)).up(1))) { ++ this.verticalChange = Math.min(-1.0F, this.verticalChange); ++ updateOffset(); ++ } ++ } ++ ++ private void updateOffset() { ++ this.offset += this.direction * 15.0F * 0.017453292F; ++ phantom.setHomeOffset(phantom.crystalPosition.add( ++ this.radius * MathHelper.cos(this.offset), ++ -4.0F + this.verticalChange, ++ this.radius * MathHelper.sin(this.offset))); ++ } ++ } ++ // Purpur end ++ + class b extends PathfinderGoal { + + private final PathfinderTargetCondition b; +@@ -253,6 +415,7 @@ public class EntityPhantom extends EntityFlying implements IMonster { + + @Override + public boolean a() { ++ if (isCirclingCrystal()) return false; // Purpur - pathfinder does not have a flag + if (this.c > 0) { + --this.c; + return false; +@@ -281,6 +444,7 @@ public class EntityPhantom extends EntityFlying implements IMonster { + + @Override + public boolean b() { ++ if (isCirclingCrystal()) return false; // Purpur - pathfinder does not have a flag + EntityLiving entityliving = EntityPhantom.this.getGoalTarget(); + + return entityliving != null ? EntityPhantom.this.a(entityliving, PathfinderTargetCondition.a) : false; +@@ -295,6 +459,7 @@ public class EntityPhantom extends EntityFlying implements IMonster { + + @Override + public boolean a() { ++ if (isCirclingCrystal()) return false; // Purpur - pathfinder does not have a flag + EntityLiving entityliving = EntityPhantom.this.getGoalTarget(); + + return entityliving != null ? EntityPhantom.this.a(EntityPhantom.this.getGoalTarget(), PathfinderTargetCondition.a) : false; +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index a12c2ae8291114f17bbb05761272bf724f848b1c..3aec221db2cd425bc5188979bb0fc0625ca40f4a 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -395,6 +395,15 @@ public class PurpurWorldConfig { + ironGolemCanSwim = getBoolean("mobs.iron_golem.can-swim", ironGolemCanSwim); + } + ++ public double phantomAttackedByCrystalRadius = 0.0D; ++ public float phantomAttackedByCrystalDamage = 1.0F; ++ public double phantomOrbitCrystalRadius = 0.0D; ++ private void phantomSettings() { ++ phantomAttackedByCrystalRadius = getDouble("mobs.phantom.attacked-by-crystal-range", phantomAttackedByCrystalRadius); ++ phantomAttackedByCrystalDamage = (float) getDouble("mobs.phantom.attacked-by-crystal-damage", phantomAttackedByCrystalDamage); ++ phantomOrbitCrystalRadius = getDouble("mobs.phantom.orbit-crystal-radius", phantomOrbitCrystalRadius); ++ } ++ + public boolean pigGiveSaddleBack = false; + private void pigSettings() { + pigGiveSaddleBack = getBoolean("mobs.pig.give-saddle-back", pigGiveSaddleBack); diff --git a/patches/Purpur/patches/server/0077-Add-phantom-spawning-options.patch b/patches/Purpur/patches/server/0077-Add-phantom-spawning-options.patch new file mode 100644 index 00000000..ae1424d4 --- /dev/null +++ b/patches/Purpur/patches/server/0077-Add-phantom-spawning-options.patch @@ -0,0 +1,302 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Fri, 3 Jul 2020 00:03:52 -0500 +Subject: [PATCH] Add phantom spawning options + + +diff --git a/src/main/java/net/minecraft/world/DifficultyDamageScaler.java b/src/main/java/net/minecraft/world/DifficultyDamageScaler.java +index c2fe4329576e6dcd5df435bc580d79a2b6db1fcd..44f19d8c8f5d344b2659cf01eb4be40f5510a2c2 100644 +--- a/src/main/java/net/minecraft/world/DifficultyDamageScaler.java ++++ b/src/main/java/net/minecraft/world/DifficultyDamageScaler.java +@@ -14,6 +14,7 @@ public class DifficultyDamageScaler { + this.b = this.a(enumdifficulty, i, j, f); + } + ++ public EnumDifficulty getGlobalDifficulty() { return a(); } // Purpur - OBFHELPER + public EnumDifficulty a() { + return this.a; + } +@@ -22,6 +23,7 @@ public class DifficultyDamageScaler { + return this.b; + } + ++ public boolean isHarderThan(float f) { return a(f); } // Purpur - OBFHELPER + public boolean a(float f) { + return this.b > f; + } +diff --git a/src/main/java/net/minecraft/world/EnumDifficulty.java b/src/main/java/net/minecraft/world/EnumDifficulty.java +index 53fac6aa71938805264b7cc4769e63a9d4a66114..a1a80aab7ef6fdb2a35082fa452d0b46c1fcdcbe 100644 +--- a/src/main/java/net/minecraft/world/EnumDifficulty.java ++++ b/src/main/java/net/minecraft/world/EnumDifficulty.java +@@ -21,6 +21,7 @@ public enum EnumDifficulty { + this.g = s; + } + ++ public int getId() { return a(); } // Purpur - OBFHELPER + public int a() { + return this.f; + } +diff --git a/src/main/java/net/minecraft/world/level/IBlockLightAccess.java b/src/main/java/net/minecraft/world/level/IBlockLightAccess.java +index 8b2e57c833c03940f2e0727e00decce59f263269..642bf019d32a2fdc18718337ecfe45d24022f8bd 100644 +--- a/src/main/java/net/minecraft/world/level/IBlockLightAccess.java ++++ b/src/main/java/net/minecraft/world/level/IBlockLightAccess.java +@@ -15,6 +15,7 @@ public interface IBlockLightAccess extends IBlockAccess { + return this.e().b(blockposition, i); + } + ++ default boolean isSkyVisible(BlockPosition blockposition) { return e(blockposition); } // Purpur - OBFHELPER + default boolean e(BlockPosition blockposition) { + return this.getBrightness(EnumSkyBlock.SKY, blockposition) >= this.K(); + } +diff --git a/src/main/java/net/minecraft/world/level/SpawnerCreature.java b/src/main/java/net/minecraft/world/level/SpawnerCreature.java +index 9b55da1f4d40ae36b2d2b8e7b3b18989dc4f6006..050651462390f0896f0629408d0f7d29d35bdb7f 100644 +--- a/src/main/java/net/minecraft/world/level/SpawnerCreature.java ++++ b/src/main/java/net/minecraft/world/level/SpawnerCreature.java +@@ -428,6 +428,7 @@ public final class SpawnerCreature { + return new BlockPosition(i, l, j); + } + ++ public static boolean canSpawn(IBlockAccess iblockaccess, BlockPosition blockposition, IBlockData iblockdata, Fluid fluid, EntityTypes entitytypes) { return a(iblockaccess, blockposition, iblockdata, fluid, entitytypes); } // Purpur - OBFHELPER + public static boolean a(IBlockAccess iblockaccess, BlockPosition blockposition, IBlockData iblockdata, Fluid fluid, EntityTypes entitytypes) { + return iblockdata.r(iblockaccess, blockposition) ? false : (iblockdata.isPowerSource() ? false : (!fluid.isEmpty() ? false : (iblockdata.a((Tag) TagsBlock.PREVENT_MOB_SPAWNING_INSIDE) ? false : !entitytypes.a(iblockdata)))); + } +diff --git a/src/main/java/net/minecraft/world/level/World.java b/src/main/java/net/minecraft/world/level/World.java +index 22d91a970c7376aa6349bb6cd9cb174e89bc8a09..7133b814b414a8aae2f056b9205cf58ca68ab887 100644 +--- a/src/main/java/net/minecraft/world/level/World.java ++++ b/src/main/java/net/minecraft/world/level/World.java +@@ -1664,6 +1664,7 @@ public abstract class World implements GeneratorAccess, AutoCloseable { + return new DifficultyDamageScaler(this.getDifficulty(), this.getDayTime(), i, f); + } + ++ public int getSkyDarkness() { return c(); } // Purpur - OBFHELPER + @Override + public int c() { + return this.d; +diff --git a/src/main/java/net/minecraft/world/level/levelgen/MobSpawnerPhantom.java b/src/main/java/net/minecraft/world/level/levelgen/MobSpawnerPhantom.java +index e4f5e570636862481aac92ec9b74d6cf5723eb6e..e954adeff4fbfc1aa85ac3785c0c4c86bde24cdb 100644 +--- a/src/main/java/net/minecraft/world/level/levelgen/MobSpawnerPhantom.java ++++ b/src/main/java/net/minecraft/world/level/levelgen/MobSpawnerPhantom.java +@@ -1,9 +1,6 @@ + package net.minecraft.world.level.levelgen; + +-import java.util.Iterator; +-import java.util.Random; + import net.minecraft.core.BlockPosition; +-import net.minecraft.nbt.NBTTagCompound; + import net.minecraft.server.MCUtil; + import net.minecraft.server.level.EntityPlayer; + import net.minecraft.server.level.WorldServer; +@@ -15,92 +12,103 @@ import net.minecraft.world.entity.EntityTypes; + import net.minecraft.world.entity.EnumMobSpawn; + import net.minecraft.world.entity.GroupDataEntity; + import net.minecraft.world.entity.monster.EntityPhantom; +-import net.minecraft.world.entity.player.EntityHuman; + import net.minecraft.world.level.GameRules; +-import net.minecraft.world.level.IBlockAccess; + import net.minecraft.world.level.MobSpawner; + import net.minecraft.world.level.SpawnerCreature; +-import net.minecraft.world.level.World; +-import net.minecraft.world.level.block.state.IBlockData; +-import net.minecraft.world.level.material.Fluid; ++import com.destroystokyo.paper.event.entity.PhantomPreSpawnEvent; ++import org.bukkit.event.entity.CreatureSpawnEvent; + + public class MobSpawnerPhantom implements MobSpawner { +- +- private int a; ++ private int spawnDelay; + + public MobSpawnerPhantom() {} + + @Override +- public int a(WorldServer worldserver, boolean flag, boolean flag1) { +- if (!flag) { ++ public int a(WorldServer world, boolean allowMonsters, boolean allowAnimals) { ++ // Purpur start - rewrite entire thing ++ if (!allowMonsters) { ++ return 0; ++ } ++ ++ if (!world.getGameRules().getBoolean(GameRules.DO_INSOMNIA)) { + return 0; +- } else if (!worldserver.getGameRules().getBoolean(GameRules.DO_INSOMNIA)) { ++ } ++ ++ --this.spawnDelay; ++ if (this.spawnDelay > 0) { + return 0; +- } else { +- Random random = worldserver.random; +- +- --this.a; +- if (this.a > 0) { +- return 0; +- } else { +- this.a += (60 + random.nextInt(60)) * 20; +- if (worldserver.c() < 5 && worldserver.getDimensionManager().hasSkyLight()) { +- return 0; +- } else { +- int i = 0; +- Iterator iterator = worldserver.getPlayers().iterator(); +- +- while (iterator.hasNext()) { +- EntityHuman entityhuman = (EntityHuman) iterator.next(); +- +- if (!entityhuman.isSpectator() && (!worldserver.paperConfig.phantomIgnoreCreative || !entityhuman.isCreative())) { // Paper +- BlockPosition blockposition = entityhuman.getChunkCoordinates(); +- +- if (!worldserver.getDimensionManager().hasSkyLight() || blockposition.getY() >= worldserver.getSeaLevel() && worldserver.e(blockposition)) { +- DifficultyDamageScaler difficultydamagescaler = worldserver.getDamageScaler(blockposition); +- +- if (difficultydamagescaler.a(random.nextFloat() * 3.0F)) { +- ServerStatisticManager serverstatisticmanager = ((EntityPlayer) entityhuman).getStatisticManager(); +- int j = MathHelper.clamp(serverstatisticmanager.getStatisticValue(StatisticList.CUSTOM.b(StatisticList.TIME_SINCE_REST)), 1, Integer.MAX_VALUE); +- boolean flag2 = true; +- +- if (random.nextInt(j) >= 72000) { +- BlockPosition blockposition1 = blockposition.up(20 + random.nextInt(15)).east(-10 + random.nextInt(21)).south(-10 + random.nextInt(21)); +- IBlockData iblockdata = worldserver.getType(blockposition1); +- Fluid fluid = worldserver.getFluid(blockposition1); +- +- if (SpawnerCreature.a((IBlockAccess) worldserver, blockposition1, iblockdata, fluid, EntityTypes.PHANTOM)) { +- GroupDataEntity groupdataentity = null; +- int k = 1 + random.nextInt(difficultydamagescaler.a().a() + 1); +- +- for (int l = 0; l < k; ++l) { +- // Paper start +- com.destroystokyo.paper.event.entity.PhantomPreSpawnEvent event = new com.destroystokyo.paper.event.entity.PhantomPreSpawnEvent(MCUtil.toLocation(worldserver, blockposition1), ((EntityPlayer) entityhuman).getBukkitEntity(), org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.NATURAL); +- if (!event.callEvent()) { +- if (event.shouldAbortSpawn()) { +- break; +- } +- continue; +- } +- // Paper end +- EntityPhantom entityphantom = (EntityPhantom) EntityTypes.PHANTOM.a((World) worldserver); +- entityphantom.setSpawningEntity(entityhuman.getUniqueID()); // Paper +- entityphantom.setPositionRotation(blockposition1, 0.0F, 0.0F); +- groupdataentity = entityphantom.prepare(worldserver, difficultydamagescaler, EnumMobSpawn.NATURAL, groupdataentity, (NBTTagCompound) null); +- worldserver.addAllEntities(entityphantom, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.NATURAL); // CraftBukkit +- } +- +- i += k; +- } +- } +- } +- } +- } ++ } ++ this.spawnDelay += world.purpurConfig.phantomSpawnDelayMin + world.random.nextInt(world.purpurConfig.phantomSpawnDelayMax - world.purpurConfig.phantomSpawnDelayMin); ++ ++ if (!world.getDimensionManager().hasSkyLight() || world.getSkyDarkness() < world.purpurConfig.phantomSpawnMinSkyDarkness) { ++ return 0; ++ } ++ ++ int numberSpawnsAttempted = 0; ++ for (EntityPlayer player : world.getPlayers()) { ++ if (player.isSpectator() || (player.isCreative() && world.paperConfig.phantomIgnoreCreative)) { // Paper ++ continue; ++ } ++ ++ BlockPosition playerPos = player.getChunkCoordinates(); ++ if (playerPos.getY() < world.getSeaLevel() && world.purpurConfig.phantomSpawnOnlyAboveSeaLevel) { ++ continue; ++ } ++ ++ if (!world.isSkyVisible(playerPos) && world.purpurConfig.phantomSpawnOnlyWithVisibleSky) { ++ continue; ++ } ++ ++ DifficultyDamageScaler dmgScaler = world.getDamageScaler(playerPos); ++ if (!dmgScaler.isHarderThan(world.random.nextFloat() * (float) world.purpurConfig.phantomSpawnLocalDifficultyChance)) { ++ continue; ++ } ++ ++ ServerStatisticManager stats = player.getStatisticManager(); ++ int timeSinceRest = MathHelper.clamp(stats.getStatisticValue(StatisticList.CUSTOM.get(StatisticList.TIME_SINCE_REST)), 1, Integer.MAX_VALUE); ++ if (world.random.nextInt(timeSinceRest) < world.purpurConfig.phantomSpawnMinTimeSinceSlept) { ++ continue; ++ } ++ ++ BlockPosition spawnPos = playerPos ++ .up(world.purpurConfig.phantomSpawnMinOverhead + world.random.nextInt(world.purpurConfig.phantomSpawnMaxOverhead - world.purpurConfig.phantomSpawnMinOverhead)) ++ .east(-world.purpurConfig.phantomSpawnOverheadRadius + world.random.nextInt(world.purpurConfig.phantomSpawnOverheadRadius + 1)) ++ .south(-world.purpurConfig.phantomSpawnOverheadRadius + world.random.nextInt(world.purpurConfig.phantomSpawnOverheadRadius + 1)); ++ ++ if (!SpawnerCreature.canSpawn(world, spawnPos, world.getType(spawnPos), world.getFluid(spawnPos), EntityTypes.PHANTOM)) { ++ continue; ++ } ++ ++ int difficulty = dmgScaler.getGlobalDifficulty().getId(); ++ int spawnAttempts = world.purpurConfig.phantomSpawnMinPerAttempt + world.random.nextInt((world.purpurConfig.phantomSpawnMaxPerAttempt < 0 ? difficulty : world.purpurConfig.phantomSpawnMaxPerAttempt) + world.purpurConfig.phantomSpawnMinPerAttempt); ++ ++ GroupDataEntity groupData = null; ++ for (int count = 0; count < spawnAttempts; ++count) { ++ // Paper start ++ PhantomPreSpawnEvent event = new PhantomPreSpawnEvent(MCUtil.toLocation(world, spawnPos), player.getBukkitEntity(), CreatureSpawnEvent.SpawnReason.NATURAL); ++ if (!event.callEvent()) { ++ if (event.shouldAbortSpawn()) { ++ break; + } ++ continue; ++ } ++ // Paper end + +- return i; ++ EntityPhantom phantom = EntityTypes.PHANTOM.create(world); ++ if (phantom == null) { ++ continue; + } ++ ++ phantom.setSpawningEntity(player.getUniqueID()); // Paper ++ phantom.setPositionRotation(spawnPos, 0.0F, 0.0F); ++ groupData = phantom.prepare(world, dmgScaler, EnumMobSpawn.NATURAL, groupData, null); ++ world.addEntity(phantom, CreatureSpawnEvent.SpawnReason.NATURAL); // CraftBukkit + } ++ ++ numberSpawnsAttempted += spawnAttempts; + } ++ ++ return numberSpawnsAttempted; ++ // Purpur end - rewrite entire thing + } + } +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 3aec221db2cd425bc5188979bb0fc0625ca40f4a..d957ee4c10fde8596442f2f05f0347994df7bae5 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -398,10 +398,34 @@ public class PurpurWorldConfig { + public double phantomAttackedByCrystalRadius = 0.0D; + public float phantomAttackedByCrystalDamage = 1.0F; + public double phantomOrbitCrystalRadius = 0.0D; ++ public int phantomSpawnDelayMin = 1200; ++ public int phantomSpawnDelayMax = 2400; ++ public int phantomSpawnMinSkyDarkness = 5; ++ public boolean phantomSpawnOnlyAboveSeaLevel = true; ++ public boolean phantomSpawnOnlyWithVisibleSky = true; ++ public double phantomSpawnLocalDifficultyChance = 3.0D; ++ public int phantomSpawnMinTimeSinceSlept = 72000; ++ public int phantomSpawnMinOverhead = 20; ++ public int phantomSpawnMaxOverhead = 35; ++ public int phantomSpawnOverheadRadius = 10; ++ public int phantomSpawnMinPerAttempt = 1; ++ public int phantomSpawnMaxPerAttempt = -1; + private void phantomSettings() { + phantomAttackedByCrystalRadius = getDouble("mobs.phantom.attacked-by-crystal-range", phantomAttackedByCrystalRadius); + phantomAttackedByCrystalDamage = (float) getDouble("mobs.phantom.attacked-by-crystal-damage", phantomAttackedByCrystalDamage); + phantomOrbitCrystalRadius = getDouble("mobs.phantom.orbit-crystal-radius", phantomOrbitCrystalRadius); ++ phantomSpawnDelayMin = getInt("mobs.phantom.spawn.delay.min", phantomSpawnDelayMin); ++ phantomSpawnDelayMax = getInt("mobs.phantom.spawn.delay.max", phantomSpawnDelayMax); ++ phantomSpawnMinSkyDarkness = getInt("mobs.phantom.spawn.min-sky-darkness", phantomSpawnMinSkyDarkness); ++ phantomSpawnOnlyAboveSeaLevel = getBoolean("mobs.phantom.spawn.only-above-sea-level", phantomSpawnOnlyAboveSeaLevel); ++ phantomSpawnOnlyWithVisibleSky = getBoolean("mobs.phantom.spawn.only-with-visible-sky", phantomSpawnOnlyWithVisibleSky); ++ phantomSpawnLocalDifficultyChance = getDouble("mobs.phantom.spawn.local-difficulty-chance", phantomSpawnLocalDifficultyChance); ++ phantomSpawnMinTimeSinceSlept = getInt("mobs.phantom.spawn.min-time-since-slept", phantomSpawnMinTimeSinceSlept); ++ phantomSpawnMinOverhead = getInt("mobs.phantom.spawn.overhead.min", phantomSpawnMinOverhead); ++ phantomSpawnMaxOverhead = getInt("mobs.phantom.spawn.overhead.max", phantomSpawnMaxOverhead); ++ phantomSpawnOverheadRadius = getInt("mobs.phantom.spawn.overhead.radius", phantomSpawnOverheadRadius); ++ phantomSpawnMinPerAttempt = getInt("mobs.phantom.spawn.per-attempt.min", phantomSpawnMinPerAttempt); ++ phantomSpawnMaxPerAttempt = getInt("mobs.phantom.spawn.per-attempt.max", phantomSpawnMaxPerAttempt); + } + + public boolean pigGiveSaddleBack = false; diff --git a/patches/Purpur/patches/server/0078-Implement-bed-explosion-options.patch b/patches/Purpur/patches/server/0078-Implement-bed-explosion-options.patch new file mode 100644 index 00000000..f691001e --- /dev/null +++ b/patches/Purpur/patches/server/0078-Implement-bed-explosion-options.patch @@ -0,0 +1,62 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sat, 4 Jul 2020 13:12:43 -0500 +Subject: [PATCH] Implement bed explosion options + + +diff --git a/src/main/java/net/minecraft/world/level/block/BlockBed.java b/src/main/java/net/minecraft/world/level/block/BlockBed.java +index 00a01a157deec004bcf2f8587723a0ecd0bfef85..d42a3e73c6e4e65f023fa5af65a26acbf2f01281 100644 +--- a/src/main/java/net/minecraft/world/level/block/BlockBed.java ++++ b/src/main/java/net/minecraft/world/level/block/BlockBed.java +@@ -138,7 +138,7 @@ public class BlockBed extends BlockFacingHorizontal implements ITileEntity { + world.a(blockposition1, false); + } + +- world.createExplosion((Entity) null, DamageSource.a(), (ExplosionDamageCalculator) null, (double) blockposition.getX() + 0.5D, (double) blockposition.getY() + 0.5D, (double) blockposition.getZ() + 0.5D, 5.0F, true, Explosion.Effect.DESTROY); ++ if (world.purpurConfig.bedExplode) world.createExplosion(null, DamageSource.a(), null, (double) blockposition.getX() + 0.5D, (double) blockposition.getY() + 0.5D, (double) blockposition.getZ() + 0.5D, (float) world.purpurConfig.bedExplosionPower, world.purpurConfig.bedExplosionFire, world.purpurConfig.bedExplosionEffect); // Purpur + return EnumInteractionResult.SUCCESS; + } + } +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index d957ee4c10fde8596442f2f05f0347994df7bae5..83f43b44946a9e5aeecacae776684934685d79ac 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -1,6 +1,7 @@ + package net.pl3x.purpur; + + import net.minecraft.core.IRegistry; ++import net.minecraft.world.level.Explosion; + import net.minecraft.world.level.block.Block; + import net.minecraft.world.level.block.Blocks; + import net.minecraft.world.item.Item; +@@ -12,6 +13,7 @@ import java.util.ArrayList; + import java.util.HashMap; + import java.util.List; + import java.util.Map; ++import java.util.logging.Level; + + import static net.pl3x.purpur.PurpurConfig.log; + +@@ -258,6 +260,22 @@ public class PurpurWorldConfig { + }); + } + ++ public boolean bedExplode = true; ++ public double bedExplosionPower = 5.0D; ++ public boolean bedExplosionFire = true; ++ public Explosion.Effect bedExplosionEffect = Explosion.Effect.DESTROY; ++ private void bedSettings() { ++ bedExplode = getBoolean("blocks.bed.explode", bedExplode); ++ bedExplosionPower = getDouble("blocks.bed.explosion-power", bedExplosionPower); ++ bedExplosionFire = getBoolean("blocks.bed.explosion-fire", bedExplosionFire); ++ try { ++ bedExplosionEffect = Explosion.Effect.valueOf(getString("blocks.bed.explosion-effect", bedExplosionEffect.name())); ++ } catch (IllegalArgumentException e) { ++ log(Level.SEVERE, "Unknown value for `blocks.bed.explosion-effect`! Using default of `DESTROY`"); ++ bedExplosionEffect = Explosion.Effect.DESTROY; ++ } ++ } ++ + public boolean dispenserApplyCursedArmor = true; + private void dispenserSettings() { + dispenserApplyCursedArmor = getBoolean("blocks.dispenser.apply-cursed-to-armor-slots", dispenserApplyCursedArmor); diff --git a/patches/Purpur/patches/server/0079-Implement-respawn-anchor-explosion-options.patch b/patches/Purpur/patches/server/0079-Implement-respawn-anchor-explosion-options.patch new file mode 100644 index 00000000..9c9686ee --- /dev/null +++ b/patches/Purpur/patches/server/0079-Implement-respawn-anchor-explosion-options.patch @@ -0,0 +1,58 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sat, 4 Jul 2020 13:23:19 -0500 +Subject: [PATCH] Implement respawn anchor explosion options + + +diff --git a/src/main/java/net/minecraft/world/level/block/BlockRespawnAnchor.java b/src/main/java/net/minecraft/world/level/block/BlockRespawnAnchor.java +index 028e98decf8b0496b4ebcd1aad3aa474e5c4e7c1..9b7a7f1ae50baf53d314bbf1588afeb8e61dae5d 100644 +--- a/src/main/java/net/minecraft/world/level/block/BlockRespawnAnchor.java ++++ b/src/main/java/net/minecraft/world/level/block/BlockRespawnAnchor.java +@@ -115,10 +115,7 @@ public class BlockRespawnAnchor extends Block { + + private void d(IBlockData iblockdata, World world, final BlockPosition blockposition) { + world.a(blockposition, false); +- Stream stream = EnumDirection.EnumDirectionLimit.HORIZONTAL.a(); +- +- blockposition.getClass(); +- boolean flag = stream.map(blockposition::shift).anyMatch((blockposition1) -> { ++ boolean flag = EnumDirection.EnumDirectionLimit.HORIZONTAL.a().map(blockposition::shift).anyMatch((blockposition1) -> { // Purpur - decompile error + return a(blockposition1, world); + }); + final boolean flag1 = flag || world.getFluid(blockposition.up()).a((Tag) TagsFluid.WATER); +@@ -129,7 +126,7 @@ public class BlockRespawnAnchor extends Block { + } + }; + +- world.createExplosion((Entity) null, DamageSource.a(), explosiondamagecalculator, (double) blockposition.getX() + 0.5D, (double) blockposition.getY() + 0.5D, (double) blockposition.getZ() + 0.5D, 5.0F, true, Explosion.Effect.DESTROY); ++ if (world.purpurConfig.respawnAnchorExplode) world.createExplosion(null, DamageSource.a(), explosiondamagecalculator, (double) blockposition.getX() + 0.5D, (double) blockposition.getY() + 0.5D, (double) blockposition.getZ() + 0.5D, (float) world.purpurConfig.respawnAnchorExplosionPower, world.purpurConfig.respawnAnchorExplosionFire, world.purpurConfig.respawnAnchorExplosionEffect); // Purpur + } + + public static boolean a(World world) { +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 83f43b44946a9e5aeecacae776684934685d79ac..9d7f7fc586200206ff87dfa463479150ed8cd5f1 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -297,6 +297,22 @@ public class PurpurWorldConfig { + lavaSpeedNotNether = getInt("blocks.lava.speed.not-nether", lavaSpeedNotNether); + } + ++ public boolean respawnAnchorExplode = true; ++ public double respawnAnchorExplosionPower = 5.0D; ++ public boolean respawnAnchorExplosionFire = true; ++ public Explosion.Effect respawnAnchorExplosionEffect = Explosion.Effect.DESTROY; ++ private void respawnAnchorSettings() { ++ respawnAnchorExplode = getBoolean("blocks.respawn_anchor.explode", respawnAnchorExplode); ++ respawnAnchorExplosionPower = getDouble("blocks.respawn_anchor.explosion-power", respawnAnchorExplosionPower); ++ respawnAnchorExplosionFire = getBoolean("blocks.respawn_anchor.explosion-fire", respawnAnchorExplosionFire); ++ try { ++ respawnAnchorExplosionEffect = Explosion.Effect.valueOf(getString("blocks.respawn_anchor.explosion-effect", respawnAnchorExplosionEffect.name())); ++ } catch (IllegalArgumentException e) { ++ log(Level.SEVERE, "Unknown value for `blocks.respawn_anchor.explosion-effect`! Using default of `DESTROY`"); ++ respawnAnchorExplosionEffect = Explosion.Effect.DESTROY; ++ } ++ } ++ + public boolean signAllowColors = false; + public boolean signRightClickEdit = false; + private void signSettings() { diff --git a/patches/Purpur/patches/server/0080-Add-allow-water-in-end-world-option.patch b/patches/Purpur/patches/server/0080-Add-allow-water-in-end-world-option.patch new file mode 100644 index 00000000..ed10bb73 --- /dev/null +++ b/patches/Purpur/patches/server/0080-Add-allow-water-in-end-world-option.patch @@ -0,0 +1,85 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sun, 5 Jul 2020 23:40:16 -0500 +Subject: [PATCH] Add allow water in end world option + + +diff --git a/src/main/java/net/minecraft/world/item/ItemBucket.java b/src/main/java/net/minecraft/world/item/ItemBucket.java +index f97447d77890cd65b5613899c389483bcf82be01..7eb3238b5820bb13f25d78d7808722659cb521f2 100644 +--- a/src/main/java/net/minecraft/world/item/ItemBucket.java ++++ b/src/main/java/net/minecraft/world/item/ItemBucket.java +@@ -163,7 +163,7 @@ public class ItemBucket extends Item { + // CraftBukkit end + if (!flag1) { + return movingobjectpositionblock != null && this.a(entityhuman, world, movingobjectpositionblock.getBlockPosition().shift(movingobjectpositionblock.getDirection()), (MovingObjectPositionBlock) null, enumdirection, clicked, itemstack, enumhand); // CraftBukkit // Paper - add enumhand +- } else if (world.getDimensionManager().isNether() && this.fluidType.a((Tag) TagsFluid.WATER)) { ++ } else if ((world.isNether() || (world.isTheEnd() && !net.pl3x.purpur.PurpurConfig.allowWaterPlacementInTheEnd)) && this.fluidType.a((Tag) TagsFluid.WATER)) { // Purpur + int i = blockposition.getX(); + int j = blockposition.getY(); + int k = blockposition.getZ(); +@@ -171,7 +171,7 @@ public class ItemBucket extends Item { + world.playSound(entityhuman, blockposition, SoundEffects.BLOCK_FIRE_EXTINGUISH, SoundCategory.BLOCKS, 0.5F, 2.6F + (world.random.nextFloat() - world.random.nextFloat()) * 0.8F); + + for (int l = 0; l < 8; ++l) { +- world.addParticle(Particles.LARGE_SMOKE, (double) i + Math.random(), (double) j + Math.random(), (double) k + Math.random(), 0.0D, 0.0D, 0.0D); ++ ((WorldServer) world).sendParticles(null, Particles.LARGE_SMOKE, (double) i + Math.random(), (double) j + Math.random(), (double) k + Math.random(), 1, 0.0D, 0.0D, 0.0D, 0.0D, true); // Purpur + } + + return true; +diff --git a/src/main/java/net/minecraft/world/level/World.java b/src/main/java/net/minecraft/world/level/World.java +index 7133b814b414a8aae2f056b9205cf58ca68ab887..137583da4926ce85d258fce98c919618d02a5f77 100644 +--- a/src/main/java/net/minecraft/world/level/World.java ++++ b/src/main/java/net/minecraft/world/level/World.java +@@ -1739,4 +1739,14 @@ public abstract class World implements GeneratorAccess, AutoCloseable { + public final boolean isDebugWorld() { + return this.debugWorld; + } ++ ++ // Purpur start ++ public boolean isNether() { ++ return getWorld().getEnvironment() == org.bukkit.World.Environment.NETHER; ++ } ++ ++ public boolean isTheEnd() { ++ return getWorld().getEnvironment() == org.bukkit.World.Environment.THE_END; ++ } ++ // Purpur end + } +diff --git a/src/main/java/net/minecraft/world/level/block/BlockIce.java b/src/main/java/net/minecraft/world/level/block/BlockIce.java +index 461c85b426aab30c34529897e55aa842b45d0555..486a03f2582d6ece2775cb2db127953d31d041f8 100644 +--- a/src/main/java/net/minecraft/world/level/block/BlockIce.java ++++ b/src/main/java/net/minecraft/world/level/block/BlockIce.java +@@ -27,7 +27,7 @@ public class BlockIce extends BlockHalfTransparent { + public void a(World world, EntityHuman entityhuman, BlockPosition blockposition, IBlockData iblockdata, @Nullable TileEntity tileentity, ItemStack itemstack) { + super.a(world, entityhuman, blockposition, iblockdata, tileentity, itemstack); + if (EnchantmentManager.getEnchantmentLevel(Enchantments.SILK_TOUCH, itemstack) == 0) { +- if (world.getDimensionManager().isNether()) { ++ if (world.isNether() || (world.isTheEnd() && !net.pl3x.purpur.PurpurConfig.allowWaterPlacementInTheEnd)) { // Purpur + world.a(blockposition, false); + return; + } +@@ -55,7 +55,7 @@ public class BlockIce extends BlockHalfTransparent { + return; + } + // CraftBukkit end +- if (world.getDimensionManager().isNether()) { ++ if (world.isNether() || (world.isTheEnd() && !net.pl3x.purpur.PurpurConfig.allowWaterPlacementInTheEnd)) { // Purpur + world.a(blockposition, false); + } else { + world.setTypeUpdate(blockposition, Blocks.WATER.getBlockData()); +diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java +index b1b12a46f0b662aff24357b407b65124428ecfaa..1a9d5409d38be0884c005524069c341a2dc27365 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java +@@ -186,6 +186,11 @@ public class PurpurConfig { + dontSendUselessEntityPackets = getBoolean("settings.dont-send-useless-entity-packets", dontSendUselessEntityPackets); + } + ++ public static boolean allowWaterPlacementInTheEnd = true; ++ private static void allowWaterPlacementInEnd() { ++ allowWaterPlacementInTheEnd = getBoolean("settings.allow-water-placement-in-the-end", allowWaterPlacementInTheEnd); ++ } ++ + public static boolean loggerSuppressInitLegacyMaterialError = false; + public static boolean loggerSuppressIgnoredAdvancementWarnings = false; + private static void loggerSettings() { diff --git a/patches/Purpur/patches/server/0081-Allow-color-codes-in-books.patch b/patches/Purpur/patches/server/0081-Allow-color-codes-in-books.patch new file mode 100644 index 00000000..3f2ff2a6 --- /dev/null +++ b/patches/Purpur/patches/server/0081-Allow-color-codes-in-books.patch @@ -0,0 +1,54 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Tue, 3 Nov 2020 01:25:06 -0600 +Subject: [PATCH] Allow color codes in books + + +diff --git a/src/main/java/net/minecraft/server/network/PlayerConnection.java b/src/main/java/net/minecraft/server/network/PlayerConnection.java +index e8a9c8a7fc4089e48e09afc1638cf1ccde7b0fab..d16149731efbaa9ad19083d5654f4e1e14ef3b76 100644 +--- a/src/main/java/net/minecraft/server/network/PlayerConnection.java ++++ b/src/main/java/net/minecraft/server/network/PlayerConnection.java +@@ -1224,7 +1224,8 @@ public class PlayerConnection implements PacketListenerPlayIn { + if (itemstack.getItem() == Items.WRITABLE_BOOK) { + NBTTagList nbttaglist = new NBTTagList(); + +- list.stream().map(NBTTagString::a).forEach(nbttaglist::add); ++ boolean hasPerm = getPlayer().hasPermission("purpur.book.color.edit"); // Purpur - edit book ++ list.stream().map(s -> s = color(s, hasPerm, false)).map(NBTTagString::a).forEach(nbttaglist::add); // Purpur - edit book + ItemStack old = itemstack.cloneItemStack(); // CraftBukkit + itemstack.a("pages", (NBTBase) nbttaglist); + this.player.inventory.setItem(i, CraftEventFactory.handleEditBookEvent(player, i, old, itemstack)); // CraftBukkit // Paper - Don't ignore result (see other callsite for handleEditBookEvent) +@@ -1242,13 +1243,14 @@ public class PlayerConnection implements PacketListenerPlayIn { + itemstack1.setTag(nbttagcompound.clone()); + } + ++ boolean hasPerm = getPlayer().hasPermission("purpur.book.color.edit") || getPlayer().hasPermission("purpur.book.color.sign"); // Purpur + itemstack1.a("author", (NBTBase) NBTTagString.a(this.player.getDisplayName().getString())); +- itemstack1.a("title", (NBTBase) NBTTagString.a(s)); ++ itemstack1.a("title", (NBTBase) NBTTagString.a(color(s, hasPerm))); // Purpur - sign book + NBTTagList nbttaglist = new NBTTagList(); + Iterator iterator = list.iterator(); + + while (iterator.hasNext()) { +- String s1 = (String) iterator.next(); ++ String s1 = color((String) iterator.next(), hasPerm);// Purpur - sign book + ChatComponentText chatcomponenttext = new ChatComponentText(s1); + String s2 = IChatBaseComponent.ChatSerializer.a((IChatBaseComponent) chatcomponenttext); + +@@ -1260,6 +1262,16 @@ public class PlayerConnection implements PacketListenerPlayIn { + } + } + ++ // Purpur start ++ private String color(String str, boolean hasPerm) { ++ return color(str, hasPerm, true); ++ } ++ ++ private String color(String str, boolean hasPerm, boolean parseHex) { ++ return hasPerm ? org.bukkit.ChatColor.color(str, parseHex) : str; ++ } ++ // Purpur end ++ + @Override + public void a(PacketPlayInEntityNBTQuery packetplayinentitynbtquery) { + PlayerConnectionUtils.ensureMainThread(packetplayinentitynbtquery, this, this.player.getWorldServer()); diff --git a/patches/Purpur/patches/server/0082-Entity-lifespan.patch b/patches/Purpur/patches/server/0082-Entity-lifespan.patch new file mode 100644 index 00000000..d93e63bc --- /dev/null +++ b/patches/Purpur/patches/server/0082-Entity-lifespan.patch @@ -0,0 +1,121 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sat, 11 Jul 2020 19:41:34 -0500 +Subject: [PATCH] Entity lifespan + + +diff --git a/src/main/java/net/minecraft/server/network/PlayerConnection.java b/src/main/java/net/minecraft/server/network/PlayerConnection.java +index d16149731efbaa9ad19083d5654f4e1e14ef3b76..10c5af3949af4a3bee4999753e7545f0ac745e63 100644 +--- a/src/main/java/net/minecraft/server/network/PlayerConnection.java ++++ b/src/main/java/net/minecraft/server/network/PlayerConnection.java +@@ -2472,6 +2472,7 @@ public class PlayerConnection implements PacketListenerPlayIn { + boolean triggerLeashUpdate = itemInHand != null && itemInHand.getItem() == Items.LEAD && entity instanceof EntityInsentient; + Item origItem = this.player.inventory.getItemInHand() == null ? null : this.player.inventory.getItemInHand().getItem(); + PlayerInteractEntityEvent event; ++ if (entity instanceof EntityInsentient) ((EntityInsentient) entity).ticksSinceLastInteraction = 0; // Purpur + if (packetplayinuseentity.b() == PacketPlayInUseEntity.EnumEntityUseAction.INTERACT) { + event = new PlayerInteractEntityEvent((Player) this.getPlayer(), entity.getBukkitEntity(), (packetplayinuseentity.c() == EnumHand.OFF_HAND) ? EquipmentSlot.OFF_HAND : EquipmentSlot.HAND); + } else { +diff --git a/src/main/java/net/minecraft/world/entity/EntityInsentient.java b/src/main/java/net/minecraft/world/entity/EntityInsentient.java +index b70120c32027a456037daac363d420d2edd4bdfe..fdc1b99f0a032a76a02ee88b28d62e049a2fc54c 100644 +--- a/src/main/java/net/minecraft/world/entity/EntityInsentient.java ++++ b/src/main/java/net/minecraft/world/entity/EntityInsentient.java +@@ -124,7 +124,7 @@ public abstract class EntityInsentient extends EntityLiving { + private NBTTagCompound by; + private BlockPosition bz; + private float bA; +- ++ public int ticksSinceLastInteraction; // Purpur + public boolean aware = true; // CraftBukkit + + protected EntityInsentient(EntityTypes entitytypes, World world) { +@@ -276,6 +276,7 @@ public abstract class EntityInsentient extends EntityLiving { + entityliving = null; + } + } ++ if (entityliving instanceof EntityPlayer) this.ticksSinceLastInteraction = 0; // Purpur + this.goalTarget = entityliving; + return true; + // CraftBukkit end +@@ -320,10 +321,35 @@ public abstract class EntityInsentient extends EntityLiving { + this.m(); + this.F(); + } +- ++ incrementTicksSinceLastInteraction(); // Purpur + this.world.getMethodProfiler().exit(); + } + ++ // Purpur start ++ private void incrementTicksSinceLastInteraction() { ++ ++ticksSinceLastInteraction; ++ //if (hasRider()) { ++ // ticksSinceLastInteraction = 0; ++ // return; ++ //} ++ if (world.purpurConfig.entityLifeSpan <= 0) { ++ return; // feature disabled ++ } ++ if (!isTypeNotPersistent(0) || isPersistent() || isSpecialPersistence() || hasCustomName()) { ++ return; // mob persistent ++ } ++ if (ticksSinceLastInteraction > world.purpurConfig.entityLifeSpan) { ++ this.dead = true; ++ } ++ } ++ ++ @Override ++ public boolean damageEntity(DamageSource damagesource, float f) { ++ if (damagesource.getEntity() instanceof EntityPlayer) this.ticksSinceLastInteraction = 0; // Purpur ++ return super.damageEntity(damagesource, f); ++ } ++ // Purpur end ++ + @Override + protected void c(DamageSource damagesource) { + this.m(); +@@ -497,6 +523,7 @@ public abstract class EntityInsentient extends EntityLiving { + } + + nbttagcompound.setBoolean("Bukkit.Aware", this.aware); // CraftBukkit ++ nbttagcompound.setInt("Purpur.ticksSinceLastInteraction", ticksSinceLastInteraction); // Purpur + } + + @Override +@@ -567,6 +594,11 @@ public abstract class EntityInsentient extends EntityLiving { + this.aware = nbttagcompound.getBoolean("Bukkit.Aware"); + } + // CraftBukkit end ++ // Purpur start ++ if (nbttagcompound.hasKey("Purpur.ticksSinceLastInteraction")) { ++ ticksSinceLastInteraction = nbttagcompound.getInt("Purpur.ticksSinceLastInteraction"); ++ } ++ // Purpur end + } + + @Override +@@ -1626,7 +1658,7 @@ public abstract class EntityInsentient extends EntityLiving { + this.a((EntityLiving) this, entity); + this.z(entity); + } +- ++ if (entity instanceof EntityPlayer) this.ticksSinceLastInteraction = 0; // Purpur + return flag; + } + +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 9d7f7fc586200206ff87dfa463479150ed8cd5f1..fa003079da19ee63a02045d57ea3d6cf64578ebd 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -137,6 +137,11 @@ public class PurpurWorldConfig { + } + } + ++ public int entityLifeSpan = 0; ++ private void entitySettings() { ++ entityLifeSpan = getInt("gameplay-mechanics.entity-lifespan", entityLifeSpan); ++ } ++ + public List itemImmuneToCactus = new ArrayList<>(); + public List itemImmuneToExplosion = new ArrayList<>(); + public List itemImmuneToFire = new ArrayList<>(); diff --git a/patches/Purpur/patches/server/0083-Add-option-to-teleport-to-spawn-if-outside-world-bor.patch b/patches/Purpur/patches/server/0083-Add-option-to-teleport-to-spawn-if-outside-world-bor.patch new file mode 100644 index 00000000..a8fef9ce --- /dev/null +++ b/patches/Purpur/patches/server/0083-Add-option-to-teleport-to-spawn-if-outside-world-bor.patch @@ -0,0 +1,73 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Mon, 13 Jul 2020 11:40:00 -0500 +Subject: [PATCH] Add option to teleport to spawn if outside world border + + +diff --git a/src/main/java/net/minecraft/server/level/EntityPlayer.java b/src/main/java/net/minecraft/server/level/EntityPlayer.java +index 4ce97052092c4b5f0fa59de7442654f7025febb6..38d63449b4ec833ec53de5fe6deebbb3f744492e 100644 +--- a/src/main/java/net/minecraft/server/level/EntityPlayer.java ++++ b/src/main/java/net/minecraft/server/level/EntityPlayer.java +@@ -2588,4 +2588,26 @@ public class EntityPlayer extends EntityHuman implements ICrafting { + return (CraftPlayer) super.getBukkitEntity(); + } + // CraftBukkit end ++ ++ // Purpur start ++ public void teleport(Location to) { ++ this.ejectPassengers(); ++ this.stopRiding(true); ++ ++ if (this.isSleeping()) { ++ this.wakeup(true, false); ++ } ++ ++ if (this.activeContainer != this.defaultContainer) { ++ this.closeInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason.TELEPORT); ++ } ++ ++ WorldServer toWorld = ((CraftWorld) to.getWorld()).getHandle(); ++ if (this.world == toWorld) { ++ this.playerConnection.teleport(to); ++ } else { ++ this.server.getPlayerList().moveToWorld(this, toWorld, true, to, !toWorld.paperConfig.disableTeleportationSuffocationCheck); ++ } ++ } ++ // Purpur end + } +diff --git a/src/main/java/net/minecraft/world/entity/EntityLiving.java b/src/main/java/net/minecraft/world/entity/EntityLiving.java +index 4bac98718f67699433fdd89307c20438f3ee6425..087b18b1fbf9d5e64ddf7f303aaad58bb9e1c3f5 100644 +--- a/src/main/java/net/minecraft/world/entity/EntityLiving.java ++++ b/src/main/java/net/minecraft/world/entity/EntityLiving.java +@@ -45,6 +45,7 @@ import net.minecraft.network.syncher.DataWatcher; + import net.minecraft.network.syncher.DataWatcherObject; + import net.minecraft.network.syncher.DataWatcherRegistry; + import net.minecraft.resources.MinecraftKey; ++import net.minecraft.server.MCUtil; + import net.minecraft.server.level.ChunkProviderServer; + import net.minecraft.server.level.EntityPlayer; + import net.minecraft.server.level.WorldServer; +@@ -375,6 +376,7 @@ public abstract class EntityLiving extends Entity { + double d1 = this.world.getWorldBorder().getDamageAmount(); + + if (d1 > 0.0D) { ++ if (world.purpurConfig.teleportIfOutsideBorder && this instanceof EntityPlayer) { ((EntityPlayer) this).teleport(MCUtil.toLocation(world, world.getSpawn())); return; } // Purpur + this.damageEntity(DamageSource.STUCK, (float) Math.max(1, MathHelper.floor(-d0 * d1))); + } + } +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index fa003079da19ee63a02045d57ea3d6cf64578ebd..cd9970db68b6c2f358115b616c36f52ad324fc90 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -242,6 +242,11 @@ public class PurpurWorldConfig { + playerInvulnerableWhileAcceptingResourcePack = getBoolean("gameplay-mechanics.player.invulnerable-while-accepting-resource-pack", playerInvulnerableWhileAcceptingResourcePack); + } + ++ public boolean teleportIfOutsideBorder = false; ++ private void teleportIfOutsideBorder() { ++ teleportIfOutsideBorder = getBoolean("gameplay-mechanics.player.teleport-if-outside-border", teleportIfOutsideBorder); ++ } ++ + public boolean silkTouchEnabled = false; + public String silkTouchSpawnerName = "Spawner"; + public List silkTouchSpawnerLore = new ArrayList<>(); diff --git a/patches/Purpur/patches/server/0084-Squid-EAR-immunity.patch b/patches/Purpur/patches/server/0084-Squid-EAR-immunity.patch new file mode 100644 index 00000000..0858d1db --- /dev/null +++ b/patches/Purpur/patches/server/0084-Squid-EAR-immunity.patch @@ -0,0 +1,42 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Mon, 13 Jul 2020 13:49:41 -0500 +Subject: [PATCH] Squid EAR immunity + + +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index cd9970db68b6c2f358115b616c36f52ad324fc90..86578f20429aa6bf5f3de1233c6287ce26be9827 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -499,6 +499,11 @@ public class PurpurWorldConfig { + snowGolemPutPumpkinBack = getBoolean("mobs.snow_golem.pumpkin-can-be-added-back", snowGolemPutPumpkinBack); + } + ++ public boolean squidImmuneToEAR = true; ++ private void squidSettings() { ++ squidImmuneToEAR = getBoolean("mobs.squid.immune-to-EAR", squidImmuneToEAR); ++ } ++ + public int villagerBrainTicks = 1; + public boolean villagerUseBrainTicksOnlyWhenLagging = true; + public boolean villagerCanBeLeashed = false; +diff --git a/src/main/java/org/spigotmc/ActivationRange.java b/src/main/java/org/spigotmc/ActivationRange.java +index 2bbbd4a7ae87c2ead3dc2fd5520adfaefe2776b8..2fbc24a6907c06bbc12815a89b507d4479be6dc5 100644 +--- a/src/main/java/org/spigotmc/ActivationRange.java ++++ b/src/main/java/org/spigotmc/ActivationRange.java +@@ -11,6 +11,7 @@ import net.minecraft.world.entity.EntityLiving; + import net.minecraft.world.entity.ambient.EntityAmbient; + import net.minecraft.world.entity.animal.EntityAnimal; + import net.minecraft.world.entity.animal.EntitySheep; ++import net.minecraft.world.entity.animal.EntitySquid; + import net.minecraft.world.entity.boss.EntityComplexPart; + import net.minecraft.world.entity.boss.enderdragon.EntityEnderCrystal; + import net.minecraft.world.entity.boss.enderdragon.EntityEnderDragon; +@@ -375,6 +376,7 @@ public class ActivationRange + */ + public static boolean checkIfActive(Entity entity) + { ++ if (entity.world.purpurConfig.squidImmuneToEAR && entity instanceof EntitySquid) return true; // Purpur + // Never safe to skip fireworks or entities not yet added to chunk + if ( !entity.inChunk || entity instanceof EntityFireworks ) { + return true; diff --git a/patches/Purpur/patches/server/0085-Configurable-end-spike-seed.patch b/patches/Purpur/patches/server/0085-Configurable-end-spike-seed.patch new file mode 100644 index 00000000..4368ebd1 --- /dev/null +++ b/patches/Purpur/patches/server/0085-Configurable-end-spike-seed.patch @@ -0,0 +1,45 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Wed, 15 Jul 2020 11:49:36 -0500 +Subject: [PATCH] Configurable end spike seed + + +diff --git a/src/main/java/net/minecraft/world/level/levelgen/feature/WorldGenEnder.java b/src/main/java/net/minecraft/world/level/levelgen/feature/WorldGenEnder.java +index 1bf09c99ba318813755ea3d3456d0fbb60847e5c..a185d31911bb4e9e996640940dc035f2300cddec 100644 +--- a/src/main/java/net/minecraft/world/level/levelgen/feature/WorldGenEnder.java ++++ b/src/main/java/net/minecraft/world/level/levelgen/feature/WorldGenEnder.java +@@ -36,7 +36,8 @@ public class WorldGenEnder extends WorldGenerator a(GeneratorAccessSeed generatoraccessseed) { +- Random random = new Random(generatoraccessseed.getSeed()); ++ int seed = net.pl3x.purpur.PurpurConfig.endSpikeSeed; // Purpur ++ Random random = new Random(seed == -1 ? generatoraccessseed.getSeed() : seed); // Purpur + long i = random.nextLong() & 65535L; + + return (List) WorldGenEnder.a.getUnchecked(i); +diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java +index 1a9d5409d38be0884c005524069c341a2dc27365..7a95f27827cbf5d5f69e0f3d55f327bac4203573 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java +@@ -1,5 +1,6 @@ + package net.pl3x.purpur; + ++import co.aikar.timings.TimingsManager; + import com.google.common.base.Throwables; + import net.minecraft.locale.LocaleLanguage; + import net.minecraft.server.MinecraftServer; +@@ -141,6 +142,13 @@ public class PurpurConfig { + pingCommandOutput = getString("settings.messages.ping-command-output", pingCommandOutput); + } + ++ public static int endSpikeSeed = -1; ++ private static void seedSettings() { ++ endSpikeSeed = getInt("settings.seed.end-spike", endSpikeSeed); ++ if (!TimingsManager.hiddenConfigs.contains("settings.seed")) TimingsManager.hiddenConfigs.add("settings.seed"); ++ if (!TimingsManager.hiddenConfigs.contains("settings.seed.end-spike")) TimingsManager.hiddenConfigs.add("settings.seed.end-spike"); ++ } ++ + public static String serverModName = "Purpur"; + private static void serverModName() { + serverModName = getString("settings.server-mod-name", serverModName); diff --git a/patches/Purpur/patches/server/0086-Configurable-dungeon-seed.patch b/patches/Purpur/patches/server/0086-Configurable-dungeon-seed.patch new file mode 100644 index 00000000..f33b977b --- /dev/null +++ b/patches/Purpur/patches/server/0086-Configurable-dungeon-seed.patch @@ -0,0 +1,50 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Wed, 15 Jul 2020 12:40:25 -0500 +Subject: [PATCH] Configurable dungeon seed + + +diff --git a/src/main/java/net/minecraft/world/level/levelgen/feature/WorldGenDungeons.java b/src/main/java/net/minecraft/world/level/levelgen/feature/WorldGenDungeons.java +index 4a2e3af98ef3383678445c1bdf535203097558ee..363de0352804e6a778d4e6ee34609a9491744aaf 100644 +--- a/src/main/java/net/minecraft/world/level/levelgen/feature/WorldGenDungeons.java ++++ b/src/main/java/net/minecraft/world/level/levelgen/feature/WorldGenDungeons.java +@@ -27,12 +27,21 @@ public class WorldGenDungeons extends WorldGenerator[] ab = new EntityTypes[]{EntityTypes.SKELETON, EntityTypes.ZOMBIE, EntityTypes.ZOMBIE, EntityTypes.SPIDER}; + private static final IBlockData ac = Blocks.CAVE_AIR.getBlockData(); ++ private Random random; // Purpur + + public WorldGenDungeons(Codec codec) { + super(codec); + } + ++ public boolean generate(GeneratorAccessSeed generatoraccessseed, ChunkGenerator chunkgenerator, Random random, BlockPosition blockposition, WorldGenFeatureEmptyConfiguration worldgenfeatureemptyconfiguration) { return a(generatoraccessseed, chunkgenerator, random, blockposition, worldgenfeatureemptyconfiguration); } // Purpur - decompile error? + public boolean a(GeneratorAccessSeed generatoraccessseed, ChunkGenerator chunkgenerator, Random random, BlockPosition blockposition, WorldGenFeatureEmptyConfiguration worldgenfeatureemptyconfiguration) { ++ // Purpur start ++ if (this.random == null) { ++ int seed = net.pl3x.purpur.PurpurConfig.dungeonSeed; ++ this.random = seed == -1 ? random : new Random(seed); ++ } ++ random = this.random; ++ // Purpur end + boolean flag = true; + int i = random.nextInt(2) + 2; + int j = -i - 1; +diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java +index 7a95f27827cbf5d5f69e0f3d55f327bac4203573..013f8a21be68f4e0470c0b873252bf21dd611127 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java +@@ -142,10 +142,13 @@ public class PurpurConfig { + pingCommandOutput = getString("settings.messages.ping-command-output", pingCommandOutput); + } + ++ public static int dungeonSeed = -1; + public static int endSpikeSeed = -1; + private static void seedSettings() { ++ dungeonSeed = getInt("settings.seed.dungeon", dungeonSeed); + endSpikeSeed = getInt("settings.seed.end-spike", endSpikeSeed); + if (!TimingsManager.hiddenConfigs.contains("settings.seed")) TimingsManager.hiddenConfigs.add("settings.seed"); ++ if (!TimingsManager.hiddenConfigs.contains("settings.seed.dungeon")) TimingsManager.hiddenConfigs.add("settings.seed.dungeon"); + if (!TimingsManager.hiddenConfigs.contains("settings.seed.end-spike")) TimingsManager.hiddenConfigs.add("settings.seed.end-spike"); + } + diff --git a/patches/Purpur/patches/server/0087-Phantoms-burn-in-light.patch b/patches/Purpur/patches/server/0087-Phantoms-burn-in-light.patch new file mode 100644 index 00000000..90be944e --- /dev/null +++ b/patches/Purpur/patches/server/0087-Phantoms-burn-in-light.patch @@ -0,0 +1,111 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: draycia +Date: Sun, 12 Apr 2020 20:41:59 -0700 +Subject: [PATCH] Phantoms burn in light + + +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityPhantom.java b/src/main/java/net/minecraft/world/entity/monster/EntityPhantom.java +index e20b26ae0435c593218541eba6c68ef297fea7c8..fd2e3a4abcfedaf04db4277291983627c097b545 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityPhantom.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityPhantom.java +@@ -18,6 +18,7 @@ import net.minecraft.sounds.SoundEffect; + import net.minecraft.sounds.SoundEffects; + import net.minecraft.util.MathHelper; + import net.minecraft.world.DifficultyDamageScaler; ++import net.minecraft.world.EnumHand; + import net.minecraft.world.damagesource.DamageSource; + import net.minecraft.world.entity.Entity; + import net.minecraft.world.entity.EntityFlying; +@@ -41,6 +42,7 @@ import net.minecraft.world.entity.boss.enderdragon.EntityEnderCrystal; + import net.minecraft.world.entity.player.EntityHuman; + import net.minecraft.world.item.ItemStack; + import net.minecraft.world.item.Items; ++import net.minecraft.world.item.crafting.RecipeItemStack; + import net.minecraft.world.level.World; + import net.minecraft.world.level.WorldAccess; + import net.minecraft.world.level.levelgen.HeightMap; +@@ -54,6 +56,7 @@ public class EntityPhantom extends EntityFlying implements IMonster { + private BlockPosition d; public void setHome(BlockPosition home) { this.d = home; } public BlockPosition getHome() { return this.d; } // Purpur - OBFHELPER + private EntityPhantom.AttackPhase bo; public AttackPhase getAttackPhase() { return this.bo; } // Purpur - OBFHELPER + private Vec3D crystalPosition; // Purpur ++ private static final RecipeItemStack TORCH = RecipeItemStack.a(Items.torch(), Items.soulTorch()); // Purpur + + public EntityPhantom(EntityTypes entitytypes, World world) { + super(entitytypes, world); +@@ -166,7 +169,7 @@ public class EntityPhantom extends EntityFlying implements IMonster { + + @Override + public void movementTick() { +- if (this.isAlive() && shouldBurnInDay && this.eG()) { // Paper - Configurable Burning ++ if (this.isAlive() && (((shouldBurnInDay || world.purpurConfig.phantomBurnInDaylight) && this.isInDaylight()) || (world.purpurConfig.phantomBurnInLight > 0 && world.getLightLevel(new BlockPosition(this)) >= world.purpurConfig.phantomBurnInLight))) { // Paper - Configurable Burning // Purpur + this.setOnFire(8); + } + +@@ -422,7 +425,7 @@ public class EntityPhantom extends EntityFlying implements IMonster { + } else { + this.c = 60; + List list = EntityPhantom.this.world.a(this.b, (EntityLiving) EntityPhantom.this, EntityPhantom.this.getBoundingBox().grow(16.0D, 64.0D, 16.0D)); +- ++ if (world.purpurConfig.phantomIgnorePlayersWithTorch) list.removeIf(human -> TORCH.test(human.getItemInHand(EnumHand.MAIN_HAND)) || TORCH.test(human.getItemInHand(EnumHand.OFF_HAND)));// Purpur + if (!list.isEmpty()) { + list.sort(Comparator.comparing(Entity::locY).reversed()); + Iterator iterator = list.iterator(); +@@ -521,6 +524,12 @@ public class EntityPhantom extends EntityFlying implements IMonster { + return false; + } else if (entityliving instanceof EntityHuman && (((EntityHuman) entityliving).isSpectator() || ((EntityHuman) entityliving).isCreative())) { + return false; ++ // Purpur start ++ } else if (world.purpurConfig.phantomBurnInLight > 0 && world.getLightLevel(new BlockPosition(EntityPhantom.this)) >= world.purpurConfig.phantomBurnInLight) { ++ return false; ++ } else if (world.purpurConfig.phantomIgnorePlayersWithTorch && (TORCH.test(entityliving.getItemInHand(EnumHand.MAIN_HAND)) || TORCH.test(entityliving.getItemInHand(EnumHand.OFF_HAND)))) { ++ return false; ++ // Purpur end + } else if (!this.a()) { + return false; + } else { +diff --git a/src/main/java/net/minecraft/world/item/Items.java b/src/main/java/net/minecraft/world/item/Items.java +index 993a88a5937417016821ef9d7cd58e4ee097491c..64b4fcf6f43c39db0fe57fc7a74f0d954e966a61 100644 +--- a/src/main/java/net/minecraft/world/item/Items.java ++++ b/src/main/java/net/minecraft/world/item/Items.java +@@ -187,7 +187,7 @@ public class Items { + public static final Item cm = a(Blocks.BOOKSHELF, CreativeModeTab.b); + public static final Item cn = a(Blocks.MOSSY_COBBLESTONE, CreativeModeTab.b); + public static final Item co = a(Blocks.OBSIDIAN, CreativeModeTab.b); +- public static final Item cp = a((ItemBlock) (new ItemBlockWallable(Blocks.TORCH, Blocks.WALL_TORCH, (new Item.Info()).a(CreativeModeTab.c)))); ++ public static final Item cp = a((ItemBlock) (new ItemBlockWallable(Blocks.TORCH, Blocks.WALL_TORCH, (new Item.Info()).a(CreativeModeTab.c)))); public static final Item torch() { return cp; } // Purpur - OBFHELPER + public static final Item cq = a(Blocks.END_ROD, CreativeModeTab.c); + public static final Item cr = a(Blocks.CHORUS_PLANT, CreativeModeTab.c); + public static final Item cs = a(Blocks.CHORUS_FLOWER, CreativeModeTab.c); +@@ -239,7 +239,7 @@ public class Items { + public static final Item dm = a(Blocks.SOUL_SOIL, CreativeModeTab.b); + public static final Item dn = a(Blocks.BASALT, CreativeModeTab.b); + public static final Item do_ = a(Blocks.cP, CreativeModeTab.b); +- public static final Item dp = a((ItemBlock) (new ItemBlockWallable(Blocks.SOUL_TORCH, Blocks.SOUL_WALL_TORCH, (new Item.Info()).a(CreativeModeTab.c)))); ++ public static final Item dp = a((ItemBlock) (new ItemBlockWallable(Blocks.SOUL_TORCH, Blocks.SOUL_WALL_TORCH, (new Item.Info()).a(CreativeModeTab.c)))); public static final Item soulTorch() { return dp; } // Purpur - OBFHELPER + public static final Item dq = a(Blocks.GLOWSTONE, CreativeModeTab.b); + public static final Item dr = a(Blocks.JACK_O_LANTERN, CreativeModeTab.b); + public static final Item ds = a(Blocks.OAK_TRAPDOOR, CreativeModeTab.d); +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 86578f20429aa6bf5f3de1233c6287ce26be9827..201974ec4db915e5a79ed36625f0870a7ff84207 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -454,6 +454,9 @@ public class PurpurWorldConfig { + public int phantomSpawnOverheadRadius = 10; + public int phantomSpawnMinPerAttempt = 1; + public int phantomSpawnMaxPerAttempt = -1; ++ public int phantomBurnInLight = 0; ++ public boolean phantomIgnorePlayersWithTorch = false; ++ public boolean phantomBurnInDaylight = true; + private void phantomSettings() { + phantomAttackedByCrystalRadius = getDouble("mobs.phantom.attacked-by-crystal-range", phantomAttackedByCrystalRadius); + phantomAttackedByCrystalDamage = (float) getDouble("mobs.phantom.attacked-by-crystal-damage", phantomAttackedByCrystalDamage); +@@ -470,6 +473,9 @@ public class PurpurWorldConfig { + phantomSpawnOverheadRadius = getInt("mobs.phantom.spawn.overhead.radius", phantomSpawnOverheadRadius); + phantomSpawnMinPerAttempt = getInt("mobs.phantom.spawn.per-attempt.min", phantomSpawnMinPerAttempt); + phantomSpawnMaxPerAttempt = getInt("mobs.phantom.spawn.per-attempt.max", phantomSpawnMaxPerAttempt); ++ phantomBurnInLight = getInt("mobs.phantom.burn-in-light", phantomBurnInLight); ++ phantomBurnInDaylight = getBoolean("mobs.phantom.burn-in-daylight", phantomBurnInDaylight); ++ phantomIgnorePlayersWithTorch = getBoolean("mobs.phantom.ignore-players-with-torch", phantomIgnorePlayersWithTorch); + } + + public boolean pigGiveSaddleBack = false; diff --git a/patches/Purpur/patches/server/0088-Configurable-villager-breeding.patch b/patches/Purpur/patches/server/0088-Configurable-villager-breeding.patch new file mode 100644 index 00000000..6ef73a7b --- /dev/null +++ b/patches/Purpur/patches/server/0088-Configurable-villager-breeding.patch @@ -0,0 +1,39 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: draycia +Date: Tue, 31 Mar 2020 23:48:55 -0700 +Subject: [PATCH] Configurable villager breeding + + +diff --git a/src/main/java/net/minecraft/world/entity/npc/EntityVillager.java b/src/main/java/net/minecraft/world/entity/npc/EntityVillager.java +index aaf8d2cd3089adba69c873c4ea62b0e8837b21d6..2ff9dffc0f0b20582f5b3bffd01743ee26c63c20 100644 +--- a/src/main/java/net/minecraft/world/entity/npc/EntityVillager.java ++++ b/src/main/java/net/minecraft/world/entity/npc/EntityVillager.java +@@ -712,7 +712,7 @@ public class EntityVillager extends EntityVillagerAbstract implements Reputation + + @Override + public boolean canBreed() { +- return this.bx + this.fv() >= 12 && this.getAge() == 0; ++ return world.purpurConfig.villagerCanBreed && this.bx + this.fv() >= 12 && this.getAge() == 0; // Purpur + } + + private boolean fr() { +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 201974ec4db915e5a79ed36625f0870a7ff84207..db5638c4f2b6d672e619c9ba44184b6d9fe113a1 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -517,6 +517,7 @@ public class PurpurWorldConfig { + public boolean villagerFollowEmeraldBlock = false; + public int villagerSpawnIronGolemRadius = 0; + public int villagerSpawnIronGolemLimit = 0; ++ public boolean villagerCanBreed = true; + private void villagerSettings() { + villagerBrainTicks = getInt("mobs.villager.brain-ticks", villagerBrainTicks); + villagerUseBrainTicksOnlyWhenLagging = getBoolean("mobs.villager.use-brain-ticks-only-when-lagging", villagerUseBrainTicksOnlyWhenLagging); +@@ -525,6 +526,7 @@ public class PurpurWorldConfig { + villagerFollowEmeraldBlock = getBoolean("mobs.villager.follow-emerald-blocks", villagerFollowEmeraldBlock); + villagerSpawnIronGolemRadius = getInt("mobs.villager.spawn-iron-golem.radius", villagerSpawnIronGolemRadius); + villagerSpawnIronGolemLimit = getInt("mobs.villager.spawn-iron-golem.limit", villagerSpawnIronGolemLimit); ++ villagerCanBreed = getBoolean("mobs.villager.can-breed", villagerCanBreed); + } + + public boolean villagerTraderCanBeLeashed = false; diff --git a/patches/Purpur/patches/server/0089-Redstone-deactivates-spawners.patch b/patches/Purpur/patches/server/0089-Redstone-deactivates-spawners.patch new file mode 100644 index 00000000..5864456e --- /dev/null +++ b/patches/Purpur/patches/server/0089-Redstone-deactivates-spawners.patch @@ -0,0 +1,43 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: draycia +Date: Tue, 14 Apr 2020 00:35:12 -0700 +Subject: [PATCH] Redstone deactivates spawners + + +diff --git a/src/main/java/net/minecraft/world/level/MobSpawnerAbstract.java b/src/main/java/net/minecraft/world/level/MobSpawnerAbstract.java +index 33a5dbcc11455f81088d9fd685a8c4b1b8f4b1f2..b65609bab36650c46e9dabdd25a139ae2af9d83a 100644 +--- a/src/main/java/net/minecraft/world/level/MobSpawnerAbstract.java ++++ b/src/main/java/net/minecraft/world/level/MobSpawnerAbstract.java +@@ -69,6 +69,7 @@ public abstract class MobSpawnerAbstract { + private boolean h() { + BlockPosition blockposition = this.b(); + ++ if (getWorld().purpurConfig.spawnerDeactivateByRedstone && getWorld().isBlockIndirectlyPowered(blockposition)) { return false; } // Purpur + return this.a().isAffectsSpawningPlayerNearby((double) blockposition.getX() + 0.5D, (double) blockposition.getY() + 0.5D, (double) blockposition.getZ() + 0.5D, (double) this.requiredPlayerRange); // Paper + } + +@@ -348,7 +349,7 @@ public abstract class MobSpawnerAbstract { + + public abstract void a(int i); + +- public abstract World a(); ++ public abstract World a(); public World getWorld() { return a(); } // Purpur - OBFHELPER + + public abstract BlockPosition b(); + } +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index db5638c4f2b6d672e619c9ba44184b6d9fe113a1..a36b9ea779fd984a16332e66f122d9505fad67de 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -330,6 +330,11 @@ public class PurpurWorldConfig { + signRightClickEdit = getBoolean("blocks.sign.right-click-edit", signRightClickEdit); + } + ++ public boolean spawnerDeactivateByRedstone = false; ++ private void spawnerSettings() { ++ spawnerDeactivateByRedstone = getBoolean("blocks.spawner.deactivate-by-redstone", spawnerDeactivateByRedstone); ++ } ++ + public boolean turtleEggsBreakFromExpOrbs = true; + public boolean turtleEggsBreakFromItems = true; + public boolean turtleEggsBreakFromMinecarts = true; diff --git a/patches/Purpur/patches/server/0090-Totems-work-in-inventory.patch b/patches/Purpur/patches/server/0090-Totems-work-in-inventory.patch new file mode 100644 index 00000000..e77937ef --- /dev/null +++ b/patches/Purpur/patches/server/0090-Totems-work-in-inventory.patch @@ -0,0 +1,46 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: draycia +Date: Wed, 29 Apr 2020 00:45:58 -0700 +Subject: [PATCH] Totems work in inventory + + +diff --git a/src/main/java/net/minecraft/world/entity/EntityLiving.java b/src/main/java/net/minecraft/world/entity/EntityLiving.java +index 087b18b1fbf9d5e64ddf7f303aaad58bb9e1c3f5..1140fc3cade24320bbc3e09a8664ded27df604fe 100644 +--- a/src/main/java/net/minecraft/world/entity/EntityLiving.java ++++ b/src/main/java/net/minecraft/world/entity/EntityLiving.java +@@ -1423,6 +1423,19 @@ public abstract class EntityLiving extends Entity { + } + } + ++ // Purpur start ++ if (world.purpurConfig.totemOfUndyingWorksInInventory && this instanceof EntityPlayer && (itemstack == null || itemstack.getItem() != Items.TOTEM_OF_UNDYING)) { ++ EntityPlayer player = (EntityPlayer) this; ++ for (ItemStack item : player.inventory.items) { ++ if (item.getItem() == Items.TOTEM_OF_UNDYING) { ++ itemstack1 = item; ++ itemstack = item.cloneItemStack(); ++ break; ++ } ++ } ++ } ++ // Purpur end ++ + EntityResurrectEvent event = new EntityResurrectEvent((LivingEntity) this.getBukkitEntity()); + event.setCancelled(itemstack == null); + this.world.getServer().getPluginManager().callEvent(event); +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index a36b9ea779fd984a16332e66f122d9505fad67de..ad4da617cf718e1c03e1532a9b45d7f927539a14 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -247,6 +247,11 @@ public class PurpurWorldConfig { + teleportIfOutsideBorder = getBoolean("gameplay-mechanics.player.teleport-if-outside-border", teleportIfOutsideBorder); + } + ++ public boolean totemOfUndyingWorksInInventory = false; ++ private void totemOfUndyingWorksInInventory() { ++ totemOfUndyingWorksInInventory = getBoolean("gameplay-mechanics.player.totem-of-undying-works-in-inventory", totemOfUndyingWorksInInventory); ++ } ++ + public boolean silkTouchEnabled = false; + public String silkTouchSpawnerName = "Spawner"; + public List silkTouchSpawnerLore = new ArrayList<>(); diff --git a/patches/Purpur/patches/server/0091-Populator-seed-controls.patch b/patches/Purpur/patches/server/0091-Populator-seed-controls.patch new file mode 100644 index 00000000..db414103 --- /dev/null +++ b/patches/Purpur/patches/server/0091-Populator-seed-controls.patch @@ -0,0 +1,101 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Sat, 18 Jul 2020 11:27:43 -0500 +Subject: [PATCH] Populator seed controls + + +diff --git a/src/main/java/co/aikar/timings/TimingsExport.java b/src/main/java/co/aikar/timings/TimingsExport.java +index 5e672a0660d0aceffcdb26d185590ca18aa4f023..4b171a2a60e24947e884f8988920f335bd99a471 100644 +--- a/src/main/java/co/aikar/timings/TimingsExport.java ++++ b/src/main/java/co/aikar/timings/TimingsExport.java +@@ -293,7 +293,7 @@ public class TimingsExport extends Thread { + JSONObject object = new JSONObject(); + for (String key : config.getKeys(false)) { + String fullKey = (parentKey != null ? parentKey + "." + key : key); +- if (fullKey.equals("database") || fullKey.equals("settings.bungeecord-addresses") || TimingsManager.hiddenConfigs.contains(fullKey) || key.startsWith("seed-") || key.equals("worldeditregentempworld")) { ++ if (fullKey.equals("database") || fullKey.equals("settings.bungeecord-addresses") || TimingsManager.hiddenConfigs.contains(fullKey) || key.startsWith("seed-") || key.equals("worldeditregentempworld") || fullKey.contains("worldgen.seeds.populator")) { // Tuinity + continue; + } + final Object val = config.get(key); +diff --git a/src/main/java/com/tuinity/tuinity/config/TuinityConfig.java b/src/main/java/com/tuinity/tuinity/config/TuinityConfig.java +index 48ad624592e59911d781b3cec92eea9d0ed92e0e..8f252995622dc9bfc8c66fb54a6964e63622f788 100644 +--- a/src/main/java/com/tuinity/tuinity/config/TuinityConfig.java ++++ b/src/main/java/com/tuinity/tuinity/config/TuinityConfig.java +@@ -1,5 +1,6 @@ + package com.tuinity.tuinity.config; + ++import co.aikar.timings.TimingsManager; + import com.destroystokyo.paper.util.SneakyThrow; + import net.minecraft.server.MinecraftServer; + import net.minecraft.server.level.TicketType; +@@ -450,6 +451,19 @@ public final class TuinityConfig { + this.threads = threads == -1 ? TuinityConfig.tickThreads : threads; + }*/ + ++ public Long populatorSeed; ++ public boolean useRandomPopulatorSeed; ++ ++ private void populatorSeed() { ++ final String seedString = this.getString("worldgen.seeds.populator", "default"); ++ if (seedString.equalsIgnoreCase("random")) { ++ this.useRandomPopulatorSeed = true; ++ } else if (!seedString.equalsIgnoreCase("default")) { ++ this.populatorSeed = Long.parseLong(seedString); ++ } ++ if (!TimingsManager.hiddenConfigs.contains("worldgen.seeds.populator")) TimingsManager.hiddenConfigs.add("worldgen.seeds.populator"); ++ } ++ + public int spawnLimitMonsters; + public int spawnLimitAnimals; + public int spawnLimitWaterAmbient; +diff --git a/src/main/java/net/minecraft/world/level/biome/BiomeBase.java b/src/main/java/net/minecraft/world/level/biome/BiomeBase.java +index 9bbd175f7e20591bbefdbddcb5e998e7098c5adb..c4fb051739c1c186c1574185e0653f513755987d 100644 +--- a/src/main/java/net/minecraft/world/level/biome/BiomeBase.java ++++ b/src/main/java/net/minecraft/world/level/biome/BiomeBase.java +@@ -23,7 +23,9 @@ import net.minecraft.core.SectionPosition; + import net.minecraft.data.RegistryGeneration; + import net.minecraft.resources.MinecraftKey; + import net.minecraft.resources.RegistryFileCodec; ++import net.minecraft.server.level.ChunkProviderServer; + import net.minecraft.server.level.RegionLimitedWorldAccess; ++import net.minecraft.server.level.WorldServer; + import net.minecraft.util.INamable; + import net.minecraft.world.level.ChunkCoordIntPair; + import net.minecraft.world.level.EnumSkyBlock; +@@ -257,6 +259,10 @@ public final class BiomeBase { + return this.k; + } + ++ // Tuinity start - populator seed control ++ private static final java.security.SecureRandom SECURE_RANDOM = new java.security.SecureRandom(); ++ // Tuinity end - populator seed control ++ + public void a(StructureManager structuremanager, ChunkGenerator chunkgenerator, RegionLimitedWorldAccess regionlimitedworldaccess, long i, SeededRandom seededrandom, BlockPosition blockposition) { + List>>> list = this.k.c(); + int j = WorldGenStage.Decoration.values().length; +@@ -293,12 +299,24 @@ public final class BiomeBase { + } + } + ++ // Tuinity start - populator seed control ++ long populatorSeed; ++ WorldServer world = (WorldServer)((ChunkProviderServer)regionlimitedworldaccess.getChunkProvider()).getWorld(); ++ if (world.tuinityConfig.useRandomPopulatorSeed) { ++ populatorSeed = SECURE_RANDOM.nextLong(); ++ } else if (world.tuinityConfig.populatorSeed != null) { ++ populatorSeed = world.tuinityConfig.populatorSeed.longValue(); ++ } else { ++ populatorSeed = i; ++ } ++ // Tuinity end - populator seed control ++ + if (list.size() > k) { + for (Iterator iterator1 = ((List) list.get(k)).iterator(); iterator1.hasNext(); ++l) { + Supplier> supplier = (Supplier) iterator1.next(); + WorldGenFeatureConfigured worldgenfeatureconfigured = (WorldGenFeatureConfigured) supplier.get(); + +- seededrandom.b(i, l, k); ++ seededrandom.b(populatorSeed, l, k); // Tuinity - populator seed control - move i up into default branch + + try { + worldgenfeatureconfigured.a(regionlimitedworldaccess, chunkgenerator, seededrandom, blockposition); diff --git a/patches/Purpur/patches/server/0092-Add-vindicator-johnny-spawn-chance.patch b/patches/Purpur/patches/server/0092-Add-vindicator-johnny-spawn-chance.patch new file mode 100644 index 00000000..389e35cf --- /dev/null +++ b/patches/Purpur/patches/server/0092-Add-vindicator-johnny-spawn-chance.patch @@ -0,0 +1,47 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Fri, 24 Jul 2020 19:38:21 -0500 +Subject: [PATCH] Add vindicator johnny spawn chance + + +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityVindicator.java b/src/main/java/net/minecraft/world/entity/monster/EntityVindicator.java +index f0eda0b83bab8e3a8adbb569b5997402b0e08e9a..fe84d6d2b74b6ae00c4c66682107296a40b69adc 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityVindicator.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityVindicator.java +@@ -6,6 +6,7 @@ import java.util.Map; + import java.util.function.Predicate; + import javax.annotation.Nullable; + import net.minecraft.nbt.NBTTagCompound; ++import net.minecraft.network.chat.ChatMessage; + import net.minecraft.network.chat.IChatBaseComponent; + import net.minecraft.server.level.WorldServer; + import net.minecraft.sounds.SoundEffect; +@@ -122,6 +123,12 @@ public class EntityVindicator extends EntityIllagerAbstract { + ((Navigation) this.getNavigation()).a(true); + this.a(difficultydamagescaler); + this.b(difficultydamagescaler); ++ // Purpur start ++ World world = worldaccess.getMinecraftWorld(); ++ if (world.purpurConfig.vindicatorJohnnySpawnChance > 0D && random.nextDouble() <= world.purpurConfig.vindicatorJohnnySpawnChance) { ++ setCustomName(new ChatMessage("Johnny")); ++ } ++ // Purpur end + return groupdataentity1; + } + +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index ad4da617cf718e1c03e1532a9b45d7f927539a14..b328c9f69fd43ca7ed57ee7f5b46ca998f2cb672 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -40,6 +40,11 @@ public class PurpurWorldConfig { + } + } + ++ public double vindicatorJohnnySpawnChance = 0D; ++ private void vindicatorSettings() { ++ vindicatorJohnnySpawnChance = getDouble("mobs.vindicator.johnny.spawn-chance", vindicatorJohnnySpawnChance); ++ } ++ + private ConfigurationSection getConfigurationSection(String path) { + ConfigurationSection section = PurpurConfig.config.getConfigurationSection("world-settings." + worldName + "." + path); + return section != null ? section : PurpurConfig.config.getConfigurationSection("world-settings.default." + path); diff --git a/patches/Purpur/patches/server/0093-Add-option-to-disable-certain-block-updates.patch b/patches/Purpur/patches/server/0093-Add-option-to-disable-certain-block-updates.patch new file mode 100644 index 00000000..1774b583 --- /dev/null +++ b/patches/Purpur/patches/server/0093-Add-option-to-disable-certain-block-updates.patch @@ -0,0 +1,132 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Tue, 4 Aug 2020 17:11:58 -0500 +Subject: [PATCH] Add option to disable certain block updates + + +diff --git a/src/main/java/net/minecraft/world/level/block/BlockChorusFruit.java b/src/main/java/net/minecraft/world/level/block/BlockChorusFruit.java +index 42a5345d569661726742a7ca53c2eb09f79a1958..248777af038bcbb20399d2aa24a42e77f8b8a9ba 100644 +--- a/src/main/java/net/minecraft/world/level/block/BlockChorusFruit.java ++++ b/src/main/java/net/minecraft/world/level/block/BlockChorusFruit.java +@@ -24,6 +24,7 @@ public class BlockChorusFruit extends BlockSprawling { + + @Override + public IBlockData getPlacedState(BlockActionContext blockactioncontext) { ++ if (net.pl3x.purpur.PurpurConfig.disableChorusPlantUpdates) return this.getBlockData(); // Purpur + return this.a((IBlockAccess) blockactioncontext.getWorld(), blockactioncontext.getClickPosition()); + } + +@@ -40,6 +41,7 @@ public class BlockChorusFruit extends BlockSprawling { + + @Override + public IBlockData updateState(IBlockData iblockdata, EnumDirection enumdirection, IBlockData iblockdata1, GeneratorAccess generatoraccess, BlockPosition blockposition, BlockPosition blockposition1) { ++ if (net.pl3x.purpur.PurpurConfig.disableChorusPlantUpdates) return iblockdata; // Purpur + if (!iblockdata.canPlace(generatoraccess, blockposition)) { + generatoraccess.getBlockTickList().a(blockposition, this, 1); + return super.updateState(iblockdata, enumdirection, iblockdata1, generatoraccess, blockposition, blockposition1); +diff --git a/src/main/java/net/minecraft/world/level/block/BlockHugeMushroom.java b/src/main/java/net/minecraft/world/level/block/BlockHugeMushroom.java +index 987301bfb9d963e3bebc2653bd95cf7f17a2a1e4..fd61c18905e81b1b193260f1c32b4ad0e29be227 100644 +--- a/src/main/java/net/minecraft/world/level/block/BlockHugeMushroom.java ++++ b/src/main/java/net/minecraft/world/level/block/BlockHugeMushroom.java +@@ -24,30 +24,57 @@ public class BlockHugeMushroom extends Block { + + public BlockHugeMushroom(BlockBase.Info blockbase_info) { + super(blockbase_info); +- this.j((IBlockData) ((IBlockData) ((IBlockData) ((IBlockData) ((IBlockData) ((IBlockData) ((IBlockData) this.blockStateList.getBlockData()).set(BlockHugeMushroom.a, true)).set(BlockHugeMushroom.b, true)).set(BlockHugeMushroom.c, true)).set(BlockHugeMushroom.d, true)).set(BlockHugeMushroom.e, true)).set(BlockHugeMushroom.f, true)); ++ this.j(this.blockStateList.getBlockData() ++ .set(BlockHugeMushroom.a, true) ++ .set(BlockHugeMushroom.b, true) ++ .set(BlockHugeMushroom.c, true) ++ .set(BlockHugeMushroom.d, true) ++ .set(BlockHugeMushroom.e, true) ++ .set(BlockHugeMushroom.f, true)); + } + + @Override + public IBlockData getPlacedState(BlockActionContext blockactioncontext) { + World world = blockactioncontext.getWorld(); ++ if (net.pl3x.purpur.PurpurConfig.disableMushroomBlockUpdates) return this.getBlockData(); + BlockPosition blockposition = blockactioncontext.getClickPosition(); +- +- return (IBlockData) ((IBlockData) ((IBlockData) ((IBlockData) ((IBlockData) ((IBlockData) this.getBlockData().set(BlockHugeMushroom.f, this != world.getType(blockposition.down()).getBlock())).set(BlockHugeMushroom.e, this != world.getType(blockposition.up()).getBlock())).set(BlockHugeMushroom.a, this != world.getType(blockposition.north()).getBlock())).set(BlockHugeMushroom.b, this != world.getType(blockposition.east()).getBlock())).set(BlockHugeMushroom.c, this != world.getType(blockposition.south()).getBlock())).set(BlockHugeMushroom.d, this != world.getType(blockposition.west()).getBlock()); ++ return this.getBlockData() ++ .set(BlockHugeMushroom.f, this != world.getType(blockposition.down()).getBlock()) ++ .set(BlockHugeMushroom.e, this != world.getType(blockposition.up()).getBlock()) ++ .set(BlockHugeMushroom.a, this != world.getType(blockposition.north()).getBlock()) ++ .set(BlockHugeMushroom.b, this != world.getType(blockposition.east()).getBlock()) ++ .set(BlockHugeMushroom.c, this != world.getType(blockposition.south()).getBlock()) ++ .set(BlockHugeMushroom.d, this != world.getType(blockposition.west()).getBlock()); + } + + @Override + public IBlockData updateState(IBlockData iblockdata, EnumDirection enumdirection, IBlockData iblockdata1, GeneratorAccess generatoraccess, BlockPosition blockposition, BlockPosition blockposition1) { +- return iblockdata1.a((Block) this) ? (IBlockData) iblockdata.set((IBlockState) BlockHugeMushroom.g.get(enumdirection), false) : super.updateState(iblockdata, enumdirection, iblockdata1, generatoraccess, blockposition, blockposition1); ++ if (net.pl3x.purpur.PurpurConfig.disableMushroomBlockUpdates) return iblockdata; ++ return iblockdata1.a(this) ? iblockdata.set(BlockHugeMushroom.g.get(enumdirection), false) : super.updateState(iblockdata, enumdirection, iblockdata1, generatoraccess, blockposition, blockposition1); + } + + @Override + public IBlockData a(IBlockData iblockdata, EnumBlockRotation enumblockrotation) { +- return (IBlockData) ((IBlockData) ((IBlockData) ((IBlockData) ((IBlockData) ((IBlockData) iblockdata.set((IBlockState) BlockHugeMushroom.g.get(enumblockrotation.a(EnumDirection.NORTH)), iblockdata.get(BlockHugeMushroom.a))).set((IBlockState) BlockHugeMushroom.g.get(enumblockrotation.a(EnumDirection.SOUTH)), iblockdata.get(BlockHugeMushroom.c))).set((IBlockState) BlockHugeMushroom.g.get(enumblockrotation.a(EnumDirection.EAST)), iblockdata.get(BlockHugeMushroom.b))).set((IBlockState) BlockHugeMushroom.g.get(enumblockrotation.a(EnumDirection.WEST)), iblockdata.get(BlockHugeMushroom.d))).set((IBlockState) BlockHugeMushroom.g.get(enumblockrotation.a(EnumDirection.UP)), iblockdata.get(BlockHugeMushroom.e))).set((IBlockState) BlockHugeMushroom.g.get(enumblockrotation.a(EnumDirection.DOWN)), iblockdata.get(BlockHugeMushroom.f)); ++ if (net.pl3x.purpur.PurpurConfig.disableMushroomBlockUpdates) return iblockdata; ++ return iblockdata ++ .set(BlockHugeMushroom.g.get(enumblockrotation.a(EnumDirection.NORTH)), iblockdata.get(BlockHugeMushroom.a)) ++ .set(BlockHugeMushroom.g.get(enumblockrotation.a(EnumDirection.SOUTH)), iblockdata.get(BlockHugeMushroom.c)) ++ .set(BlockHugeMushroom.g.get(enumblockrotation.a(EnumDirection.EAST)), iblockdata.get(BlockHugeMushroom.b)) ++ .set(BlockHugeMushroom.g.get(enumblockrotation.a(EnumDirection.WEST)), iblockdata.get(BlockHugeMushroom.d)) ++ .set(BlockHugeMushroom.g.get(enumblockrotation.a(EnumDirection.UP)), iblockdata.get(BlockHugeMushroom.e)) ++ .set(BlockHugeMushroom.g.get(enumblockrotation.a(EnumDirection.DOWN)), iblockdata.get(BlockHugeMushroom.f)); + } + + @Override + public IBlockData a(IBlockData iblockdata, EnumBlockMirror enumblockmirror) { +- return (IBlockData) ((IBlockData) ((IBlockData) ((IBlockData) ((IBlockData) ((IBlockData) iblockdata.set((IBlockState) BlockHugeMushroom.g.get(enumblockmirror.b(EnumDirection.NORTH)), iblockdata.get(BlockHugeMushroom.a))).set((IBlockState) BlockHugeMushroom.g.get(enumblockmirror.b(EnumDirection.SOUTH)), iblockdata.get(BlockHugeMushroom.c))).set((IBlockState) BlockHugeMushroom.g.get(enumblockmirror.b(EnumDirection.EAST)), iblockdata.get(BlockHugeMushroom.b))).set((IBlockState) BlockHugeMushroom.g.get(enumblockmirror.b(EnumDirection.WEST)), iblockdata.get(BlockHugeMushroom.d))).set((IBlockState) BlockHugeMushroom.g.get(enumblockmirror.b(EnumDirection.UP)), iblockdata.get(BlockHugeMushroom.e))).set((IBlockState) BlockHugeMushroom.g.get(enumblockmirror.b(EnumDirection.DOWN)), iblockdata.get(BlockHugeMushroom.f)); ++ if (net.pl3x.purpur.PurpurConfig.disableMushroomBlockUpdates) return iblockdata; ++ return iblockdata ++ .set(BlockHugeMushroom.g.get(enumblockmirror.b(EnumDirection.NORTH)), iblockdata.get(BlockHugeMushroom.a)) ++ .set(BlockHugeMushroom.g.get(enumblockmirror.b(EnumDirection.SOUTH)), iblockdata.get(BlockHugeMushroom.c)) ++ .set(BlockHugeMushroom.g.get(enumblockmirror.b(EnumDirection.EAST)), iblockdata.get(BlockHugeMushroom.b)) ++ .set(BlockHugeMushroom.g.get(enumblockmirror.b(EnumDirection.WEST)), iblockdata.get(BlockHugeMushroom.d)) ++ .set(BlockHugeMushroom.g.get(enumblockmirror.b(EnumDirection.UP)), iblockdata.get(BlockHugeMushroom.e)) ++ .set(BlockHugeMushroom.g.get(enumblockmirror.b(EnumDirection.DOWN)), iblockdata.get(BlockHugeMushroom.f)); + } + + @Override +diff --git a/src/main/java/net/minecraft/world/level/block/BlockNote.java b/src/main/java/net/minecraft/world/level/block/BlockNote.java +index feec1db88b22a4d13ffd3034633da79ed41b94fe..148718f8f96d94e76a4a7a96d5955b624c2dc661 100644 +--- a/src/main/java/net/minecraft/world/level/block/BlockNote.java ++++ b/src/main/java/net/minecraft/world/level/block/BlockNote.java +@@ -35,11 +35,13 @@ public class BlockNote extends Block { + + @Override + public IBlockData getPlacedState(BlockActionContext blockactioncontext) { ++ if (net.pl3x.purpur.PurpurConfig.disableNoteBlockUpdates) return this.getBlockData(); // Purpur + return (IBlockData) this.getBlockData().set(BlockNote.INSTRUMENT, BlockPropertyInstrument.a(blockactioncontext.getWorld().getType(blockactioncontext.getClickPosition().down()))); + } + + @Override + public IBlockData updateState(IBlockData iblockdata, EnumDirection enumdirection, IBlockData iblockdata1, GeneratorAccess generatoraccess, BlockPosition blockposition, BlockPosition blockposition1) { ++ if (net.pl3x.purpur.PurpurConfig.disableNoteBlockUpdates) return iblockdata; // Purpur + return enumdirection == EnumDirection.DOWN ? (IBlockData) iblockdata.set(BlockNote.INSTRUMENT, BlockPropertyInstrument.a(iblockdata1)) : super.updateState(iblockdata, enumdirection, iblockdata1, generatoraccess, blockposition, blockposition1); + } + +diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java +index 013f8a21be68f4e0470c0b873252bf21dd611127..ad41b9a096e8618a1a033a47918dd26c75781f96 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java +@@ -202,6 +202,15 @@ public class PurpurConfig { + allowWaterPlacementInTheEnd = getBoolean("settings.allow-water-placement-in-the-end", allowWaterPlacementInTheEnd); + } + ++ public static boolean disableMushroomBlockUpdates = false; ++ public static boolean disableNoteBlockUpdates = false; ++ public static boolean disableChorusPlantUpdates = false; ++ private static void blockUpdatesSettings() { ++ disableMushroomBlockUpdates = getBoolean("settings.blocks.disable-mushroom-updates", disableMushroomBlockUpdates); ++ disableNoteBlockUpdates = getBoolean("settings.blocks.disable-note-block-updates", disableNoteBlockUpdates); ++ disableChorusPlantUpdates = getBoolean("settings.blocks.disable-chorus-plant-updates", disableChorusPlantUpdates); ++ } ++ + public static boolean loggerSuppressInitLegacyMaterialError = false; + public static boolean loggerSuppressIgnoredAdvancementWarnings = false; + private static void loggerSettings() { diff --git a/patches/Purpur/patches/server/0094-Dispensers-place-anvils-option.patch b/patches/Purpur/patches/server/0094-Dispensers-place-anvils-option.patch new file mode 100644 index 00000000..68248f4e --- /dev/null +++ b/patches/Purpur/patches/server/0094-Dispensers-place-anvils-option.patch @@ -0,0 +1,85 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Tue, 4 Aug 2020 21:11:03 -0500 +Subject: [PATCH] Dispensers place anvils option + + +diff --git a/src/main/java/net/minecraft/core/EnumDirection.java b/src/main/java/net/minecraft/core/EnumDirection.java +index 7918d830a4aef09c9f517284e83a9376299116ad..29d747f7fc5824a222755ebf96dfe053896d43d0 100644 +--- a/src/main/java/net/minecraft/core/EnumDirection.java ++++ b/src/main/java/net/minecraft/core/EnumDirection.java +@@ -116,6 +116,7 @@ public enum EnumDirection implements INamable { + return fromType1(this.h); + } + ++ public EnumDirection rotateCW() { return g(); } // Purpur - OBFHELPER + public EnumDirection g() { + switch (this) { + case NORTH: +@@ -131,6 +132,7 @@ public enum EnumDirection implements INamable { + } + } + ++ public EnumDirection rotateCCW() { return h(); } // Purpur - OBFHELPER + public EnumDirection h() { + switch (this) { + case NORTH: +@@ -162,6 +164,7 @@ public enum EnumDirection implements INamable { + return this.j; + } + ++ public EnumDirection.EnumAxis getAxis() { return n(); } // Purpur - OBFHELPER + public EnumDirection.EnumAxis n() { + return this.k; + } +diff --git a/src/main/java/net/minecraft/core/dispenser/IDispenseBehavior.java b/src/main/java/net/minecraft/core/dispenser/IDispenseBehavior.java +index 0055a96b51a1d38d31e129c417c97bcfc9d0b745..31237773907341ee64c71507b5e1bf247ef2c524 100644 +--- a/src/main/java/net/minecraft/core/dispenser/IDispenseBehavior.java ++++ b/src/main/java/net/minecraft/core/dispenser/IDispenseBehavior.java +@@ -52,6 +52,7 @@ import net.minecraft.world.level.IMaterial; + import net.minecraft.world.level.IWorldReader; + import net.minecraft.world.level.World; + import net.minecraft.world.level.block.Block; ++import net.minecraft.world.level.block.BlockAnvil; + import net.minecraft.world.level.block.BlockBeehive; + import net.minecraft.world.level.block.BlockCampfire; + import net.minecraft.world.level.block.BlockDispenser; +@@ -995,6 +996,23 @@ public interface IDispenseBehavior { + } + })); + BlockDispenser.a((IMaterial) Items.SHEARS.getItem(), (IDispenseBehavior) (new DispenseBehaviorShears())); ++ // Purpur start ++ BlockDispenser.a(Blocks.ANVIL, new DispenseBehaviorMaybe() { ++ @Override ++ protected ItemStack a(ISourceBlock dispenser, ItemStack itemstack) { ++ World world = dispenser.getWorld(); ++ if (!world.purpurConfig.dispenserPlaceAnvils) return super.a(dispenser, itemstack); ++ EnumDirection facing = dispenser.getBlockData().get(BlockDispenser.FACING); ++ BlockPosition blockposition = dispenser.getBlockPosition().shift(facing); ++ IBlockData iblockdata = world.getType(blockposition); ++ if (iblockdata.isAir()) { ++ world.setTypeUpdate(blockposition, Blocks.ANVIL.getBlockData().set(BlockAnvil.FACING, facing.getAxis() == EnumDirection.EnumAxis.Y ? EnumDirection.NORTH : facing.rotateCW())); ++ itemstack.subtract(1); ++ } ++ return itemstack; ++ } ++ }); ++ // Purpur end + } + + static void a(ISourceBlock isourceblock, Entity entity, EnumDirection enumdirection) { +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index b328c9f69fd43ca7ed57ee7f5b46ca998f2cb672..54b8021bfac69800d4cec996a94c2fea53249130 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -297,8 +297,10 @@ public class PurpurWorldConfig { + } + + public boolean dispenserApplyCursedArmor = true; ++ public boolean dispenserPlaceAnvils = false; + private void dispenserSettings() { + dispenserApplyCursedArmor = getBoolean("blocks.dispenser.apply-cursed-to-armor-slots", dispenserApplyCursedArmor); ++ dispenserPlaceAnvils = getBoolean("blocks.dispenser.place-anvils", dispenserPlaceAnvils); + } + + public boolean farmlandGetsMoistFromBelow = false; diff --git a/patches/Purpur/patches/server/0095-Allow-anvil-colors.patch b/patches/Purpur/patches/server/0095-Allow-anvil-colors.patch new file mode 100644 index 00000000..21f2238b --- /dev/null +++ b/patches/Purpur/patches/server/0095-Allow-anvil-colors.patch @@ -0,0 +1,58 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Tue, 4 Aug 2020 22:08:23 -0500 +Subject: [PATCH] Allow anvil colors + + +diff --git a/src/main/java/net/minecraft/world/inventory/ContainerAnvil.java b/src/main/java/net/minecraft/world/inventory/ContainerAnvil.java +index 1b2d633f3d5d735039f18f27fb1387bd5a74f0d8..77810fbb70bf2e1ad03c28c0d69ceaa63221d94c 100644 +--- a/src/main/java/net/minecraft/world/inventory/ContainerAnvil.java ++++ b/src/main/java/net/minecraft/world/inventory/ContainerAnvil.java +@@ -28,6 +28,13 @@ import org.apache.logging.log4j.Logger; + import org.bukkit.craftbukkit.inventory.CraftInventoryView; + // CraftBukkit end + ++// Purpur start ++import io.papermc.paper.adventure.PaperAdventure; ++import net.kyori.adventure.text.Component; ++ ++import static net.kyori.adventure.text.format.TextDecoration.ITALIC; ++// Purpur end ++ + public class ContainerAnvil extends ContainerAnvilAbstract { + + private static final Logger LOGGER = LogManager.getLogger(); +@@ -269,6 +276,17 @@ public class ContainerAnvil extends ContainerAnvilAbstract { + } else if (!this.renameText.equals(itemstack.getName().getString())) { + b1 = 1; + i += b1; ++ // Purpur start ++ if (player != null && player.world.purpurConfig.anvilAllowColors && player.getBukkitEntity().hasPermission("purpur.anvil.color")) { ++ final Component renameTextComponent; ++ if (renameText.startsWith("&r") && player.getBukkitEntity().hasPermission("purpur.anvil.remove_italics")) { ++ renameTextComponent = PaperAdventure.LEGACY_AMPERSAND.deserialize(renameText.substring(2)).decoration(ITALIC, false); ++ } else { ++ renameTextComponent = PaperAdventure.LEGACY_AMPERSAND.deserialize(renameText); ++ } ++ itemstack1.a(PaperAdventure.asVanilla(renameTextComponent)); ++ } else ++ // Purpur end + itemstack1.a((IChatBaseComponent) (new ChatComponentText(this.renameText))); + } + +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 54b8021bfac69800d4cec996a94c2fea53249130..96e5aaec4e35bd092e9a71ca5cb61c6a66b9c0fc 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -280,6 +280,11 @@ public class PurpurWorldConfig { + }); + } + ++ public boolean anvilAllowColors = false; ++ private void anvilSettings() { ++ anvilAllowColors = getBoolean("blocks.anvil.allow-colors", anvilAllowColors); ++ } ++ + public boolean bedExplode = true; + public double bedExplosionPower = 5.0D; + public boolean bedExplosionFire = true; diff --git a/patches/Purpur/patches/server/0096-Add-no-random-tick-block-list.patch b/patches/Purpur/patches/server/0096-Add-no-random-tick-block-list.patch new file mode 100644 index 00000000..4afaaa04 --- /dev/null +++ b/patches/Purpur/patches/server/0096-Add-no-random-tick-block-list.patch @@ -0,0 +1,88 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Fri, 7 Aug 2020 12:53:36 -0500 +Subject: [PATCH] Add no-random-tick block list + + +diff --git a/src/main/java/net/minecraft/server/level/WorldServer.java b/src/main/java/net/minecraft/server/level/WorldServer.java +index a0c731af6dffa30832b321f8fd86cef76ec06522..9668619480706cb5d3a3e2ed0d85ac5bdd6b3c1f 100644 +--- a/src/main/java/net/minecraft/server/level/WorldServer.java ++++ b/src/main/java/net/minecraft/server/level/WorldServer.java +@@ -532,14 +532,14 @@ public class WorldServer extends World implements GeneratorAccessSeed { + // CraftBukkit end + if (com.destroystokyo.paper.PaperConfig.useOptimizedTickList) { + this.nextTickListBlock = new com.destroystokyo.paper.server.ticklist.PaperTickList<>(this, (block) -> { +- return block == null || block.getBlockData().isAir(); ++ return block == null || block.getBlockData().isAir() || purpurConfig.noRandomTickBlocks.contains(block); // Purpur + }, IRegistry.BLOCK::getKey, this::b, "Blocks"); // Paper - Timings + this.nextTickListFluid = new com.destroystokyo.paper.server.ticklist.PaperTickList<>(this, (fluidtype) -> { + return fluidtype == null || fluidtype == FluidTypes.EMPTY; + }, IRegistry.FLUID::getKey, this::a, "Fluids"); // Paper - Timings + } else { + this.nextTickListBlock = new TickListServer<>(this, (block) -> { +- return block == null || block.getBlockData().isAir(); ++ return block == null || block.getBlockData().isAir() || purpurConfig.noRandomTickBlocks.contains(block); // Purpur + }, IRegistry.BLOCK::getKey, this::b, "Blocks"); // Paper - Timings + this.nextTickListFluid = new TickListServer<>(this, (fluidtype) -> { + return fluidtype == null || fluidtype == FluidTypes.EMPTY; +diff --git a/src/main/java/net/minecraft/world/level/block/state/BlockBase.java b/src/main/java/net/minecraft/world/level/block/state/BlockBase.java +index 1d82f719440c95765c01a588f4785d630b8b527a..0ea0a1fc5f4d879d48bbdf24731dabec10dbccd1 100644 +--- a/src/main/java/net/minecraft/world/level/block/state/BlockBase.java ++++ b/src/main/java/net/minecraft/world/level/block/state/BlockBase.java +@@ -671,10 +671,12 @@ public abstract class BlockBase { + } + + public void a(WorldServer worldserver, BlockPosition blockposition, Random random) { ++ if (worldserver.purpurConfig.noRandomTickBlocks.contains(getBlock())) return; // Purpur + this.getBlock().tickAlways(this.p(), worldserver, blockposition, random); + } + + public void b(WorldServer worldserver, BlockPosition blockposition, Random random) { ++ if (worldserver.purpurConfig.noRandomTickBlocks.contains(getBlock())) return; // Purpur + this.getBlock().tick(this.p(), worldserver, blockposition, random); + } + +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 96e5aaec4e35bd092e9a71ca5cb61c6a66b9c0fc..aa4302ba319c0968632025524d5a9c5479a693e2 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -11,8 +11,10 @@ import org.bukkit.configuration.ConfigurationSection; + + import java.util.ArrayList; + import java.util.HashMap; ++import java.util.HashSet; + import java.util.List; + import java.util.Map; ++import java.util.Set; + import java.util.logging.Level; + + import static net.pl3x.purpur.PurpurConfig.log; +@@ -247,6 +249,28 @@ public class PurpurWorldConfig { + playerInvulnerableWhileAcceptingResourcePack = getBoolean("gameplay-mechanics.player.invulnerable-while-accepting-resource-pack", playerInvulnerableWhileAcceptingResourcePack); + } + ++ public Set noRandomTickBlocks = new HashSet<>(); ++ private void noRandomTickBlocks() { ++ if (PurpurConfig.version < 11) { ++ List oldList = PurpurConfig.config.getStringList("world-settings." + worldName + ".blocks.no-tick"); ++ if (!oldList.isEmpty()) { ++ PurpurConfig.config.set("world-settings." + worldName + ".blocks.no-random-tick", oldList); ++ PurpurConfig.config.set("world-settings." + worldName + ".blocks.no-tick", null); ++ } ++ oldList = PurpurConfig.config.getStringList("world-settings.default.blocks.no-tick"); ++ if (!oldList.isEmpty()) { ++ PurpurConfig.config.set("world-settings.default.blocks.no-random-tick", oldList); ++ PurpurConfig.config.set("world-settings.default.blocks.no-tick", null); ++ } ++ } ++ getList("blocks.no-random-tick", new ArrayList<>()).forEach(key -> { ++ Block block = IRegistry.BLOCK.get(new MinecraftKey(key.toString())); ++ if (!block.getBlockData().isAir()) { ++ noRandomTickBlocks.add(block); ++ } ++ }); ++ } ++ + public boolean teleportIfOutsideBorder = false; + private void teleportIfOutsideBorder() { + teleportIfOutsideBorder = getBoolean("gameplay-mechanics.player.teleport-if-outside-border", teleportIfOutsideBorder); diff --git a/patches/Purpur/patches/server/0097-Add-option-to-disable-dolphin-treasure-searching.patch b/patches/Purpur/patches/server/0097-Add-option-to-disable-dolphin-treasure-searching.patch new file mode 100644 index 00000000..b6405f16 --- /dev/null +++ b/patches/Purpur/patches/server/0097-Add-option-to-disable-dolphin-treasure-searching.patch @@ -0,0 +1,34 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sat, 8 Aug 2020 16:11:51 -0500 +Subject: [PATCH] Add option to disable dolphin treasure searching + + +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityDolphin.java b/src/main/java/net/minecraft/world/entity/animal/EntityDolphin.java +index 5d18e19eafd5dc01a6caa45075d8c0598f1bb709..e0a9b931c26dbd4e7739d09ae45e1cee72ab210c 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityDolphin.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityDolphin.java +@@ -393,6 +393,7 @@ public class EntityDolphin extends EntityWaterAnimal { + + @Override + public boolean a() { ++ if (this.a.world.purpurConfig.dolphinDisableTreasureSearching) return false; // Purpur + return this.a.gotFish() && this.a.getAirTicks() >= 100 && this.a.world.getWorld().canGenerateStructures(); // MC-151364, SPIGOT-5494: hangs if generate-structures=false + } + +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index aa4302ba319c0968632025524d5a9c5479a693e2..c2e4a8a50b0e70283fccce265e76fa78841f47b9 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -411,6 +411,11 @@ public class PurpurWorldConfig { + creeperChargedChance = getDouble("mobs.creeper.naturally-charged-chance", creeperChargedChance); + } + ++ public boolean dolphinDisableTreasureSearching = false; ++ private void dolphinSettings() { ++ dolphinDisableTreasureSearching = getBoolean("mobs.dolphin.disable-treasure-searching", dolphinDisableTreasureSearching); ++ } ++ + public boolean drownedJockeyOnlyBaby = true; + public double drownedJockeyChance = 0.05D; + public boolean drownedJockeyTryExistingChickens = true; diff --git a/patches/Purpur/patches/server/0098-Short-enderman-height.patch b/patches/Purpur/patches/server/0098-Short-enderman-height.patch new file mode 100644 index 00000000..71441886 --- /dev/null +++ b/patches/Purpur/patches/server/0098-Short-enderman-height.patch @@ -0,0 +1,58 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Mon, 10 Aug 2020 21:46:22 -0500 +Subject: [PATCH] Short enderman height + + +diff --git a/src/main/java/net/minecraft/world/entity/EntityTypes.java b/src/main/java/net/minecraft/world/entity/EntityTypes.java +index 1bfde4cfc0f27705238abf7852ad9bb7997e23e6..2cf4e8f68fa85c4e09effda0da0c3a3f64ae7ba9 100644 +--- a/src/main/java/net/minecraft/world/entity/EntityTypes.java ++++ b/src/main/java/net/minecraft/world/entity/EntityTypes.java +@@ -268,7 +268,8 @@ public class EntityTypes { + private IChatBaseComponent bp; + @Nullable + private MinecraftKey bq; +- private final EntitySize br; ++ public void setEntitySize(EntitySize entitySize) { this.br = entitySize; } // Purpur - OBFHELPER ++ private EntitySize br; // Purpur - remove final + + private static EntityTypes a(String s, EntityTypes.Builder entitytypes_builder) { // CraftBukkit - decompile error + return (EntityTypes) IRegistry.a((IRegistry) IRegistry.ENTITY_TYPE, s, (Object) entitytypes_builder.a(s)); +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityEnderman.java b/src/main/java/net/minecraft/world/entity/monster/EntityEnderman.java +index 6a5593ff735a9e0486d7ed9b3afb4f44ad156b34..1e50f7c51f88afaed01777d2da9ed543718a610d 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityEnderman.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityEnderman.java +@@ -375,6 +375,7 @@ public class EntityEnderman extends EntityMonster implements IEntityAngerable { + public boolean damageEntity(DamageSource damagesource, float f) { + if (this.isInvulnerable(damagesource)) { + return false; ++ } else if (net.pl3x.purpur.PurpurConfig.endermanShortHeight && damagesource == DamageSource.STUCK) { return false; // Purpur - no suffocation damage if short height + } else if (damagesource instanceof EntityDamageSourceIndirect) { + if (this.tryEscape(EndermanEscapeEvent.Reason.INDIRECT)) { // Paper start + for (int i = 0; i < 64; ++i) { +diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java +index ad41b9a096e8618a1a033a47918dd26c75781f96..fc458beb3afcb9083b994246454c6ee3d94c80ac 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java +@@ -4,6 +4,8 @@ import co.aikar.timings.TimingsManager; + import com.google.common.base.Throwables; + import net.minecraft.locale.LocaleLanguage; + import net.minecraft.server.MinecraftServer; ++import net.minecraft.world.entity.EntitySize; ++import net.minecraft.world.entity.EntityTypes; + import net.pl3x.purpur.command.PurpurCommand; + import org.bukkit.Bukkit; + import org.bukkit.command.Command; +@@ -192,6 +194,12 @@ public class PurpurConfig { + enderChestPermissionRows = getBoolean("settings.blocks.ender_chest.use-permissions-for-rows", enderChestPermissionRows); + } + ++ public static boolean endermanShortHeight = false; ++ private static void entitySettings() { ++ endermanShortHeight = getBoolean("settings.entity.enderman.short-height", endermanShortHeight); ++ if (endermanShortHeight) EntityTypes.ENDERMAN.setEntitySize(EntitySize.b(0.6F, 1.9F)); ++ } ++ + public static boolean dontSendUselessEntityPackets = false; + private static void dontSendUselessEntityPackets() { + dontSendUselessEntityPackets = getBoolean("settings.dont-send-useless-entity-packets", dontSendUselessEntityPackets); diff --git a/patches/Purpur/patches/server/0099-Stop-squids-floating-on-top-of-water.patch b/patches/Purpur/patches/server/0099-Stop-squids-floating-on-top-of-water.patch new file mode 100644 index 00000000..b9dc8544 --- /dev/null +++ b/patches/Purpur/patches/server/0099-Stop-squids-floating-on-top-of-water.patch @@ -0,0 +1,67 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Thu, 13 Aug 2020 04:00:26 -0500 +Subject: [PATCH] Stop squids floating on top of water + + +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index 6dc051e0da0a97bcd9e4cba94c2cabc411ebb86f..fdb7f1b582b791a938451b90914b621347a48189 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -3590,8 +3590,13 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, ne + this.lastYaw = this.yaw; + } + ++ // Purpur start ++ public AxisAlignedBB getAxisForFluidCheck() { ++ return this.getBoundingBox().shrink(0.001D); ++ } + public boolean a(Tag tag, double d0) { +- AxisAlignedBB axisalignedbb = this.getBoundingBox().shrink(0.001D); ++ AxisAlignedBB axisalignedbb = getAxisForFluidCheck(); ++ // Purpur end + int i = MathHelper.floor(axisalignedbb.minX); + int j = MathHelper.f(axisalignedbb.maxX); + int k = MathHelper.floor(axisalignedbb.minY); +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntitySquid.java b/src/main/java/net/minecraft/world/entity/animal/EntitySquid.java +index 1f5f3e0d209426b97e32b82dd15176b800f85816..e6757b22497c6e274c3999d58671653e931ebe2b 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntitySquid.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntitySquid.java +@@ -27,6 +27,7 @@ import net.minecraft.world.level.GeneratorAccess; + import net.minecraft.world.level.World; + import net.minecraft.world.level.block.state.IBlockData; + import net.minecraft.world.level.material.Fluid; ++import net.minecraft.world.phys.AxisAlignedBB; + import net.minecraft.world.phys.Vec3D; + + public class EntitySquid extends EntityWaterAnimal { +@@ -52,6 +53,14 @@ public class EntitySquid extends EntityWaterAnimal { + this.bu = 1.0F / (this.random.nextFloat() + 1.0F) * 0.2F; + } + ++ // Purpur start ++ @Override ++ public AxisAlignedBB getAxisForFluidCheck() { ++ // Stops squids from floating just over the water ++ return this.getBoundingBox().shrink(0.001D).offsetY(world.purpurConfig.squidOffsetWaterCheck); ++ } ++ // Purpur end ++ + @Override + protected void initPathfinder() { + this.goalSelector.a(0, new EntitySquid.PathfinderGoalSquid(this)); +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index c2e4a8a50b0e70283fccce265e76fa78841f47b9..f16f99517999ccbb0b5a678ffcb3befc93a3ae45 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -557,8 +557,10 @@ public class PurpurWorldConfig { + } + + public boolean squidImmuneToEAR = true; ++ public double squidOffsetWaterCheck = 0.0D; + private void squidSettings() { + squidImmuneToEAR = getBoolean("mobs.squid.immune-to-EAR", squidImmuneToEAR); ++ squidOffsetWaterCheck = getDouble("mobs.squid.water-offset-check", squidOffsetWaterCheck); + } + + public int villagerBrainTicks = 1; diff --git a/patches/Purpur/patches/server/0100-Ridables.patch b/patches/Purpur/patches/server/0100-Ridables.patch new file mode 100644 index 00000000..2d836595 --- /dev/null +++ b/patches/Purpur/patches/server/0100-Ridables.patch @@ -0,0 +1,7069 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sun, 5 Jul 2020 22:19:49 -0500 +Subject: [PATCH] Ridables + + +diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java +index afe3c53252354760b22901f7f109fd5d265928e0..aacc1b82ed178d6c0e499a53ce1aec7e20dad875 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -1544,6 +1544,7 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant 0; // Paper + worldserver.hasEntityMoveEvent = EntityMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper ++ worldserver.hasRidableMoveEvent = net.pl3x.purpur.event.entity.RidableMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Purpur + TileEntityHopper.skipHopperEvents = worldserver.paperConfig.disableHopperMoveEvents || org.bukkit.event.inventory.InventoryMoveItemEvent.getHandlerList().getRegisteredListeners().length == 0; // Paper + + this.methodProfiler.a(() -> { +diff --git a/src/main/java/net/minecraft/server/PathfinderGoalHasRider.java b/src/main/java/net/minecraft/server/PathfinderGoalHasRider.java +new file mode 100644 +index 0000000000000000000000000000000000000000..4c5dd9431b9afb2f110228d058d2b0f0808f0ab9 +--- /dev/null ++++ b/src/main/java/net/minecraft/server/PathfinderGoalHasRider.java +@@ -0,0 +1,21 @@ ++package net.minecraft.server; ++ ++import net.minecraft.world.entity.EntityInsentient; ++import net.minecraft.world.entity.ai.goal.PathfinderGoal; ++ ++import java.util.EnumSet; ++ ++public class PathfinderGoalHasRider extends PathfinderGoal { ++ public final EntityInsentient entity; ++ ++ public PathfinderGoalHasRider(EntityInsentient entity) { ++ this.entity = entity; ++ setTypes(EnumSet.of(Type.JUMP, Type.MOVE, Type.LOOK, Type.TARGET, Type.UNKNOWN_BEHAVIOR)); ++ } ++ ++ // shouldExecute ++ @Override ++ public boolean a() { ++ return entity.hasPurpurRider(); ++ } ++} +diff --git a/src/main/java/net/minecraft/server/PathfinderGoalHorseHasRider.java b/src/main/java/net/minecraft/server/PathfinderGoalHorseHasRider.java +new file mode 100644 +index 0000000000000000000000000000000000000000..8b66d1215a6eef1302b5ecb46a4b3d502846fef8 +--- /dev/null ++++ b/src/main/java/net/minecraft/server/PathfinderGoalHorseHasRider.java +@@ -0,0 +1,18 @@ ++package net.minecraft.server; ++ ++import net.minecraft.world.entity.animal.horse.EntityHorseAbstract; ++ ++public class PathfinderGoalHorseHasRider extends PathfinderGoalHasRider { ++ private final EntityHorseAbstract horse; ++ ++ public PathfinderGoalHorseHasRider(EntityHorseAbstract entity) { ++ super(entity); ++ this.horse = entity; ++ } ++ ++ // shouldExecute ++ @Override ++ public boolean a() { ++ return super.a() && horse.hasSaddle(); ++ } ++} +diff --git a/src/main/java/net/minecraft/server/level/EntityPlayer.java b/src/main/java/net/minecraft/server/level/EntityPlayer.java +index 38d63449b4ec833ec53de5fe6deebbb3f744492e..b66c50e078d83a1cda0f7010b353ae4b3ba9fd35 100644 +--- a/src/main/java/net/minecraft/server/level/EntityPlayer.java ++++ b/src/main/java/net/minecraft/server/level/EntityPlayer.java +@@ -80,7 +80,6 @@ import net.minecraft.server.network.PlayerConnection; + import net.minecraft.server.players.PlayerList; + import net.minecraft.sounds.SoundCategory; + import net.minecraft.sounds.SoundEffect; +-import net.minecraft.stats.RecipeBook; + import net.minecraft.stats.RecipeBookServer; + import net.minecraft.stats.ServerStatisticManager; + import net.minecraft.stats.Statistic; +@@ -132,7 +131,6 @@ import net.minecraft.world.level.block.entity.TileEntityCommand; + import net.minecraft.world.level.block.entity.TileEntitySign; + import net.minecraft.world.level.block.state.IBlockData; + import net.minecraft.world.level.portal.ShapeDetectorShape; +-import net.minecraft.world.level.storage.WorldData; + import net.minecraft.world.phys.AxisAlignedBB; + import net.minecraft.world.phys.Vec3D; + import net.minecraft.world.scores.ScoreboardScore; +@@ -652,6 +650,15 @@ public class EntityPlayer extends EntityHuman implements ICrafting { + } + + this.advancementDataPlayer.b(this); ++ ++ // Purpur start ++ if (this.world.purpurConfig.useNightVisionWhenRiding && this.getVehicle() != null && this.getVehicle().getPurpurRider() == this && world.getTime() % 100 == 0) { // 5 seconds ++ MobEffect nightVision = this.getEffect(MobEffects.NIGHT_VISION); ++ if (nightVision == null || nightVision.getDuration() <= 300) { // 15 seconds ++ this.addEffect(new MobEffect(MobEffects.NIGHT_VISION, 400, 0)); // 20 seconds ++ } ++ } ++ // Purpur end + } + + public void playerTick() { +diff --git a/src/main/java/net/minecraft/server/level/WorldServer.java b/src/main/java/net/minecraft/server/level/WorldServer.java +index 9668619480706cb5d3a3e2ed0d85ac5bdd6b3c1f..08e4fab02a740bf0c30985e2a858da2ae2caf8d8 100644 +--- a/src/main/java/net/minecraft/server/level/WorldServer.java ++++ b/src/main/java/net/minecraft/server/level/WorldServer.java +@@ -216,6 +216,7 @@ public class WorldServer extends World implements GeneratorAccessSeed { + public final UUID uuid; + public boolean hasPhysicsEvent = true; // Paper + public boolean hasEntityMoveEvent = false; // Paper ++ public boolean hasRidableMoveEvent = false; // Purpur + private static Throwable getAddToWorldStackTrace(Entity entity) { + return new Throwable(entity + " Added to world at " + new java.util.Date()); + } +diff --git a/src/main/java/net/minecraft/server/network/PlayerConnection.java b/src/main/java/net/minecraft/server/network/PlayerConnection.java +index 10c5af3949af4a3bee4999753e7545f0ac745e63..764ec67150a37f3a18eb1efde9d0c8810a92da6d 100644 +--- a/src/main/java/net/minecraft/server/network/PlayerConnection.java ++++ b/src/main/java/net/minecraft/server/network/PlayerConnection.java +@@ -2481,6 +2481,8 @@ public class PlayerConnection implements PacketListenerPlayIn { + } + this.server.getPluginManager().callEvent(event); + ++ player.processClick(enumhand); // Purpur ++ + // Fish bucket - SPIGOT-4048 + if ((entity instanceof EntityFish && origItem != null && origItem.getItem() == Items.WATER_BUCKET) && (event.isCancelled() || this.player.inventory.getItemInHand() == null || this.player.inventory.getItemInHand().getItem() != origItem)) { + this.sendPacket(new PacketPlayOutSpawnEntityLiving((EntityFish) entity)); +diff --git a/src/main/java/net/minecraft/world/damagesource/DamageSource.java b/src/main/java/net/minecraft/world/damagesource/DamageSource.java +index e6bf78f46acc37d9515d58cec3587e236ac0733c..5842d23a536449d0c394c7b23ee0cef3d54d8dff 100644 +--- a/src/main/java/net/minecraft/world/damagesource/DamageSource.java ++++ b/src/main/java/net/minecraft/world/damagesource/DamageSource.java +@@ -67,6 +67,7 @@ public class DamageSource { + return new EntityDamageSource("mob", entityliving); + } + ++ public static DamageSource indirectMobAttack(Entity entity, EntityLiving entityliving) { return a(entity, entityliving); } // Purpur - OBFHELPER + public static DamageSource a(Entity entity, EntityLiving entityliving) { + return new EntityDamageSourceIndirect("mob", entity, entityliving); + } +@@ -128,6 +129,7 @@ public class DamageSource { + return this.B; + } + ++ public DamageSource setProjectile() { return c(); } // Purpur - OBFHELPER + public DamageSource c() { + this.B = true; + return this; +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index fdb7f1b582b791a938451b90914b621347a48189..6d17a5f75e073acccabbad65b998b4eb9e8cf400 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -22,6 +22,7 @@ import net.minecraft.BlockUtil; + import net.minecraft.CrashReport; + import net.minecraft.CrashReportSystemDetails; + import net.minecraft.ReportedException; ++import net.minecraft.SystemUtils; + import net.minecraft.advancements.CriterionTriggers; + import net.minecraft.commands.CommandListenerWrapper; + import net.minecraft.commands.ICommandListener; +@@ -104,7 +105,6 @@ import net.minecraft.world.phys.AxisAlignedBB; + import net.minecraft.world.phys.MovingObjectPosition; + import net.minecraft.world.phys.Vec2F; + import net.minecraft.world.phys.Vec3D; +-import net.minecraft.world.phys.shapes.OperatorBoolean; + import net.minecraft.world.phys.shapes.VoxelShape; + import net.minecraft.world.phys.shapes.VoxelShapeCollision; + import net.minecraft.world.phys.shapes.VoxelShapes; +@@ -197,7 +197,7 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, ne + private int id; + public boolean i; public final boolean blocksEntitySpawning() { return this.i; } // Paper - OBFHELPER + public final List passengers; +- protected int j; ++ protected int j; public int getRideCooldown() { return j; } // Purpur - OBFHELPER + @Nullable + private Entity vehicle; + public boolean attachedToPlayer; +@@ -213,7 +213,7 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, ne + public float lastYaw; + public float lastPitch; + private AxisAlignedBB boundingBox; +- protected boolean onGround; ++ public boolean onGround; // Purpur - protected -> public + public boolean positionChanged; + public boolean v; + public boolean velocityChanged; +@@ -269,7 +269,7 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, ne + private boolean az; + private final double[] aA; + private long aB; +- private EntitySize size; ++ protected EntitySize size; // Purpur - private -> protected + private float headHeight; + // CraftBukkit start + public boolean persist = true; +@@ -1618,6 +1618,7 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, ne + return !this.justCreated && this.M.getDouble(TagsFluid.LAVA) > 0.0D; + } + ++ public void moveRelative(float speed, Vec3D motion) { this.a(speed, motion); } // Purpur - OBFHELPER + public void a(float f, Vec3D vec3d) { + Vec3D vec3d1 = a(vec3d, f, this.yaw); + +@@ -2379,6 +2380,7 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, ne + return this.a(entity, false); + } + ++ public boolean startRiding(Entity entity, boolean flag) { return a(entity, flag); } // Purpur - OBFHELPER + public boolean a(Entity entity, boolean flag) { + for (Entity entity1 = entity; entity1.vehicle != null; entity1 = entity1.vehicle) { + if (entity1.vehicle == this) { +@@ -2474,6 +2476,13 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, ne + this.passengers.add(entity); + } + ++ // Purpur start ++ if (isRidable() && passengers.get(0) == entity && entity instanceof EntityHuman) { ++ EntityHuman entityhuman = (EntityHuman) entity; ++ onMount(entityhuman); ++ this.purpurRider = entityhuman; ++ } ++ // Purpur end + } + return true; // CraftBukkit + } +@@ -2514,6 +2523,12 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, ne + return false; + } + // Spigot end ++ // Purpur start ++ if (purpurRider != null && passengers.get(0) == purpurRider) { ++ onDismount(purpurRider); ++ this.purpurRider = null; ++ } ++ // Purpur end + this.passengers.remove(entity); + entity.j = 60; + } +@@ -2680,6 +2695,7 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, ne + this.setFlag(4, flag); + } + ++ public boolean isGlowing() { return bE(); } // Purpur - OBFHELPER + public boolean bE() { + return this.glowing || this.world.isClientSide && this.getFlag(6); + } +@@ -2902,6 +2918,7 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, ne + + public void setHeadRotation(float f) {} + ++ public void setBodyYaw(float yaw) { n(yaw); } // Purpur - OBFHELPER + public void n(float f) {} + + public boolean bL() { +@@ -3343,6 +3360,18 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, ne + return false; + } + ++ // Purpur Start ++ public void sendMessage(String str) { ++ sendMessage(org.bukkit.craftbukkit.util.CraftChatMessage.fromStringOrNull(str)); ++ } ++ ++ public void sendMessage(IChatBaseComponent ichatbasecomponent) { ++ if (ichatbasecomponent != null) { ++ sendMessage(ichatbasecomponent, SystemUtils.getNullUUID()); ++ } ++ } ++ // Purpur end ++ + @Override + public void sendMessage(IChatBaseComponent ichatbasecomponent, UUID uuid) {} + +@@ -3795,4 +3824,47 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, ne + return ((ChunkProviderServer) world.getChunkProvider()).isInEntityTickingChunk(this); + } + // Paper end ++ ++ // Purpur start ++ private EntityHuman purpurRider; ++ ++ public EntityHuman getPurpurRider() { ++ return purpurRider; ++ } ++ ++ public boolean hasPurpurRider() { ++ return purpurRider != null; ++ } ++ ++ public boolean isRidable() { ++ return false; ++ } ++ ++ public boolean isRidableInWater() { ++ return false; ++ } ++ ++ public void onMount(EntityHuman entityhuman) { ++ if (this instanceof EntityInsentient) { ++ ((EntityInsentient) this).setGoalTarget(null, null, false); ++ ((EntityInsentient) this).getNavigation().stopPathfinding(); ++ } ++ entityhuman.setJumping(false); // fixes jump on mount ++ } ++ ++ public void onDismount(EntityHuman entityhuman) { ++ } ++ ++ public boolean onSpacebar() { ++ return false; ++ } ++ ++ public boolean onClick(EnumHand hand) { ++ return false; ++ } ++ ++ public boolean processClick(EnumHand hand) { ++ return false; ++ } ++ // Purpur end + } +diff --git a/src/main/java/net/minecraft/world/entity/EntityInsentient.java b/src/main/java/net/minecraft/world/entity/EntityInsentient.java +index fdc1b99f0a032a76a02ee88b28d62e049a2fc54c..0ee99a2c9a966eaaaf09879cce2f54bc68eb3151 100644 +--- a/src/main/java/net/minecraft/world/entity/EntityInsentient.java ++++ b/src/main/java/net/minecraft/world/entity/EntityInsentient.java +@@ -46,8 +46,6 @@ import net.minecraft.world.entity.ai.sensing.EntitySenses; + import net.minecraft.world.entity.decoration.EntityHanging; + import net.minecraft.world.entity.decoration.EntityLeash; + import net.minecraft.world.entity.item.EntityItem; +-import net.minecraft.world.entity.monster.EntityBlaze; +-import net.minecraft.world.entity.monster.EntityEnderman; + import net.minecraft.world.entity.monster.IMonster; + import net.minecraft.world.entity.npc.EntityVillagerAbstract; + import net.minecraft.world.entity.player.EntityHuman; +@@ -100,7 +98,7 @@ public abstract class EntityInsentient extends EntityLiving { + protected int f; + protected ControllerLook lookController; + protected ControllerMove moveController; +- protected ControllerJump bi; ++ protected ControllerJump bi; public ControllerJump getJumpController() { return bi; } // Purpur - OBFHELPER + private final EntityAIBodyControl c; + protected NavigationAbstract navigation; + public PathfinderGoalSelector goalSelector; +@@ -138,8 +136,8 @@ public abstract class EntityInsentient extends EntityLiving { + this.bA = -1.0F; + this.goalSelector = new PathfinderGoalSelector(world.getMethodProfilerSupplier()); + this.targetSelector = new PathfinderGoalSelector(world.getMethodProfilerSupplier()); +- this.lookController = new ControllerLook(this); +- this.moveController = new ControllerMove(this); ++ this.lookController = new net.pl3x.purpur.controller.ControllerLookWASD(this); // Purpur ++ this.moveController = new net.pl3x.purpur.controller.ControllerMoveWASD(this); // Purpur + this.bi = new ControllerJump(this); + this.c = this.r(); + this.navigation = this.b(world); +@@ -328,10 +326,10 @@ public abstract class EntityInsentient extends EntityLiving { + // Purpur start + private void incrementTicksSinceLastInteraction() { + ++ticksSinceLastInteraction; +- //if (hasRider()) { +- // ticksSinceLastInteraction = 0; +- // return; +- //} ++ if (hasPurpurRider()) { ++ ticksSinceLastInteraction = 0; ++ return; ++ } + if (world.purpurConfig.entityLifeSpan <= 0) { + return; // feature disabled + } +@@ -626,14 +624,17 @@ public abstract class EntityInsentient extends EntityLiving { + return super.dp(); + } + ++ public void setForwardSpeed(float speed) { this.t(speed); } // Purpur - OBFHELPER + public void t(float f) { + this.aT = f; + } + ++ public void setVerticalSpeed(float speed) { this.u(speed); } // Purpur - OBFHELPER + public void u(float f) { + this.aS = f; + } + ++ public void setStrafeSpeed(float speed) { this.v(speed); } // Purpur - OBFHELPER + public void v(float f) { + this.aR = f; + } +@@ -1326,7 +1327,7 @@ public abstract class EntityInsentient extends EntityLiving { + protected void a(EntityHuman entityhuman, EntityInsentient entityinsentient) {} + + protected EnumInteractionResult b(EntityHuman entityhuman, EnumHand enumhand) { +- return EnumInteractionResult.PASS; ++ return tryRide(entityhuman, enumhand); // Purpur + } + + public boolean ev() { +@@ -1707,4 +1708,54 @@ public abstract class EntityInsentient extends EntityLiving { + this.unleash(true, event.isDropLeash()); + // Paper end + } ++ ++ // Purpur start ++ public double getMaxY() { ++ return world.getHeight(); ++ } ++ ++ public EnumInteractionResult tryRide(EntityHuman entityhuman, EnumHand enumhand) { ++ if (!isRidable()) { ++ return EnumInteractionResult.PASS; ++ } ++ if (enumhand != EnumHand.MAIN_HAND) { ++ return EnumInteractionResult.PASS; ++ } ++ if (entityhuman.isSneaking()) { ++ return EnumInteractionResult.PASS; ++ } ++ if (!entityhuman.getItemInHand(enumhand).isEmpty()) { ++ return EnumInteractionResult.PASS; ++ } ++ if (!passengers.isEmpty() || entityhuman.isPassenger()) { ++ return EnumInteractionResult.PASS; ++ } ++ if (this instanceof EntityTameableAnimal) { ++ EntityTameableAnimal tameable = (EntityTameableAnimal) this; ++ if (tameable.isTamed() && !tameable.isOwner(entityhuman)) { ++ return EnumInteractionResult.PASS; ++ } ++ if (!tameable.isTamed() && !world.purpurConfig.untamedTamablesAreRidable) { ++ return EnumInteractionResult.PASS; ++ } ++ } ++ if (this instanceof EntityAgeable) { ++ EntityAgeable ageable = (EntityAgeable) this; ++ if (ageable.isBaby() && !world.purpurConfig.babiesAreRidable) { ++ return EnumInteractionResult.PASS; ++ } ++ } ++ if (!entityhuman.getBukkitEntity().hasPermission("allow.ride." + getEntityType().getName())) { ++ entityhuman.sendMessage(net.pl3x.purpur.PurpurConfig.cannotRideMob); ++ return EnumInteractionResult.PASS; ++ } ++ entityhuman.yaw = this.yaw; ++ entityhuman.pitch = this.pitch; ++ if (entityhuman.startRiding(this)) { ++ return EnumInteractionResult.SUCCESS; ++ } else { ++ return EnumInteractionResult.PASS; ++ } ++ } ++ // Purpur end + } +diff --git a/src/main/java/net/minecraft/world/entity/EntityLiving.java b/src/main/java/net/minecraft/world/entity/EntityLiving.java +index 1140fc3cade24320bbc3e09a8664ded27df604fe..3b66833adcd3912ebbfac49f0a59b1dc6fb3971d 100644 +--- a/src/main/java/net/minecraft/world/entity/EntityLiving.java ++++ b/src/main/java/net/minecraft/world/entity/EntityLiving.java +@@ -558,7 +558,7 @@ public abstract class EntityLiving extends Entity { + + @Override + public boolean bt() { +- return false; ++ return isRidableInWater(); // Purpur + } + + protected void cU() { +@@ -2297,7 +2297,7 @@ public abstract class EntityLiving extends Entity { + return 0.42F * this.getBlockJumpFactor(); + } + +- protected void jump() { ++ public void jump() { // Purpur - protected -> public + float f = this.dJ(); + + if (this.hasEffect(MobEffects.JUMP)) { +@@ -2546,10 +2546,12 @@ public abstract class EntityLiving extends Entity { + return this.onGround ? this.dN() * (0.21600002F / (f * f * f)) : this.aE; + } + ++ public float getSpeed() { return dN(); } // Purpur - OBFHELPER + public float dN() { + return this.bu; + } + ++ public void setSpeed(float speed) { q(speed); } // Purpur - OBFHELPER + public void q(float f) { + this.bu = f; + } +@@ -2935,8 +2937,10 @@ public abstract class EntityLiving extends Entity { + this.collideNearby(); + this.world.getMethodProfiler().exit(); + // Paper start +- if (((WorldServer) world).hasEntityMoveEvent) { +- if (lastX != locX() || lastY != locY() || lastZ != locZ() || lastYaw != yaw || lastPitch != pitch) { ++ // Purpur start ++ if (lastX != locX() || lastY != locY() || lastZ != locZ() || lastYaw != yaw || lastPitch != pitch) { ++ if (((WorldServer) world).hasEntityMoveEvent) { ++ // Purpur end + Location from = new Location(world.getWorld(), lastX, lastY, lastZ, lastYaw, lastPitch); + Location to = new Location (world.getWorld(), locX(), locY(), locZ(), yaw, pitch); + EntityMoveEvent event = new EntityMoveEvent(getBukkitLivingEntity(), from, to.clone()); +@@ -2946,6 +2950,21 @@ public abstract class EntityLiving extends Entity { + setLocation(event.getTo().getX(), event.getTo().getY(), event.getTo().getZ(), event.getTo().getYaw(), event.getTo().getPitch()); + } + } ++ // Purpur start ++ if (hasPurpurRider()) { ++ getPurpurRider().resetIdleTimer(); ++ if (((WorldServer) world).hasRidableMoveEvent && this instanceof EntityInsentient) { ++ Location from = new Location(world.getWorld(), lastX, lastY, lastZ, lastYaw, lastPitch); ++ Location to = new Location(world.getWorld(), locX(), locY(), locZ(), yaw, pitch); ++ net.pl3x.purpur.event.entity.RidableMoveEvent event = new net.pl3x.purpur.event.entity.RidableMoveEvent((org.bukkit.entity.Mob) getBukkitLivingEntity(), (Player) getPurpurRider().getBukkitEntity(), from, to.clone()); ++ if (!event.callEvent()) { ++ setLocation(from.getX(), from.getY(), from.getZ(), from.getYaw(), from.getPitch()); ++ } else if (!to.equals(event.getTo())) { ++ setLocation(to.getX(), to.getY(), to.getZ(), to.getYaw(), to.getPitch()); ++ } ++ } ++ } ++ // Purpur end + } + // Paper end + if (!this.world.isClientSide && this.dO() && this.aG()) { +diff --git a/src/main/java/net/minecraft/world/entity/EntityTameableAnimal.java b/src/main/java/net/minecraft/world/entity/EntityTameableAnimal.java +index 74636c4c0851da1cd5732daa0a2d1a4edda2050f..cdb56555889d17913d7b0c03d5ba23408a500f26 100644 +--- a/src/main/java/net/minecraft/world/entity/EntityTameableAnimal.java ++++ b/src/main/java/net/minecraft/world/entity/EntityTameableAnimal.java +@@ -144,6 +144,7 @@ public abstract class EntityTameableAnimal extends EntityAnimal { + return this.i(entityliving) ? false : super.c(entityliving); + } + ++ public boolean isOwner(EntityLiving entityLiving) { return i(entityLiving); } // Purpur - OBFHELPER + public boolean i(EntityLiving entityliving) { + return entityliving == this.getOwner(); + } +diff --git a/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeDefaults.java b/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeDefaults.java +index 1b9cf77aa5d73b4834e5260a91d338620e0bb6b3..b6cc0e1286294e64568d11c452684071d4c5b636 100644 +--- a/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeDefaults.java ++++ b/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeDefaults.java +@@ -50,6 +50,7 @@ import net.minecraft.world.entity.monster.EntityGuardianElder; + import net.minecraft.world.entity.monster.EntityIllagerIllusioner; + import net.minecraft.world.entity.monster.EntityMagmaCube; + import net.minecraft.world.entity.monster.EntityMonster; ++import net.minecraft.world.entity.monster.EntityPhantom; + import net.minecraft.world.entity.monster.EntityPigZombie; + import net.minecraft.world.entity.monster.EntityPillager; + import net.minecraft.world.entity.monster.EntityRavager; +@@ -74,7 +75,80 @@ import org.apache.logging.log4j.Logger; + public class AttributeDefaults { + + private static final Logger LOGGER = LogManager.getLogger(); +- private static final Map, AttributeProvider> b = ImmutableMap.builder().put(EntityTypes.ARMOR_STAND, EntityLiving.cL().a()).put(EntityTypes.BAT, EntityBat.m().a()).put(EntityTypes.BEE, EntityBee.eZ().a()).put(EntityTypes.BLAZE, EntityBlaze.m().a()).put(EntityTypes.CAT, EntityCat.fa().a()).put(EntityTypes.CAVE_SPIDER, EntityCaveSpider.m().a()).put(EntityTypes.CHICKEN, EntityChicken.eK().a()).put(EntityTypes.COD, EntityFish.m().a()).put(EntityTypes.COW, EntityCow.eK().a()).put(EntityTypes.CREEPER, EntityCreeper.m().a()).put(EntityTypes.DOLPHIN, EntityDolphin.eM().a()).put(EntityTypes.DONKEY, EntityHorseChestedAbstract.eL().a()).put(EntityTypes.DROWNED, EntityZombie.eS().a()).put(EntityTypes.ELDER_GUARDIAN, EntityGuardianElder.m().a()).put(EntityTypes.ENDERMAN, EntityEnderman.m().a()).put(EntityTypes.ENDERMITE, EntityEndermite.m().a()).put(EntityTypes.ENDER_DRAGON, EntityEnderDragon.m().a()).put(EntityTypes.EVOKER, EntityEvoker.eK().a()).put(EntityTypes.FOX, EntityFox.eK().a()).put(EntityTypes.GHAST, EntityGhast.eJ().a()).put(EntityTypes.GIANT, EntityGiantZombie.m().a()).put(EntityTypes.GUARDIAN, EntityGuardian.eM().a()).put(EntityTypes.HOGLIN, EntityHoglin.eK().a()).put(EntityTypes.HORSE, EntityHorseAbstract.fi().a()).put(EntityTypes.HUSK, EntityZombie.eS().a()).put(EntityTypes.ILLUSIONER, EntityIllagerIllusioner.eK().a()).put(EntityTypes.IRON_GOLEM, EntityIronGolem.m().a()).put(EntityTypes.LLAMA, EntityLlama.fw().a()).put(EntityTypes.MAGMA_CUBE, EntityMagmaCube.m().a()).put(EntityTypes.MOOSHROOM, EntityCow.eK().a()).put(EntityTypes.MULE, EntityHorseChestedAbstract.eL().a()).put(EntityTypes.OCELOT, EntityOcelot.eK().a()).put(EntityTypes.PANDA, EntityPanda.eY().a()).put(EntityTypes.PARROT, EntityParrot.eU().a()).put(EntityTypes.PHANTOM, EntityMonster.eR().a()).put(EntityTypes.PIG, EntityPig.eK().a()).put(EntityTypes.PIGLIN, EntityPiglin.eT().a()).put(EntityTypes.PIGLIN_BRUTE, EntityPiglinBrute.eS().a()).put(EntityTypes.PILLAGER, EntityPillager.eK().a()).put(EntityTypes.PLAYER, EntityHuman.ep().a()).put(EntityTypes.POLAR_BEAR, EntityPolarBear.eK().a()).put(EntityTypes.PUFFERFISH, EntityFish.m().a()).put(EntityTypes.RABBIT, EntityRabbit.eL().a()).put(EntityTypes.RAVAGER, EntityRavager.m().a()).put(EntityTypes.SALMON, EntityFish.m().a()).put(EntityTypes.SHEEP, EntitySheep.eK().a()).put(EntityTypes.SHULKER, EntityShulker.m().a()).put(EntityTypes.SILVERFISH, EntitySilverfish.m().a()).put(EntityTypes.SKELETON, EntitySkeletonAbstract.m().a()).put(EntityTypes.SKELETON_HORSE, EntityHorseSkeleton.eL().a()).put(EntityTypes.SLIME, EntityMonster.eR().a()).put(EntityTypes.SNOW_GOLEM, EntitySnowman.m().a()).put(EntityTypes.SPIDER, EntitySpider.eK().a()).put(EntityTypes.SQUID, EntitySquid.m().a()).put(EntityTypes.STRAY, EntitySkeletonAbstract.m().a()).put(EntityTypes.STRIDER, EntityStrider.eM().a()).put(EntityTypes.TRADER_LLAMA, EntityLlama.fw().a()).put(EntityTypes.TROPICAL_FISH, EntityFish.m().a()).put(EntityTypes.TURTLE, EntityTurtle.eM().a()).put(EntityTypes.VEX, EntityVex.m().a()).put(EntityTypes.VILLAGER, EntityVillager.eY().a()).put(EntityTypes.VINDICATOR, EntityVindicator.eK().a()).put(EntityTypes.WANDERING_TRADER, EntityInsentient.p().a()).put(EntityTypes.WITCH, EntityWitch.eK().a()).put(EntityTypes.WITHER, EntityWither.eK().a()).put(EntityTypes.WITHER_SKELETON, EntitySkeletonAbstract.m().a()).put(EntityTypes.WOLF, EntityWolf.eU().a()).put(EntityTypes.ZOGLIN, EntityZoglin.m().a()).put(EntityTypes.ZOMBIE, EntityZombie.eS().a()).put(EntityTypes.ZOMBIE_HORSE, EntityHorseZombie.eL().a()).put(EntityTypes.ZOMBIE_VILLAGER, EntityZombie.eS().a()).put(EntityTypes.ZOMBIFIED_PIGLIN, EntityPigZombie.eW().a()).build(); ++ private static final Map, AttributeProvider> b = ImmutableMap., AttributeProvider>builder() // Purpur decompile error ++ .put(EntityTypes.ARMOR_STAND, EntityLiving.cL().a()) ++ .put(EntityTypes.BAT, EntityBat.m().a()) ++ .put(EntityTypes.BEE, EntityBee.eZ().a()) ++ .put(EntityTypes.BLAZE, EntityBlaze.m().a()) ++ .put(EntityTypes.CAT, EntityCat.fa().a()) ++ .put(EntityTypes.CAVE_SPIDER, EntityCaveSpider.m().a()) ++ .put(EntityTypes.CHICKEN, EntityChicken.eK().a()) ++ .put(EntityTypes.COD, EntityFish.m().a()) ++ .put(EntityTypes.COW, EntityCow.eK().a()) ++ .put(EntityTypes.CREEPER, EntityCreeper.m().a()) ++ .put(EntityTypes.DOLPHIN, EntityDolphin.eM().a()) ++ .put(EntityTypes.DONKEY, EntityHorseChestedAbstract.eL().a()) ++ .put(EntityTypes.DROWNED, EntityZombie.eS().a()) ++ .put(EntityTypes.ELDER_GUARDIAN, EntityGuardianElder.m().a()) ++ .put(EntityTypes.ENDERMAN, EntityEnderman.m().a()) ++ .put(EntityTypes.ENDERMITE, EntityEndermite.m().a()) ++ .put(EntityTypes.ENDER_DRAGON, EntityEnderDragon.m().a()) ++ .put(EntityTypes.EVOKER, EntityEvoker.eK().a()) ++ .put(EntityTypes.FOX, EntityFox.eK().a()) ++ .put(EntityTypes.GHAST, EntityGhast.eJ().a()) ++ .put(EntityTypes.GIANT, EntityGiantZombie.m().a()) ++ .put(EntityTypes.GUARDIAN, EntityGuardian.eM().a()) ++ .put(EntityTypes.HOGLIN, EntityHoglin.eK().a()) ++ .put(EntityTypes.HORSE, EntityHorseAbstract.fi().a()) ++ .put(EntityTypes.HUSK, EntityZombie.eS().a()) ++ .put(EntityTypes.ILLUSIONER, EntityIllagerIllusioner.eK().a()) ++ .put(EntityTypes.IRON_GOLEM, EntityIronGolem.m().a()) ++ .put(EntityTypes.LLAMA, EntityLlama.fw().a()) ++ .put(EntityTypes.MAGMA_CUBE, EntityMagmaCube.m().a()) ++ .put(EntityTypes.MOOSHROOM, EntityCow.eK().a()) ++ .put(EntityTypes.MULE, EntityHorseChestedAbstract.eL().a()) ++ .put(EntityTypes.OCELOT, EntityOcelot.eK().a()) ++ .put(EntityTypes.PANDA, EntityPanda.eY().a()) ++ .put(EntityTypes.PARROT, EntityParrot.eU().a()) ++ .put(EntityTypes.PHANTOM, EntityPhantom.defaultAttributes().build()) // Purpur ++ .put(EntityTypes.PIG, EntityPig.eK().a()) ++ .put(EntityTypes.PIGLIN, EntityPiglin.eT().a()) ++ .put(EntityTypes.PIGLIN_BRUTE, EntityPiglinBrute.eS().a()) ++ .put(EntityTypes.PILLAGER, EntityPillager.eK().a()) ++ .put(EntityTypes.PLAYER, EntityHuman.ep().a()) ++ .put(EntityTypes.POLAR_BEAR, EntityPolarBear.eK().a()) ++ .put(EntityTypes.PUFFERFISH, EntityFish.m().a()) ++ .put(EntityTypes.RABBIT, EntityRabbit.eL().a()) ++ .put(EntityTypes.RAVAGER, EntityRavager.m().a()) ++ .put(EntityTypes.SALMON, EntityFish.m().a()) ++ .put(EntityTypes.SHEEP, EntitySheep.eK().a()) ++ .put(EntityTypes.SHULKER, EntityShulker.m().a()) ++ .put(EntityTypes.SILVERFISH, EntitySilverfish.m().a()) ++ .put(EntityTypes.SKELETON, EntitySkeletonAbstract.m().a()) ++ .put(EntityTypes.SKELETON_HORSE, EntityHorseSkeleton.eL().a()) ++ .put(EntityTypes.SLIME, EntityMonster.eR().a()) ++ .put(EntityTypes.SNOW_GOLEM, EntitySnowman.m().a()) ++ .put(EntityTypes.SPIDER, EntitySpider.eK().a()) ++ .put(EntityTypes.SQUID, EntitySquid.m().a()) ++ .put(EntityTypes.STRAY, EntitySkeletonAbstract.m().a()) ++ .put(EntityTypes.STRIDER, EntityStrider.eM().a()) ++ .put(EntityTypes.TRADER_LLAMA, EntityLlama.fw().a()) ++ .put(EntityTypes.TROPICAL_FISH, EntityFish.m().a()) ++ .put(EntityTypes.TURTLE, EntityTurtle.eM().a()) ++ .put(EntityTypes.VEX, EntityVex.m().a()) ++ .put(EntityTypes.VILLAGER, EntityVillager.eY().a()) ++ .put(EntityTypes.VINDICATOR, EntityVindicator.eK().a()) ++ .put(EntityTypes.WANDERING_TRADER, EntityInsentient.p().a()) ++ .put(EntityTypes.WITCH, EntityWitch.eK().a()) ++ .put(EntityTypes.WITHER, EntityWither.eK().a()) ++ .put(EntityTypes.WITHER_SKELETON, EntitySkeletonAbstract.m().a()) ++ .put(EntityTypes.WOLF, EntityWolf.eU().a()) ++ .put(EntityTypes.ZOGLIN, EntityZoglin.m().a()) ++ .put(EntityTypes.ZOMBIE, EntityZombie.eS().a()) ++ .put(EntityTypes.ZOMBIE_HORSE, EntityHorseZombie.eL().a()) ++ .put(EntityTypes.ZOMBIE_VILLAGER, EntityZombie.eS().a()) ++ .put(EntityTypes.ZOMBIFIED_PIGLIN, EntityPigZombie.eW().a()) ++ .build(); + + public static AttributeProvider a(EntityTypes entitytypes) { + return (AttributeProvider) AttributeDefaults.b.get(entitytypes); +diff --git a/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeProvider.java b/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeProvider.java +index c75659d0f2a6a198f338c38b600e639a4cb3d9ee..5edad3ee07cc0357442ede3a1e14e8d5c121e530 100644 +--- a/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeProvider.java ++++ b/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeProvider.java +@@ -102,6 +102,7 @@ public class AttributeProvider { + return this; + } + ++ public AttributeProvider build() { return a(); } // Purpur - OBFHELPER + public AttributeProvider a() { + this.b = true; + return new AttributeProvider(this.a); +diff --git a/src/main/java/net/minecraft/world/entity/ai/control/ControllerLookDolphin.java b/src/main/java/net/minecraft/world/entity/ai/control/ControllerLookDolphin.java +index bf059f201c662d6492b093184e7feec711b846e8..1b472a659c140b368173237d54633f0dfbeb7419 100644 +--- a/src/main/java/net/minecraft/world/entity/ai/control/ControllerLookDolphin.java ++++ b/src/main/java/net/minecraft/world/entity/ai/control/ControllerLookDolphin.java +@@ -3,7 +3,7 @@ package net.minecraft.world.entity.ai.control; + import net.minecraft.util.MathHelper; + import net.minecraft.world.entity.EntityInsentient; + +-public class ControllerLookDolphin extends ControllerLook { ++public class ControllerLookDolphin extends net.pl3x.purpur.controller.ControllerLookWASD { // Purpur + + private final int h; + +@@ -13,7 +13,7 @@ public class ControllerLookDolphin extends ControllerLook { + } + + @Override +- public void a() { ++ public void tick() { // Purpur + if (this.d) { + this.d = false; + this.a.aC = this.a(this.a.aC, this.h() + 20.0F, this.b); +diff --git a/src/main/java/net/minecraft/world/entity/ai/control/ControllerMove.java b/src/main/java/net/minecraft/world/entity/ai/control/ControllerMove.java +index 2aa5789437ba7eb20579da238c407a65a25b1d44..434229b146978ba7dc08a83ea55fdb3ab743fbf8 100644 +--- a/src/main/java/net/minecraft/world/entity/ai/control/ControllerMove.java ++++ b/src/main/java/net/minecraft/world/entity/ai/control/ControllerMove.java +@@ -20,9 +20,9 @@ public class ControllerMove { + protected double b; + protected double c; + protected double d; +- protected double e; +- protected float f; +- protected float g; ++ protected double e; public double getSpeed() { return e; } public void setSpeed(double speed) { this.e = speed; } // Purpur - OBFHELPER ++ protected float f; public float getForward() { return f; } public void setForward(float forward) { this.f = forward; } // Purpur - OBFHELPER ++ protected float g; public float getStrafe() { return g; } public void setStrafe(float strafe) { this.g = strafe; } // Purpur - OBFHELPER + protected ControllerMove.Operation h; + + public ControllerMove(EntityInsentient entityinsentient) { +diff --git a/src/main/java/net/minecraft/world/entity/ambient/EntityBat.java b/src/main/java/net/minecraft/world/entity/ambient/EntityBat.java +index 61ebb278cf4ef57ae7a86c6c6ef1fa14559f21e2..bee72578fae2fba56f8e8dcc1142ab54c7ba7cb8 100644 +--- a/src/main/java/net/minecraft/world/entity/ambient/EntityBat.java ++++ b/src/main/java/net/minecraft/world/entity/ambient/EntityBat.java +@@ -21,6 +21,7 @@ import net.minecraft.world.entity.EntityPose; + import net.minecraft.world.entity.EntitySize; + import net.minecraft.world.entity.EntityTypes; + import net.minecraft.world.entity.EnumMobSpawn; ++import net.minecraft.world.entity.EnumMoveType; + import net.minecraft.world.entity.ai.attributes.AttributeProvider; + import net.minecraft.world.entity.ai.attributes.GenericAttributes; + import net.minecraft.world.entity.ai.targeting.PathfinderTargetCondition; +@@ -40,9 +41,48 @@ public class EntityBat extends EntityAmbient { + + public EntityBat(EntityTypes entitytypes, World world) { + super(entitytypes, world); ++ this.moveController = new net.pl3x.purpur.controller.ControllerMoveWASDFlyingWithSpacebar(this, 0.075F); // Purpur + this.setAsleep(true); + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.batRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.batRidableInWater; ++ } ++ ++ @Override ++ public double getMaxY() { ++ return world.purpurConfig.batMaxY; ++ } ++ ++ @Override ++ public void onMount(EntityHuman entityhuman) { ++ super.onMount(entityhuman); ++ if (isAsleep()) { ++ setAsleep(false); ++ world.playEffect(null, 1025, new BlockPosition(this).up(), 0); ++ } ++ } ++ ++ @Override ++ public void g(Vec3D vec3d) { ++ super.g(vec3d); ++ if (hasPurpurRider() && !onGround) { ++ float speed = (float) getAttributeInstance(GenericAttributes.FLYING_SPEED).getValue() * 2; ++ setSpeed(speed); ++ Vec3D mot = getMot(); ++ move(EnumMoveType.SELF, mot.multiply(speed, 0.25, speed)); ++ setMot(mot.a(0.9D)); ++ } ++ } ++ // Purpur end ++ + @Override + protected void initDatawatcher() { + super.initDatawatcher(); +@@ -87,7 +127,7 @@ public class EntityBat extends EntityAmbient { + protected void collideNearby() {} + + public static AttributeProvider.Builder m() { +- return EntityInsentient.p().a(GenericAttributes.MAX_HEALTH, 6.0D); ++ return EntityInsentient.p().a(GenericAttributes.MAX_HEALTH, 6.0D).a(GenericAttributes.FLYING_SPEED, 0.6D); // Purpur + } + + public boolean isAsleep() { +@@ -119,6 +159,13 @@ public class EntityBat extends EntityAmbient { + + @Override + protected void mobTick() { ++ // Purpur start ++ if (hasPurpurRider()) { ++ Vec3D mot = getMot(); ++ setMot(mot.x, mot.y + (getVertical() > 0 ? 0.07D : 0.0D), mot.z); ++ return; ++ } ++ // Purpur end + super.mobTick(); + BlockPosition blockposition = this.getChunkCoordinates(); + BlockPosition blockposition1 = blockposition.up(); +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityBee.java b/src/main/java/net/minecraft/world/entity/animal/EntityBee.java +index 1d1f71a995a99b2101891a7a5bda7bec5d67f118..bcd510e0bf647a240edfaac1348119c5e1d7dc42 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityBee.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityBee.java +@@ -22,6 +22,7 @@ import net.minecraft.network.protocol.game.PacketDebug; + import net.minecraft.network.syncher.DataWatcher; + import net.minecraft.network.syncher.DataWatcherObject; + import net.minecraft.network.syncher.DataWatcherRegistry; ++import net.minecraft.server.PathfinderGoalHasRider; + import net.minecraft.server.level.WorldServer; + import net.minecraft.sounds.SoundEffect; + import net.minecraft.sounds.SoundEffects; +@@ -44,10 +45,10 @@ import net.minecraft.world.entity.EntityPose; + import net.minecraft.world.entity.EntitySize; + import net.minecraft.world.entity.EntityTypes; + import net.minecraft.world.entity.EnumMonsterType; ++import net.minecraft.world.entity.EnumMoveType; + import net.minecraft.world.entity.IEntityAngerable; + import net.minecraft.world.entity.ai.attributes.AttributeProvider; + import net.minecraft.world.entity.ai.attributes.GenericAttributes; +-import net.minecraft.world.entity.ai.control.ControllerLook; + import net.minecraft.world.entity.ai.control.ControllerMoveFlying; + import net.minecraft.world.entity.ai.goal.PathfinderGoal; + import net.minecraft.world.entity.ai.goal.PathfinderGoalBreed; +@@ -111,6 +112,7 @@ public class EntityBee extends EntityAnimal implements IEntityAngerable, EntityB + + public EntityBee(EntityTypes entitytypes, World world) { + super(entitytypes, world); ++ final net.pl3x.purpur.controller.ControllerMoveWASDFlying flyingController = new net.pl3x.purpur.controller.ControllerMoveWASDFlying(this, 0.25F, false); // Purpur + // Paper start - apply gravity to bees when they get stuck in the void, fixes MC-167279 + this.moveController = new ControllerMoveFlying(this, 20, true) { + @Override +@@ -120,6 +122,22 @@ public class EntityBee extends EntityAnimal implements IEntityAngerable, EntityB + } + super.tick(); + } ++ ++ // Purpur start ++ @Override ++ public void a() { // tick ++ if (getEntity().hasPurpurRider()) { ++ flyingController.tick(getEntity().getPurpurRider()); ++ } else { ++ tick(); ++ } ++ } ++ ++ @Override ++ public boolean b() { // isUpdating ++ return getEntity().hasPurpurRider() || super.b(); ++ } ++ // Purpur end + }; + // Paper end + this.lookController = new EntityBee.j(this); +@@ -130,6 +148,35 @@ public class EntityBee extends EntityAnimal implements IEntityAngerable, EntityB + this.a(PathType.FENCE, -1.0F); + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.beeRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.beeRidableInWater; ++ } ++ ++ @Override ++ public double getMaxY() { ++ return world.purpurConfig.beeMaxY; ++ } ++ ++ @Override ++ public void g(Vec3D vec3d) { ++ super.g(vec3d); ++ if (hasPurpurRider() && !onGround) { ++ float speed = (float) getAttributeInstance(GenericAttributes.FLYING_SPEED).getValue() * 2; ++ setSpeed(speed); ++ Vec3D mot = getMot(); ++ move(EnumMoveType.SELF, mot.multiply(speed, speed, speed)); ++ setMot(mot.a(0.9D)); ++ } ++ } ++ // Purpur end ++ + @Override + protected void initDatawatcher() { + super.initDatawatcher(); +@@ -144,6 +191,7 @@ public class EntityBee extends EntityAnimal implements IEntityAngerable, EntityB + + @Override + protected void initPathfinder() { ++ this.goalSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.goalSelector.a(0, new EntityBee.b(this, 1.399999976158142D, true)); + this.goalSelector.a(1, new EntityBee.d()); + this.goalSelector.a(2, new PathfinderGoalBreed(this, 1.0D)); +@@ -159,6 +207,7 @@ public class EntityBee extends EntityAnimal implements IEntityAngerable, EntityB + this.goalSelector.a(7, new EntityBee.g()); + this.goalSelector.a(8, new EntityBee.l()); + this.goalSelector.a(9, new PathfinderGoalFloat(this)); ++ this.targetSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.targetSelector.a(1, (new EntityBee.h(this)).a(new Class[0])); + this.targetSelector.a(2, new EntityBee.c(this)); + this.targetSelector.a(3, new PathfinderGoalUniversalAngerReset<>(this, true)); +@@ -629,6 +678,7 @@ public class EntityBee extends EntityAnimal implements IEntityAngerable, EntityB + + private d() { + super(); // CraftBukkit - decompile error ++ this.a(EnumSet.of(PathfinderGoal.Type.UNKNOWN_BEHAVIOR)); // Purpur - enter hive + } + + @Override +@@ -691,6 +741,7 @@ public class EntityBee extends EntityAnimal implements IEntityAngerable, EntityB + + private g() { + super(); // CraftBukkit - decompile error ++ this.a(EnumSet.of(PathfinderGoal.Type.UNKNOWN_BEHAVIOR)); // Purpur - grow crop + } + + @Override +@@ -755,6 +806,7 @@ public class EntityBee extends EntityAnimal implements IEntityAngerable, EntityB + + private i() { + super(); // CraftBukkit - decompile error ++ this.a(EnumSet.of(PathfinderGoal.Type.UNKNOWN_BEHAVIOR)); // Purpur - go to hive + } + + @Override +@@ -978,16 +1030,16 @@ public class EntityBee extends EntityAnimal implements IEntityAngerable, EntityB + } + } + +- class j extends ControllerLook { ++ class j extends net.pl3x.purpur.controller.ControllerLookWASD { // Purpur + + j(EntityInsentient entityinsentient) { + super(entityinsentient); + } + + @Override +- public void a() { ++ public void tick() { // Purpur + if (!EntityBee.this.isAngry()) { +- super.a(); ++ super.tick(); // Purpur + } + } + +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityCat.java b/src/main/java/net/minecraft/world/entity/animal/EntityCat.java +index c8f529b3fd227ce3354f442038b27cd716f57254..bac3035e2382df2d79e592b02395753eee08fa4b 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityCat.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityCat.java +@@ -14,6 +14,7 @@ import net.minecraft.network.syncher.DataWatcher; + import net.minecraft.network.syncher.DataWatcherObject; + import net.minecraft.network.syncher.DataWatcherRegistry; + import net.minecraft.resources.MinecraftKey; ++import net.minecraft.server.PathfinderGoalHasRider; + import net.minecraft.server.level.WorldServer; + import net.minecraft.sounds.SoundEffect; + import net.minecraft.sounds.SoundEffects; +@@ -104,6 +105,25 @@ public class EntityCat extends EntityTameableAnimal { + super(entitytypes, world); + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.catRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.catRidableInWater; ++ } ++ ++ public void onMount(EntityHuman entityhuman) { ++ super.onMount(entityhuman); ++ setSitting(false); ++ setSleepingWithOwner(false); ++ setHeadDown(false); ++ } ++ // Purpur end ++ + public MinecraftKey eU() { + return (MinecraftKey) EntityCat.bq.getOrDefault(this.getCatType(), EntityCat.bq.get(0)); + } +@@ -111,7 +131,8 @@ public class EntityCat extends EntityTameableAnimal { + @Override + protected void initPathfinder() { + this.bx = new EntityCat.PathfinderGoalTemptChance(this, 0.6D, EntityCat.br, true); +- this.goalSelector.a(1, new PathfinderGoalFloat(this)); ++ this.goalSelector.a(0, new PathfinderGoalFloat(this)); // Purpur ++ this.goalSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.goalSelector.a(1, new PathfinderGoalSit(this)); + this.goalSelector.a(2, new EntityCat.b(this)); + this.goalSelector.a(3, this.bx); +@@ -123,6 +144,7 @@ public class EntityCat extends EntityTameableAnimal { + this.goalSelector.a(10, new PathfinderGoalBreed(this, 0.8D)); + this.goalSelector.a(11, new PathfinderGoalRandomStrollLand(this, 0.8D, 1.0000001E-5F)); + this.goalSelector.a(12, new PathfinderGoalLookAtPlayer(this, EntityHuman.class, 10.0F)); ++ this.targetSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.targetSelector.a(1, new PathfinderGoalRandomTargetNonTamed<>(this, EntityRabbit.class, false, (Predicate) null)); + this.targetSelector.a(1, new PathfinderGoalRandomTargetNonTamed<>(this, EntityTurtle.class, false, EntityTurtle.bo)); + } +@@ -139,6 +161,7 @@ public class EntityCat extends EntityTameableAnimal { + this.datawatcher.set(EntityCat.bs, i); + } + ++ public void setSleepingWithOwner(boolean flag) { x(flag); } // Purpur - OBFHELPER + public void x(boolean flag) { + this.datawatcher.set(EntityCat.bt, flag); + } +@@ -147,6 +170,7 @@ public class EntityCat extends EntityTameableAnimal { + return (Boolean) this.datawatcher.get(EntityCat.bt); + } + ++ public void setHeadDown(boolean flag) { y(flag); } // Purpur - OBFHELPER + public void y(boolean flag) { + this.datawatcher.set(EntityCat.bu, flag); + } +@@ -365,6 +389,7 @@ public class EntityCat extends EntityTameableAnimal { + + @Override + public EnumInteractionResult b(EntityHuman entityhuman, EnumHand enumhand) { ++ if (hasPurpurRider()) return EnumInteractionResult.PASS; // Purpur + ItemStack itemstack = entityhuman.b(enumhand); + Item item = itemstack.getItem(); + +@@ -462,6 +487,7 @@ public class EntityCat extends EntityTameableAnimal { + + public b(EntityCat entitycat) { + this.a = entitycat; ++ this.a(java.util.EnumSet.of(PathfinderGoal.Type.UNKNOWN_BEHAVIOR)); // Purpur - lay on owner + } + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityChicken.java b/src/main/java/net/minecraft/world/entity/animal/EntityChicken.java +index 600d6ebdf554dbaa8ca46a22a12d8b4e3255d987..5c744f1eac19e144c39a2c146d312f0547d6e589 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityChicken.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityChicken.java +@@ -2,6 +2,7 @@ package net.minecraft.world.entity.animal; + + import net.minecraft.core.BlockPosition; + import net.minecraft.nbt.NBTTagCompound; ++import net.minecraft.server.PathfinderGoalHasRider; + import net.minecraft.server.level.WorldServer; + import net.minecraft.sounds.SoundEffect; + import net.minecraft.sounds.SoundEffects; +@@ -54,6 +55,16 @@ public class EntityChicken extends EntityAnimal { + } + + // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.chickenRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.chickenRidableInWater; ++ } ++ + @Override + protected void initAttributes() { + if (world.purpurConfig.chickenRetaliate) { +@@ -65,6 +76,7 @@ public class EntityChicken extends EntityAnimal { + @Override + protected void initPathfinder() { + this.goalSelector.a(0, new PathfinderGoalFloat(this)); ++ this.goalSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + //this.goalSelector.a(1, new PathfinderGoalPanic(this, 1.4D)); // Purpur - moved down + this.goalSelector.a(2, new PathfinderGoalBreed(this, 1.0D)); + this.goalSelector.a(3, new PathfinderGoalTempt(this, 1.0D, false, EntityChicken.bv)); +@@ -75,6 +87,7 @@ public class EntityChicken extends EntityAnimal { + // Purpur start + if (world.purpurConfig.chickenRetaliate) { + this.goalSelector.a(1, new PathfinderGoalMeleeAttack(this, 1.0D, false)); ++ this.targetSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.targetSelector.a(1, new PathfinderGoalHurtByTarget(this)); + } else { + this.goalSelector.a(1, new PathfinderGoalPanic(this, 1.4D)); +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityCod.java b/src/main/java/net/minecraft/world/entity/animal/EntityCod.java +index aac7992a30a0b69cb34097aeb0fe021f54a3cdac..897e0d5ca44a0c475634f08e7d4fcf129ee197ab 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityCod.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityCod.java +@@ -14,6 +14,18 @@ public class EntityCod extends EntityFishSchool { + super(entitytypes, world); + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.codRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return true; ++ } ++ // Purpur end ++ + @Override + protected ItemStack eK() { + return new ItemStack(Items.COD_BUCKET); +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityCow.java b/src/main/java/net/minecraft/world/entity/animal/EntityCow.java +index 962dde5fcc617bc39b7d06a1e295370b9d60696c..b2d3fc3151a952ac783101443772736a206a6a3b 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityCow.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityCow.java +@@ -2,6 +2,7 @@ package net.minecraft.world.entity.animal; + + import net.minecraft.core.BlockPosition; + import net.minecraft.core.particles.Particles; ++import net.minecraft.server.PathfinderGoalHasRider; + import net.minecraft.server.level.WorldServer; + import net.minecraft.sounds.SoundEffect; + import net.minecraft.sounds.SoundEffects; +@@ -43,9 +44,22 @@ public class EntityCow extends EntityAnimal { + super(entitytypes, world); + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.cowRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.cowRidableInWater; ++ } ++ // Purpur end ++ + @Override + protected void initPathfinder() { + this.goalSelector.a(0, new PathfinderGoalFloat(this)); ++ this.goalSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.goalSelector.a(1, new PathfinderGoalPanic(this, 2.0D)); + this.goalSelector.a(2, new PathfinderGoalBreed(this, 1.0D)); + if (world.purpurConfig.cowFeedMushrooms > 0) this.goalSelector.a(3, new PathfinderGoalTempt(this, 1.25D, RecipeItemStack.a(Items.WHEAT, Blocks.RED_MUSHROOM.getItem(), Blocks.BROWN_MUSHROOM.getItem()), false)); else // Purpur +@@ -87,6 +101,7 @@ public class EntityCow extends EntityAnimal { + + @Override + public EnumInteractionResult b(EntityHuman entityhuman, EnumHand enumhand) { ++ if (hasPurpurRider()) return EnumInteractionResult.PASS; // Purpur + ItemStack itemstack = entityhuman.b(enumhand); + + if (itemstack.getItem() == Items.BUCKET && !this.isBaby()) { +@@ -94,7 +109,7 @@ public class EntityCow extends EntityAnimal { + org.bukkit.event.player.PlayerBucketFillEvent event = CraftEventFactory.callPlayerBucketFillEvent((WorldServer) entityhuman.world, entityhuman, this.getChunkCoordinates(), this.getChunkCoordinates(), null, itemstack, Items.MILK_BUCKET, enumhand); // Paper - add enumHand + + if (event.isCancelled()) { +- return EnumInteractionResult.PASS; ++ return tryRide(entityhuman, enumhand); // Purpur + } + // CraftBukkit end + +@@ -105,7 +120,7 @@ public class EntityCow extends EntityAnimal { + return EnumInteractionResult.a(this.world.isClientSide); + // Purpur start - feed mushroom to change to mooshroom + } else if (world.purpurConfig.cowFeedMushrooms > 0 && getEntityType() != EntityTypes.MOOSHROOM && isMushroom(itemstack)) { +- return feedMushroom(entityhuman, itemstack); ++ return feedMushroom(entityhuman, enumhand, itemstack); + // Purpur end + } else { + return super.b(entityhuman, enumhand); +@@ -128,7 +143,7 @@ public class EntityCow extends EntityAnimal { + } + } + +- private EnumInteractionResult feedMushroom(EntityHuman entityhuman, ItemStack itemstack) { ++ private EnumInteractionResult feedMushroom(EntityHuman entityhuman, EnumHand enumhand, ItemStack itemstack) { + world.broadcastEntityEffect(this, (byte) 18); // hearts + playSound(SoundEffects.ENTITY_COW_MILK, 1.0F, 1.0F); + if (incrementFeedCount(itemstack) < world.purpurConfig.cowFeedMushrooms) { +@@ -139,7 +154,7 @@ public class EntityCow extends EntityAnimal { + } + EntityMushroomCow mooshroom = EntityTypes.MOOSHROOM.create(world); + if (mooshroom == null) { +- return EnumInteractionResult.PASS; ++ return tryRide(entityhuman, enumhand); + } + if (itemstack.getItem() == Blocks.BROWN_MUSHROOM.getItem()) { + mooshroom.setVariant(EntityMushroomCow.Type.BROWN); +@@ -158,10 +173,10 @@ public class EntityCow extends EntityAnimal { + mooshroom.setCustomName(this.getCustomName()); + } + if (CraftEventFactory.callEntityTransformEvent(this, mooshroom, org.bukkit.event.entity.EntityTransformEvent.TransformReason.INFECTION).isCancelled()) { +- return EnumInteractionResult.PASS; ++ return tryRide(entityhuman, enumhand); + } + if (!new com.destroystokyo.paper.event.entity.EntityTransformedEvent(this.getBukkitEntity(), mooshroom.getBukkitEntity(), com.destroystokyo.paper.event.entity.EntityTransformedEvent.TransformedReason.INFECTED).callEvent()) { +- return EnumInteractionResult.PASS; ++ return tryRide(entityhuman, enumhand); + } + this.world.addEntity(mooshroom); + this.die(); +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityDolphin.java b/src/main/java/net/minecraft/world/entity/animal/EntityDolphin.java +index e0a9b931c26dbd4e7739d09ae45e1cee72ab210c..e4442716b329f3101bfd39fc7ce13d5419b427bf 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityDolphin.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityDolphin.java +@@ -16,6 +16,7 @@ import net.minecraft.network.syncher.DataWatcher; + import net.minecraft.network.syncher.DataWatcherObject; + import net.minecraft.network.syncher.DataWatcherRegistry; + import net.minecraft.resources.ResourceKey; ++import net.minecraft.server.PathfinderGoalHasRider; + import net.minecraft.server.level.WorldServer; + import net.minecraft.sounds.SoundEffect; + import net.minecraft.sounds.SoundEffects; +@@ -81,6 +82,7 @@ public class EntityDolphin extends EntityWaterAnimal { + public static final Predicate b = (entityitem) -> { + return !entityitem.p() && entityitem.isAlive() && entityitem.isInWater(); + }; ++ private int spitCooldown; // Purpur + + public EntityDolphin(EntityTypes entitytypes, World world) { + super(entitytypes, world); +@@ -89,6 +91,45 @@ public class EntityDolphin extends EntityWaterAnimal { + this.setCanPickupLoot(true); + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.dolphinRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return true; ++ } ++ ++ @Override ++ public boolean onSpacebar() { ++ if (spitCooldown == 0 && hasPurpurRider()) { ++ spitCooldown = world.purpurConfig.dolphinSpitCooldown; ++ if (!hasPurpurRider()) { ++ return false; ++ } ++ ++ org.bukkit.craftbukkit.entity.CraftPlayer player = (org.bukkit.craftbukkit.entity.CraftPlayer) getPurpurRider().getBukkitEntity(); ++ if (!player.hasPermission("allow.special.dolphin")) { ++ return false; ++ } ++ ++ org.bukkit.Location loc = player.getEyeLocation(); ++ loc.setPitch(loc.getPitch() - 10); ++ org.bukkit.util.Vector target = loc.getDirection().normalize().multiply(10).add(loc.toVector()); ++ ++ net.pl3x.purpur.entity.DolphinSpit spit = new net.pl3x.purpur.entity.DolphinSpit(world, this); ++ spit.shoot(target.getX() - locX(), target.getY() - locY(), target.getZ() - locZ(), world.purpurConfig.dolphinSpitSpeed, 5.0F); ++ ++ world.addEntity(spit); ++ playSound(SoundEffects.ENTITY_DOLPHIN_ATTACK, 1.0F, 1.0F + (random.nextFloat() - random.nextFloat()) * 0.2F); ++ return true; ++ } ++ return false; ++ } ++ // Purpur end ++ + @Nullable + @Override + public GroupDataEntity prepare(WorldAccess worldaccess, DifficultyDamageScaler difficultydamagescaler, EnumMobSpawn enummobspawn, @Nullable GroupDataEntity groupdataentity, @Nullable NBTTagCompound nbttagcompound) { +@@ -163,6 +204,7 @@ public class EntityDolphin extends EntityWaterAnimal { + protected void initPathfinder() { + this.goalSelector.a(0, new PathfinderGoalBreath(this)); + this.goalSelector.a(0, new PathfinderGoalWater(this)); ++ this.goalSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.goalSelector.a(1, new EntityDolphin.b(this)); + this.goalSelector.a(2, new EntityDolphin.c(this, 4.0D)); + this.goalSelector.a(4, new PathfinderGoalRandomSwim(this, 1.0D, 10)); +@@ -173,6 +215,7 @@ public class EntityDolphin extends EntityWaterAnimal { + this.goalSelector.a(8, new EntityDolphin.d()); + this.goalSelector.a(8, new PathfinderGoalFollowBoat(this)); + this.goalSelector.a(9, new PathfinderGoalAvoidTarget<>(this, EntityGuardian.class, 8.0F, 1.0D, 1.0D)); ++ this.targetSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.targetSelector.a(1, (new PathfinderGoalHurtByTarget(this, new Class[]{EntityGuardian.class})).a(new Class[0])); // CraftBukkit - decompile error + } + +@@ -224,7 +267,7 @@ public class EntityDolphin extends EntityWaterAnimal { + + @Override + protected boolean n(Entity entity) { +- return true; ++ return getRideCooldown() <= 0; // Purpur - make dolphin honor ride cooldown like all other non-boss mobs + } + + @Override +@@ -259,6 +302,9 @@ public class EntityDolphin extends EntityWaterAnimal { + @Override + public void tick() { + super.tick(); ++ if (spitCooldown > 0) { ++ spitCooldown--; ++ } + if (this.isNoAI()) { + this.setAirTicks(this.bH()); + } else { +@@ -532,7 +578,7 @@ public class EntityDolphin extends EntityWaterAnimal { + + private int b; + +- private d() {} ++ private d() { this.a(java.util.EnumSet.of(PathfinderGoal.Type.MOVE)); } // Purpur - play with item + + @Override + public boolean a() { +@@ -600,7 +646,7 @@ public class EntityDolphin extends EntityWaterAnimal { + } + } + +- static class a extends ControllerMove { ++ static class a extends net.pl3x.purpur.controller.ControllerMoveWASDWater { // Purpur + + private final EntityDolphin i; + +@@ -610,7 +656,20 @@ public class EntityDolphin extends EntityWaterAnimal { + } + + @Override +- public void a() { ++ // Purpur start ++ public void tick(EntityHuman rider) { ++ if (this.i.getAirTicks() < 150) { ++ // if drowning override player WASD controls to find air ++ tick(); ++ } else { ++ super.tick(rider); ++ this.i.setMot(this.i.getMot().add(0.0D, 0.005D, 0.0D)); ++ } ++ } ++ ++ @Override ++ public void tick() { ++ // Purpur end + if (this.i.isInWater()) { + this.i.setMot(this.i.getMot().add(0.0D, 0.005D, 0.0D)); + } +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityFish.java b/src/main/java/net/minecraft/world/entity/animal/EntityFish.java +index cbd7c37cd1d6f5dddcbc515ecc2d9df46e109bfa..d9a5d5fb718f8c3d66844279622eae44fe826fff 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityFish.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityFish.java +@@ -1,13 +1,14 @@ + package net.minecraft.world.entity.animal; + + import java.util.Random; +-import java.util.function.Predicate; ++ + import net.minecraft.advancements.CriterionTriggers; + import net.minecraft.core.BlockPosition; + import net.minecraft.nbt.NBTTagCompound; + import net.minecraft.network.syncher.DataWatcher; + import net.minecraft.network.syncher.DataWatcherObject; + import net.minecraft.network.syncher.DataWatcherRegistry; ++import net.minecraft.server.PathfinderGoalHasRider; + import net.minecraft.server.level.EntityPlayer; + import net.minecraft.sounds.SoundEffect; + import net.minecraft.sounds.SoundEffects; +@@ -29,7 +30,6 @@ import net.minecraft.world.entity.ai.control.ControllerMove; + import net.minecraft.world.entity.ai.goal.PathfinderGoalAvoidTarget; + import net.minecraft.world.entity.ai.goal.PathfinderGoalPanic; + import net.minecraft.world.entity.ai.goal.PathfinderGoalRandomSwim; +-import net.minecraft.world.entity.ai.goal.PathfinderGoalSelector; + import net.minecraft.world.entity.ai.navigation.NavigationAbstract; + import net.minecraft.world.entity.ai.navigation.NavigationGuardian; + import net.minecraft.world.entity.player.EntityHuman; +@@ -116,13 +116,12 @@ public abstract class EntityFish extends EntityWaterAnimal { + @Override + protected void initPathfinder() { + super.initPathfinder(); +- this.goalSelector.a(0, new PathfinderGoalPanic(this, 1.25D)); +- PathfinderGoalSelector pathfindergoalselector = this.goalSelector; +- Predicate predicate = IEntitySelector.g; +- +- predicate.getClass(); +- pathfindergoalselector.a(2, new PathfinderGoalAvoidTarget<>(this, EntityHuman.class, 8.0F, 1.6D, 1.4D, predicate::test)); +- this.goalSelector.a(4, new EntityFish.b(this)); ++ // Purpur start ++ this.goalSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur ++ this.goalSelector.a(1, new PathfinderGoalPanic(this, 1.25D)); ++ this.goalSelector.a(3, new PathfinderGoalAvoidTarget<>(this, EntityHuman.class, 8.0F, 1.6D, 1.4D, IEntitySelector.g::test)); // Purpur - decompile error ++ this.goalSelector.a(5, new EntityFish.b(this)); ++ // Purpur end + } + + @Override +@@ -133,7 +132,7 @@ public abstract class EntityFish extends EntityWaterAnimal { + @Override + public void g(Vec3D vec3d) { + if (this.doAITick() && this.isInWater()) { +- this.a(0.01F, vec3d); ++ this.a(hasPurpurRider() ? getSpeed() : 0.01F, vec3d); // Purpur + this.move(EnumMoveType.SELF, this.getMot()); + this.setMot(this.getMot().a(0.9D)); + if (this.getGoalTarget() == null) { +@@ -220,9 +219,9 @@ public abstract class EntityFish extends EntityWaterAnimal { + @Override + protected void b(BlockPosition blockposition, IBlockData iblockdata) {} + +- static class a extends ControllerMove { ++ static class a extends net.pl3x.purpur.controller.ControllerMoveWASDWater { // Purpur + +- private final EntityFish i; ++ private final EntityFish i; public EntityFish getFish() { return i; } // Purpur - OBFHELPER + + a(EntityFish entityfish) { + super(entityfish); +@@ -230,7 +229,15 @@ public abstract class EntityFish extends EntityWaterAnimal { + } + + @Override +- public void a() { ++ // Purpur start ++ public void tick(EntityHuman rider) { ++ super.tick(rider); ++ getFish().setMot(getFish().getMot().add(0.0D, 0.005D, 0.0D)); ++ } ++ ++ @Override ++ public void tick() { ++ // Purpur end + if (this.i.a((Tag) TagsFluid.WATER)) { + this.i.setMot(this.i.getMot().add(0.0D, 0.005D, 0.0D)); + } +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityFishSchool.java b/src/main/java/net/minecraft/world/entity/animal/EntityFishSchool.java +index 21780f5dbcd4384649f08161f0812202ee94c96d..a03b0ed0a3f74ccb7572e1c4fa8e345a9e9bc49f 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityFishSchool.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityFishSchool.java +@@ -25,7 +25,7 @@ public abstract class EntityFishSchool extends EntityFish { + @Override + protected void initPathfinder() { + super.initPathfinder(); +- this.goalSelector.a(5, new PathfinderGoalFishSchool(this)); ++ this.goalSelector.a(6, new PathfinderGoalFishSchool(this)); // Purpur + } + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityFox.java b/src/main/java/net/minecraft/world/entity/animal/EntityFox.java +index 19a9affdaba52d8e7dc1c4c20d5c0d52829f4989..7b1a6d846f25d8bc659a541fce59df79347ba9bc 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityFox.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityFox.java +@@ -21,6 +21,7 @@ import net.minecraft.network.syncher.DataWatcher; + import net.minecraft.network.syncher.DataWatcherObject; + import net.minecraft.network.syncher.DataWatcherRegistry; + import net.minecraft.resources.ResourceKey; ++import net.minecraft.server.PathfinderGoalHasRider; + import net.minecraft.server.level.EntityPlayer; + import net.minecraft.server.level.WorldServer; + import net.minecraft.sounds.SoundEffect; +@@ -48,8 +49,6 @@ import net.minecraft.world.entity.GroupDataEntity; + import net.minecraft.world.entity.IEntitySelector; + import net.minecraft.world.entity.ai.attributes.AttributeProvider; + import net.minecraft.world.entity.ai.attributes.GenericAttributes; +-import net.minecraft.world.entity.ai.control.ControllerLook; +-import net.minecraft.world.entity.ai.control.ControllerMove; + import net.minecraft.world.entity.ai.goal.PathfinderGoal; + import net.minecraft.world.entity.ai.goal.PathfinderGoalAvoidTarget; + import net.minecraft.world.entity.ai.goal.PathfinderGoalBreed; +@@ -127,6 +126,39 @@ public class EntityFox extends EntityAnimal { + this.setCanPickupLoot(true); + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.foxRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.foxRidableInWater; ++ } ++ ++ @Override ++ public float getJumpHeight() { ++ return !hasPurpurRider() ? super.getJumpHeight() : 0.5F; ++ } ++ ++ @Override ++ public void onMount(EntityHuman entityhuman) { ++ super.onMount(entityhuman); ++ setCanPickupLoot(false); ++ stopActions(); ++ setChasing(false); ++ spit(getEquipment(EnumItemSlot.MAINHAND)); ++ setSlot(EnumItemSlot.MAINHAND, ItemStack.NULL_ITEM); ++ } ++ ++ @Override ++ public void onDismount(EntityHuman entityhuman) { ++ super.onDismount(entityhuman); ++ setCanPickupLoot(true); ++ } ++ // Purpur end ++ + @Override + protected void initDatawatcher() { + super.initDatawatcher(); +@@ -146,6 +178,7 @@ public class EntityFox extends EntityAnimal { + return entityliving instanceof EntityFishSchool; + }); + this.goalSelector.a(0, new EntityFox.g()); ++ this.goalSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.goalSelector.a(1, new EntityFox.b()); + this.goalSelector.a(2, new EntityFox.n(2.2D)); + this.goalSelector.a(3, new EntityFox.e(1.0D)); +@@ -171,6 +204,7 @@ public class EntityFox extends EntityAnimal { + this.goalSelector.a(11, new EntityFox.p()); + this.goalSelector.a(12, new EntityFox.j(this, EntityHuman.class, 24.0F)); + this.goalSelector.a(13, new EntityFox.r()); ++ this.targetSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.targetSelector.a(3, new EntityFox.a(EntityLiving.class, false, false, (entityliving) -> { + return EntityFox.bt.test(entityliving) && !this.c(entityliving.getUniqueID()); + })); +@@ -458,6 +492,7 @@ public class EntityFox extends EntityAnimal { + return itemstack1.isEmpty() || this.bD > 0 && item.isFood() && !itemstack1.getItem().isFood(); + } + ++ public void spit(ItemStack itemstack) { m(itemstack); } // Purpur - OBFHELPER + private void m(ItemStack itemstack) { + if (!itemstack.isEmpty() && !this.world.isClientSide) { + EntityItem entityitem = new EntityItem(this.world, this.locX() + this.getLookDirection().x, this.locY() + 1.0D, this.locZ() + this.getLookDirection().z, itemstack); +@@ -553,6 +588,7 @@ public class EntityFox extends EntityAnimal { + return this.t(16); + } + ++ public void setChasing(boolean flag) { u(flag); } // Purpur - OBFHELPER + public void u(boolean flag) { + this.d(16, flag); + } +@@ -595,6 +631,7 @@ public class EntityFox extends EntityAnimal { + this.setSleeping(false); + } + ++ public void stopActions() { fd(); } // Purpur - OBFHELPER + private void fd() { + this.w(false); + this.setCrouching(false); +@@ -760,16 +797,16 @@ public class EntityFox extends EntityAnimal { + } + } + +- public class k extends ControllerLook { ++ public class k extends net.pl3x.purpur.controller.ControllerLookWASD { // Purpur + + public k() { + super(EntityFox.this); + } + + @Override +- public void a() { ++ public void tick() { // Purpur + if (!EntityFox.this.isSleeping()) { +- super.a(); ++ super.tick(); // Purpur + } + + } +@@ -1439,16 +1476,16 @@ public class EntityFox extends EntityAnimal { + } + } + +- class m extends ControllerMove { ++ class m extends net.pl3x.purpur.controller.ControllerMoveWASD { // Purpur + + public m() { + super(EntityFox.this); + } + + @Override +- public void a() { ++ public void tick() { // Purpur + if (EntityFox.this.fe()) { +- super.a(); ++ super.tick(); // Purpur + } + + } +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityIronGolem.java b/src/main/java/net/minecraft/world/entity/animal/EntityIronGolem.java +index 62cff5faafa076d05ebc59ad5c4fb020bea0509e..23e614f0c3cf1178acff8e72e0441c42c658e76b 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityIronGolem.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityIronGolem.java +@@ -14,6 +14,7 @@ import net.minecraft.nbt.NBTTagCompound; + import net.minecraft.network.syncher.DataWatcher; + import net.minecraft.network.syncher.DataWatcherObject; + import net.minecraft.network.syncher.DataWatcherRegistry; ++import net.minecraft.server.PathfinderGoalHasRider; + import net.minecraft.server.level.WorldServer; + import net.minecraft.sounds.SoundEffect; + import net.minecraft.sounds.SoundEffects; +@@ -69,9 +70,22 @@ public class EntityIronGolem extends EntityGolem implements IEntityAngerable { + this.G = 1.0F; + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.ironGolemRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.ironGolemRidableInWater; ++ } ++ // Purpur end ++ + @Override + protected void initPathfinder() { + if (world.purpurConfig.ironGolemCanSwim) this.goalSelector.a(0, new PathfinderGoalFloat(this)); // Purpur ++ this.goalSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.goalSelector.a(1, new PathfinderGoalMeleeAttack(this, 1.0D, true)); + this.goalSelector.a(2, new PathfinderGoalMoveTowardsTarget(this, 0.9D, 32.0F)); + this.goalSelector.a(2, new PathfinderGoalStrollVillage(this, 0.6D, false)); +@@ -79,6 +93,7 @@ public class EntityIronGolem extends EntityGolem implements IEntityAngerable { + this.goalSelector.a(5, new PathfinderGoalOfferFlower(this)); + this.goalSelector.a(7, new PathfinderGoalLookAtPlayer(this, EntityHuman.class, 6.0F)); + this.goalSelector.a(8, new PathfinderGoalRandomLookaround(this)); ++ this.targetSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.targetSelector.a(1, new PathfinderGoalDefendVillage(this)); + this.targetSelector.a(2, new PathfinderGoalHurtByTarget(this, new Class[0])); + this.targetSelector.a(3, new PathfinderGoalNearestAttackableTarget<>(this, EntityHuman.class, 10, true, false, this::a_)); +@@ -248,13 +263,13 @@ public class EntityIronGolem extends EntityGolem implements IEntityAngerable { + Item item = itemstack.getItem(); + + if (item != Items.IRON_INGOT) { +- return EnumInteractionResult.PASS; ++ return tryRide(entityhuman, enumhand); // Purpur + } else { + float f = this.getHealth(); + + this.heal(25.0F); + if (this.getHealth() == f) { +- return EnumInteractionResult.PASS; ++ return tryRide(entityhuman, enumhand); // Purpur + } else { + float f1 = 1.0F + (this.random.nextFloat() - this.random.nextFloat()) * 0.2F; + +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityMushroomCow.java b/src/main/java/net/minecraft/world/entity/animal/EntityMushroomCow.java +index d28d4d2c1eff2c130f49c2bce3c19da212dba5dc..815e907e8db721f2a6f0f831b69c44a9573b5c9b 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityMushroomCow.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityMushroomCow.java +@@ -57,6 +57,18 @@ public class EntityMushroomCow extends EntityCow implements IShearable { + super(entitytypes, world); + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.mooshroomRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.mooshroomRidableInWater; ++ } ++ // Purpur end ++ + @Override + public float a(BlockPosition blockposition, IWorldReader iworldreader) { + return iworldreader.getType(blockposition.down()).a(Blocks.MYCELIUM) ? 10.0F : iworldreader.y(blockposition) - 0.5F; +@@ -118,7 +130,7 @@ public class EntityMushroomCow extends EntityCow implements IShearable { + } else if (itemstack.getItem() == Items.SHEARS && this.canShear()) { + // CraftBukkit start + if (!CraftEventFactory.handlePlayerShearEntityEvent(entityhuman, this, itemstack, enumhand)) { +- return EnumInteractionResult.PASS; ++ return tryRide(entityhuman, enumhand); // Purpur + } + // CraftBukkit end + this.shear(SoundCategory.PLAYERS); +@@ -138,7 +150,7 @@ public class EntityMushroomCow extends EntityCow implements IShearable { + Optional> optional = this.l(itemstack); + + if (!optional.isPresent()) { +- return EnumInteractionResult.PASS; ++ return tryRide(entityhuman, enumhand); // Purpur + } + + Pair pair = (Pair) optional.get(); +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityOcelot.java b/src/main/java/net/minecraft/world/entity/animal/EntityOcelot.java +index f3e9c73f28584bcccd6f82d8974eabe4b4a892fa..d7938ff0dca305f1d47fdfdbc57648892debe367 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityOcelot.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityOcelot.java +@@ -10,6 +10,7 @@ import net.minecraft.nbt.NBTTagCompound; + import net.minecraft.network.syncher.DataWatcher; + import net.minecraft.network.syncher.DataWatcherObject; + import net.minecraft.network.syncher.DataWatcherRegistry; ++import net.minecraft.server.PathfinderGoalHasRider; + import net.minecraft.server.level.WorldServer; + import net.minecraft.sounds.SoundEffect; + import net.minecraft.sounds.SoundEffects; +@@ -63,6 +64,18 @@ public class EntityOcelot extends EntityAnimal { + this.eL(); + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.ocelotRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.ocelotRidableInWater; ++ } ++ // Purpur end ++ + private boolean isTrusting() { + return (Boolean) this.datawatcher.get(EntityOcelot.bp); + } +@@ -94,12 +107,14 @@ public class EntityOcelot extends EntityAnimal { + protected void initPathfinder() { + this.br = new EntityOcelot.b(this, 0.6D, EntityOcelot.bo, true); + this.goalSelector.a(1, new PathfinderGoalFloat(this)); ++ this.goalSelector.a(1, new PathfinderGoalHasRider(this)); // Purpur + this.goalSelector.a(3, this.br); + this.goalSelector.a(7, new PathfinderGoalLeapAtTarget(this, 0.3F)); + this.goalSelector.a(8, new PathfinderGoalOcelotAttack(this)); + this.goalSelector.a(9, new PathfinderGoalBreed(this, 0.8D)); + this.goalSelector.a(10, new PathfinderGoalRandomStrollLand(this, 0.8D, 1.0000001E-5F)); + this.goalSelector.a(11, new PathfinderGoalLookAtPlayer(this, EntityHuman.class, 10.0F)); ++ this.targetSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.targetSelector.a(1, new PathfinderGoalNearestAttackableTarget<>(this, EntityChicken.class, false)); + this.targetSelector.a(1, new PathfinderGoalNearestAttackableTarget<>(this, EntityTurtle.class, 10, false, false, EntityTurtle.bo)); + } +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityPanda.java b/src/main/java/net/minecraft/world/entity/animal/EntityPanda.java +index 711b322007a0973ff0aebf3c25efbae8fc7741d0..0d912399e1975d9c0d5525f5b89049f40e7efcc0 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityPanda.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityPanda.java +@@ -16,6 +16,7 @@ import net.minecraft.nbt.NBTTagCompound; + import net.minecraft.network.syncher.DataWatcher; + import net.minecraft.network.syncher.DataWatcherObject; + import net.minecraft.network.syncher.DataWatcherRegistry; ++import net.minecraft.server.PathfinderGoalHasRider; + import net.minecraft.server.level.WorldServer; + import net.minecraft.sounds.SoundEffect; + import net.minecraft.sounds.SoundEffects; +@@ -101,6 +102,27 @@ public class EntityPanda extends EntityAnimal { + + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.pandaRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.pandaRidableInWater; ++ } ++ ++ @Override ++ public void onMount(EntityHuman entityhuman) { ++ super.onMount(entityhuman); ++ this.setForwardSpeed(0.0F); ++ this.setScared(false); ++ this.setEating(false); ++ this.setLayingOnBack(false); ++ } ++ // Purpur end ++ + @Override + public boolean e(ItemStack itemstack) { + EnumItemSlot enumitemslot = EntityInsentient.j(itemstack); +@@ -124,6 +146,7 @@ public class EntityPanda extends EntityAnimal { + return this.w(8); + } + ++ public void setScared(boolean scared) { this.t(scared); } // Purpur - OBFHELPER + public void t(boolean flag) { + this.d(8, flag); + } +@@ -132,6 +155,7 @@ public class EntityPanda extends EntityAnimal { + return this.w(16); + } + ++ public void setLayingOnBack(boolean layingOnBack) { this.u(layingOnBack); } // Purpur - OBFHELPER + public void u(boolean flag) { + this.d(16, flag); + } +@@ -148,6 +172,7 @@ public class EntityPanda extends EntityAnimal { + return (Integer) this.datawatcher.get(EntityPanda.br); + } + ++ public void setEating(boolean eating) { this.v(eating); } // Purpur - OBFHELPER + private void v(int i) { + this.datawatcher.set(EntityPanda.br, i); + } +@@ -256,6 +281,7 @@ public class EntityPanda extends EntityAnimal { + @Override + protected void initPathfinder() { + this.goalSelector.a(0, new PathfinderGoalFloat(this)); ++ this.goalSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.goalSelector.a(2, new EntityPanda.i(this, 2.0D)); + this.goalSelector.a(2, new EntityPanda.d(this, 1.0D)); + this.goalSelector.a(3, new EntityPanda.b(this, 1.2000000476837158D, true)); +@@ -271,6 +297,7 @@ public class EntityPanda extends EntityAnimal { + this.goalSelector.a(12, new EntityPanda.j(this)); + this.goalSelector.a(13, new PathfinderGoalFollowParent(this, 1.25D)); + this.goalSelector.a(14, new PathfinderGoalRandomStrollLand(this, 1.0D)); ++ this.targetSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.targetSelector.a(1, (new EntityPanda.e(this, new Class[0])).a(new Class[0])); + } + +@@ -591,7 +618,7 @@ public class EntityPanda extends EntityAnimal { + ItemStack itemstack = entityhuman.b(enumhand); + + if (this.ff()) { +- return EnumInteractionResult.PASS; ++ return tryRide(entityhuman, enumhand); // Purpur + } else if (this.eN()) { + this.u(false); + return EnumInteractionResult.a(this.world.isClientSide); +@@ -608,7 +635,7 @@ public class EntityPanda extends EntityAnimal { + this.g(entityhuman); + } else { + if (this.world.isClientSide || this.eM() || this.isInWater()) { +- return EnumInteractionResult.PASS; ++ return tryRide(entityhuman, enumhand); // Purpur + } + + this.ft(); +@@ -625,7 +652,7 @@ public class EntityPanda extends EntityAnimal { + + return EnumInteractionResult.SUCCESS; + } else { +- return EnumInteractionResult.PASS; ++ return tryRide(entityhuman, enumhand); // Purpur + } + } + +@@ -738,6 +765,7 @@ public class EntityPanda extends EntityAnimal { + + public f(EntityPanda entitypanda) { + this.a = entitypanda; ++ this.a(EnumSet.of(PathfinderGoal.Type.UNKNOWN_BEHAVIOR)); // Purpur - lay on back + } + + @Override +@@ -901,6 +929,7 @@ public class EntityPanda extends EntityAnimal { + + public l(EntityPanda entitypanda) { + this.a = entitypanda; ++ this.a(EnumSet.of(PathfinderGoal.Type.UNKNOWN_BEHAVIOR)); // Purpur - sneeze + } + + @Override +@@ -1030,7 +1059,7 @@ public class EntityPanda extends EntityAnimal { + } + } + +- static class h extends ControllerMove { ++ static class h extends net.pl3x.purpur.controller.ControllerMoveWASD { // Purpur + + private final EntityPanda i; + +@@ -1040,9 +1069,9 @@ public class EntityPanda extends EntityAnimal { + } + + @Override +- public void a() { ++ public void tick() { // Purpur + if (this.i.fh()) { +- super.a(); ++ super.tick(); // Purpur + } + } + } +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityParrot.java b/src/main/java/net/minecraft/world/entity/animal/EntityParrot.java +index 699dd0ac1f8d0d340ab1a560106336fc7cc95d5b..9f705b75a14ba456808485ce4ddef9550aac3fe9 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityParrot.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityParrot.java +@@ -16,6 +16,7 @@ import net.minecraft.nbt.NBTTagCompound; + import net.minecraft.network.syncher.DataWatcher; + import net.minecraft.network.syncher.DataWatcherObject; + import net.minecraft.network.syncher.DataWatcherRegistry; ++import net.minecraft.server.PathfinderGoalHasRider; + import net.minecraft.server.level.WorldServer; + import net.minecraft.sounds.SoundCategory; + import net.minecraft.sounds.SoundEffect; +@@ -38,6 +39,7 @@ import net.minecraft.world.entity.EntityPose; + import net.minecraft.world.entity.EntitySize; + import net.minecraft.world.entity.EntityTypes; + import net.minecraft.world.entity.EnumMobSpawn; ++import net.minecraft.world.entity.EnumMoveType; + import net.minecraft.world.entity.GroupDataEntity; + import net.minecraft.world.entity.ai.attributes.AttributeProvider; + import net.minecraft.world.entity.ai.attributes.GenericAttributes; +@@ -119,12 +121,58 @@ public class EntityParrot extends EntityPerchable implements EntityBird { + + public EntityParrot(EntityTypes entitytypes, World world) { + super(entitytypes, world); +- this.moveController = new ControllerMoveFlying(this, 10, false); ++ // Purpur start ++ final net.pl3x.purpur.controller.ControllerMoveWASDFlyingWithSpacebar flyingController = new net.pl3x.purpur.controller.ControllerMoveWASDFlyingWithSpacebar(this, 0.3F); ++ this.moveController = new ControllerMoveFlying(this, 10, false) { ++ @Override ++ public void a() { // tick ++ if (getEntity().hasPurpurRider()) { ++ flyingController.tick(getEntity().getPurpurRider()); ++ } else { ++ tick(); ++ } ++ } ++ ++ @Override ++ public boolean b() { // isUpdating ++ return getEntity().hasPurpurRider() ? getForward() != 0 || getStrafe() != 0 : super.b(); ++ } ++ }; ++ // Purpur end + this.a(PathType.DANGER_FIRE, -1.0F); + this.a(PathType.DAMAGE_FIRE, -1.0F); + this.a(PathType.COCOA, -1.0F); + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.parrotRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.parrotRidableInWater; ++ } ++ ++ @Override ++ public double getMaxY() { ++ return world.purpurConfig.parrotMaxY; ++ } ++ ++ @Override ++ public void g(Vec3D vec3d) { ++ super.g(vec3d); ++ if (hasPurpurRider() && !onGround) { ++ float speed = (float) getAttributeInstance(GenericAttributes.FLYING_SPEED).getValue() * 2; ++ setSpeed(speed); ++ Vec3D mot = getMot(); ++ move(EnumMoveType.SELF, mot.multiply(speed, 0.25, speed)); ++ setMot(mot.a(0.9D)); ++ } ++ } ++ // Purpur end ++ + @Nullable + @Override + public GroupDataEntity prepare(WorldAccess worldaccess, DifficultyDamageScaler difficultydamagescaler, EnumMobSpawn enummobspawn, @Nullable GroupDataEntity groupdataentity, @Nullable NBTTagCompound nbttagcompound) { +@@ -143,8 +191,10 @@ public class EntityParrot extends EntityPerchable implements EntityBird { + + @Override + protected void initPathfinder() { +- this.goalSelector.a(0, new PathfinderGoalPanic(this, 1.25D)); ++ // this.goalSelector.a(0, new PathfinderGoalPanic(this, 1.25D)); // Purpur - move down + this.goalSelector.a(0, new PathfinderGoalFloat(this)); ++ this.goalSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur ++ this.goalSelector.a(1, new PathfinderGoalPanic(this, 1.25D)); // Purpur + this.goalSelector.a(1, new PathfinderGoalLookAtPlayer(this, EntityHuman.class, 8.0F)); + this.goalSelector.a(2, new PathfinderGoalSit(this)); + this.goalSelector.a(2, new PathfinderGoalFollowOwner(this, 1.0D, 5.0F, 1.0F, true)); +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityPig.java b/src/main/java/net/minecraft/world/entity/animal/EntityPig.java +index 1a540e41e6161d011ca4ed30c68ae9df4567b8db..cef69f99d7bc9b6605b9654c50f43a1ebc1a8509 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityPig.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityPig.java +@@ -9,6 +9,7 @@ import net.minecraft.nbt.NBTTagCompound; + import net.minecraft.network.syncher.DataWatcher; + import net.minecraft.network.syncher.DataWatcherObject; + import net.minecraft.network.syncher.DataWatcherRegistry; ++import net.minecraft.server.PathfinderGoalHasRider; + import net.minecraft.server.level.WorldServer; + import net.minecraft.sounds.SoundCategory; + import net.minecraft.sounds.SoundEffect; +@@ -66,9 +67,22 @@ public class EntityPig extends EntityAnimal implements ISteerable, ISaddleable { + this.saddleStorage = new SaddleStorage(this.datawatcher, EntityPig.bp, EntityPig.bo); + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.pigRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.pigRidableInWater; ++ } ++ // Purpur end ++ + @Override + protected void initPathfinder() { + this.goalSelector.a(0, new PathfinderGoalFloat(this)); ++ this.goalSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.goalSelector.a(1, new PathfinderGoalPanic(this, 1.25D)); + this.goalSelector.a(3, new PathfinderGoalBreed(this, 1.0D)); + this.goalSelector.a(4, new PathfinderGoalTempt(this, 1.2D, RecipeItemStack.a(Items.CARROT_ON_A_STICK), false)); +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityPolarBear.java b/src/main/java/net/minecraft/world/entity/animal/EntityPolarBear.java +index f25f5ced218555af0d62844a78842cfc7599d608..b46315700b8857318b03b83097fcf829047f8ca4 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityPolarBear.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityPolarBear.java +@@ -14,6 +14,7 @@ import net.minecraft.network.syncher.DataWatcher; + import net.minecraft.network.syncher.DataWatcherObject; + import net.minecraft.network.syncher.DataWatcherRegistry; + import net.minecraft.resources.ResourceKey; ++import net.minecraft.server.PathfinderGoalHasRider; + import net.minecraft.server.level.WorldServer; + import net.minecraft.sounds.SoundEffect; + import net.minecraft.sounds.SoundEffects; +@@ -66,12 +67,34 @@ public class EntityPolarBear extends EntityAnimal implements IEntityAngerable { + private static final IntRange bs = TimeRange.a(20, 39); + private int bt; + private UUID bu; ++ private int standTimer = 0; // Purpur + + public EntityPolarBear(EntityTypes entitytypes, World world) { + super(entitytypes, world); + } + + // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.polarBearRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.polarBearRidableInWater; ++ } ++ ++ @Override ++ public boolean onSpacebar() { ++ if (!isStanding()) { ++ if (hasPurpurRider() && getPurpurRider().getForward() == 0 && getPurpurRider().getStrafe() == 0) { ++ setStanding(true); ++ playSound(SoundEffects.ENTITY_POLAR_BEAR_WARNING, 1.0F, 1.0F); ++ } ++ } ++ return false; ++ } ++ + @Override + public boolean mate(EntityAnimal entityanimal) { + if (entityanimal == this) { +@@ -109,6 +132,7 @@ public class EntityPolarBear extends EntityAnimal implements IEntityAngerable { + protected void initPathfinder() { + super.initPathfinder(); + this.goalSelector.a(0, new PathfinderGoalFloat(this)); ++ this.goalSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.goalSelector.a(1, new EntityPolarBear.c()); + this.goalSelector.a(1, new EntityPolarBear.d()); + // Purpur start +@@ -121,6 +145,7 @@ public class EntityPolarBear extends EntityAnimal implements IEntityAngerable { + this.goalSelector.a(5, new PathfinderGoalRandomStroll(this, 1.0D)); + this.goalSelector.a(6, new PathfinderGoalLookAtPlayer(this, EntityHuman.class, 6.0F)); + this.goalSelector.a(7, new PathfinderGoalRandomLookaround(this)); ++ this.targetSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.targetSelector.a(1, new EntityPolarBear.b()); + this.targetSelector.a(2, new EntityPolarBear.a()); + this.targetSelector.a(3, new PathfinderGoalNearestAttackableTarget<>(this, EntityHuman.class, 10, true, false, this::a_)); +@@ -233,6 +258,11 @@ public class EntityPolarBear extends EntityAnimal implements IEntityAngerable { + this.a((WorldServer) this.world, true); + } + ++ // Purpur start ++ if (isStanding() && --standTimer <= 0) { ++ setStanding(false); ++ } ++ // Purpur end + } + + @Override +@@ -266,6 +296,7 @@ public class EntityPolarBear extends EntityAnimal implements IEntityAngerable { + public void setStanding(boolean standing) { t(standing); } // Purpur - OBFHELPER + public void t(boolean flag) { + this.datawatcher.set(EntityPolarBear.bo, flag); ++ standTimer = flag ? 20 : -1; // Purpur + } + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityPufferFish.java b/src/main/java/net/minecraft/world/entity/animal/EntityPufferFish.java +index 4e4327b3cb84367534c6f5855cf8b89763b1419d..b94aa69e2c5f41161e8c21d68078a522d063e03d 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityPufferFish.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityPufferFish.java +@@ -39,6 +39,18 @@ public class EntityPufferFish extends EntityFish { + super(entitytypes, world); + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.pufferfishRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return true; ++ } ++ // Purpur end ++ + @Override + protected void initDatawatcher() { + super.initDatawatcher(); +@@ -82,7 +94,7 @@ public class EntityPufferFish extends EntityFish { + @Override + protected void initPathfinder() { + super.initPathfinder(); +- this.goalSelector.a(1, new EntityPufferFish.a(this)); ++ this.goalSelector.a(2, new EntityPufferFish.a(this)); // Purpur + } + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityRabbit.java b/src/main/java/net/minecraft/world/entity/animal/EntityRabbit.java +index 180fc927074dc683ad4d482a00dd4e04ff7923d0..4660f37bc89418e0c3767305d390a53f5c0d3c55 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityRabbit.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityRabbit.java +@@ -10,6 +10,7 @@ import net.minecraft.network.syncher.DataWatcher; + import net.minecraft.network.syncher.DataWatcherObject; + import net.minecraft.network.syncher.DataWatcherRegistry; + import net.minecraft.resources.MinecraftKey; ++import net.minecraft.server.PathfinderGoalHasRider; + import net.minecraft.server.level.WorldServer; + import net.minecraft.sounds.SoundCategory; + import net.minecraft.sounds.SoundEffect; +@@ -27,7 +28,6 @@ import net.minecraft.world.entity.GroupDataEntity; + import net.minecraft.world.entity.ai.attributes.AttributeProvider; + import net.minecraft.world.entity.ai.attributes.GenericAttributes; + import net.minecraft.world.entity.ai.control.ControllerJump; +-import net.minecraft.world.entity.ai.control.ControllerMove; + import net.minecraft.world.entity.ai.goal.PathfinderGoalAvoidTarget; + import net.minecraft.world.entity.ai.goal.PathfinderGoalBreed; + import net.minecraft.world.entity.ai.goal.PathfinderGoalFloat; +@@ -75,6 +75,18 @@ public class EntityRabbit extends EntityAnimal { + this.initializePathFinderGoals(); // CraftBukkit - moved code + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.rabbitRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.rabbitRidableInWater; ++ } ++ // Purpur end ++ + // CraftBukkit start - code from constructor + public void initializePathFinderGoals(){ + this.i(0.0D); +@@ -83,7 +95,8 @@ public class EntityRabbit extends EntityAnimal { + + @Override + public void initPathfinder() { +- this.goalSelector.a(1, new PathfinderGoalFloat(this)); ++ this.goalSelector.a(0, new PathfinderGoalFloat(this)); // Purpur ++ this.goalSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.goalSelector.a(1, new EntityRabbit.PathfinderGoalRabbitPanic(this, 2.2D)); + this.goalSelector.a(2, new PathfinderGoalBreed(this, 0.8D)); + this.goalSelector.a(3, new PathfinderGoalTempt(this, 1.0D, RecipeItemStack.a(Items.CARROT, Items.GOLDEN_CARROT, Blocks.DANDELION), false)); +@@ -96,7 +109,15 @@ public class EntityRabbit extends EntityAnimal { + } + + @Override +- protected float dJ() { ++ // Purpur start ++ public float getJumpHeight() { ++ if (hasPurpurRider()) { ++ if (getForward() < 0) { ++ setSpeed(getForward() * 2F); ++ } ++ return actualJump ? 0.5F : 0.3F; ++ } ++ // Purpur end + if (!this.positionChanged && (!this.moveController.b() || this.moveController.e() <= this.locY() + 0.5D)) { + PathEntity pathentity = this.navigation.k(); + +@@ -115,7 +136,7 @@ public class EntityRabbit extends EntityAnimal { + } + + @Override +- protected void jump() { ++ public void jump() { // Purpur - protected -> public + super.jump(); + double d0 = this.moveController.c(); + +@@ -147,6 +168,7 @@ public class EntityRabbit extends EntityAnimal { + + } + ++ public void startJumping() { eK(); } // Purpur - OBFHELPER + public void eK() { + this.setJumping(true); + this.br = 10; +@@ -161,6 +183,13 @@ public class EntityRabbit extends EntityAnimal { + + @Override + public void mobTick() { ++ // Purpur start ++ if (hasPurpurRider()) { ++ handleJumping(); ++ return; ++ } ++ // Purpur end ++ + if (this.bt > 0) { + --this.bt; + } +@@ -211,6 +240,39 @@ public class EntityRabbit extends EntityAnimal { + this.bs = this.onGround; + } + ++ // Purpur start ++ private boolean wasOnGround; ++ private boolean actualJump; ++ ++ private void handleJumping() { ++ if (onGround) { ++ ControllerJumpRabbit jumpController = (ControllerJumpRabbit) getJumpController(); ++ if (!wasOnGround) { ++ setJumping(false); ++ jumpController.setCanJump(false); ++ } ++ if (!jumpController.isJumping()) { ++ if (moveController.b()) { // isUpdating ++ startJumping(); ++ } ++ } else if (!jumpController.canJump()) { ++ jumpController.setCanJump(true); ++ } ++ } ++ wasOnGround = onGround; ++ } ++ ++ @Override ++ public boolean onSpacebar() { ++ if (onGround) { ++ actualJump = true; ++ jump(); ++ actualJump = false; ++ } ++ return true; ++ } ++ // Purpur end ++ + @Override + public boolean aO() { + return false; +@@ -540,7 +602,7 @@ public class EntityRabbit extends EntityAnimal { + } + } + +- static class ControllerMoveRabbit extends ControllerMove { ++ static class ControllerMoveRabbit extends net.pl3x.purpur.controller.ControllerMoveWASD { // Purpur + + private final EntityRabbit i; + private double j; +@@ -551,14 +613,14 @@ public class EntityRabbit extends EntityAnimal { + } + + @Override +- public void a() { ++ public void tick() { // Purpur + if (this.i.onGround && !this.i.jumping && !((EntityRabbit.ControllerJumpRabbit) this.i.bi).c()) { + this.i.i(0.0D); + } else if (this.b()) { + this.i.i(this.j); + } + +- super.a(); ++ super.tick(); // Purpur + } + + @Override +@@ -585,14 +647,17 @@ public class EntityRabbit extends EntityAnimal { + this.c = entityrabbit; + } + ++ public boolean isJumping() { return c(); } // Purpur - OBFHELPER + public boolean c() { + return this.a; + } + ++ public boolean canJump() { return d(); } // Purpur - OBFHELPER + public boolean d() { + return this.d; + } + ++ public void setCanJump(boolean canJump) { a(canJump); } // Purpur - OBFHELPER + public void a(boolean flag) { + this.d = flag; + } +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntitySalmon.java b/src/main/java/net/minecraft/world/entity/animal/EntitySalmon.java +index ca125342f189d5db95ebd04043a2d11e5fbfd3fd..bf565671c167162b3d935447961f0d44ed4a2779 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntitySalmon.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntitySalmon.java +@@ -14,6 +14,18 @@ public class EntitySalmon extends EntityFishSchool { + super(entitytypes, world); + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.salmonRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return true; ++ } ++ // Purpur end ++ + @Override + public int eN() { + return 5; +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntitySheep.java b/src/main/java/net/minecraft/world/entity/animal/EntitySheep.java +index 88bed962bc17242ee6a9c93b7e0fec8bc578b35f..8f3296031f220dd7bb3ae9fe2443e479954ebad3 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntitySheep.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntitySheep.java +@@ -14,6 +14,7 @@ import net.minecraft.network.syncher.DataWatcher; + import net.minecraft.network.syncher.DataWatcherObject; + import net.minecraft.network.syncher.DataWatcherRegistry; + import net.minecraft.resources.MinecraftKey; ++import net.minecraft.server.PathfinderGoalHasRider; + import net.minecraft.server.level.WorldServer; + import net.minecraft.sounds.SoundCategory; + import net.minecraft.sounds.SoundEffect; +@@ -110,10 +111,23 @@ public class EntitySheep extends EntityAnimal implements IShearable { + super(entitytypes, world); + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.sheepRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.sheepRidableInWater; ++ } ++ // Purpur end ++ + @Override + protected void initPathfinder() { + this.bs = new PathfinderGoalEatTile(this); + this.goalSelector.a(0, new PathfinderGoalFloat(this)); ++ this.goalSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.goalSelector.a(1, new PathfinderGoalPanic(this, 1.25D)); + this.goalSelector.a(2, new PathfinderGoalBreed(this, 1.0D)); + this.goalSelector.a(3, new PathfinderGoalTempt(this, 1.1D, RecipeItemStack.a(Items.WHEAT), false)); +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntitySnowman.java b/src/main/java/net/minecraft/world/entity/animal/EntitySnowman.java +index 44119f52a4f169ffcea53fb69393bfedfd1a62a7..a692b973717ecc56d808039418599a11aedc2c5a 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntitySnowman.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntitySnowman.java +@@ -6,6 +6,7 @@ import net.minecraft.nbt.NBTTagCompound; + import net.minecraft.network.syncher.DataWatcher; + import net.minecraft.network.syncher.DataWatcherObject; + import net.minecraft.network.syncher.DataWatcherRegistry; ++import net.minecraft.server.PathfinderGoalHasRider; + import net.minecraft.sounds.SoundCategory; + import net.minecraft.sounds.SoundEffect; + import net.minecraft.sounds.SoundEffects; +@@ -50,12 +51,26 @@ public class EntitySnowman extends EntityGolem implements IShearable, IRangedEnt + super(entitytypes, world); + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.snowGolemRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.snowGolemRidableInWater; ++ } ++ // Purpur end ++ + @Override + protected void initPathfinder() { ++ this.goalSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.goalSelector.a(1, new PathfinderGoalArrowAttack(this, 1.25D, 20, 10.0F)); + this.goalSelector.a(2, new PathfinderGoalRandomStrollLand(this, 1.0D, 1.0000001E-5F)); + this.goalSelector.a(3, new PathfinderGoalLookAtPlayer(this, EntityHuman.class, 6.0F)); + this.goalSelector.a(4, new PathfinderGoalRandomLookaround(this)); ++ this.targetSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.targetSelector.a(1, new PathfinderGoalNearestAttackableTarget<>(this, EntityInsentient.class, 10, true, false, (entityliving) -> { + return entityliving instanceof IMonster; + })); +@@ -107,6 +122,7 @@ public class EntitySnowman extends EntityGolem implements IShearable, IRangedEnt + return; + } + ++ if (hasPurpurRider() && !world.purpurConfig.snowGolemLeaveTrailWhenRidden) return; // Purpur - don't leave snow trail when being ridden + IBlockData iblockdata = Blocks.SNOW.getBlockData(); + + for (int l = 0; l < 4; ++l) { +@@ -149,7 +165,7 @@ public class EntitySnowman extends EntityGolem implements IShearable, IRangedEnt + if (itemstack.getItem() == Items.SHEARS && this.canShear()) { + // CraftBukkit start + if (!CraftEventFactory.handlePlayerShearEntityEvent(entityhuman, this, itemstack, enumhand)) { +- return EnumInteractionResult.PASS; ++ return tryRide(entityhuman, enumhand); // Purpur + } + // CraftBukkit end + this.shear(SoundCategory.PLAYERS); +@@ -169,7 +185,7 @@ public class EntitySnowman extends EntityGolem implements IShearable, IRangedEnt + return EnumInteractionResult.SUCCESS; + // Purpur end + } else { +- return EnumInteractionResult.PASS; ++ return tryRide(entityhuman, enumhand); // Purpur + } + } + +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntitySquid.java b/src/main/java/net/minecraft/world/entity/animal/EntitySquid.java +index e6757b22497c6e274c3999d58671653e931ebe2b..777c3bcf267d6cf31300588826d3af6b55cab350 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntitySquid.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntitySquid.java +@@ -4,6 +4,7 @@ package net.minecraft.world.entity.animal; + import java.util.Random; + import net.minecraft.core.BlockPosition; + import net.minecraft.core.particles.Particles; ++import net.minecraft.server.PathfinderGoalHasRider; + import net.minecraft.server.level.WorldServer; + import net.minecraft.sounds.SoundEffect; + import net.minecraft.sounds.SoundEffects; +@@ -23,6 +24,7 @@ import net.minecraft.world.entity.EnumMoveType; + import net.minecraft.world.entity.ai.attributes.AttributeProvider; + import net.minecraft.world.entity.ai.attributes.GenericAttributes; + import net.minecraft.world.entity.ai.goal.PathfinderGoal; ++import net.minecraft.world.entity.player.EntityHuman; + import net.minecraft.world.level.GeneratorAccess; + import net.minecraft.world.level.World; + import net.minecraft.world.level.block.state.IBlockData; +@@ -54,17 +56,38 @@ public class EntitySquid extends EntityWaterAnimal { + } + + // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.squidRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return true; ++ } ++ + @Override + public AxisAlignedBB getAxisForFluidCheck() { + // Stops squids from floating just over the water + return this.getBoundingBox().shrink(0.001D).offsetY(world.purpurConfig.squidOffsetWaterCheck); + } ++ ++ private void rotateVectorAroundY(org.bukkit.util.Vector vector, double degrees) { ++ double rad = Math.toRadians(degrees); ++ double cos = Math.cos(rad); ++ double sine = Math.sin(rad); ++ double x = vector.getX(); ++ double z = vector.getZ(); ++ vector.setX(cos * x - sine * z); ++ vector.setZ(sine * x + cos * z); ++ } + // Purpur end + + @Override + protected void initPathfinder() { + this.goalSelector.a(0, new EntitySquid.PathfinderGoalSquid(this)); +- this.goalSelector.a(1, new EntitySquid.a()); ++ this.goalSelector.a(1, new PathfinderGoalHasRider(this)); // Purpur ++ this.goalSelector.a(2, new EntitySquid.a()); // Purpur + } + + public static AttributeProvider.Builder m() { +@@ -209,6 +232,7 @@ public class EntitySquid extends EntityWaterAnimal { + return blockposition.getY() > generatoraccess.getMinecraftWorld().spigotConfig.squidSpawnRangeMin && blockposition.getY() < maxHeight; // Spigot // Paper + } + ++ public void setMovementVector(float x, float y, float z) { a(x, y, z); } // Purpur - OBFHELPER + public void a(float f, float f1, float f2) { + this.bw = f; + this.bx = f1; +@@ -280,7 +304,7 @@ public class EntitySquid extends EntityWaterAnimal { + + class PathfinderGoalSquid extends PathfinderGoal { + +- private final EntitySquid b; ++ private final EntitySquid b; public EntitySquid getSquid() { return b; } // Purpur - OBFHELPER + + public PathfinderGoalSquid(EntitySquid entitysquid) { + this.b = entitysquid; +@@ -293,6 +317,38 @@ public class EntitySquid extends EntityWaterAnimal { + + @Override + public void e() { ++ // Purpur start ++ EntitySquid squid = getSquid(); ++ EntityHuman rider = squid.getPurpurRider(); ++ if (rider != null) { ++ if (rider.jumping) { ++ squid.onSpacebar(); ++ } ++ float forward = rider.getForward(); ++ float strafe = rider.getStrafe(); ++ float speed = (float) squid.getAttributeInstance(GenericAttributes.MOVEMENT_SPEED).getValue() * 10F; ++ if (forward < 0.0F) { ++ speed *= -0.5; ++ } ++ org.bukkit.util.Vector dir = rider.getBukkitEntity().getEyeLocation().getDirection().normalize().multiply(speed / 20.0F); ++ if (strafe != 0.0F) { ++ if (forward == 0.0F) { ++ dir.setY(0); ++ rotateVectorAroundY(dir, strafe > 0.0F ? -90 : 90); ++ } else if (forward < 0.0F) { ++ rotateVectorAroundY(dir, strafe > 0.0F ? 45 : -45); ++ } else { ++ rotateVectorAroundY(dir, strafe > 0.0F ? -45 : 45); ++ } ++ } ++ if (forward != 0.0F || strafe != 0.0F) { ++ squid.setMovementVector((float) dir.getX(), (float) dir.getY(), (float) dir.getZ()); ++ } else { ++ squid.setMovementVector(0.0F, 0.0F, 0.0F); ++ } ++ return; ++ } ++ // Purpur end + int i = this.b.dd(); + + if (i > 100) { +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityTropicalFish.java b/src/main/java/net/minecraft/world/entity/animal/EntityTropicalFish.java +index 29f6835da58c73a99fe620d6de7d86fede6ac893..478e55475ccc1410a442f4e30a1cbc08f479dbda 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityTropicalFish.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityTropicalFish.java +@@ -37,6 +37,18 @@ public class EntityTropicalFish extends EntityFishSchool { + super(entitytypes, world); + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.tropicalFishRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return true; ++ } ++ // Purpur end ++ + @Override + protected void initDatawatcher() { + super.initDatawatcher(); +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityTurtle.java b/src/main/java/net/minecraft/world/entity/animal/EntityTurtle.java +index ecec8a3c4d4b5d491f79ad60d7ce5a118f30b3db..28d6e673f55fc8fae40dff4a96ac2c2b5eeab9d6 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityTurtle.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityTurtle.java +@@ -15,6 +15,7 @@ import net.minecraft.network.syncher.DataWatcher; + import net.minecraft.network.syncher.DataWatcherObject; + import net.minecraft.network.syncher.DataWatcherRegistry; + import net.minecraft.server.MCUtil; ++import net.minecraft.server.PathfinderGoalHasRider; + import net.minecraft.server.level.EntityPlayer; + import net.minecraft.server.level.WorldServer; + import net.minecraft.sounds.SoundCategory; +@@ -90,6 +91,18 @@ public class EntityTurtle extends EntityAnimal { + this.G = 1.0F; + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.turtleRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.turtleRidableInWater; ++ } ++ // Purpur end ++ + public void setHomePos(BlockPosition blockposition) { + this.datawatcher.set(EntityTurtle.bp, blockposition.immutableCopy()); // Paper - called with mutablepos... + } +@@ -198,12 +211,13 @@ public class EntityTurtle extends EntityAnimal { + + @Override + protected void initPathfinder() { +- this.goalSelector.a(0, new EntityTurtle.f(this, 1.2D)); +- this.goalSelector.a(1, new EntityTurtle.a(this, 1.0D)); +- this.goalSelector.a(1, new EntityTurtle.d(this, 1.0D)); +- this.goalSelector.a(2, new EntityTurtle.i(this, 1.1D, Blocks.SEAGRASS.getItem())); +- this.goalSelector.a(3, new EntityTurtle.c(this, 1.0D)); +- this.goalSelector.a(4, new EntityTurtle.b(this, 1.0D)); ++ this.goalSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur ++ this.goalSelector.a(1, new EntityTurtle.f(this, 1.2D)); // Purpur ++ this.goalSelector.a(2, new EntityTurtle.a(this, 1.0D)); // Purpur ++ this.goalSelector.a(2, new EntityTurtle.d(this, 1.0D)); // Purpur ++ this.goalSelector.a(3, new EntityTurtle.i(this, 1.1D, Blocks.SEAGRASS.getItem())); // Purpur ++ this.goalSelector.a(4, new EntityTurtle.c(this, 1.0D)); // Purpur ++ this.goalSelector.a(5, new EntityTurtle.b(this, 1.0D)); // Purpur + this.goalSelector.a(7, new EntityTurtle.j(this, 1.0D)); + this.goalSelector.a(8, new PathfinderGoalLookAtPlayer(this, EntityHuman.class, 8.0F)); + this.goalSelector.a(9, new EntityTurtle.h(this, 1.0D, 100)); +@@ -386,13 +400,15 @@ public class EntityTurtle extends EntityAnimal { + } + } + +- static class e extends ControllerMove { ++ static class e extends net.pl3x.purpur.controller.ControllerMoveWASD { // Purpur + +- private final EntityTurtle i; ++ private final EntityTurtle i; public EntityTurtle getTurtle() { return i; } // Purpur - OBFHELPER ++ private final net.pl3x.purpur.controller.ControllerMoveWASDWater waterController; // Purpur + + e(EntityTurtle entityturtle) { +- super(entityturtle); ++ super(entityturtle, 0.1D); // Purpur + this.i = entityturtle; ++ waterController = new net.pl3x.purpur.controller.ControllerMoveWASDWater(entityturtle, 0.25D); // Purpur + } + + private void g() { +@@ -412,7 +428,18 @@ public class EntityTurtle extends EntityAnimal { + } + + @Override +- public void a() { ++ // Purpur start ++ public void tick(EntityHuman rider) { ++ if (getTurtle().isInWater()) { ++ waterController.tick(rider); ++ } else { ++ super.tick(rider); ++ } ++ } ++ ++ @Override ++ public void tick() { ++ // Purpur end + this.g(); + if (this.h == ControllerMove.Operation.MOVE_TO && !this.i.getNavigation().m()) { + double d0 = this.b - this.i.locX(); +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityWolf.java b/src/main/java/net/minecraft/world/entity/animal/EntityWolf.java +index b44b1544f401c1a5127bed3239bfd60420d17329..3fbd8f9122d7a5ac23af4d872f877030644ef86a 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityWolf.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityWolf.java +@@ -9,6 +9,7 @@ import net.minecraft.nbt.NBTTagCompound; + import net.minecraft.network.syncher.DataWatcher; + import net.minecraft.network.syncher.DataWatcherObject; + import net.minecraft.network.syncher.DataWatcherRegistry; ++import net.minecraft.server.PathfinderGoalHasRider; + import net.minecraft.server.level.WorldServer; + import net.minecraft.sounds.SoundEffect; + import net.minecraft.sounds.SoundEffects; +@@ -91,9 +92,27 @@ public class EntityWolf extends EntityTameableAnimal implements IEntityAngerable + this.setTamed(false); + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.wolfRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.wolfRidableInWater; ++ } ++ ++ public void onMount(EntityHuman entityhuman) { ++ super.onMount(entityhuman); ++ setSitting(false); ++ } ++ // Purpur end ++ + @Override + protected void initPathfinder() { + this.goalSelector.a(1, new PathfinderGoalFloat(this)); ++ this.goalSelector.a(1, new PathfinderGoalHasRider(this)); // Purpur + this.goalSelector.a(2, new PathfinderGoalSit(this)); + this.goalSelector.a(3, new EntityWolf.a<>(this, EntityLlama.class, 24.0F, 1.5D, 1.5D)); + this.goalSelector.a(4, new PathfinderGoalLeapAtTarget(this, 0.4F)); +@@ -104,6 +123,7 @@ public class EntityWolf extends EntityTameableAnimal implements IEntityAngerable + this.goalSelector.a(9, new PathfinderGoalBeg(this, 8.0F)); + this.goalSelector.a(10, new PathfinderGoalLookAtPlayer(this, EntityHuman.class, 8.0F)); + this.goalSelector.a(10, new PathfinderGoalRandomLookaround(this)); ++ this.targetSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.targetSelector.a(1, new PathfinderGoalOwnerHurtByTarget(this)); + this.targetSelector.a(2, new PathfinderGoalOwnerHurtTarget(this)); + this.targetSelector.a(3, (new PathfinderGoalHurtByTarget(this, new Class[0])).a(new Class[0])); // CraftBukkit - decompile error +diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorse.java b/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorse.java +index 48f67652a0a6797e217ce1f6040b5dc0f7a74938..650f13b1133e4c61f71b36f3f91a9d2913996435 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorse.java ++++ b/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorse.java +@@ -41,6 +41,13 @@ public class EntityHorse extends EntityHorseAbstract { + super(entitytypes, world); + } + ++ // Purpur start ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.horseRidableInWater; ++ } ++ // Purpur end ++ + @Override + protected void eK() { + this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue((double) this.fp()); +diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseAbstract.java b/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseAbstract.java +index cb6e2053d1315b65812e7bff8a17988b5b8ab0e4..d4556fa190c754406d0c65baae941fb23af3f81f 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseAbstract.java ++++ b/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseAbstract.java +@@ -14,6 +14,7 @@ import net.minecraft.nbt.NBTTagCompound; + import net.minecraft.network.syncher.DataWatcher; + import net.minecraft.network.syncher.DataWatcherObject; + import net.minecraft.network.syncher.DataWatcherRegistry; ++import net.minecraft.server.PathfinderGoalHorseHasRider; + import net.minecraft.server.level.EntityPlayer; + import net.minecraft.server.level.WorldServer; + import net.minecraft.server.players.NameReferencingFileConverter; +@@ -43,6 +44,8 @@ import net.minecraft.world.entity.IJumpable; + import net.minecraft.world.entity.ISaddleable; + import net.minecraft.world.entity.ai.attributes.AttributeProvider; + import net.minecraft.world.entity.ai.attributes.GenericAttributes; ++import net.minecraft.world.entity.ai.control.ControllerLook; ++import net.minecraft.world.entity.ai.control.ControllerMove; + import net.minecraft.world.entity.ai.goal.PathfinderGoalBreed; + import net.minecraft.world.entity.ai.goal.PathfinderGoalFloat; + import net.minecraft.world.entity.ai.goal.PathfinderGoalFollowParent; +@@ -101,12 +104,27 @@ public abstract class EntityHorseAbstract extends EntityAnimal implements IInven + + protected EntityHorseAbstract(EntityTypes entitytypes, World world) { + super(entitytypes, world); ++ this.moveController = new ControllerMove(this); // Purpur - use vanilla controller ++ this.lookController = new ControllerLook(this); // Purpur - use vanilla controller + this.G = 1.0F; + this.loadChest(); + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return false; // vanilla handles ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return false; ++ } ++ // Purpur end ++ + @Override + protected void initPathfinder() { ++ this.goalSelector.a(0, new PathfinderGoalHorseHasRider(this)); // Purpur + this.goalSelector.a(1, new PathfinderGoalPanic(this, 1.2D)); + this.goalSelector.a(1, new PathfinderGoalTame(this, 1.2D)); + this.goalSelector.a(2, new PathfinderGoalBreed(this, 1.0D, EntityHorseAbstract.class)); +@@ -114,6 +132,7 @@ public abstract class EntityHorseAbstract extends EntityAnimal implements IInven + this.goalSelector.a(6, new PathfinderGoalRandomStrollLand(this, 0.7D)); + this.goalSelector.a(7, new PathfinderGoalLookAtPlayer(this, EntityHuman.class, 6.0F)); + this.goalSelector.a(8, new PathfinderGoalRandomLookaround(this)); ++ this.targetSelector.a(0, new PathfinderGoalHorseHasRider(this)); // Purpur + this.eV(); + } + +diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseDonkey.java b/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseDonkey.java +index d9c87411f5c636bee3f28b724abf665826788be4..50700bf85a296b87fe3155651f869e2bbdb0875d 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseDonkey.java ++++ b/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseDonkey.java +@@ -16,6 +16,13 @@ public class EntityHorseDonkey extends EntityHorseChestedAbstract { + super(entitytypes, world); + } + ++ // Purpur start ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.donkeyRidableInWater; ++ } ++ // Purpur end ++ + @Override + protected SoundEffect getSoundAmbient() { + super.getSoundAmbient(); +diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseMule.java b/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseMule.java +index 7a5c14c1e80bde623473a39acb01b78b79d593e4..b6385a23050296611dbc8864b92d2cdd8321a1d0 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseMule.java ++++ b/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseMule.java +@@ -15,6 +15,12 @@ public class EntityHorseMule extends EntityHorseChestedAbstract { + super(entitytypes, world); + } + ++ // Purpur start ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.muleRidableInWater; ++ } ++ // Purpur end + @Override + protected SoundEffect getSoundAmbient() { + super.getSoundAmbient(); +diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseSkeleton.java b/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseSkeleton.java +index da5365372e89b847d626e52c5541544467f14702..d21399fbb6ddc4f26a7509ce547f8c4ad6458089 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseSkeleton.java ++++ b/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseSkeleton.java +@@ -17,6 +17,7 @@ import net.minecraft.world.entity.EnumMonsterType; + import net.minecraft.world.entity.ai.attributes.AttributeProvider; + import net.minecraft.world.entity.ai.attributes.GenericAttributes; + import net.minecraft.world.entity.ai.goal.PathfinderGoal; ++import net.minecraft.world.entity.ai.goal.PathfinderGoalFloat; + import net.minecraft.world.entity.player.EntityHuman; + import net.minecraft.world.item.ItemStack; + import net.minecraft.world.item.Items; +@@ -32,6 +33,18 @@ public class EntityHorseSkeleton extends EntityHorseAbstract { + super(entitytypes, world); + } + ++ // Purpur start ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.skeletonHorseRidableInWater; ++ } ++ ++ @Override ++ public boolean isTamed() { ++ return true; ++ } ++ // Purpur end ++ + public static AttributeProvider.Builder eL() { + return fi().a(GenericAttributes.MAX_HEALTH, 15.0D).a(GenericAttributes.MOVEMENT_SPEED, 0.20000000298023224D); + } +@@ -42,7 +55,7 @@ public class EntityHorseSkeleton extends EntityHorseAbstract { + } + + @Override +- protected void eV() {} ++ protected void eV() { if (world.purpurConfig.skeletonHorseCanSwim) goalSelector.a(0, new PathfinderGoalFloat(this)); } // Purpur + + @Override + protected SoundEffect getSoundAmbient() { +@@ -137,7 +150,7 @@ public class EntityHorseSkeleton extends EntityHorseAbstract { + + @Override + public boolean bt() { +- return true; ++ return super.bt(); // Purpur + } + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseZombie.java b/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseZombie.java +index 2e448a40dbf2fa5b4df4493f14738210615bab38..d57e7c02268e5d8a00b0b5897fa03dcee10cd2e0 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseZombie.java ++++ b/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseZombie.java +@@ -13,6 +13,7 @@ import net.minecraft.world.entity.EntityTypes; + import net.minecraft.world.entity.EnumMonsterType; + import net.minecraft.world.entity.ai.attributes.AttributeProvider; + import net.minecraft.world.entity.ai.attributes.GenericAttributes; ++import net.minecraft.world.entity.ai.goal.PathfinderGoalFloat; + import net.minecraft.world.entity.player.EntityHuman; + import net.minecraft.world.item.ItemStack; + import net.minecraft.world.item.Items; +@@ -24,6 +25,18 @@ public class EntityHorseZombie extends EntityHorseAbstract { + super(entitytypes, world); + } + ++ // Purpur start ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.zombieHorseRidableInWater; ++ } ++ ++ @Override ++ public boolean isTamed() { ++ return true; ++ } ++ // Purpur end ++ + public static AttributeProvider.Builder eL() { + return fi().a(GenericAttributes.MAX_HEALTH, 15.0D).a(GenericAttributes.MOVEMENT_SPEED, 0.20000000298023224D); + } +@@ -95,5 +108,5 @@ public class EntityHorseZombie extends EntityHorseAbstract { + } + + @Override +- protected void eV() {} ++ protected void eV() { if (world.purpurConfig.zombieHorseCanSwim) goalSelector.a(0, new PathfinderGoalFloat(this)); } // Purpur + } +diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/EntityLlama.java b/src/main/java/net/minecraft/world/entity/animal/horse/EntityLlama.java +index 1c6435bf2cd870b795f87368057d8dfc1e1c938a..d25177f9500a084e0f18a20b1eb1c4ac170048ec 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/horse/EntityLlama.java ++++ b/src/main/java/net/minecraft/world/entity/animal/horse/EntityLlama.java +@@ -8,6 +8,7 @@ import net.minecraft.nbt.NBTTagCompound; + import net.minecraft.network.syncher.DataWatcher; + import net.minecraft.network.syncher.DataWatcherObject; + import net.minecraft.network.syncher.DataWatcherRegistry; ++import net.minecraft.server.PathfinderGoalHorseHasRider; + import net.minecraft.server.level.WorldServer; + import net.minecraft.sounds.SoundEffect; + import net.minecraft.sounds.SoundEffects; +@@ -68,7 +69,46 @@ public class EntityLlama extends EntityHorseChestedAbstract implements IRangedEn + + public EntityLlama(EntityTypes entitytypes, World world) { + super(entitytypes, world); ++ // Purpur start ++ this.moveController = new net.pl3x.purpur.controller.ControllerMoveWASD(this) { ++ @Override ++ public void a() { // tick ++ if (entity.hasPurpurRider() && hasSaddle()) { ++ tick(entity.getPurpurRider()); ++ } else { ++ tick(); ++ } ++ } ++ }; ++ this.lookController = new net.pl3x.purpur.controller.ControllerLookWASD(this) { ++ @Override ++ public void a() { // tick ++ if (entity.hasPurpurRider() && hasSaddle()) { ++ tick(entity.getPurpurRider()); ++ } else { ++ tick(); ++ } ++ } ++ }; ++ // Purpur end ++ } ++ ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.llamaRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.llamaRidableInWater; ++ } ++ ++ @Override ++ public boolean hasSaddle() { ++ return super.hasSaddle() || (isTamed() && getColor() != null); + } ++ // Purpur end + + public void setStrength(int i) { + this.datawatcher.set(EntityLlama.bx, Math.max(1, Math.min(5, i))); +@@ -116,6 +156,7 @@ public class EntityLlama extends EntityHorseChestedAbstract implements IRangedEn + @Override + protected void initPathfinder() { + this.goalSelector.a(0, new PathfinderGoalFloat(this)); ++ this.goalSelector.a(0, new PathfinderGoalHorseHasRider(this)); // Purpur + this.goalSelector.a(1, new PathfinderGoalTame(this, 1.2D)); + this.goalSelector.a(2, new PathfinderGoalLlamaFollow(this, 2.0999999046325684D)); + this.goalSelector.a(3, new PathfinderGoalArrowAttack(this, 1.25D, 40, 20.0F)); +@@ -125,6 +166,7 @@ public class EntityLlama extends EntityHorseChestedAbstract implements IRangedEn + this.goalSelector.a(6, new PathfinderGoalRandomStrollLand(this, 0.7D)); + this.goalSelector.a(7, new PathfinderGoalLookAtPlayer(this, EntityHuman.class, 6.0F)); + this.goalSelector.a(8, new PathfinderGoalRandomLookaround(this)); ++ this.targetSelector.a(0, new PathfinderGoalHorseHasRider(this)); // Purpur + this.targetSelector.a(1, new EntityLlama.c(this)); + this.targetSelector.a(2, new EntityLlama.a(this)); + } +@@ -362,7 +404,7 @@ public class EntityLlama extends EntityHorseChestedAbstract implements IRangedEn + } + + @Nullable +- public EnumColor fy() { ++ public EnumColor fy() { return getColor(); } public EnumColor getColor() { // Purpur - OBFHELPER + int i = (Integer) this.datawatcher.get(EntityLlama.by); + + return i == -1 ? null : EnumColor.fromColorIndex(i); +diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/EntityLlamaTrader.java b/src/main/java/net/minecraft/world/entity/animal/horse/EntityLlamaTrader.java +index f761e37f7329342f01f04df5602573a51c0aca4e..0fb651bcde1109b0eb30b60226d3512648dceb41 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/horse/EntityLlamaTrader.java ++++ b/src/main/java/net/minecraft/world/entity/animal/horse/EntityLlamaTrader.java +@@ -27,6 +27,23 @@ public class EntityLlamaTrader extends EntityLlama { + super(entitytypes, world); + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.llamaTraderRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.llamaTraderRidableInWater; ++ } ++ ++ @Override ++ public boolean hasSaddle() { ++ return super.hasSaddle() || isTamed(); ++ } ++ // Purpur end ++ + @Override + protected EntityLlama fz() { + return (EntityLlama) EntityTypes.TRADER_LLAMA.a(this.world); +diff --git a/src/main/java/net/minecraft/world/entity/boss/EntityComplexPart.java b/src/main/java/net/minecraft/world/entity/boss/EntityComplexPart.java +index f1065c2a37835d760fb57194f7edfd029f426b48..3f2065e2939be54639f44501f7aa8ee5500dfc84 100644 +--- a/src/main/java/net/minecraft/world/entity/boss/EntityComplexPart.java ++++ b/src/main/java/net/minecraft/world/entity/boss/EntityComplexPart.java +@@ -2,11 +2,14 @@ package net.minecraft.world.entity.boss; + + import net.minecraft.nbt.NBTTagCompound; + import net.minecraft.network.protocol.Packet; ++import net.minecraft.world.EnumHand; ++import net.minecraft.world.EnumInteractionResult; + import net.minecraft.world.damagesource.DamageSource; + import net.minecraft.world.entity.Entity; + import net.minecraft.world.entity.EntityPose; + import net.minecraft.world.entity.EntitySize; + import net.minecraft.world.entity.boss.enderdragon.EntityEnderDragon; ++import net.minecraft.world.entity.player.EntityHuman; + + public class EntityComplexPart extends Entity { + +@@ -55,4 +58,11 @@ public class EntityComplexPart extends Entity { + public EntitySize a(EntityPose entitypose) { + return this.d; + } ++ ++ // Purpur start ++ @Override ++ public EnumInteractionResult a(EntityHuman entityhuman, EnumHand enumhand) { ++ return owner.isAlive() ? owner.tryRide(entityhuman, enumhand) : EnumInteractionResult.PASS; ++ } ++ // Purpur end + } +diff --git a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EntityEnderDragon.java b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EntityEnderDragon.java +index 3fff101637708a1a12f9a457bd3512ae94a8f884..b2d1a0144353a1da61221b59a0acc028b0cf746e 100644 +--- a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EntityEnderDragon.java ++++ b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EntityEnderDragon.java +@@ -23,6 +23,7 @@ import net.minecraft.world.entity.Entity; + import net.minecraft.world.entity.EntityExperienceOrb; + import net.minecraft.world.entity.EntityInsentient; + import net.minecraft.world.entity.EntityLiving; ++import net.minecraft.world.entity.EntitySize; + import net.minecraft.world.entity.EntityTypes; + import net.minecraft.world.entity.EnumMoveType; + import net.minecraft.world.entity.IEntitySelector; +@@ -95,6 +96,7 @@ public class EntityEnderDragon extends EntityInsentient implements IMonster { + private final int[] bK = new int[24]; + private final Path bL = new Path(); + private Explosion explosionSource = new Explosion(null, this, null, null, Double.NaN, Double.NaN, Double.NaN, Float.NaN, true, Explosion.Effect.DESTROY); // CraftBukkit - reusable source for CraftTNTPrimed.getSource() ++ private boolean hadRider; // Purpur + + public EntityEnderDragon(EntityTypes entitytypes, World world) { + super(EntityTypes.ENDER_DRAGON, world); +@@ -109,8 +111,44 @@ public class EntityEnderDragon extends EntityInsentient implements IMonster { + } + + this.bG = new DragonControllerManager(this); ++ // Purpur start ++ this.moveController = new net.pl3x.purpur.controller.ControllerMoveWASDFlying(this) { ++ @Override ++ public void tick() { ++ // dragon doesn't use the controller. do nothing ++ } ++ }; ++ this.lookController = new net.pl3x.purpur.controller.ControllerLookWASD(this) { ++ @Override ++ public void tick() { ++ // dragon doesn't use the controller. do nothing ++ } ++ ++ @Override ++ public void tick(EntityHuman rider) { ++ setYawPitch(rider.yaw - 180F, rider.pitch * 0.5F); ++ } ++ }; ++ // Purpur end ++ } ++ ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.enderDragonRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.enderDragonRidableInWater; + } + ++ @Override ++ public double getMaxY() { ++ return world.purpurConfig.enderDragonMaxY; ++ } ++ // Purpur end ++ + public static AttributeProvider.Builder m() { + return EntityInsentient.p().a(GenericAttributes.MAX_HEALTH, 200.0D); + } +@@ -143,6 +181,37 @@ public class EntityEnderDragon extends EntityInsentient implements IMonster { + + @Override + public void movementTick() { ++ // Purpur start ++ boolean hasRider = getPurpurRider() != null; ++ if (hasRider) { ++ if (!hadRider) { ++ hadRider = true; ++ noclip = false; ++ this.size = EntitySize.b(4.0F, 2.0F); ++ } ++ ++ // dragon doesn't use controllers, so must tick manually ++ moveController.a(); ++ lookController.a(); ++ ++ moveRelative((float) getAttributeInstance(GenericAttributes.MOVEMENT_SPEED).getValue() * 0.1F, new Vec3D(-getStrafe(), getVertical(), -getForward())); ++ Vec3D mot = getMot(); ++ setMot(mot); ++ move(EnumMoveType.PLAYER, mot); ++ ++ mot = mot.multiply(0.9F, 0.9F, 0.9F); ++ setMot(mot); ++ ++ // control wing flap speed on client ++ getDragonControllerManager().setControllerPhase(mot.getX() * mot.getX() + mot.getZ() * mot.getZ() < 0.005F ? DragonControllerPhase.HOVER : DragonControllerPhase.HOLDING_PATTERN); ++ } else if (hadRider) { ++ hadRider = false; ++ noclip = true; ++ this.size = EntitySize.b(16.0F, 8.0F); ++ getDragonControllerManager().setControllerPhase(DragonControllerPhase.HOLDING_PATTERN); // HoldingPattern ++ } ++ // Purpur end ++ + float f; + float f1; + +@@ -164,6 +233,7 @@ public class EntityEnderDragon extends EntityInsentient implements IMonster { + + this.bp = this.bq; + if (this.dl()) { ++ if (hasRider) ejectPassengers(); // Purpur + f = (this.random.nextFloat() - 0.5F) * 8.0F; + f1 = (this.random.nextFloat() - 0.5F) * 4.0F; + float f2 = (this.random.nextFloat() - 0.5F) * 8.0F; +@@ -175,9 +245,9 @@ public class EntityEnderDragon extends EntityInsentient implements IMonster { + + f1 = 0.2F / (MathHelper.sqrt(c(vec3d)) * 10.0F + 1.0F); + f1 *= (float) Math.pow(2.0D, vec3d.y); +- if (this.bG.a().a()) { ++ if (!hasRider && this.bG.a().a()) { // Purpur + this.bq += 0.1F; +- } else if (this.br) { ++ } else if (!hasRider && this.br) { // Purpur + this.bq += f1 * 0.5F; + } else { + this.bq += f1; +@@ -221,7 +291,7 @@ public class EntityEnderDragon extends EntityInsentient implements IMonster { + } + + this.bG.a().b(); +- } else { ++ } else if (!hasRider) { // Purpur + IDragonController idragoncontroller = this.bG.a(); + + idragoncontroller.c(); +@@ -288,7 +358,7 @@ public class EntityEnderDragon extends EntityInsentient implements IMonster { + this.a(this.bz, (double) (f11 * 0.5F), 0.0D, (double) (-f12 * 0.5F)); + this.a(this.bD, (double) (f12 * 4.5F), 2.0D, (double) (f11 * 4.5F)); + this.a(this.bE, (double) (f12 * -4.5F), 2.0D, (double) (f11 * -4.5F)); +- if (!this.world.isClientSide && this.hurtTicks == 0) { ++ if (!hasRider && !this.world.isClientSide && this.hurtTicks == 0) { // Purpur + this.a(this.world.getEntities(this, this.bD.getBoundingBox().grow(4.0D, 2.0D, 4.0D).d(0.0D, -2.0D, 0.0D), IEntitySelector.e)); + this.a(this.world.getEntities(this, this.bE.getBoundingBox().grow(4.0D, 2.0D, 4.0D).d(0.0D, -2.0D, 0.0D), IEntitySelector.e)); + this.b(this.world.getEntities(this, this.bo.getBoundingBox().g(1.0D), IEntitySelector.e)); +@@ -331,7 +401,7 @@ public class EntityEnderDragon extends EntityInsentient implements IMonster { + } + + if (!this.world.isClientSide) { +- this.br = this.b(this.bo.getBoundingBox()) | this.b(this.by.getBoundingBox()) | this.b(this.bz.getBoundingBox()); ++ this.br = !hasRider && this.b(this.bo.getBoundingBox()) | this.b(this.by.getBoundingBox()) | this.b(this.bz.getBoundingBox()); // Purpur + if (this.bF != null) { + this.bF.b(this); + } +diff --git a/src/main/java/net/minecraft/world/entity/boss/wither/EntityWither.java b/src/main/java/net/minecraft/world/entity/boss/wither/EntityWither.java +index 3cfe3173f710fc54ec77a47a9cbb8f5ff6a6f0b6..9ffac9aa79dee1b6dd6eeb8483b5a81416c11d9b 100644 +--- a/src/main/java/net/minecraft/world/entity/boss/wither/EntityWither.java ++++ b/src/main/java/net/minecraft/world/entity/boss/wither/EntityWither.java +@@ -12,6 +12,7 @@ import net.minecraft.network.chat.IChatBaseComponent; + import net.minecraft.network.syncher.DataWatcher; + import net.minecraft.network.syncher.DataWatcherObject; + import net.minecraft.network.syncher.DataWatcherRegistry; ++import net.minecraft.server.PathfinderGoalHasRider; + import net.minecraft.server.level.BossBattleServer; + import net.minecraft.server.level.EntityPlayer; + import net.minecraft.sounds.SoundEffect; +@@ -20,6 +21,7 @@ import net.minecraft.tags.TagsBlock; + import net.minecraft.util.MathHelper; + import net.minecraft.world.BossBattle; + import net.minecraft.world.EnumDifficulty; ++import net.minecraft.world.EnumHand; + import net.minecraft.world.damagesource.DamageSource; + import net.minecraft.world.effect.MobEffect; + import net.minecraft.world.effect.MobEffects; +@@ -28,6 +30,7 @@ import net.minecraft.world.entity.EntityInsentient; + import net.minecraft.world.entity.EntityLiving; + import net.minecraft.world.entity.EntityTypes; + import net.minecraft.world.entity.EnumMonsterType; ++import net.minecraft.world.entity.EnumMoveType; + import net.minecraft.world.entity.ai.attributes.AttributeProvider; + import net.minecraft.world.entity.ai.attributes.GenericAttributes; + import net.minecraft.world.entity.ai.goal.PathfinderGoal; +@@ -48,14 +51,16 @@ import net.minecraft.world.item.Items; + import net.minecraft.world.level.Explosion; + import net.minecraft.world.level.GameRules; + import net.minecraft.world.level.IMaterial; ++import net.minecraft.world.level.RayTrace; + import net.minecraft.world.level.World; + import net.minecraft.world.level.block.state.IBlockData; ++import net.minecraft.world.phys.MovingObjectPosition; ++import net.minecraft.world.phys.MovingObjectPositionBlock; ++import net.minecraft.world.phys.MovingObjectPositionEntity; + import net.minecraft.world.phys.Vec3D; + + // CraftBukkit start + import net.minecraft.network.protocol.game.PacketPlayOutWorldEvent; +-import net.minecraft.server.MinecraftServer; +-import net.minecraft.server.level.WorldServer; + import net.minecraft.world.level.block.Blocks; + import org.bukkit.craftbukkit.event.CraftEventFactory; + import org.bukkit.event.entity.EntityRegainHealthEvent; +@@ -82,6 +87,7 @@ public class EntityWither extends EntityMonster implements IRangedEntity { + return entityliving.getMonsterType() != EnumMonsterType.UNDEAD && entityliving.ei(); + }; + private static final PathfinderTargetCondition bz = (new PathfinderTargetCondition()).a(20.0D).a(EntityWither.by); ++ private int shootCooldown = 0; // Purpur + // Paper start + private boolean canPortal = false; + +@@ -94,15 +100,122 @@ public class EntityWither extends EntityMonster implements IRangedEntity { + this.setHealth(this.getMaxHealth()); + this.getNavigation().d(true); + this.f = 50; ++ this.moveController = new net.pl3x.purpur.controller.ControllerMoveWASDFlyingWithSpacebar(this, 0.1F); // Purpur + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.witherRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.witherRidableInWater; ++ } ++ ++ @Override ++ public double getMaxY() { ++ return world.purpurConfig.witherMaxY; ++ } ++ ++ @Override ++ public void g(Vec3D vec3d) { ++ super.g(vec3d); ++ if (hasPurpurRider() && !onGround) { ++ float speed = (float) getAttributeInstance(GenericAttributes.FLYING_SPEED).getValue() * 5F; ++ setSpeed(speed); ++ Vec3D mot = getMot(); ++ move(EnumMoveType.SELF, mot.multiply(speed, 0.5, speed)); ++ setMot(mot.a(0.9D)); ++ } ++ } ++ ++ @Override ++ public void onMount(EntityHuman entityhuman) { ++ super.onMount(entityhuman); ++ this.datawatcher.set(bo.get(0), 0); ++ this.datawatcher.set(bo.get(1), 0); ++ this.datawatcher.set(bo.get(2), 0); ++ getNavigation().stopPathfinding(); ++ shootCooldown = 20; ++ } ++ ++ @Override ++ public boolean onClick(EnumHand hand) { ++ return shoot(getPurpurRider(), hand == EnumHand.MAIN_HAND ? new int[]{1} : new int[]{2}); ++ } ++ ++ public boolean shoot(EntityHuman rider, int[] heads) { ++ if (shootCooldown > 0) { ++ return false; ++ } ++ ++ shootCooldown = 20; ++ if (rider == null) { ++ return false; ++ } ++ ++ org.bukkit.craftbukkit.entity.CraftHumanEntity player = rider.getBukkitEntity(); ++ if (!player.hasPermission("allow.special.wither")) { ++ return false; ++ } ++ ++ MovingObjectPosition rayTrace = getRayTrace(120, RayTrace.FluidCollisionOption.NONE); ++ if (rayTrace == null) { ++ return false; ++ } ++ ++ Vec3D loc; ++ if (rayTrace.getType() == MovingObjectPosition.EnumMovingObjectType.BLOCK) { ++ BlockPosition pos = ((MovingObjectPositionBlock) rayTrace).getBlockPosition(); ++ loc = new Vec3D(pos.getX() + 0.5D, pos.getY() + 0.5D, pos.getZ() + 0.5D); ++ } else if (rayTrace.getType() == MovingObjectPosition.EnumMovingObjectType.ENTITY) { ++ Entity target = ((MovingObjectPositionEntity) rayTrace).getEntity(); ++ loc = new Vec3D(target.locX(), target.locY() + (target.getHeadHeight() / 2), target.locZ()); ++ } else { ++ org.bukkit.block.Block block = player.getTargetBlock(null, 120); ++ loc = new Vec3D(block.getX() + 0.5D, block.getY() + 0.5D, block.getZ() + 0.5D); ++ } ++ ++ for (int head : heads) { ++ shoot(head, loc.getX(), loc.getY(), loc.getZ(), rider); ++ } ++ ++ return true; // handled ++ } ++ ++ public void shoot(int head, double x, double y, double z, EntityHuman rider) { ++ world.playEvent(null, 1024, getChunkCoordinates(), 0); ++ double headX = getHeadX(head); ++ double headY = getHeadY(head); ++ double headZ = getHeadZ(head); ++ EntityWitherSkull skull = new EntityWitherSkull(world, this, x - headX, y - headY, z - headZ) { ++ @Override ++ public boolean canSaveToDisk() { ++ return false; ++ } ++ ++ @Override ++ public boolean hitPredicate(Entity target) { ++ // do not hit rider ++ return target != rider && super.hitPredicate(target); ++ } ++ }; ++ skull.setPositionRaw(headX, headY, headZ); ++ world.addEntity(skull); ++ } ++ // Purpur end ++ + @Override + protected void initPathfinder() { +- this.goalSelector.a(0, new EntityWither.a()); ++ this.goalSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur ++ this.goalSelector.a(1, new EntityWither.a()); // Purpur + this.goalSelector.a(2, new PathfinderGoalArrowAttack(this, 1.0D, 40, 20.0F)); + this.goalSelector.a(5, new PathfinderGoalRandomStrollLand(this, 1.0D)); + this.goalSelector.a(6, new PathfinderGoalLookAtPlayer(this, EntityHuman.class, 8.0F)); + this.goalSelector.a(7, new PathfinderGoalRandomLookaround(this)); ++ this.targetSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.targetSelector.a(1, new PathfinderGoalHurtByTarget(this, new Class[0])); + if(this.world.paperConfig.fixWitherTargetingBug) this.targetSelector.a(2, new PathfinderGoalNearestAttackableTarget<>(this, EntityHuman.class, 0, false, false, null)); // Paper - Fix MC-29274 + this.targetSelector.a(2, new PathfinderGoalNearestAttackableTarget<>(this, EntityInsentient.class, 0, false, false, EntityWither.by)); +@@ -245,6 +358,16 @@ public class EntityWither extends EntityMonster implements IRangedEntity { + + @Override + protected void mobTick() { ++ // Purpur start ++ if (hasPurpurRider()) { ++ Vec3D mot = getMot(); ++ setMot(mot.x, mot.y + (getVertical() > 0 ? 0.07D : 0.0D), mot.z); ++ } ++ if (shootCooldown > 0) { ++ shootCooldown--; ++ } ++ // Purpur end ++ + int i; + + if (this.getInvul() > 0) { +@@ -428,7 +551,7 @@ public class EntityWither extends EntityMonster implements IRangedEntity { + this.bossBattle.removePlayer(entityplayer); + } + +- private double u(int i) { ++ private double u(int i) { return getHeadX(i); } private double getHeadX(int i) { // Purpur - OBFHELPER + if (i <= 0) { + return this.locX(); + } else { +@@ -439,11 +562,11 @@ public class EntityWither extends EntityMonster implements IRangedEntity { + } + } + +- private double v(int i) { ++ private double v(int i) { return getHeadY(i); } private double getHeadY(int i) { // Purpur - OBFHELPER + return i <= 0 ? this.locY() + 3.0D : this.locY() + 2.2D; + } + +- private double w(int i) { ++ private double w(int i) { return getHeadZ(i); } private double getHeadZ(int i) { // Purpur - OBFHELPER + if (i <= 0) { + return this.locZ(); + } else { +@@ -567,7 +690,7 @@ public class EntityWither extends EntityMonster implements IRangedEntity { + } + + public static AttributeProvider.Builder eK() { +- return EntityMonster.eR().a(GenericAttributes.MAX_HEALTH, 300.0D).a(GenericAttributes.MOVEMENT_SPEED, 0.6000000238418579D).a(GenericAttributes.FOLLOW_RANGE, 40.0D).a(GenericAttributes.ARMOR, 4.0D); ++ return EntityMonster.eR().a(GenericAttributes.MAX_HEALTH, 300.0D).a(GenericAttributes.MOVEMENT_SPEED, 0.6000000238418579D).a(GenericAttributes.FOLLOW_RANGE, 40.0D).a(GenericAttributes.ARMOR, 4.0D).a(GenericAttributes.FLYING_SPEED, 0.6D); // Purpur + } + + public int getInvul() { +@@ -579,11 +702,11 @@ public class EntityWither extends EntityMonster implements IRangedEntity { + } + + public int getHeadTarget(int i) { +- return (Integer) this.datawatcher.get((DataWatcherObject) EntityWither.bo.get(i)); ++ return hasPurpurRider() ? 0 : this.datawatcher.get(EntityWither.bo.get(i)); // Purpur + } + + public void setHeadTarget(int i, int j) { +- this.datawatcher.set((DataWatcherObject) EntityWither.bo.get(i), j); ++ if (!hasPurpurRider()) this.datawatcher.set(EntityWither.bo.get(i), j); // Purpur + } + + public final boolean isPowered() { return this.S_(); } // Paper - OBFHELPER +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityBlaze.java b/src/main/java/net/minecraft/world/entity/monster/EntityBlaze.java +index 88a4dcf9feaa5f66da1394c139b795582c00a8ac..6553fd92c26d71ac0a60bd046c7f968f2dfe6667 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityBlaze.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityBlaze.java +@@ -5,6 +5,7 @@ import net.minecraft.core.particles.Particles; + import net.minecraft.network.syncher.DataWatcher; + import net.minecraft.network.syncher.DataWatcherObject; + import net.minecraft.network.syncher.DataWatcherRegistry; ++import net.minecraft.server.PathfinderGoalHasRider; + import net.minecraft.sounds.SoundEffect; + import net.minecraft.sounds.SoundEffects; + import net.minecraft.util.MathHelper; +@@ -12,6 +13,7 @@ import net.minecraft.world.damagesource.DamageSource; + import net.minecraft.world.entity.Entity; + import net.minecraft.world.entity.EntityLiving; + import net.minecraft.world.entity.EntityTypes; ++import net.minecraft.world.entity.EnumMoveType; + import net.minecraft.world.entity.ai.attributes.AttributeProvider; + import net.minecraft.world.entity.ai.attributes.GenericAttributes; + import net.minecraft.world.entity.ai.goal.PathfinderGoal; +@@ -35,6 +37,7 @@ public class EntityBlaze extends EntityMonster { + + public EntityBlaze(EntityTypes entitytypes, World world) { + super(entitytypes, world); ++ this.moveController = new net.pl3x.purpur.controller.ControllerMoveWASDFlyingWithSpacebar(this, 0.3F); // Purpur + this.a(PathType.WATER, -1.0F); + this.a(PathType.LAVA, 8.0F); + this.a(PathType.DANGER_FIRE, 0.0F); +@@ -42,19 +45,50 @@ public class EntityBlaze extends EntityMonster { + this.f = 10; + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.blazeRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.blazeRidableInWater; ++ } ++ ++ @Override ++ public double getMaxY() { ++ return world.purpurConfig.blazeMaxY; ++ } ++ ++ @Override ++ public void g(Vec3D vec3d) { ++ super.g(vec3d); ++ if (hasPurpurRider() && !onGround) { ++ float speed = (float) getAttributeInstance(GenericAttributes.FLYING_SPEED).getValue(); ++ setSpeed(speed); ++ Vec3D mot = getMot(); ++ move(EnumMoveType.SELF, mot.multiply(speed, 1.0, speed)); ++ setMot(mot.a(0.9D)); ++ } ++ } ++ // Purpur end ++ + @Override + protected void initPathfinder() { ++ this.goalSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.goalSelector.a(4, new EntityBlaze.PathfinderGoalBlazeFireball(this)); + this.goalSelector.a(5, new PathfinderGoalMoveTowardsRestriction(this, 1.0D)); + this.goalSelector.a(7, new PathfinderGoalRandomStrollLand(this, 1.0D, 0.0F)); + this.goalSelector.a(8, new PathfinderGoalLookAtPlayer(this, EntityHuman.class, 8.0F)); + this.goalSelector.a(8, new PathfinderGoalRandomLookaround(this)); +- this.targetSelector.a(1, (new PathfinderGoalHurtByTarget(this, new Class[0])).a()); ++ this.targetSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur ++ this.targetSelector.a(1, (new PathfinderGoalHurtByTarget(this, new Class[0])).a(new Class[0])); // Purpur - decompile error + this.targetSelector.a(2, new PathfinderGoalNearestAttackableTarget<>(this, EntityHuman.class, true)); + } + + public static AttributeProvider.Builder m() { +- return EntityMonster.eR().a(GenericAttributes.ATTACK_DAMAGE, 6.0D).a(GenericAttributes.MOVEMENT_SPEED, 0.23000000417232513D).a(GenericAttributes.FOLLOW_RANGE, 48.0D); ++ return EntityMonster.eR().a(GenericAttributes.ATTACK_DAMAGE, 6.0D).a(GenericAttributes.MOVEMENT_SPEED, 0.23000000417232513D).a(GenericAttributes.FOLLOW_RANGE, 48.0D).a(GenericAttributes.FLYING_SPEED, 0.6D); // Purpur + } + + @Override +@@ -109,6 +143,14 @@ public class EntityBlaze extends EntityMonster { + + @Override + protected void mobTick() { ++ // Purpur start ++ if (hasPurpurRider()) { ++ Vec3D mot = getMot(); ++ setMot(mot.x, getVertical() > 0 ? 0.07D : -0.07D, mot.z); ++ return; ++ } ++ // Purpur end ++ + --this.c; + if (this.c <= 0) { + this.c = 100; +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityCaveSpider.java b/src/main/java/net/minecraft/world/entity/monster/EntityCaveSpider.java +index 65d0027186f19f10292ea64976ebb93c12b98394..27baf5cde99d8f25b1e7583c30339fcc71a3786f 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityCaveSpider.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityCaveSpider.java +@@ -24,6 +24,18 @@ public class EntityCaveSpider extends EntitySpider { + super(entitytypes, world); + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.caveSpiderRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.caveSpiderRidableInWater; ++ } ++ // Purpur end ++ + public static AttributeProvider.Builder m() { + return EntitySpider.eK().a(GenericAttributes.MAX_HEALTH, 12.0D); + } +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityCreeper.java b/src/main/java/net/minecraft/world/entity/monster/EntityCreeper.java +index 09df2bd3b523072de0e9858e6e707e3721474422..1daacdd75c709cd5508434b41589bd57032de27c 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityCreeper.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityCreeper.java +@@ -6,6 +6,7 @@ import net.minecraft.nbt.NBTTagCompound; + import net.minecraft.network.syncher.DataWatcher; + import net.minecraft.network.syncher.DataWatcherObject; + import net.minecraft.network.syncher.DataWatcherRegistry; ++import net.minecraft.server.PathfinderGoalHasRider; + import net.minecraft.server.level.WorldServer; + import net.minecraft.sounds.SoundEffect; + import net.minecraft.sounds.SoundEffects; +@@ -58,12 +59,27 @@ public class EntityCreeper extends EntityMonster { + public int maxFuseTicks = 30; + public int explosionRadius = 3; + private int bs; ++ // Purpur start ++ private int spacebarCharge = 0; ++ private int prevSpacebarCharge = 0; ++ private int powerToggleDelay = 0; ++ // Purpur end + + public EntityCreeper(EntityTypes entitytypes, World world) { + super(entitytypes, world); + } + + // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.creeperRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.creeperRidableInWater; ++ } ++ + @Override + public GroupDataEntity prepare(WorldAccess worldaccess, DifficultyDamageScaler difficultydamagescaler, EnumMobSpawn enummobspawn, @javax.annotation.Nullable GroupDataEntity groupdataentity, @javax.annotation.Nullable NBTTagCompound nbttagcompound) { + double chance = worldaccess.getMinecraftWorld().purpurConfig.creeperChargedChance; +@@ -72,18 +88,69 @@ public class EntityCreeper extends EntityMonster { + } + return super.prepare(worldaccess, difficultydamagescaler, enummobspawn, groupdataentity, nbttagcompound); + } ++ ++ @Override ++ protected void mobTick() { ++ if (powerToggleDelay > 0) { ++ powerToggleDelay--; ++ } ++ if (hasPurpurRider()) { ++ if (getPurpurRider().getForward() != 0 || getPurpurRider().getStrafe() != 0) { ++ spacebarCharge = 0; ++ setIgnited(false); ++ } ++ if (spacebarCharge == prevSpacebarCharge) { ++ spacebarCharge = 0; ++ } ++ prevSpacebarCharge = spacebarCharge; ++ } ++ super.mobTick(); ++ } ++ ++ @Override ++ public void onMount(EntityHuman entityhuman) { ++ super.onMount(entityhuman); ++ setIgnited(false); ++ } ++ ++ @Override ++ public boolean onSpacebar() { ++ if (powerToggleDelay > 0) { ++ return true; // just toggled power, do not jump or ignite ++ } ++ spacebarCharge++; ++ if (spacebarCharge > maxFuseTicks - 2) { ++ spacebarCharge = 0; ++ if (getPurpurRider().getBukkitEntity().hasPermission("allow.powered.creeper")) { ++ powerToggleDelay = 20; ++ setPowered(!isPowered()); ++ setIgnited(false); ++ return true; ++ } ++ } ++ if (!isIgnited()) { ++ if (hasPurpurRider() && getPurpurRider().getForward() == 0 && getPurpurRider().getStrafe() == 0 && ++ getPurpurRider().getBukkitEntity().hasPermission("allow.special.creeper")) { ++ setIgnited(true); ++ return true; ++ } ++ } ++ return getForward() == 0 && getStrafe() == 0; // do not jump if standing still ++ } + // Purpur end + + @Override + protected void initPathfinder() { + this.goalSelector.a(1, new PathfinderGoalFloat(this)); + this.goalSelector.a(2, new PathfinderGoalSwell(this)); ++ this.goalSelector.a(3, new PathfinderGoalHasRider(this)); // Purpur + this.goalSelector.a(3, new PathfinderGoalAvoidTarget<>(this, EntityOcelot.class, 6.0F, 1.0D, 1.2D)); + this.goalSelector.a(3, new PathfinderGoalAvoidTarget<>(this, EntityCat.class, 6.0F, 1.0D, 1.2D)); + this.goalSelector.a(4, new PathfinderGoalMeleeAttack(this, 1.0D, false)); + this.goalSelector.a(5, new PathfinderGoalRandomStrollLand(this, 0.8D)); + this.goalSelector.a(6, new PathfinderGoalLookAtPlayer(this, EntityHuman.class, 8.0F)); + this.goalSelector.a(6, new PathfinderGoalRandomLookaround(this)); ++ this.targetSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.targetSelector.a(1, new PathfinderGoalNearestAttackableTarget<>(this, EntityHuman.class, true)); + this.targetSelector.a(2, new PathfinderGoalHurtByTarget(this, new Class[0])); + } +@@ -214,6 +281,7 @@ public class EntityCreeper extends EntityMonster { + return (Integer) this.datawatcher.get(EntityCreeper.b); + } + ++ public void setSwellDirection(int i) { a(i); } // Purpur - OBFHELPER + public void a(int i) { + this.datawatcher.set(EntityCreeper.b, i); + } +@@ -314,6 +382,7 @@ public class EntityCreeper extends EntityMonster { + com.destroystokyo.paper.event.entity.CreeperIgniteEvent event = new com.destroystokyo.paper.event.entity.CreeperIgniteEvent((org.bukkit.entity.Creeper) getBukkitEntity(), ignited); + if (event.callEvent()) { + this.datawatcher.set(EntityCreeper.d, event.isIgnited()); ++ if (!event.isIgnited()) setSwellDirection(-1); // Purpur + } + } + // Paper end +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityDrowned.java b/src/main/java/net/minecraft/world/entity/monster/EntityDrowned.java +index ea776755767f29e49de2792afa30f79420d0fa4c..1d4039d61a2c77a38a31947010cee26f41c0becd 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityDrowned.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityDrowned.java +@@ -73,6 +73,16 @@ public class EntityDrowned extends EntityZombie implements IRangedEntity { + } + + // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.drownedRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.drownedRidableInWater; ++ } ++ + @Override + public boolean jockeyOnlyBaby() { + return world.purpurConfig.drownedJockeyOnlyBaby; +@@ -270,7 +280,7 @@ public class EntityDrowned extends EntityZombie implements IRangedEntity { + this.d = flag; + } + +- static class d extends ControllerMove { ++ static class d extends net.pl3x.purpur.controller.ControllerMoveWASD { // Purpur + + private final EntityDrowned i; + +@@ -280,7 +290,7 @@ public class EntityDrowned extends EntityZombie implements IRangedEntity { + } + + @Override +- public void a() { ++ public void tick() { // Purpur + EntityLiving entityliving = this.i.getGoalTarget(); + + if (this.i.eW() && this.i.isInWater()) { +@@ -313,7 +323,7 @@ public class EntityDrowned extends EntityZombie implements IRangedEntity { + this.i.setMot(this.i.getMot().add(0.0D, -0.008D, 0.0D)); + } + +- super.a(); ++ super.tick(); // Purpur + } + + } +@@ -452,6 +462,7 @@ public class EntityDrowned extends EntityZombie implements IRangedEntity { + this.a = entitydrowned; + this.b = d0; + this.c = i; ++ this.a(EnumSet.of(PathfinderGoal.Type.UNKNOWN_BEHAVIOR)); // Purpur - swim up + } + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityEnderman.java b/src/main/java/net/minecraft/world/entity/monster/EntityEnderman.java +index 1e50f7c51f88afaed01777d2da9ed543718a610d..a15dbd76e1d1afae7eb3809ef2e0448d8e2ab8e6 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityEnderman.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityEnderman.java +@@ -16,6 +16,7 @@ import net.minecraft.nbt.NBTTagCompound; + import net.minecraft.network.syncher.DataWatcher; + import net.minecraft.network.syncher.DataWatcherObject; + import net.minecraft.network.syncher.DataWatcherRegistry; ++import net.minecraft.server.PathfinderGoalHasRider; + import net.minecraft.server.level.WorldServer; + import net.minecraft.sounds.SoundEffect; + import net.minecraft.sounds.SoundEffects; +@@ -84,9 +85,22 @@ public class EntityEnderman extends EntityMonster implements IEntityAngerable { + this.a(PathType.WATER, -1.0F); + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.endermanRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.endermanRidableInWater; ++ } ++ // Purpur end ++ + @Override + protected void initPathfinder() { + this.goalSelector.a(0, new PathfinderGoalFloat(this)); ++ this.goalSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.goalSelector.a(1, new EntityEnderman.a(this)); + this.goalSelector.a(2, new PathfinderGoalMeleeAttack(this, 1.0D, false)); + this.goalSelector.a(7, new PathfinderGoalRandomStrollLand(this, 1.0D, 0.0F)); +@@ -94,6 +108,7 @@ public class EntityEnderman extends EntityMonster implements IEntityAngerable { + this.goalSelector.a(8, new PathfinderGoalRandomLookaround(this)); + this.goalSelector.a(10, new EntityEnderman.PathfinderGoalEndermanPlaceBlock(this)); + this.goalSelector.a(11, new EntityEnderman.PathfinderGoalEndermanPickupBlock(this)); ++ this.targetSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.targetSelector.a(1, new EntityEnderman.PathfinderGoalPlayerWhoLookedAtTarget(this, this::a_)); + this.targetSelector.a(2, new PathfinderGoalHurtByTarget(this, new Class[0])); + this.targetSelector.a(3, new PathfinderGoalNearestAttackableTarget<>(this, EntityEndermite.class, 10, true, false, EntityEnderman.bq)); +@@ -274,7 +289,7 @@ public class EntityEnderman extends EntityMonster implements IEntityAngerable { + + @Override + protected void mobTick() { +- if (this.world.isDay() && this.ticksLived >= this.bs + 600) { ++ if (!hasPurpurRider() && this.world.isDay() && this.ticksLived >= this.bs + 600) { // Purpur - no random teleporting + float f = this.aR(); + + if (f > 0.5F && this.world.e(this.getChunkCoordinates()) && this.random.nextFloat() * 30.0F < (f - 0.4F) * 2.0F && this.tryEscape(EndermanEscapeEvent.Reason.RUNAWAY)) { // Paper +@@ -376,6 +391,7 @@ public class EntityEnderman extends EntityMonster implements IEntityAngerable { + if (this.isInvulnerable(damagesource)) { + return false; + } else if (net.pl3x.purpur.PurpurConfig.endermanShortHeight && damagesource == DamageSource.STUCK) { return false; // Purpur - no suffocation damage if short height ++ } else if (hasPurpurRider()) { return super.damageEntity(damagesource, f); // Purpur - no teleporting on damage + } else if (damagesource instanceof EntityDamageSourceIndirect) { + if (this.tryEscape(EndermanEscapeEvent.Reason.INDIRECT)) { // Paper start + for (int i = 0; i < 64; ++i) { +@@ -420,6 +436,7 @@ public class EntityEnderman extends EntityMonster implements IEntityAngerable { + + public PathfinderGoalEndermanPickupBlock(EntityEnderman entityenderman) { + this.enderman = entityenderman; ++ this.a(EnumSet.of(PathfinderGoal.Type.UNKNOWN_BEHAVIOR)); // Purpur + } + + @Override +@@ -462,6 +479,7 @@ public class EntityEnderman extends EntityMonster implements IEntityAngerable { + + public PathfinderGoalEndermanPlaceBlock(EntityEnderman entityenderman) { + this.a = entityenderman; ++ this.a(EnumSet.of(PathfinderGoal.Type.UNKNOWN_BEHAVIOR)); // Purpur + } + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityEndermite.java b/src/main/java/net/minecraft/world/entity/monster/EntityEndermite.java +index 906ac1f861241a184819b4b113abe56625ff5e60..1c87bea9de812e57f8ccd3c9aa85330af87ed240 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityEndermite.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityEndermite.java +@@ -4,6 +4,7 @@ import java.util.Random; + import net.minecraft.core.BlockPosition; + import net.minecraft.core.particles.Particles; + import net.minecraft.nbt.NBTTagCompound; ++import net.minecraft.server.PathfinderGoalHasRider; + import net.minecraft.sounds.SoundEffect; + import net.minecraft.sounds.SoundEffects; + import net.minecraft.world.damagesource.DamageSource; +@@ -36,14 +37,28 @@ public class EntityEndermite extends EntityMonster { + this.f = 3; + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.endermiteRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.endermiteRidableInWater; ++ } ++ // Purpur end ++ + @Override + protected void initPathfinder() { + this.goalSelector.a(1, new PathfinderGoalFloat(this)); ++ this.goalSelector.a(1, new PathfinderGoalHasRider(this)); // Purpur + this.goalSelector.a(2, new PathfinderGoalMeleeAttack(this, 1.0D, false)); + this.goalSelector.a(3, new PathfinderGoalRandomStrollLand(this, 1.0D)); + this.goalSelector.a(7, new PathfinderGoalLookAtPlayer(this, EntityHuman.class, 8.0F)); + this.goalSelector.a(8, new PathfinderGoalRandomLookaround(this)); +- this.targetSelector.a(1, (new PathfinderGoalHurtByTarget(this, new Class[0])).a()); ++ this.targetSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur ++ this.targetSelector.a(1, (new PathfinderGoalHurtByTarget(this, new Class[0])).a(new Class[0])); // Purpur - decompile error + this.targetSelector.a(2, new PathfinderGoalNearestAttackableTarget<>(this, EntityHuman.class, true)); + } + +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityEvoker.java b/src/main/java/net/minecraft/world/entity/monster/EntityEvoker.java +index 2aa6b6ca93c25c59ad224348aad1bb34d9bbc6a3..55607910183155080e3d96296421438d17f19c8f 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityEvoker.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityEvoker.java +@@ -5,6 +5,7 @@ import javax.annotation.Nullable; + import net.minecraft.core.BlockPosition; + import net.minecraft.core.EnumDirection; + import net.minecraft.nbt.NBTTagCompound; ++import net.minecraft.server.PathfinderGoalHasRider; + import net.minecraft.server.level.WorldServer; + import net.minecraft.sounds.SoundEffect; + import net.minecraft.sounds.SoundEffects; +@@ -19,6 +20,7 @@ import net.minecraft.world.entity.EnumMonsterType; + import net.minecraft.world.entity.GroupDataEntity; + import net.minecraft.world.entity.ai.attributes.AttributeProvider; + import net.minecraft.world.entity.ai.attributes.GenericAttributes; ++import net.minecraft.world.entity.ai.goal.PathfinderGoal; + import net.minecraft.world.entity.ai.goal.PathfinderGoalAvoidTarget; + import net.minecraft.world.entity.ai.goal.PathfinderGoalFloat; + import net.minecraft.world.entity.ai.goal.PathfinderGoalLookAtPlayer; +@@ -47,10 +49,23 @@ public class EntityEvoker extends EntityIllagerWizard { + this.f = 10; + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.evokerRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.evokerRidableInWater; ++ } ++ // Purpur end ++ + @Override + protected void initPathfinder() { + super.initPathfinder(); + this.goalSelector.a(0, new PathfinderGoalFloat(this)); ++ this.goalSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.goalSelector.a(1, new EntityEvoker.b()); + this.goalSelector.a(2, new PathfinderGoalAvoidTarget<>(this, EntityHuman.class, 8.0F, 0.6D, 1.0D)); + this.goalSelector.a(4, new EntityEvoker.c()); +@@ -59,6 +74,7 @@ public class EntityEvoker extends EntityIllagerWizard { + this.goalSelector.a(8, new PathfinderGoalRandomStroll(this, 0.6D)); + this.goalSelector.a(9, new PathfinderGoalLookAtPlayer(this, EntityHuman.class, 3.0F, 1.0F)); + this.goalSelector.a(10, new PathfinderGoalLookAtPlayer(this, EntityInsentient.class, 8.0F)); ++ this.targetSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.targetSelector.a(1, (new PathfinderGoalHurtByTarget(this, new Class[]{EntityRaider.class})).a(new Class[0])); // Paper - decompile fix + this.targetSelector.a(2, (new PathfinderGoalNearestAttackableTarget<>(this, EntityHuman.class, true)).a(300)); + this.targetSelector.a(3, (new PathfinderGoalNearestAttackableTarget<>(this, EntityVillagerAbstract.class, false)).a(300)); +@@ -139,6 +155,7 @@ public class EntityEvoker extends EntityIllagerWizard { + + public d() { + super(); ++ this.a(java.util.EnumSet.of(PathfinderGoal.Type.UNKNOWN_BEHAVIOR)); // Purpur - wolololo spell + } + + @Override +@@ -217,6 +234,7 @@ public class EntityEvoker extends EntityIllagerWizard { + private c() { + super(); + this.e = (new PathfinderTargetCondition()).a(16.0D).c().e().a().b(); ++ this.a(java.util.EnumSet.of(PathfinderGoal.Type.UNKNOWN_BEHAVIOR)); // Purpur - summon spell + } + + @Override +@@ -273,6 +291,7 @@ public class EntityEvoker extends EntityIllagerWizard { + + private a() { + super(); ++ this.a(java.util.EnumSet.of(PathfinderGoal.Type.UNKNOWN_BEHAVIOR)); // Purpur - attack with spell + } + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityGhast.java b/src/main/java/net/minecraft/world/entity/monster/EntityGhast.java +index a3e3f6e07674c54c2d2a02661ce4342b43aafe44..b6d49740a1c8dfa19e871869b92b307fc8397588 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityGhast.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityGhast.java +@@ -7,6 +7,7 @@ import net.minecraft.nbt.NBTTagCompound; + import net.minecraft.network.syncher.DataWatcher; + import net.minecraft.network.syncher.DataWatcherObject; + import net.minecraft.network.syncher.DataWatcherRegistry; ++import net.minecraft.server.PathfinderGoalHasRider; + import net.minecraft.sounds.SoundCategory; + import net.minecraft.sounds.SoundEffect; + import net.minecraft.sounds.SoundEffects; +@@ -21,6 +22,7 @@ import net.minecraft.world.entity.EntityPose; + import net.minecraft.world.entity.EntitySize; + import net.minecraft.world.entity.EntityTypes; + import net.minecraft.world.entity.EnumMobSpawn; ++import net.minecraft.world.entity.EnumMoveType; + import net.minecraft.world.entity.ai.attributes.AttributeProvider; + import net.minecraft.world.entity.ai.attributes.GenericAttributes; + import net.minecraft.world.entity.ai.control.ControllerMove; +@@ -44,11 +46,42 @@ public class EntityGhast extends EntityFlying implements IMonster { + this.moveController = new EntityGhast.ControllerGhast(this); + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.ghastRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.ghastRidableInWater; ++ } ++ ++ @Override ++ public double getMaxY() { ++ return world.purpurConfig.ghastMaxY; ++ } ++ ++ @Override ++ public void g(Vec3D vec3d) { ++ super.g(vec3d); ++ if (hasPurpurRider() && !onGround) { ++ float speed = (float) getAttributeInstance(GenericAttributes.FLYING_SPEED).getValue(); ++ setSpeed(speed); ++ Vec3D mot = getMot(); ++ move(EnumMoveType.SELF, mot.multiply(speed, 1.0, speed)); ++ setMot(mot.a(0.9D)); ++ } ++ } ++ // Purpur end ++ + @Override + protected void initPathfinder() { ++ this.goalSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.goalSelector.a(5, new EntityGhast.PathfinderGoalGhastIdleMove(this)); + this.goalSelector.a(7, new EntityGhast.PathfinderGoalGhastMoveTowardsTarget(this)); + this.goalSelector.a(7, new EntityGhast.PathfinderGoalGhastAttackTarget(this)); ++ this.targetSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.targetSelector.a(1, new PathfinderGoalNearestAttackableTarget<>(this, EntityHuman.class, 10, true, false, (entityliving) -> { + return Math.abs(entityliving.locY() - this.locY()) <= 4.0D; + })); +@@ -86,7 +119,7 @@ public class EntityGhast extends EntityFlying implements IMonster { + } + + public static AttributeProvider.Builder eJ() { +- return EntityInsentient.p().a(GenericAttributes.MAX_HEALTH, 10.0D).a(GenericAttributes.FOLLOW_RANGE, 100.0D); ++ return EntityInsentient.p().a(GenericAttributes.MAX_HEALTH, 10.0D).a(GenericAttributes.FOLLOW_RANGE, 100.0D).a(GenericAttributes.FLYING_SPEED, 0.6D); // Purpur + } + + @Override +@@ -285,7 +318,7 @@ public class EntityGhast extends EntityFlying implements IMonster { + } + } + +- static class ControllerGhast extends ControllerMove { ++ static class ControllerGhast extends net.pl3x.purpur.controller.ControllerMoveWASDFlying { // Purpur + + private final EntityGhast i; + private int j; +@@ -296,7 +329,7 @@ public class EntityGhast extends EntityFlying implements IMonster { + } + + @Override +- public void a() { ++ public void tick() { // Purpur + if (this.h == ControllerMove.Operation.MOVE_TO) { + if (this.j-- <= 0) { + this.j += this.i.getRandom().nextInt(5) + 2; +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityGiantZombie.java b/src/main/java/net/minecraft/world/entity/monster/EntityGiantZombie.java +index a188a89143cb1b0243dacdec33c446ca4120219f..7395fa90198a9138b2c33273d8f3540355300029 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityGiantZombie.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityGiantZombie.java +@@ -2,6 +2,7 @@ package net.minecraft.world.entity.monster; + + import net.minecraft.core.BlockPosition; + import net.minecraft.nbt.NBTTagCompound; ++import net.minecraft.server.PathfinderGoalHasRider; + import net.minecraft.world.DifficultyDamageScaler; + import net.minecraft.world.EnumDifficulty; + import net.minecraft.world.entity.EntityPose; +@@ -41,16 +42,28 @@ public class EntityGiantZombie extends EntityMonster { + } + + // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.giantRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.giantRidableInWater; ++ } ++ + @Override + protected void initPathfinder() { + if (world.purpurConfig.giantHaveAI) { + this.goalSelector.a(0, new PathfinderGoalFloat(this)); ++ this.goalSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.goalSelector.a(7, new PathfinderGoalRandomStrollLand(this, 1.0D)); + this.goalSelector.a(8, new PathfinderGoalLookAtPlayer(this, EntityHuman.class, 16.0F)); + this.goalSelector.a(8, new PathfinderGoalRandomLookaround(this)); + this.goalSelector.a(5, new PathfinderGoalMoveTowardsRestriction(this, 1.0D)); + if (world.purpurConfig.giantHaveHostileAI) { + this.goalSelector.a(2, new PathfinderGoalMeleeAttack(this, 1.0D, false)); ++ this.targetSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.targetSelector.a(1, new PathfinderGoalHurtByTarget(this).a(EntityPigZombie.class)); + this.targetSelector.a(2, new PathfinderGoalNearestAttackableTarget<>(this, EntityHuman.class, true)); + this.targetSelector.a(3, new PathfinderGoalNearestAttackableTarget<>(this, EntityVillager.class, false)); +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityGuardian.java b/src/main/java/net/minecraft/world/entity/monster/EntityGuardian.java +index d53e2a9d27f9976d1fd8ea30b88a0da089aec7b6..66ae664add95f4441724b49a470a2fef569042d6 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityGuardian.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityGuardian.java +@@ -9,6 +9,7 @@ import net.minecraft.core.particles.Particles; + import net.minecraft.network.syncher.DataWatcher; + import net.minecraft.network.syncher.DataWatcherObject; + import net.minecraft.network.syncher.DataWatcherRegistry; ++import net.minecraft.server.PathfinderGoalHasRider; + import net.minecraft.sounds.SoundEffect; + import net.minecraft.sounds.SoundEffects; + import net.minecraft.tags.Tag; +@@ -63,15 +64,36 @@ public class EntityGuardian extends EntityMonster { + this.f = 10; + this.a(PathType.WATER, 0.0F); + this.moveController = new EntityGuardian.ControllerMoveGuardian(this); ++ // Purpur start ++ this.lookController = new net.pl3x.purpur.controller.ControllerLookWASD(this) { ++ @Override ++ public void setYawPitch(float yaw, float pitch) { ++ super.setYawPitch(yaw, pitch * 0.35F); ++ } ++ }; ++ // Purpur end + this.bo = this.random.nextFloat(); + this.bp = this.bo; + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.guardianRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return true; ++ } ++ // Purpur end ++ + @Override + protected void initPathfinder() { + PathfinderGoalMoveTowardsRestriction pathfindergoalmovetowardsrestriction = new PathfinderGoalMoveTowardsRestriction(this, 1.0D); + + this.goalRandomStroll = new PathfinderGoalRandomStroll(this, 1.0D, 80); ++ this.goalSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.goalSelector.a(4, new EntityGuardian.PathfinderGoalGuardianAttack(this)); + this.goalSelector.a(5, pathfindergoalmovetowardsrestriction); + this.goalSelector.a(7, this.goalRandomStroll); +@@ -80,6 +102,7 @@ public class EntityGuardian extends EntityMonster { + this.goalSelector.a(9, new PathfinderGoalRandomLookaround(this)); + this.goalRandomStroll.a(EnumSet.of(PathfinderGoal.Type.MOVE, PathfinderGoal.Type.LOOK)); + pathfindergoalmovetowardsrestriction.a(EnumSet.of(PathfinderGoal.Type.MOVE, PathfinderGoal.Type.LOOK)); ++ this.targetSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.targetSelector.a(1, new PathfinderGoalNearestAttackableTarget<>(this, EntityLiving.class, 10, true, false, new EntityGuardian.EntitySelectorGuardianTargetHumanSquid(this))); + } + +@@ -113,6 +136,7 @@ public class EntityGuardian extends EntityMonster { + return (Boolean) this.datawatcher.get(EntityGuardian.b); + } + ++ private void setMovingFlag(boolean movingFlag) { t(movingFlag); } // Purpur - OBFHELPER + private void t(boolean flag) { + this.datawatcher.set(EntityGuardian.b, flag); + } +@@ -327,7 +351,7 @@ public class EntityGuardian extends EntityMonster { + @Override + public void g(Vec3D vec3d) { + if (this.doAITick() && this.isInWater()) { +- this.a(0.1F, vec3d); ++ this.a(hasPurpurRider() ? getSpeed() : 0.1F, vec3d); // Purpur + this.move(EnumMoveType.SELF, this.getMot()); + this.setMot(this.getMot().a(0.9D)); + if (!this.eN() && this.getGoalTarget() == null) { +@@ -339,17 +363,26 @@ public class EntityGuardian extends EntityMonster { + + } + +- static class ControllerMoveGuardian extends ControllerMove { ++ static class ControllerMoveGuardian extends net.pl3x.purpur.controller.ControllerMoveWASDWater { // Purpur + +- private final EntityGuardian i; ++ private final EntityGuardian i; private EntityGuardian getGuardian() { return i; } // Purpur - OBFHELPER + + public ControllerMoveGuardian(EntityGuardian entityguardian) { + super(entityguardian); + this.i = entityguardian; + } + ++ // Purpur start ++ @Override ++ public void tick(EntityHuman rider) { ++ super.tick(rider); ++ getGuardian().setMot(getGuardian().getMot().add(0.0D, 0.005D, 0.0D)); ++ getGuardian().setMovingFlag(getGuardian().getForward() > 0.0F); // control tail speed ++ } ++ // Purpur end ++ + @Override +- public void a() { ++ public void tick() { // Purpur + if (this.h == ControllerMove.Operation.MOVE_TO && !this.i.getNavigation().m()) { + Vec3D vec3d = new Vec3D(this.b - this.i.locX(), this.c - this.i.locY(), this.d - this.i.locZ()); + double d0 = vec3d.f(); +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityGuardianElder.java b/src/main/java/net/minecraft/world/entity/monster/EntityGuardianElder.java +index 300efeb98bb68b24faa68a4af9d703bf2b8c405c..ef48184f79920f053d62d34cc7b56a98e8aa4274 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityGuardianElder.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityGuardianElder.java +@@ -30,6 +30,18 @@ public class EntityGuardianElder extends EntityGuardian { + + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.elderGuardianRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return true; ++ } ++ // Purpur end ++ + public static AttributeProvider.Builder m() { + return EntityGuardian.eM().a(GenericAttributes.MOVEMENT_SPEED, 0.30000001192092896D).a(GenericAttributes.ATTACK_DAMAGE, 8.0D).a(GenericAttributes.MAX_HEALTH, 80.0D); + } +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityIllagerIllusioner.java b/src/main/java/net/minecraft/world/entity/monster/EntityIllagerIllusioner.java +index cb092bee9d6827d4b0276bfa9b033cf7ca86ead4..5186d9957c94be359da5b08fd821e9471c159f03 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityIllagerIllusioner.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityIllagerIllusioner.java +@@ -3,6 +3,7 @@ package net.minecraft.world.entity.monster; + import javax.annotation.Nullable; + import net.minecraft.core.particles.Particles; + import net.minecraft.nbt.NBTTagCompound; ++import net.minecraft.server.PathfinderGoalHasRider; + import net.minecraft.sounds.SoundEffect; + import net.minecraft.sounds.SoundEffects; + import net.minecraft.util.MathHelper; +@@ -57,6 +58,16 @@ public class EntityIllagerIllusioner extends EntityIllagerWizard implements IRan + } + + // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.illusionerRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.illusionerRidableInWater; ++ } ++ + @Override + protected void initAttributes() { + this.getAttributeInstance(GenericAttributes.MOVEMENT_SPEED).setValue(this.world.purpurConfig.illusionerMovementSpeed); +@@ -69,6 +80,7 @@ public class EntityIllagerIllusioner extends EntityIllagerWizard implements IRan + protected void initPathfinder() { + super.initPathfinder(); + this.goalSelector.a(0, new PathfinderGoalFloat(this)); ++ this.goalSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.goalSelector.a(1, new EntityIllagerWizard.b()); + this.goalSelector.a(4, new EntityIllagerIllusioner.b()); + this.goalSelector.a(5, new EntityIllagerIllusioner.a()); +@@ -76,6 +88,7 @@ public class EntityIllagerIllusioner extends EntityIllagerWizard implements IRan + this.goalSelector.a(8, new PathfinderGoalRandomStroll(this, 0.6D)); + this.goalSelector.a(9, new PathfinderGoalLookAtPlayer(this, EntityHuman.class, 3.0F, 1.0F)); + this.goalSelector.a(10, new PathfinderGoalLookAtPlayer(this, EntityInsentient.class, 8.0F)); ++ this.targetSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.targetSelector.a(1, (new PathfinderGoalHurtByTarget(this, new Class[]{EntityRaider.class})).a(new Class[0])); // CraftBukkit - decompile error + this.targetSelector.a(2, (new PathfinderGoalNearestAttackableTarget<>(this, EntityHuman.class, true)).a(300)); + this.targetSelector.a(3, (new PathfinderGoalNearestAttackableTarget<>(this, EntityVillagerAbstract.class, false)).a(300)); +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityMagmaCube.java b/src/main/java/net/minecraft/world/entity/monster/EntityMagmaCube.java +index fe80e93b00f3bb2f297c6528c3951313fa3c08c7..15ed51a2746c09538a425fce25fa25f2619b7033 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityMagmaCube.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityMagmaCube.java +@@ -29,6 +29,23 @@ public class EntityMagmaCube extends EntitySlime { + super(entitytypes, world); + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.magmaCubeRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.magmaCubeRidableInWater; ++ } ++ ++ @Override ++ public float getJumpHeight() { ++ return 0.42F * this.getBlockJumpFactor(); // from EntityLiving ++ } ++ // Purpur end ++ + public static AttributeProvider.Builder m() { + return EntityMonster.eR().a(GenericAttributes.MOVEMENT_SPEED, 0.20000000298023224D); + } +@@ -79,11 +96,12 @@ public class EntityMagmaCube extends EntitySlime { + } + + @Override +- protected void jump() { ++ public void jump() { // Purpur - protected -> public + Vec3D vec3d = this.getMot(); + + this.setMot(vec3d.x, (double) (this.dJ() + (float) this.getSize() * 0.1F), vec3d.z); + this.impulse = true; ++ this.actualJump = false; // Purpur + } + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityPhantom.java b/src/main/java/net/minecraft/world/entity/monster/EntityPhantom.java +index fd2e3a4abcfedaf04db4277291983627c097b545..1ea3054cebbf32588219f8915f9fb496495e3a10 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityPhantom.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityPhantom.java +@@ -13,6 +13,7 @@ import net.minecraft.network.syncher.DataWatcher; + import net.minecraft.network.syncher.DataWatcherObject; + import net.minecraft.network.syncher.DataWatcherRegistry; + import net.minecraft.server.level.WorldServer; ++import net.minecraft.server.PathfinderGoalHasRider; + import net.minecraft.sounds.SoundCategory; + import net.minecraft.sounds.SoundEffect; + import net.minecraft.sounds.SoundEffects; +@@ -29,11 +30,11 @@ import net.minecraft.world.entity.EntitySize; + import net.minecraft.world.entity.EntityTypes; + import net.minecraft.world.entity.EnumMobSpawn; + import net.minecraft.world.entity.EnumMonsterType; ++import net.minecraft.world.entity.EnumMoveType; + import net.minecraft.world.entity.GroupDataEntity; + import net.minecraft.world.entity.IEntitySelector; ++import net.minecraft.world.entity.ai.attributes.AttributeProvider; + import net.minecraft.world.entity.ai.attributes.GenericAttributes; +-import net.minecraft.world.entity.ai.control.ControllerLook; +-import net.minecraft.world.entity.ai.control.ControllerMove; + import net.minecraft.world.entity.ai.control.EntityAIBodyControl; + import net.minecraft.world.entity.ai.goal.PathfinderGoal; + import net.minecraft.world.entity.ai.targeting.PathfinderTargetCondition; +@@ -68,6 +69,59 @@ public class EntityPhantom extends EntityFlying implements IMonster { + this.lookController = new EntityPhantom.f(this); + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.phantomRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.phantomRidableInWater; ++ } ++ ++ @Override ++ public double getMaxY() { ++ return world.purpurConfig.phantomMaxY; ++ } ++ ++ @Override ++ public void g(Vec3D vec3d) { ++ super.g(vec3d); ++ if (hasPurpurRider() && !onGround) { ++ float speed = (float) getAttributeInstance(GenericAttributes.FLYING_SPEED).getValue(); ++ setSpeed(speed); ++ Vec3D mot = getMot(); ++ move(EnumMoveType.SELF, mot.multiply(speed, speed, speed)); ++ setMot(mot.a(0.9D)); ++ } ++ } ++ ++ public static AttributeProvider.Builder defaultAttributes() { ++ return EntityMonster.eR().a(GenericAttributes.FLYING_SPEED, 3.0D); ++ } ++ ++ @Override ++ public boolean onSpacebar() { ++ if (hasPurpurRider() && getPurpurRider().getBukkitEntity().hasPermission("allow.special.phantom")) { ++ shoot(); ++ } ++ return false; ++ } ++ ++ public boolean shoot() { ++ org.bukkit.Location loc = ((org.bukkit.entity.LivingEntity) getBukkitEntity()).getEyeLocation(); ++ loc.setPitch(-loc.getPitch()); ++ org.bukkit.util.Vector target = loc.getDirection().normalize().multiply(100).add(loc.toVector()); ++ ++ net.pl3x.purpur.entity.PhantomFlames flames = new net.pl3x.purpur.entity.PhantomFlames(world, this); ++ flames.canGrief = world.purpurConfig.phantomAllowGriefing; ++ flames.shoot(target.getX() - locX(), target.getY() - locY(), target.getZ() - locZ(), 1.0F, 5.0F); ++ world.addEntity(flames); ++ return true; ++ } ++ // Purpur end ++ + @Override + protected EntityAIBodyControl r() { + return new EntityPhantom.d(this); +@@ -76,6 +130,7 @@ public class EntityPhantom extends EntityFlying implements IMonster { + @Override + protected void initPathfinder() { + // Purpur start ++ this.goalSelector.a(0, new PathfinderGoalHasRider(this)); + if (world.purpurConfig.phantomOrbitCrystalRadius > 0) { + this.goalSelector.a(1, new FindCrystalGoal(this)); + this.goalSelector.a(2, new OrbitCrystalGoal(this)); +@@ -83,6 +138,7 @@ public class EntityPhantom extends EntityFlying implements IMonster { + this.goalSelector.a(3, new EntityPhantom.c()); // PickAttackGoal + this.goalSelector.a(4, new EntityPhantom.i()); // SweepAttackGoal + this.goalSelector.a(5, new EntityPhantom.e()); // OrbitPointGoal ++ this.targetSelector.a(0, new PathfinderGoalHasRider(this)); + this.targetSelector.a(1, new EntityPhantom.b()); // AttackPlayer Goal + // Purpur end + } +@@ -169,7 +225,7 @@ public class EntityPhantom extends EntityFlying implements IMonster { + + @Override + public void movementTick() { +- if (this.isAlive() && (((shouldBurnInDay || world.purpurConfig.phantomBurnInDaylight) && this.isInDaylight()) || (world.purpurConfig.phantomBurnInLight > 0 && world.getLightLevel(new BlockPosition(this)) >= world.purpurConfig.phantomBurnInLight))) { // Paper - Configurable Burning // Purpur ++ if (this.isAlive() && !hasPurpurRider() && (((shouldBurnInDay || world.purpurConfig.phantomBurnInDaylight) && this.isInDaylight()) || (world.purpurConfig.phantomBurnInLight > 0 && world.getLightLevel(new BlockPosition(this)) >= world.purpurConfig.phantomBurnInLight))) { // Paper - Configurable Burning // Purpur + this.setOnFire(8); + } + +@@ -418,7 +474,7 @@ public class EntityPhantom extends EntityFlying implements IMonster { + + @Override + public boolean a() { +- if (isCirclingCrystal()) return false; // Purpur - pathfinder does not have a flag ++ if (getPurpurRider() != null || isCirclingCrystal()) return false; // Purpur - pathfinder does not have a flag + if (this.c > 0) { + --this.c; + return false; +@@ -447,7 +503,7 @@ public class EntityPhantom extends EntityFlying implements IMonster { + + @Override + public boolean b() { +- if (isCirclingCrystal()) return false; // Purpur - pathfinder does not have a flag ++ if (getPurpurRider() != null || isCirclingCrystal()) return false; // Purpur - pathfinder does not have a flag + EntityLiving entityliving = EntityPhantom.this.getGoalTarget(); + + return entityliving != null ? EntityPhantom.this.a(entityliving, PathfinderTargetCondition.a) : false; +@@ -462,7 +518,7 @@ public class EntityPhantom extends EntityFlying implements IMonster { + + @Override + public boolean a() { +- if (isCirclingCrystal()) return false; // Purpur - pathfinder does not have a flag ++ if (getPurpurRider() != null || isCirclingCrystal()) return false; // Purpur - pathfinder does not have a flag + EntityLiving entityliving = EntityPhantom.this.getGoalTarget(); + + return entityliving != null ? EntityPhantom.this.a(EntityPhantom.this.getGoalTarget(), PathfinderTargetCondition.a) : false; +@@ -660,14 +716,23 @@ public class EntityPhantom extends EntityFlying implements IMonster { + } + } + +- class f extends ControllerLook { ++ class f extends net.pl3x.purpur.controller.ControllerLookWASD { // Purpur + + public f(EntityInsentient entityinsentient) { + super(entityinsentient); + } + + @Override +- public void a() {} ++ // Purpur start ++ public void tick(EntityHuman rider) { ++ setYawPitch(rider.yaw, -rider.pitch * 0.75F); ++ } ++ ++ @Override ++ public void tick() { ++ // do nothing ++ } ++ // Purpur end + } + + class d extends EntityAIBodyControl { +@@ -683,7 +748,7 @@ public class EntityPhantom extends EntityFlying implements IMonster { + } + } + +- class g extends ControllerMove { ++ class g extends net.pl3x.purpur.controller.ControllerMoveWASDFlying { // Purpur + + private float j = 0.1F; + +@@ -692,7 +757,19 @@ public class EntityPhantom extends EntityFlying implements IMonster { + } + + @Override +- public void a() { ++ // Purpur start ++ public void tick(EntityHuman rider) { ++ if (!EntityPhantom.this.onGround) { ++ // phantom is always in motion when flying ++ // TODO - FIX THIS ++ // rider.setForward(1.0F); ++ } ++ super.tick(rider); ++ } ++ ++ @Override ++ public void tick() { ++ // Purpur end + if (EntityPhantom.this.positionChanged) { + EntityPhantom.this.yaw += 180.0F; + this.j = 0.1F; +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityPigZombie.java b/src/main/java/net/minecraft/world/entity/monster/EntityPigZombie.java +index ee17e62d996d81ea149a5c0eae2e29404e363dcf..9f50054211db48e7fe764434e8d71aab0995e57a 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityPigZombie.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityPigZombie.java +@@ -57,6 +57,16 @@ public class EntityPigZombie extends EntityZombie implements IEntityAngerable { + } + + // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.zombifiedPiglinRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.zombifiedPiglinRidableInWater; ++ } ++ + @Override + public boolean jockeyOnlyBaby() { + return world.purpurConfig.zombifiedPiglinJockeyOnlyBaby; +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityPillager.java b/src/main/java/net/minecraft/world/entity/monster/EntityPillager.java +index ea105fb86553f5212d616c976eaf2a16bf5b6561..2a4ac6e608650d56cc2b564e715b7b685e7f3f62 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityPillager.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityPillager.java +@@ -9,6 +9,7 @@ import net.minecraft.nbt.NBTTagList; + import net.minecraft.network.syncher.DataWatcher; + import net.minecraft.network.syncher.DataWatcherObject; + import net.minecraft.network.syncher.DataWatcherRegistry; ++import net.minecraft.server.PathfinderGoalHasRider; + import net.minecraft.sounds.SoundEffect; + import net.minecraft.sounds.SoundEffects; + import net.minecraft.world.DifficultyDamageScaler; +@@ -61,15 +62,29 @@ public class EntityPillager extends EntityIllagerAbstract implements ICrossbow { + super(entitytypes, world); + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.pillagerRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.pillagerRidableInWater; ++ } ++ // Purpur end ++ + @Override + protected void initPathfinder() { + super.initPathfinder(); + this.goalSelector.a(0, new PathfinderGoalFloat(this)); ++ this.goalSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.goalSelector.a(2, new EntityRaider.a(this, 10.0F)); + this.goalSelector.a(3, new PathfinderGoalCrossbowAttack<>(this, 1.0D, 8.0F)); + this.goalSelector.a(8, new PathfinderGoalRandomStroll(this, 0.6D)); + this.goalSelector.a(9, new PathfinderGoalLookAtPlayer(this, EntityHuman.class, 15.0F, 1.0F)); + this.goalSelector.a(10, new PathfinderGoalLookAtPlayer(this, EntityInsentient.class, 15.0F)); ++ this.targetSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.targetSelector.a(1, (new PathfinderGoalHurtByTarget(this, new Class[]{EntityRaider.class})).a(new Class[0])); // CraftBukkit - decompile error + this.targetSelector.a(2, new PathfinderGoalNearestAttackableTarget<>(this, EntityHuman.class, true)); + this.targetSelector.a(3, new PathfinderGoalNearestAttackableTarget<>(this, EntityVillagerAbstract.class, false)); +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityRavager.java b/src/main/java/net/minecraft/world/entity/monster/EntityRavager.java +index 16d5cae64887b82e67eeb61ccb714e6125ff0c09..cc37e545ece89803fad91801775470df4620bd62 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityRavager.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityRavager.java +@@ -7,6 +7,7 @@ import javax.annotation.Nullable; + import net.minecraft.core.BlockPosition; + import net.minecraft.core.particles.Particles; + import net.minecraft.nbt.NBTTagCompound; ++import net.minecraft.server.PathfinderGoalHasRider; + import net.minecraft.sounds.SoundEffect; + import net.minecraft.sounds.SoundEffects; + import net.minecraft.tags.Tag; +@@ -38,7 +39,6 @@ import net.minecraft.world.level.IBlockAccess; + import net.minecraft.world.level.IWorldReader; + import net.minecraft.world.level.World; + import net.minecraft.world.level.block.Block; +-import net.minecraft.world.level.block.BlockLeaves; + import net.minecraft.world.level.block.state.IBlockData; + import net.minecraft.world.level.pathfinder.PathType; + import net.minecraft.world.level.pathfinder.Pathfinder; +@@ -61,14 +61,37 @@ public class EntityRavager extends EntityRaider { + this.f = 20; + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.ravagerRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.ravagerRidableInWater; ++ } ++ ++ @Override ++ public void onMount(EntityHuman entityhuman) { ++ super.onMount(entityhuman); ++ getNavigation().stopPathfinding(); ++ ++ double speed = this.getAttributeInstance(GenericAttributes.MOVEMENT_SPEED).getBaseValue(); ++ getAttributeInstance(GenericAttributes.MOVEMENT_SPEED).setValue(speed); ++ } ++ // Purpur end ++ + @Override + protected void initPathfinder() { + super.initPathfinder(); + this.goalSelector.a(0, new PathfinderGoalFloat(this)); ++ this.goalSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.goalSelector.a(4, new EntityRavager.a()); + this.goalSelector.a(5, new PathfinderGoalRandomStrollLand(this, 0.4D)); + this.goalSelector.a(6, new PathfinderGoalLookAtPlayer(this, EntityHuman.class, 6.0F)); + this.goalSelector.a(10, new PathfinderGoalLookAtPlayer(this, EntityInsentient.class, 8.0F)); ++ this.targetSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.targetSelector.a(2, (new PathfinderGoalHurtByTarget(this, new Class[]{EntityRaider.class})).a(new Class[0])); // CraftBukkit - decompile error + this.targetSelector.a(3, new PathfinderGoalNearestAttackableTarget<>(this, EntityHuman.class, true)); + this.targetSelector.a(4, new PathfinderGoalNearestAttackableTarget<>(this, EntityVillagerAbstract.class, true)); +@@ -140,7 +163,7 @@ public class EntityRavager extends EntityRaider { + @Override + public void movementTick() { + super.movementTick(); +- if (this.isAlive()) { ++ if (this.isAlive() && !hasPurpurRider()) { + if (this.isFrozen()) { + this.getAttributeInstance(GenericAttributes.MOVEMENT_SPEED).setValue(0.0D); + } else { +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityShulker.java b/src/main/java/net/minecraft/world/entity/monster/EntityShulker.java +index 49523302dd72a3dafab23c047412a2e77b6247ed..4b5c1691664f16594f316e55576086f2ae54e59e 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityShulker.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityShulker.java +@@ -12,6 +12,7 @@ import net.minecraft.nbt.NBTTagCompound; + import net.minecraft.network.syncher.DataWatcher; + import net.minecraft.network.syncher.DataWatcherObject; + import net.minecraft.network.syncher.DataWatcherRegistry; ++import net.minecraft.server.PathfinderGoalHasRider; + import net.minecraft.sounds.SoundCategory; + import net.minecraft.sounds.SoundEffect; + import net.minecraft.sounds.SoundEffects; +@@ -71,12 +72,26 @@ public class EntityShulker extends EntityGolem implements IMonster { + this.f = 5; + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.shulkerRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.shulkerRidableInWater; ++ } ++ // Purpur end ++ + @Override + protected void initPathfinder() { ++ this.goalSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.goalSelector.a(1, new PathfinderGoalLookAtPlayer(this, EntityHuman.class, 8.0F)); + this.goalSelector.a(4, new EntityShulker.a()); + this.goalSelector.a(7, new EntityShulker.e()); + this.goalSelector.a(8, new PathfinderGoalRandomLookaround(this)); ++ this.targetSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.targetSelector.a(1, (new PathfinderGoalHurtByTarget(this, new Class[0])).a(new Class[0])); // CraftBukkit - decompile error + this.targetSelector.a(2, new EntityShulker.d(this)); + this.targetSelector.a(3, new EntityShulker.c(this)); +@@ -560,7 +575,7 @@ public class EntityShulker extends EntityGolem implements IMonster { + + private int b; + +- private e() {} ++ private e() { this.a(EnumSet.of(PathfinderGoal.Type.UNKNOWN_BEHAVIOR)); } // Purpur - peek + + @Override + public boolean a() { +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntitySilverfish.java b/src/main/java/net/minecraft/world/entity/monster/EntitySilverfish.java +index e1fcb1be102822e87eaf7757fbd64a516b2f58ac..c0601af022d85c7b03463f0df975d713c0366b2c 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntitySilverfish.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntitySilverfish.java +@@ -4,6 +4,7 @@ import java.util.EnumSet; + import java.util.Random; + import net.minecraft.core.BlockPosition; + import net.minecraft.core.EnumDirection; ++import net.minecraft.server.PathfinderGoalHasRider; + import net.minecraft.sounds.SoundEffect; + import net.minecraft.sounds.SoundEffects; + import net.minecraft.world.damagesource.DamageSource; +@@ -38,13 +39,27 @@ public class EntitySilverfish extends EntityMonster { + super(entitytypes, world); + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.silverfishRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.silverfishRidableInWater; ++ } ++ // Purpur end ++ + @Override + protected void initPathfinder() { + this.b = new EntitySilverfish.PathfinderGoalSilverfishWakeOthers(this); + this.goalSelector.a(1, new PathfinderGoalFloat(this)); ++ this.goalSelector.a(1, new PathfinderGoalHasRider(this)); // Purpur + this.goalSelector.a(3, this.b); + this.goalSelector.a(4, new PathfinderGoalMeleeAttack(this, 1.0D, false)); + this.goalSelector.a(5, new EntitySilverfish.PathfinderGoalSilverfishHideInBlock(this)); ++ this.targetSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.targetSelector.a(1, (new PathfinderGoalHurtByTarget(this, new Class[0])).a(new Class[0])); // CraftBukkit - decompile error + this.targetSelector.a(2, new PathfinderGoalNearestAttackableTarget<>(this, EntityHuman.class, true)); + } +@@ -204,6 +219,7 @@ public class EntitySilverfish extends EntityMonster { + + public PathfinderGoalSilverfishWakeOthers(EntitySilverfish entitysilverfish) { + this.silverfish = entitysilverfish; ++ this.a(EnumSet.of(PathfinderGoal.Type.UNKNOWN_BEHAVIOR)); // Purpur + } + + public void g() { +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntitySkeleton.java b/src/main/java/net/minecraft/world/entity/monster/EntitySkeleton.java +index 342bc9b586ef835e865d6f84bf66f1069ab10f00..0b8517d4e83d14ddf8b6d1f1cf4c538f9e4cc68f 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntitySkeleton.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntitySkeleton.java +@@ -15,6 +15,18 @@ public class EntitySkeleton extends EntitySkeletonAbstract { + super(entitytypes, world); + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.skeletonRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.skeletonRidableInWater; ++ } ++ // Purpur end ++ + @Override + protected SoundEffect getSoundAmbient() { + return SoundEffects.ENTITY_SKELETON_AMBIENT; +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntitySkeletonAbstract.java b/src/main/java/net/minecraft/world/entity/monster/EntitySkeletonAbstract.java +index f8358e40c42f219232bf928f4e0073339a5e19d5..81059fc3fc22f251b5b08f0cd6814a992cff6b1e 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntitySkeletonAbstract.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntitySkeletonAbstract.java +@@ -5,6 +5,7 @@ import java.time.temporal.ChronoField; + import javax.annotation.Nullable; + import net.minecraft.core.BlockPosition; + import net.minecraft.nbt.NBTTagCompound; ++import net.minecraft.server.PathfinderGoalHasRider; + import net.minecraft.sounds.SoundEffect; + import net.minecraft.sounds.SoundEffects; + import net.minecraft.util.MathHelper; +@@ -70,12 +71,14 @@ public abstract class EntitySkeletonAbstract extends EntityMonster implements IR + + @Override + protected void initPathfinder() { ++ this.goalSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.goalSelector.a(2, new PathfinderGoalRestrictSun(this)); + this.goalSelector.a(3, new PathfinderGoalFleeSun(this, 1.0D)); + this.goalSelector.a(3, new PathfinderGoalAvoidTarget<>(this, EntityWolf.class, 6.0F, 1.0D, 1.2D)); + this.goalSelector.a(5, new PathfinderGoalRandomStrollLand(this, 1.0D)); + this.goalSelector.a(6, new PathfinderGoalLookAtPlayer(this, EntityHuman.class, 8.0F)); + this.goalSelector.a(6, new PathfinderGoalRandomLookaround(this)); ++ this.targetSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.targetSelector.a(1, new PathfinderGoalHurtByTarget(this, new Class[0])); + this.targetSelector.a(2, new PathfinderGoalNearestAttackableTarget<>(this, EntityHuman.class, true)); + this.targetSelector.a(3, new PathfinderGoalNearestAttackableTarget<>(this, EntityIronGolem.class, true)); +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntitySkeletonStray.java b/src/main/java/net/minecraft/world/entity/monster/EntitySkeletonStray.java +index 8481b8fffed3f1f60e2e72e115e79e9ae1aaa635..8484000a1b0d9c252d6fab205b1e316e3f6f33bd 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntitySkeletonStray.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntitySkeletonStray.java +@@ -21,6 +21,18 @@ public class EntitySkeletonStray extends EntitySkeletonAbstract { + super(entitytypes, world); + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.strayRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.strayRidableInWater; ++ } ++ // Purpur end ++ + public static boolean a(EntityTypes entitytypes, WorldAccess worldaccess, EnumMobSpawn enummobspawn, BlockPosition blockposition, Random random) { + return b(entitytypes, worldaccess, enummobspawn, blockposition, random) && (enummobspawn == EnumMobSpawn.SPAWNER || worldaccess.e(blockposition)); + } +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntitySkeletonWither.java b/src/main/java/net/minecraft/world/entity/monster/EntitySkeletonWither.java +index a90ac635ef7aef5289d21f948db7b170b23160d3..cb52c4e63ac487d55dc16accca6976f44f904112 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntitySkeletonWither.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntitySkeletonWither.java +@@ -34,6 +34,18 @@ public class EntitySkeletonWither extends EntitySkeletonAbstract { + this.a(PathType.LAVA, 8.0F); + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.witherSkeletonRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.witherSkeletonRidableInWater; ++ } ++ // Purpur end ++ + @Override + protected void initPathfinder() { + this.targetSelector.a(3, new PathfinderGoalNearestAttackableTarget<>(this, EntityPiglinAbstract.class, true)); +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntitySlime.java b/src/main/java/net/minecraft/world/entity/monster/EntitySlime.java +index 0af0b232ff1b6f1d58cf3fb543d32bd108be0af7..feb40c2ca8e8f3fae5665b2d71296a6b811b11f6 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntitySlime.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntitySlime.java +@@ -14,6 +14,7 @@ import net.minecraft.network.syncher.DataWatcher; + import net.minecraft.network.syncher.DataWatcherObject; + import net.minecraft.network.syncher.DataWatcherRegistry; + import net.minecraft.resources.MinecraftKey; ++import net.minecraft.server.PathfinderGoalHasRider; + import net.minecraft.sounds.SoundEffect; + import net.minecraft.sounds.SoundEffects; + import net.minecraft.util.MathHelper; +@@ -74,12 +75,45 @@ public class EntitySlime extends EntityInsentient implements IMonster { + this.moveController = new EntitySlime.ControllerMoveSlime(this); + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.slimeRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.slimeRidableInWater; ++ } ++ ++ protected boolean actualJump; ++ ++ @Override ++ public float getJumpHeight() { ++ float height = super.getJumpHeight(); ++ return hasPurpurRider() && actualJump ? height * 1.5F : height; ++ } ++ ++ @Override ++ public boolean onSpacebar() { ++ if (onGround && hasPurpurRider()) { ++ actualJump = true; ++ if (getPurpurRider().getForward() == 0 || getPurpurRider().getStrafe() == 0) { ++ jump(); // jump() here if not moving ++ } ++ } ++ return true; // do not jump() in wasd controller, let vanilla controller handle ++ } ++ // Purpur end ++ + @Override + protected void initPathfinder() { ++ this.goalSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.goalSelector.a(1, new EntitySlime.PathfinderGoalSlimeRandomJump(this)); + this.goalSelector.a(2, new EntitySlime.PathfinderGoalSlimeNearestPlayer(this)); + this.goalSelector.a(3, new EntitySlime.PathfinderGoalSlimeRandomDirection(this)); + this.goalSelector.a(5, new EntitySlime.PathfinderGoalSlimeIdle(this)); ++ this.targetSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.targetSelector.a(1, new PathfinderGoalNearestAttackableTarget<>(this, EntityHuman.class, 10, true, false, (entityliving) -> { + return Math.abs(entityliving.locY() - this.locY()) <= 4.0D; + })); +@@ -365,11 +399,12 @@ public class EntitySlime extends EntityInsentient implements IMonster { + } + + @Override +- protected void jump() { ++ public void jump() { // Purpur - protected -> public + Vec3D vec3d = this.getMot(); + + this.setMot(vec3d.x, (double) this.dJ(), vec3d.z); + this.impulse = true; ++ this.actualJump = false; // Purpur + } + + @Nullable +@@ -538,10 +573,10 @@ public class EntitySlime extends EntityInsentient implements IMonster { + // Paper end + } + +- static class ControllerMoveSlime extends ControllerMove { ++ static class ControllerMoveSlime extends net.pl3x.purpur.controller.ControllerMoveWASD { // Purpur + + private float i; +- private int j; ++ private int j; private int getJumpDelay() { return j; } private void setJumpDelay(int delay) { j = delay; } // Purpur - OBFHELPER + private final EntitySlime k; + private boolean l; + +@@ -563,15 +598,27 @@ public class EntitySlime extends EntityInsentient implements IMonster { + + @Override + public void a() { ++ // Purpur start ++ if (entity.hasPurpurRider()) { ++ tick(entity.getPurpurRider()); ++ if (entity.getForward() != 0 || entity.getStrafe() != 0) { ++ if (getJumpDelay() > 10) { ++ setJumpDelay(6); ++ } ++ } else { ++ setJumpDelay(20); ++ } ++ } else { ++ // Purpur end + this.a.yaw = this.a(this.a.yaw, this.i, 90.0F); + this.a.aC = this.a.yaw; + this.a.aA = this.a.yaw; +- if (this.h != ControllerMove.Operation.MOVE_TO) { ++ } if (!entity.hasPurpurRider() && this.h != ControllerMove.Operation.MOVE_TO) { // Purpur + this.a.t(0.0F); + } else { + this.h = ControllerMove.Operation.WAIT; + if (this.a.isOnGround()) { +- this.a.q((float) (this.e * this.a.b(GenericAttributes.MOVEMENT_SPEED))); ++ this.a.q((float) (this.e * this.a.b(GenericAttributes.MOVEMENT_SPEED) * (entity.hasPurpurRider() && (entity.getPurpurRider().getForward() != 0 || entity.getPurpurRider().getStrafe() != 0) ? 2.0D : 1.0D))); // Purpur + if (this.j-- <= 0) { + this.j = this.k.eJ(); + if (this.l) { +@@ -588,7 +635,7 @@ public class EntitySlime extends EntityInsentient implements IMonster { + this.a.q(0.0F); + } + } else { +- this.a.q((float) (this.e * this.a.b(GenericAttributes.MOVEMENT_SPEED))); ++ this.a.q((float) (this.e * this.a.b(GenericAttributes.MOVEMENT_SPEED) * (entity.hasPurpurRider() && (entity.getPurpurRider().getForward() != 0 || entity.getPurpurRider().getStrafe() != 0) ? 2.0D : 1.0D))); // Purpur + } + + } +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntitySpider.java b/src/main/java/net/minecraft/world/entity/monster/EntitySpider.java +index c7b443623f3dd90741e52216199d8ed90bcea6b3..fbf7c31f57f6dbfac997480eb7db55efc15ef4cc 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntitySpider.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntitySpider.java +@@ -7,6 +7,7 @@ import net.minecraft.nbt.NBTTagCompound; + import net.minecraft.network.syncher.DataWatcher; + import net.minecraft.network.syncher.DataWatcherObject; + import net.minecraft.network.syncher.DataWatcherRegistry; ++import net.minecraft.server.PathfinderGoalHasRider; + import net.minecraft.sounds.SoundEffect; + import net.minecraft.sounds.SoundEffects; + import net.minecraft.world.DifficultyDamageScaler; +@@ -50,14 +51,28 @@ public class EntitySpider extends EntityMonster { + super(entitytypes, world); + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.spiderRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.spiderRidableInWater; ++ } ++ // Purpur end ++ + @Override + protected void initPathfinder() { + this.goalSelector.a(1, new PathfinderGoalFloat(this)); ++ this.goalSelector.a(1, new PathfinderGoalHasRider(this)); // Purpur + this.goalSelector.a(3, new PathfinderGoalLeapAtTarget(this, 0.4F)); + this.goalSelector.a(4, new EntitySpider.PathfinderGoalSpiderMeleeAttack(this)); + this.goalSelector.a(5, new PathfinderGoalRandomStrollLand(this, 0.8D)); + this.goalSelector.a(6, new PathfinderGoalLookAtPlayer(this, EntityHuman.class, 8.0F)); + this.goalSelector.a(6, new PathfinderGoalRandomLookaround(this)); ++ this.targetSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.targetSelector.a(1, new PathfinderGoalHurtByTarget(this, new Class[0])); + this.targetSelector.a(2, new EntitySpider.PathfinderGoalSpiderNearestAttackableTarget<>(this, EntityHuman.class)); + this.targetSelector.a(3, new EntitySpider.PathfinderGoalSpiderNearestAttackableTarget<>(this, EntityIronGolem.class)); +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityStrider.java b/src/main/java/net/minecraft/world/entity/monster/EntityStrider.java +index 5ce50c6fe788fbd6db95f6406bacbf218b7e691c..14dda6743ed9e6f4880bc560f7ba8892d8e84afe 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityStrider.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityStrider.java +@@ -13,6 +13,7 @@ import net.minecraft.nbt.NBTTagCompound; + import net.minecraft.network.syncher.DataWatcher; + import net.minecraft.network.syncher.DataWatcherObject; + import net.minecraft.network.syncher.DataWatcherRegistry; ++import net.minecraft.server.PathfinderGoalHasRider; + import net.minecraft.server.level.WorldServer; + import net.minecraft.sounds.SoundCategory; + import net.minecraft.sounds.SoundEffect; +@@ -94,6 +95,18 @@ public class EntityStrider extends EntityAnimal implements ISteerable, ISaddleab + this.a(PathType.DAMAGE_FIRE, 0.0F); + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.striderRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.striderRidableInWater; ++ } ++ // Purpur end ++ + public static boolean c(EntityTypes entitytypes, GeneratorAccess generatoraccess, EnumMobSpawn enummobspawn, BlockPosition blockposition, Random random) { + BlockPosition.MutableBlockPosition blockposition_mutableblockposition = blockposition.i(); + +@@ -155,6 +168,7 @@ public class EntityStrider extends EntityAnimal implements ISteerable, ISaddleab + @Override + protected void initPathfinder() { + this.bv = new PathfinderGoalPanic(this, 1.65D); ++ this.goalSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.goalSelector.a(1, this.bv); + this.goalSelector.a(2, new PathfinderGoalBreed(this, 1.0D)); + this.bu = new PathfinderGoalTempt(this, 1.4D, false, EntityStrider.bp); +@@ -434,7 +448,7 @@ public class EntityStrider extends EntityAnimal implements ISteerable, ISaddleab + if (!enuminteractionresult.a()) { + ItemStack itemstack = entityhuman.b(enumhand); + +- return itemstack.getItem() == Items.SADDLE ? itemstack.a(entityhuman, (EntityLiving) this, enumhand) : EnumInteractionResult.PASS; ++ return itemstack.getItem() == Items.SADDLE ? itemstack.a(entityhuman, (EntityLiving) this, enumhand) : tryRide(entityhuman, enumhand); // Purpur + } else { + if (flag && !this.isSilent()) { + this.world.playSound((EntityHuman) null, this.locX(), this.locY(), this.locZ(), SoundEffects.ENTITY_STRIDER_EAT, this.getSoundCategory(), 1.0F, 1.0F + (this.random.nextFloat() - this.random.nextFloat()) * 0.2F); +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityVex.java b/src/main/java/net/minecraft/world/entity/monster/EntityVex.java +index 9645d052069957311478a1ceca42ad52f7a9aa0b..5e2114d2321c1542dc892bc7aed07080008cfd20 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityVex.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityVex.java +@@ -7,6 +7,7 @@ import net.minecraft.nbt.NBTTagCompound; + import net.minecraft.network.syncher.DataWatcher; + import net.minecraft.network.syncher.DataWatcherObject; + import net.minecraft.network.syncher.DataWatcherRegistry; ++import net.minecraft.server.PathfinderGoalHasRider; + import net.minecraft.sounds.SoundEffect; + import net.minecraft.sounds.SoundEffects; + import net.minecraft.util.MathHelper; +@@ -54,6 +55,45 @@ public class EntityVex extends EntityMonster { + this.f = 3; + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.vexRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.vexRidableInWater; ++ } ++ ++ @Override ++ public double getMaxY() { ++ return world.purpurConfig.vexMaxY; ++ } ++ ++ @Override ++ public void g(Vec3D vec3d) { ++ super.g(vec3d); ++ if (hasPurpurRider()) { ++ float speed; ++ if (onGround) { ++ speed = (float) getAttributeInstance(GenericAttributes.MOVEMENT_SPEED).getValue() * 0.1F; ++ } else { ++ speed = (float) getAttributeInstance(GenericAttributes.FLYING_SPEED).getValue(); ++ } ++ setSpeed(speed); ++ Vec3D mot = getMot(); ++ move(EnumMoveType.SELF, mot.multiply(speed, 1.0, speed)); ++ setMot(mot.a(0.9D)); ++ } ++ } ++ ++ @Override ++ public boolean b(float f, float f1) { ++ return false; // no fall damage please ++ } ++ // Purpur end ++ + @Override + public void move(EnumMoveType enummovetype, Vec3D vec3d) { + super.move(enummovetype, vec3d); +@@ -62,7 +102,7 @@ public class EntityVex extends EntityMonster { + + @Override + public void tick() { +- this.noclip = true; ++ this.noclip = !hasPurpurRider(); // Purpur + super.tick(); + this.noclip = false; + this.setNoGravity(true); +@@ -77,17 +117,19 @@ public class EntityVex extends EntityMonster { + protected void initPathfinder() { + super.initPathfinder(); + this.goalSelector.a(0, new PathfinderGoalFloat(this)); ++ this.goalSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.goalSelector.a(4, new EntityVex.a()); + this.goalSelector.a(8, new EntityVex.d()); + this.goalSelector.a(9, new PathfinderGoalLookAtPlayer(this, EntityHuman.class, 3.0F, 1.0F)); + this.goalSelector.a(10, new PathfinderGoalLookAtPlayer(this, EntityInsentient.class, 8.0F)); ++ this.targetSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.targetSelector.a(1, (new PathfinderGoalHurtByTarget(this, new Class[]{EntityRaider.class})).a(new Class[0])); // CraftBukkit - decompile error + this.targetSelector.a(2, new EntityVex.b(this)); + this.targetSelector.a(3, new PathfinderGoalNearestAttackableTarget<>(this, EntityHuman.class, true)); + } + + public static AttributeProvider.Builder m() { +- return EntityMonster.eR().a(GenericAttributes.MAX_HEALTH, 14.0D).a(GenericAttributes.ATTACK_DAMAGE, 4.0D); ++ return EntityMonster.eR().a(GenericAttributes.MAX_HEALTH, 14.0D).a(GenericAttributes.ATTACK_DAMAGE, 4.0D).a(GenericAttributes.FLYING_SPEED, 0.6D); // Purpur + } + + @Override +@@ -319,14 +361,14 @@ public class EntityVex extends EntityMonster { + } + } + +- class c extends ControllerMove { ++ class c extends net.pl3x.purpur.controller.ControllerMoveWASDFlying { // Purpur + + public c(EntityVex entityvex) { + super(entityvex); + } + + @Override +- public void a() { ++ public void tick() { // Purpur + if (this.h == ControllerMove.Operation.MOVE_TO) { + Vec3D vec3d = new Vec3D(this.b - EntityVex.this.locX(), this.c - EntityVex.this.locY(), this.d - EntityVex.this.locZ()); + double d0 = vec3d.f(); +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityVindicator.java b/src/main/java/net/minecraft/world/entity/monster/EntityVindicator.java +index fe84d6d2b74b6ae00c4c66682107296a40b69adc..28d345e87f45fa839bc3bd758f79f34aba546db7 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityVindicator.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityVindicator.java +@@ -8,6 +8,7 @@ import javax.annotation.Nullable; + import net.minecraft.nbt.NBTTagCompound; + import net.minecraft.network.chat.ChatMessage; + import net.minecraft.network.chat.IChatBaseComponent; ++import net.minecraft.server.PathfinderGoalHasRider; + import net.minecraft.server.level.WorldServer; + import net.minecraft.sounds.SoundEffect; + import net.minecraft.sounds.SoundEffects; +@@ -59,14 +60,28 @@ public class EntityVindicator extends EntityIllagerAbstract { + super(entitytypes, world); + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.vindicatorRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.vindicatorRidableInWater; ++ } ++ // Purpur end ++ + @Override + protected void initPathfinder() { + super.initPathfinder(); + this.goalSelector.a(0, new PathfinderGoalFloat(this)); ++ this.goalSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.goalSelector.a(1, new EntityVindicator.a(this)); + this.goalSelector.a(2, new EntityIllagerAbstract.b(this)); + this.goalSelector.a(3, new EntityRaider.a(this, 10.0F)); + this.goalSelector.a(4, new EntityVindicator.c(this)); ++ this.targetSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.targetSelector.a(1, (new PathfinderGoalHurtByTarget(this, new Class[]{EntityRaider.class})).a(new Class[0])); // Paper - decompile fix + this.targetSelector.a(2, new PathfinderGoalNearestAttackableTarget<>(this, EntityHuman.class, true)); + this.targetSelector.a(3, new PathfinderGoalNearestAttackableTarget<>(this, EntityVillagerAbstract.class, true)); +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityWitch.java b/src/main/java/net/minecraft/world/entity/monster/EntityWitch.java +index 63fb08e7b4290353e5148d1acb58f091dc5b08be..c4663c5b02363bd1499ce1f3b50027f8aa7c68e7 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityWitch.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityWitch.java +@@ -2,6 +2,7 @@ package net.minecraft.world.entity.monster; + + // Paper start + import com.destroystokyo.paper.event.entity.WitchReadyPotionEvent; ++import net.minecraft.server.PathfinderGoalHasRider; + import org.bukkit.craftbukkit.inventory.CraftItemStack; + import org.bukkit.entity.Witch; + // Paper end +@@ -63,6 +64,18 @@ public class EntityWitch extends EntityRaider implements IRangedEntity { + super(entitytypes, world); + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.witchRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.witchRidableInWater; ++ } ++ // Purpur end ++ + @Override + protected void initPathfinder() { + super.initPathfinder(); +@@ -71,10 +84,12 @@ public class EntityWitch extends EntityRaider implements IRangedEntity { + }); + this.bs = new PathfinderGoalNearestAttackableTargetWitch<>(this, EntityHuman.class, 10, true, false, (Predicate) null); + this.goalSelector.a(1, new PathfinderGoalFloat(this)); ++ this.goalSelector.a(1, new PathfinderGoalHasRider(this)); // Purpur + this.goalSelector.a(2, new PathfinderGoalArrowAttack(this, 1.0D, 60, 10.0F)); + this.goalSelector.a(2, new PathfinderGoalRandomStrollLand(this, 1.0D)); + this.goalSelector.a(3, new PathfinderGoalLookAtPlayer(this, EntityHuman.class, 8.0F)); + this.goalSelector.a(3, new PathfinderGoalRandomLookaround(this)); ++ this.targetSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.targetSelector.a(1, new PathfinderGoalHurtByTarget(this, new Class[]{EntityRaider.class})); + this.targetSelector.a(2, this.br); + this.targetSelector.a(3, this.bs); +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityZoglin.java b/src/main/java/net/minecraft/world/entity/monster/EntityZoglin.java +index aed585e2c1c88a4d09318c6be7ebe7168eac3631..249fb9cf43527af5c7818ce6b07487ad446811b7 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityZoglin.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityZoglin.java +@@ -62,6 +62,18 @@ public class EntityZoglin extends EntityMonster implements IMonster, IOglin { + this.f = 5; + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.zoglinRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.zoglinRidableInWater; ++ } ++ // Purpur end ++ + @Override + protected BehaviorController.b cK() { + return BehaviorController.a((Collection) EntityZoglin.c, (Collection) EntityZoglin.b); +@@ -93,10 +105,10 @@ public class EntityZoglin extends EntityMonster implements IMonster, IOglin { + } + + private Optional eO() { +- return ((List) this.getBehaviorController().getMemory(MemoryModuleType.VISIBLE_MOBS).orElse(ImmutableList.of())).stream().filter(EntityZoglin::i).findFirst(); ++ return (this.getBehaviorController().getMemory(MemoryModuleType.VISIBLE_MOBS).orElse(ImmutableList.of())).stream().filter(EntityZoglin::predicate).findFirst(); // Purpur - decompile error + } + +- private static boolean i(EntityLiving entityliving) { ++ private static boolean predicate(EntityLiving entityliving) { // Purpur - decompile error + EntityTypes entitytypes = entityliving.getEntityType(); + + return entitytypes != EntityTypes.ZOGLIN && entitytypes != EntityTypes.CREEPER && IEntitySelector.f.test(entityliving); +@@ -181,14 +193,14 @@ public class EntityZoglin extends EntityMonster implements IMonster, IOglin { + + @Override + public BehaviorController getBehaviorController() { +- return super.getBehaviorController(); ++ return (BehaviorController) super.getBehaviorController(); // Purpur - decompile error + } + + protected void eL() { +- Activity activity = (Activity) this.bg.f().orElse((Object) null); ++ Activity activity = (Activity) this.bg.f().orElse(null); // Purpur - decompile error + + this.bg.a((List) ImmutableList.of(Activity.FLIGHT, Activity.IDLE)); +- Activity activity1 = (Activity) this.bg.f().orElse((Object) null); ++ Activity activity1 = (Activity) this.bg.f().orElse(null); // Purpur - decompile error + + if (activity1 == Activity.FLIGHT && activity != Activity.FLIGHT) { + this.eN(); +@@ -200,7 +212,8 @@ public class EntityZoglin extends EntityMonster implements IMonster, IOglin { + @Override + protected void mobTick() { + this.world.getMethodProfiler().enter("zoglinBrain"); +- this.getBehaviorController().a((WorldServer) this.world, (EntityLiving) this); ++ if (getPurpurRider() == null) // Purpur - only use brain if no rider ++ this.getBehaviorController().a((WorldServer) this.world, this); // Purpur - decompile error + this.world.getMethodProfiler().exit(); + this.eL(); + } +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityZombie.java b/src/main/java/net/minecraft/world/entity/monster/EntityZombie.java +index 5ac950614fc90d02a568bb38f71faee124584c16..901fe8d224130c67bad00636b065bc798859a18e 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityZombie.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityZombie.java +@@ -16,6 +16,7 @@ import net.minecraft.nbt.NBTTagCompound; + import net.minecraft.network.syncher.DataWatcher; + import net.minecraft.network.syncher.DataWatcherObject; + import net.minecraft.network.syncher.DataWatcherRegistry; ++import net.minecraft.server.PathfinderGoalHasRider; + import net.minecraft.server.level.WorldServer; + import net.minecraft.sounds.SoundCategory; + import net.minecraft.sounds.SoundEffect; +@@ -108,6 +109,16 @@ public class EntityZombie extends EntityMonster { + } + + // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.zombieRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.zombieRidableInWater; ++ } ++ + public boolean jockeyOnlyBaby() { + return world.purpurConfig.zombieJockeyOnlyBaby; + } +@@ -123,9 +134,11 @@ public class EntityZombie extends EntityMonster { + + @Override + protected void initPathfinder() { ++ this.goalSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + if (world.paperConfig.zombiesTargetTurtleEggs) this.goalSelector.a(4, new EntityZombie.a(this, 1.0D, 3)); // Paper + this.goalSelector.a(8, new PathfinderGoalLookAtPlayer(this, EntityHuman.class, 8.0F)); + this.goalSelector.a(8, new PathfinderGoalRandomLookaround(this)); ++ this.targetSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.m(); + } + +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityZombieHusk.java b/src/main/java/net/minecraft/world/entity/monster/EntityZombieHusk.java +index 5d3e5873f19aaf8389eb5525693b9378ea9f94ee..ad801fc394fbb83cf280ee96f962e7f311615d72 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityZombieHusk.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityZombieHusk.java +@@ -23,6 +23,16 @@ public class EntityZombieHusk extends EntityZombie { + } + + // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.huskRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.huskRidableInWater; ++ } ++ + @Override + public boolean jockeyOnlyBaby() { + return world.purpurConfig.huskJockeyOnlyBaby; +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityZombieVillager.java b/src/main/java/net/minecraft/world/entity/monster/EntityZombieVillager.java +index 99d0932e5352589cfbcc48a5e789651d0d77edde..b8395c7317494adf36010080931a1c8635ab6cfa 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityZombieVillager.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityZombieVillager.java +@@ -71,6 +71,16 @@ public class EntityZombieVillager extends EntityZombie implements VillagerDataHo + } + + // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.zombieVillagerRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.zombieVillagerRidableInWater; ++ } ++ + @Override + public boolean jockeyOnlyBaby() { + return world.purpurConfig.zombieVillagerJockeyOnlyBaby; +diff --git a/src/main/java/net/minecraft/world/entity/monster/hoglin/EntityHoglin.java b/src/main/java/net/minecraft/world/entity/monster/hoglin/EntityHoglin.java +index 375409f4b72edc7990da90460b30486fb2980fb6..9bac45983b55abf9b72f2c45f632cdedd48f81f9 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/hoglin/EntityHoglin.java ++++ b/src/main/java/net/minecraft/world/entity/monster/hoglin/EntityHoglin.java +@@ -54,13 +54,25 @@ public class EntityHoglin extends EntityAnimal implements IMonster, IOglin { + public int conversionTicks = 0; + public boolean cannotBeHunted = false; + protected static final ImmutableList>> bo = ImmutableList.of(SensorType.c, SensorType.d, SensorType.n, SensorType.m); +- protected static final ImmutableList> bp = ImmutableList.of(MemoryModuleType.BREED_TARGET, MemoryModuleType.MOBS, MemoryModuleType.VISIBLE_MOBS, MemoryModuleType.NEAREST_VISIBLE_PLAYER, MemoryModuleType.NEAREST_VISIBLE_TARGETABLE_PLAYER, MemoryModuleType.LOOK_TARGET, MemoryModuleType.WALK_TARGET, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE, MemoryModuleType.PATH, MemoryModuleType.ATTACK_TARGET, MemoryModuleType.ATTACK_COOLING_DOWN, MemoryModuleType.NEAREST_VISIBLE_ADULT_PIGLIN, new MemoryModuleType[]{MemoryModuleType.AVOID_TARGET, MemoryModuleType.VISIBLE_ADULT_PIGLIN_COUNT, MemoryModuleType.VISIBLE_ADULT_HOGLIN_COUNT, MemoryModuleType.NEAREST_VISIBLE_ADULT_HOGLINS, MemoryModuleType.NEAREST_VISIBLE_ADULY, MemoryModuleType.NEAREST_REPELLENT, MemoryModuleType.PACIFIED}); ++ protected static final ImmutableList bp = ImmutableList.of(MemoryModuleType.BREED_TARGET, MemoryModuleType.MOBS, MemoryModuleType.VISIBLE_MOBS, MemoryModuleType.NEAREST_VISIBLE_PLAYER, MemoryModuleType.NEAREST_VISIBLE_TARGETABLE_PLAYER, MemoryModuleType.LOOK_TARGET, MemoryModuleType.WALK_TARGET, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE, MemoryModuleType.PATH, MemoryModuleType.ATTACK_TARGET, MemoryModuleType.ATTACK_COOLING_DOWN, MemoryModuleType.NEAREST_VISIBLE_ADULT_PIGLIN, new MemoryModuleType[]{MemoryModuleType.AVOID_TARGET, MemoryModuleType.VISIBLE_ADULT_PIGLIN_COUNT, MemoryModuleType.VISIBLE_ADULT_HOGLIN_COUNT, MemoryModuleType.NEAREST_VISIBLE_ADULT_HOGLINS, MemoryModuleType.NEAREST_VISIBLE_ADULY, MemoryModuleType.NEAREST_REPELLENT, MemoryModuleType.PACIFIED}); // Purpur - decompile error + + public EntityHoglin(EntityTypes entitytypes, World world) { + super(entitytypes, world); + this.f = 5; + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.hoglinRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.hoglinRidableInWater; ++ } ++ // Purpur end ++ + @Override + public boolean a(EntityHuman entityhuman) { + return !this.isLeashed(); +@@ -118,13 +130,14 @@ public class EntityHoglin extends EntityAnimal implements IMonster, IOglin { + + @Override + public BehaviorController getBehaviorController() { +- return super.getBehaviorController(); ++ return (BehaviorController) super.getBehaviorController(); // Purpur decompile error + } + + @Override + protected void mobTick() { + this.world.getMethodProfiler().enter("hoglinBrain"); +- this.getBehaviorController().a((WorldServer) this.world, (EntityLiving) this); ++ if (getPurpurRider() == null) // Purpur - only use brain if no rider ++ this.getBehaviorController().a((WorldServer) this.world, this); // Purpour - decompile error + this.world.getMethodProfiler().exit(); + HoglinAI.a(this); + if (this.isConverting()) { +@@ -300,7 +313,7 @@ public class EntityHoglin extends EntityAnimal implements IMonster, IOglin { + + @Override + protected SoundEffect getSoundAmbient() { +- return this.world.isClientSide ? null : (SoundEffect) HoglinAI.b(this).orElse((Object) null); ++ return this.world.isClientSide ? null : (SoundEffect) HoglinAI.b(this).orElse(null); // Purpur - decompile error + } + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/monster/piglin/EntityPiglin.java b/src/main/java/net/minecraft/world/entity/monster/piglin/EntityPiglin.java +index 9a7bebd77302dbfd07ac802acbe2b9cb80eec26f..edac17b1072102abe322d69072c4277e6c21cfbe 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/piglin/EntityPiglin.java ++++ b/src/main/java/net/minecraft/world/entity/monster/piglin/EntityPiglin.java +@@ -86,6 +86,18 @@ public class EntityPiglin extends EntityPiglinAbstract implements ICrossbow { + this.f = 5; + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.piglinRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.piglinRidableInWater; ++ } ++ // Purpur end ++ + @Override + public void saveData(NBTTagCompound nbttagcompound) { + super.saveData(nbttagcompound); +@@ -275,6 +287,7 @@ public class EntityPiglin extends EntityPiglinAbstract implements ICrossbow { + @Override + protected void mobTick() { + this.world.getMethodProfiler().enter("piglinBrain"); ++ if (getPurpurRider() == null) // Purpur - only use brain if no rider + this.getBehaviorController().a((WorldServer) this.world, (EntityPiglin) this); // CraftBukkit - decompile error + this.world.getMethodProfiler().exit(); + PiglinAI.b(this); +diff --git a/src/main/java/net/minecraft/world/entity/monster/piglin/EntityPiglinBrute.java b/src/main/java/net/minecraft/world/entity/monster/piglin/EntityPiglinBrute.java +index 3d85501791fce621335f34bf508becb74b80210d..1370d2d8568a4ed62f2ec3d54abc7d2bebc48f75 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/piglin/EntityPiglinBrute.java ++++ b/src/main/java/net/minecraft/world/entity/monster/piglin/EntityPiglinBrute.java +@@ -39,6 +39,18 @@ public class EntityPiglinBrute extends EntityPiglinAbstract { + this.f = 20; + } + ++ // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.piglinBruteRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.piglinBruteRidableInWater; ++ } ++ // Purpur end ++ + public static AttributeProvider.Builder eS() { + return EntityMonster.eR().a(GenericAttributes.MAX_HEALTH, 50.0D).a(GenericAttributes.MOVEMENT_SPEED, 0.3499999940395355D).a(GenericAttributes.ATTACK_DAMAGE, 7.0D); + } +@@ -68,7 +80,7 @@ public class EntityPiglinBrute extends EntityPiglinAbstract { + + @Override + public BehaviorController getBehaviorController() { +- return super.getBehaviorController(); ++ return (BehaviorController) super.getBehaviorController(); // Purpur - decompile error + } + + @Override +@@ -84,7 +96,8 @@ public class EntityPiglinBrute extends EntityPiglinAbstract { + @Override + protected void mobTick() { + this.world.getMethodProfiler().enter("piglinBruteBrain"); +- this.getBehaviorController().a((WorldServer) this.world, (EntityLiving) this); ++ if (getPurpurRider() == null) // Purpur - only use brain if no rider ++ this.getBehaviorController().a((WorldServer) this.world, this); // Purpur - decompile error + this.world.getMethodProfiler().exit(); + PiglinBruteAI.b(this); + PiglinBruteAI.c(this); +diff --git a/src/main/java/net/minecraft/world/entity/npc/EntityVillager.java b/src/main/java/net/minecraft/world/entity/npc/EntityVillager.java +index 2ff9dffc0f0b20582f5b3bffd01743ee26c63c20..85242947bd115f63f8807e1d4e6784fff537e802 100644 +--- a/src/main/java/net/minecraft/world/entity/npc/EntityVillager.java ++++ b/src/main/java/net/minecraft/world/entity/npc/EntityVillager.java +@@ -32,6 +32,7 @@ import net.minecraft.network.syncher.DataWatcherObject; + import net.minecraft.network.syncher.DataWatcherRegistry; + import net.minecraft.server.MCUtil; + import net.minecraft.server.MinecraftServer; ++import net.minecraft.server.PathfinderGoalHasRider; + import net.minecraft.server.level.WorldServer; + import net.minecraft.sounds.SoundEffect; + import net.minecraft.sounds.SoundEffects; +@@ -145,8 +146,19 @@ public class EntityVillager extends EntityVillagerAbstract implements Reputation + } + + // Purpur start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.villagerRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.villagerRidableInWater; ++ } ++ + @Override + protected void initPathfinder() { ++ this.goalSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + if (world.purpurConfig.villagerFollowEmeraldBlock) this.goalSelector.a(3, new PathfinderGoalTempt(this, 1.0D, false, TEMPT_ITEMS)); + } + +@@ -311,7 +323,7 @@ public class EntityVillager extends EntityVillagerAbstract implements Reputation + if (itemstack.getItem() != Items.VILLAGER_SPAWN_EGG && this.isAlive() && !this.eN() && !this.isSleeping()) { + if (this.isBaby()) { + this.fk(); +- return EnumInteractionResult.a(this.world.isClientSide); ++ return super.b(entityhuman, enumhand); // Purpur + } else { + boolean flag = this.getOffers().isEmpty(); + +@@ -324,8 +336,9 @@ public class EntityVillager extends EntityVillagerAbstract implements Reputation + } + + if (flag) { +- return EnumInteractionResult.a(this.world.isClientSide); ++ return tryRide(entityhuman, enumhand); // Purpur + } else { ++ if (world.purpurConfig.villagerRidable && itemstack.isEmpty()) return tryRide(entityhuman, enumhand); // Purpur + if (!this.world.isClientSide && !this.trades.isEmpty()) { + this.h(entityhuman); + } +diff --git a/src/main/java/net/minecraft/world/entity/npc/EntityVillagerTrader.java b/src/main/java/net/minecraft/world/entity/npc/EntityVillagerTrader.java +index 8df4d985e3124ddc1643da8385b15348937bc320..6c390fb20c7f29133a60780a75676d8d3d6eab29 100644 +--- a/src/main/java/net/minecraft/world/entity/npc/EntityVillagerTrader.java ++++ b/src/main/java/net/minecraft/world/entity/npc/EntityVillagerTrader.java +@@ -6,6 +6,7 @@ import net.minecraft.core.BlockPosition; + import net.minecraft.core.IPosition; + import net.minecraft.nbt.GameProfileSerializer; + import net.minecraft.nbt.NBTTagCompound; ++import net.minecraft.server.PathfinderGoalHasRider; + import net.minecraft.server.level.WorldServer; + import net.minecraft.sounds.SoundEffect; + import net.minecraft.sounds.SoundEffects; +@@ -73,6 +74,7 @@ public class EntityVillagerTrader extends EntityVillagerAbstract { + @Override + protected void initPathfinder() { + this.goalSelector.a(0, new PathfinderGoalFloat(this)); ++ this.goalSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.goalSelector.a(0, new PathfinderGoalUseItem<>(this, PotionUtil.a(new ItemStack(Items.POTION), Potions.INVISIBILITY), SoundEffects.ENTITY_WANDERING_TRADER_DISAPPEARED, (entityvillagertrader) -> { + return canDrinkPotion && this.world.isNight() && !entityvillagertrader.isInvisible(); // Paper - Add more WanderingTrader API + })); +@@ -98,6 +100,16 @@ public class EntityVillagerTrader extends EntityVillagerAbstract { + } + + // Purpur - start ++ @Override ++ public boolean isRidable() { ++ return world.purpurConfig.villagerTraderRidable; ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return world.purpurConfig.villagerTraderRidableInWater; ++ } ++ + @Override + public boolean a(EntityHuman entityhuman) { + return world.purpurConfig.villagerTraderCanBeLeashed && !this.isLeashed(); +@@ -125,8 +137,9 @@ public class EntityVillagerTrader extends EntityVillagerAbstract { + } + + if (this.getOffers().isEmpty()) { +- return EnumInteractionResult.a(this.world.isClientSide); ++ return tryRide(entityhuman, enumhand); // Purpur + } else { ++ if (world.purpurConfig.villagerTraderRidable && itemstack.isEmpty()) return tryRide(entityhuman, enumhand); // Purpur + if (!this.world.isClientSide) { + this.setTradingPlayer(entityhuman); + this.openTrade(entityhuman, this.getScoreboardDisplayName(), 1); +diff --git a/src/main/java/net/minecraft/world/entity/player/EntityHuman.java b/src/main/java/net/minecraft/world/entity/player/EntityHuman.java +index f9ce15aa4a2b1ee07f9c31b793410a4ff27ec829..ba8add51b86fc8a6417c1a9ac7a97ac605a9939b 100644 +--- a/src/main/java/net/minecraft/world/entity/player/EntityHuman.java ++++ b/src/main/java/net/minecraft/world/entity/player/EntityHuman.java +@@ -111,7 +111,6 @@ import net.minecraft.world.phys.AxisAlignedBB; + import net.minecraft.world.phys.Vec3D; + import net.minecraft.world.scores.Scoreboard; + import net.minecraft.world.scores.ScoreboardTeam; +-import net.minecraft.world.scores.ScoreboardTeamBase; + + // CraftBukkit start + import org.bukkit.craftbukkit.entity.CraftHumanEntity; +@@ -182,6 +181,8 @@ public abstract class EntityHuman extends EntityLiving { + // CraftBukkit end + + // Purpur start ++ public abstract void resetIdleTimer(); ++ + private javax.script.ScriptEngine scriptEngine = new javax.script.ScriptEngineManager().getEngineByName("rhino"); + + public void setAfk(boolean setAfk){ +@@ -2265,4 +2266,15 @@ public abstract class EntityHuman extends EntityLiving { + return this.g; + } + } ++ ++ // Purpur start ++ @Override ++ public boolean processClick(EnumHand hand) { ++ Entity vehicle = getRootVehicle(); ++ if (vehicle != null && vehicle.getPurpurRider() == this) { ++ return vehicle.onClick(hand); ++ } ++ return false; ++ } ++ // Purpur end + } +diff --git a/src/main/java/net/minecraft/world/entity/projectile/IProjectile.java b/src/main/java/net/minecraft/world/entity/projectile/IProjectile.java +index 8fe98404ebb8b3b5d1fdac0896b27da10736026d..390023a7a825eed850a13572b719f47ed534c003 100644 +--- a/src/main/java/net/minecraft/world/entity/projectile/IProjectile.java ++++ b/src/main/java/net/minecraft/world/entity/projectile/IProjectile.java +@@ -24,7 +24,7 @@ public abstract class IProjectile extends Entity { + + private UUID shooter; + private int c; +- private boolean d; ++ private boolean d; public boolean leftOwner() { return d; } public void setLeftOwner(boolean leftOwner) { this.d = leftOwner; } // Purpur - OBFHELPER + + // CraftBukkit start + private boolean hitCancelled = false; +@@ -90,6 +90,7 @@ public abstract class IProjectile extends Entity { + super.tick(); + } + ++ public boolean checkIfLeftOwner() { return this.h(); } // Purpur - OBFHELPER + private boolean h() { + Entity entity = this.getShooter(); + +@@ -167,7 +168,7 @@ public abstract class IProjectile extends Entity { + iblockdata.a(this.world, iblockdata, movingobjectpositionblock, this); + } + +- protected boolean a(Entity entity) { ++ protected boolean a(Entity entity) { return hitPredicate(entity); } public boolean hitPredicate(Entity entity) { // Purpur - OBFHELPER + if (!entity.isSpectator() && entity.isAlive() && entity.isInteractable()) { + Entity entity1 = this.getShooter(); + // Paper start - Cancel hit for vanished players +diff --git a/src/main/java/net/minecraft/world/entity/projectile/ProjectileHelper.java b/src/main/java/net/minecraft/world/entity/projectile/ProjectileHelper.java +index 75889ac851d1c2b26c0b57bea6b75c1b65c2309f..80834537eba8bd33a0688e19d0aa9b963de4398a 100644 +--- a/src/main/java/net/minecraft/world/entity/projectile/ProjectileHelper.java ++++ b/src/main/java/net/minecraft/world/entity/projectile/ProjectileHelper.java +@@ -21,6 +21,7 @@ import net.minecraft.world.phys.Vec3D; + + public final class ProjectileHelper { + ++ public static MovingObjectPosition getHitResult(Entity entity, Predicate predicate) { return a(entity, predicate); } // Purpur - OBFHELPER + public static MovingObjectPosition a(Entity entity, Predicate predicate) { + Vec3D vec3d = entity.getMot(); + World world = entity.world; +diff --git a/src/main/java/net/minecraft/world/level/GeneratorAccess.java b/src/main/java/net/minecraft/world/level/GeneratorAccess.java +index 96efd974f1eb9c1e7c70e576e51ed69e15aacb99..fc86ef53c48503139667f7703019a07c40814fd4 100644 +--- a/src/main/java/net/minecraft/world/level/GeneratorAccess.java ++++ b/src/main/java/net/minecraft/world/level/GeneratorAccess.java +@@ -48,6 +48,7 @@ public interface GeneratorAccess extends ICombinedAccess, IWorldTime { + + void addParticle(ParticleParam particleparam, double d0, double d1, double d2, double d3, double d4, double d5); + ++ default void playEvent(@Nullable EntityHuman entityhuman, int i, BlockPosition blockposition, int j) { a(entityhuman, i, blockposition, j); } // Purpur - OBFHELPER + void a(@Nullable EntityHuman entityhuman, int i, BlockPosition blockposition, int j); + + default int getHeight() { +diff --git a/src/main/java/net/minecraft/world/level/World.java b/src/main/java/net/minecraft/world/level/World.java +index 137583da4926ce85d258fce98c919618d02a5f77..b6b4e759975776afcb9d33e650774b9e30d7eb96 100644 +--- a/src/main/java/net/minecraft/world/level/World.java ++++ b/src/main/java/net/minecraft/world/level/World.java +@@ -1748,5 +1748,10 @@ public abstract class World implements GeneratorAccess, AutoCloseable { + public boolean isTheEnd() { + return getWorld().getEnvironment() == org.bukkit.World.Environment.THE_END; + } ++ ++ // Purpur start ++ public void playEffect(@Nullable EntityHuman entityhuman, int i, BlockPosition blockposition, int j) { ++ this.a(entityhuman, i, blockposition, j); ++ } + // Purpur end + } +diff --git a/src/main/java/net/minecraft/world/phys/Vec3D.java b/src/main/java/net/minecraft/world/phys/Vec3D.java +index a19a26a88f247d359354902efeece9923f3e0e0b..1119f60890784d953c2cd4e0078af4d04d10d557 100644 +--- a/src/main/java/net/minecraft/world/phys/Vec3D.java ++++ b/src/main/java/net/minecraft/world/phys/Vec3D.java +@@ -50,6 +50,7 @@ public class Vec3D implements IPosition { + return new Vec3D(vec3d.x - this.x, vec3d.y - this.y, vec3d.z - this.z); + } + ++ public Vec3D normalize() { return d(); } // Purpur - OBFHELPER + public Vec3D d() { + double d0 = (double) MathHelper.sqrt(this.x * this.x + this.y * this.y + this.z * this.z); + +@@ -109,6 +110,7 @@ public class Vec3D implements IPosition { + return d3 * d3 + d4 * d4 + d5 * d5; + } + ++ public Vec3D scale(double scale) { return a(scale); } // Purpur - OBFHELPER + public Vec3D a(double d0) { + return this.d(d0, d0, d0); + } +@@ -117,6 +119,7 @@ public class Vec3D implements IPosition { + return this.d(vec3d.x, vec3d.y, vec3d.z); + } + ++ public Vec3D multiply (double x, double y, double z) { return d(x, y, z); } // Purpur - OBFHELPER + public Vec3D d(double d0, double d1, double d2) { + return new Vec3D(this.x * d0, this.y * d1, this.z * d2); + } +diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java +index fc458beb3afcb9083b994246454c6ee3d94c80ac..65f436e0a27c8687180d7008dbff1cf8f667383c 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java +@@ -137,11 +137,13 @@ public class PurpurConfig { + public static String afkBroadcastBack = "§e§o%s is no longer AFK"; + public static String afkTabListPrefix = "[AFK] "; + public static String pingCommandOutput = "§a%s's ping is %sms"; ++ public static String cannotRideMob = "§cYou cannot mount that mob"; + private static void messages() { + afkBroadcastAway = getString("settings.messages.afk-broadcast-away", afkBroadcastAway); + afkBroadcastBack = getString("settings.messages.afk-broadcast-back", afkBroadcastBack); + afkTabListPrefix = getString("settings.messages.afk-tab-list-prefix", afkTabListPrefix); + pingCommandOutput = getString("settings.messages.ping-command-output", pingCommandOutput); ++ cannotRideMob = getString("settings.messages.cannot-ride-mob", cannotRideMob); + } + + public static int dungeonSeed = -1; +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index f16f99517999ccbb0b5a678ffcb3befc93a3ae45..9fcc63a2f4a4c363ace85087665bf3a978d3d648 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -42,11 +42,6 @@ public class PurpurWorldConfig { + } + } + +- public double vindicatorJohnnySpawnChance = 0D; +- private void vindicatorSettings() { +- vindicatorJohnnySpawnChance = getDouble("mobs.vindicator.johnny.spawn-chance", vindicatorJohnnySpawnChance); +- } +- + private ConfigurationSection getConfigurationSection(String path) { + ConfigurationSection section = PurpurConfig.config.getConfigurationSection("world-settings." + worldName + "." + path); + return section != null ? section : PurpurConfig.config.getConfigurationSection("world-settings.default." + path); +@@ -385,61 +380,186 @@ public class PurpurWorldConfig { + turtleEggsBreakFromMinecarts = getBoolean("blocks.turtle_egg.break-from-minecarts", turtleEggsBreakFromMinecarts); + } + ++ public boolean babiesAreRidable = true; ++ public boolean untamedTamablesAreRidable = true; ++ public boolean useNightVisionWhenRiding = false; ++ private void ridableSettings() { ++ babiesAreRidable = getBoolean("ridable-settings.babies-are-ridable", babiesAreRidable); ++ untamedTamablesAreRidable = getBoolean("ridable-settings.untamed-tamables-are-ridable", untamedTamablesAreRidable); ++ useNightVisionWhenRiding = getBoolean("ridable-settings.use-night-vision", useNightVisionWhenRiding); ++ } ++ ++ public boolean batRidable = false; ++ public boolean batRidableInWater = false; ++ public double batMaxY = 256D; ++ private void batSettings() { ++ batRidable = getBoolean("mobs.bat.ridable", batRidable); ++ batRidableInWater = getBoolean("mobs.bat.ridable-in-water", batRidableInWater); ++ batMaxY = getDouble("mobs.bat.ridable-max-y", batMaxY); ++ } ++ ++ public boolean beeRidable = false; ++ public boolean beeRidableInWater = false; ++ public double beeMaxY = 256D; ++ private void beeSettings() { ++ beeRidable = getBoolean("mobs.bee.ridable", beeRidable); ++ beeRidableInWater = getBoolean("mobs.bee.ridable-in-water", beeRidableInWater); ++ beeMaxY = getDouble("mobs.bee.ridable-max-y", beeMaxY); ++ } ++ ++ public boolean blazeRidable = false; ++ public boolean blazeRidableInWater = false; ++ public double blazeMaxY = 256D; ++ private void blazeSettings() { ++ blazeRidable = getBoolean("mobs.blaze.ridable", blazeRidable); ++ blazeRidableInWater = getBoolean("mobs.blaze.ridable-in-water", blazeRidableInWater); ++ blazeMaxY = getDouble("mobs.blaze.ridable-max-y", blazeMaxY); ++ } ++ ++ public boolean catRidable = false; ++ public boolean catRidableInWater = false; + public int catSpawnDelay = 1200; + public int catSpawnSwampHutScanRange = 16; + public int catSpawnVillageScanRange = 48; + private void catSettings() { ++ catRidable = getBoolean("mobs.cat.ridable", catRidable); ++ catRidableInWater = getBoolean("mobs.cat.ridable-in-water", catRidableInWater); + catSpawnDelay = getInt("mobs.cat.spawn-delay", catSpawnDelay); + catSpawnSwampHutScanRange = getInt("mobs.cat.scan-range-for-other-cats.swamp-hut", catSpawnSwampHutScanRange); + catSpawnVillageScanRange = getInt("mobs.cat.scan-range-for-other-cats.village", catSpawnVillageScanRange); + } + ++ public boolean caveSpiderRidable = false; ++ public boolean caveSpiderRidableInWater = false; ++ private void caveSpiderSettings() { ++ caveSpiderRidable = getBoolean("mobs.cave_spider.ridable", caveSpiderRidable); ++ caveSpiderRidableInWater = getBoolean("mobs.cave_spider.ridable-in-water", caveSpiderRidableInWater); ++ } ++ ++ public boolean chickenRidable = false; ++ public boolean chickenRidableInWater = false; + public boolean chickenRetaliate = false; + private void chickenSettings() { ++ chickenRidable = getBoolean("mobs.chicken.ridable", chickenRidable); ++ chickenRidableInWater = getBoolean("mobs.chicken.ridable-in-water", chickenRidableInWater); + chickenRetaliate = getBoolean("mobs.chicken.retaliate", chickenRetaliate); + } + ++ public boolean codRidable = false; ++ private void codSettings() { ++ codRidable = getBoolean("mobs.cod.ridable", codRidable); ++ } ++ ++ public boolean cowRidable = false; ++ public boolean cowRidableInWater = false; + public int cowFeedMushrooms = 0; + private void cowSettings() { ++ cowRidable = getBoolean("mobs.cow.ridable", cowRidable); ++ cowRidableInWater = getBoolean("mobs.cow.ridable-in-water", cowRidableInWater); + cowFeedMushrooms = getInt("mobs.cow.feed-mushrooms-for-mooshroom", cowFeedMushrooms); + } + ++ public boolean creeperRidable = false; ++ public boolean creeperRidableInWater = false; + public boolean creeperAllowGriefing = true; + public double creeperChargedChance = 0.0D; + private void creeperSettings() { ++ creeperRidable = getBoolean("mobs.creeper.ridable", creeperRidable); ++ creeperRidableInWater = getBoolean("mobs.creeper.ridable-in-water", creeperRidableInWater); + creeperAllowGriefing = getBoolean("mobs.creeper.allow-griefing", creeperAllowGriefing); + creeperChargedChance = getDouble("mobs.creeper.naturally-charged-chance", creeperChargedChance); + } + ++ public boolean dolphinRidable = false; ++ public int dolphinSpitCooldown = 20; ++ public float dolphinSpitSpeed = 1.0F; ++ public float dolphinSpitDamage = 2.0F; + public boolean dolphinDisableTreasureSearching = false; + private void dolphinSettings() { ++ dolphinRidable = getBoolean("mobs.dolphin.ridable", dolphinRidable); ++ dolphinSpitCooldown = getInt("mobs.dolphin.spit.cooldown", dolphinSpitCooldown); ++ dolphinSpitSpeed = (float) getDouble("mobs.dolphin.spit.speed", dolphinSpitSpeed); ++ dolphinSpitDamage = (float) getDouble("mobs.dolphin.spit.damage", dolphinSpitDamage); + dolphinDisableTreasureSearching = getBoolean("mobs.dolphin.disable-treasure-searching", dolphinDisableTreasureSearching); + } + ++ public boolean donkeyRidableInWater = false; ++ private void donkeySettings() { ++ donkeyRidableInWater = getBoolean("mobs.donkey.ridable-in-water", donkeyRidableInWater); ++ } ++ ++ public boolean drownedRidable = false; ++ public boolean drownedRidableInWater = false; + public boolean drownedJockeyOnlyBaby = true; + public double drownedJockeyChance = 0.05D; + public boolean drownedJockeyTryExistingChickens = true; + private void drownedSettings() { ++ drownedRidable = getBoolean("mobs.drowned.ridable", drownedRidable); ++ drownedRidableInWater = getBoolean("mobs.drowned.ridable-in-water", drownedRidableInWater); + drownedJockeyOnlyBaby = getBoolean("mobs.drowned.jockey.only-babies", drownedJockeyOnlyBaby); + drownedJockeyChance = getDouble("mobs.drowned.jockey.chance", drownedJockeyChance); + drownedJockeyTryExistingChickens = getBoolean("mobs.drowned.jockey.try-existing-chickens", drownedJockeyTryExistingChickens); + } + ++ public boolean elderGuardianRidable = false; ++ private void elderGuardianSettings() { ++ elderGuardianRidable = getBoolean("mobs.elder_guardian.ridable", elderGuardianRidable); ++ } ++ ++ public boolean enderDragonRidable = false; ++ public boolean enderDragonRidableInWater = false; ++ public double enderDragonMaxY = 256D; + public boolean enderDragonAlwaysDropsFullExp = false; + private void enderDragonSettings() { ++ enderDragonRidable = getBoolean("mobs.ender_dragon.ridable", enderDragonRidable); ++ enderDragonRidableInWater = getBoolean("mobs.ender_dragon.ridable-in-water", enderDragonRidableInWater); ++ enderDragonMaxY = getDouble("mobs.ender_dragon.ridable-max-y", enderDragonMaxY); + enderDragonAlwaysDropsFullExp = getBoolean("mobs.ender_dragon.always-drop-full-exp", enderDragonAlwaysDropsFullExp); + } + ++ public boolean endermanRidable = false; ++ public boolean endermanRidableInWater = false; + public boolean endermanAllowGriefing = true; + private void endermanSettings() { ++ endermanRidable = getBoolean("mobs.enderman.ridable", endermanRidable); ++ endermanRidableInWater = getBoolean("mobs.enderman.ridable-in-water", endermanRidableInWater); + endermanAllowGriefing = getBoolean("mobs.enderman.allow-griefing", endermanAllowGriefing); + } + ++ public boolean endermiteRidable = false; ++ public boolean endermiteRidableInWater = false; ++ private void endermiteSettings() { ++ endermiteRidable = getBoolean("mobs.endermite.ridable", endermiteRidable); ++ endermiteRidableInWater = getBoolean("mobs.endermite.ridable-in-water", endermiteRidableInWater); ++ } ++ ++ public boolean evokerRidable = false; ++ public boolean evokerRidableInWater = false; ++ private void evokerSettings() { ++ evokerRidable = getBoolean("mobs.evoker.ridable", evokerRidable); ++ evokerRidableInWater = getBoolean("mobs.evoker.ridable-in-water", evokerRidableInWater); ++ } ++ ++ public boolean foxRidable = false; ++ public boolean foxRidableInWater = false; + public boolean foxTypeChangesWithTulips = false; + private void foxSettings() { ++ foxRidable = getBoolean("mobs.fox.ridable", foxRidable); ++ foxRidableInWater = getBoolean("mobs.fox.ridable-in-water", foxRidableInWater); + foxTypeChangesWithTulips = getBoolean("mobs.fox.tulips-change-type", foxTypeChangesWithTulips); + } + ++ public boolean ghastRidable = false; ++ public boolean ghastRidableInWater = false; ++ public double ghastMaxY = 256D; ++ private void ghastSettings() { ++ ghastRidable = getBoolean("mobs.ghast.ridable", ghastRidable); ++ ghastRidableInWater = getBoolean("mobs.ghast.ridable-in-water", ghastRidableInWater); ++ ghastMaxY = getDouble("mobs.ghast.ridable-max-y", ghastMaxY); ++ } ++ ++ public boolean giantRidable = false; ++ public boolean giantRidableInWater = false; + public float giantStepHeight = 2.0F; + public float giantJumpHeight = 1.0F; + public double giantMovementSpeed = 0.5D; +@@ -448,6 +568,8 @@ public class PurpurWorldConfig { + public boolean giantHaveHostileAI = false; + public double giantMaxHealth = 100.0D; + private void giantSettings() { ++ giantRidable = getBoolean("mobs.giant.ridable", giantRidable); ++ giantRidableInWater = getBoolean("mobs.giant.ridable-in-water", giantRidableInWater); + giantStepHeight = (float) getDouble("mobs.giant.step-height", giantStepHeight); + giantJumpHeight = (float) getDouble("mobs.giant.jump-height", giantJumpHeight); + giantMovementSpeed = getDouble("mobs.giant.movement-speed", giantMovementSpeed); +@@ -462,19 +584,44 @@ public class PurpurWorldConfig { + giantMaxHealth = getDouble("mobs.giant.attributes.max-health", giantMaxHealth); + } + ++ public boolean guardianRidable = false; ++ private void guardianSettings() { ++ guardianRidable = getBoolean("mobs.guardian.ridable", guardianRidable); ++ } ++ ++ public boolean hoglinRidable = false; ++ public boolean hoglinRidableInWater = false; ++ private void hoglinSettings() { ++ hoglinRidable = getBoolean("mobs.hoglin.ridable", hoglinRidable); ++ hoglinRidableInWater = getBoolean("mobs.hoglin.ridable-in-water", hoglinRidableInWater); ++ } ++ ++ public boolean horseRidableInWater = false; ++ private void horseSettings() { ++ horseRidableInWater = getBoolean("mobs.horse.ridable-in-water", horseRidableInWater); ++ } ++ ++ public boolean huskRidable = false; ++ public boolean huskRidableInWater = false; + public boolean huskJockeyOnlyBaby = true; + public double huskJockeyChance = 0.05D; + public boolean huskJockeyTryExistingChickens = true; + private void huskSettings() { ++ huskRidable = getBoolean("mobs.husk.ridable", huskRidable); ++ huskRidableInWater = getBoolean("mobs.husk.ridable-in-water", huskRidableInWater); + huskJockeyOnlyBaby = getBoolean("mobs.husk.jockey.only-babies", huskJockeyOnlyBaby); + huskJockeyChance = getDouble("mobs.husk.jockey.chance", huskJockeyChance); + huskJockeyTryExistingChickens = getBoolean("mobs.husk.jockey.try-existing-chickens", huskJockeyTryExistingChickens); + } + ++ public boolean illusionerRidable = false; ++ public boolean illusionerRidableInWater = false; + public double illusionerMovementSpeed = 0.5D; + public double illusionerFollowRange = 18.0D; + public double illusionerMaxHealth = 32.0D; + private void illusionerSettings() { ++ illusionerRidable = getBoolean("mobs.illusioner.ridable", illusionerRidable); ++ illusionerRidableInWater = getBoolean("mobs.illusioner.ridable-in-water", illusionerRidableInWater); + illusionerMovementSpeed = getDouble("mobs.illusioner.movement-speed", illusionerMovementSpeed); + illusionerFollowRange = getDouble("mobs.illusioner.follow-range", illusionerFollowRange); + if (PurpurConfig.version < 8) { +@@ -485,11 +632,76 @@ public class PurpurWorldConfig { + illusionerMaxHealth = getDouble("mobs.illusioner.attributes.max-health", illusionerMaxHealth); + } + ++ public boolean ironGolemRidable = false; ++ public boolean ironGolemRidableInWater = false; + public boolean ironGolemCanSwim = false; + private void ironGolemSettings() { ++ ironGolemRidable = getBoolean("mobs.iron_golem.ridable", ironGolemRidable); ++ ironGolemRidableInWater = getBoolean("mobs.iron_golem.ridable-in-water", ironGolemRidableInWater); + ironGolemCanSwim = getBoolean("mobs.iron_golem.can-swim", ironGolemCanSwim); + } + ++ public boolean llamaRidable = false; ++ public boolean llamaRidableInWater = false; ++ private void llamaSettings() { ++ llamaRidable = getBoolean("mobs.llama.ridable", llamaRidable); ++ llamaRidableInWater = getBoolean("mobs.llama.ridable-in-water", llamaRidableInWater); ++ } ++ ++ public boolean llamaTraderRidable = false; ++ public boolean llamaTraderRidableInWater = false; ++ private void llamaTraderSettings() { ++ llamaTraderRidable = getBoolean("mobs.trader_llama.ridable", llamaTraderRidable); ++ llamaTraderRidableInWater = getBoolean("mobs.trader_llama.ridable-in-water", llamaTraderRidableInWater); ++ } ++ ++ public boolean magmaCubeRidable = false; ++ public boolean magmaCubeRidableInWater = false; ++ private void magmaCubeSettings() { ++ magmaCubeRidable = getBoolean("mobs.magma_cube.ridable", magmaCubeRidable); ++ magmaCubeRidableInWater = getBoolean("mobs.magma_cube.ridable-in-water", magmaCubeRidableInWater); ++ } ++ ++ public boolean mooshroomRidable = false; ++ public boolean mooshroomRidableInWater = false; ++ private void mooshroomSettings() { ++ mooshroomRidable = getBoolean("mobs.mooshroom.ridable", mooshroomRidable); ++ mooshroomRidableInWater = getBoolean("mobs.mooshroom.ridable-in-water", mooshroomRidableInWater); ++ } ++ ++ public boolean muleRidableInWater = false; ++ private void muleSettings() { ++ muleRidableInWater = getBoolean("mobs.mule.ridable-in-water", muleRidableInWater); ++ } ++ ++ public boolean ocelotRidable = false; ++ public boolean ocelotRidableInWater = false; ++ private void ocelotSettings() { ++ ocelotRidable = getBoolean("mobs.ocelot.ridable", ocelotRidable); ++ ocelotRidableInWater = getBoolean("mobs.ocelot.ridable-in-water", ocelotRidableInWater); ++ } ++ ++ public boolean pandaRidable = false; ++ public boolean pandaRidableInWater = false; ++ private void pandaSettings() { ++ pandaRidable = getBoolean("mobs.panda.ridable", pandaRidable); ++ pandaRidableInWater = getBoolean("mobs.panda.ridable-in-water", pandaRidableInWater); ++ } ++ ++ public boolean parrotRidable = false; ++ public boolean parrotRidableInWater = false; ++ public double parrotMaxY = 256D; ++ private void parrotSettings() { ++ parrotRidable = getBoolean("mobs.parrot.ridable", parrotRidable); ++ parrotRidableInWater = getBoolean("mobs.parrot.ridable-in-water", parrotRidableInWater); ++ parrotMaxY = getDouble("mobs.parrot.ridable-max-y", parrotMaxY); ++ } ++ ++ public boolean phantomRidable = false; ++ public boolean phantomRidableInWater = false; ++ public double phantomMaxY = 256D; ++ public float phantomFlameDamage = 1.0F; ++ public int phantomFlameFireTime = 8; + public double phantomAttackedByCrystalRadius = 0.0D; + public float phantomAttackedByCrystalDamage = 1.0F; + public double phantomOrbitCrystalRadius = 0.0D; +@@ -508,7 +720,13 @@ public class PurpurWorldConfig { + public int phantomBurnInLight = 0; + public boolean phantomIgnorePlayersWithTorch = false; + public boolean phantomBurnInDaylight = true; ++ public boolean phantomAllowGriefing = false; + private void phantomSettings() { ++ phantomRidable = getBoolean("mobs.phantom.ridable", phantomRidable); ++ phantomRidableInWater = getBoolean("mobs.phantom.ridable-in-water", phantomRidableInWater); ++ phantomMaxY = getDouble("mobs.phantom.ridable-max-y", phantomMaxY); ++ phantomFlameDamage = (float) getDouble("mobs.phantom.flames.damage", phantomFlameDamage); ++ phantomFlameFireTime = getInt("mobs.phantom.flames.fire-time", phantomFlameFireTime); + phantomAttackedByCrystalRadius = getDouble("mobs.phantom.attacked-by-crystal-range", phantomAttackedByCrystalRadius); + phantomAttackedByCrystalDamage = (float) getDouble("mobs.phantom.attacked-by-crystal-damage", phantomAttackedByCrystalDamage); + phantomOrbitCrystalRadius = getDouble("mobs.phantom.orbit-crystal-radius", phantomOrbitCrystalRadius); +@@ -527,42 +745,187 @@ public class PurpurWorldConfig { + phantomBurnInLight = getInt("mobs.phantom.burn-in-light", phantomBurnInLight); + phantomBurnInDaylight = getBoolean("mobs.phantom.burn-in-daylight", phantomBurnInDaylight); + phantomIgnorePlayersWithTorch = getBoolean("mobs.phantom.ignore-players-with-torch", phantomIgnorePlayersWithTorch); ++ phantomAllowGriefing = getBoolean("mobs.phantom.allow-griefing", phantomAllowGriefing); + } + ++ public boolean pigRidable = false; ++ public boolean pigRidableInWater = false; + public boolean pigGiveSaddleBack = false; + private void pigSettings() { ++ pigRidable = getBoolean("mobs.pig.ridable", pigRidable); ++ pigRidableInWater = getBoolean("mobs.pig.ridable-in-water", pigRidableInWater); + pigGiveSaddleBack = getBoolean("mobs.pig.give-saddle-back", pigGiveSaddleBack); + } + ++ public boolean piglinRidable = false; ++ public boolean piglinRidableInWater = false; ++ private void piglinSettings() { ++ piglinRidable = getBoolean("mobs.piglin.ridable", piglinRidable); ++ piglinRidableInWater = getBoolean("mobs.piglin.ridable-in-water", piglinRidableInWater); ++ } ++ ++ public boolean piglinBruteRidable = false; ++ public boolean piglinBruteRidableInWater = false; ++ private void piglinBruteSettings() { ++ piglinBruteRidable = getBoolean("mobs.piglin_brute.ridable", piglinBruteRidable); ++ piglinBruteRidableInWater = getBoolean("mobs.piglin_brute.ridable-in-water", piglinBruteRidableInWater); ++ } ++ ++ public boolean pillagerRidable = false; ++ public boolean pillagerRidableInWater = false; ++ private void pillagerSettings() { ++ pillagerRidable = getBoolean("mobs.pillager.ridable", pillagerRidable); ++ pillagerRidableInWater = getBoolean("mobs.pillager.ridable-in-water", pillagerRidableInWater); ++ } ++ ++ public boolean polarBearRidable = false; ++ public boolean polarBearRidableInWater = false; + public String polarBearBreedableItemString = ""; + public Item polarBearBreedableItem = null; + private void polarBearSettings() { ++ polarBearRidable = getBoolean("mobs.polar_bear.ridable", polarBearRidable); ++ polarBearRidableInWater = getBoolean("mobs.polar_bear.ridable-in-water", polarBearRidableInWater); + polarBearBreedableItemString = getString("mobs.polar_bear.breedable-item", polarBearBreedableItemString); + Item item = IRegistry.ITEM.get(new MinecraftKey(polarBearBreedableItemString)); + if (item != Items.AIR) polarBearBreedableItem = item; + } + ++ public boolean pufferfishRidable = false; ++ private void pufferfishSettings() { ++ pufferfishRidable = getBoolean("mobs.pufferfish.ridable", pufferfishRidable); ++ } ++ ++ public boolean rabbitRidable = false; ++ public boolean rabbitRidableInWater = false; + public double rabbitNaturalToast = 0.0D; + public double rabbitNaturalKiller = 0.0D; + private void rabbitSettings() { ++ rabbitRidable = getBoolean("mobs.rabbit.ridable", rabbitRidable); ++ rabbitRidableInWater = getBoolean("mobs.rabbit.ridable-in-water", rabbitRidableInWater); + rabbitNaturalToast = getDouble("mobs.rabbit.spawn-toast-chance", rabbitNaturalToast); + rabbitNaturalKiller = getDouble("mobs.rabbit.spawn-killer-rabbit-chance", rabbitNaturalKiller); + } + ++ public boolean ravagerRidable = false; ++ public boolean ravagerRidableInWater = false; ++ private void ravagerSettings() { ++ ravagerRidable = getBoolean("mobs.ravager.ridable", ravagerRidable); ++ ravagerRidableInWater = getBoolean("mobs.ravager.ridable-in-water", ravagerRidableInWater); ++ } ++ ++ public boolean salmonRidable = false; ++ private void salmonSettings() { ++ salmonRidable = getBoolean("mobs.salmon.ridable", salmonRidable); ++ } ++ ++ public boolean sheepRidable = false; ++ public boolean sheepRidableInWater = false; ++ private void sheepSettings() { ++ sheepRidable = getBoolean("mobs.sheep.ridable", sheepRidable); ++ sheepRidableInWater = getBoolean("mobs.sheep.ridable-in-water", sheepRidableInWater); ++ } ++ ++ public boolean shulkerRidable = false; ++ public boolean shulkerRidableInWater = false; ++ private void shulkerSettings() { ++ shulkerRidable = getBoolean("mobs.shulker.ridable", shulkerRidable); ++ shulkerRidableInWater = getBoolean("mobs.shulker.ridable-in-water", shulkerRidableInWater); ++ } ++ ++ public boolean silverfishRidable = false; ++ public boolean silverfishRidableInWater = false; ++ private void silverfishSettings() { ++ silverfishRidable = getBoolean("mobs.silverfish.ridable", silverfishRidable); ++ silverfishRidableInWater = getBoolean("mobs.silverfish.ridable-in-water", silverfishRidableInWater); ++ } ++ ++ public boolean skeletonRidable = false; ++ public boolean skeletonRidableInWater = false; ++ private void skeletonSettings() { ++ skeletonRidable = getBoolean("mobs.skeleton.ridable", skeletonRidable); ++ skeletonRidableInWater = getBoolean("mobs.skeleton.ridable-in-water", skeletonRidableInWater); ++ } ++ ++ public boolean skeletonHorseCanSwim = false; ++ public boolean skeletonHorseRidableInWater = true; ++ private void skeletonHorseSettings() { ++ skeletonHorseCanSwim = getBoolean("mobs.skeleton_horse.can-swim", skeletonHorseCanSwim); ++ skeletonHorseRidableInWater = getBoolean("mobs.skeleton_horse.ridable-in-water", skeletonHorseRidableInWater); ++ } ++ ++ public boolean slimeRidable = false; ++ public boolean slimeRidableInWater = false; ++ private void slimeSettings() { ++ slimeRidable = getBoolean("mobs.slime.ridable", slimeRidable); ++ slimeRidableInWater = getBoolean("mobs.slime.ridable-in-water", slimeRidableInWater); ++ } ++ ++ public boolean snowGolemRidable = false; ++ public boolean snowGolemRidableInWater = false; ++ public boolean snowGolemLeaveTrailWhenRidden = false; + public boolean snowGolemDropsPumpkin = true; + public boolean snowGolemPutPumpkinBack = false; + private void snowGolemSettings() { ++ snowGolemRidable = getBoolean("mobs.snow_golem.ridable", snowGolemRidable); ++ snowGolemRidableInWater = getBoolean("mobs.snow_golem.ridable-in-water", snowGolemRidableInWater); ++ snowGolemLeaveTrailWhenRidden = getBoolean("mobs.snow_golem.leave-trail-when-ridden", snowGolemLeaveTrailWhenRidden); + snowGolemDropsPumpkin = getBoolean("mobs.snow_golem.drop-pumpkin-when-sheared", snowGolemDropsPumpkin); + snowGolemPutPumpkinBack = getBoolean("mobs.snow_golem.pumpkin-can-be-added-back", snowGolemPutPumpkinBack); + } + ++ public boolean squidRidable = false; + public boolean squidImmuneToEAR = true; + public double squidOffsetWaterCheck = 0.0D; + private void squidSettings() { ++ squidRidable = getBoolean("mobs.squid.ridable", squidRidable); + squidImmuneToEAR = getBoolean("mobs.squid.immune-to-EAR", squidImmuneToEAR); + squidOffsetWaterCheck = getDouble("mobs.squid.water-offset-check", squidOffsetWaterCheck); + } + ++ public boolean spiderRidable = false; ++ public boolean spiderRidableInWater = false; ++ private void spiderSettings() { ++ spiderRidable = getBoolean("mobs.spider.ridable", spiderRidable); ++ spiderRidableInWater = getBoolean("mobs.spider.ridable-in-water", spiderRidableInWater); ++ } ++ ++ public boolean strayRidable = false; ++ public boolean strayRidableInWater = false; ++ private void straySettings() { ++ strayRidable = getBoolean("mobs.stray.ridable", strayRidable); ++ strayRidableInWater = getBoolean("mobs.stray.ridable-in-water", strayRidableInWater); ++ } ++ ++ public boolean striderRidable = false; ++ public boolean striderRidableInWater = false; ++ private void striderSettings() { ++ striderRidable = getBoolean("mobs.strider.ridable", striderRidable); ++ striderRidableInWater = getBoolean("mobs.strider.ridable-in-water", striderRidableInWater); ++ } ++ ++ public boolean tropicalFishRidable = false; ++ private void tropicalFishSettings() { ++ tropicalFishRidable = getBoolean("mobs.tropical_fish.ridable", tropicalFishRidable); ++ } ++ ++ public boolean turtleRidable = false; ++ public boolean turtleRidableInWater = false; ++ private void turtleSettings() { ++ turtleRidable = getBoolean("mobs.turtle.ridable", turtleRidable); ++ turtleRidableInWater = getBoolean("mobs.turtle.ridable-in-water", turtleRidableInWater); ++ } ++ ++ public boolean vexRidable = false; ++ public boolean vexRidableInWater = false; ++ public double vexMaxY = 256D; ++ private void vexSettings() { ++ vexRidable = getBoolean("mobs.vex.ridable", vexRidable); ++ vexRidableInWater = getBoolean("mobs.vex.ridable-in-water", vexRidableInWater); ++ vexMaxY = getDouble("mobs.vex.ridable-max-y", vexMaxY); ++ } ++ ++ public boolean villagerRidable = false; ++ public boolean villagerRidableInWater = false; + public int villagerBrainTicks = 1; + public boolean villagerUseBrainTicksOnlyWhenLagging = true; + public boolean villagerCanBeLeashed = false; +@@ -572,6 +935,8 @@ public class PurpurWorldConfig { + public int villagerSpawnIronGolemLimit = 0; + public boolean villagerCanBreed = true; + private void villagerSettings() { ++ villagerRidable = getBoolean("mobs.villager.ridable", villagerRidable); ++ villagerRidableInWater = getBoolean("mobs.villager.ridable-in-water", villagerRidableInWater); + villagerBrainTicks = getInt("mobs.villager.brain-ticks", villagerBrainTicks); + villagerUseBrainTicksOnlyWhenLagging = getBoolean("mobs.villager.use-brain-ticks-only-when-lagging", villagerUseBrainTicksOnlyWhenLagging); + villagerCanBeLeashed = getBoolean("mobs.villager.can-be-leashed", villagerCanBeLeashed); +@@ -582,45 +947,108 @@ public class PurpurWorldConfig { + villagerCanBreed = getBoolean("mobs.villager.can-breed", villagerCanBreed); + } + ++ public boolean villagerTraderRidable = false; ++ public boolean villagerTraderRidableInWater = false; + public boolean villagerTraderCanBeLeashed = false; + public boolean villagerTraderFollowEmeraldBlock = false; + private void villagerTraderSettings() { ++ villagerTraderRidable = getBoolean("mobs.wandering_trader.ridable", villagerTraderRidable); ++ villagerTraderRidableInWater = getBoolean("mobs.wandering_trader.ridable-in-water", villagerTraderRidableInWater); + villagerTraderCanBeLeashed = getBoolean("mobs.wandering_trader.can-be-leashed", villagerTraderCanBeLeashed); + villagerTraderFollowEmeraldBlock = getBoolean("mobs.wandering_trader.follow-emerald-blocks", villagerTraderFollowEmeraldBlock); + } + ++ public boolean vindicatorRidable = false; ++ public boolean vindicatorRidableInWater = false; ++ public double vindicatorJohnnySpawnChance = 0D; ++ private void vindicatorSettings() { ++ vindicatorRidable = getBoolean("mobs.vindicator.ridable", vindicatorRidable); ++ vindicatorRidableInWater = getBoolean("mobs.vindicator.ridable-in-water", vindicatorRidableInWater); ++ vindicatorJohnnySpawnChance = getDouble("mobs.vindicator.johnny.spawn-chance", vindicatorJohnnySpawnChance); ++ } ++ ++ public boolean witchRidable = false; ++ public boolean witchRidableInWater = false; ++ private void witchSettings() { ++ witchRidable = getBoolean("mobs.witch.ridable", witchRidable); ++ witchRidableInWater = getBoolean("mobs.witch.ridable-in-water", witchRidableInWater); ++ } ++ ++ public boolean witherRidable = false; ++ public boolean witherRidableInWater = false; ++ public double witherMaxY = 256D; ++ private void witherSettings() { ++ witherRidable = getBoolean("mobs.wither.ridable", witherRidable); ++ witherRidableInWater = getBoolean("mobs.wither.ridable-in-water", witherRidableInWater); ++ witherMaxY = getDouble("mobs.wither.ridable-max-y", witherMaxY); ++ } ++ ++ public boolean witherSkeletonRidable = false; ++ public boolean witherSkeletonRidableInWater = false; + public boolean witherSkeletonTakesWitherDamage = false; + private void witherSkeletonSettings() { ++ witherSkeletonRidable = getBoolean("mobs.wither_skeleton.ridable", witherSkeletonRidable); ++ witherSkeletonRidableInWater = getBoolean("mobs.wither_skeleton.ridable-in-water", witherSkeletonRidableInWater); + witherSkeletonTakesWitherDamage = getBoolean("mobs.wither_skeleton.takes-wither-damage", witherSkeletonTakesWitherDamage); + } + ++ public boolean wolfRidable = false; ++ public boolean wolfRidableInWater = false; ++ private void wolfSettings() { ++ wolfRidable = getBoolean("mobs.wolf.ridable", wolfRidable); ++ wolfRidableInWater = getBoolean("mobs.wolf.ridable-in-water", wolfRidableInWater); ++ } ++ ++ public boolean zoglinRidable = false; ++ public boolean zoglinRidableInWater = false; ++ private void zoglinSettings() { ++ zoglinRidable = getBoolean("mobs.zoglin.ridable", zoglinRidable); ++ zoglinRidableInWater = getBoolean("mobs.zoglin.ridable-in-water", zoglinRidableInWater); ++ } ++ ++ public boolean zombieRidable = false; ++ public boolean zombieRidableInWater = false; + public boolean zombieJockeyOnlyBaby = true; + public double zombieJockeyChance = 0.05D; + public boolean zombieJockeyTryExistingChickens = true; + private void zombieSettings() { ++ zombieRidable = getBoolean("mobs.zombie.ridable", zombieRidable); ++ zombieRidableInWater = getBoolean("mobs.zombie.ridable-in-water", zombieRidableInWater); + zombieJockeyOnlyBaby = getBoolean("mobs.zombie.jockey.only-babies", zombieJockeyOnlyBaby); + zombieJockeyChance = getDouble("mobs.zombie.jockey.chance", zombieJockeyChance); + zombieJockeyTryExistingChickens = getBoolean("mobs.zombie.jockey.try-existing-chickens", zombieJockeyTryExistingChickens); + } + ++ public boolean zombieHorseCanSwim = false; ++ public boolean zombieHorseRidableInWater = false; + public double zombieHorseSpawnChance = 0.0D; + private void zombieHorseSettings() { ++ zombieHorseCanSwim = getBoolean("mobs.zombie_horse.can-swim", zombieHorseCanSwim); ++ zombieHorseRidableInWater = getBoolean("mobs.zombie_horse.ridable-in-water", zombieHorseRidableInWater); + zombieHorseSpawnChance = getDouble("mobs.zombie_horse.spawn-chance", zombieHorseSpawnChance); + } + ++ public boolean zombifiedPiglinRidable = false; ++ public boolean zombifiedPiglinRidableInWater = false; + public boolean zombifiedPiglinJockeyOnlyBaby = true; + public double zombifiedPiglinJockeyChance = 0.05D; + public boolean zombifiedPiglinJockeyTryExistingChickens = true; + private void zombifiedPiglinSettings() { ++ zombifiedPiglinRidable = getBoolean("mobs.zombified_piglin.ridable", zombifiedPiglinRidable); ++ zombifiedPiglinRidableInWater = getBoolean("mobs.zombified_piglin.ridable-in-water", zombifiedPiglinRidableInWater); + zombifiedPiglinJockeyOnlyBaby = getBoolean("mobs.zombified_piglin.jockey.only-babies", zombifiedPiglinJockeyOnlyBaby); + zombifiedPiglinJockeyChance = getDouble("mobs.zombified_piglin.jockey.chance", zombifiedPiglinJockeyChance); + zombifiedPiglinJockeyTryExistingChickens = getBoolean("mobs.zombified_piglin.jockey.try-existing-chickens", zombifiedPiglinJockeyTryExistingChickens); + } + ++ public boolean zombieVillagerRidable = false; ++ public boolean zombieVillagerRidableInWater = false; + public boolean zombieVillagerJockeyOnlyBaby = true; + public double zombieVillagerJockeyChance = 0.05D; + public boolean zombieVillagerJockeyTryExistingChickens = true; + private void zombieVillagerSettings() { ++ zombieVillagerRidable = getBoolean("mobs.zombie_villager.ridable", zombieVillagerRidable); ++ zombieVillagerRidableInWater = getBoolean("mobs.zombie_villager.ridable-in-water", zombieVillagerRidableInWater); + zombieVillagerJockeyOnlyBaby = getBoolean("mobs.zombie_villager.jockey.only-babies", zombieVillagerJockeyOnlyBaby); + zombieVillagerJockeyChance = getDouble("mobs.zombie_villager.jockey.chance", zombieVillagerJockeyChance); + zombieVillagerJockeyTryExistingChickens = getBoolean("mobs.zombie_villager.jockey.try-existing-chickens", zombieVillagerJockeyTryExistingChickens); +diff --git a/src/main/java/net/pl3x/purpur/controller/ControllerLookWASD.java b/src/main/java/net/pl3x/purpur/controller/ControllerLookWASD.java +new file mode 100644 +index 0000000000000000000000000000000000000000..088c830471b796908781bc1aa0693355849754cd +--- /dev/null ++++ b/src/main/java/net/pl3x/purpur/controller/ControllerLookWASD.java +@@ -0,0 +1,76 @@ ++package net.pl3x.purpur.controller; ++ ++import net.minecraft.network.protocol.game.PacketPlayOutEntity; ++import net.minecraft.world.entity.ai.control.ControllerLook; ++import net.minecraft.world.entity.EntityInsentient; ++import net.minecraft.util.MathHelper; ++import net.minecraft.world.entity.player.EntityHuman; ++ ++public class ControllerLookWASD extends ControllerLook { ++ protected final EntityInsentient entity; ++ private float yawOffset = 0; ++ private float pitchOffset = 0; ++ ++ public ControllerLookWASD(EntityInsentient entity) { ++ super(entity); ++ this.entity = entity; ++ } ++ ++ // tick ++ @Override ++ public void a() { ++ if (entity.hasPurpurRider()) { ++ tick(entity.getPurpurRider()); ++ } else { ++ tick(); ++ } ++ } ++ ++ protected void tick() { ++ super.a(); // tick ++ } ++ ++ protected void tick(EntityHuman rider) { ++ setYawPitch(rider.yaw, rider.pitch); ++ } ++ ++ public void setYawPitch(float yaw, float pitch) { ++ entity.yaw = normalizeYaw(yaw + yawOffset); ++ entity.lastYaw = entity.yaw; ++ entity.setBodyYaw(entity.yaw); ++ entity.setRenderYawOffset(entity.yaw); ++ entity.setHeadRotation(entity.yaw); ++ entity.pitch = normalizePitch(pitch + pitchOffset); ++ ++ entity.tracker.broadcast(new PacketPlayOutEntity ++ .PacketPlayOutRelEntityMoveLook(entity.getId(), ++ (short) 0, (short) 0, (short) 0, ++ (byte) MathHelper.d(entity.yaw * 256.0F / 360.0F), ++ (byte) MathHelper.d(entity.pitch * 256.0F / 360.0F), ++ entity.onGround)); ++ } ++ ++ public void setOffsets(float yaw, float pitch) { ++ yawOffset = yaw; ++ pitchOffset = pitch; ++ } ++ ++ public float normalizeYaw(float yaw) { ++ yaw %= 360.0f; ++ if (yaw >= 180.0f) { ++ yaw -= 360.0f; ++ } else if (yaw < -180.0f) { ++ yaw += 360.0f; ++ } ++ return yaw; ++ } ++ ++ public float normalizePitch(float pitch) { ++ if (pitch > 90.0f) { ++ pitch = 90.0f; ++ } else if (pitch < -90.0f) { ++ pitch = -90.0f; ++ } ++ return pitch; ++ } ++} +diff --git a/src/main/java/net/pl3x/purpur/controller/ControllerMoveWASD.java b/src/main/java/net/pl3x/purpur/controller/ControllerMoveWASD.java +new file mode 100644 +index 0000000000000000000000000000000000000000..6b1f37398ef6cf5935e7acb4295f9223a026226a +--- /dev/null ++++ b/src/main/java/net/pl3x/purpur/controller/ControllerMoveWASD.java +@@ -0,0 +1,92 @@ ++package net.pl3x.purpur.controller; ++ ++import net.minecraft.world.entity.ai.control.ControllerMove; ++import net.minecraft.world.entity.Entity; ++import net.minecraft.world.entity.EntityInsentient; ++import net.minecraft.world.entity.ai.attributes.GenericAttributes; ++import net.minecraft.world.entity.player.EntityHuman; ++import net.pl3x.purpur.event.entity.RidableSpacebarEvent; ++ ++public class ControllerMoveWASD extends ControllerMove { ++ protected final EntityInsentient entity; ++ private final double speedModifier; ++ ++ public ControllerMoveWASD(EntityInsentient entity) { ++ this(entity, 1.0D); ++ } ++ ++ public ControllerMoveWASD(EntityInsentient entity, double speedModifier) { ++ super(entity); ++ this.entity = entity; ++ this.speedModifier = speedModifier; ++ } ++ ++ // isUpdating ++ @Override ++ public boolean b() { ++ return entity.hasPurpurRider() ? getForward() != 0 || getStrafe() != 0 : super.b(); ++ } ++ ++ // tick ++ @Override ++ public void a() { ++ if (entity.hasPurpurRider()) { ++ tick(entity.getPurpurRider()); ++ } else { ++ tick(); ++ } ++ } ++ ++ public void tick() { ++ super.a(); // tick ++ } ++ ++ public void tick(EntityHuman rider) { ++ float forward = rider.getForward() * 0.5F; ++ float strafe = rider.getStrafe() * 0.25F; ++ ++ if (forward <= 0.0F) { ++ forward *= 0.5F; ++ } ++ ++ float yawOffset = 0; ++ if (strafe != 0) { ++ if (forward == 0) { ++ yawOffset += strafe > 0 ? -90 : 90; ++ forward = Math.abs(strafe * 2); ++ } else { ++ yawOffset += strafe > 0 ? -30 : 30; ++ strafe /= 2; ++ if (forward < 0) { ++ yawOffset += strafe > 0 ? -110 : 110; ++ forward *= -1; ++ } ++ } ++ } else if (forward < 0) { ++ yawOffset -= 180; ++ forward *= -1; ++ } ++ ++ ((ControllerLookWASD) entity.getControllerLook()).setOffsets(yawOffset, 0); ++ ++ if (rider.jumping && spacebarEvent(entity) && !entity.onSpacebar() && entity.onGround) { ++ entity.jump(); ++ } ++ ++ setSpeed(entity.getAttributeInstance(GenericAttributes.MOVEMENT_SPEED).getValue() * speedModifier); ++ ++ entity.setSpeed((float) getSpeed()); ++ entity.setForward(forward); ++ ++ setForward(entity.getForward()); ++ setStrafe(entity.getStrafe()); ++ } ++ ++ public static boolean spacebarEvent(Entity entity) { ++ if (RidableSpacebarEvent.getHandlerList().getRegisteredListeners().length > 0) { ++ return new RidableSpacebarEvent(entity.getBukkitEntity()).callEvent(); ++ } else { ++ return true; ++ } ++ } ++} +diff --git a/src/main/java/net/pl3x/purpur/controller/ControllerMoveWASDFlying.java b/src/main/java/net/pl3x/purpur/controller/ControllerMoveWASDFlying.java +new file mode 100644 +index 0000000000000000000000000000000000000000..7737e87048e88b40c0b6b4a1093e2256ae252802 +--- /dev/null ++++ b/src/main/java/net/pl3x/purpur/controller/ControllerMoveWASDFlying.java +@@ -0,0 +1,61 @@ ++package net.pl3x.purpur.controller; ++ ++import net.minecraft.world.entity.EntityInsentient; ++import net.minecraft.world.entity.ai.attributes.GenericAttributes; ++import net.minecraft.world.entity.player.EntityHuman; ++ ++public class ControllerMoveWASDFlying extends ControllerMoveWASD { ++ protected final float groundSpeedModifier; ++ protected int tooHighCooldown = 0; ++ protected boolean setGravityFlag = true; ++ ++ public ControllerMoveWASDFlying(EntityInsentient entity) { ++ this(entity, 1.0F); ++ } ++ ++ public ControllerMoveWASDFlying(EntityInsentient entity, float groundSpeedModifier) { ++ this(entity, groundSpeedModifier, true); ++ } ++ ++ public ControllerMoveWASDFlying(EntityInsentient entity, float groundSpeedModifier, boolean setGravityFlag) { ++ super(entity); ++ this.groundSpeedModifier = groundSpeedModifier; ++ this.setGravityFlag = setGravityFlag; ++ } ++ ++ @Override ++ public void tick(EntityHuman rider) { ++ float forward = Math.max(0.0F, rider.getForward()); ++ float vertical = forward == 0.0F ? 0.0F : -(rider.pitch / 45.0F); ++ float strafe = rider.getStrafe(); ++ ++ if (rider.jumping && spacebarEvent(entity)) { ++ entity.onSpacebar(); ++ } ++ ++ if (entity.locY() >= entity.getMaxY() || --tooHighCooldown > 0) { ++ tooHighCooldown = 60; ++ entity.setMot(entity.getMot().add(0.0D, -0.05D, 0.0D)); ++ vertical = 0.0F; ++ } ++ ++ setSpeed(entity.getAttributeInstance(GenericAttributes.MOVEMENT_SPEED).getValue()); ++ float speed = (float) getSpeed(); ++ ++ if (entity.onGround) { ++ speed *= groundSpeedModifier; // TODO = fix this! ++ } ++ ++ if (setGravityFlag) { ++ entity.setNoGravity(forward > 0); ++ } ++ ++ entity.setSpeed(speed); ++ entity.setVertical(vertical); ++ entity.setStrafe(strafe); ++ entity.setForward(forward); ++ ++ setForward(entity.getForward()); ++ setStrafe(entity.getStrafe()); ++ } ++} +diff --git a/src/main/java/net/pl3x/purpur/controller/ControllerMoveWASDFlyingWithSpacebar.java b/src/main/java/net/pl3x/purpur/controller/ControllerMoveWASDFlyingWithSpacebar.java +new file mode 100644 +index 0000000000000000000000000000000000000000..cdd32aa66b6bd9c01854e3d9baf25757c7e2a707 +--- /dev/null ++++ b/src/main/java/net/pl3x/purpur/controller/ControllerMoveWASDFlyingWithSpacebar.java +@@ -0,0 +1,61 @@ ++package net.pl3x.purpur.controller; ++ ++import net.minecraft.world.entity.EntityInsentient; ++import net.minecraft.world.entity.ai.attributes.GenericAttributes; ++import net.minecraft.world.entity.player.EntityHuman; ++import net.minecraft.world.phys.Vec3D; ++ ++public class ControllerMoveWASDFlyingWithSpacebar extends ControllerMoveWASDFlying { ++ public ControllerMoveWASDFlyingWithSpacebar(EntityInsentient entity) { ++ super(entity); ++ } ++ ++ public ControllerMoveWASDFlyingWithSpacebar(EntityInsentient entity, float groundSpeedModifier) { ++ super(entity, groundSpeedModifier); ++ } ++ ++ @Override ++ public void tick(EntityHuman rider) { ++ float forward = rider.getForward(); ++ float strafe = rider.getStrafe() * 0.5F; ++ float vertical = 0; ++ ++ if (forward < 0.0F) { ++ forward *= 0.5F; ++ strafe *= 0.5F; ++ } ++ ++ float speed = (float) entity.getAttributeInstance(GenericAttributes.MOVEMENT_SPEED).getValue(); ++ ++ if (entity.onGround) { ++ speed *= groundSpeedModifier; ++ } ++ ++ if (rider.jumping && spacebarEvent(entity) && !entity.onSpacebar()) { ++ entity.setNoGravity(true); ++ vertical = 1.0F; ++ } else { ++ entity.setNoGravity(false); ++ } ++ ++ if (entity.locY() >= entity.getMaxY() || --tooHighCooldown > 0) { ++ tooHighCooldown = 60; ++ entity.setMot(entity.getMot().add(0.0D, -0.2D, 0.0D)); ++ vertical = 0.0F; ++ } ++ ++ setSpeed(speed); ++ entity.setSpeed((float) getSpeed()); ++ entity.setVertical(vertical); ++ entity.setStrafe(strafe); ++ entity.setForward(forward); ++ ++ setForward(entity.getForward()); ++ setStrafe(entity.getStrafe()); ++ ++ Vec3D mot = entity.getMot(); ++ if (mot.y > 0.2D) { ++ entity.setMot(mot.x, 0.2D, mot.z); ++ } ++ } ++} +diff --git a/src/main/java/net/pl3x/purpur/controller/ControllerMoveWASDWater.java b/src/main/java/net/pl3x/purpur/controller/ControllerMoveWASDWater.java +new file mode 100644 +index 0000000000000000000000000000000000000000..aa7eb0b3bd7be8d1992e99bf156dbad167e571aa +--- /dev/null ++++ b/src/main/java/net/pl3x/purpur/controller/ControllerMoveWASDWater.java +@@ -0,0 +1,50 @@ ++package net.pl3x.purpur.controller; ++ ++import net.minecraft.world.entity.EntityInsentient; ++import net.minecraft.world.entity.ai.attributes.GenericAttributes; ++import net.minecraft.world.entity.player.EntityHuman; ++ ++public class ControllerMoveWASDWater extends ControllerMoveWASD { ++ private final double speedModifier; ++ ++ public ControllerMoveWASDWater(EntityInsentient entity) { ++ this(entity, 1.0D); ++ } ++ ++ public ControllerMoveWASDWater(EntityInsentient entity, double speedModifier) { ++ super(entity); ++ this.speedModifier = speedModifier; ++ } ++ ++ @Override ++ public void tick(EntityHuman rider) { ++ float forward = rider.getForward(); ++ float strafe = rider.getStrafe() * 0.5F; // strafe slower by default ++ float vertical = -(rider.pitch / 90); ++ ++ if (forward == 0.0F) { ++ // strafe slower if not moving forward ++ strafe *= 0.5F; ++ // do not move vertically if not moving forward ++ vertical = 0.0F; ++ } else if (forward < 0.0F) { ++ // water animals can't swim backwards ++ forward = 0.0F; ++ vertical = 0.0F; ++ } ++ ++ if (rider.jumping && spacebarEvent(entity)) { ++ entity.onSpacebar(); ++ } ++ ++ setSpeed(entity.getAttributeInstance(GenericAttributes.MOVEMENT_SPEED).getValue() * speedModifier); ++ entity.setSpeed((float) getSpeed() * 0.1F); ++ ++ entity.setForward(forward * (float) speedModifier); ++ entity.setStrafe(strafe * (float) speedModifier); ++ entity.setVertical(vertical * (float) speedModifier); ++ ++ setForward(entity.getForward()); ++ setStrafe(entity.getStrafe()); ++ } ++} +diff --git a/src/main/java/net/pl3x/purpur/entity/DolphinSpit.java b/src/main/java/net/pl3x/purpur/entity/DolphinSpit.java +new file mode 100644 +index 0000000000000000000000000000000000000000..621e4d0af89e78404e79a92ba717392e4cf4f82b +--- /dev/null ++++ b/src/main/java/net/pl3x/purpur/entity/DolphinSpit.java +@@ -0,0 +1,119 @@ ++package net.pl3x.purpur.entity; ++ ++import net.minecraft.world.entity.animal.EntityDolphin; ++import net.minecraft.world.entity.projectile.EntityLlamaSpit; ++import net.minecraft.world.damagesource.DamageSource; ++import net.minecraft.world.entity.Entity; ++import net.minecraft.world.entity.EntityLiving; ++import net.minecraft.world.entity.EntityTypes; ++import net.minecraft.world.level.block.state.IBlockData; ++import net.minecraft.util.MathHelper; ++import net.minecraft.world.phys.MovingObjectPosition; ++import net.minecraft.world.phys.MovingObjectPositionBlock; ++import net.minecraft.world.phys.MovingObjectPositionEntity; ++import net.minecraft.core.particles.Particles; ++import net.minecraft.world.entity.projectile.ProjectileHelper; ++import net.minecraft.world.phys.Vec3D; ++import net.minecraft.world.level.World; ++import net.minecraft.server.level.WorldServer; ++import org.bukkit.craftbukkit.event.CraftEventFactory; ++ ++public class DolphinSpit extends EntityLlamaSpit { ++ public EntityLiving dolphin; ++ public int ticksLived; ++ ++ public DolphinSpit(EntityTypes entitytypes, World world) { ++ super(entitytypes, world); ++ } ++ ++ public DolphinSpit(World world, EntityDolphin dolphin) { ++ this(EntityTypes.LLAMA_SPIT, world); ++ setShooter(dolphin.hasPurpurRider() ? dolphin.getPurpurRider() : dolphin); ++ this.dolphin = dolphin; ++ this.setPosition( ++ dolphin.locX() - (double) (dolphin.getWidth() + 1.0F) * 0.5D * (double) MathHelper.sin(dolphin.getRenderYawOffset() * 0.017453292F), ++ dolphin.getHeadY() - 0.10000000149011612D, ++ dolphin.locZ() + (double) (dolphin.getWidth() + 1.0F) * 0.5D * (double) MathHelper.cos(dolphin.getRenderYawOffset() * 0.017453292F)); ++ } ++ ++ @Override ++ public boolean canSaveToDisk() { ++ return false; ++ } ++ ++ public void tick() { ++ if (dead || !valid) { ++ return; ++ } ++ ++ if (!leftOwner()) { ++ setLeftOwner(checkIfLeftOwner()); ++ } ++ ++ setFlag(6, isGlowing()); ++ entityBaseTick(); ++ ++ Vec3D mot = getMot(); ++ ++ MovingObjectPosition hitResult = ProjectileHelper.getHitResult(this, this::hitPredicate); ++ if (hitResult != null) { ++ onHit(hitResult); ++ } ++ ++ double x = this.locX() + mot.x; ++ double y = this.locY() + mot.y; ++ double z = this.locZ() + mot.z; ++ setMot(mot.scale(0.99D)); ++ ++ Vec3D motDouble = mot.scale(2.0); ++ for (int i = 0; i < 5; i++) { ++ ((WorldServer) world).sendParticles(null, Particles.BUBBLE, ++ locX() + random.nextFloat() / 2 - 0.25F, ++ locY() + random.nextFloat() / 2 - 0.25F, ++ locZ() + random.nextFloat() / 2 - 0.25F, ++ 0, motDouble.getX(), motDouble.getY(), motDouble.getZ(), 0.1, true); ++ } ++ ++ if (++ticksLived > 20) { ++ die(); ++ } else { ++ setMot(mot.scale(0.99D)); ++ if (!isNoGravity()) { ++ setMot(getMot().add(0.0D, -0.06D, 0.0D)); ++ } ++ setPosition(x, y, z); ++ } ++ } ++ ++ @Override ++ public void shoot(double x, double y, double z, float speed, float inaccuracy) { ++ setMot(new Vec3D(x, y, z).normalize().add( ++ random.nextGaussian() * (double) 0.0075F * (double) inaccuracy, ++ random.nextGaussian() * (double) 0.0075F * (double) inaccuracy, ++ random.nextGaussian() * (double) 0.0075F * (double) inaccuracy) ++ .scale(speed)); ++ } ++ ++ public void onHit(MovingObjectPosition rayTrace) { ++ CraftEventFactory.callProjectileHitEvent(this, rayTrace); ++ MovingObjectPosition.EnumMovingObjectType type = rayTrace.getType(); ++ if (type == MovingObjectPosition.EnumMovingObjectType.ENTITY) { ++ onHit((MovingObjectPositionEntity) rayTrace); ++ } else if (type == MovingObjectPosition.EnumMovingObjectType.BLOCK) { ++ onHit((MovingObjectPositionBlock) rayTrace); ++ } ++ } ++ ++ protected void onHit(MovingObjectPositionEntity rayTrace) { ++ Entity shooter = getShooter(); ++ if (shooter instanceof EntityLiving) { ++ rayTrace.getEntity().damageEntity(DamageSource.indirectMobAttack(this, (EntityLiving) shooter).setProjectile(), world.purpurConfig.dolphinSpitDamage); ++ } ++ } ++ ++ protected void onHit(MovingObjectPositionBlock rayTrace) { ++ IBlockData iblockdata = world.getType(rayTrace.getBlockPosition()); ++ iblockdata.a(world, iblockdata, rayTrace, this); ++ die(); ++ } ++} +diff --git a/src/main/java/net/pl3x/purpur/entity/PhantomFlames.java b/src/main/java/net/pl3x/purpur/entity/PhantomFlames.java +new file mode 100644 +index 0000000000000000000000000000000000000000..c7cd0327084943dcb6339998805e6b7db1d87bba +--- /dev/null ++++ b/src/main/java/net/pl3x/purpur/entity/PhantomFlames.java +@@ -0,0 +1,140 @@ ++package net.pl3x.purpur.entity; ++ ++import net.minecraft.world.damagesource.DamageSource; ++import net.minecraft.world.entity.Entity; ++import net.minecraft.world.entity.EntityLiving; ++import net.minecraft.world.entity.EntityTypes; ++import net.minecraft.world.entity.decoration.EntityArmorStand; ++import net.minecraft.world.entity.monster.EntityPhantom; ++import net.minecraft.world.entity.projectile.EntityLlamaSpit; ++import net.minecraft.world.level.block.state.BlockBase; ++import net.minecraft.world.level.block.state.IBlockData; ++import net.minecraft.util.MathHelper; ++import net.minecraft.world.phys.MovingObjectPosition; ++import net.minecraft.world.phys.MovingObjectPositionBlock; ++import net.minecraft.world.phys.MovingObjectPositionEntity; ++import net.minecraft.core.particles.Particles; ++import net.minecraft.world.entity.projectile.ProjectileHelper; ++import net.minecraft.world.phys.Vec3D; ++import net.minecraft.world.level.World; ++import net.minecraft.server.level.WorldServer; ++import org.bukkit.craftbukkit.event.CraftEventFactory; ++ ++public class PhantomFlames extends EntityLlamaSpit { ++ public EntityPhantom phantom; ++ public int ticksLived; ++ public boolean canGrief = false; ++ ++ public PhantomFlames(EntityTypes entitytypes, World world) { ++ super(entitytypes, world); ++ } ++ ++ public PhantomFlames(World world, EntityPhantom phantom) { ++ this(EntityTypes.LLAMA_SPIT, world); ++ setShooter(phantom.hasPurpurRider() ? phantom.getPurpurRider() : phantom); ++ this.phantom = phantom; ++ this.setPosition( ++ phantom.locX() - (double) (phantom.getWidth() + 1.0F) * 0.5D * (double) MathHelper.sin(phantom.getRenderYawOffset() * 0.017453292F), ++ phantom.getHeadY() - 0.10000000149011612D, ++ phantom.locZ() + (double) (phantom.getWidth() + 1.0F) * 0.5D * (double) MathHelper.cos(phantom.getRenderYawOffset() * 0.017453292F)); ++ } ++ ++ @Override ++ public boolean canSaveToDisk() { ++ return false; ++ } ++ ++ @Override ++ public void tick() { ++ if (dead || !valid) { ++ return; ++ } ++ ++ if (!leftOwner()) { ++ setLeftOwner(checkIfLeftOwner()); ++ } ++ ++ setFlag(6, isGlowing()); ++ entityBaseTick(); ++ ++ Vec3D mot = getMot(); ++ ++ MovingObjectPosition hitResult = ProjectileHelper.getHitResult(this, this::hitPredicate); ++ if (hitResult != null) { ++ onHit(hitResult); ++ } ++ ++ if (dead) { ++ return; ++ } ++ ++ double x = this.locX() + mot.x; ++ double y = this.locY() + mot.y; ++ double z = this.locZ() + mot.z; ++ setMot(mot.scale(0.99D)); ++ ++ Vec3D motDouble = mot.scale(2.0); ++ for (int i = 0; i < 5; i++) { ++ ((WorldServer) world).sendParticles(null, Particles.FLAME, ++ locX() + random.nextFloat() / 2 - 0.25F, ++ locY() + random.nextFloat() / 2 - 0.25F, ++ locZ() + random.nextFloat() / 2 - 0.25F, ++ 0, motDouble.getX(), motDouble.getY(), motDouble.getZ(), 0.1, true); ++ } ++ ++ if (world.a(getBoundingBox()).noneMatch(BlockBase.BlockData::isAir)) { ++ die(); ++ } else if (isInWaterOrBubbleColumn()) { ++ die(); ++ } else if (++ticksLived > 20) { ++ die(); ++ } else { ++ setMot(mot.scale(0.99D)); ++ if (!isNoGravity()) { ++ setMot(getMot().add(0.0D, -0.06D, 0.0D)); ++ } ++ setPosition(x, y, z); ++ } ++ } ++ ++ @Override ++ public void shoot(double x, double y, double z, float speed, float inaccuracy) { ++ setMot(new Vec3D(x, y, z).normalize().add( ++ random.nextGaussian() * (double) 0.0075F * (double) inaccuracy, ++ random.nextGaussian() * (double) 0.0075F * (double) inaccuracy, ++ random.nextGaussian() * (double) 0.0075F * (double) inaccuracy) ++ .scale(speed)); ++ } ++ ++ public void onHit(MovingObjectPosition rayTrace) { ++ CraftEventFactory.callProjectileHitEvent(this, rayTrace); ++ MovingObjectPosition.EnumMovingObjectType type = rayTrace.getType(); ++ if (type == MovingObjectPosition.EnumMovingObjectType.ENTITY) { ++ onHit((MovingObjectPositionEntity) rayTrace); ++ } else if (type == MovingObjectPosition.EnumMovingObjectType.BLOCK) { ++ onHit((MovingObjectPositionBlock) rayTrace); ++ } ++ } ++ ++ protected void onHit(MovingObjectPositionEntity rayTrace) { ++ Entity shooter = getShooter(); ++ if (shooter instanceof EntityLiving) { ++ Entity target = rayTrace.getEntity(); ++ if (canGrief || (target instanceof EntityLiving && !(target instanceof EntityArmorStand))) { ++ target.damageEntity(DamageSource.indirectMobAttack(this, (EntityLiving) shooter).setProjectile(), world.purpurConfig.phantomFlameDamage); ++ if (world.purpurConfig.phantomFlameFireTime > 0) { ++ target.setOnFire(world.purpurConfig.phantomFlameFireTime); ++ } ++ } ++ } ++ die(); ++ } ++ ++ protected void onHit(MovingObjectPositionBlock rayTrace) { ++ if (canGrief) { ++ IBlockData iblockdata = world.getType(rayTrace.getBlockPosition()); ++ iblockdata.a(world, iblockdata, rayTrace, this); ++ } ++ die(); ++ } ++} +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +index dee4d12a49468d38f077784b219199f0070786f2..dcdc82b42689b4962323938a62cf7ded49afd6f4 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +@@ -12,9 +12,6 @@ import net.minecraft.nbt.NBTBase; + import net.minecraft.nbt.NBTTagCompound; + import net.minecraft.network.chat.IChatBaseComponent; + import net.minecraft.server.level.EntityPlayer; +-import net.minecraft.server.level.PlayerChunk; +-import net.minecraft.server.level.PlayerChunkMap; +-import net.minecraft.server.level.TicketType; + import net.minecraft.world.damagesource.DamageSource; + import net.minecraft.world.entity.Entity; + import net.minecraft.world.entity.EntityAreaEffectCloud; +@@ -147,7 +144,6 @@ import net.minecraft.world.entity.vehicle.EntityMinecartHopper; + import net.minecraft.world.entity.vehicle.EntityMinecartMobSpawner; + import net.minecraft.world.entity.vehicle.EntityMinecartRideable; + import net.minecraft.world.entity.vehicle.EntityMinecartTNT; +-import net.minecraft.world.level.ChunkCoordIntPair; + import net.minecraft.world.phys.AxisAlignedBB; + import org.bukkit.Chunk; // Paper + import org.bukkit.EntityEffect; +@@ -1175,4 +1171,26 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { + return getHandle().isTicking(); + } + // Paper end ++ ++ // Purpur start ++ @Override ++ public org.bukkit.entity.Player getRider() { ++ return hasRider() ? (org.bukkit.entity.Player) getHandle().getPurpurRider().getBukkitEntity() : null; ++ } ++ ++ @Override ++ public boolean hasRider() { ++ return getHandle().hasPurpurRider(); ++ } ++ ++ @Override ++ public boolean isRidable() { ++ return getHandle().isRidable(); ++ } ++ ++ @Override ++ public boolean isRidableInWater() { ++ return getHandle().isRidableInWater(); ++ } ++ // Purpur end + } +diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +index a678277416cd71e01cd6980bcfaf9a9803e7ea17..c4218281721cf4a5b8f2cad5e12089e3aee89737 100644 +--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java ++++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +@@ -548,6 +548,18 @@ public class CraftEventFactory { + } + craftServer.getPluginManager().callEvent(event); + ++ // Purpur start ++ switch (action) { ++ case LEFT_CLICK_BLOCK: ++ case LEFT_CLICK_AIR: ++ who.processClick(EnumHand.MAIN_HAND); ++ break; ++ case RIGHT_CLICK_BLOCK: ++ case RIGHT_CLICK_AIR: ++ who.processClick(EnumHand.OFF_HAND); ++ } ++ // Purpur end ++ + return event; + } + +@@ -951,6 +963,7 @@ public class CraftEventFactory { + damageCause = DamageCause.ENTITY_EXPLOSION; + } + event = new EntityDamageByEntityEvent(damager.getBukkitEntity(), entity.getBukkitEntity(), damageCause, modifiers, modifierFunctions); ++ damager.processClick(EnumHand.MAIN_HAND); // Purpur + } + event.setCancelled(cancelled); + +@@ -1035,6 +1048,7 @@ public class CraftEventFactory { + if (!event.isCancelled()) { + event.getEntity().setLastDamageCause(event); + } ++ damager.getHandle().processClick(EnumHand.MAIN_HAND); // Purpur + return event; + } + +@@ -1084,6 +1098,7 @@ public class CraftEventFactory { + EntityDamageEvent event; + if (damager != null) { + event = new EntityDamageByEntityEvent(damager.getBukkitEntity(), damagee.getBukkitEntity(), cause, modifiers, modifierFunctions); ++ damager.processClick(EnumHand.MAIN_HAND); // Purpur + } else { + event = new EntityDamageEvent(damagee.getBukkitEntity(), cause, modifiers, modifierFunctions); + } diff --git a/patches/Purpur/patches/server/0101-Use-configured-height-for-nether-surface-builders.patch b/patches/Purpur/patches/server/0101-Use-configured-height-for-nether-surface-builders.patch new file mode 100644 index 00000000..a1b1edd8 --- /dev/null +++ b/patches/Purpur/patches/server/0101-Use-configured-height-for-nether-surface-builders.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sat, 15 Aug 2020 06:51:46 -0500 +Subject: [PATCH] Use configured height for nether surface builders + + +diff --git a/src/main/java/net/minecraft/world/level/levelgen/surfacebuilders/WorldGenSurfaceNetherAbstract.java b/src/main/java/net/minecraft/world/level/levelgen/surfacebuilders/WorldGenSurfaceNetherAbstract.java +index b9523f5611b5b8d786fddcc5fd265e8a2043ab6c..6c4707ce08f48da027b4430eee38bfe794c2625f 100644 +--- a/src/main/java/net/minecraft/world/level/levelgen/surfacebuilders/WorldGenSurfaceNetherAbstract.java ++++ b/src/main/java/net/minecraft/world/level/levelgen/surfacebuilders/WorldGenSurfaceNetherAbstract.java +@@ -42,7 +42,7 @@ public abstract class WorldGenSurfaceNetherAbstract extends WorldGenSurface= 0; --k2) { // Paper - fix MC-187716 - use configured height + blockposition_mutableblockposition.d(k1, k2, l1); diff --git a/patches/Purpur/patches/server/0102-Crying-obsidian-valid-for-portal-frames.patch b/patches/Purpur/patches/server/0102-Crying-obsidian-valid-for-portal-frames.patch new file mode 100644 index 00000000..bc274af4 --- /dev/null +++ b/patches/Purpur/patches/server/0102-Crying-obsidian-valid-for-portal-frames.patch @@ -0,0 +1,63 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Mon, 17 Aug 2020 17:34:33 -0500 +Subject: [PATCH] Crying obsidian valid for portal frames + + +diff --git a/src/main/java/net/minecraft/world/level/block/Block.java b/src/main/java/net/minecraft/world/level/block/Block.java +index cfdc602947548970b3fde00dd9fddf4e82c28841..4e0b88e26ad8017d93841c4149a1687c1db4ff0b 100644 +--- a/src/main/java/net/minecraft/world/level/block/Block.java ++++ b/src/main/java/net/minecraft/world/level/block/Block.java +@@ -140,6 +140,7 @@ public class Block extends BlockBase implements IMaterial { + return tag.isTagged(this); + } + ++ public boolean equals(Block block) { return a(block); } // Purpur - OBFHELPER + public boolean a(Block block) { + return this == block; + } +diff --git a/src/main/java/net/minecraft/world/level/block/state/BlockBase.java b/src/main/java/net/minecraft/world/level/block/state/BlockBase.java +index 0ea0a1fc5f4d879d48bbdf24731dabec10dbccd1..df595dc52858807479584ce8da49390a25695990 100644 +--- a/src/main/java/net/minecraft/world/level/block/state/BlockBase.java ++++ b/src/main/java/net/minecraft/world/level/block/state/BlockBase.java +@@ -742,6 +742,7 @@ public abstract class BlockBase { + } + + public final boolean isSameInstance(Block block) { return a(block); } // Paper - OBFHELPER ++ public boolean equals(Block block) { return a(block); } // Purpur - OBFHELPER + public boolean a(Block block) { + return this.getBlock().a(block); + } +diff --git a/src/main/java/net/minecraft/world/level/portal/BlockPortalShape.java b/src/main/java/net/minecraft/world/level/portal/BlockPortalShape.java +index 0bce061d5a0dd0fc08f0aa4d46ead9326beb4bc7..526ae936e6d4470efcf89c1b2892e90320c42201 100644 +--- a/src/main/java/net/minecraft/world/level/portal/BlockPortalShape.java ++++ b/src/main/java/net/minecraft/world/level/portal/BlockPortalShape.java +@@ -28,7 +28,7 @@ import org.bukkit.event.world.PortalCreateEvent; + public class BlockPortalShape { + + private static final BlockBase.e a = (iblockdata, iblockaccess, blockposition) -> { +- return iblockdata.a(Blocks.OBSIDIAN); ++ return iblockdata.equals(Blocks.OBSIDIAN) || (net.pl3x.purpur.PurpurConfig.cryingObsidianValidForPortalFrame && iblockdata.equals(Blocks.CRYING_OBSIDIAN)); // Purpur + }; + private final GeneratorAccess b; + private final EnumDirection.EnumAxis c; +diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java +index 65f436e0a27c8687180d7008dbff1cf8f667383c..318caff699e2a1656ef9428641f898f0508a1df7 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java +@@ -180,6 +180,7 @@ public class PurpurConfig { + public static boolean barrelSixRows = false; + public static boolean enderChestSixRows = false; + public static boolean enderChestPermissionRows = false; ++ public static boolean cryingObsidianValidForPortalFrame = false; + private static void blockSettings() { + if (version < 3) { + boolean oldValue = getBoolean("settings.barrel.packed-barrels", true); +@@ -194,6 +195,7 @@ public class PurpurConfig { + enderChestSixRows = getBoolean("settings.blocks.ender_chest.six-rows", enderChestSixRows); + InventoryType.ENDER_CHEST.setDefaultSize(enderChestSixRows ? 54 : 27); + enderChestPermissionRows = getBoolean("settings.blocks.ender_chest.use-permissions-for-rows", enderChestPermissionRows); ++ cryingObsidianValidForPortalFrame = getBoolean("settings.blocks.crying_obsidian.valid-for-portal-frame", cryingObsidianValidForPortalFrame); + } + + public static boolean endermanShortHeight = false; diff --git a/patches/Purpur/patches/server/0103-Entities-can-use-portals-configuration.patch b/patches/Purpur/patches/server/0103-Entities-can-use-portals-configuration.patch new file mode 100644 index 00000000..7259c7a2 --- /dev/null +++ b/patches/Purpur/patches/server/0103-Entities-can-use-portals-configuration.patch @@ -0,0 +1,48 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Mon, 17 Aug 2020 19:32:05 -0500 +Subject: [PATCH] Entities can use portals configuration + + +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index 6d17a5f75e073acccabbad65b998b4eb9e8cf400..e2de4d53e90b30f46a477c995505ac9f48cac842 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -2555,7 +2555,7 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, ne + public void d(BlockPosition blockposition) { + if (this.ai()) { + this.resetPortalCooldown(); +- } else { ++ } else if (world.purpurConfig.entitiesCanUsePortals || this instanceof EntityPlayer) { // Purpur + if (!this.world.isClientSide && !blockposition.equals(this.ac)) { + this.ac = blockposition.immutableCopy(); + } +@@ -3136,7 +3136,7 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, ne + } + + public boolean canPortal() { +- return isAlive() && valid; // Paper ++ return isAlive() && valid && (world.purpurConfig.entitiesCanUsePortals || this instanceof EntityPlayer); // Paper // Purpur + } + + public float a(Explosion explosion, IBlockAccess iblockaccess, BlockPosition blockposition, IBlockData iblockdata, Fluid fluid, float f) { +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 9fcc63a2f4a4c363ace85087665bf3a978d3d648..55366240f249c05cf3d40eaf29f2cd21cd86cd07 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -202,6 +202,7 @@ public class PurpurWorldConfig { + public boolean boatEjectPlayersOnLand = false; + public boolean disableDropsOnCrammingDeath = false; + public boolean entitiesPickUpLootBypassMobGriefing = false; ++ public boolean entitiesCanUsePortals = true; + public boolean milkCuresBadOmen = true; + public double tridentLoyaltyVoidReturnHeight = 0.0D; + public double voidDamageHeight = -64.0D; +@@ -211,6 +212,7 @@ public class PurpurWorldConfig { + boatEjectPlayersOnLand = getBoolean("gameplay-mechanics.boat.eject-players-on-land", boatEjectPlayersOnLand); + disableDropsOnCrammingDeath = getBoolean("gameplay-mechanics.disable-drops-on-cramming-death", disableDropsOnCrammingDeath); + entitiesPickUpLootBypassMobGriefing = getBoolean("gameplay-mechanics.entities-pick-up-loot-bypass-mob-griefing", entitiesPickUpLootBypassMobGriefing); ++ entitiesCanUsePortals = getBoolean("gameplay-mechanics.entities-can-use-portals", entitiesCanUsePortals); + milkCuresBadOmen = getBoolean("gameplay-mechanics.milk-cures-bad-omen", milkCuresBadOmen); + tridentLoyaltyVoidReturnHeight = getDouble("gameplay-mechanics.trident-loyalty-void-return-height", tridentLoyaltyVoidReturnHeight); + voidDamageHeight = getDouble("gameplay-mechanics.void-damage-height", voidDamageHeight); diff --git a/patches/Purpur/patches/server/0104-LivingEntity-broadcastItemBreak.patch b/patches/Purpur/patches/server/0104-LivingEntity-broadcastItemBreak.patch new file mode 100644 index 00000000..eeb55649 --- /dev/null +++ b/patches/Purpur/patches/server/0104-LivingEntity-broadcastItemBreak.patch @@ -0,0 +1,22 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Mon, 17 Aug 2020 21:50:39 -0500 +Subject: [PATCH] LivingEntity#broadcastItemBreak + + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +index 75af4d5385d4366e562a53716e020ba20ccbea94..411a84840764ce6f7a83e11655cc04403d6ee5ee 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +@@ -886,5 +886,11 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { + public void setSafeFallDistance(float safeFallDistance) { + getHandle().safeFallDistance = safeFallDistance; + } ++ ++ @Override ++ public void broadcastItemBreak(org.bukkit.inventory.EquipmentSlot slot) { ++ if (slot == null) return; ++ getHandle().broadcastItemBreak(org.bukkit.craftbukkit.CraftEquipmentSlot.getNMS(slot)); ++ } + // Purpur end + } diff --git a/patches/Purpur/patches/server/0105-Customizable-wither-health-and-healing.patch b/patches/Purpur/patches/server/0105-Customizable-wither-health-and-healing.patch new file mode 100644 index 00000000..08e25ec5 --- /dev/null +++ b/patches/Purpur/patches/server/0105-Customizable-wither-health-and-healing.patch @@ -0,0 +1,71 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: jmp +Date: Thu, 20 Aug 2020 17:38:12 -0700 +Subject: [PATCH] Customizable wither health and healing + +Adds the ability to customize the health of the wither, as well as the amount that it heals, and how often. + +diff --git a/src/main/java/net/minecraft/world/entity/boss/wither/EntityWither.java b/src/main/java/net/minecraft/world/entity/boss/wither/EntityWither.java +index 9ffac9aa79dee1b6dd6eeb8483b5a81416c11d9b..528161748472b0fb84718268800864e94ceaa079 100644 +--- a/src/main/java/net/minecraft/world/entity/boss/wither/EntityWither.java ++++ b/src/main/java/net/minecraft/world/entity/boss/wither/EntityWither.java +@@ -205,6 +205,11 @@ public class EntityWither extends EntityMonster implements IRangedEntity { + skull.setPositionRaw(headX, headY, headZ); + world.addEntity(skull); + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(world.purpurConfig.witherMaxHealth); ++ } + // Purpur end + + @Override +@@ -409,7 +414,7 @@ public class EntityWither extends EntityMonster implements IRangedEntity { + + this.setInvul(i); + if (this.ticksLived % 10 == 0) { +- this.heal(10.0F, EntityRegainHealthEvent.RegainReason.WITHER_SPAWN); // CraftBukkit ++ this.heal(this.getMaxHealth() / 33, EntityRegainHealthEvent.RegainReason.WITHER_SPAWN); // CraftBukkit // Purpur - use max health for healing instead of a constant + } + + } else { +@@ -518,8 +523,10 @@ public class EntityWither extends EntityMonster implements IRangedEntity { + } + } + +- if (this.ticksLived % 20 == 0) { +- this.heal(1.0F, EntityRegainHealthEvent.RegainReason.REGEN); // CraftBukkit ++ // Purpur start - customizable heal rate and amount ++ if (this.ticksLived % world.purpurConfig.witherHealthRegenDelay == 0) { ++ this.heal(world.purpurConfig.witherHealthRegenAmount, EntityRegainHealthEvent.RegainReason.REGEN); // CraftBukkit ++ // Purpur end + } + + //this.bossBattle.setProgress(this.getHealth() / this.getMaxHealth()); // Paper - Moved down +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 55366240f249c05cf3d40eaf29f2cd21cd86cd07..db9deac5b43626b264f1237d8a2d2535d7bb639b 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -979,10 +979,21 @@ public class PurpurWorldConfig { + public boolean witherRidable = false; + public boolean witherRidableInWater = false; + public double witherMaxY = 256D; ++ public float witherHealthRegenAmount = 1.0f; ++ public int witherHealthRegenDelay = 20; ++ public double witherMaxHealth = 300.0D; + private void witherSettings() { + witherRidable = getBoolean("mobs.wither.ridable", witherRidable); + witherRidableInWater = getBoolean("mobs.wither.ridable-in-water", witherRidableInWater); + witherMaxY = getDouble("mobs.wither.ridable-max-y", witherMaxY); ++ witherHealthRegenAmount = (float) getDouble("mobs.wither.health-regen-amount", witherHealthRegenAmount); ++ witherHealthRegenDelay = getInt("mobs.wither.health-regen-delay", witherHealthRegenDelay); ++ if (PurpurConfig.version < 8) { ++ double oldValue = getDouble("mobs.wither.max-health", witherMaxHealth); ++ set("mobs.wither.attributes.max-health", oldValue); ++ set("mobs.wither.max-health", null); ++ } ++ witherMaxHealth = getDouble("mobs.wither.attributes.max-health", witherMaxHealth); + } + + public boolean witherSkeletonRidable = false; diff --git a/patches/Purpur/patches/server/0106-Allow-toggling-special-MobSpawners-per-world.patch b/patches/Purpur/patches/server/0106-Allow-toggling-special-MobSpawners-per-world.patch new file mode 100644 index 00000000..5a9411e2 --- /dev/null +++ b/patches/Purpur/patches/server/0106-Allow-toggling-special-MobSpawners-per-world.patch @@ -0,0 +1,176 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: jmp +Date: Sat, 22 Aug 2020 20:47:11 -0700 +Subject: [PATCH] Allow toggling special MobSpawners per world + +In vanilla, these are all hardcoded on for world type 0 (overworld) and hardcoded off for every other world type. Default config behaviour matches this. + +diff --git a/src/main/java/net/minecraft/server/level/WorldServer.java b/src/main/java/net/minecraft/server/level/WorldServer.java +index 08e4fab02a740bf0c30985e2a858da2ae2caf8d8..d4df33c7cb47c10987431b7c863d429d2a9e82bc 100644 +--- a/src/main/java/net/minecraft/server/level/WorldServer.java ++++ b/src/main/java/net/minecraft/server/level/WorldServer.java +@@ -92,6 +92,7 @@ import net.minecraft.world.entity.EnumCreatureType; + import net.minecraft.world.entity.ReputationHandler; + import net.minecraft.world.entity.ai.navigation.NavigationAbstract; + import net.minecraft.world.entity.ai.village.ReputationEvent; ++import net.minecraft.world.entity.ai.village.VillageSiege; + import net.minecraft.world.entity.ai.village.poi.VillagePlace; + import net.minecraft.world.entity.ai.village.poi.VillagePlaceType; + import net.minecraft.world.entity.animal.EntityAnimal; +@@ -101,6 +102,8 @@ import net.minecraft.world.entity.animal.horse.EntityHorseSkeleton; + import net.minecraft.world.entity.boss.EntityComplexPart; + import net.minecraft.world.entity.boss.enderdragon.EntityEnderDragon; + import net.minecraft.world.entity.item.EntityItem; ++import net.minecraft.world.entity.npc.MobSpawnerCat; ++import net.minecraft.world.entity.npc.MobSpawnerTrader; + import net.minecraft.world.entity.npc.NPC; + import net.minecraft.world.entity.player.EntityHuman; + import net.minecraft.world.entity.raid.PersistentRaid; +@@ -133,6 +136,8 @@ import net.minecraft.world.level.chunk.storage.RegionFile; + import net.minecraft.world.level.dimension.DimensionManager; + import net.minecraft.world.level.dimension.end.EnderDragonBattle; + import net.minecraft.world.level.levelgen.HeightMap; ++import net.minecraft.world.level.levelgen.MobSpawnerPatrol; ++import net.minecraft.world.level.levelgen.MobSpawnerPhantom; + import net.minecraft.world.level.levelgen.feature.StructureGenerator; + import net.minecraft.world.level.levelgen.structure.StructureBoundingBox; + import net.minecraft.world.level.levelgen.structure.StructureStart; +@@ -550,7 +555,24 @@ public class WorldServer extends World implements GeneratorAccessSeed { + this.L = new ObjectLinkedOpenHashSet(); + this.Q = flag1; + this.server = minecraftserver; +- this.mobSpawners = list; ++ // Purpur start - enable/disable MobSpawners per world ++ this.mobSpawners = new java.util.ArrayList<>(); ++ if (purpurConfig.phantomSpawning) { ++ mobSpawners.add(new MobSpawnerPhantom()); ++ } ++ if (purpurConfig.patrolSpawning) { ++ mobSpawners.add(new MobSpawnerPatrol()); ++ } ++ if (purpurConfig.catSpawning) { ++ mobSpawners.add(new MobSpawnerCat()); ++ } ++ if (purpurConfig.villageSiegeSpawning) { ++ mobSpawners.add(new VillageSiege()); ++ } ++ if (purpurConfig.villagerTraderSpawning) { ++ mobSpawners.add(new MobSpawnerTrader(iworlddataserver)); ++ } ++ // Purpur end + // CraftBukkit start + this.worldDataServer = (WorldDataServer) iworlddataserver; + worldDataServer.world = this; +diff --git a/src/main/java/net/minecraft/world/entity/npc/MobSpawnerTrader.java b/src/main/java/net/minecraft/world/entity/npc/MobSpawnerTrader.java +index 7c8a2151be8a0f48cba1c15d231d5dbdb500b4d6..361771fc4fcf16b1b013c550734019535cef2924 100644 +--- a/src/main/java/net/minecraft/world/entity/npc/MobSpawnerTrader.java ++++ b/src/main/java/net/minecraft/world/entity/npc/MobSpawnerTrader.java +@@ -5,6 +5,7 @@ import java.util.Optional; + import java.util.Random; + import javax.annotation.Nullable; + import net.minecraft.core.BlockPosition; ++import net.minecraft.core.EnumDirection; + import net.minecraft.nbt.NBTTagCompound; + import net.minecraft.network.chat.IChatBaseComponent; + import net.minecraft.server.level.EntityPlayer; +@@ -153,7 +154,17 @@ public class MobSpawnerTrader implements MobSpawner { + int k = blockposition.getX() + this.a.nextInt(i * 2) - i; + int l = blockposition.getZ() + this.a.nextInt(i * 2) - i; + int i1 = iworldreader.a(HeightMap.Type.WORLD_SURFACE, k, l); +- BlockPosition blockposition2 = new BlockPosition(k, i1, l); ++ // Purpur start - allow traders to spawn below nether roof ++ BlockPosition.MutableBlockPosition blockposition2 = new BlockPosition.MutableBlockPosition(k, i1, l); ++ if (iworldreader.getDimensionManager().hasCeiling()) { ++ do { ++ blockposition2.c(EnumDirection.DOWN); ++ } while (!iworldreader.getType(blockposition2).isAir()); ++ do { ++ blockposition2.c(EnumDirection.DOWN); ++ } while (iworldreader.getType(blockposition2).isAir() && blockposition2.getY() > 0); ++ } ++ // Purpur end + + if (SpawnerCreature.a(EntityPositionTypes.Surface.ON_GROUND, iworldreader, blockposition2, EntityTypes.WANDERING_TRADER)) { + blockposition1 = blockposition2; +diff --git a/src/main/java/net/minecraft/world/level/World.java b/src/main/java/net/minecraft/world/level/World.java +index b6b4e759975776afcb9d33e650774b9e30d7eb96..a3215b1cccf4d00de888ca4696c03ffb6adf7041 100644 +--- a/src/main/java/net/minecraft/world/level/World.java ++++ b/src/main/java/net/minecraft/world/level/World.java +@@ -255,7 +255,7 @@ public abstract class World implements GeneratorAccess, AutoCloseable { + this.paperConfig = new com.destroystokyo.paper.PaperWorldConfig(((net.minecraft.world.level.storage.WorldDataServer) worlddatamutable).getName(), this.spigotConfig); // Paper + this.chunkPacketBlockController = this.paperConfig.antiXray ? new ChunkPacketBlockControllerAntiXray(this, executor) : ChunkPacketBlockController.NO_OPERATION_INSTANCE; // Paper - Anti-Xray + this.tuinityConfig = new com.tuinity.tuinity.config.TuinityConfig.WorldConfig(((net.minecraft.world.level.storage.WorldDataServer)worlddatamutable).getName()); // Tuinity - Server Config +- this.purpurConfig = new net.pl3x.purpur.PurpurWorldConfig((((net.minecraft.world.level.storage.WorldDataServer)worlddatamutable).getName())); // Purpur ++ this.purpurConfig = new net.pl3x.purpur.PurpurWorldConfig((((net.minecraft.world.level.storage.WorldDataServer)worlddatamutable).getName()), env); // Purpur + this.generator = gen; + this.world = new CraftWorld((WorldServer) this, gen, env); + this.ticksPerAnimalSpawns = this.getServer().getTicksPerAnimalSpawns(); // CraftBukkit +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index db9deac5b43626b264f1237d8a2d2535d7bb639b..63cf32fe3359eb00f5e526689a9b10f673911a86 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -7,6 +7,8 @@ import net.minecraft.world.level.block.Blocks; + import net.minecraft.world.item.Item; + import net.minecraft.world.item.Items; + import net.minecraft.resources.MinecraftKey; ++import org.apache.commons.lang3.BooleanUtils; ++import org.bukkit.World; + import org.bukkit.configuration.ConfigurationSection; + + import java.util.ArrayList; +@@ -15,6 +17,7 @@ import java.util.HashSet; + import java.util.List; + import java.util.Map; + import java.util.Set; ++import java.util.function.Predicate; + import java.util.logging.Level; + + import static net.pl3x.purpur.PurpurConfig.log; +@@ -22,9 +25,11 @@ import static net.pl3x.purpur.PurpurConfig.log; + public class PurpurWorldConfig { + + private final String worldName; ++ private final World.Environment environment; + +- public PurpurWorldConfig(String worldName) { ++ public PurpurWorldConfig(String worldName, World.Environment environment) { + this.worldName = worldName; ++ this.environment = environment; + init(); + } + +@@ -52,6 +57,12 @@ public class PurpurWorldConfig { + return PurpurConfig.config.getBoolean("world-settings." + worldName + "." + path, PurpurConfig.config.getBoolean("world-settings.default." + path)); + } + ++ private boolean getBoolean(String path, Predicate predicate) { ++ String val = getString(path, "default").toLowerCase(); ++ Boolean bool = BooleanUtils.toBooleanObject(val, "true", "false", "default"); ++ return predicate.test(bool); ++ } ++ + private double getDouble(String path, double def) { + PurpurConfig.config.addDefault("world-settings.default." + path, def); + return PurpurConfig.config.getDouble("world-settings." + worldName + "." + path, PurpurConfig.config.getDouble("world-settings.default." + path)); +@@ -219,6 +230,21 @@ public class PurpurWorldConfig { + voidDamageDealt = getDouble("gameplay-mechanics.void-damage-dealt", voidDamageDealt); + } + ++ public boolean catSpawning; ++ public boolean patrolSpawning; ++ public boolean phantomSpawning; ++ public boolean villagerTraderSpawning; ++ public boolean villageSiegeSpawning; ++ private void mobSpawnerSettings() { ++ // values of "default" or null will default to true only if the world environment is normal (aka overworld) ++ Predicate predicate = (bool) -> (bool != null && bool) || (bool == null && environment == World.Environment.NORMAL); ++ catSpawning = getBoolean("gameplay-mechanics.mob-spawning.village-cats", predicate); ++ patrolSpawning = getBoolean("gameplay-mechanics.mob-spawning.raid-patrols", predicate); ++ phantomSpawning = getBoolean("gameplay-mechanics.mob-spawning.phantoms", predicate); ++ villagerTraderSpawning = getBoolean("gameplay-mechanics.mob-spawning.wandering-traders", predicate); ++ villageSiegeSpawning = getBoolean("gameplay-mechanics.mob-spawning.village-sieges", predicate); ++ } ++ + public int elytraDamagePerSecond = 1; + public double elytraDamageMultiplyBySpeed = 0; + public boolean elytraIgnoreUnbreaking = false; diff --git a/patches/Purpur/patches/server/0107-Raid-cooldown-setting.patch b/patches/Purpur/patches/server/0107-Raid-cooldown-setting.patch new file mode 100644 index 00000000..06c3376f --- /dev/null +++ b/patches/Purpur/patches/server/0107-Raid-cooldown-setting.patch @@ -0,0 +1,73 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: jmp +Date: Thu, 27 Aug 2020 13:48:52 -0700 +Subject: [PATCH] Raid cooldown setting + + +diff --git a/src/main/java/net/minecraft/world/entity/raid/PersistentRaid.java b/src/main/java/net/minecraft/world/entity/raid/PersistentRaid.java +index c939ca087af4588e14669a2d53d7c116dcb59f16..11271762dcf5783c3179de1afc6a882c5330b4dd 100644 +--- a/src/main/java/net/minecraft/world/entity/raid/PersistentRaid.java ++++ b/src/main/java/net/minecraft/world/entity/raid/PersistentRaid.java +@@ -27,6 +27,7 @@ import net.minecraft.world.phys.Vec3D; + + public class PersistentRaid extends PersistentBase { + ++ public final Map playerCooldowns = new java.util.HashMap<>(); // Purpur + public final Map raids = Maps.newHashMap(); + private final WorldServer b; + private int c; +@@ -45,6 +46,17 @@ public class PersistentRaid extends PersistentBase { + + public void a() { + ++this.d; ++ // Purpur start ++ if (b.purpurConfig.raidCooldownSeconds != 0 && this.d % 20 == 0) { ++ com.google.common.collect.ImmutableMap.copyOf(playerCooldowns).forEach((id, i) -> { ++ if (i < 1) { ++ playerCooldowns.remove(id); ++ } else { ++ playerCooldowns.put(id, i - 1); ++ } ++ }); ++ } ++ // Purpur end + Iterator iterator = this.raids.values().iterator(); + + while (iterator.hasNext()) { +@@ -128,10 +140,15 @@ public class PersistentRaid extends PersistentBase { + + if (flag) { + // CraftBukkit start +- if (!org.bukkit.craftbukkit.event.CraftEventFactory.callRaidTriggerEvent(raid, entityplayer)) { ++ if ((b.purpurConfig.raidCooldownSeconds != 0 && playerCooldowns.containsKey(entityplayer.getUniqueID())) || !org.bukkit.craftbukkit.event.CraftEventFactory.callRaidTriggerEvent(raid, entityplayer)) { // Purpur + entityplayer.removeEffect(MobEffects.BAD_OMEN); + return null; + } ++ // Purpur start ++ if (b.purpurConfig.raidCooldownSeconds != 0) { ++ playerCooldowns.put(entityplayer.getUniqueID(), b.purpurConfig.raidCooldownSeconds); ++ } ++ // Purpur end + + if (!this.raids.containsKey(raid.getId())) { + this.raids.put(raid.getId(), raid); +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 63cf32fe3359eb00f5e526689a9b10f673911a86..1e0af82c74259783fdc86a7824b18ff1d14fe938 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -218,6 +218,7 @@ public class PurpurWorldConfig { + public double tridentLoyaltyVoidReturnHeight = 0.0D; + public double voidDamageHeight = -64.0D; + public double voidDamageDealt = 4.0D; ++ public int raidCooldownSeconds = 0; + private void miscGameplayMechanicsSettings() { + useBetterMending = getBoolean("gameplay-mechanics.use-better-mending", useBetterMending); + boatEjectPlayersOnLand = getBoolean("gameplay-mechanics.boat.eject-players-on-land", boatEjectPlayersOnLand); +@@ -228,6 +229,7 @@ public class PurpurWorldConfig { + tridentLoyaltyVoidReturnHeight = getDouble("gameplay-mechanics.trident-loyalty-void-return-height", tridentLoyaltyVoidReturnHeight); + voidDamageHeight = getDouble("gameplay-mechanics.void-damage-height", voidDamageHeight); + voidDamageDealt = getDouble("gameplay-mechanics.void-damage-dealt", voidDamageDealt); ++ raidCooldownSeconds = getInt("gameplay-mechanics.raid-cooldown-seconds", raidCooldownSeconds); + } + + public boolean catSpawning; diff --git a/patches/Purpur/patches/server/0108-Despawn-rate-config-options-per-projectile-type.patch b/patches/Purpur/patches/server/0108-Despawn-rate-config-options-per-projectile-type.patch new file mode 100644 index 00000000..c585d886 --- /dev/null +++ b/patches/Purpur/patches/server/0108-Despawn-rate-config-options-per-projectile-type.patch @@ -0,0 +1,343 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: jmp +Date: Mon, 14 Sep 2020 10:09:05 -0700 +Subject: [PATCH] Despawn rate config options per projectile type + +Default values of -1 respect vanilla behaviour. + +diff --git a/src/main/java/net/minecraft/world/entity/projectile/EntityArrow.java b/src/main/java/net/minecraft/world/entity/projectile/EntityArrow.java +index 42c1a7e8d51868c74e92d97f1df8d36fcaab6252..5775a28cb9d94b94b6e6bbc810fe31260810632e 100644 +--- a/src/main/java/net/minecraft/world/entity/projectile/EntityArrow.java ++++ b/src/main/java/net/minecraft/world/entity/projectile/EntityArrow.java +@@ -61,7 +61,7 @@ public abstract class EntityArrow extends IProjectile { + protected int c; + public EntityArrow.PickupStatus fromPlayer; + public int shake; +- public int despawnCounter; ++ //public int despawnCounter; // Purpur - moved to IProjectile + private double damage; + public int knockbackStrength; + private SoundEffect ak; +@@ -293,13 +293,23 @@ public abstract class EntityArrow extends IProjectile { + + } + +- protected final void tickDespawnCounter() { this.h(); } // Paper - OBFHELPER +- protected void h() { +- ++this.despawnCounter; +- if (this.despawnCounter >= (fromPlayer == PickupStatus.CREATIVE_ONLY ? world.paperConfig.creativeArrowDespawnRate : (fromPlayer == PickupStatus.DISALLOWED ? world.paperConfig.nonPlayerArrowDespawnRate : ((this instanceof EntityThrownTrident) ? world.spigotConfig.tridentDespawnRate : world.spigotConfig.arrowDespawnRate)))) { // Spigot // Paper - TODO: Extract this to init? +- this.die(); ++ // Purpur start ++ protected int getPurpurDespawnRate() { ++ if (fromPlayer == PickupStatus.CREATIVE_ONLY) { ++ return world.paperConfig.creativeArrowDespawnRate; ++ } ++ if (fromPlayer == PickupStatus.DISALLOWED) { ++ return world.paperConfig.nonPlayerArrowDespawnRate; ++ } ++ if (this instanceof EntityThrownTrident) { ++ return world.spigotConfig.tridentDespawnRate; + } ++ return world.spigotConfig.arrowDespawnRate; ++ } ++ // Purpur end + ++ protected void h() { ++ tickDespawnCounter(); // Purpur + } + + private void A() { +diff --git a/src/main/java/net/minecraft/world/entity/projectile/EntityDragonFireball.java b/src/main/java/net/minecraft/world/entity/projectile/EntityDragonFireball.java +index 27853f510e15e40c66da2cb4905c43f5e8f99d3d..98dcfedc8826ebb067438be713549e2cfb19ebb0 100644 +--- a/src/main/java/net/minecraft/world/entity/projectile/EntityDragonFireball.java ++++ b/src/main/java/net/minecraft/world/entity/projectile/EntityDragonFireball.java +@@ -87,4 +87,11 @@ public class EntityDragonFireball extends EntityFireball { + protected boolean W_() { + return false; + } ++ ++ // Purpur start ++ @Override ++ protected int getPurpurDespawnRate() { ++ return this.world.purpurConfig.dragonFireballDespawnRate; ++ } ++ // Purpur end + } +diff --git a/src/main/java/net/minecraft/world/entity/projectile/EntityEgg.java b/src/main/java/net/minecraft/world/entity/projectile/EntityEgg.java +index dc2e51718395494f60b0376d65d496daf2f76e71..d97511c27ff376b2dd0fbedb227f9a0c337a1264 100644 +--- a/src/main/java/net/minecraft/world/entity/projectile/EntityEgg.java ++++ b/src/main/java/net/minecraft/world/entity/projectile/EntityEgg.java +@@ -99,4 +99,11 @@ public class EntityEgg extends EntityProjectileThrowable { + protected Item getDefaultItem() { + return Items.EGG; + } ++ ++ // Purpur start ++ @Override ++ protected int getPurpurDespawnRate() { ++ return this.world.purpurConfig.eggDespawnRate; ++ } ++ // Purpur end + } +diff --git a/src/main/java/net/minecraft/world/entity/projectile/EntityEnderPearl.java b/src/main/java/net/minecraft/world/entity/projectile/EntityEnderPearl.java +index efdf5bc4f07231690c680429b3f77bd07970eee0..cf2c691357c41a7e7044f7a719144db2ffab5dbe 100644 +--- a/src/main/java/net/minecraft/world/entity/projectile/EntityEnderPearl.java ++++ b/src/main/java/net/minecraft/world/entity/projectile/EntityEnderPearl.java +@@ -122,4 +122,11 @@ public class EntityEnderPearl extends EntityProjectileThrowable { + + return super.b(worldserver); + } ++ ++ // Purpur start ++ @Override ++ protected int getPurpurDespawnRate() { ++ return this.world.purpurConfig.enderPearlDespawnRate; ++ } ++ // Purpur end + } +diff --git a/src/main/java/net/minecraft/world/entity/projectile/EntityFireworks.java b/src/main/java/net/minecraft/world/entity/projectile/EntityFireworks.java +index ca7a10c4b04766d7eb55be9252e96ef939e76df3..6a6ed24640c152bd5d6637b30ccce3efdf8a4856 100644 +--- a/src/main/java/net/minecraft/world/entity/projectile/EntityFireworks.java ++++ b/src/main/java/net/minecraft/world/entity/projectile/EntityFireworks.java +@@ -323,4 +323,11 @@ public class EntityFireworks extends IProjectile { + public Packet P() { + return new PacketPlayOutSpawnEntity(this); + } ++ ++ // Purpur start ++ @Override ++ protected int getPurpurDespawnRate() { ++ return this.world.purpurConfig.fireworkDespawnRate; ++ } ++ // Purpur end + } +diff --git a/src/main/java/net/minecraft/world/entity/projectile/EntityFishingHook.java b/src/main/java/net/minecraft/world/entity/projectile/EntityFishingHook.java +index 45f0f004e97b20e5c6c5b1f205b088bf8aa86017..242ba2c1feb07f9e582a722f34e6362dd84f27cc 100644 +--- a/src/main/java/net/minecraft/world/entity/projectile/EntityFishingHook.java ++++ b/src/main/java/net/minecraft/world/entity/projectile/EntityFishingHook.java +@@ -615,4 +615,11 @@ public class EntityFishingHook extends IProjectile { + + private HookState() {} + } ++ ++ // Purpur start ++ @Override ++ protected int getPurpurDespawnRate() { ++ return this.world.purpurConfig.fishingHookDespawnRate; ++ } ++ // Purpur end + } +diff --git a/src/main/java/net/minecraft/world/entity/projectile/EntityLargeFireball.java b/src/main/java/net/minecraft/world/entity/projectile/EntityLargeFireball.java +index cf2663d9883654f53b327246d85ee63c3990cd71..e860737bacfea0a1d728dbaaf41d62165658ad89 100644 +--- a/src/main/java/net/minecraft/world/entity/projectile/EntityLargeFireball.java ++++ b/src/main/java/net/minecraft/world/entity/projectile/EntityLargeFireball.java +@@ -77,4 +77,11 @@ public class EntityLargeFireball extends EntityFireballFireball { + } + + } ++ ++ // Purpur start ++ @Override ++ protected int getPurpurDespawnRate() { ++ return this.world.purpurConfig.largeFireballDespawnRate; ++ } ++ // Purpur end + } +diff --git a/src/main/java/net/minecraft/world/entity/projectile/EntityLlamaSpit.java b/src/main/java/net/minecraft/world/entity/projectile/EntityLlamaSpit.java +index 6f497fc1b1eb33d0d9dfb0dc014b25b7eeb0dfac..56de41fc11720f4a37ee4e1e7cbec1b2dbe3ab76 100644 +--- a/src/main/java/net/minecraft/world/entity/projectile/EntityLlamaSpit.java ++++ b/src/main/java/net/minecraft/world/entity/projectile/EntityLlamaSpit.java +@@ -86,4 +86,11 @@ public class EntityLlamaSpit extends IProjectile { + public Packet P() { + return new PacketPlayOutSpawnEntity(this); + } ++ ++ // Purpur start ++ @Override ++ protected int getPurpurDespawnRate() { ++ return this.world.purpurConfig.llamaSpitDespawnRate; ++ } ++ // Purpur end + } +diff --git a/src/main/java/net/minecraft/world/entity/projectile/EntityPotion.java b/src/main/java/net/minecraft/world/entity/projectile/EntityPotion.java +index 9348288fb752e758fe7aee8c2a630ea0fb7b9a8c..fa2a4f9e9c0364893abf83ffc627f33b198b2e81 100644 +--- a/src/main/java/net/minecraft/world/entity/projectile/EntityPotion.java ++++ b/src/main/java/net/minecraft/world/entity/projectile/EntityPotion.java +@@ -283,4 +283,11 @@ public class EntityPotion extends EntityProjectileThrowable { + } + + } ++ ++ // Purpur start ++ @Override ++ protected int getPurpurDespawnRate() { ++ return this.world.purpurConfig.potionDespawnRate; ++ } ++ // Purpur end + } +diff --git a/src/main/java/net/minecraft/world/entity/projectile/EntityShulkerBullet.java b/src/main/java/net/minecraft/world/entity/projectile/EntityShulkerBullet.java +index 24076f3de298173e293507f2024105532f833455..96c609aa888b4fb83db6eddba259bd553fe0dd0a 100644 +--- a/src/main/java/net/minecraft/world/entity/projectile/EntityShulkerBullet.java ++++ b/src/main/java/net/minecraft/world/entity/projectile/EntityShulkerBullet.java +@@ -337,4 +337,11 @@ public class EntityShulkerBullet extends IProjectile { + public Packet P() { + return new PacketPlayOutSpawnEntity(this); + } ++ ++ // Purpur start ++ @Override ++ protected int getPurpurDespawnRate() { ++ return this.world.purpurConfig.shulkerBulletDespawnRate; ++ } ++ // Purpur end + } +diff --git a/src/main/java/net/minecraft/world/entity/projectile/EntitySmallFireball.java b/src/main/java/net/minecraft/world/entity/projectile/EntitySmallFireball.java +index d139c5806e5971e82865c2ce627e87c631e42d7a..bf747cbf6e1ef9ea9d1d41d0441b29a46ce874c0 100644 +--- a/src/main/java/net/minecraft/world/entity/projectile/EntitySmallFireball.java ++++ b/src/main/java/net/minecraft/world/entity/projectile/EntitySmallFireball.java +@@ -100,4 +100,11 @@ public class EntitySmallFireball extends EntityFireballFireball { + public boolean damageEntity(DamageSource damagesource, float f) { + return false; + } ++ ++ // Purpur start ++ @Override ++ protected int getPurpurDespawnRate() { ++ return this.world.purpurConfig.smallFireballDespawnRate; ++ } ++ // Purpur end + } +diff --git a/src/main/java/net/minecraft/world/entity/projectile/EntitySnowball.java b/src/main/java/net/minecraft/world/entity/projectile/EntitySnowball.java +index 3ec380ec35fade3bcc61c5f45cee651eb45ae073..0d3b9c81e47eef645335e49a1d6d88db7338aa4b 100644 +--- a/src/main/java/net/minecraft/world/entity/projectile/EntitySnowball.java ++++ b/src/main/java/net/minecraft/world/entity/projectile/EntitySnowball.java +@@ -25,6 +25,12 @@ public class EntitySnowball extends EntityProjectileThrowable { + super(EntityTypes.SNOWBALL, d0, d1, d2, world); + } + ++ // Purpur start ++ protected int getPurpurDespawnRate() { ++ return world.purpurConfig.snowballDespawnRate; ++ } ++ // Purpur end ++ + @Override + protected Item getDefaultItem() { + return Items.SNOWBALL; +diff --git a/src/main/java/net/minecraft/world/entity/projectile/EntityThrownExpBottle.java b/src/main/java/net/minecraft/world/entity/projectile/EntityThrownExpBottle.java +index e07353a6b34196e3d275ba482fbef7e4d209c31d..6ef87bd6969603a51f09034ad87b89ab8a25eadb 100644 +--- a/src/main/java/net/minecraft/world/entity/projectile/EntityThrownExpBottle.java ++++ b/src/main/java/net/minecraft/world/entity/projectile/EntityThrownExpBottle.java +@@ -61,4 +61,11 @@ public class EntityThrownExpBottle extends EntityProjectileThrowable { + } + + } ++ ++ // Purpur start ++ @Override ++ protected int getPurpurDespawnRate() { ++ return this.world.purpurConfig.expBottleDespawnRate; ++ } ++ // Purpur end + } +diff --git a/src/main/java/net/minecraft/world/entity/projectile/EntityWitherSkull.java b/src/main/java/net/minecraft/world/entity/projectile/EntityWitherSkull.java +index 021a7e31dc3650c0c404a893374528e6a63dfbad..2fe0e32a1158cccb3060f5a986c9fc41a0237aa8 100644 +--- a/src/main/java/net/minecraft/world/entity/projectile/EntityWitherSkull.java ++++ b/src/main/java/net/minecraft/world/entity/projectile/EntityWitherSkull.java +@@ -137,4 +137,11 @@ public class EntityWitherSkull extends EntityFireball { + protected boolean W_() { + return false; + } ++ ++ // Purpur start ++ @Override ++ protected int getPurpurDespawnRate() { ++ return this.world.purpurConfig.witherSkullDespawnRate; ++ } ++ // Purpur end + } +diff --git a/src/main/java/net/minecraft/world/entity/projectile/IProjectile.java b/src/main/java/net/minecraft/world/entity/projectile/IProjectile.java +index 390023a7a825eed850a13572b719f47ed534c003..8df2b646df701b4d21f956b9870d7c09c13e2b6d 100644 +--- a/src/main/java/net/minecraft/world/entity/projectile/IProjectile.java ++++ b/src/main/java/net/minecraft/world/entity/projectile/IProjectile.java +@@ -25,6 +25,7 @@ public abstract class IProjectile extends Entity { + private UUID shooter; + private int c; + private boolean d; public boolean leftOwner() { return d; } public void setLeftOwner(boolean leftOwner) { this.d = leftOwner; } // Purpur - OBFHELPER ++ public int despawnCounter; // Purpur - moved from EntityArrow + + // CraftBukkit start + private boolean hitCancelled = false; +@@ -34,6 +35,19 @@ public abstract class IProjectile extends Entity { + super(entitytypes, world); + } + ++ // Purpur start ++ protected final void tickDespawnCounter() { ++ if (this.getPurpurDespawnRate() != -1) { ++ ++this.despawnCounter; ++ if (this.despawnCounter >= this.getPurpurDespawnRate()) { ++ this.die(); ++ } ++ } ++ } ++ ++ protected abstract int getPurpurDespawnRate(); ++ // Purpur end ++ + public void setShooter(@Nullable Entity entity) { + if (entity != null) { + this.shooter = entity.getUniqueID(); +@@ -88,6 +102,12 @@ public abstract class IProjectile extends Entity { + } + + super.tick(); ++ ++ // Purpur start ++ if (!(this instanceof EntityArrow)) { // EntityArrow handles its own despawn counter ++ this.tickDespawnCounter(); ++ } ++ // Purpur end + } + + public boolean checkIfLeftOwner() { return this.h(); } // Purpur - OBFHELPER +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 1e0af82c74259783fdc86a7824b18ff1d14fe938..c9fa235746dd8cf148ae88c3cca4c4a9639d0f61 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -209,6 +209,35 @@ public class PurpurWorldConfig { + idleTimeoutUpdateTabList = getBoolean("gameplay-mechanics.player.idle-timeout.update-tab-list", idleTimeoutUpdateTabList); + } + ++ public int dragonFireballDespawnRate = -1; ++ public int eggDespawnRate = -1; ++ public int enderPearlDespawnRate = -1; ++ public int expBottleDespawnRate = -1; ++ public int fireworkDespawnRate = -1; ++ public int fishingHookDespawnRate = -1; ++ public int largeFireballDespawnRate = -1; ++ public int llamaSpitDespawnRate = -1; ++ public int potionDespawnRate = -1; ++ public int shulkerBulletDespawnRate = -1; ++ public int smallFireballDespawnRate = -1; ++ public int snowballDespawnRate = -1; ++ public int witherSkullDespawnRate = -1; ++ private void projectileDespawnRateSettings() { ++ dragonFireballDespawnRate = getInt("gameplay-mechanics.projectile-despawn-rates.dragon_fireball", dragonFireballDespawnRate); ++ eggDespawnRate = getInt("gameplay-mechanics.projectile-despawn-rates.egg", eggDespawnRate); ++ enderPearlDespawnRate = getInt("gameplay-mechanics.projectile-despawn-rates.ender_pearl", enderPearlDespawnRate); ++ expBottleDespawnRate = getInt("gameplay-mechanics.projectile-despawn-rates.experience_bottle", expBottleDespawnRate); ++ fireworkDespawnRate = getInt("gameplay-mechanics.projectile-despawn-rates.firework_rocket", fireworkDespawnRate); ++ fishingHookDespawnRate = getInt("gameplay-mechanics.projectile-despawn-rates.fishing_bobber", fishingHookDespawnRate); ++ largeFireballDespawnRate = getInt("gameplay-mechanics.projectile-despawn-rates.fireball", largeFireballDespawnRate); ++ llamaSpitDespawnRate = getInt("gameplay-mechanics.projectile-despawn-rates.llama_spit", llamaSpitDespawnRate); ++ potionDespawnRate = getInt("gameplay-mechanics.projectile-despawn-rates.potion", potionDespawnRate); ++ shulkerBulletDespawnRate = getInt("gameplay-mechanics.projectile-despawn-rates.shulker_bullet", shulkerBulletDespawnRate); ++ smallFireballDespawnRate = getInt("gameplay-mechanics.projectile-despawn-rates.small_fireball", smallFireballDespawnRate); ++ snowballDespawnRate = getInt("gameplay-mechanics.projectile-despawn-rates.snowball", snowballDespawnRate); ++ witherSkullDespawnRate = getInt("gameplay-mechanics.projectile-despawn-rates.wither_skull", witherSkullDespawnRate); ++ } ++ + public boolean useBetterMending = false; + public boolean boatEjectPlayersOnLand = false; + public boolean disableDropsOnCrammingDeath = false; diff --git a/patches/Purpur/patches/server/0109-Add-option-to-disable-zombie-aggressiveness-towards-.patch b/patches/Purpur/patches/server/0109-Add-option-to-disable-zombie-aggressiveness-towards-.patch new file mode 100644 index 00000000..30f3457d --- /dev/null +++ b/patches/Purpur/patches/server/0109-Add-option-to-disable-zombie-aggressiveness-towards-.patch @@ -0,0 +1,89 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: nitricspace +Date: Mon, 21 Sep 2020 23:19:43 +0100 +Subject: [PATCH] Add option to disable zombie aggressiveness towards villagers + when lagging + + +diff --git a/src/main/java/com/destroystokyo/paper/entity/ai/MobGoalHelper.java b/src/main/java/com/destroystokyo/paper/entity/ai/MobGoalHelper.java +index f62d0ee49ebda2b0c7a136562b24ee038502d048..995ccf9abfd91780168091da95c9af758f177b98 100644 +--- a/src/main/java/com/destroystokyo/paper/entity/ai/MobGoalHelper.java ++++ b/src/main/java/com/destroystokyo/paper/entity/ai/MobGoalHelper.java +@@ -305,6 +305,10 @@ public class MobGoalHelper { + deobfuscationMap.put("wither_a", "wither_do_nothing"); + deobfuscationMap.put("wolf_a", "wolf_avoid_entity"); + deobfuscationMap.put("zombie_a", "zombie_attack_turtle_egg"); ++ // Purpur start ++ deobfuscationMap.put("zombie_1", "zombie_attack_villager"); ++ deobfuscationMap.put("drowned_1", "drowned_attack_villager"); ++ // Purpur end + + ignored.add("selector_1"); + ignored.add("selector_2"); +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityDrowned.java b/src/main/java/net/minecraft/world/entity/monster/EntityDrowned.java +index 1d4039d61a2c77a38a31947010cee26f41c0becd..93946f4e3cad07e20189a44ce512682b4cbc163b 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityDrowned.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityDrowned.java +@@ -109,7 +109,18 @@ public class EntityDrowned extends EntityZombie implements IRangedEntity { + this.goalSelector.a(7, new PathfinderGoalRandomStroll(this, 1.0D)); + this.targetSelector.a(1, (new PathfinderGoalHurtByTarget(this, new Class[]{EntityDrowned.class})).a(EntityPigZombie.class)); + this.targetSelector.a(2, new PathfinderGoalNearestAttackableTarget<>(this, EntityHuman.class, 10, true, false, this::i)); +- if ( world.spigotConfig.zombieAggressiveTowardsVillager ) this.targetSelector.a(3, new PathfinderGoalNearestAttackableTarget<>(this, EntityVillagerAbstract.class, false)); // Paper ++ // Purpur start ++ if ( world.spigotConfig.zombieAggressiveTowardsVillager ) this.targetSelector.a(3, new PathfinderGoalNearestAttackableTarget(this, EntityVillagerAbstract.class, false) { // Spigot ++ @Override ++ public boolean a() { ++ return (world.purpurConfig.zombieAggressiveTowardsVillagerWhenLagging || !world.getMinecraftServer().server.isLagging()) && super.a(); ++ } ++ @Override ++ public boolean b() { ++ return (world.purpurConfig.zombieAggressiveTowardsVillagerWhenLagging || !world.getMinecraftServer().server.isLagging()) && super.b(); ++ } ++ }); ++ // Purpur end + this.targetSelector.a(3, new PathfinderGoalNearestAttackableTarget<>(this, EntityIronGolem.class, true)); + this.targetSelector.a(5, new PathfinderGoalNearestAttackableTarget<>(this, EntityTurtle.class, 10, true, false, EntityTurtle.bo)); + } +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityZombie.java b/src/main/java/net/minecraft/world/entity/monster/EntityZombie.java +index 901fe8d224130c67bad00636b065bc798859a18e..88264b7b2c21a377f4b0dd857065e40165f0acde 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityZombie.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityZombie.java +@@ -148,7 +148,18 @@ public class EntityZombie extends EntityMonster { + this.goalSelector.a(7, new PathfinderGoalRandomStrollLand(this, 1.0D)); + this.targetSelector.a(1, (new PathfinderGoalHurtByTarget(this, new Class[0])).a(EntityPigZombie.class)); + this.targetSelector.a(2, new PathfinderGoalNearestAttackableTarget<>(this, EntityHuman.class, true)); +- if ( world.spigotConfig.zombieAggressiveTowardsVillager ) this.targetSelector.a(3, new PathfinderGoalNearestAttackableTarget<>(this, EntityVillagerAbstract.class, false)); // Spigot ++ // Purpur start ++ if ( world.spigotConfig.zombieAggressiveTowardsVillager ) this.targetSelector.a(3, new PathfinderGoalNearestAttackableTarget(this, EntityVillagerAbstract.class, false) { // Spigot ++ @Override ++ public boolean a() { ++ return (world.purpurConfig.zombieAggressiveTowardsVillagerWhenLagging || !world.getMinecraftServer().server.isLagging()) && super.a(); ++ } ++ @Override ++ public boolean b() { ++ return (world.purpurConfig.zombieAggressiveTowardsVillagerWhenLagging || !world.getMinecraftServer().server.isLagging()) && super.b(); ++ } ++ }); ++ // Purpur end + this.targetSelector.a(3, new PathfinderGoalNearestAttackableTarget<>(this, EntityIronGolem.class, true)); + this.targetSelector.a(5, new PathfinderGoalNearestAttackableTarget<>(this, EntityTurtle.class, 10, true, false, EntityTurtle.bo)); + } +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index c9fa235746dd8cf148ae88c3cca4c4a9639d0f61..94681a3cb57950b0cd074927aa63bf84e3ef0cf7 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -1081,12 +1081,14 @@ public class PurpurWorldConfig { + public boolean zombieJockeyOnlyBaby = true; + public double zombieJockeyChance = 0.05D; + public boolean zombieJockeyTryExistingChickens = true; ++ public boolean zombieAggressiveTowardsVillagerWhenLagging = true; + private void zombieSettings() { + zombieRidable = getBoolean("mobs.zombie.ridable", zombieRidable); + zombieRidableInWater = getBoolean("mobs.zombie.ridable-in-water", zombieRidableInWater); + zombieJockeyOnlyBaby = getBoolean("mobs.zombie.jockey.only-babies", zombieJockeyOnlyBaby); + zombieJockeyChance = getDouble("mobs.zombie.jockey.chance", zombieJockeyChance); + zombieJockeyTryExistingChickens = getBoolean("mobs.zombie.jockey.try-existing-chickens", zombieJockeyTryExistingChickens); ++ zombieAggressiveTowardsVillagerWhenLagging = getBoolean("mobs.zombie.aggressive-towards-villager-when-lagging", zombieAggressiveTowardsVillagerWhenLagging); + } + + public boolean zombieHorseCanSwim = false; diff --git a/patches/Purpur/patches/server/0110-Persistent-TileEntity-Lore-and-DisplayName.patch b/patches/Purpur/patches/server/0110-Persistent-TileEntity-Lore-and-DisplayName.patch new file mode 100644 index 00000000..4cf355e9 --- /dev/null +++ b/patches/Purpur/patches/server/0110-Persistent-TileEntity-Lore-and-DisplayName.patch @@ -0,0 +1,235 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: jmp +Date: Wed, 30 Sep 2020 14:32:46 -0700 +Subject: [PATCH] Persistent TileEntity Lore and DisplayName + +Makes it so that when a TileEntity is placed in the world and then broken, +the dropped ItemStack retains any original custom display name/lore. + +diff --git a/src/main/java/net/minecraft/world/entity/decoration/EntityPainting.java b/src/main/java/net/minecraft/world/entity/decoration/EntityPainting.java +index 9c01ec42342cf0420bf5215604c24fbc89c1361b..3de0f21648ca60bdfcbc078bca896d51bf84e207 100644 +--- a/src/main/java/net/minecraft/world/entity/decoration/EntityPainting.java ++++ b/src/main/java/net/minecraft/world/entity/decoration/EntityPainting.java +@@ -15,6 +15,7 @@ import net.minecraft.sounds.SoundEffects; + import net.minecraft.world.entity.Entity; + import net.minecraft.world.entity.EntityTypes; + import net.minecraft.world.entity.player.EntityHuman; ++import net.minecraft.world.item.ItemStack; + import net.minecraft.world.item.Items; + import net.minecraft.world.level.GameRules; + import net.minecraft.world.level.IMaterial; +diff --git a/src/main/java/net/minecraft/world/entity/vehicle/EntityBoat.java b/src/main/java/net/minecraft/world/entity/vehicle/EntityBoat.java +index 01839c7319e175477ded7001e00e5937734ff516..e5cda8c040c93639211dacbf5b0c7cd6a9df9e6d 100644 +--- a/src/main/java/net/minecraft/world/entity/vehicle/EntityBoat.java ++++ b/src/main/java/net/minecraft/world/entity/vehicle/EntityBoat.java +@@ -34,6 +34,7 @@ import net.minecraft.world.entity.animal.EntityAnimal; + import net.minecraft.world.entity.animal.EntityWaterAnimal; + import net.minecraft.world.entity.player.EntityHuman; + import net.minecraft.world.item.Item; ++import net.minecraft.world.item.ItemStack; + import net.minecraft.world.item.Items; + import net.minecraft.world.level.GameRules; + import net.minecraft.world.level.IMaterial; +diff --git a/src/main/java/net/minecraft/world/item/ItemBlock.java b/src/main/java/net/minecraft/world/item/ItemBlock.java +index 59d52c252b2e59923b8e513dd4d2e1ec9ce34dc7..4be1c8ee85f411a8b01be50b8cc3dc3835f80a2e 100644 +--- a/src/main/java/net/minecraft/world/item/ItemBlock.java ++++ b/src/main/java/net/minecraft/world/item/ItemBlock.java +@@ -119,7 +119,24 @@ public class ItemBlock extends Item { + } + + protected boolean a(BlockPosition blockposition, World world, @Nullable EntityHuman entityhuman, ItemStack itemstack, IBlockData iblockdata) { +- return a(world, entityhuman, blockposition, itemstack); ++ // Purpur start ++ boolean handled = a(world, entityhuman, blockposition, itemstack); ++ if (world.purpurConfig.persistentTileEntityDisplayNames && itemstack.hasTag()) { ++ NBTTagCompound display = itemstack.getSubTag("display"); ++ if (display != null) { ++ TileEntity tile = world.getTileEntity(blockposition); ++ if (tile != null) { ++ if (display.hasKeyOfType("Name", 8)) { ++ tile.setPersistentDisplayName(display.getString("Name")); ++ } ++ if (display.hasKeyOfType("Lore", 9)) { ++ tile.setPersistentLore(display.getList("Lore", 8)); ++ } ++ } ++ } ++ } ++ return handled; ++ // Purpur end + } + + @Nullable +diff --git a/src/main/java/net/minecraft/world/level/block/Block.java b/src/main/java/net/minecraft/world/level/block/Block.java +index 4e0b88e26ad8017d93841c4149a1687c1db4ff0b..f65201f8cbf6d402b4366d63bfa03aacf329860f 100644 +--- a/src/main/java/net/minecraft/world/level/block/Block.java ++++ b/src/main/java/net/minecraft/world/level/block/Block.java +@@ -15,10 +15,15 @@ import net.minecraft.core.EnumDirection; + import net.minecraft.core.IRegistry; + import net.minecraft.core.NonNullList; + import net.minecraft.core.RegistryBlockID; ++import net.minecraft.nbt.NBTTagCompound; ++import net.minecraft.nbt.NBTTagList; ++import net.minecraft.nbt.NBTTagString; ++import net.minecraft.network.chat.IChatBaseComponent; + import net.minecraft.server.level.WorldServer; + import net.minecraft.stats.StatisticList; + import net.minecraft.tags.Tag; + import net.minecraft.tags.TagsBlock; ++import net.minecraft.world.INamableTileEntity; + import net.minecraft.world.entity.Entity; + import net.minecraft.world.entity.EntityExperienceOrb; + import net.minecraft.world.entity.EntityLiving; +@@ -247,7 +252,7 @@ public class Block extends BlockBase implements IMaterial { + public static void a(IBlockData iblockdata, GeneratorAccess generatoraccess, BlockPosition blockposition, @Nullable TileEntity tileentity) { + if (generatoraccess instanceof WorldServer) { + a(iblockdata, (WorldServer) generatoraccess, blockposition, tileentity).forEach((itemstack) -> { +- a((World) ((WorldServer) generatoraccess), blockposition, itemstack); ++ dropItem((WorldServer) generatoraccess, blockposition, applyDisplayNameAndLoreFromTile(itemstack, tileentity)); // Purpur + }); + iblockdata.dropNaturally((WorldServer) generatoraccess, blockposition, ItemStack.b); + } +@@ -256,14 +261,56 @@ public class Block extends BlockBase implements IMaterial { + + public static void dropItems(IBlockData iblockdata, World world, BlockPosition blockposition, @Nullable TileEntity tileentity, Entity entity, ItemStack itemstack) { + if (world instanceof WorldServer) { +- getDrops(iblockdata, (WorldServer) world, blockposition, tileentity, entity, itemstack).forEach((itemstack1) -> { +- a(world, blockposition, itemstack1); ++ // Purpur start ++ getDrops(iblockdata, (WorldServer) world, blockposition, tileentity, entity, itemstack).forEach(stackToDrop -> { ++ dropItem(world, blockposition, applyDisplayNameAndLoreFromTile(stackToDrop, tileentity)); ++ // Purpur end + }); + iblockdata.dropNaturally((WorldServer) world, blockposition, itemstack); + } + + } + ++ // Purpur start ++ private static ItemStack applyDisplayNameAndLoreFromTile(ItemStack itemStack, TileEntity tile) { ++ if (itemStack.getItem() instanceof ItemBlock) { ++ if (tile != null && tile.getWorld() instanceof WorldServer && tile.getWorld().purpurConfig.persistentTileEntityDisplayNames) { ++ String name = tile.getPersistentDisplayName(); ++ NBTTagList lore = tile.getPersistentLore(); ++ if (tile instanceof INamableTileEntity) { ++ INamableTileEntity namedTile = (INamableTileEntity) tile; ++ if (namedTile.hasCustomName()) { ++ name = IChatBaseComponent.ChatSerializer.componentToJson(namedTile.getCustomName()); ++ } ++ } ++ ++ if (name != null || lore != null) { ++ NBTTagCompound display = itemStack.getSubTag("display"); ++ if (display == null) { ++ display = new NBTTagCompound(); ++ } ++ ++ if (name != null) { ++ display.set("Name", NBTTagString.create(name)); ++ } ++ if (lore != null) { ++ display.set("Lore", lore); ++ } ++ ++ NBTTagCompound tag = itemStack.getTag(); ++ if (tag == null) { ++ tag = new NBTTagCompound(); ++ } ++ tag.set("display", display); ++ ++ itemStack.setTag(tag); ++ } ++ } ++ } ++ return itemStack; ++ } ++ // Purpur end ++ + public static void a(World world, BlockPosition blockposition, ItemStack itemstack) { dropItem(world, blockposition, itemstack); } public static void dropItem(World world, BlockPosition blockposition, ItemStack itemstack) { // Paper - OBFHELPER + if (!world.isClientSide && !itemstack.isEmpty() && world.getGameRules().getBoolean(GameRules.DO_TILE_DROPS)) { + float f = 0.5F; +diff --git a/src/main/java/net/minecraft/world/level/block/entity/TileEntity.java b/src/main/java/net/minecraft/world/level/block/entity/TileEntity.java +index 93d02ccb87c17404c55884f52ae40c7b7ddfb103..35c4d5414db66b977a354ac50d35a6aa0fcd4cf8 100644 +--- a/src/main/java/net/minecraft/world/level/block/entity/TileEntity.java ++++ b/src/main/java/net/minecraft/world/level/block/entity/TileEntity.java +@@ -6,6 +6,8 @@ import net.minecraft.ResourceKeyInvalidException; + import net.minecraft.core.BlockPosition; + import net.minecraft.core.IRegistry; + import net.minecraft.nbt.NBTTagCompound; ++import net.minecraft.nbt.NBTTagList; ++import net.minecraft.nbt.NBTTagString; + import net.minecraft.network.protocol.game.PacketPlayOutTileEntityData; + import net.minecraft.resources.MinecraftKey; + import net.minecraft.world.level.World; +@@ -105,9 +107,25 @@ public abstract class TileEntity implements net.minecraft.server.KeyedObject { / + this.persistentDataContainer.putAll((NBTTagCompound) persistentDataTag); + } + // CraftBukkit end ++ // Purpur start ++ if (nbttagcompound.hasKey("Purpur.persistentDisplayName")) { ++ this.persistentDisplayName = nbttagcompound.getString("Purpur.persistentDisplayName"); ++ } ++ if (nbttagcompound.hasKey("Purpur.persistentLore")) { ++ this.persistentLore = nbttagcompound.getList("Purpur.persistentLore", 8); ++ } ++ // Purpur end + } + + public NBTTagCompound save(NBTTagCompound nbttagcompound) { ++ // Purpur start ++ if (this.persistentDisplayName != null) { ++ nbttagcompound.set("Purpur.persistentDisplayName", NBTTagString.create(this.persistentDisplayName)); ++ } ++ if (this.persistentLore != null) { ++ nbttagcompound.set("Purpur.persistentLore", this.persistentLore); ++ } ++ // Purpur end + return this.b(nbttagcompound); + } + +@@ -274,4 +292,25 @@ public abstract class TileEntity implements net.minecraft.server.KeyedObject { / + return null; + } + // CraftBukkit end ++ ++ // Purpur start ++ private String persistentDisplayName = null; ++ private NBTTagList persistentLore = null; ++ ++ public void setPersistentDisplayName(String json) { ++ this.persistentDisplayName = json; ++ } ++ ++ public void setPersistentLore(NBTTagList lore) { ++ this.persistentLore = lore; ++ } ++ ++ public String getPersistentDisplayName() { ++ return this.persistentDisplayName; ++ } ++ ++ public NBTTagList getPersistentLore() { ++ return this.persistentLore; ++ } ++ // Purpur end + } +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 94681a3cb57950b0cd074927aa63bf84e3ef0cf7..a9f4732ece4764cabb1ae7b55fa9c273996f7d9d 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -244,6 +244,7 @@ public class PurpurWorldConfig { + public boolean entitiesPickUpLootBypassMobGriefing = false; + public boolean entitiesCanUsePortals = true; + public boolean milkCuresBadOmen = true; ++ public boolean persistentTileEntityDisplayNames = false; + public double tridentLoyaltyVoidReturnHeight = 0.0D; + public double voidDamageHeight = -64.0D; + public double voidDamageDealt = 4.0D; +@@ -255,6 +256,7 @@ public class PurpurWorldConfig { + entitiesPickUpLootBypassMobGriefing = getBoolean("gameplay-mechanics.entities-pick-up-loot-bypass-mob-griefing", entitiesPickUpLootBypassMobGriefing); + entitiesCanUsePortals = getBoolean("gameplay-mechanics.entities-can-use-portals", entitiesCanUsePortals); + milkCuresBadOmen = getBoolean("gameplay-mechanics.milk-cures-bad-omen", milkCuresBadOmen); ++ persistentTileEntityDisplayNames = getBoolean("gameplay-mechanics.persistent-tileentity-display-names-and-lore", persistentTileEntityDisplayNames); + tridentLoyaltyVoidReturnHeight = getDouble("gameplay-mechanics.trident-loyalty-void-return-height", tridentLoyaltyVoidReturnHeight); + voidDamageHeight = getDouble("gameplay-mechanics.void-damage-height", voidDamageHeight); + voidDamageDealt = getDouble("gameplay-mechanics.void-damage-dealt", voidDamageDealt); diff --git a/patches/Purpur/patches/server/0111-Add-predicate-to-recipe-s-ExactChoice-ingredient.patch b/patches/Purpur/patches/server/0111-Add-predicate-to-recipe-s-ExactChoice-ingredient.patch new file mode 100644 index 00000000..2e1d8f60 --- /dev/null +++ b/patches/Purpur/patches/server/0111-Add-predicate-to-recipe-s-ExactChoice-ingredient.patch @@ -0,0 +1,43 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sat, 3 Oct 2020 17:40:52 -0500 +Subject: [PATCH] Add predicate to recipe's ExactChoice ingredient + + +diff --git a/src/main/java/net/minecraft/world/item/crafting/RecipeItemStack.java b/src/main/java/net/minecraft/world/item/crafting/RecipeItemStack.java +index 63274908bc7552321a4db3d4e0eec0f55ee34786..c7f6dc5a933873a6118a5674e4ce04cfa1664f60 100644 +--- a/src/main/java/net/minecraft/world/item/crafting/RecipeItemStack.java ++++ b/src/main/java/net/minecraft/world/item/crafting/RecipeItemStack.java +@@ -36,6 +36,7 @@ public final class RecipeItemStack implements Predicate { + public ItemStack[] choices; + private IntList d; + public boolean exact; // CraftBukkit ++ public Predicate predicate; // Purpur + + public RecipeItemStack(Stream stream) { + this.b = (RecipeItemStack.Provider[]) stream.toArray((i) -> { +@@ -62,6 +63,12 @@ public final class RecipeItemStack implements Predicate { + if (this.choices.length == 0) { + return itemstack.isEmpty(); + } else { ++ // Purpur start ++ if (predicate != null) { ++ return predicate.test(itemstack.asBukkitCopy()); ++ } ++ // Purpur end ++ + ItemStack[] aitemstack = this.choices; + int i = aitemstack.length; + +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftRecipe.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftRecipe.java +index b7e8c3798628229be56289818caa3024014640d6..43c50c2c54444c67e4a875be4880afe97c32412c 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftRecipe.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftRecipe.java +@@ -22,6 +22,7 @@ public interface CraftRecipe extends Recipe { + } else if (bukkit instanceof RecipeChoice.ExactChoice) { + stack = new RecipeItemStack(((RecipeChoice.ExactChoice) bukkit).getChoices().stream().map((mat) -> new net.minecraft.world.item.crafting.RecipeItemStack.StackProvider(CraftItemStack.asNMSCopy(mat)))); + stack.exact = true; ++ stack.predicate = ((RecipeChoice.ExactChoice) bukkit).getPredicate(); // Purpur + } else { + throw new IllegalArgumentException("Unknown recipe stack instance " + bukkit); + } diff --git a/patches/Purpur/patches/server/0112-Flying-squids-Oh-my.patch b/patches/Purpur/patches/server/0112-Flying-squids-Oh-my.patch new file mode 100644 index 00000000..b2914431 --- /dev/null +++ b/patches/Purpur/patches/server/0112-Flying-squids-Oh-my.patch @@ -0,0 +1,56 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sun, 4 Oct 2020 12:00:42 -0500 +Subject: [PATCH] Flying squids! Oh my! + + +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntitySquid.java b/src/main/java/net/minecraft/world/entity/animal/EntitySquid.java +index 777c3bcf267d6cf31300588826d3af6b55cab350..7ec3e5d136cbb708b3bb29aa79bdd401d37d56dc 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntitySquid.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntitySquid.java +@@ -81,6 +81,11 @@ public class EntitySquid extends EntityWaterAnimal { + vector.setX(cos * x - sine * z); + vector.setZ(sine * x + cos * z); + } ++ ++ @Override ++ public boolean isInWater() { ++ return this.inWater || world.purpurConfig.squidsCanFly; ++ } + // Purpur end + + @Override +@@ -146,6 +151,7 @@ public class EntitySquid extends EntityWaterAnimal { + } + + if (this.aH()) { ++ if (world.purpurConfig.squidsCanFly) setNoGravity(!inWater); // Purpur + if (this.bp < 3.1415927F) { + float f = this.bp / 3.1415927F; + +@@ -353,7 +359,7 @@ public class EntitySquid extends EntityWaterAnimal { + + if (i > 100) { + this.b.a(0.0F, 0.0F, 0.0F); +- } else if (this.b.getRandom().nextInt(50) == 0 || !this.b.inWater || !this.b.eK()) { ++ } else if (this.b.getRandom().nextInt(50) == 0 || !this.b.isInWater() || !this.b.eK()) { // Purpur + float f = this.b.getRandom().nextFloat() * 6.2831855F; + float f1 = MathHelper.cos(f) * 0.2F; + float f2 = -0.1F + this.b.getRandom().nextFloat() * 0.2F; +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index a9f4732ece4764cabb1ae7b55fa9c273996f7d9d..9a18d3612d38cdd3d85cc69fba6df355b6cc6829 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -937,10 +937,12 @@ public class PurpurWorldConfig { + public boolean squidRidable = false; + public boolean squidImmuneToEAR = true; + public double squidOffsetWaterCheck = 0.0D; ++ public boolean squidsCanFly = false; + private void squidSettings() { + squidRidable = getBoolean("mobs.squid.ridable", squidRidable); + squidImmuneToEAR = getBoolean("mobs.squid.immune-to-EAR", squidImmuneToEAR); + squidOffsetWaterCheck = getDouble("mobs.squid.water-offset-check", squidOffsetWaterCheck); ++ squidsCanFly = getBoolean("mobs.squid.can-fly", squidsCanFly); + } + + public boolean spiderRidable = false; diff --git a/patches/Purpur/patches/server/0113-Infinity-bow-settings.patch b/patches/Purpur/patches/server/0113-Infinity-bow-settings.patch new file mode 100644 index 00000000..51c938b3 --- /dev/null +++ b/patches/Purpur/patches/server/0113-Infinity-bow-settings.patch @@ -0,0 +1,47 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sun, 4 Oct 2020 19:08:53 -0500 +Subject: [PATCH] Infinity bow settings + + +diff --git a/src/main/java/net/minecraft/world/item/ItemBow.java b/src/main/java/net/minecraft/world/item/ItemBow.java +index 015f4d71f35a9d512814389b6e6cab74c0daf116..c7e20b25b4d09463fa54c66e62208e90515013e2 100644 +--- a/src/main/java/net/minecraft/world/item/ItemBow.java ++++ b/src/main/java/net/minecraft/world/item/ItemBow.java +@@ -35,7 +35,7 @@ public class ItemBow extends ItemProjectileWeapon implements ItemVanishable { + float f = a(j); + + if ((double) f >= 0.1D) { +- boolean flag1 = flag && itemstack1.getItem() == Items.ARROW; ++ boolean flag1 = flag && ((itemstack1.getItem() == Items.ARROW && world.purpurConfig.infinityWorksWithNormalArrows) || (itemstack1.getItem() == Items.TIPPED_ARROW && world.purpurConfig.infinityWorksWithTippedArrows) || (itemstack1.getItem() == Items.SPECTRAL_ARROW && world.purpurConfig.infinityWorksWithSpectralArrows)); // Purpur + + if (!world.isClientSide) { + ItemArrow itemarrow = (ItemArrow) ((ItemArrow) (itemstack1.getItem() instanceof ItemArrow ? itemstack1.getItem() : Items.ARROW)); +@@ -96,6 +96,7 @@ public class ItemBow extends ItemProjectileWeapon implements ItemVanishable { + entityhuman.inventory.f(itemstack1); + } + } ++ else if (!entityhuman.abilities.canInstantlyBuild) ((org.bukkit.entity.Player) entityhuman.getBukkitEntity()).updateInventory(); // Purpur + + entityhuman.b(StatisticList.ITEM_USED.b(this)); + } +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 9a18d3612d38cdd3d85cc69fba6df355b6cc6829..e982733732e3dfd9d34cf5d9e87a9caa3af2d6e8 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -209,6 +209,15 @@ public class PurpurWorldConfig { + idleTimeoutUpdateTabList = getBoolean("gameplay-mechanics.player.idle-timeout.update-tab-list", idleTimeoutUpdateTabList); + } + ++ public boolean infinityWorksWithNormalArrows = true; ++ public boolean infinityWorksWithSpectralArrows = false; ++ public boolean infinityWorksWithTippedArrows = false; ++ private void infinityArrowsSettings() { ++ infinityWorksWithNormalArrows = getBoolean("gameplay-mechanics.infinity-bow.normal-arrows", infinityWorksWithNormalArrows); ++ infinityWorksWithSpectralArrows = getBoolean("gameplay-mechanics.infinity-bow.spectral-arrows", infinityWorksWithSpectralArrows); ++ infinityWorksWithTippedArrows = getBoolean("gameplay-mechanics.infinity-bow.tipped-arrows", infinityWorksWithTippedArrows); ++ } ++ + public int dragonFireballDespawnRate = -1; + public int eggDespawnRate = -1; + public int enderPearlDespawnRate = -1; diff --git a/patches/Purpur/patches/server/0114-Stonecutter-damage.patch b/patches/Purpur/patches/server/0114-Stonecutter-damage.patch new file mode 100644 index 00000000..574daef9 --- /dev/null +++ b/patches/Purpur/patches/server/0114-Stonecutter-damage.patch @@ -0,0 +1,69 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Mon, 5 Oct 2020 12:15:14 -0500 +Subject: [PATCH] Stonecutter damage + + +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index e2de4d53e90b30f46a477c995505ac9f48cac842..b15f117d64d4e6a1dccdda480417b6f092c161ec 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -890,7 +890,7 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, ne + } + // CraftBukkit end + +- if (this.onGround && !this.bv()) { ++ if (this.onGround && (!this.bv() || (block == Blocks.STONECUTTER && world.purpurConfig.stonecutterDamage > 0.0F))) { // Purpur + block.stepOn(this.world, blockposition, this); + } + +diff --git a/src/main/java/net/minecraft/world/level/block/BlockStonecutter.java b/src/main/java/net/minecraft/world/level/block/BlockStonecutter.java +index 54c9586cd7f8c9691a1c7ded9c9c96b0f316b0b6..68c6f090a10564a790f3bf175e2378d1f7103b8e 100644 +--- a/src/main/java/net/minecraft/world/level/block/BlockStonecutter.java ++++ b/src/main/java/net/minecraft/world/level/block/BlockStonecutter.java +@@ -94,4 +94,16 @@ public class BlockStonecutter extends Block { + public boolean a(IBlockData iblockdata, IBlockAccess iblockaccess, BlockPosition blockposition, PathMode pathmode) { + return false; + } ++ ++ // Purpur start ++ @Override ++ public void stepOn(World world, BlockPosition pos, net.minecraft.world.entity.Entity entity) { ++ if (world.purpurConfig.stonecutterDamage > 0.0F && entity instanceof net.minecraft.world.entity.EntityLiving) { ++ org.bukkit.craftbukkit.event.CraftEventFactory.blockDamage = world.getWorld().getBlockAt(pos.getX(), pos.getY(), pos.getZ()); ++ entity.damageEntity(net.minecraft.world.damagesource.DamageSource.CACTUS, world.purpurConfig.stonecutterDamage); ++ org.bukkit.craftbukkit.event.CraftEventFactory.blockDamage = null; ++ } ++ super.stepOn(world, pos, entity); ++ } ++ // Purpur end + } +diff --git a/src/main/java/net/minecraft/world/level/pathfinder/PathfinderNormal.java b/src/main/java/net/minecraft/world/level/pathfinder/PathfinderNormal.java +index 7b92a54cfb64fb77af99e6bf66eacbdb9e769dc1..9d08094165cf18d99116b5c721fff888f3cb42e2 100644 +--- a/src/main/java/net/minecraft/world/level/pathfinder/PathfinderNormal.java ++++ b/src/main/java/net/minecraft/world/level/pathfinder/PathfinderNormal.java +@@ -503,7 +503,7 @@ public class PathfinderNormal extends PathfinderAbstract { + return iblockdata.neighbourOverridePathType = PathType.DANGER_CACTUS; // Tuinity - reduce pathfinder branching + } + +- if (iblockdata.a(Blocks.SWEET_BERRY_BUSH)) { ++ if (iblockdata.a(Blocks.SWEET_BERRY_BUSH) || iblockdata.a(Blocks.STONECUTTER)) { // Purpur + return iblockdata.neighbourOverridePathType = PathType.DANGER_OTHER; // Tuinity - reduce pathfinder branching + } + +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index e982733732e3dfd9d34cf5d9e87a9caa3af2d6e8..11f699eb7d68013df708a874a214da6be3fe6773 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -441,6 +441,11 @@ public class PurpurWorldConfig { + spawnerDeactivateByRedstone = getBoolean("blocks.spawner.deactivate-by-redstone", spawnerDeactivateByRedstone); + } + ++ public float stonecutterDamage = 0.0F; ++ private void stonecutterSettings() { ++ stonecutterDamage = (float) getDouble("blocks.stonecutter.damage", stonecutterDamage); ++ } ++ + public boolean turtleEggsBreakFromExpOrbs = true; + public boolean turtleEggsBreakFromItems = true; + public boolean turtleEggsBreakFromMinecarts = true; diff --git a/patches/Purpur/patches/server/0115-Configurable-daylight-cycle.patch b/patches/Purpur/patches/server/0115-Configurable-daylight-cycle.patch new file mode 100644 index 00000000..60e99ea9 --- /dev/null +++ b/patches/Purpur/patches/server/0115-Configurable-daylight-cycle.patch @@ -0,0 +1,101 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sat, 10 Oct 2020 14:29:55 -0500 +Subject: [PATCH] Configurable daylight cycle + + +diff --git a/src/main/java/net/minecraft/network/protocol/game/PacketPlayOutUpdateTime.java b/src/main/java/net/minecraft/network/protocol/game/PacketPlayOutUpdateTime.java +index 3086ee023685781d94e2fb99fc8dff5264f01165..74c1047305cac5673e274096709c757ede4605f4 100644 +--- a/src/main/java/net/minecraft/network/protocol/game/PacketPlayOutUpdateTime.java ++++ b/src/main/java/net/minecraft/network/protocol/game/PacketPlayOutUpdateTime.java +@@ -7,7 +7,7 @@ import net.minecraft.network.protocol.Packet; + public class PacketPlayOutUpdateTime implements Packet { + + private long a; private final void setWorldAge(final long age) { this.a = age; } private final long getWorldAge() { return this.a; } // Paper - OBFHELPER +- private long b; ++ private long b; public void setPlayerTime(long time) { this.b = time; } // Purpur + + public PacketPlayOutUpdateTime() {} + +diff --git a/src/main/java/net/minecraft/server/level/WorldServer.java b/src/main/java/net/minecraft/server/level/WorldServer.java +index d4df33c7cb47c10987431b7c863d429d2a9e82bc..ab0e16b8f659ff86f022fef210b97dfa59206b0c 100644 +--- a/src/main/java/net/minecraft/server/level/WorldServer.java ++++ b/src/main/java/net/minecraft/server/level/WorldServer.java +@@ -64,6 +64,7 @@ import net.minecraft.network.protocol.game.PacketPlayOutExplosion; + import net.minecraft.network.protocol.game.PacketPlayOutGameStateChange; + import net.minecraft.network.protocol.game.PacketPlayOutNamedSoundEffect; + import net.minecraft.network.protocol.game.PacketPlayOutSpawnPosition; ++import net.minecraft.network.protocol.game.PacketPlayOutUpdateTime; + import net.minecraft.network.protocol.game.PacketPlayOutWorldEvent; + import net.minecraft.network.protocol.game.PacketPlayOutWorldParticles; + import net.minecraft.resources.MinecraftKey; +@@ -213,6 +214,7 @@ public class WorldServer extends World implements GeneratorAccessSeed { + private final EnderDragonBattle dragonBattle; + private final StructureManager structureManager; + private final boolean Q; ++ private double fakeTime; // Purpur + + + // CraftBukkit start +@@ -604,6 +606,7 @@ public class WorldServer extends World implements GeneratorAccessSeed { + this.getServer().addWorld(this.getWorld()); // CraftBukkit + + this.asyncChunkTaskManager = new com.destroystokyo.paper.io.chunk.ChunkTaskManager(this); // Paper ++ this.fakeTime = this.worldDataServer.getDayTime(); // Purpur + } + + // Tuinity start - optimise collision +@@ -1190,7 +1193,21 @@ public class WorldServer extends World implements GeneratorAccessSeed { + this.nextTickListBlock.nextTick(); // Paper + this.nextTickListFluid.nextTick(); // Paper + this.worldDataServer.u().a(this.server, i); +- if (this.worldData.q().getBoolean(GameRules.DO_DAYLIGHT_CYCLE)) { ++ // Purpur start ++ WorldServer world = this.worldDataServer.world; ++ if (world.getGameRules().getBoolean(GameRules.DO_DAYLIGHT_CYCLE)) { ++ double incrementTimeBy = 12000.0D / (double) (world.isDay() ? world.purpurConfig.daytimeTicks : world.purpurConfig.nighttimeTicks); ++ if (incrementTimeBy != 1.0D) { ++ this.fakeTime += incrementTimeBy; ++ this.setDayTime(this.fakeTime); ++ PacketPlayOutUpdateTime packet = new PacketPlayOutUpdateTime(world.getTime(), world.getDayTime(), true); ++ for (EntityHuman entityhuman : world.players) { ++ EntityPlayer player = (EntityPlayer) entityhuman; ++ packet.setPlayerTime(player.getPlayerTime()); ++ player.playerConnection.sendPacket(packet); ++ } ++ } else ++ // Purpur end + this.setDayTime(this.worldData.getDayTime() + 1L); + } + +@@ -1199,6 +1216,12 @@ public class WorldServer extends World implements GeneratorAccessSeed { + + public void setDayTime(long i) { + this.worldDataServer.setDayTime(i); ++ // Purpur start ++ this.fakeTime = i; ++ } ++ public void setDayTime(double i) { ++ this.worldDataServer.setDayTime((long) i); ++ // Purpur end + } + + public void doMobSpawning(boolean flag, boolean flag1) { +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 11f699eb7d68013df708a874a214da6be3fe6773..b11a71a1dda78098f1995f289a1fb45c9a02eeb6 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -150,6 +150,13 @@ public class PurpurWorldConfig { + } + } + ++ public int daytimeTicks = 12000; ++ public int nighttimeTicks = 12000; ++ private void daytimeCycleSettings() { ++ daytimeTicks = getInt("gameplay-mechanics.daylight-cycle-ticks.daytime", daytimeTicks); ++ nighttimeTicks = getInt("gameplay-mechanics.daylight-cycle-ticks.nighttime", nighttimeTicks); ++ } ++ + public int entityLifeSpan = 0; + private void entitySettings() { + entityLifeSpan = getInt("gameplay-mechanics.entity-lifespan", entityLifeSpan); diff --git a/patches/Purpur/patches/server/0116-Allow-infinite-and-mending-enchantments-together.patch b/patches/Purpur/patches/server/0116-Allow-infinite-and-mending-enchantments-together.patch new file mode 100644 index 00000000..4d9943d6 --- /dev/null +++ b/patches/Purpur/patches/server/0116-Allow-infinite-and-mending-enchantments-together.patch @@ -0,0 +1,39 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Tue, 13 Oct 2020 20:04:33 -0500 +Subject: [PATCH] Allow infinite and mending enchantments together + + +diff --git a/src/main/java/net/minecraft/world/item/enchantment/EnchantmentInfiniteArrows.java b/src/main/java/net/minecraft/world/item/enchantment/EnchantmentInfiniteArrows.java +index bf9d6d0e593951aa5abc9aef6cf4803430ea18e5..29bebbccf8dd6ff8976d1bfdb4c2ddcfc9de57dc 100644 +--- a/src/main/java/net/minecraft/world/item/enchantment/EnchantmentInfiniteArrows.java ++++ b/src/main/java/net/minecraft/world/item/enchantment/EnchantmentInfiniteArrows.java +@@ -25,6 +25,6 @@ public class EnchantmentInfiniteArrows extends Enchantment { + + @Override + public boolean a(Enchantment enchantment) { +- return enchantment instanceof EnchantmentMending ? false : super.a(enchantment); ++ return enchantment instanceof EnchantmentMending ? net.pl3x.purpur.PurpurConfig.allowInfinityMending : super.a(enchantment); // Purpur + } + } +diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java +index 318caff699e2a1656ef9428641f898f0508a1df7..f068f0d4101b63b728809dca8dd322c45c793e04 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java +@@ -198,6 +198,16 @@ public class PurpurConfig { + cryingObsidianValidForPortalFrame = getBoolean("settings.blocks.crying_obsidian.valid-for-portal-frame", cryingObsidianValidForPortalFrame); + } + ++ public static boolean allowInfinityMending = false; ++ private static void enchantmentSettings() { ++ if (version < 5) { ++ boolean oldValue = getBoolean("settings.enchantment.allow-infinite-and-mending-together", false); ++ set("settings.enchantment.allow-infinity-and-mending-together", oldValue); ++ set("settings.enchantment.allow-infinite-and-mending-together", null); ++ } ++ allowInfinityMending = getBoolean("settings.enchantment.allow-infinity-and-mending-together", allowInfinityMending); ++ } ++ + public static boolean endermanShortHeight = false; + private static void entitySettings() { + endermanShortHeight = getBoolean("settings.entity.enderman.short-height", endermanShortHeight); diff --git a/patches/Purpur/patches/server/0117-Infinite-fuel-furnace.patch b/patches/Purpur/patches/server/0117-Infinite-fuel-furnace.patch new file mode 100644 index 00000000..5e29941e --- /dev/null +++ b/patches/Purpur/patches/server/0117-Infinite-fuel-furnace.patch @@ -0,0 +1,74 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Mon, 19 Oct 2020 15:14:01 -0500 +Subject: [PATCH] Infinite fuel furnace + + +diff --git a/src/main/java/net/minecraft/world/level/block/entity/TileEntityFurnace.java b/src/main/java/net/minecraft/world/level/block/entity/TileEntityFurnace.java +index 9ce19b89c16eb6edd3d5d5cc87a966a37f66895c..ac42fd627009a87709448354f232d8b5ed7fa6b9 100644 +--- a/src/main/java/net/minecraft/world/level/block/entity/TileEntityFurnace.java ++++ b/src/main/java/net/minecraft/world/level/block/entity/TileEntityFurnace.java +@@ -12,6 +12,7 @@ import java.util.Map; + import javax.annotation.Nullable; + import net.minecraft.SharedConstants; + import net.minecraft.SystemUtils; ++import net.minecraft.core.BlockPosition; + import net.minecraft.core.EnumDirection; + import net.minecraft.core.NonNullList; + import net.minecraft.nbt.NBTTagCompound; +@@ -38,6 +39,7 @@ import net.minecraft.world.level.World; + import net.minecraft.world.level.block.BlockFurnace; + import net.minecraft.world.level.block.Blocks; + import net.minecraft.world.level.block.state.IBlockData; ++import net.minecraft.world.level.material.Fluid; + import net.minecraft.world.phys.Vec3D; + + // CraftBukkit start +@@ -308,6 +310,22 @@ public abstract class TileEntityFurnace extends TileEntityContainer implements I + if (!this.world.isClientSide) { + ItemStack itemstack = (ItemStack) this.items.get(1); + ++ // Purpur start ++ boolean infiniteFuel = false; ++ if (world.purpurConfig.furnaceInfiniteFuel && !isBurning() && itemstack.isEmpty() && !items.get(0).isEmpty() && world.getTime() % 20 == 0) { ++ BlockPosition pos = getPosition().down(); ++ IBlockData iblockdata = world.getTypeIfLoaded(pos); ++ if (iblockdata != null && iblockdata.equals(Blocks.LAVA)) { ++ Fluid fluid = iblockdata.getFluid(); ++ if (fluid != null && fluid.isSource()) { ++ world.setTypeAndData(pos, Blocks.AIR.getBlockData(), 3); ++ itemstack = Items.LAVA_BUCKET.createItemStack(); ++ infiniteFuel = true; ++ } ++ } ++ } ++ // Purpur end ++ + if (!this.isBurning() && (itemstack.isEmpty() || ((ItemStack) this.items.get(0)).isEmpty())) { + if (!this.isBurning() && this.cookTime > 0) { + this.cookTime = MathHelper.clamp(this.cookTime - 2, 0, this.cookTimeTotal); +@@ -361,6 +379,8 @@ public abstract class TileEntityFurnace extends TileEntityContainer implements I + flag1 = true; + this.world.setTypeAndData(this.position, (IBlockData) this.world.getType(this.position).set(BlockFurnace.LIT, this.isBurning()), 3); + } ++ ++ if (infiniteFuel) this.items.set(1, ItemStack.NULL_ITEM); // Purpur + } + + if (flag1) { +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index b11a71a1dda78098f1995f289a1fb45c9a02eeb6..30ca0eaf588b7056963e9c6ecb4682608b46a463 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -409,6 +409,11 @@ public class PurpurWorldConfig { + farmlandGetsMoistFromBelow = getBoolean("blocks.farmland.gets-moist-from-below", farmlandGetsMoistFromBelow); + } + ++ public boolean furnaceInfiniteFuel = false; ++ private void furnaceSettings() { ++ furnaceInfiniteFuel = getBoolean("blocks.furnace.infinite-fuel", furnaceInfiniteFuel); ++ } ++ + public boolean lavaInfinite = false; + public int lavaInfiniteRequiredSources = 2; + public int lavaSpeedNether = 10; diff --git a/patches/Purpur/patches/server/0118-Arrows-should-not-reset-despawn-counter.patch b/patches/Purpur/patches/server/0118-Arrows-should-not-reset-despawn-counter.patch new file mode 100644 index 00000000..e0af66b8 --- /dev/null +++ b/patches/Purpur/patches/server/0118-Arrows-should-not-reset-despawn-counter.patch @@ -0,0 +1,21 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Wed, 4 Nov 2020 13:12:50 -0600 +Subject: [PATCH] Arrows should not reset despawn counter + +This prevents keeping arrows alive indefinitely (such as when the block +the arrow is stuck in gets removed, like a piston head going up/down) + +diff --git a/src/main/java/net/minecraft/world/entity/projectile/EntityArrow.java b/src/main/java/net/minecraft/world/entity/projectile/EntityArrow.java +index 5775a28cb9d94b94b6e6bbc810fe31260810632e..7861b9e28b0fcc7ab931498fc7c96404456b9998 100644 +--- a/src/main/java/net/minecraft/world/entity/projectile/EntityArrow.java ++++ b/src/main/java/net/minecraft/world/entity/projectile/EntityArrow.java +@@ -281,7 +281,7 @@ public abstract class EntityArrow extends IProjectile { + Vec3D vec3d = this.getMot(); + + this.setMot(vec3d.d((double) (this.random.nextFloat() * 0.2F), (double) (this.random.nextFloat() * 0.2F), (double) (this.random.nextFloat() * 0.2F))); +- this.despawnCounter = 0; ++ // this.despawnCounter = 0; // Purpur - do not reset despawn counter + } + + @Override diff --git a/patches/Purpur/patches/server/0119-Add-tablist-suffix-option-for-afk.patch b/patches/Purpur/patches/server/0119-Add-tablist-suffix-option-for-afk.patch new file mode 100644 index 00000000..0db8004f --- /dev/null +++ b/patches/Purpur/patches/server/0119-Add-tablist-suffix-option-for-afk.patch @@ -0,0 +1,42 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: montlikadani +Date: Thu, 12 Nov 2020 11:02:50 +0100 +Subject: [PATCH] Add tablist suffix option for afk + + +diff --git a/src/main/java/net/minecraft/server/level/EntityPlayer.java b/src/main/java/net/minecraft/server/level/EntityPlayer.java +index b66c50e078d83a1cda0f7010b353ae4b3ba9fd35..7b11b5fedd0dd6b340362c26b4ce73b93bf57b8b 100644 +--- a/src/main/java/net/minecraft/server/level/EntityPlayer.java ++++ b/src/main/java/net/minecraft/server/level/EntityPlayer.java +@@ -2152,7 +2152,11 @@ public class EntityPlayer extends EntityHuman implements ICrafting { + } + + if (world.purpurConfig.idleTimeoutUpdateTabList) { +- getBukkitEntity().setPlayerListName((setAfk ? net.pl3x.purpur.PurpurConfig.afkTabListPrefix : "") + getName()); ++ if (setAfk) { ++ getBukkitEntity().setPlayerListName(net.pl3x.purpur.PurpurConfig.afkTabListPrefix + getName() + net.pl3x.purpur.PurpurConfig.afkTabListSuffix); ++ } else { ++ getBukkitEntity().setPlayerListName(getName()); ++ } + } + + ((WorldServer) world).everyoneSleeping(); +diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java +index f068f0d4101b63b728809dca8dd322c45c793e04..6a69d14f8f30de6cb6d5c1b61d2521a206587354 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java +@@ -136,12 +136,14 @@ public class PurpurConfig { + public static String afkBroadcastAway = "§e§o%s is now AFK"; + public static String afkBroadcastBack = "§e§o%s is no longer AFK"; + public static String afkTabListPrefix = "[AFK] "; ++ public static String afkTabListSuffix = ""; + public static String pingCommandOutput = "§a%s's ping is %sms"; + public static String cannotRideMob = "§cYou cannot mount that mob"; + private static void messages() { + afkBroadcastAway = getString("settings.messages.afk-broadcast-away", afkBroadcastAway); + afkBroadcastBack = getString("settings.messages.afk-broadcast-back", afkBroadcastBack); + afkTabListPrefix = getString("settings.messages.afk-tab-list-prefix", afkTabListPrefix); ++ afkTabListSuffix = getString("settings.messages.afk-tab-list-suffix", afkTabListSuffix); + pingCommandOutput = getString("settings.messages.ping-command-output", pingCommandOutput); + cannotRideMob = getString("settings.messages.cannot-ride-mob", cannotRideMob); + } diff --git a/patches/Purpur/patches/server/0120-Ability-to-re-add-farmland-mechanics-from-Alpha.patch b/patches/Purpur/patches/server/0120-Ability-to-re-add-farmland-mechanics-from-Alpha.patch new file mode 100644 index 00000000..538d194e --- /dev/null +++ b/patches/Purpur/patches/server/0120-Ability-to-re-add-farmland-mechanics-from-Alpha.patch @@ -0,0 +1,40 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Yive +Date: Sat, 14 Nov 2020 08:06:20 -0800 +Subject: [PATCH] Ability to re-add farmland mechanics from Alpha + + +diff --git a/src/main/java/net/minecraft/world/level/block/BlockSoil.java b/src/main/java/net/minecraft/world/level/block/BlockSoil.java +index 50cf0f3a67a32fe221afaee095189de87135f355..f00eb3cda60f6f8b2534c3da5ffaa6faee334663 100644 +--- a/src/main/java/net/minecraft/world/level/block/BlockSoil.java ++++ b/src/main/java/net/minecraft/world/level/block/BlockSoil.java +@@ -113,6 +113,14 @@ public class BlockSoil extends Block { + return; + } + ++ // Purpur start ++ if (world.purpurConfig.farmlandAlpha) { ++ Block block = world.getType(blockposition.down()).getBlock(); ++ if (block instanceof BlockFence || block instanceof BlockCobbleWall) { ++ return; ++ } ++ } ++ // Purpur end + if (CraftEventFactory.callEntityChangeBlockEvent(entity, blockposition, Blocks.DIRT.getBlockData()).isCancelled()) { + return; + } +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 30ca0eaf588b7056963e9c6ecb4682608b46a463..44c27c6dd4993add42410373191a46f4cc92f42f 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -405,8 +405,10 @@ public class PurpurWorldConfig { + } + + public boolean farmlandGetsMoistFromBelow = false; ++ public boolean farmlandAlpha = false; + private void farmlandSettings() { + farmlandGetsMoistFromBelow = getBoolean("blocks.farmland.gets-moist-from-below", farmlandGetsMoistFromBelow); ++ farmlandAlpha = getBoolean("blocks.farmland.use-alpha-farmland", farmlandAlpha); + } + + public boolean furnaceInfiniteFuel = false; diff --git a/patches/Purpur/patches/server/0121-Add-adjustable-breeding-cooldown-to-config.patch b/patches/Purpur/patches/server/0121-Add-adjustable-breeding-cooldown-to-config.patch new file mode 100644 index 00000000..619b2e5e --- /dev/null +++ b/patches/Purpur/patches/server/0121-Add-adjustable-breeding-cooldown-to-config.patch @@ -0,0 +1,135 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: montlikadani +Date: Fri, 13 Nov 2020 17:52:40 +0100 +Subject: [PATCH] Add adjustable breeding cooldown to config + + +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityAnimal.java b/src/main/java/net/minecraft/world/entity/animal/EntityAnimal.java +index 4de0a733819d408e8b9a55b604f455281d7732c5..94b5874c1eb90c02a557179a2a1170b1da85deb4 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityAnimal.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityAnimal.java +@@ -145,7 +145,7 @@ public abstract class EntityAnimal extends EntityAgeable { + if (this.k(itemstack)) { + int i = this.getAge(); + +- if (!this.world.isClientSide && i == 0 && this.eP()) { ++ if (!this.world.isClientSide && i == 0 && this.eP() && (this.world.purpurConfig.animalBreedingCooldownSeconds <= 0 || !this.world.hasBreedingCooldown(entityhuman.getUniqueID(), this.getClass()))) { // Purpur + this.a(entityhuman, itemstack); + this.g(entityhuman); + return EnumInteractionResult.SUCCESS; +@@ -237,6 +237,14 @@ public abstract class EntityAnimal extends EntityAgeable { + if (entityplayer == null && entityanimal.getBreedCause() != null) { + entityplayer = entityanimal.getBreedCause(); + } ++ // Purpur start ++ if (entityplayer != null && worldserver.purpurConfig.animalBreedingCooldownSeconds > 0) { ++ if (worldserver.hasBreedingCooldown(entityplayer.getUniqueID(), this.getClass())) { ++ return; ++ } ++ worldserver.addBreedingCooldown(entityplayer.getUniqueID(), this.getClass()); ++ } ++ // Purpur end + // CraftBukkit start - call EntityBreedEvent + entityageable.setBaby(true); + entityageable.setPositionRotation(this.locX(), this.locY(), this.locZ(), 0.0F, 0.0F); +diff --git a/src/main/java/net/minecraft/world/level/World.java b/src/main/java/net/minecraft/world/level/World.java +index a3215b1cccf4d00de888ca4696c03ffb6adf7041..cb58d2635650c20da21583ead18e9f380323205b 100644 +--- a/src/main/java/net/minecraft/world/level/World.java ++++ b/src/main/java/net/minecraft/world/level/World.java +@@ -41,6 +41,7 @@ import net.minecraft.world.DifficultyDamageScaler; + import net.minecraft.world.damagesource.DamageSource; + import net.minecraft.world.entity.Entity; + import net.minecraft.world.entity.EntityTypes; ++import net.minecraft.world.entity.animal.EntityAnimal; + import net.minecraft.world.entity.decoration.EntityArmorStand; + import net.minecraft.world.entity.player.EntityHuman; + import net.minecraft.world.item.ItemStack; +@@ -164,6 +165,48 @@ public abstract class World implements GeneratorAccess, AutoCloseable { + private int tileTickPosition; + public final Map explosionDensityCache = new HashMap<>(); // Paper - Optimize explosions + public java.util.ArrayDeque redstoneUpdateInfos; // Paper - Move from Map in BlockRedstoneTorch to here ++ // Purpur start ++ private com.google.common.cache.Cache playerBreedingCooldowns; ++ ++ private com.google.common.cache.Cache getNewBreedingCooldownCache() { ++ return com.google.common.cache.CacheBuilder.newBuilder().expireAfterWrite(this.purpurConfig.animalBreedingCooldownSeconds, java.util.concurrent.TimeUnit.SECONDS).build(); ++ } ++ ++ public void resetBreedingCooldowns() { ++ this.playerBreedingCooldowns = this.getNewBreedingCooldownCache(); ++ } ++ ++ public boolean hasBreedingCooldown(java.util.UUID player, Class animalType) { // Purpur ++ return this.playerBreedingCooldowns.getIfPresent(new BreedingCooldownPair(player, animalType)) != null; ++ } ++ ++ public void addBreedingCooldown(java.util.UUID player, Class animalType) { ++ this.playerBreedingCooldowns.put(new BreedingCooldownPair(player, animalType), new Object()); ++ } ++ ++ private static final class BreedingCooldownPair { ++ private final java.util.UUID playerUUID; ++ private final Class animalType; ++ ++ public BreedingCooldownPair(java.util.UUID playerUUID, Class animalType) { ++ this.playerUUID = playerUUID; ++ this.animalType = animalType; ++ } ++ ++ @Override ++ public boolean equals(Object o) { ++ if (this == o) return true; ++ if (o == null || getClass() != o.getClass()) return false; ++ BreedingCooldownPair that = (BreedingCooldownPair) o; ++ return playerUUID.equals(that.playerUUID) && animalType.equals(that.animalType); ++ } ++ ++ @Override ++ public int hashCode() { ++ return java.util.Objects.hash(playerUUID, animalType); ++ } ++ } ++ // Purpur end + + public CraftWorld getWorld() { + return this.world; +@@ -256,6 +299,7 @@ public abstract class World implements GeneratorAccess, AutoCloseable { + this.chunkPacketBlockController = this.paperConfig.antiXray ? new ChunkPacketBlockControllerAntiXray(this, executor) : ChunkPacketBlockController.NO_OPERATION_INSTANCE; // Paper - Anti-Xray + this.tuinityConfig = new com.tuinity.tuinity.config.TuinityConfig.WorldConfig(((net.minecraft.world.level.storage.WorldDataServer)worlddatamutable).getName()); // Tuinity - Server Config + this.purpurConfig = new net.pl3x.purpur.PurpurWorldConfig((((net.minecraft.world.level.storage.WorldDataServer)worlddatamutable).getName()), env); // Purpur ++ this.playerBreedingCooldowns = this.getNewBreedingCooldownCache(); // Purpur + this.generator = gen; + this.world = new CraftWorld((WorldServer) this, gen, env); + this.ticksPerAnimalSpawns = this.getServer().getTicksPerAnimalSpawns(); // CraftBukkit +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 44c27c6dd4993add42410373191a46f4cc92f42f..b92715b115332e8197d5a02a2f308a1ab0f447b6 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -265,6 +265,7 @@ public class PurpurWorldConfig { + public double voidDamageHeight = -64.0D; + public double voidDamageDealt = 4.0D; + public int raidCooldownSeconds = 0; ++ public int animalBreedingCooldownSeconds = 0; + private void miscGameplayMechanicsSettings() { + useBetterMending = getBoolean("gameplay-mechanics.use-better-mending", useBetterMending); + boatEjectPlayersOnLand = getBoolean("gameplay-mechanics.boat.eject-players-on-land", boatEjectPlayersOnLand); +@@ -277,6 +278,7 @@ public class PurpurWorldConfig { + voidDamageHeight = getDouble("gameplay-mechanics.void-damage-height", voidDamageHeight); + voidDamageDealt = getDouble("gameplay-mechanics.void-damage-dealt", voidDamageDealt); + raidCooldownSeconds = getInt("gameplay-mechanics.raid-cooldown-seconds", raidCooldownSeconds); ++ animalBreedingCooldownSeconds = getInt("gameplay-mechanics.animal-breeding-cooldown-seconds", animalBreedingCooldownSeconds); + } + + public boolean catSpawning; +diff --git a/src/main/java/net/pl3x/purpur/command/PurpurCommand.java b/src/main/java/net/pl3x/purpur/command/PurpurCommand.java +index 536955124afaec5c8a070249c7432cb99bf43d67..0c35b1dd5147cf86c7ee743b98528e8f4bc0b5e9 100644 +--- a/src/main/java/net/pl3x/purpur/command/PurpurCommand.java ++++ b/src/main/java/net/pl3x/purpur/command/PurpurCommand.java +@@ -49,6 +49,7 @@ public class PurpurCommand extends Command { + PurpurConfig.init((File) console.options.valueOf("purpur-settings")); + for (WorldServer world : console.getWorlds()) { + world.purpurConfig.init(); ++ world.resetBreedingCooldowns(); + } + console.server.reloadCount++; + diff --git a/patches/Purpur/patches/server/0122-Make-entity-breeding-times-configurable.patch b/patches/Purpur/patches/server/0122-Make-entity-breeding-times-configurable.patch new file mode 100644 index 00000000..367ef4e7 --- /dev/null +++ b/patches/Purpur/patches/server/0122-Make-entity-breeding-times-configurable.patch @@ -0,0 +1,685 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: jmp +Date: Sun, 15 Nov 2020 02:18:15 -0800 +Subject: [PATCH] Make entity breeding times configurable + + +diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/BehaviorMakeLove.java b/src/main/java/net/minecraft/world/entity/ai/behavior/BehaviorMakeLove.java +index 79989c143fc8393172475e33d356510b3547afb9..d1315f4b6e026f70e04a0b54289fd13b4be17cde 100644 +--- a/src/main/java/net/minecraft/world/entity/ai/behavior/BehaviorMakeLove.java ++++ b/src/main/java/net/minecraft/world/entity/ai/behavior/BehaviorMakeLove.java +@@ -117,8 +117,10 @@ public class BehaviorMakeLove extends Behavior { + return Optional.empty(); + } + // CraftBukkit end +- entityvillager.setAgeRaw(6000); +- entityvillager1.setAgeRaw(6000); ++ // Purpur start ++ entityvillager.setAgeRaw(worldserver.purpurConfig.villagerBreedingTicks); ++ entityvillager1.setAgeRaw(worldserver.purpurConfig.villagerBreedingTicks); ++ // Purpur end + worldserver.addAllEntities(entityvillager2, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.BREEDING); // CraftBukkit - added SpawnReason + worldserver.broadcastEntityEffect(entityvillager2, (byte) 12); + return Optional.of(entityvillager2); +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityAnimal.java b/src/main/java/net/minecraft/world/entity/animal/EntityAnimal.java +index 94b5874c1eb90c02a557179a2a1170b1da85deb4..181bb648dd32f71c7f9d3fbb4974e2a1afba61ac 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityAnimal.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityAnimal.java +@@ -38,6 +38,7 @@ public abstract class EntityAnimal extends EntityAgeable { + public int loveTicks; + public UUID breedCause; + public ItemStack breedItem; // CraftBukkit - Add breedItem variable ++ public abstract int getPurpurBreedTime(); // Purpur + + protected EntityAnimal(EntityTypes entitytypes, World world) { + super(entitytypes, world); +@@ -261,8 +262,10 @@ public abstract class EntityAnimal extends EntityAgeable { + CriterionTriggers.o.a(entityplayer, this, entityanimal, entityageable); + } + +- this.setAgeRaw(6000); +- entityanimal.setAgeRaw(6000); ++ // Purpur start ++ this.setAgeRaw(this.getPurpurBreedTime()); ++ entityanimal.setAgeRaw(entityanimal.getPurpurBreedTime()); ++ // Purpur end + this.resetLove(); + entityanimal.resetLove(); + worldserver.addAllEntities(entityageable, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.BREEDING); // CraftBukkit - added SpawnReason +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityBee.java b/src/main/java/net/minecraft/world/entity/animal/EntityBee.java +index bcd510e0bf647a240edfaac1348119c5e1d7dc42..6086dda5b06f0c0e02734edf7141b13715420d3c 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityBee.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityBee.java +@@ -175,6 +175,11 @@ public class EntityBee extends EntityAnimal implements IEntityAngerable, EntityB + setMot(mot.a(0.9D)); + } + } ++ ++ @Override ++ public int getPurpurBreedTime() { ++ return this.world.purpurConfig.beeBreedingTicks; ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityCat.java b/src/main/java/net/minecraft/world/entity/animal/EntityCat.java +index bac3035e2382df2d79e592b02395753eee08fa4b..187047de5530ccec1e9804f8039839246ab248f3 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityCat.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityCat.java +@@ -122,6 +122,11 @@ public class EntityCat extends EntityTameableAnimal { + setSleepingWithOwner(false); + setHeadDown(false); + } ++ ++ @Override ++ public int getPurpurBreedTime() { ++ return this.world.purpurConfig.catBreedingTicks; ++ } + // Purpur end + + public MinecraftKey eU() { +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityChicken.java b/src/main/java/net/minecraft/world/entity/animal/EntityChicken.java +index 5c744f1eac19e144c39a2c146d312f0547d6e589..ab54e809f735cea7d84366d2bc205351f8992bef 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityChicken.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityChicken.java +@@ -71,6 +71,11 @@ public class EntityChicken extends EntityAnimal { + this.getAttributeInstance(GenericAttributes.ATTACK_DAMAGE).setValue(2.0D); + } + } ++ ++ @Override ++ public int getPurpurBreedTime() { ++ return this.world.purpurConfig.chickenBreedingTicks; ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityCow.java b/src/main/java/net/minecraft/world/entity/animal/EntityCow.java +index b2d3fc3151a952ac783101443772736a206a6a3b..7ed55ebe1bb768351a5cb4cdc7d4d3b0816d53b1 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityCow.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityCow.java +@@ -54,6 +54,11 @@ public class EntityCow extends EntityAnimal { + public boolean isRidableInWater() { + return world.purpurConfig.cowRidableInWater; + } ++ ++ @Override ++ public int getPurpurBreedTime() { ++ return this.world.purpurConfig.cowBreedingTicks; ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityFox.java b/src/main/java/net/minecraft/world/entity/animal/EntityFox.java +index 7b1a6d846f25d8bc659a541fce59df79347ba9bc..70369d03985250fa5eaf398fa98d35a2c2a06ff1 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityFox.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityFox.java +@@ -157,6 +157,11 @@ public class EntityFox extends EntityAnimal { + super.onDismount(entityhuman); + setCanPickupLoot(true); + } ++ ++ @Override ++ public int getPurpurBreedTime() { ++ return this.world.purpurConfig.foxBreedingTicks; ++ } + // Purpur end + + @Override +@@ -1373,8 +1378,10 @@ public class EntityFox extends EntityAnimal { + CriterionTriggers.o.a(entityplayer2, this.animal, this.partner, (EntityAgeable) entityfox); + } + +- this.animal.setAgeRaw(6000); +- this.partner.setAgeRaw(6000); ++ // Purpur start ++ this.animal.setAgeRaw(this.animal.getPurpurBreedTime()); ++ this.partner.setAgeRaw(this.partner.getPurpurBreedTime()); ++ // Purpur end + this.animal.resetLove(); + this.partner.resetLove(); + worldserver.addAllEntities(entityfox, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.BREEDING); // CraftBukkit - added SpawnReason +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityMushroomCow.java b/src/main/java/net/minecraft/world/entity/animal/EntityMushroomCow.java +index 815e907e8db721f2a6f0f831b69c44a9573b5c9b..ab4a8ee6e1912f230cbf3353eb42c3bc8a9db58e 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityMushroomCow.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityMushroomCow.java +@@ -67,6 +67,11 @@ public class EntityMushroomCow extends EntityCow implements IShearable { + public boolean isRidableInWater() { + return world.purpurConfig.mooshroomRidableInWater; + } ++ ++ @Override ++ public int getPurpurBreedTime() { ++ return this.world.purpurConfig.mooshroomBreedingTicks; ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityOcelot.java b/src/main/java/net/minecraft/world/entity/animal/EntityOcelot.java +index d7938ff0dca305f1d47fdfdbc57648892debe367..cff2ff5a8beef739f0515832e072e7e390ac388f 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityOcelot.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityOcelot.java +@@ -74,6 +74,11 @@ public class EntityOcelot extends EntityAnimal { + public boolean isRidableInWater() { + return world.purpurConfig.ocelotRidableInWater; + } ++ ++ @Override ++ public int getPurpurBreedTime() { ++ return this.world.purpurConfig.ocelotBreedingTicks; ++ } + // Purpur end + + private boolean isTrusting() { +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityPanda.java b/src/main/java/net/minecraft/world/entity/animal/EntityPanda.java +index 0d912399e1975d9c0d5525f5b89049f40e7efcc0..e6952c0a8d90eb4b133c517d97299f2c3db7e329 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityPanda.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityPanda.java +@@ -121,6 +121,11 @@ public class EntityPanda extends EntityAnimal { + this.setEating(false); + this.setLayingOnBack(false); + } ++ ++ @Override ++ public int getPurpurBreedTime() { ++ return this.world.purpurConfig.pandaBreedingTicks; ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityParrot.java b/src/main/java/net/minecraft/world/entity/animal/EntityParrot.java +index 9f705b75a14ba456808485ce4ddef9550aac3fe9..7346921a24bdd57aa3814386bc372b082b23b4bc 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityParrot.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityParrot.java +@@ -171,6 +171,11 @@ public class EntityParrot extends EntityPerchable implements EntityBird { + setMot(mot.a(0.9D)); + } + } ++ ++ @Override ++ public int getPurpurBreedTime() { ++ return 6000; ++ } + // Purpur end + + @Nullable +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityPig.java b/src/main/java/net/minecraft/world/entity/animal/EntityPig.java +index cef69f99d7bc9b6605b9654c50f43a1ebc1a8509..5aa8806063186bec36b38adc51e2ea82bf6ff21a 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityPig.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityPig.java +@@ -77,6 +77,11 @@ public class EntityPig extends EntityAnimal implements ISteerable, ISaddleable { + public boolean isRidableInWater() { + return world.purpurConfig.pigRidableInWater; + } ++ ++ @Override ++ public int getPurpurBreedTime() { ++ return this.world.purpurConfig.pigBreedingTicks; ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityPolarBear.java b/src/main/java/net/minecraft/world/entity/animal/EntityPolarBear.java +index b46315700b8857318b03b83097fcf829047f8ca4..c9c7c9de638079393bbea86f8069023dcbcbca83 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityPolarBear.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityPolarBear.java +@@ -116,6 +116,11 @@ public class EntityPolarBear extends EntityAnimal implements IEntityAngerable { + return this.isInLove() && polarbear.isInLove(); + } + } ++ ++ @Override ++ public int getPurpurBreedTime() { ++ return this.world.purpurConfig.polarBearBreedingTicks; ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityRabbit.java b/src/main/java/net/minecraft/world/entity/animal/EntityRabbit.java +index 4660f37bc89418e0c3767305d390a53f5c0d3c55..465701232567e4058f9dfc776560ccde33fee66c 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityRabbit.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityRabbit.java +@@ -85,6 +85,11 @@ public class EntityRabbit extends EntityAnimal { + public boolean isRidableInWater() { + return world.purpurConfig.rabbitRidableInWater; + } ++ ++ @Override ++ public int getPurpurBreedTime() { ++ return this.world.purpurConfig.rabbitBreedingTicks; ++ } + // Purpur end + + // CraftBukkit start - code from constructor +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntitySheep.java b/src/main/java/net/minecraft/world/entity/animal/EntitySheep.java +index 8f3296031f220dd7bb3ae9fe2443e479954ebad3..ff6fc821085e4430a3b1008140b0b7fcacc59d2e 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntitySheep.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntitySheep.java +@@ -121,6 +121,11 @@ public class EntitySheep extends EntityAnimal implements IShearable { + public boolean isRidableInWater() { + return world.purpurConfig.sheepRidableInWater; + } ++ ++ @Override ++ public int getPurpurBreedTime() { ++ return this.world.purpurConfig.sheepBreedingTicks; ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityTurtle.java b/src/main/java/net/minecraft/world/entity/animal/EntityTurtle.java +index 28d6e673f55fc8fae40dff4a96ac2c2b5eeab9d6..a16f586934f24e599d00bf793f06d3f9134ed29d 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityTurtle.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityTurtle.java +@@ -101,6 +101,11 @@ public class EntityTurtle extends EntityAnimal { + public boolean isRidableInWater() { + return world.purpurConfig.turtleRidableInWater; + } ++ ++ @Override ++ public int getPurpurBreedTime() { ++ return this.world.purpurConfig.turtleBreedingTicks; ++ } + // Purpur end + + public void setHomePos(BlockPosition blockposition) { +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityWolf.java b/src/main/java/net/minecraft/world/entity/animal/EntityWolf.java +index 3fbd8f9122d7a5ac23af4d872f877030644ef86a..dd3c7ad7701ad18ccaf86d73fde7051090ed3d57 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityWolf.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityWolf.java +@@ -107,6 +107,11 @@ public class EntityWolf extends EntityTameableAnimal implements IEntityAngerable + super.onMount(entityhuman); + setSitting(false); + } ++ ++ @Override ++ public int getPurpurBreedTime() { ++ return this.world.purpurConfig.wolfBreedingTicks; ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorse.java b/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorse.java +index 650f13b1133e4c61f71b36f3f91a9d2913996435..c830bf6e5e38f5ebacc07673c3d67e4157c8c2b5 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorse.java ++++ b/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorse.java +@@ -46,6 +46,11 @@ public class EntityHorse extends EntityHorseAbstract { + public boolean isRidableInWater() { + return world.purpurConfig.horseRidableInWater; + } ++ ++ @Override ++ public int getPurpurBreedTime() { ++ return this.world.purpurConfig.horseBreedingTicks; ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseDonkey.java b/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseDonkey.java +index 50700bf85a296b87fe3155651f869e2bbdb0875d..3b44394dcba8e9905aca46e6e585ee6d7a87de44 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseDonkey.java ++++ b/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseDonkey.java +@@ -21,6 +21,11 @@ public class EntityHorseDonkey extends EntityHorseChestedAbstract { + public boolean isRidableInWater() { + return world.purpurConfig.donkeyRidableInWater; + } ++ ++ @Override ++ public int getPurpurBreedTime() { ++ return this.world.purpurConfig.donkeyBreedingTicks; ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseMule.java b/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseMule.java +index b6385a23050296611dbc8864b92d2cdd8321a1d0..0536112357e0321dbb902331467b847894a4c11b 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseMule.java ++++ b/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseMule.java +@@ -20,6 +20,11 @@ public class EntityHorseMule extends EntityHorseChestedAbstract { + public boolean isRidableInWater() { + return world.purpurConfig.muleRidableInWater; + } ++ ++ @Override ++ public int getPurpurBreedTime() { ++ return this.world.purpurConfig.muleBreedingTicks; ++ } + // Purpur end + @Override + protected SoundEffect getSoundAmbient() { +diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseSkeleton.java b/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseSkeleton.java +index d21399fbb6ddc4f26a7509ce547f8c4ad6458089..28c6e3745c61d0670bf7f3a324169472250e25f4 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseSkeleton.java ++++ b/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseSkeleton.java +@@ -43,6 +43,11 @@ public class EntityHorseSkeleton extends EntityHorseAbstract { + public boolean isTamed() { + return true; + } ++ ++ @Override ++ public int getPurpurBreedTime() { ++ return 6000; ++ } + // Purpur end + + public static AttributeProvider.Builder eL() { +diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseZombie.java b/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseZombie.java +index d57e7c02268e5d8a00b0b5897fa03dcee10cd2e0..c776f18722d1aa73f53da66ef6b37564eeaddd2a 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseZombie.java ++++ b/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseZombie.java +@@ -35,6 +35,11 @@ public class EntityHorseZombie extends EntityHorseAbstract { + public boolean isTamed() { + return true; + } ++ ++ @Override ++ public int getPurpurBreedTime() { ++ return 6000; ++ } + // Purpur end + + public static AttributeProvider.Builder eL() { +diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/EntityLlama.java b/src/main/java/net/minecraft/world/entity/animal/horse/EntityLlama.java +index d25177f9500a084e0f18a20b1eb1c4ac170048ec..2710c246a147f117d2d90014c37988888010dc36 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/horse/EntityLlama.java ++++ b/src/main/java/net/minecraft/world/entity/animal/horse/EntityLlama.java +@@ -108,6 +108,11 @@ public class EntityLlama extends EntityHorseChestedAbstract implements IRangedEn + public boolean hasSaddle() { + return super.hasSaddle() || (isTamed() && getColor() != null); + } ++ ++ @Override ++ public int getPurpurBreedTime() { ++ return this.world.purpurConfig.llamaBreedingTicks; ++ } + // Purpur end + + public void setStrength(int i) { +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityStrider.java b/src/main/java/net/minecraft/world/entity/monster/EntityStrider.java +index 14dda6743ed9e6f4880bc560f7ba8892d8e84afe..cba66a08feceeeaf7c123da595fc7b12c5749783 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityStrider.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityStrider.java +@@ -105,6 +105,11 @@ public class EntityStrider extends EntityAnimal implements ISteerable, ISaddleab + public boolean isRidableInWater() { + return world.purpurConfig.striderRidableInWater; + } ++ ++ @Override ++ public int getPurpurBreedTime() { ++ return this.world.purpurConfig.striderBreedingTicks; ++ } + // Purpur end + + public static boolean c(EntityTypes entitytypes, GeneratorAccess generatoraccess, EnumMobSpawn enummobspawn, BlockPosition blockposition, Random random) { +diff --git a/src/main/java/net/minecraft/world/entity/monster/hoglin/EntityHoglin.java b/src/main/java/net/minecraft/world/entity/monster/hoglin/EntityHoglin.java +index 9bac45983b55abf9b72f2c45f632cdedd48f81f9..9f2af4b37ffb22034b537cc27b42d520a41d4fe7 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/hoglin/EntityHoglin.java ++++ b/src/main/java/net/minecraft/world/entity/monster/hoglin/EntityHoglin.java +@@ -71,6 +71,11 @@ public class EntityHoglin extends EntityAnimal implements IMonster, IOglin { + public boolean isRidableInWater() { + return world.purpurConfig.hoglinRidableInWater; + } ++ ++ @Override ++ public int getPurpurBreedTime() { ++ return this.world.purpurConfig.hoglinBreedingTicks; ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index b92715b115332e8197d5a02a2f308a1ab0f447b6..bd37234624a720c1077aabf0123de61a0d4e05cb 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -492,10 +492,12 @@ public class PurpurWorldConfig { + public boolean beeRidable = false; + public boolean beeRidableInWater = false; + public double beeMaxY = 256D; ++ public int beeBreedingTicks = 6000; + private void beeSettings() { + beeRidable = getBoolean("mobs.bee.ridable", beeRidable); + beeRidableInWater = getBoolean("mobs.bee.ridable-in-water", beeRidableInWater); + beeMaxY = getDouble("mobs.bee.ridable-max-y", beeMaxY); ++ beeBreedingTicks = getInt("mobs.bee.breeding-delay-ticks", beeBreedingTicks); + } + + public boolean blazeRidable = false; +@@ -512,12 +514,14 @@ public class PurpurWorldConfig { + public int catSpawnDelay = 1200; + public int catSpawnSwampHutScanRange = 16; + public int catSpawnVillageScanRange = 48; ++ public int catBreedingTicks = 6000; + private void catSettings() { + catRidable = getBoolean("mobs.cat.ridable", catRidable); + catRidableInWater = getBoolean("mobs.cat.ridable-in-water", catRidableInWater); + catSpawnDelay = getInt("mobs.cat.spawn-delay", catSpawnDelay); + catSpawnSwampHutScanRange = getInt("mobs.cat.scan-range-for-other-cats.swamp-hut", catSpawnSwampHutScanRange); + catSpawnVillageScanRange = getInt("mobs.cat.scan-range-for-other-cats.village", catSpawnVillageScanRange); ++ catBreedingTicks = getInt("mobs.cat.breeding-delay-ticks", catBreedingTicks); + } + + public boolean caveSpiderRidable = false; +@@ -530,10 +534,12 @@ public class PurpurWorldConfig { + public boolean chickenRidable = false; + public boolean chickenRidableInWater = false; + public boolean chickenRetaliate = false; ++ public int chickenBreedingTicks = 6000; + private void chickenSettings() { + chickenRidable = getBoolean("mobs.chicken.ridable", chickenRidable); + chickenRidableInWater = getBoolean("mobs.chicken.ridable-in-water", chickenRidableInWater); + chickenRetaliate = getBoolean("mobs.chicken.retaliate", chickenRetaliate); ++ chickenBreedingTicks = getInt("mobs.chicken.breeding-delay-ticks", chickenBreedingTicks); + } + + public boolean codRidable = false; +@@ -544,10 +550,12 @@ public class PurpurWorldConfig { + public boolean cowRidable = false; + public boolean cowRidableInWater = false; + public int cowFeedMushrooms = 0; ++ public int cowBreedingTicks = 6000; + private void cowSettings() { + cowRidable = getBoolean("mobs.cow.ridable", cowRidable); + cowRidableInWater = getBoolean("mobs.cow.ridable-in-water", cowRidableInWater); + cowFeedMushrooms = getInt("mobs.cow.feed-mushrooms-for-mooshroom", cowFeedMushrooms); ++ cowBreedingTicks = getInt("mobs.cow.breeding-delay-ticks", cowBreedingTicks); + } + + public boolean creeperRidable = false; +@@ -575,8 +583,10 @@ public class PurpurWorldConfig { + } + + public boolean donkeyRidableInWater = false; ++ public int donkeyBreedingTicks = 6000; + private void donkeySettings() { + donkeyRidableInWater = getBoolean("mobs.donkey.ridable-in-water", donkeyRidableInWater); ++ donkeyBreedingTicks = getInt("mobs.donkey.breeding-delay-ticks", donkeyBreedingTicks); + } + + public boolean drownedRidable = false; +@@ -634,10 +644,12 @@ public class PurpurWorldConfig { + public boolean foxRidable = false; + public boolean foxRidableInWater = false; + public boolean foxTypeChangesWithTulips = false; ++ public int foxBreedingTicks = 6000; + private void foxSettings() { + foxRidable = getBoolean("mobs.fox.ridable", foxRidable); + foxRidableInWater = getBoolean("mobs.fox.ridable-in-water", foxRidableInWater); + foxTypeChangesWithTulips = getBoolean("mobs.fox.tulips-change-type", foxTypeChangesWithTulips); ++ foxBreedingTicks = getInt("mobs.fox.breeding-delay-ticks", foxBreedingTicks); + } + + public boolean ghastRidable = false; +@@ -682,14 +694,18 @@ public class PurpurWorldConfig { + + public boolean hoglinRidable = false; + public boolean hoglinRidableInWater = false; ++ public int hoglinBreedingTicks = 6000; + private void hoglinSettings() { + hoglinRidable = getBoolean("mobs.hoglin.ridable", hoglinRidable); + hoglinRidableInWater = getBoolean("mobs.hoglin.ridable-in-water", hoglinRidableInWater); ++ hoglinBreedingTicks = getInt("mobs.hoglin.breeding-delay-ticks", hoglinBreedingTicks); + } + + public boolean horseRidableInWater = false; ++ public int horseBreedingTicks = 6000; + private void horseSettings() { + horseRidableInWater = getBoolean("mobs.horse.ridable-in-water", horseRidableInWater); ++ horseBreedingTicks = getInt("mobs.horse.breeding-delay-ticks", horseBreedingTicks); + } + + public boolean huskRidable = false; +@@ -734,9 +750,11 @@ public class PurpurWorldConfig { + + public boolean llamaRidable = false; + public boolean llamaRidableInWater = false; ++ public int llamaBreedingTicks = 6000; + private void llamaSettings() { + llamaRidable = getBoolean("mobs.llama.ridable", llamaRidable); + llamaRidableInWater = getBoolean("mobs.llama.ridable-in-water", llamaRidableInWater); ++ llamaBreedingTicks = getInt("mobs.llama.breeding-delay-ticks", llamaBreedingTicks); + } + + public boolean llamaTraderRidable = false; +@@ -755,28 +773,36 @@ public class PurpurWorldConfig { + + public boolean mooshroomRidable = false; + public boolean mooshroomRidableInWater = false; ++ public int mooshroomBreedingTicks = 6000; + private void mooshroomSettings() { + mooshroomRidable = getBoolean("mobs.mooshroom.ridable", mooshroomRidable); + mooshroomRidableInWater = getBoolean("mobs.mooshroom.ridable-in-water", mooshroomRidableInWater); ++ mooshroomBreedingTicks = getInt("mobs.mooshroom.breeding-delay-ticks", mooshroomBreedingTicks); + } + + public boolean muleRidableInWater = false; ++ public int muleBreedingTicks = 6000; + private void muleSettings() { + muleRidableInWater = getBoolean("mobs.mule.ridable-in-water", muleRidableInWater); ++ muleBreedingTicks = getInt("mobs.mule.breeding-delay-ticks", muleBreedingTicks); + } + + public boolean ocelotRidable = false; + public boolean ocelotRidableInWater = false; ++ public int ocelotBreedingTicks = 6000; + private void ocelotSettings() { + ocelotRidable = getBoolean("mobs.ocelot.ridable", ocelotRidable); + ocelotRidableInWater = getBoolean("mobs.ocelot.ridable-in-water", ocelotRidableInWater); ++ ocelotBreedingTicks = getInt("mobs.ocelot.breeding-delay-ticks", ocelotBreedingTicks); + } + + public boolean pandaRidable = false; + public boolean pandaRidableInWater = false; ++ public int pandaBreedingTicks = 6000; + private void pandaSettings() { + pandaRidable = getBoolean("mobs.panda.ridable", pandaRidable); + pandaRidableInWater = getBoolean("mobs.panda.ridable-in-water", pandaRidableInWater); ++ pandaBreedingTicks = getInt("mobs.panda.breeding-delay-ticks", pandaBreedingTicks); + } + + public boolean parrotRidable = false; +@@ -842,10 +868,12 @@ public class PurpurWorldConfig { + public boolean pigRidable = false; + public boolean pigRidableInWater = false; + public boolean pigGiveSaddleBack = false; ++ public int pigBreedingTicks = 6000; + private void pigSettings() { + pigRidable = getBoolean("mobs.pig.ridable", pigRidable); + pigRidableInWater = getBoolean("mobs.pig.ridable-in-water", pigRidableInWater); + pigGiveSaddleBack = getBoolean("mobs.pig.give-saddle-back", pigGiveSaddleBack); ++ pigBreedingTicks = getInt("mobs.pig.breeding-delay-ticks", pigBreedingTicks); + } + + public boolean piglinRidable = false; +@@ -873,12 +901,14 @@ public class PurpurWorldConfig { + public boolean polarBearRidableInWater = false; + public String polarBearBreedableItemString = ""; + public Item polarBearBreedableItem = null; ++ public int polarBearBreedingTicks = 6000; + private void polarBearSettings() { + polarBearRidable = getBoolean("mobs.polar_bear.ridable", polarBearRidable); + polarBearRidableInWater = getBoolean("mobs.polar_bear.ridable-in-water", polarBearRidableInWater); + polarBearBreedableItemString = getString("mobs.polar_bear.breedable-item", polarBearBreedableItemString); + Item item = IRegistry.ITEM.get(new MinecraftKey(polarBearBreedableItemString)); + if (item != Items.AIR) polarBearBreedableItem = item; ++ polarBearBreedingTicks = getInt("mobs.polar_bear.breeding-delay-ticks", polarBearBreedingTicks); + } + + public boolean pufferfishRidable = false; +@@ -890,11 +920,13 @@ public class PurpurWorldConfig { + public boolean rabbitRidableInWater = false; + public double rabbitNaturalToast = 0.0D; + public double rabbitNaturalKiller = 0.0D; ++ public int rabbitBreedingTicks = 6000; + private void rabbitSettings() { + rabbitRidable = getBoolean("mobs.rabbit.ridable", rabbitRidable); + rabbitRidableInWater = getBoolean("mobs.rabbit.ridable-in-water", rabbitRidableInWater); + rabbitNaturalToast = getDouble("mobs.rabbit.spawn-toast-chance", rabbitNaturalToast); + rabbitNaturalKiller = getDouble("mobs.rabbit.spawn-killer-rabbit-chance", rabbitNaturalKiller); ++ rabbitBreedingTicks = getInt("mobs.rabbit.breeding-delay-ticks", rabbitBreedingTicks); + } + + public boolean ravagerRidable = false; +@@ -911,9 +943,11 @@ public class PurpurWorldConfig { + + public boolean sheepRidable = false; + public boolean sheepRidableInWater = false; ++ public int sheepBreedingTicks = 6000; + private void sheepSettings() { + sheepRidable = getBoolean("mobs.sheep.ridable", sheepRidable); + sheepRidableInWater = getBoolean("mobs.sheep.ridable-in-water", sheepRidableInWater); ++ sheepBreedingTicks = getInt("mobs.sheep.breeding-delay-ticks", sheepBreedingTicks); + } + + public boolean shulkerRidable = false; +@@ -991,9 +1025,11 @@ public class PurpurWorldConfig { + + public boolean striderRidable = false; + public boolean striderRidableInWater = false; ++ public int striderBreedingTicks = 6000; + private void striderSettings() { + striderRidable = getBoolean("mobs.strider.ridable", striderRidable); + striderRidableInWater = getBoolean("mobs.strider.ridable-in-water", striderRidableInWater); ++ striderBreedingTicks = getInt("mobs.strider.breeding-delay-ticks", striderBreedingTicks); + } + + public boolean tropicalFishRidable = false; +@@ -1003,9 +1039,11 @@ public class PurpurWorldConfig { + + public boolean turtleRidable = false; + public boolean turtleRidableInWater = false; ++ public int turtleBreedingTicks = 6000; + private void turtleSettings() { + turtleRidable = getBoolean("mobs.turtle.ridable", turtleRidable); + turtleRidableInWater = getBoolean("mobs.turtle.ridable-in-water", turtleRidableInWater); ++ turtleBreedingTicks = getInt("mobs.turtle.breeding-delay-ticks", turtleBreedingTicks); + } + + public boolean vexRidable = false; +@@ -1027,6 +1065,7 @@ public class PurpurWorldConfig { + public int villagerSpawnIronGolemRadius = 0; + public int villagerSpawnIronGolemLimit = 0; + public boolean villagerCanBreed = true; ++ public int villagerBreedingTicks = 6000; + private void villagerSettings() { + villagerRidable = getBoolean("mobs.villager.ridable", villagerRidable); + villagerRidableInWater = getBoolean("mobs.villager.ridable-in-water", villagerRidableInWater); +@@ -1038,6 +1077,7 @@ public class PurpurWorldConfig { + villagerSpawnIronGolemRadius = getInt("mobs.villager.spawn-iron-golem.radius", villagerSpawnIronGolemRadius); + villagerSpawnIronGolemLimit = getInt("mobs.villager.spawn-iron-golem.limit", villagerSpawnIronGolemLimit); + villagerCanBreed = getBoolean("mobs.villager.can-breed", villagerCanBreed); ++ villagerBreedingTicks = getInt("mobs.villager.breeding-delay-ticks", villagerBreedingTicks); + } + + public boolean villagerTraderRidable = false; +@@ -1098,9 +1138,11 @@ public class PurpurWorldConfig { + + public boolean wolfRidable = false; + public boolean wolfRidableInWater = false; ++ public int wolfBreedingTicks = 6000; + private void wolfSettings() { + wolfRidable = getBoolean("mobs.wolf.ridable", wolfRidable); + wolfRidableInWater = getBoolean("mobs.wolf.ridable-in-water", wolfRidableInWater); ++ wolfBreedingTicks = getInt("mobs.wolf.breeding-delay-ticks", wolfBreedingTicks); + } + + public boolean zoglinRidable = false; diff --git a/patches/Purpur/patches/server/0123-Apply-display-names-from-item-forms-of-entities-to-e.patch b/patches/Purpur/patches/server/0123-Apply-display-names-from-item-forms-of-entities-to-e.patch new file mode 100644 index 00000000..52b56cbf --- /dev/null +++ b/patches/Purpur/patches/server/0123-Apply-display-names-from-item-forms-of-entities-to-e.patch @@ -0,0 +1,186 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: jmp +Date: Tue, 17 Nov 2020 03:23:48 -0800 +Subject: [PATCH] Apply display names from item forms of entities to entities + and vice versa + + +diff --git a/src/main/java/net/minecraft/world/entity/decoration/EntityArmorStand.java b/src/main/java/net/minecraft/world/entity/decoration/EntityArmorStand.java +index 89d3734489b65245e815376edf4e2d9baea1563a..43dc0925887e2e9e86445cccff57be7994ca0d58 100644 +--- a/src/main/java/net/minecraft/world/entity/decoration/EntityArmorStand.java ++++ b/src/main/java/net/minecraft/world/entity/decoration/EntityArmorStand.java +@@ -588,7 +588,13 @@ public class EntityArmorStand extends EntityLiving { + } + + private void f(DamageSource damagesource) { +- drops.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(new ItemStack(Items.ARMOR_STAND))); // CraftBukkit - add to drops ++ // Purpur start ++ final ItemStack armorStand = new ItemStack(Items.ARMOR_STAND); ++ if (this.world.purpurConfig.persistentDroppableEntityDisplayNames && this.hasCustomName()) { ++ armorStand.setName(this.getCustomName()); ++ } ++ drops.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(armorStand)); // CraftBukkit - add to drops ++ // Purpur end + this.g(damagesource); + } + +diff --git a/src/main/java/net/minecraft/world/entity/decoration/EntityItemFrame.java b/src/main/java/net/minecraft/world/entity/decoration/EntityItemFrame.java +index 43152a6c70c9433d627a58051101530ddd693307..eb07db442c5a0da73249f4a02be7dacae0ff0e45 100644 +--- a/src/main/java/net/minecraft/world/entity/decoration/EntityItemFrame.java ++++ b/src/main/java/net/minecraft/world/entity/decoration/EntityItemFrame.java +@@ -229,7 +229,13 @@ public class EntityItemFrame extends EntityHanging { + } + + if (flag) { +- this.a((IMaterial) Items.ITEM_FRAME); ++ // Purpur start ++ final ItemStack itemFrame = new ItemStack(Items.ITEM_FRAME); ++ if (this.world.purpurConfig.persistentDroppableEntityDisplayNames && this.hasCustomName()) { ++ itemFrame.setName(this.getCustomName()); ++ } ++ this.dropItem(itemFrame); ++ // Purpur end + } + + if (!itemstack.isEmpty()) { +diff --git a/src/main/java/net/minecraft/world/entity/decoration/EntityPainting.java b/src/main/java/net/minecraft/world/entity/decoration/EntityPainting.java +index 3de0f21648ca60bdfcbc078bca896d51bf84e207..7517e861301e0c329c70aa6f2bf5aa40114b6589 100644 +--- a/src/main/java/net/minecraft/world/entity/decoration/EntityPainting.java ++++ b/src/main/java/net/minecraft/world/entity/decoration/EntityPainting.java +@@ -108,7 +108,13 @@ public class EntityPainting extends EntityHanging { + } + } + +- this.a((IMaterial) Items.PAINTING); ++ // Purpur start ++ final ItemStack painting = new ItemStack(Items.PAINTING); ++ if (this.world.purpurConfig.persistentDroppableEntityDisplayNames && this.hasCustomName()) { ++ painting.setName(this.getCustomName()); ++ } ++ this.dropItem(painting); ++ // Purpur end + } + } + +diff --git a/src/main/java/net/minecraft/world/entity/vehicle/EntityBoat.java b/src/main/java/net/minecraft/world/entity/vehicle/EntityBoat.java +index e5cda8c040c93639211dacbf5b0c7cd6a9df9e6d..9cd1a2a2a8db1d8daf7c712d6bd03fad1b048485 100644 +--- a/src/main/java/net/minecraft/world/entity/vehicle/EntityBoat.java ++++ b/src/main/java/net/minecraft/world/entity/vehicle/EntityBoat.java +@@ -201,7 +201,13 @@ public class EntityBoat extends Entity { + } + // CraftBukkit end + if (!flag && this.world.getGameRules().getBoolean(GameRules.DO_ENTITY_DROPS)) { +- this.a((IMaterial) this.g()); ++ // Purpur start ++ final ItemStack boat = new ItemStack(this.getBoatItem()); ++ if (this.world.purpurConfig.persistentDroppableEntityDisplayNames && this.hasCustomName()) { ++ boat.setName(this.getCustomName()); ++ } ++ this.dropItem(boat); ++ // Purpur end + } + + this.die(); +diff --git a/src/main/java/net/minecraft/world/item/ItemArmorStand.java b/src/main/java/net/minecraft/world/item/ItemArmorStand.java +index cd46df5485ebfd597ea72360a27872d46174ee19..245d3fe09feb9dc27b097642d40664a9f2377581 100644 +--- a/src/main/java/net/minecraft/world/item/ItemArmorStand.java ++++ b/src/main/java/net/minecraft/world/item/ItemArmorStand.java +@@ -63,6 +63,14 @@ public class ItemArmorStand extends Item { + return EnumInteractionResult.FAIL; + } + // CraftBukkit end ++ // Purpur start ++ if (itemactioncontext.getWorld().purpurConfig.persistentDroppableEntityDisplayNames && itemactioncontext.getItemStack().hasName()) { ++ entityarmorstand.setCustomName(itemactioncontext.getItemStack().getName()); ++ if (itemactioncontext.getWorld().purpurConfig.armorstandSetNameVisible) { ++ entityarmorstand.setCustomNameVisible(true); ++ } ++ } ++ // Purpur end + worldserver.addAllEntities(entityarmorstand); // Paper - moved down + world.playSound((EntityHuman) null, entityarmorstand.locX(), entityarmorstand.locY(), entityarmorstand.locZ(), SoundEffects.ENTITY_ARMOR_STAND_PLACE, SoundCategory.BLOCKS, 0.75F, 0.8F); + } +diff --git a/src/main/java/net/minecraft/world/item/ItemBoat.java b/src/main/java/net/minecraft/world/item/ItemBoat.java +index 1d812b3e27f87213afc3e441eb20ca984458ce2a..636a8bc76d436fc770b4e05a93f1991210b64230 100644 +--- a/src/main/java/net/minecraft/world/item/ItemBoat.java ++++ b/src/main/java/net/minecraft/world/item/ItemBoat.java +@@ -65,6 +65,11 @@ public class ItemBoat extends Item { + + entityboat.setType(this.b); + entityboat.yaw = entityhuman.yaw; ++ // Purpur start ++ if (world.purpurConfig.persistentDroppableEntityDisplayNames && itemstack.hasName()) { ++ entityboat.setCustomName(itemstack.getName()); ++ } ++ // Purpur end + if (!world.getCubes(entityboat, entityboat.getBoundingBox().g(-0.1D))) { + return InteractionResultWrapper.fail(itemstack); + } else { +diff --git a/src/main/java/net/minecraft/world/item/ItemHanging.java b/src/main/java/net/minecraft/world/item/ItemHanging.java +index bbd3bb2d12e500d15485598783d39b0cb63a6d83..8e4c3304779cfccf7d45d4843f9c15bffce8ba07 100644 +--- a/src/main/java/net/minecraft/world/item/ItemHanging.java ++++ b/src/main/java/net/minecraft/world/item/ItemHanging.java +@@ -39,7 +39,7 @@ public class ItemHanging extends Item { + return EnumInteractionResult.FAIL; + } else { + World world = itemactioncontext.getWorld(); +- Object object; ++ Entity object; // Purpur + + if (this.a == EntityTypes.PAINTING) { + object = new EntityPainting(world, blockposition1, enumdirection); +@@ -55,6 +55,11 @@ public class ItemHanging extends Item { + + if (nbttagcompound != null) { + EntityTypes.a(world, entityhuman, (Entity) object, nbttagcompound); ++ // Purpur start ++ if (itemactioncontext.getWorld().purpurConfig.persistentDroppableEntityDisplayNames && itemactioncontext.getItemStack().hasName()) { ++ object.setCustomName(itemactioncontext.getItemStack().getName()); ++ } ++ // Purpur end + } + + if (((EntityHanging) object).survives()) { +diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java +index 2aa761656ce75f78732c502fd4ce65034b6c2919..a4c41caae425e054db3f40a9abc41f45ccd20730 100644 +--- a/src/main/java/net/minecraft/world/item/ItemStack.java ++++ b/src/main/java/net/minecraft/world/item/ItemStack.java +@@ -788,6 +788,7 @@ public final class ItemStack { + return this.getItem().h(this); + } + ++ public ItemStack setName(@Nullable IChatBaseComponent component) { return this.a(component); } // Purpur - OBFHELPER + public ItemStack a(@Nullable IChatBaseComponent ichatbasecomponent) { + NBTTagCompound nbttagcompound = this.a("display"); + +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index bd37234624a720c1077aabf0123de61a0d4e05cb..b650293ff3315760e29307113e29fb2731af472b 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -83,8 +83,10 @@ public class PurpurWorldConfig { + return PurpurConfig.config.getString("world-settings." + worldName + "." + path, PurpurConfig.config.getString("world-settings.default." + path)); + } + ++ public boolean armorstandSetNameVisible = false; + public float armorstandStepHeight = 0.0F; + private void armorstandSettings() { ++ armorstandSetNameVisible = getBoolean("gameplay-mechanics.armorstand.set-name-visible-when-placing-with-custom-name", armorstandSetNameVisible); + armorstandStepHeight = (float) getDouble("gameplay-mechanics.armorstand.step-height", armorstandStepHeight); + } + +@@ -261,6 +263,7 @@ public class PurpurWorldConfig { + public boolean entitiesCanUsePortals = true; + public boolean milkCuresBadOmen = true; + public boolean persistentTileEntityDisplayNames = false; ++ public boolean persistentDroppableEntityDisplayNames = false; + public double tridentLoyaltyVoidReturnHeight = 0.0D; + public double voidDamageHeight = -64.0D; + public double voidDamageDealt = 4.0D; +@@ -274,6 +277,7 @@ public class PurpurWorldConfig { + entitiesCanUsePortals = getBoolean("gameplay-mechanics.entities-can-use-portals", entitiesCanUsePortals); + milkCuresBadOmen = getBoolean("gameplay-mechanics.milk-cures-bad-omen", milkCuresBadOmen); + persistentTileEntityDisplayNames = getBoolean("gameplay-mechanics.persistent-tileentity-display-names-and-lore", persistentTileEntityDisplayNames); ++ persistentDroppableEntityDisplayNames = getBoolean("gameplay-mechanics.persistent-droppable-entity-display-names", persistentDroppableEntityDisplayNames); + tridentLoyaltyVoidReturnHeight = getDouble("gameplay-mechanics.trident-loyalty-void-return-height", tridentLoyaltyVoidReturnHeight); + voidDamageHeight = getDouble("gameplay-mechanics.void-damage-height", voidDamageHeight); + voidDamageDealt = getDouble("gameplay-mechanics.void-damage-dealt", voidDamageDealt); diff --git a/patches/Purpur/patches/server/0124-Set-name-visible-when-using-a-Name-Tag-on-an-Armor-S.patch b/patches/Purpur/patches/server/0124-Set-name-visible-when-using-a-Name-Tag-on-an-Armor-S.patch new file mode 100644 index 00000000..facfc495 --- /dev/null +++ b/patches/Purpur/patches/server/0124-Set-name-visible-when-using-a-Name-Tag-on-an-Armor-S.patch @@ -0,0 +1,46 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: jmp +Date: Tue, 17 Nov 2020 13:12:09 -0800 +Subject: [PATCH] Set name visible when using a Name Tag on an Armor Stand + + +diff --git a/src/main/java/net/minecraft/world/item/ItemNameTag.java b/src/main/java/net/minecraft/world/item/ItemNameTag.java +index b9b2b27e534ba87a1aae3c521f393a066a18a199..4f4e9ebb9af4970fe920a540d40dbc56682efd57 100644 +--- a/src/main/java/net/minecraft/world/item/ItemNameTag.java ++++ b/src/main/java/net/minecraft/world/item/ItemNameTag.java +@@ -5,6 +5,7 @@ import net.minecraft.world.EnumHand; + import net.minecraft.world.EnumInteractionResult; + import net.minecraft.world.entity.EntityInsentient; + import net.minecraft.world.entity.EntityLiving; ++import net.minecraft.world.entity.decoration.EntityArmorStand; + import net.minecraft.world.entity.player.EntityHuman; + + // Paper start +@@ -27,6 +28,11 @@ public class ItemNameTag extends Item { + if (!event.callEvent()) return EnumInteractionResult.PASS; + EntityLiving newEntityLiving = ((org.bukkit.craftbukkit.entity.CraftLivingEntity) event.getEntity()).getHandle(); + newEntityLiving.setCustomName(event.getName() != null ? PaperAdventure.asVanilla(event.getName()) : null); ++ // Purpur start ++ if (entityhuman.world.purpurConfig.armorstandFixNametags && entityliving instanceof EntityArmorStand) { ++ entityliving.setCustomNameVisible(true); ++ } ++ // Purpur end + if (event.isPersistent() && newEntityLiving instanceof EntityInsentient) { + ((EntityInsentient) newEntityLiving).setPersistent(); + } +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index b650293ff3315760e29307113e29fb2731af472b..dc1418f8f324eae24af3e993c6c720ff73702c92 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -84,9 +84,11 @@ public class PurpurWorldConfig { + } + + public boolean armorstandSetNameVisible = false; ++ public boolean armorstandFixNametags = false; + public float armorstandStepHeight = 0.0F; + private void armorstandSettings() { + armorstandSetNameVisible = getBoolean("gameplay-mechanics.armorstand.set-name-visible-when-placing-with-custom-name", armorstandSetNameVisible); ++ armorstandFixNametags = getBoolean("gameplay-mechanics.armorstand.fix-nametags", armorstandFixNametags); + armorstandStepHeight = (float) getDouble("gameplay-mechanics.armorstand.step-height", armorstandStepHeight); + } + diff --git a/patches/Purpur/patches/server/0125-Add-twisting-and-weeping-vines-growth-rates.patch b/patches/Purpur/patches/server/0125-Add-twisting-and-weeping-vines-growth-rates.patch new file mode 100644 index 00000000..def89357 --- /dev/null +++ b/patches/Purpur/patches/server/0125-Add-twisting-and-weeping-vines-growth-rates.patch @@ -0,0 +1,113 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Sun, 22 Nov 2020 06:02:32 -0600 +Subject: [PATCH] Add twisting and weeping vines growth rates + + +diff --git a/src/main/java/net/minecraft/world/level/block/BlockGrowingTop.java b/src/main/java/net/minecraft/world/level/block/BlockGrowingTop.java +index 84bd1fa9edb59b8515685a47783ed5e6abe7333f..546c7877647bac41753a600bd25c630a0510be56 100644 +--- a/src/main/java/net/minecraft/world/level/block/BlockGrowingTop.java ++++ b/src/main/java/net/minecraft/world/level/block/BlockGrowingTop.java +@@ -38,9 +38,11 @@ public abstract class BlockGrowingTop extends BlockGrowingAbstract implements IB + return (Integer) iblockdata.get(BlockGrowingTop.d) < 25; + } + ++ public abstract double getGrowthModifier(WorldServer worldserver); // Purpur ++ + @Override + public void tick(IBlockData iblockdata, WorldServer worldserver, BlockPosition blockposition, Random random) { +- if ((Integer) iblockdata.get(BlockGrowingTop.d) < 25 && random.nextDouble() < (100.0D / worldserver.spigotConfig.kelpModifier) * this.e) { // Spigot ++ if ((Integer) iblockdata.get(BlockGrowingTop.d) < 25 && random.nextDouble() < (100.0D / getGrowthModifier(worldserver)) * this.e) { // Spigot // Purpur + BlockPosition blockposition1 = blockposition.shift(this.a); + + if (this.h(worldserver.getType(blockposition1))) { +diff --git a/src/main/java/net/minecraft/world/level/block/BlockKelp.java b/src/main/java/net/minecraft/world/level/block/BlockKelp.java +index 424b9b3c1263910eb6113f19efc14607dd2bf638..27f1cbe8786d7c37d62193a21baf0a2bdc6f0294 100644 +--- a/src/main/java/net/minecraft/world/level/block/BlockKelp.java ++++ b/src/main/java/net/minecraft/world/level/block/BlockKelp.java +@@ -4,6 +4,7 @@ import java.util.Random; + import javax.annotation.Nullable; + import net.minecraft.core.BlockPosition; + import net.minecraft.core.EnumDirection; ++import net.minecraft.server.level.WorldServer; + import net.minecraft.tags.Tag; + import net.minecraft.tags.TagsFluid; + import net.minecraft.world.item.context.BlockActionContext; +@@ -66,4 +67,10 @@ public class BlockKelp extends BlockGrowingTop implements IFluidContainer { + public Fluid d(IBlockData iblockdata) { + return FluidTypes.WATER.a(false); + } ++ ++ // Purpur start ++ public double getGrowthModifier(WorldServer worldserver) { ++ return worldserver.spigotConfig.kelpModifier; ++ } ++ // Purpur end + } +diff --git a/src/main/java/net/minecraft/world/level/block/BlockTwistingVines.java b/src/main/java/net/minecraft/world/level/block/BlockTwistingVines.java +index 2cfa96f144391e664207ac8e8bdd3f11bfed4dff..3a8d08a1ee8f066cea36e6acff492e5af62993c5 100644 +--- a/src/main/java/net/minecraft/world/level/block/BlockTwistingVines.java ++++ b/src/main/java/net/minecraft/world/level/block/BlockTwistingVines.java +@@ -2,6 +2,7 @@ package net.minecraft.world.level.block; + + import java.util.Random; + import net.minecraft.core.EnumDirection; ++import net.minecraft.server.level.WorldServer; + import net.minecraft.world.level.block.state.BlockBase; + import net.minecraft.world.level.block.state.IBlockData; + import net.minecraft.world.phys.shapes.VoxelShape; +@@ -28,4 +29,10 @@ public class BlockTwistingVines extends BlockGrowingTop { + protected boolean h(IBlockData iblockdata) { + return BlockNetherVinesUtil.a(iblockdata); + } ++ ++ // Purpur start ++ public double getGrowthModifier(WorldServer worldserver) { ++ return worldserver.purpurConfig.twistingVinesGrowthModifier; ++ } ++ // Purpur end + } +diff --git a/src/main/java/net/minecraft/world/level/block/BlockWeepingVines.java b/src/main/java/net/minecraft/world/level/block/BlockWeepingVines.java +index 2552631084926c2fad40b3f21ae479c0e1cfdb77..198bd8857571872ed3f7437529c330dceeb825db 100644 +--- a/src/main/java/net/minecraft/world/level/block/BlockWeepingVines.java ++++ b/src/main/java/net/minecraft/world/level/block/BlockWeepingVines.java +@@ -2,6 +2,7 @@ package net.minecraft.world.level.block; + + import java.util.Random; + import net.minecraft.core.EnumDirection; ++import net.minecraft.server.level.WorldServer; + import net.minecraft.world.level.block.state.BlockBase; + import net.minecraft.world.level.block.state.IBlockData; + import net.minecraft.world.phys.shapes.VoxelShape; +@@ -28,4 +29,10 @@ public class BlockWeepingVines extends BlockGrowingTop { + protected boolean h(IBlockData iblockdata) { + return BlockNetherVinesUtil.a(iblockdata); + } ++ ++ // Purpur start ++ public double getGrowthModifier(WorldServer worldserver) { ++ return worldserver.purpurConfig.weepingVinesGrowthModifier; ++ } ++ // Purpur end + } +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index dc1418f8f324eae24af3e993c6c720ff73702c92..17bbe2ceea016bcb00dc5542bea47e083e723ea5 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -477,6 +477,16 @@ public class PurpurWorldConfig { + turtleEggsBreakFromMinecarts = getBoolean("blocks.turtle_egg.break-from-minecarts", turtleEggsBreakFromMinecarts); + } + ++ public double twistingVinesGrowthModifier = 0.10D; ++ private void twistingVinesSettings() { ++ twistingVinesGrowthModifier = getDouble("blocks.twisting_vines.growth-modifier", twistingVinesGrowthModifier); ++ } ++ ++ public double weepingVinesGrowthModifier = 0.10D; ++ private void weepingVinesSettings() { ++ weepingVinesGrowthModifier = getDouble("blocks.weeping_vines.growth-modifier", weepingVinesGrowthModifier); ++ } ++ + public boolean babiesAreRidable = true; + public boolean untamedTamablesAreRidable = true; + public boolean useNightVisionWhenRiding = false; diff --git a/patches/Purpur/patches/server/0126-Kelp-weeping-and-twisting-vines-configurable-max-gro.patch b/patches/Purpur/patches/server/0126-Kelp-weeping-and-twisting-vines-configurable-max-gro.patch new file mode 100644 index 00000000..bdd2fc3d --- /dev/null +++ b/patches/Purpur/patches/server/0126-Kelp-weeping-and-twisting-vines-configurable-max-gro.patch @@ -0,0 +1,124 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Sun, 22 Nov 2020 20:13:27 -0600 +Subject: [PATCH] Kelp weeping and twisting vines configurable max growth age + + +diff --git a/src/main/java/net/minecraft/world/level/block/BlockGrowingTop.java b/src/main/java/net/minecraft/world/level/block/BlockGrowingTop.java +index 546c7877647bac41753a600bd25c630a0510be56..3d6a1131a138114424b683a81d04478e92d05544 100644 +--- a/src/main/java/net/minecraft/world/level/block/BlockGrowingTop.java ++++ b/src/main/java/net/minecraft/world/level/block/BlockGrowingTop.java +@@ -30,7 +30,7 @@ public abstract class BlockGrowingTop extends BlockGrowingAbstract implements IB + + @Override + public IBlockData a(GeneratorAccess generatoraccess) { +- return (IBlockData) this.getBlockData().set(BlockGrowingTop.d, generatoraccess.getRandom().nextInt(25)); ++ return (IBlockData) this.getBlockData().set(BlockGrowingTop.d, generatoraccess.getRandom().nextInt(getMaxGrowthAge(generatoraccess.getMinecraftWorld()))); // Purpur + } + + @Override +@@ -40,9 +40,11 @@ public abstract class BlockGrowingTop extends BlockGrowingAbstract implements IB + + public abstract double getGrowthModifier(WorldServer worldserver); // Purpur + ++ public abstract int getMaxGrowthAge(WorldServer worldserver); // Purpur ++ + @Override + public void tick(IBlockData iblockdata, WorldServer worldserver, BlockPosition blockposition, Random random) { +- if ((Integer) iblockdata.get(BlockGrowingTop.d) < 25 && random.nextDouble() < (100.0D / getGrowthModifier(worldserver)) * this.e) { // Spigot // Purpur ++ if ((Integer) iblockdata.get(BlockGrowingTop.d) < getMaxGrowthAge(worldserver) && random.nextDouble() < (100.0D / getGrowthModifier(worldserver)) * this.e) { // Spigot // Purpur + BlockPosition blockposition1 = blockposition.shift(this.a); + + if (this.h(worldserver.getType(blockposition1))) { +@@ -87,13 +89,13 @@ public abstract class BlockGrowingTop extends BlockGrowingAbstract implements IB + @Override + public void a(WorldServer worldserver, Random random, BlockPosition blockposition, IBlockData iblockdata) { + BlockPosition blockposition1 = blockposition.shift(this.a); +- int i = Math.min((Integer) iblockdata.get(BlockGrowingTop.d) + 1, 25); ++ int i = Math.min((Integer) iblockdata.get(BlockGrowingTop.d) + 1, getMaxGrowthAge(worldserver)); // Purpur + int j = this.a(random); + + for (int k = 0; k < j && this.h(worldserver.getType(blockposition1)); ++k) { + worldserver.setTypeUpdate(blockposition1, (IBlockData) iblockdata.set(BlockGrowingTop.d, i)); + blockposition1 = blockposition1.shift(this.a); +- i = Math.min(i + 1, 25); ++ i = Math.min(i + 1, getMaxGrowthAge(worldserver)); // Purpur + } + + } +diff --git a/src/main/java/net/minecraft/world/level/block/BlockKelp.java b/src/main/java/net/minecraft/world/level/block/BlockKelp.java +index 27f1cbe8786d7c37d62193a21baf0a2bdc6f0294..90ad39d40e4f979126d80c70df292e01e07ed793 100644 +--- a/src/main/java/net/minecraft/world/level/block/BlockKelp.java ++++ b/src/main/java/net/minecraft/world/level/block/BlockKelp.java +@@ -72,5 +72,9 @@ public class BlockKelp extends BlockGrowingTop implements IFluidContainer { + public double getGrowthModifier(WorldServer worldserver) { + return worldserver.spigotConfig.kelpModifier; + } ++ ++ public int getMaxGrowthAge(WorldServer worldserver) { ++ return worldserver.purpurConfig.kelpMaxGrowthAge; ++ } + // Purpur end + } +diff --git a/src/main/java/net/minecraft/world/level/block/BlockTwistingVines.java b/src/main/java/net/minecraft/world/level/block/BlockTwistingVines.java +index 3a8d08a1ee8f066cea36e6acff492e5af62993c5..d95151d50d2652e5f1b215267c898402f0b28829 100644 +--- a/src/main/java/net/minecraft/world/level/block/BlockTwistingVines.java ++++ b/src/main/java/net/minecraft/world/level/block/BlockTwistingVines.java +@@ -34,5 +34,9 @@ public class BlockTwistingVines extends BlockGrowingTop { + public double getGrowthModifier(WorldServer worldserver) { + return worldserver.purpurConfig.twistingVinesGrowthModifier; + } ++ ++ public int getMaxGrowthAge(WorldServer worldserver) { ++ return worldserver.purpurConfig.twistingVinesMaxGrowthAge; ++ } + // Purpur end + } +diff --git a/src/main/java/net/minecraft/world/level/block/BlockWeepingVines.java b/src/main/java/net/minecraft/world/level/block/BlockWeepingVines.java +index 198bd8857571872ed3f7437529c330dceeb825db..a71f97e87ee7210f3246e542dd768403905f7679 100644 +--- a/src/main/java/net/minecraft/world/level/block/BlockWeepingVines.java ++++ b/src/main/java/net/minecraft/world/level/block/BlockWeepingVines.java +@@ -34,5 +34,9 @@ public class BlockWeepingVines extends BlockGrowingTop { + public double getGrowthModifier(WorldServer worldserver) { + return worldserver.purpurConfig.weepingVinesGrowthModifier; + } ++ ++ public int getMaxGrowthAge(WorldServer worldserver) { ++ return worldserver.purpurConfig.weepingVinesMaxGrowthAge; ++ } + // Purpur end + } +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 17bbe2ceea016bcb00dc5542bea47e083e723ea5..221b6d3c98afe1c72481a922ac7eeff9801d8c2f 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -424,6 +424,11 @@ public class PurpurWorldConfig { + furnaceInfiniteFuel = getBoolean("blocks.furnace.infinite-fuel", furnaceInfiniteFuel); + } + ++ public int kelpMaxGrowthAge = 25; ++ private void kelpSettings() { ++ kelpMaxGrowthAge = getInt("blocks.kelp.max-growth-age", kelpMaxGrowthAge); ++ } ++ + public boolean lavaInfinite = false; + public int lavaInfiniteRequiredSources = 2; + public int lavaSpeedNether = 10; +@@ -478,13 +483,17 @@ public class PurpurWorldConfig { + } + + public double twistingVinesGrowthModifier = 0.10D; ++ public int twistingVinesMaxGrowthAge = 25; + private void twistingVinesSettings() { + twistingVinesGrowthModifier = getDouble("blocks.twisting_vines.growth-modifier", twistingVinesGrowthModifier); ++ twistingVinesMaxGrowthAge = getInt("blocks.twisting_vines.max-growth-age", twistingVinesMaxGrowthAge); + } + + public double weepingVinesGrowthModifier = 0.10D; ++ public int weepingVinesMaxGrowthAge = 25; + private void weepingVinesSettings() { + weepingVinesGrowthModifier = getDouble("blocks.weeping_vines.growth-modifier", weepingVinesGrowthModifier); ++ weepingVinesMaxGrowthAge = getInt("blocks.weeping_vines.max-growth-age", weepingVinesMaxGrowthAge); + } + + public boolean babiesAreRidable = true; diff --git a/patches/Purpur/patches/server/0127-Add-config-for-allowing-Endermen-to-despawn-even-whi.patch b/patches/Purpur/patches/server/0127-Add-config-for-allowing-Endermen-to-despawn-even-whi.patch new file mode 100644 index 00000000..e417ee9d --- /dev/null +++ b/patches/Purpur/patches/server/0127-Add-config-for-allowing-Endermen-to-despawn-even-whi.patch @@ -0,0 +1,39 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: jmp +Date: Sun, 22 Nov 2020 22:17:53 -0800 +Subject: [PATCH] Add config for allowing Endermen to despawn even while + holding a block + +This should help to reduce the amount of dirt, gravel, grass, and etc. +that Endermen like to randomly place all over the world. + +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityEnderman.java b/src/main/java/net/minecraft/world/entity/monster/EntityEnderman.java +index a15dbd76e1d1afae7eb3809ef2e0448d8e2ab8e6..cae2b2139e398dd26e9562636f06e096b3e028ae 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityEnderman.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityEnderman.java +@@ -427,7 +427,7 @@ public class EntityEnderman extends EntityMonster implements IEntityAngerable { + + @Override + public boolean isSpecialPersistence() { +- return super.isSpecialPersistence() || this.getCarried() != null; ++ return super.isSpecialPersistence() || (!this.world.purpurConfig.endermanDespawnEvenWithBlock && this.getCarried() != null); // Purpur + } + + static class PathfinderGoalEndermanPickupBlock extends PathfinderGoal { +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 221b6d3c98afe1c72481a922ac7eeff9801d8c2f..3b9898ee7ae0fb826cfc3102d3b84bc5323d163d 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -646,10 +646,12 @@ public class PurpurWorldConfig { + public boolean endermanRidable = false; + public boolean endermanRidableInWater = false; + public boolean endermanAllowGriefing = true; ++ public boolean endermanDespawnEvenWithBlock = false; + private void endermanSettings() { + endermanRidable = getBoolean("mobs.enderman.ridable", endermanRidable); + endermanRidableInWater = getBoolean("mobs.enderman.ridable-in-water", endermanRidableInWater); + endermanAllowGriefing = getBoolean("mobs.enderman.allow-griefing", endermanAllowGriefing); ++ endermanDespawnEvenWithBlock = getBoolean("mobs.enderman.can-despawn-with-held-block", endermanDespawnEvenWithBlock); + } + + public boolean endermiteRidable = false; diff --git a/patches/Purpur/patches/server/0128-Add-critical-hit-check-to-EntityDamagedByEntityEvent.patch b/patches/Purpur/patches/server/0128-Add-critical-hit-check-to-EntityDamagedByEntityEvent.patch new file mode 100644 index 00000000..3e51c300 --- /dev/null +++ b/patches/Purpur/patches/server/0128-Add-critical-hit-check-to-EntityDamagedByEntityEvent.patch @@ -0,0 +1,65 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Tue, 24 Nov 2020 04:30:46 -0600 +Subject: [PATCH] Add critical hit check to EntityDamagedByEntityEvent + + +diff --git a/src/main/java/net/minecraft/world/entity/player/EntityHuman.java b/src/main/java/net/minecraft/world/entity/player/EntityHuman.java +index ba8add51b86fc8a6417c1a9ac7a97ac605a9939b..c2a35fac1065b2b67a0a3ce94432246892f6f4a5 100644 +--- a/src/main/java/net/minecraft/world/entity/player/EntityHuman.java ++++ b/src/main/java/net/minecraft/world/entity/player/EntityHuman.java +@@ -169,6 +169,7 @@ public abstract class EntityHuman extends EntityLiving { + // Paper start + public boolean affectsSpawning = true; + // Paper end ++ public boolean isCritical = false; // Purpur + + // CraftBukkit start + public boolean fauxSleeping; +@@ -1176,6 +1177,7 @@ public abstract class EntityHuman extends EntityLiving { + flag2 = flag2 && !world.paperConfig.disablePlayerCrits; // Paper + flag2 = flag2 && !this.isSprinting(); + if (flag2) { ++ this.isCritical = true; // Purpur + f *= 1.5F; + } + +@@ -1212,6 +1214,7 @@ public abstract class EntityHuman extends EntityLiving { + + Vec3D vec3d = entity.getMot(); + boolean flag5 = entity.damageEntity(DamageSource.playerAttack(this), f); ++ this.isCritical = false; // Purpur + + if (flag5) { + if (i > 0) { +diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +index c4218281721cf4a5b8f2cad5e12089e3aee89737..c07ff0cc7cae358c3fd772d24c2944cc92e1acff 100644 +--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java ++++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +@@ -962,7 +962,7 @@ public class CraftEventFactory { + } else { + damageCause = DamageCause.ENTITY_EXPLOSION; + } +- event = new EntityDamageByEntityEvent(damager.getBukkitEntity(), entity.getBukkitEntity(), damageCause, modifiers, modifierFunctions); ++ event = new EntityDamageByEntityEvent(damager.getBukkitEntity(), entity.getBukkitEntity(), damageCause, modifiers, modifierFunctions, damager instanceof HumanEntity && ((EntityHuman)damager).isCritical); // Purpur + damager.processClick(EnumHand.MAIN_HAND); // Purpur + } + event.setCancelled(cancelled); +@@ -1042,7 +1042,7 @@ public class CraftEventFactory { + } else { + throw new IllegalStateException(String.format("Unhandled damage of %s by %s from %s", entity, damager.getHandle(), source.translationIndex)); + } +- EntityDamageEvent event = new EntityDamageByEntityEvent(damager, entity.getBukkitEntity(), cause, modifiers, modifierFunctions); ++ EntityDamageEvent event = new EntityDamageByEntityEvent(damager, entity.getBukkitEntity(), cause, modifiers, modifierFunctions, entityDamage instanceof HumanEntity && ((EntityHuman)entityDamage).isCritical); // Purpur + event.setCancelled(cancelled); + callEvent(event); + if (!event.isCancelled()) { +@@ -1097,7 +1097,7 @@ public class CraftEventFactory { + private static EntityDamageEvent callEntityDamageEvent(Entity damager, Entity damagee, DamageCause cause, Map modifiers, Map> modifierFunctions, boolean cancelled) { + EntityDamageEvent event; + if (damager != null) { +- event = new EntityDamageByEntityEvent(damager.getBukkitEntity(), damagee.getBukkitEntity(), cause, modifiers, modifierFunctions); ++ event = new EntityDamageByEntityEvent(damager.getBukkitEntity(), damagee.getBukkitEntity(), cause, modifiers, modifierFunctions, damager instanceof HumanEntity && ((EntityHuman)damager).isCritical); // Purpur + damager.processClick(EnumHand.MAIN_HAND); // Purpur + } else { + event = new EntityDamageEvent(damagee.getBukkitEntity(), cause, modifiers, modifierFunctions); diff --git a/patches/Purpur/patches/server/0129-Add-configurable-snowball-damage.patch b/patches/Purpur/patches/server/0129-Add-configurable-snowball-damage.patch new file mode 100644 index 00000000..f5b27b08 --- /dev/null +++ b/patches/Purpur/patches/server/0129-Add-configurable-snowball-damage.patch @@ -0,0 +1,35 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Tue, 24 Nov 2020 05:32:02 -0600 +Subject: [PATCH] Add configurable snowball damage + + +diff --git a/src/main/java/net/minecraft/world/entity/projectile/EntitySnowball.java b/src/main/java/net/minecraft/world/entity/projectile/EntitySnowball.java +index 0d3b9c81e47eef645335e49a1d6d88db7338aa4b..6bfd3f57e6c04ed426870d6dbf068bf324f22d6e 100644 +--- a/src/main/java/net/minecraft/world/entity/projectile/EntitySnowball.java ++++ b/src/main/java/net/minecraft/world/entity/projectile/EntitySnowball.java +@@ -40,7 +40,7 @@ public class EntitySnowball extends EntityProjectileThrowable { + protected void a(MovingObjectPositionEntity movingobjectpositionentity) { + super.a(movingobjectpositionentity); + Entity entity = movingobjectpositionentity.getEntity(); +- int i = entity instanceof EntityBlaze ? 3 : 0; ++ int i = entity.world.purpurConfig.snowballDamage >= 0 ? entity.world.purpurConfig.snowballDamage : entity instanceof EntityBlaze ? 3 : 0; // Purpur + + entity.damageEntity(DamageSource.projectile(this, this.getShooter()), (float) i); + } +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 3b9898ee7ae0fb826cfc3102d3b84bc5323d163d..b6a3d73dc0866d98b00f52d65a39646ab001a1f2 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -258,6 +258,11 @@ public class PurpurWorldConfig { + witherSkullDespawnRate = getInt("gameplay-mechanics.projectile-despawn-rates.wither_skull", witherSkullDespawnRate); + } + ++ public int snowballDamage = -1; ++ private void snowballSettings() { ++ snowballDamage = getInt("gameplay-mechanics.projectile-damage.snowball", snowballDamage); ++ } ++ + public boolean useBetterMending = false; + public boolean boatEjectPlayersOnLand = false; + public boolean disableDropsOnCrammingDeath = false; diff --git a/patches/Purpur/patches/server/0130-Zombie-break-door-minimum-difficulty-option.patch b/patches/Purpur/patches/server/0130-Zombie-break-door-minimum-difficulty-option.patch new file mode 100644 index 00000000..ced0497c --- /dev/null +++ b/patches/Purpur/patches/server/0130-Zombie-break-door-minimum-difficulty-option.patch @@ -0,0 +1,83 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Fri, 27 Nov 2020 10:33:33 -0600 +Subject: [PATCH] Zombie break door minimum difficulty option + + +diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoalBreakDoor.java b/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoalBreakDoor.java +index 10ee8a0a717354f50b29e7ebeab0ee2aa7bf42f7..d785066e2a52699c18315f7244d80db6cab0c736 100644 +--- a/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoalBreakDoor.java ++++ b/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoalBreakDoor.java +@@ -3,7 +3,9 @@ package net.minecraft.world.entity.ai.goal; + import java.util.function.Predicate; + import net.minecraft.core.IPosition; + import net.minecraft.world.EnumDifficulty; ++import net.minecraft.world.entity.Entity; + import net.minecraft.world.entity.EntityInsentient; ++import net.minecraft.world.entity.monster.EntityZombie; + import net.minecraft.world.level.GameRules; + import net.minecraft.world.level.block.Block; + +@@ -18,7 +20,7 @@ public class PathfinderGoalBreakDoor extends PathfinderGoalDoorInteract { + super(entityinsentient); + this.b = -1; + this.c = -1; +- this.g = predicate; ++ this.g = entityinsentient instanceof EntityZombie ? difficulty -> testDifficulty(entity) : predicate; // Purpur + } + + public PathfinderGoalBreakDoor(EntityInsentient entityinsentient, int i, Predicate predicate) { +@@ -87,4 +89,21 @@ public class PathfinderGoalBreakDoor extends PathfinderGoalDoorInteract { + private boolean a(EnumDifficulty enumdifficulty) { + return this.g.test(enumdifficulty); + } ++ ++ // Purpur start ++ private boolean testDifficulty(Entity entity) { ++ EnumDifficulty difficulty = entity.world.getDifficulty(); ++ switch (entity.world.purpurConfig.zombieBreakDoorMinDifficulty) { ++ case PEACEFUL: ++ return difficulty == EnumDifficulty.HARD || difficulty == EnumDifficulty.NORMAL || difficulty == EnumDifficulty.EASY || difficulty == EnumDifficulty.PEACEFUL; ++ case EASY: ++ return difficulty == EnumDifficulty.HARD || difficulty == EnumDifficulty.NORMAL || difficulty == EnumDifficulty.EASY; ++ case NORMAL: ++ return difficulty == EnumDifficulty.HARD || difficulty == EnumDifficulty.NORMAL; ++ case HARD: ++ default: ++ return difficulty == EnumDifficulty.HARD; ++ } ++ } ++ // Purpur end + } +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index b6a3d73dc0866d98b00f52d65a39646ab001a1f2..1ea011a2fbf6b6d2b7f9ff59e86303d17d130831 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -1,6 +1,7 @@ + package net.pl3x.purpur; + + import net.minecraft.core.IRegistry; ++import net.minecraft.world.EnumDifficulty; + import net.minecraft.world.level.Explosion; + import net.minecraft.world.level.block.Block; + import net.minecraft.world.level.block.Blocks; +@@ -1190,6 +1191,7 @@ public class PurpurWorldConfig { + public double zombieJockeyChance = 0.05D; + public boolean zombieJockeyTryExistingChickens = true; + public boolean zombieAggressiveTowardsVillagerWhenLagging = true; ++ public EnumDifficulty zombieBreakDoorMinDifficulty = EnumDifficulty.HARD; + private void zombieSettings() { + zombieRidable = getBoolean("mobs.zombie.ridable", zombieRidable); + zombieRidableInWater = getBoolean("mobs.zombie.ridable-in-water", zombieRidableInWater); +@@ -1197,6 +1199,11 @@ public class PurpurWorldConfig { + zombieJockeyChance = getDouble("mobs.zombie.jockey.chance", zombieJockeyChance); + zombieJockeyTryExistingChickens = getBoolean("mobs.zombie.jockey.try-existing-chickens", zombieJockeyTryExistingChickens); + zombieAggressiveTowardsVillagerWhenLagging = getBoolean("mobs.zombie.aggressive-towards-villager-when-lagging", zombieAggressiveTowardsVillagerWhenLagging); ++ try { ++ zombieBreakDoorMinDifficulty = EnumDifficulty.valueOf(getString("mobs.zombie.break-door-minimum-difficulty", zombieBreakDoorMinDifficulty.name())); ++ } catch (IllegalArgumentException ignore) { ++ zombieBreakDoorMinDifficulty = EnumDifficulty.HARD; ++ } + } + + public boolean zombieHorseCanSwim = false; diff --git a/patches/Purpur/patches/server/0131-Add-demo-command.patch b/patches/Purpur/patches/server/0131-Add-demo-command.patch new file mode 100644 index 00000000..e9dfecbe --- /dev/null +++ b/patches/Purpur/patches/server/0131-Add-demo-command.patch @@ -0,0 +1,96 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Mon, 30 Nov 2020 03:12:04 -0600 +Subject: [PATCH] Add demo command + + +diff --git a/src/main/java/net/minecraft/commands/CommandDispatcher.java b/src/main/java/net/minecraft/commands/CommandDispatcher.java +index 185dee82b86aa3abb04809ddcf31c81e29664c62..0ea56c863a9a1019b36f7f9f9164301aef12637b 100644 +--- a/src/main/java/net/minecraft/commands/CommandDispatcher.java ++++ b/src/main/java/net/minecraft/commands/CommandDispatcher.java +@@ -191,6 +191,7 @@ public class CommandDispatcher { + CommandIdleTimeout.a(this.b); + CommandStop.a(this.b); + CommandWhitelist.a(this.b); ++ net.pl3x.purpur.command.DemoCommand.register(getDispatcher()); // Purpur + net.pl3x.purpur.command.PingCommand.register(getDispatcher()); // Purpur + } + +diff --git a/src/main/java/net/minecraft/network/protocol/game/PacketPlayOutGameStateChange.java b/src/main/java/net/minecraft/network/protocol/game/PacketPlayOutGameStateChange.java +index edb6c0ab2826051b04e025a713d794dbc5de4792..0161657748d398b6827ef8bc2b00b8a63bf37c55 100644 +--- a/src/main/java/net/minecraft/network/protocol/game/PacketPlayOutGameStateChange.java ++++ b/src/main/java/net/minecraft/network/protocol/game/PacketPlayOutGameStateChange.java +@@ -13,7 +13,7 @@ public class PacketPlayOutGameStateChange implements Packet dispatcher) { ++ dispatcher.register(CommandDispatcher.literal("demo") ++ .requires((listener) -> { ++ return listener.hasPermission(2); ++ }) ++ .executes((context) -> { ++ return execute(context.getSource(), Collections.singleton(context.getSource().getPlayerOrException())); ++ }) ++ .then(CommandDispatcher.argument("targets", ArgumentEntity.players()) ++ .executes((context) -> { ++ return execute(context.getSource(), ArgumentEntity.getPlayers(context, "targets")); ++ }) ++ ) ++ ).setPermission("bukkit.command.demo"); ++ } ++ ++ private static int execute(CommandListenerWrapper sender, Collection targets) { ++ for (EntityPlayer player : targets) { ++ PacketPlayOutGameStateChange packet = new PacketPlayOutGameStateChange(PacketPlayOutGameStateChange.demo(), 0); ++ player.playerConnection.sendPacket(packet); ++ String output = String.format(PurpurConfig.demoCommandOutput, player.getProfile().getName()); ++ sender.sendMessage(CraftChatMessage.fromStringOrNull(output), false); ++ } ++ return targets.size(); ++ } ++} diff --git a/patches/Purpur/patches/server/0132-Left-handed-API.patch b/patches/Purpur/patches/server/0132-Left-handed-API.patch new file mode 100644 index 00000000..dc0b6d4b --- /dev/null +++ b/patches/Purpur/patches/server/0132-Left-handed-API.patch @@ -0,0 +1,25 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Mon, 30 Nov 2020 06:03:06 -0600 +Subject: [PATCH] Left handed API + + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java +index 125be4ca56d38c6cba1d1f4e7587abda075ee491..30d3b2f89e08056db128aa95e76c319b196b89ea 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java +@@ -133,4 +133,14 @@ public abstract class CraftMob extends CraftLivingEntity implements Mob { + return getHandle().getMaxHeadXRot(); + } + // Paper end ++ ++ // Purpur start ++ public boolean isLeftHanded() { ++ return getHandle().isLeftHanded(); ++ } ++ ++ public void setLeftHanded(boolean leftHanded) { ++ getHandle().setLeftHanded(leftHanded); ++ } ++ // Purpur end + } diff --git a/patches/Purpur/patches/server/0133-Origami-Fix-ProtocolLib-issues-on-Java-15.patch b/patches/Purpur/patches/server/0133-Origami-Fix-ProtocolLib-issues-on-Java-15.patch new file mode 100644 index 00000000..158f2947 --- /dev/null +++ b/patches/Purpur/patches/server/0133-Origami-Fix-ProtocolLib-issues-on-Java-15.patch @@ -0,0 +1,65 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Phoenix616 +Date: Mon, 19 Oct 2020 17:20:53 +0100 +Subject: [PATCH] Origami - Fix ProtocolLib issues on Java 15 + + +diff --git a/src/main/java/net/minecraft/network/NetworkManager.java b/src/main/java/net/minecraft/network/NetworkManager.java +index b6c0ef0df93f0350fa70e857e06d79ae34d7d4b1..1dce5d3b1e994a060067de4901912dd5a9be7e15 100644 +--- a/src/main/java/net/minecraft/network/NetworkManager.java ++++ b/src/main/java/net/minecraft/network/NetworkManager.java +@@ -435,9 +435,9 @@ public class NetworkManager extends SimpleChannelInboundHandler> { + // note: since the type is not dynamic here, we need to actually copy the old executor code + // into two branches. On conflict, just re-copy - no changes were made inside the executor code. + if (flush) { +- choice1 = () -> { ++ choice1 = new Runnable() { public void run() { // Origami - flatten lambda + if (enumprotocol != enumprotocol1) { +- this.setProtocol(enumprotocol); ++ NetworkManager.this.setProtocol(enumprotocol); // Origami - flatten lambda + } + + // Paper start +@@ -447,7 +447,7 @@ public class NetworkManager extends SimpleChannelInboundHandler> { + } + try { + // Paper end +- ChannelFuture channelfuture1 = (flush) ? this.channel.writeAndFlush(packet) : this.channel.write(packet); // Tuinity - add flush parameter ++ ChannelFuture channelfuture1 = (flush) ? NetworkManager.this.channel.writeAndFlush(packet) : NetworkManager.this.channel.write(packet); // Tuinity - add flush parameter // Origami - flatten lambda + + + if (genericfuturelistener != null) { +@@ -467,12 +467,12 @@ public class NetworkManager extends SimpleChannelInboundHandler> { + packet.onPacketDispatchFinish(player, null); + } + // Paper end +- }; ++ }}; // Origami - flatten lambda + } else { + // explicitly declare a variable to make the lambda use the type +- choice2 = () -> { ++ choice2 = new AbstractEventExecutor.LazyRunnable() { public void run() { // Origami - flatten lambda + if (enumprotocol != enumprotocol1) { +- this.setProtocol(enumprotocol); ++ NetworkManager.this.setProtocol(enumprotocol); // Origami - flatten lambda + } + + // Paper start +@@ -482,7 +482,7 @@ public class NetworkManager extends SimpleChannelInboundHandler> { + } + try { + // Paper end +- ChannelFuture channelfuture1 = (flush) ? this.channel.writeAndFlush(packet) : this.channel.write(packet); // Tuinity - add flush parameter ++ ChannelFuture channelfuture1 = (flush) ? NetworkManager.this.channel.writeAndFlush(packet) : NetworkManager.this.channel.write(packet); // Tuinity - add flush parameter // Origami - flatten lambda + + + if (genericfuturelistener != null) { +@@ -502,7 +502,7 @@ public class NetworkManager extends SimpleChannelInboundHandler> { + packet.onPacketDispatchFinish(player, null); + } + // Paper end +- }; ++ }}; // Origami - flatten lambda + } + this.channel.eventLoop().execute(choice1 != null ? choice1 : choice2); + // Tuinity end - optimise packets that are not flushed diff --git a/patches/Purpur/patches/server/0134-Changeable-Mob-Left-Handed-Chance.patch b/patches/Purpur/patches/server/0134-Changeable-Mob-Left-Handed-Chance.patch new file mode 100644 index 00000000..f9bfd919 --- /dev/null +++ b/patches/Purpur/patches/server/0134-Changeable-Mob-Left-Handed-Chance.patch @@ -0,0 +1,34 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ben Kerllenevich +Date: Mon, 30 Nov 2020 11:40:11 -0500 +Subject: [PATCH] Changeable Mob Left Handed Chance + + +diff --git a/src/main/java/net/minecraft/world/entity/EntityInsentient.java b/src/main/java/net/minecraft/world/entity/EntityInsentient.java +index 0ee99a2c9a966eaaaf09879cce2f54bc68eb3151..8c74adf071e1edb640b3f2375bc92567cc2f6086 100644 +--- a/src/main/java/net/minecraft/world/entity/EntityInsentient.java ++++ b/src/main/java/net/minecraft/world/entity/EntityInsentient.java +@@ -1208,7 +1208,7 @@ public abstract class EntityInsentient extends EntityLiving { + @Nullable + public GroupDataEntity prepare(WorldAccess worldaccess, DifficultyDamageScaler difficultydamagescaler, EnumMobSpawn enummobspawn, @Nullable GroupDataEntity groupdataentity, @Nullable NBTTagCompound nbttagcompound) { + this.getAttributeInstance(GenericAttributes.FOLLOW_RANGE).addModifier(new AttributeModifier("Random spawn bonus", this.random.nextGaussian() * 0.05D, AttributeModifier.Operation.MULTIPLY_BASE)); +- if (this.random.nextFloat() < 0.05F) { ++ if (this.random.nextFloat() < this.world.purpurConfig.entityLeftHandedChance) { // Purpur + this.setLeftHanded(true); + } else { + this.setLeftHanded(false); +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 1ea011a2fbf6b6d2b7f9ff59e86303d17d130831..5e3b23d50b6e8494066c71bdf7c14edc4a4a3716 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -163,8 +163,10 @@ public class PurpurWorldConfig { + } + + public int entityLifeSpan = 0; ++ public float entityLeftHandedChance = 0.05f; + private void entitySettings() { + entityLifeSpan = getInt("gameplay-mechanics.entity-lifespan", entityLifeSpan); ++ entityLeftHandedChance = (float) getDouble("gameplay-mechanics.entity-left-handed-chance", entityLeftHandedChance); + } + + public List itemImmuneToCactus = new ArrayList<>(); diff --git a/patches/Purpur/patches/server/0135-Add-boat-fall-damage-config.patch b/patches/Purpur/patches/server/0135-Add-boat-fall-damage-config.patch new file mode 100644 index 00000000..9f711b51 --- /dev/null +++ b/patches/Purpur/patches/server/0135-Add-boat-fall-damage-config.patch @@ -0,0 +1,48 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Mon, 30 Nov 2020 19:36:35 -0600 +Subject: [PATCH] Add boat fall damage config + + +diff --git a/src/main/java/net/minecraft/server/level/EntityPlayer.java b/src/main/java/net/minecraft/server/level/EntityPlayer.java +index 7b11b5fedd0dd6b340362c26b4ce73b93bf57b8b..c631e4d27518a1382869c184af41bec911cce908 100644 +--- a/src/main/java/net/minecraft/server/level/EntityPlayer.java ++++ b/src/main/java/net/minecraft/server/level/EntityPlayer.java +@@ -1149,7 +1149,16 @@ public class EntityPlayer extends EntityHuman implements ICrafting { + if (this.isInvulnerable(damagesource)) { + return false; + } else { +- if (damagesource == DamageSource.FALL && getRootVehicle() instanceof net.minecraft.world.entity.vehicle.EntityMinecartAbstract && world.purpurConfig.minecartControllable && !world.purpurConfig.minecartControllableFallDamage) return false; // Purpur ++ // Purpur start ++ if (damagesource == DamageSource.FALL) { ++ if (getRootVehicle() instanceof net.minecraft.world.entity.vehicle.EntityMinecartAbstract && world.purpurConfig.minecartControllable && !world.purpurConfig.minecartControllableFallDamage) { ++ return false; ++ } ++ if (getRootVehicle() instanceof net.minecraft.world.entity.vehicle.EntityBoat && !world.purpurConfig.boatsDoFallDamage) { ++ return false; ++ } ++ } ++ // Purpur end + boolean flag = this.server.j() && this.canPvP() && "fall".equals(damagesource.translationIndex); + + if (!flag && isSpawnInvulnerable() && damagesource != DamageSource.OUT_OF_WORLD) { // Purpur +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 5e3b23d50b6e8494066c71bdf7c14edc4a4a3716..944c1bbcb868e2e24f26db04b588f6f0c13164e5 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -268,6 +268,7 @@ public class PurpurWorldConfig { + + public boolean useBetterMending = false; + public boolean boatEjectPlayersOnLand = false; ++ public boolean boatsDoFallDamage = true; + public boolean disableDropsOnCrammingDeath = false; + public boolean entitiesPickUpLootBypassMobGriefing = false; + public boolean entitiesCanUsePortals = true; +@@ -282,6 +283,7 @@ public class PurpurWorldConfig { + private void miscGameplayMechanicsSettings() { + useBetterMending = getBoolean("gameplay-mechanics.use-better-mending", useBetterMending); + boatEjectPlayersOnLand = getBoolean("gameplay-mechanics.boat.eject-players-on-land", boatEjectPlayersOnLand); ++ boatsDoFallDamage = getBoolean("gameplay-mechanics.boat.do-fall-damage", boatsDoFallDamage); + disableDropsOnCrammingDeath = getBoolean("gameplay-mechanics.disable-drops-on-cramming-death", disableDropsOnCrammingDeath); + entitiesPickUpLootBypassMobGriefing = getBoolean("gameplay-mechanics.entities-pick-up-loot-bypass-mob-griefing", entitiesPickUpLootBypassMobGriefing); + entitiesCanUsePortals = getBoolean("gameplay-mechanics.entities-can-use-portals", entitiesCanUsePortals); diff --git a/patches/Purpur/patches/server/0136-Config-migration-disable-saving-projectiles-to-disk-.patch b/patches/Purpur/patches/server/0136-Config-migration-disable-saving-projectiles-to-disk-.patch new file mode 100644 index 00000000..d1e2e582 --- /dev/null +++ b/patches/Purpur/patches/server/0136-Config-migration-disable-saving-projectiles-to-disk-.patch @@ -0,0 +1,66 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: jmp +Date: Mon, 30 Nov 2020 18:30:13 -0800 +Subject: [PATCH] Config migration: disable saving projectiles to disk -> + projectile load/save limit of 0 + + +diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java +index c68ef95730c9c0b2f81be1cfbbc849e0f1c505fd..8a1311eeb2504bc9708403686518ea38bf598c71 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java +@@ -1,6 +1,7 @@ + package net.pl3x.purpur; + + import co.aikar.timings.TimingsManager; ++import com.destroystokyo.paper.PaperConfig; + import com.google.common.base.Throwables; + import net.minecraft.locale.LocaleLanguage; + import net.minecraft.server.MinecraftServer; +@@ -133,6 +134,17 @@ public class PurpurConfig { + return config.getString(path, config.getString(path)); + } + ++ private static void migrateDisableProjectileSaving() { ++ if (PurpurConfig.version < 6) { ++ final boolean saveProjectilesToDisk = getBoolean("world-settings.default.gameplay-mechanics.save-projectiles-to-disk", true); ++ set("world-settings.default.gameplay-mechanics.save-projectiles-to-disk", null); ++ if (!saveProjectilesToDisk) { ++ PaperConfig.config.set("world-settings.default.projectile-load-save-per-chunk-limit", 0); ++ PaperConfig.saveConfig(); ++ } ++ } ++ } ++ + public static String afkBroadcastAway = "§e§o%s is now AFK"; + public static String afkBroadcastBack = "§e§o%s is no longer AFK"; + public static String afkTabListPrefix = "[AFK] "; +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 944c1bbcb868e2e24f26db04b588f6f0c13164e5..c2044a89fd1547092fd3d6be671570fcf2a60f09 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -1,5 +1,6 @@ + package net.pl3x.purpur; + ++import com.destroystokyo.paper.PaperConfig; + import net.minecraft.core.IRegistry; + import net.minecraft.world.EnumDifficulty; + import net.minecraft.world.level.Explosion; +@@ -84,6 +85,17 @@ public class PurpurWorldConfig { + return PurpurConfig.config.getString("world-settings." + worldName + "." + path, PurpurConfig.config.getString("world-settings.default." + path)); + } + ++ private void migrateDisableProjectileSaving() { ++ if (PurpurConfig.version < 6) { ++ final boolean saveProjectilesToDisk = PurpurConfig.config.getBoolean("world-settings." + worldName + ".gameplay-mechanics.save-projectiles-to-disk", true); ++ PurpurConfig.config.set("world-settings." + worldName + ".gameplay-mechanics.save-projectiles-to-disk", null); ++ if (!saveProjectilesToDisk) { ++ PaperConfig.config.set("world-settings." + worldName + ".projectile-load-save-per-chunk-limit", 0); ++ PaperConfig.saveConfig(); ++ } ++ } ++ } ++ + public boolean armorstandSetNameVisible = false; + public boolean armorstandFixNametags = false; + public float armorstandStepHeight = 0.0F; diff --git a/patches/Purpur/patches/server/0137-Snow-Golem-rate-of-fire-config.patch b/patches/Purpur/patches/server/0137-Snow-Golem-rate-of-fire-config.patch new file mode 100644 index 00000000..b1f61e1d --- /dev/null +++ b/patches/Purpur/patches/server/0137-Snow-Golem-rate-of-fire-config.patch @@ -0,0 +1,49 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Simon Gardling +Date: Tue, 1 Dec 2020 16:50:36 -0500 +Subject: [PATCH] Snow Golem rate of fire config + +The formula used to determine the amount of ticks between shots is: + ((sqrt(distanceToTarget) / snowGolemAttackDistance) / snowGolemSnowBallModifer) * (maxShootIntervalTicks - minShootIntervalTicks) + minShootIntervalTicks + +If min-shoot-interval-ticks and max-shoot-interval-ticks are both set to +0, snow golems won't shoot any snowballs. + +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntitySnowman.java b/src/main/java/net/minecraft/world/entity/animal/EntitySnowman.java +index a692b973717ecc56d808039418599a11aedc2c5a..76fe39cf57384602c7422cb340f15ca7cac65ef9 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntitySnowman.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntitySnowman.java +@@ -66,7 +66,7 @@ public class EntitySnowman extends EntityGolem implements IShearable, IRangedEnt + @Override + protected void initPathfinder() { + this.goalSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur +- this.goalSelector.a(1, new PathfinderGoalArrowAttack(this, 1.25D, 20, 10.0F)); ++ this.goalSelector.a(1, new PathfinderGoalArrowAttack(this, world.purpurConfig.snowGolemAttackDistance, world.purpurConfig.snowGolemSnowBallMin, world.purpurConfig.snowGolemSnowBallMax, world.purpurConfig.snowGolemSnowBallModifier)); // Purpur - configurable snow golem snowball throwing + this.goalSelector.a(2, new PathfinderGoalRandomStrollLand(this, 1.0D, 1.0000001E-5F)); + this.goalSelector.a(3, new PathfinderGoalLookAtPlayer(this, EntityHuman.class, 6.0F)); + this.goalSelector.a(4, new PathfinderGoalRandomLookaround(this)); +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index c2044a89fd1547092fd3d6be671570fcf2a60f09..ed2b682b3717e58eb18ef12c18f362a75174f069 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -1039,12 +1039,20 @@ public class PurpurWorldConfig { + public boolean snowGolemLeaveTrailWhenRidden = false; + public boolean snowGolemDropsPumpkin = true; + public boolean snowGolemPutPumpkinBack = false; ++ public int snowGolemSnowBallMin = 20; ++ public int snowGolemSnowBallMax = 20; ++ public float snowGolemSnowBallModifier = 10.0F; ++ public double snowGolemAttackDistance = 1.25D; + private void snowGolemSettings() { + snowGolemRidable = getBoolean("mobs.snow_golem.ridable", snowGolemRidable); + snowGolemRidableInWater = getBoolean("mobs.snow_golem.ridable-in-water", snowGolemRidableInWater); + snowGolemLeaveTrailWhenRidden = getBoolean("mobs.snow_golem.leave-trail-when-ridden", snowGolemLeaveTrailWhenRidden); + snowGolemDropsPumpkin = getBoolean("mobs.snow_golem.drop-pumpkin-when-sheared", snowGolemDropsPumpkin); + snowGolemPutPumpkinBack = getBoolean("mobs.snow_golem.pumpkin-can-be-added-back", snowGolemPutPumpkinBack); ++ snowGolemSnowBallMin = getInt("mobs.snow_golem.min-shoot-interval-ticks", snowGolemSnowBallMin); ++ snowGolemSnowBallMax = getInt("mobs.snow_golem.max-shoot-interval-ticks", snowGolemSnowBallMax); ++ snowGolemSnowBallModifier = (float) getDouble("mobs.snow_golem.snow-ball-modifier", snowGolemSnowBallModifier); ++ snowGolemAttackDistance = getDouble("mobs.snow_golem.attack-distance", snowGolemAttackDistance); + } + + public boolean squidRidable = false; diff --git a/patches/Purpur/patches/server/0138-PaperPR-Config-option-for-Piglins-guarding-chests.patch b/patches/Purpur/patches/server/0138-PaperPR-Config-option-for-Piglins-guarding-chests.patch new file mode 100644 index 00000000..b9c2801a --- /dev/null +++ b/patches/Purpur/patches/server/0138-PaperPR-Config-option-for-Piglins-guarding-chests.patch @@ -0,0 +1,34 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: jmp +Date: Wed, 2 Dec 2020 03:07:58 -0800 +Subject: [PATCH] PaperPR - Config option for Piglins guarding chests + + +diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java +index fcacc08db8f5a58ddd06be7f9f2cb2cf6b2231c3..03c26e4dfb4775bfd9caa4f155bde58e83865388 100644 +--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java ++++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java +@@ -719,6 +719,11 @@ public class PaperWorldConfig { + zombiesTargetTurtleEggs = getBoolean("zombies-target-turtle-eggs", zombiesTargetTurtleEggs); + } + ++ public boolean piglinsGuardChests = true; ++ private void piglinsGuardChests() { ++ piglinsGuardChests = getBoolean("piglins-guard-chests", piglinsGuardChests); ++ } ++ + public boolean useEigencraftRedstone = false; + private void useEigencraftRedstone() { + useEigencraftRedstone = this.getBoolean("use-faster-eigencraft-redstone", false); +diff --git a/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinAI.java b/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinAI.java +index 44ecce39996cc4e7baad543803e1b5cfc22f8cf0..b7213d5a9c3d0f60a8f8f725cef6506d5b22d0ed 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinAI.java ++++ b/src/main/java/net/minecraft/world/entity/monster/piglin/PiglinAI.java +@@ -437,6 +437,7 @@ public class PiglinAI { + } + + public static void a(EntityHuman entityhuman, boolean flag) { ++ if (!entityhuman.world.paperConfig.piglinsGuardChests) return; // Paper + List list = entityhuman.world.a(EntityPiglin.class, entityhuman.getBoundingBox().g(16.0D)); // CraftBukkit - decompile error + + list.stream().filter(PiglinAI::d).filter((entitypiglin) -> { diff --git a/patches/Purpur/patches/server/0139-EMC-Configurable-disable-give-dropping.patch b/patches/Purpur/patches/server/0139-EMC-Configurable-disable-give-dropping.patch new file mode 100644 index 00000000..a8fd9d60 --- /dev/null +++ b/patches/Purpur/patches/server/0139-EMC-Configurable-disable-give-dropping.patch @@ -0,0 +1,37 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Thu, 14 Jan 2016 00:49:14 -0500 +Subject: [PATCH] EMC - Configurable disable give dropping + +Modified version of a patch by Aikar from EMC. Adds a config option in +purpur.yml to disable the /give command from dropping items on the +floor when a player's inventory is full. + +diff --git a/src/main/java/net/minecraft/server/commands/CommandGive.java b/src/main/java/net/minecraft/server/commands/CommandGive.java +index a10207f7cb9455e29db7e6906cb2138ad5609a1f..9557fd12f87e7e825501759598eaee75cd3891ac 100644 +--- a/src/main/java/net/minecraft/server/commands/CommandGive.java ++++ b/src/main/java/net/minecraft/server/commands/CommandGive.java +@@ -47,6 +47,7 @@ public class CommandGive { + boolean flag = entityplayer.inventory.pickup(itemstack); + EntityItem entityitem; + ++ if (net.pl3x.purpur.PurpurConfig.disableGiveCommandDrops) continue; // Purpur - add config option for toggling give command dropping + if (flag && itemstack.isEmpty()) { + itemstack.setCount(1); + entityitem = entityplayer.drop(itemstack, false, false, true); // Paper - Fix duplicating /give items on item drop cancel +diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java +index 8a1311eeb2504bc9708403686518ea38bf598c71..f4fab86ed176aea7d5fca3836e76f53e6101575f 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java +@@ -193,6 +193,11 @@ public class PurpurConfig { + useAlternateKeepAlive = getBoolean("settings.use-alternate-keepalive", useAlternateKeepAlive); + } + ++ public static boolean disableGiveCommandDrops = false; ++ private static void disableGiveCommandDrops() { ++ disableGiveCommandDrops = getBoolean("settings.disable-give-dropping", disableGiveCommandDrops); ++ } ++ + public static boolean barrelSixRows = false; + public static boolean enderChestSixRows = false; + public static boolean enderChestPermissionRows = false; diff --git a/patches/Purpur/patches/server/0140-Config-migration-climbing-should-not-bypass-cramming.patch b/patches/Purpur/patches/server/0140-Config-migration-climbing-should-not-bypass-cramming.patch new file mode 100644 index 00000000..fc17eff0 --- /dev/null +++ b/patches/Purpur/patches/server/0140-Config-migration-climbing-should-not-bypass-cramming.patch @@ -0,0 +1,51 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: jmp +Date: Wed, 2 Dec 2020 14:49:10 -0800 +Subject: [PATCH] Config migration: climbing should not bypass cramming + gamerule + + +diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java +index f4fab86ed176aea7d5fca3836e76f53e6101575f..36cfcd57fa3c3d33d46be5e3f70f4cf9a84f8b77 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java +@@ -145,6 +145,17 @@ public class PurpurConfig { + } + } + ++ private static void migrateClimbingCrammingFix() { ++ if (PurpurConfig.version < 7) { ++ final boolean climbingCrammingFix = getBoolean("world-settings.default.gameplay-mechanics.fix-climbing-bypassing-cramming-rule", false); ++ set("world-settings.default.gameplay-mechanics.fix-climbing-bypassing-cramming-rule", null); ++ if (climbingCrammingFix) { ++ PaperConfig.config.set("world-settings.default.fix-climbing-bypassing-cramming-rule", true); ++ PaperConfig.saveConfig(); ++ } ++ } ++ } ++ + public static String afkBroadcastAway = "§e§o%s is now AFK"; + public static String afkBroadcastBack = "§e§o%s is no longer AFK"; + public static String afkTabListPrefix = "[AFK] "; +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index ed2b682b3717e58eb18ef12c18f362a75174f069..3e2898e3582efc00764885739e1df3a2ab5d5f6e 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -96,6 +96,17 @@ public class PurpurWorldConfig { + } + } + ++ private void migrateClimbingCrammingFix() { ++ if (PurpurConfig.version < 7) { ++ final boolean climbingCrammingFix = PurpurConfig.config.getBoolean("world-settings." + worldName + ".gameplay-mechanics.fix-climbing-bypassing-cramming-rule", false); ++ PurpurConfig.config.set("world-settings." + worldName + ".gameplay-mechanics.fix-climbing-bypassing-cramming-rule", null); ++ if (climbingCrammingFix) { ++ PaperConfig.config.set("world-settings." + worldName + ".fix-climbing-bypassing-cramming-rule", true); ++ PaperConfig.saveConfig(); ++ } ++ } ++ } ++ + public boolean armorstandSetNameVisible = false; + public boolean armorstandFixNametags = false; + public float armorstandStepHeight = 0.0F; diff --git a/patches/Purpur/patches/server/0141-Lobotomize-stuck-villagers.patch b/patches/Purpur/patches/server/0141-Lobotomize-stuck-villagers.patch new file mode 100644 index 00000000..dcb81572 --- /dev/null +++ b/patches/Purpur/patches/server/0141-Lobotomize-stuck-villagers.patch @@ -0,0 +1,126 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Thu, 3 Dec 2020 17:56:18 -0600 +Subject: [PATCH] Lobotomize stuck villagers + + +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index b15f117d64d4e6a1dccdda480417b6f092c161ec..ca5afdcc9c5ae7b5f67a2c12f62e89ef5e227e3c 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -206,7 +206,7 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, ne + public double lastY; + public double lastZ; + private Vec3D loc; +- private BlockPosition locBlock; ++ private BlockPosition locBlock; public BlockPosition getBlockLocation() { return locBlock; } // Purpur + private Vec3D mot; + public float yaw; + public float pitch; +diff --git a/src/main/java/net/minecraft/world/entity/ai/navigation/NavigationAbstract.java b/src/main/java/net/minecraft/world/entity/ai/navigation/NavigationAbstract.java +index 148bdbc2cffb002d8b6dd05e70854ab503804949..a1b7ba4f2cef36e9ac7e21c22060090944ba943b 100644 +--- a/src/main/java/net/minecraft/world/entity/ai/navigation/NavigationAbstract.java ++++ b/src/main/java/net/minecraft/world/entity/ai/navigation/NavigationAbstract.java +@@ -123,6 +123,7 @@ public abstract class NavigationAbstract { + } + + @Nullable ++ public PathEntity calculateDestination(BlockPosition blockposition, int i) { return a(blockposition, i); } // Purpur - OBFHELPER + public PathEntity a(BlockPosition blockposition, int i) { + // Paper start - add target parameter + return this.a(blockposition, null, i); +diff --git a/src/main/java/net/minecraft/world/entity/npc/EntityVillager.java b/src/main/java/net/minecraft/world/entity/npc/EntityVillager.java +index 85242947bd115f63f8807e1d4e6784fff537e802..df73d1ff1d5c2e878693aabf50105e315a0152c9 100644 +--- a/src/main/java/net/minecraft/world/entity/npc/EntityVillager.java ++++ b/src/main/java/net/minecraft/world/entity/npc/EntityVillager.java +@@ -89,6 +89,7 @@ import net.minecraft.world.level.IWorldReader; + import net.minecraft.world.level.World; + import net.minecraft.world.level.WorldAccess; + import net.minecraft.world.level.block.state.IBlockData; ++import net.minecraft.world.level.pathfinder.PathEntity; + import net.minecraft.world.phys.AxisAlignedBB; + import org.apache.logging.log4j.Logger; + +@@ -258,15 +259,39 @@ public class EntityVillager extends EntityVillagerAbstract implements Reputation + } + // Spigot End + ++ private int behaviorTick = 0; ++ ++ // Purpur start ++ boolean lobotomized = false; ++ ++ private boolean isLobotomized() { ++ if ((world.getTime() + brainTickOffset) % world.purpurConfig.villagerLobotomizeCheck == 0) { ++ this.lobotomized = !canTravelFrom(getBlockLocation().up()); ++ } ++ return this.lobotomized; ++ } ++ ++ private boolean canTravelFrom(BlockPosition pos) { ++ return canTravelTo(pos.east()) || canTravelTo(pos.west()) || canTravelTo(pos.north()) || canTravelTo(pos.south()); ++ } ++ ++ private boolean canTravelTo(BlockPosition pos) { ++ PathEntity to = navigation.calculateDestination(pos, 0); ++ return to != null && to.getPoints().size() > 1; ++ } ++ // Purpur end ++ + @Override + protected void mobTick() { mobTick(false); } + protected void mobTick(boolean inactive) { + this.world.getMethodProfiler().enter("villagerBrain"); + // Purpur start ++ if (world.purpurConfig.villagerLobotomizeEnabled) inactive = inactive || isLobotomized(); + boolean tick = (world.getTime() + brainTickOffset) % world.purpurConfig.villagerBrainTicks == 0; + if (((WorldServer) world).getMinecraftServer().lagging ? tick : world.purpurConfig.villagerUseBrainTicksOnlyWhenLagging || tick) + // Purpur end + if (!inactive) this.getBehaviorController().a((WorldServer) this.world, this); // CraftBukkit - decompile error // Paper ++ else if (shouldRestock()) doRestock(); // Purpur + this.world.getMethodProfiler().exit(); + if (this.bF) { + this.bF = false; +@@ -398,6 +423,7 @@ public class EntityVillager extends EntityVillagerAbstract implements Reputation + return true; + } + ++ public void doRestock() { fb(); } // Purpur - OBFHELPER + public void fb() { + this.fp(); + Iterator iterator = this.getOffers().iterator(); +@@ -432,6 +458,7 @@ public class EntityVillager extends EntityVillagerAbstract implements Reputation + return this.bD == 0 || this.bD < 2 && this.world.getTime() > this.bC + 2400L; + } + ++ public boolean shouldRestock() { return fc(); } // Purpur - OBFHELPER + public boolean fc() { + long i = this.bC + 12000L; + long j = this.world.getTime(); +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 3e2898e3582efc00764885739e1df3a2ab5d5f6e..6f4aab0495e168afe3927b994e9c42ddce59dc20 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -1134,6 +1134,8 @@ public class PurpurWorldConfig { + public int villagerSpawnIronGolemLimit = 0; + public boolean villagerCanBreed = true; + public int villagerBreedingTicks = 6000; ++ public boolean villagerLobotomizeEnabled = false; ++ public int villagerLobotomizeCheck = 60; + private void villagerSettings() { + villagerRidable = getBoolean("mobs.villager.ridable", villagerRidable); + villagerRidableInWater = getBoolean("mobs.villager.ridable-in-water", villagerRidableInWater); +@@ -1146,6 +1148,13 @@ public class PurpurWorldConfig { + villagerSpawnIronGolemLimit = getInt("mobs.villager.spawn-iron-golem.limit", villagerSpawnIronGolemLimit); + villagerCanBreed = getBoolean("mobs.villager.can-breed", villagerCanBreed); + villagerBreedingTicks = getInt("mobs.villager.breeding-delay-ticks", villagerBreedingTicks); ++ if (PurpurConfig.version < 9) { ++ boolean oldValue = getBoolean("mobs.villager.lobotomize-1x1", villagerLobotomizeEnabled); ++ set("mobs.villager.lobotomize.enabled", oldValue); ++ set("mobs.villager.lobotomize-1x1", null); ++ } ++ villagerLobotomizeEnabled = getBoolean("mobs.villager.lobotomize.enabled", villagerLobotomizeEnabled); ++ villagerLobotomizeCheck = getInt("mobs.villager.lobotomize.check-interval", villagerLobotomizeCheck); + } + + public boolean villagerTraderRidable = false; diff --git a/patches/Purpur/patches/server/0142-Option-for-Villager-Clerics-to-farm-Nether-Wart.patch b/patches/Purpur/patches/server/0142-Option-for-Villager-Clerics-to-farm-Nether-Wart.patch new file mode 100644 index 00000000..84321464 --- /dev/null +++ b/patches/Purpur/patches/server/0142-Option-for-Villager-Clerics-to-farm-Nether-Wart.patch @@ -0,0 +1,247 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: jmp +Date: Sat, 5 Dec 2020 01:20:16 -0800 +Subject: [PATCH] Option for Villager Clerics to farm Nether Wart + +Adds an option so that Villagers with the Cleric profession are able to +farm Nether Wart. Reimplemented based on a feature of the carpet-extra +mod. + +diff --git a/src/main/java/net/minecraft/world/IInventory.java b/src/main/java/net/minecraft/world/IInventory.java +index 774ba6a923f7e329f6af5efc17e1c46e87ed2d77..b8c73cd0ba916b7bf166a6d2f6b7ab68cd9c939b 100644 +--- a/src/main/java/net/minecraft/world/IInventory.java ++++ b/src/main/java/net/minecraft/world/IInventory.java +@@ -38,6 +38,7 @@ public interface IInventory extends Clearable { + return true; + } + ++ default int getAmount(Item item) { return this.a(item); } // Purpur - OBFHELPER + default int a(Item item) { + int i = 0; + +@@ -52,6 +53,7 @@ public interface IInventory extends Clearable { + return i; + } + ++ default boolean containsAny(Set itemSet) { return a(itemSet); } // Purpur - OBFHELPER + default boolean a(Set set) { + for (int i = 0; i < this.getSize(); ++i) { + ItemStack itemstack = this.getItem(i); +diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/BehaviorFarm.java b/src/main/java/net/minecraft/world/entity/ai/behavior/BehaviorFarm.java +index 42c70a6c2972ac38e889a6d42fe2d7d4f6017d57..752642c0a15d68fcc1871e1cb02658b12c8978b3 100644 +--- a/src/main/java/net/minecraft/world/entity/ai/behavior/BehaviorFarm.java ++++ b/src/main/java/net/minecraft/world/entity/ai/behavior/BehaviorFarm.java +@@ -32,6 +32,7 @@ public class BehaviorFarm extends Behavior { + private long c; + private int d; + private final List e = Lists.newArrayList(); ++ private boolean clericWartFarmer = false; // Purpur + + public BehaviorFarm() { + super(ImmutableMap.of(MemoryModuleType.LOOK_TARGET, MemoryStatus.VALUE_ABSENT, MemoryModuleType.WALK_TARGET, MemoryStatus.VALUE_ABSENT, MemoryModuleType.SECONDARY_JOB_SITE, MemoryStatus.VALUE_PRESENT)); +@@ -40,9 +41,14 @@ public class BehaviorFarm extends Behavior { + protected boolean a(WorldServer worldserver, EntityVillager entityvillager) { + if (!worldserver.getGameRules().getBoolean(GameRules.MOB_GRIEFING) && !worldserver.purpurConfig.villagerFarmingBypassMobGriefing) { // Purpur + return false; +- } else if (entityvillager.getVillagerData().getProfession() != VillagerProfession.FARMER) { ++ } else if (entityvillager.getVillagerData().getProfession() != VillagerProfession.FARMER && !(worldserver.purpurConfig.villagerClericsFarmWarts && entityvillager.getVillagerData().getProfession() == VillagerProfession.CLERIC)) { // Purpur + return false; + } else { ++ // Purpur start ++ if (!this.clericWartFarmer && entityvillager.getVillagerData().getProfession() == VillagerProfession.CLERIC) { ++ this.clericWartFarmer = true; ++ } ++ // Purpur end + BlockPosition.MutableBlockPosition blockposition_mutableblockposition = entityvillager.getChunkCoordinates().i(); + + this.e.clear(); +@@ -73,6 +79,11 @@ public class BehaviorFarm extends Behavior { + Block block = iblockdata.getBlock(); + Block block1 = worldserver.getType(blockposition.down()).getBlock(); + ++ // Purpur start ++ if (this.clericWartFarmer) { ++ return block == Blocks.NETHER_WART && iblockdata.get(net.minecraft.world.level.block.BlockNetherWart.AGE) == 3 || iblockdata.isAir() && block1 == Blocks.SOUL_SAND; ++ } ++ // Purpur end + return block instanceof BlockCrops && ((BlockCrops) block).isRipe(iblockdata) || iblockdata.isAir() && block1 instanceof BlockSoil; + } + +@@ -98,7 +109,7 @@ public class BehaviorFarm extends Behavior { + Block block = iblockdata.getBlock(); + Block block1 = worldserver.getType(this.farmBlock.down()).getBlock(); + +- if (block instanceof BlockCrops && ((BlockCrops) block).isRipe(iblockdata)) { ++ if (block instanceof BlockCrops && ((BlockCrops) block).isRipe(iblockdata) && !this.clericWartFarmer || this.clericWartFarmer && block == Blocks.NETHER_WART && iblockdata.get(net.minecraft.world.level.block.BlockNetherWart.AGE) == 3) { // Purpur + // CraftBukkit start + if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(entityvillager, this.farmBlock, Blocks.AIR.getBlockData()).isCancelled()) { + worldserver.a(this.farmBlock, true, entityvillager); +@@ -106,7 +117,7 @@ public class BehaviorFarm extends Behavior { + // CraftBukkit end + } + +- if (iblockdata.isAir() && block1 instanceof BlockSoil && entityvillager.canPlant()) { ++ if (iblockdata.isAir() && (block1 instanceof BlockSoil && !this.clericWartFarmer || this.clericWartFarmer && block1 == Blocks.SOUL_SAND) && entityvillager.canPlant()) { // Purpur + InventorySubcontainer inventorysubcontainer = entityvillager.getInventory(); + + for (int j = 0; j < inventorysubcontainer.getSize(); ++j) { +@@ -116,6 +127,14 @@ public class BehaviorFarm extends Behavior { + if (!itemstack.isEmpty()) { + // CraftBukkit start + Block planted = null; ++ // Purpur start ++ if (this.clericWartFarmer) { ++ if (itemstack.getItem() == Items.NETHER_WART) { ++ planted = Blocks.NETHER_WART; ++ flag = true; ++ } ++ } else ++ // Purpur end + if (itemstack.getItem() == Items.WHEAT_SEEDS) { + planted = Blocks.WHEAT; + flag = true; +@@ -139,7 +158,7 @@ public class BehaviorFarm extends Behavior { + } + + if (flag) { +- worldserver.playSound((EntityHuman) null, (double) this.farmBlock.getX(), (double) this.farmBlock.getY(), (double) this.farmBlock.getZ(), SoundEffects.ITEM_CROP_PLANT, SoundCategory.BLOCKS, 1.0F, 1.0F); ++ worldserver.playSound((EntityHuman) null, (double) this.farmBlock.getX(), (double) this.farmBlock.getY(), (double) this.farmBlock.getZ(), this.clericWartFarmer ? SoundEffects.ITEM_NETHER_WART_PLANT : SoundEffects.ITEM_CROP_PLANT, SoundCategory.BLOCKS, 1.0F, 1.0F); // Purpur + itemstack.subtract(1); + if (itemstack.isEmpty()) { + inventorysubcontainer.setItem(j, ItemStack.b); +diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/BehaviorTradeVillager.java b/src/main/java/net/minecraft/world/entity/ai/behavior/BehaviorTradeVillager.java +index 71ea6c43d76bf1abe6b08dadb20ea4708b0ecfc7..c73b4475182541fa8261bec44f1eeeef21c22f42 100644 +--- a/src/main/java/net/minecraft/world/entity/ai/behavior/BehaviorTradeVillager.java ++++ b/src/main/java/net/minecraft/world/entity/ai/behavior/BehaviorTradeVillager.java +@@ -53,6 +53,11 @@ public class BehaviorTradeVillager extends Behavior { + if (entityvillager1.getVillagerData().getProfession() == VillagerProfession.FARMER && entityvillager.getInventory().a(Items.WHEAT) > Items.WHEAT.getMaxStackSize() / 2) { + a(entityvillager, ImmutableSet.of(Items.WHEAT), entityvillager1); + } ++ // Purpur start ++ if (worldserver.purpurConfig.villagerClericsFarmWarts && worldserver.purpurConfig.villagerClericFarmersThrowWarts && entityvillager.getVillagerData().getProfession() == VillagerProfession.CLERIC && entityvillager.getInventory().getAmount(Items.NETHER_WART) > Items.NETHER_WART.getMaxStackSize() / 2) { ++ tryThrowingItems(entityvillager, ImmutableSet.of(Items.NETHER_WART), entityvillager1); ++ } ++ // Purpur end + + if (!this.b.isEmpty() && entityvillager.getInventory().a(this.b)) { + a(entityvillager, this.b, entityvillager1); +@@ -74,6 +79,7 @@ public class BehaviorTradeVillager extends Behavior { + }).collect(Collectors.toSet()); + } + ++ private static void tryThrowingItems(EntityVillager entityVillager, Set acceptableItems, EntityLiving targetEntity) { a(entityVillager, acceptableItems, targetEntity); } // Purpur - OBFHELPER + private static void a(EntityVillager entityvillager, Set set, EntityLiving entityliving) { + InventorySubcontainer inventorysubcontainer = entityvillager.getInventory(); + ItemStack itemstack = ItemStack.b; +diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/Behaviors.java b/src/main/java/net/minecraft/world/entity/ai/behavior/Behaviors.java +index df12193e1a2e449193a3feab53fc684a2571ae3a..4a8217862a98488ce71ce577b5fa9d6a0f9c898a 100644 +--- a/src/main/java/net/minecraft/world/entity/ai/behavior/Behaviors.java ++++ b/src/main/java/net/minecraft/world/entity/ai/behavior/Behaviors.java +@@ -21,10 +21,13 @@ public class Behaviors { + return ImmutableList.of(Pair.of(0, new BehaviorSwim(0.8F)), Pair.of(0, new BehaviorInteractDoor()), Pair.of(0, new BehaviorLook(45, 90)), Pair.of(0, new BehaviorPanic()), Pair.of(0, new BehaviorWake()), Pair.of(0, new BehaviorBellAlert()), Pair.of(0, new BehaviorRaid()), Pair.of(0, new BehaviorPositionValidate(villagerprofession.b(), MemoryModuleType.JOB_SITE)), Pair.of(0, new BehaviorPositionValidate(villagerprofession.b(), MemoryModuleType.POTENTIAL_JOB_SITE)), Pair.of(1, new BehavorMove()), Pair.of(2, new BehaviorBetterJob(villagerprofession)), Pair.of(3, new BehaviorInteractPlayer(f)), new Pair[]{Pair.of(5, new BehaviorFindAdmirableItem<>(f, false, 4)), Pair.of(6, new BehaviorFindPosition(villagerprofession.b(), MemoryModuleType.JOB_SITE, MemoryModuleType.POTENTIAL_JOB_SITE, true, Optional.empty())), Pair.of(7, new BehaviorPotentialJobSite(f)), Pair.of(8, new BehaviorLeaveJob(f)), Pair.of(10, new BehaviorFindPosition(VillagePlaceType.r, MemoryModuleType.HOME, false, Optional.of((byte) 14))), Pair.of(10, new BehaviorFindPosition(VillagePlaceType.s, MemoryModuleType.MEETING_POINT, true, Optional.of((byte) 14))), Pair.of(10, new BehaviorCareer()), Pair.of(10, new BehaviorProfession())}); + } + +- public static ImmutableList>> b(VillagerProfession villagerprofession, float f) { +- Object object; ++ // Purpur start - OBFHELPER, add clericsFarmWarts param ++ public static ImmutableList>> b(VillagerProfession villagerprofession, float f) { return createWorkTask(villagerprofession, f, false); } ++ public static ImmutableList>> createWorkTask(VillagerProfession villagerprofession, float f, boolean clericsFarmWarts) { ++ BehaviorWork object; // Purpur - decompile fix + +- if (villagerprofession == VillagerProfession.FARMER) { ++ if (villagerprofession == VillagerProfession.FARMER || (clericsFarmWarts && villagerprofession == VillagerProfession.CLERIC)) { ++ // Purpur end + object = new BehaviorWorkComposter(); + } else { + object = new BehaviorWork(); +diff --git a/src/main/java/net/minecraft/world/entity/ai/sensing/SensorSecondaryPlaces.java b/src/main/java/net/minecraft/world/entity/ai/sensing/SensorSecondaryPlaces.java +index 25c10973c74f98224dd1d2ae5e7178b9781374aa..d50b5632f0e53147ea23109f1ed627b44f798b58 100644 +--- a/src/main/java/net/minecraft/world/entity/ai/sensing/SensorSecondaryPlaces.java ++++ b/src/main/java/net/minecraft/world/entity/ai/sensing/SensorSecondaryPlaces.java +@@ -20,6 +20,13 @@ public class SensorSecondaryPlaces extends Sensor { + } + + protected void a(WorldServer worldserver, EntityVillager entityvillager) { ++ // Purpur start - make sure clerics don't wander to soul sand when the option is off ++ BehaviorController behaviorcontroller = entityvillager.getBehaviorController(); ++ if (!worldserver.purpurConfig.villagerClericsFarmWarts && entityvillager.getVillagerData().getProfession() == net.minecraft.world.entity.npc.VillagerProfession.CLERIC) { ++ behaviorcontroller.removeMemory(MemoryModuleType.SECONDARY_JOB_SITE); ++ return; ++ } ++ // Purpur end + ResourceKey resourcekey = worldserver.getDimensionKey(); + BlockPosition blockposition = entityvillager.getChunkCoordinates(); + List list = Lists.newArrayList(); +@@ -37,10 +44,10 @@ public class SensorSecondaryPlaces extends Sensor { + } + } + +- BehaviorController behaviorcontroller = entityvillager.getBehaviorController(); ++ //BehaviorController behaviorcontroller = entityvillager.getBehaviorController(); // Purpur - move up + + if (!list.isEmpty()) { +- behaviorcontroller.setMemory(MemoryModuleType.SECONDARY_JOB_SITE, (Object) list); ++ behaviorcontroller.setMemory(MemoryModuleType.SECONDARY_JOB_SITE, list); // Purpur - decompile fix + } else { + behaviorcontroller.removeMemory(MemoryModuleType.SECONDARY_JOB_SITE); + } +diff --git a/src/main/java/net/minecraft/world/entity/npc/EntityVillager.java b/src/main/java/net/minecraft/world/entity/npc/EntityVillager.java +index df73d1ff1d5c2e878693aabf50105e315a0152c9..d888aa8df65d54a0dce23eaae609aa0d2c3be3d9 100644 +--- a/src/main/java/net/minecraft/world/entity/npc/EntityVillager.java ++++ b/src/main/java/net/minecraft/world/entity/npc/EntityVillager.java +@@ -203,7 +203,7 @@ public class EntityVillager extends EntityVillagerAbstract implements Reputation + behaviorcontroller.a(Activity.PLAY, Behaviors.a(0.5F)); + } else { + behaviorcontroller.setSchedule(Schedule.VILLAGER_DEFAULT); +- behaviorcontroller.a(Activity.WORK, Behaviors.b(villagerprofession, 0.5F), (Set) ImmutableSet.of(Pair.of(MemoryModuleType.JOB_SITE, MemoryStatus.VALUE_PRESENT))); ++ behaviorcontroller.a(Activity.WORK, Behaviors.createWorkTask(villagerprofession, 0.5F, this.world.purpurConfig.villagerClericsFarmWarts), ImmutableSet.of(Pair.of(MemoryModuleType.JOB_SITE, MemoryStatus.VALUE_PRESENT))); // Purpur + } + + behaviorcontroller.a(Activity.CORE, Behaviors.a(villagerprofession, 0.5F)); +@@ -951,6 +951,11 @@ public class EntityVillager extends EntityVillagerAbstract implements Reputation + } + + public boolean canPlant() { ++ // Purpur start ++ if (this.world.purpurConfig.villagerClericsFarmWarts && this.getVillagerData().getProfession() == VillagerProfession.CLERIC) { ++ return this.getInventory().containsAny(ImmutableSet.of(Items.NETHER_WART)); ++ } ++ // Purpur end + return this.getInventory().a((Set) ImmutableSet.of(Items.WHEAT_SEEDS, Items.POTATO, Items.CARROT, Items.BEETROOT_SEEDS)); + } + +diff --git a/src/main/java/net/minecraft/world/entity/npc/VillagerProfession.java b/src/main/java/net/minecraft/world/entity/npc/VillagerProfession.java +index 69de7588eebba7557cdaec129f19ec1fc2c675c5..dd9b678481620856fb7eaaa04c3b812c861e892a 100644 +--- a/src/main/java/net/minecraft/world/entity/npc/VillagerProfession.java ++++ b/src/main/java/net/minecraft/world/entity/npc/VillagerProfession.java +@@ -18,7 +18,7 @@ public class VillagerProfession { + public static final VillagerProfession ARMORER = a("armorer", VillagePlaceType.d, SoundEffects.ENTITY_VILLAGER_WORK_ARMORER); + public static final VillagerProfession BUTCHER = a("butcher", VillagePlaceType.e, SoundEffects.ENTITY_VILLAGER_WORK_BUTCHER); + public static final VillagerProfession CARTOGRAPHER = a("cartographer", VillagePlaceType.f, SoundEffects.ENTITY_VILLAGER_WORK_CARTOGRAPHER); +- public static final VillagerProfession CLERIC = a("cleric", VillagePlaceType.g, SoundEffects.ENTITY_VILLAGER_WORK_CLERIC); ++ public static final VillagerProfession CLERIC = a("cleric", VillagePlaceType.g, ImmutableSet.of(Items.NETHER_WART), ImmutableSet.of(Blocks.SOUL_SAND), SoundEffects.ENTITY_VILLAGER_WORK_CLERIC); // Purpur + public static final VillagerProfession FARMER = a("farmer", VillagePlaceType.h, ImmutableSet.of(Items.WHEAT, Items.WHEAT_SEEDS, Items.BEETROOT_SEEDS, Items.BONE_MEAL), ImmutableSet.of(Blocks.FARMLAND), SoundEffects.ENTITY_VILLAGER_WORK_FARMER); + public static final VillagerProfession FISHERMAN = a("fisherman", VillagePlaceType.i, SoundEffects.ENTITY_VILLAGER_WORK_FISHERMAN); + public static final VillagerProfession FLETCHER = a("fletcher", VillagePlaceType.j, SoundEffects.ENTITY_VILLAGER_WORK_FLETCHER); +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 6f4aab0495e168afe3927b994e9c42ddce59dc20..efe82464beb6741413b73bbd6adc5c45eba7bcd6 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -1136,6 +1136,8 @@ public class PurpurWorldConfig { + public int villagerBreedingTicks = 6000; + public boolean villagerLobotomizeEnabled = false; + public int villagerLobotomizeCheck = 60; ++ public boolean villagerClericsFarmWarts = false; ++ public boolean villagerClericFarmersThrowWarts = true; + private void villagerSettings() { + villagerRidable = getBoolean("mobs.villager.ridable", villagerRidable); + villagerRidableInWater = getBoolean("mobs.villager.ridable-in-water", villagerRidableInWater); +@@ -1155,6 +1157,8 @@ public class PurpurWorldConfig { + } + villagerLobotomizeEnabled = getBoolean("mobs.villager.lobotomize.enabled", villagerLobotomizeEnabled); + villagerLobotomizeCheck = getInt("mobs.villager.lobotomize.check-interval", villagerLobotomizeCheck); ++ villagerClericsFarmWarts = getBoolean("mobs.villager.clerics-farm-warts", villagerClericsFarmWarts); ++ villagerClericFarmersThrowWarts = getBoolean("mobs.villager.cleric-wart-farmers-throw-warts-at-villagers", villagerClericFarmersThrowWarts); + } + + public boolean villagerTraderRidable = false; diff --git a/patches/Purpur/patches/server/0143-Toggle-for-Zombified-Piglin-death-always-counting-as.patch b/patches/Purpur/patches/server/0143-Toggle-for-Zombified-Piglin-death-always-counting-as.patch new file mode 100644 index 00000000..e2cc2138 --- /dev/null +++ b/patches/Purpur/patches/server/0143-Toggle-for-Zombified-Piglin-death-always-counting-as.patch @@ -0,0 +1,55 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: jmp +Date: Sat, 5 Dec 2020 02:34:22 -0800 +Subject: [PATCH] Toggle for Zombified Piglin death always counting as player + kill when angry + +In Vanilla (as of 1.16.4), when Zombified Piglins die while angry, it will +count as a player kill regardless of whether a player has ever hit them, +meaning they will drop XP. This is abused in Zombified Piglin farms where +the player kills the entities through cramming, but they still drop XP due +to the Piglin being angry, even though the player never hit them. + +This patch adds a toggle to disable this behavior. + +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityPigZombie.java b/src/main/java/net/minecraft/world/entity/monster/EntityPigZombie.java +index 9f50054211db48e7fe764434e8d71aab0995e57a..82279ab2f3c1edec14c24c3a7ad24d097d52dea2 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityPigZombie.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityPigZombie.java +@@ -130,7 +130,7 @@ public class EntityPigZombie extends EntityZombie implements IEntityAngerable { + this.eY(); + } + +- if (this.isAngry()) { ++ if (this.isAngry() && this.world.purpurConfig.zombifiedPiglinCountAsPlayerKillWhenAngry) { // Purpur + this.lastDamageByPlayerTime = this.ticksLived; + } + +@@ -185,7 +185,7 @@ public class EntityPigZombie extends EntityZombie implements IEntityAngerable { + this.bt = EntityPigZombie.bs.a(this.random); + } + +- if (entityliving instanceof EntityHuman) { ++ if (entityliving instanceof EntityHuman && this.world.purpurConfig.zombifiedPiglinCountAsPlayerKillWhenAngry) { // Purpur + this.e((EntityHuman) entityliving); + } + +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index efe82464beb6741413b73bbd6adc5c45eba7bcd6..7d32788c5e538be6eff9b6ff4655f279ac1e0e6b 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -1268,12 +1268,14 @@ public class PurpurWorldConfig { + public boolean zombifiedPiglinJockeyOnlyBaby = true; + public double zombifiedPiglinJockeyChance = 0.05D; + public boolean zombifiedPiglinJockeyTryExistingChickens = true; ++ public boolean zombifiedPiglinCountAsPlayerKillWhenAngry = true; + private void zombifiedPiglinSettings() { + zombifiedPiglinRidable = getBoolean("mobs.zombified_piglin.ridable", zombifiedPiglinRidable); + zombifiedPiglinRidableInWater = getBoolean("mobs.zombified_piglin.ridable-in-water", zombifiedPiglinRidableInWater); + zombifiedPiglinJockeyOnlyBaby = getBoolean("mobs.zombified_piglin.jockey.only-babies", zombifiedPiglinJockeyOnlyBaby); + zombifiedPiglinJockeyChance = getDouble("mobs.zombified_piglin.jockey.chance", zombifiedPiglinJockeyChance); + zombifiedPiglinJockeyTryExistingChickens = getBoolean("mobs.zombified_piglin.jockey.try-existing-chickens", zombifiedPiglinJockeyTryExistingChickens); ++ zombifiedPiglinCountAsPlayerKillWhenAngry = getBoolean("mobs.zombified_piglin.count-as-player-kill-when-angry", zombifiedPiglinCountAsPlayerKillWhenAngry); + } + + public boolean zombieVillagerRidable = false; diff --git a/patches/Purpur/patches/server/0144-Spread-out-and-optimise-player-list-ticks.patch b/patches/Purpur/patches/server/0144-Spread-out-and-optimise-player-list-ticks.patch new file mode 100644 index 00000000..558b047d --- /dev/null +++ b/patches/Purpur/patches/server/0144-Spread-out-and-optimise-player-list-ticks.patch @@ -0,0 +1,76 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: James Lyne +Date: Mon, 7 Dec 2020 17:52:36 +0000 +Subject: [PATCH] Spread out and optimise player list ticks + + +diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java +index 80f6a4e7204bceca3f312fe5c8d572f971a7fa4b..62f2033606170248f07f7683688b8a11ca3bd302 100644 +--- a/src/main/java/net/minecraft/server/players/PlayerList.java ++++ b/src/main/java/net/minecraft/server/players/PlayerList.java +@@ -151,7 +151,7 @@ public abstract class PlayerList { + private int viewDistance; + private EnumGamemode u; + private boolean v; +- private int w; ++ private int w; private int getTick() { return this.w; } private int setTick(int i) { return this.w = i; } // Purpur - OBFHELPER + + // CraftBukkit start + private CraftServer cserver; +@@ -1029,22 +1029,23 @@ public abstract class PlayerList { + } + + public void tick() { +- if (++this.w > 600) { +- // CraftBukkit start +- for (int i = 0; i < this.players.size(); ++i) { +- final EntityPlayer target = (EntityPlayer) this.players.get(i); +- +- target.playerConnection.sendPacket(new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.UPDATE_LATENCY, Iterables.filter(this.players, new Predicate() { +- @Override +- public boolean apply(EntityPlayer input) { +- return target.getBukkitEntity().canSee(input.getBukkitEntity()); +- } +- }))); ++ // Purpur start ++ int tick = getTick(); ++ if (tick < this.players.size()) { ++ final org.bukkit.craftbukkit.entity.CraftPlayer target = this.players.get(tick).getBukkitEntity(); ++ final java.util.List list = new java.util.ArrayList<>(); ++ for (EntityPlayer entityplayer : this.players) { ++ if (target.canSee(entityplayer.getUniqueID())) { ++ list.add(entityplayer); ++ } + } +- // CraftBukkit end +- this.w = 0; ++ target.getHandle().playerConnection.sendPacket(new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.UPDATE_LATENCY, list)); + } +- ++ if (++tick > 600) { ++ tick = 0; ++ } ++ setTick(tick); ++ // Purpur end + } + + public void sendAll(Packet packet) { +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +index b7180dea1d71a68e4025388916600093dfd000c7..8cc2b2b83ad3cb74f8cf7916141ae1f4ade27908 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +@@ -1447,7 +1447,13 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + + @Override + public boolean canSee(Player player) { +- return !hiddenPlayers.containsKey(player.getUniqueId()); ++ // Purpur start ++ return canSee(player.getUniqueId()); ++ } ++ ++ public boolean canSee(UUID uuid) { ++ return !hiddenPlayers.containsKey(uuid); ++ // Purpur end + } + + @Override diff --git a/patches/Purpur/patches/server/0145-Configurable-chance-for-wolves-to-spawn-rabid.patch b/patches/Purpur/patches/server/0145-Configurable-chance-for-wolves-to-spawn-rabid.patch new file mode 100644 index 00000000..4527c2d8 --- /dev/null +++ b/patches/Purpur/patches/server/0145-Configurable-chance-for-wolves-to-spawn-rabid.patch @@ -0,0 +1,283 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Encode42 +Date: Tue, 8 Dec 2020 17:15:15 -0500 +Subject: [PATCH] Configurable chance for wolves to spawn rabid + +Configurable chance to spawn a wolf that is rabid. +Rabid wolves attack all players, mobs, and animals. + +diff --git a/src/main/java/net/minecraft/world/entity/EntityLiving.java b/src/main/java/net/minecraft/world/entity/EntityLiving.java +index 3b66833adcd3912ebbfac49f0a59b1dc6fb3971d..3b76a652a3888d7d0b7dfb13f9ebbf0732e71d71 100644 +--- a/src/main/java/net/minecraft/world/entity/EntityLiving.java ++++ b/src/main/java/net/minecraft/world/entity/EntityLiving.java +@@ -2197,6 +2197,7 @@ public abstract class EntityLiving extends Entity { + } + } + ++ public final void setItemInHand(EnumHand enumHand, ItemStack itemStack) { this.a(enumHand, itemStack); } // Purpur - OBFHELPER + public void a(EnumHand enumhand, ItemStack itemstack) { + if (enumhand == EnumHand.MAIN_HAND) { + this.setSlot(EnumItemSlot.MAINHAND, itemstack); +diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoalAvoidTarget.java b/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoalAvoidTarget.java +index 5115c56487a12f904ff836355375f66a16098790..35502bd2f7d9cebf5cfe1060e300a5032dbe6a5d 100644 +--- a/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoalAvoidTarget.java ++++ b/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoalAvoidTarget.java +@@ -17,7 +17,7 @@ public class PathfinderGoalAvoidTarget extends Pathfinde + protected final EntityCreature a; + private final double i; + private final double j; +- protected T b; ++ protected T b; protected T getTarget() { return this.b; } // Purpur - OBFHELPER + protected final float c; + protected PathEntity d; + protected final NavigationAbstract e; +@@ -27,12 +27,7 @@ public class PathfinderGoalAvoidTarget extends Pathfinde + private final PathfinderTargetCondition k; + + public PathfinderGoalAvoidTarget(EntityCreature entitycreature, Class oclass, float f, double d0, double d1) { +- Predicate predicate = (entityliving) -> { +- return true; +- }; +- Predicate predicate1 = IEntitySelector.e; +- +- this(entitycreature, oclass, predicate, f, d0, d1, predicate1::test); ++ this(entitycreature, oclass, entityliving -> true, f, d0, d1, IEntitySelector.e::test); // Purpur - decompile fix + } + + public PathfinderGoalAvoidTarget(EntityCreature entitycreature, Class oclass, Predicate predicate, float f, double d0, double d1, Predicate predicate1) { +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityWolf.java b/src/main/java/net/minecraft/world/entity/animal/EntityWolf.java +index dd3c7ad7701ad18ccaf86d73fde7051090ed3d57..e8c6aca70db693250224d1c162e3c2684687ea41 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityWolf.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityWolf.java +@@ -10,15 +10,19 @@ import net.minecraft.network.syncher.DataWatcher; + import net.minecraft.network.syncher.DataWatcherObject; + import net.minecraft.network.syncher.DataWatcherRegistry; + import net.minecraft.server.PathfinderGoalHasRider; ++import net.minecraft.server.level.EntityPlayer; + import net.minecraft.server.level.WorldServer; + import net.minecraft.sounds.SoundEffect; + import net.minecraft.sounds.SoundEffects; + import net.minecraft.util.IntRange; + import net.minecraft.util.MathHelper; + import net.minecraft.util.TimeRange; ++import net.minecraft.world.DifficultyDamageScaler; + import net.minecraft.world.EnumHand; + import net.minecraft.world.EnumInteractionResult; + import net.minecraft.world.damagesource.DamageSource; ++import net.minecraft.world.effect.MobEffect; ++import net.minecraft.world.effect.MobEffects; + import net.minecraft.world.entity.Entity; + import net.minecraft.world.entity.EntityAgeable; + import net.minecraft.world.entity.EntityInsentient; +@@ -27,9 +31,12 @@ import net.minecraft.world.entity.EntityPose; + import net.minecraft.world.entity.EntitySize; + import net.minecraft.world.entity.EntityTameableAnimal; + import net.minecraft.world.entity.EntityTypes; ++import net.minecraft.world.entity.EnumMobSpawn; ++import net.minecraft.world.entity.GroupDataEntity; + import net.minecraft.world.entity.IEntityAngerable; + import net.minecraft.world.entity.ai.attributes.AttributeProvider; + import net.minecraft.world.entity.ai.attributes.GenericAttributes; ++import net.minecraft.world.entity.ai.goal.PathfinderGoal; + import net.minecraft.world.entity.ai.goal.PathfinderGoalAvoidTarget; + import net.minecraft.world.entity.ai.goal.PathfinderGoalBeg; + import net.minecraft.world.entity.ai.goal.PathfinderGoalBreed; +@@ -60,6 +67,7 @@ import net.minecraft.world.item.ItemDye; + import net.minecraft.world.item.ItemStack; + import net.minecraft.world.item.Items; + import net.minecraft.world.level.World; ++import net.minecraft.world.level.WorldAccess; + import net.minecraft.world.level.block.state.IBlockData; + import net.minecraft.world.phys.Vec3D; + +@@ -73,11 +81,42 @@ public class EntityWolf extends EntityTameableAnimal implements IEntityAngerable + private static final DataWatcherObject br = DataWatcher.a(EntityWolf.class, DataWatcherRegistry.i); + private static final DataWatcherObject bs = DataWatcher.a(EntityWolf.class, DataWatcherRegistry.b); + private static final DataWatcherObject bt = DataWatcher.a(EntityWolf.class, DataWatcherRegistry.b); +- public static final Predicate bq = (entityliving) -> { ++ public static Predicate vanillaPredicate() { return bq; } public static final Predicate bq = (entityliving) -> { // Purpur - OBFHELPER + EntityTypes entitytypes = entityliving.getEntityType(); + + return entitytypes == EntityTypes.SHEEP || entitytypes == EntityTypes.RABBIT || entitytypes == EntityTypes.FOX; + }; ++ // Purpur start - rabid wolf spawn chance ++ private boolean isRabid = false; ++ private static final Predicate RABID_PREDICATE = e -> e instanceof EntityPlayer || e instanceof EntityInsentient; ++ private final PathfinderGoal PATHFINDER_VANILLA = new PathfinderGoalRandomTargetNonTamed<>(this, EntityAnimal.class, false, vanillaPredicate()); ++ private final PathfinderGoal PATHFINDER_RABID = new PathfinderGoalRandomTargetNonTamed<>(this, EntityLiving.class, false, RABID_PREDICATE); ++ private static final class PathfinderGoalAvoidRabidWolves extends PathfinderGoalAvoidTarget { ++ private final EntityWolf wolf; ++ ++ public PathfinderGoalAvoidRabidWolves(EntityWolf wolf, float distance, double minSpeed, double maxSpeed) { ++ super(wolf, EntityWolf.class, distance, minSpeed, maxSpeed); ++ this.wolf = wolf; ++ } ++ ++ @Override ++ public boolean a() { // shouldExecute ++ return super.a() && !this.wolf.isRabid() && this.getTarget() != null && this.getTarget().isRabid(); // wolves which are not rabid run away from rabid wolves ++ } ++ ++ @Override ++ public void c() { // startExecuting ++ this.wolf.setGoalTarget(null); ++ super.c(); ++ } ++ ++ @Override ++ public void e() { // tick ++ this.wolf.setGoalTarget(null); ++ super.e(); ++ } ++ } ++ // Purpur end + private float bu; + private float bv; + private boolean bw; +@@ -112,6 +151,37 @@ public class EntityWolf extends EntityTameableAnimal implements IEntityAngerable + public int getPurpurBreedTime() { + return this.world.purpurConfig.wolfBreedingTicks; + } ++ ++ public boolean isRabid() { ++ return this.isRabid; ++ } ++ ++ public void setRabid(boolean isRabid) { ++ this.isRabid = isRabid; ++ updatePathfinders(true); ++ } ++ ++ public void updatePathfinders(boolean modifyEffects) { ++ this.targetSelector.removeGoal(PATHFINDER_VANILLA); ++ this.targetSelector.removeGoal(PATHFINDER_RABID); ++ if (this.isRabid) { ++ setTamed(false); ++ setOwnerUUID(null); ++ this.targetSelector.addGoal(5, PATHFINDER_RABID); ++ if (modifyEffects) this.addEffect(new MobEffect(MobEffects.CONFUSION, 1200)); ++ } else { ++ this.targetSelector.addGoal(5, PATHFINDER_VANILLA); ++ this.pacify(); ++ if (modifyEffects) this.removeEffect(MobEffects.CONFUSION); ++ } ++ } ++ ++ @Override ++ public GroupDataEntity prepare(WorldAccess worldaccess, DifficultyDamageScaler difficultydamagescaler, EnumMobSpawn enummobspawn, @Nullable GroupDataEntity groupdataentity, @Nullable NBTTagCompound nbttagcompound) { ++ this.isRabid = world.purpurConfig.wolfNaturalRabid > 0.0D && random.nextDouble() <= world.purpurConfig.wolfNaturalRabid; ++ this.updatePathfinders(false); ++ return super.prepare(worldaccess, difficultydamagescaler, enummobspawn, groupdataentity, nbttagcompound); ++ } + // Purpur end + + @Override +@@ -120,6 +190,7 @@ public class EntityWolf extends EntityTameableAnimal implements IEntityAngerable + this.goalSelector.a(1, new PathfinderGoalHasRider(this)); // Purpur + this.goalSelector.a(2, new PathfinderGoalSit(this)); + this.goalSelector.a(3, new EntityWolf.a<>(this, EntityLlama.class, 24.0F, 1.5D, 1.5D)); ++ this.goalSelector.addGoal(3, new PathfinderGoalAvoidRabidWolves(this, 24.0F, 1.5D, 1.5D)); // Purpur + this.goalSelector.a(4, new PathfinderGoalLeapAtTarget(this, 0.4F)); + this.goalSelector.a(5, new PathfinderGoalMeleeAttack(this, 1.0D, true)); + this.goalSelector.a(6, new PathfinderGoalFollowOwner(this, 1.0D, 10.0F, 2.0F, false)); +@@ -133,7 +204,7 @@ public class EntityWolf extends EntityTameableAnimal implements IEntityAngerable + this.targetSelector.a(2, new PathfinderGoalOwnerHurtTarget(this)); + this.targetSelector.a(3, (new PathfinderGoalHurtByTarget(this, new Class[0])).a(new Class[0])); // CraftBukkit - decompile error + this.targetSelector.a(4, new PathfinderGoalNearestAttackableTarget<>(this, EntityHuman.class, 10, true, false, this::a_)); +- this.targetSelector.a(5, new PathfinderGoalRandomTargetNonTamed<>(this, EntityAnimal.class, false, EntityWolf.bq)); ++ //this.targetSelector.a(5, new PathfinderGoalRandomTargetNonTamed<>(this, EntityAnimal.class, false, EntityWolf.bq)); // Purpur - moved to updatePathfinders() + this.targetSelector.a(6, new PathfinderGoalRandomTargetNonTamed<>(this, EntityTurtle.class, false, EntityTurtle.bo)); + this.targetSelector.a(7, new PathfinderGoalNearestAttackableTarget<>(this, EntitySkeletonAbstract.class, false)); + this.targetSelector.a(8, new PathfinderGoalUniversalAngerReset<>(this, true)); +@@ -178,6 +249,7 @@ public class EntityWolf extends EntityTameableAnimal implements IEntityAngerable + public void saveData(NBTTagCompound nbttagcompound) { + super.saveData(nbttagcompound); + nbttagcompound.setByte("CollarColor", (byte) this.getCollarColor().getColorIndex()); ++ nbttagcompound.setBoolean("Purpur.IsRabid", this.isRabid); // Purpur + this.c(nbttagcompound); + } + +@@ -187,6 +259,10 @@ public class EntityWolf extends EntityTameableAnimal implements IEntityAngerable + if (nbttagcompound.hasKeyOfType("CollarColor", 99)) { + this.setCollarColor(EnumColor.fromColorIndex(nbttagcompound.getInt("CollarColor"))); + } ++ // Purpur start ++ this.isRabid = nbttagcompound.getBoolean("Purpur.IsRabid"); ++ this.updatePathfinders(false); ++ // Purpur end + + this.a((WorldServer) this.world, nbttagcompound); + } +@@ -231,6 +307,11 @@ public class EntityWolf extends EntityTameableAnimal implements IEntityAngerable + public void tick() { + super.tick(); + if (this.isAlive()) { ++ // Purpur start ++ if (this.ticksLived % 300 == 0 && this.isRabid()) { ++ this.addEffect(new MobEffect(MobEffects.CONFUSION, 400)); ++ } ++ // Purpur end + this.bv = this.bu; + if (this.eY()) { + this.bu += (1.0F - this.bu) * 0.4F; +@@ -402,6 +483,20 @@ public class EntityWolf extends EntityTameableAnimal implements IEntityAngerable + + return EnumInteractionResult.SUCCESS; + } ++ // Purpur start ++ else if (this.world.purpurConfig.wolfMilkCuresRabies && itemstack.getItem() == Items.MILK_BUCKET && this.isRabid()) { ++ if (!entityhuman.isCreative()) { ++ entityhuman.setItemInHand(enumhand, new ItemStack(Items.BUCKET)); ++ } ++ this.setRabid(false); ++ for (int i = 0; i < 10; ++i) { ++ ((WorldServer) world).sendParticles(((WorldServer) world).players, null, Particles.HAPPY_VILLAGER, ++ locX() + random.nextFloat(), locY() + (random.nextFloat() * 1.5), locZ() + random.nextFloat(), 1, ++ random.nextGaussian() * 0.05D, random.nextGaussian() * 0.05D, random.nextGaussian() * 0.05D, 0, true); ++ } ++ return EnumInteractionResult.SUCCESS; ++ } ++ // Purpur end + + return super.b(entityhuman, enumhand); + } +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 7d32788c5e538be6eff9b6ff4655f279ac1e0e6b..5a05d4e511bf7c96d3e01c59e6e53b105bf7baf6 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -1219,10 +1219,14 @@ public class PurpurWorldConfig { + + public boolean wolfRidable = false; + public boolean wolfRidableInWater = false; ++ public boolean wolfMilkCuresRabies = true; ++ public double wolfNaturalRabid = 0.0D; + public int wolfBreedingTicks = 6000; + private void wolfSettings() { + wolfRidable = getBoolean("mobs.wolf.ridable", wolfRidable); + wolfRidableInWater = getBoolean("mobs.wolf.ridable-in-water", wolfRidableInWater); ++ wolfMilkCuresRabies = getBoolean("mobs.wolf.milk-cures-rabid-wolves", wolfMilkCuresRabies); ++ wolfNaturalRabid = getDouble("mobs.wolf.spawn-rabid-chance", wolfNaturalRabid); + wolfBreedingTicks = getInt("mobs.wolf.breeding-delay-ticks", wolfBreedingTicks); + } + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftWolf.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftWolf.java +index dc5ba91ebdef25d633205a65148b62f1853b4da5..71e5b36b7d0bb92ef6e94759318a4a82a19e729a 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftWolf.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftWolf.java +@@ -45,4 +45,16 @@ public class CraftWolf extends CraftTameableAnimal implements Wolf { + public void setCollarColor(DyeColor color) { + getHandle().setCollarColor(EnumColor.fromColorIndex(color.getWoolData())); + } ++ ++ // Purpur start ++ @Override ++ public boolean isRabid() { ++ return getHandle().isRabid(); ++ } ++ ++ @Override ++ public void setRabid(boolean isRabid) { ++ getHandle().setRabid(isRabid); ++ } ++ // Purpur end + } diff --git a/patches/Purpur/patches/server/0146-Configurable-default-wolf-collar-color.patch b/patches/Purpur/patches/server/0146-Configurable-default-wolf-collar-color.patch new file mode 100644 index 00000000..b2e3efad --- /dev/null +++ b/patches/Purpur/patches/server/0146-Configurable-default-wolf-collar-color.patch @@ -0,0 +1,56 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Encode42 +Date: Thu, 10 Dec 2020 13:43:28 -0500 +Subject: [PATCH] Configurable default wolf collar color + +This allows for the server to set a default collar color when a wolf is tamed. +Resets to RED when the value is invalid. + +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityWolf.java b/src/main/java/net/minecraft/world/entity/animal/EntityWolf.java +index e8c6aca70db693250224d1c162e3c2684687ea41..e33aadead6e6c5e0a7b39ef95e7aeb0f0092a94e 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityWolf.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityWolf.java +@@ -182,6 +182,12 @@ public class EntityWolf extends EntityTameableAnimal implements IEntityAngerable + this.updatePathfinders(false); + return super.prepare(worldaccess, difficultydamagescaler, enummobspawn, groupdataentity, nbttagcompound); + } ++ ++ @Override ++ public void tame(EntityHuman entityhuman) { ++ setCollarColor(world.purpurConfig.wolfDefaultCollarColor); ++ super.tame(entityhuman); ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 5a05d4e511bf7c96d3e01c59e6e53b105bf7baf6..0666c523f82b9083ed8e81570faa923bbeb00ab8 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -3,6 +3,7 @@ package net.pl3x.purpur; + import com.destroystokyo.paper.PaperConfig; + import net.minecraft.core.IRegistry; + import net.minecraft.world.EnumDifficulty; ++import net.minecraft.world.item.EnumColor; + import net.minecraft.world.level.Explosion; + import net.minecraft.world.level.block.Block; + import net.minecraft.world.level.block.Blocks; +@@ -1219,12 +1220,18 @@ public class PurpurWorldConfig { + + public boolean wolfRidable = false; + public boolean wolfRidableInWater = false; ++ public EnumColor wolfDefaultCollarColor = EnumColor.RED; + public boolean wolfMilkCuresRabies = true; + public double wolfNaturalRabid = 0.0D; + public int wolfBreedingTicks = 6000; + private void wolfSettings() { + wolfRidable = getBoolean("mobs.wolf.ridable", wolfRidable); + wolfRidableInWater = getBoolean("mobs.wolf.ridable-in-water", wolfRidableInWater); ++ try { ++ wolfDefaultCollarColor = EnumColor.valueOf(getString("mobs.wolf.default-collar-color", wolfDefaultCollarColor.name())); ++ } catch (IllegalArgumentException ignore) { ++ wolfDefaultCollarColor = EnumColor.RED; ++ } + wolfMilkCuresRabies = getBoolean("mobs.wolf.milk-cures-rabid-wolves", wolfMilkCuresRabies); + wolfNaturalRabid = getDouble("mobs.wolf.spawn-rabid-chance", wolfNaturalRabid); + wolfBreedingTicks = getInt("mobs.wolf.breeding-delay-ticks", wolfBreedingTicks); diff --git a/patches/Purpur/patches/server/0147-Configurable-entity-base-attributes.patch b/patches/Purpur/patches/server/0147-Configurable-entity-base-attributes.patch new file mode 100644 index 00000000..caec592d --- /dev/null +++ b/patches/Purpur/patches/server/0147-Configurable-entity-base-attributes.patch @@ -0,0 +1,2655 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Thu, 10 Dec 2020 16:44:54 -0600 +Subject: [PATCH] Configurable entity base attributes + + +diff --git a/src/main/java/net/minecraft/world/entity/ambient/EntityBat.java b/src/main/java/net/minecraft/world/entity/ambient/EntityBat.java +index bee72578fae2fba56f8e8dcc1142ab54c7ba7cb8..5c9e4724d46b6864cdb85f7d3c8fb0fe37032444 100644 +--- a/src/main/java/net/minecraft/world/entity/ambient/EntityBat.java ++++ b/src/main/java/net/minecraft/world/entity/ambient/EntityBat.java +@@ -81,6 +81,18 @@ public class EntityBat extends EntityAmbient { + setMot(mot.a(0.9D)); + } + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.batMaxHealth); ++ this.getAttributeInstance(GenericAttributes.FOLLOW_RANGE).setValue(this.world.purpurConfig.batFollowRange); ++ this.getAttributeInstance(GenericAttributes.KNOCKBACK_RESISTANCE).setValue(this.world.purpurConfig.batKnockbackResistance); ++ this.getAttributeInstance(GenericAttributes.MOVEMENT_SPEED).setValue(this.world.purpurConfig.batMovementSpeed); ++ this.getAttributeInstance(GenericAttributes.FLYING_SPEED).setValue(this.world.purpurConfig.batFlyingSpeed); ++ this.getAttributeInstance(GenericAttributes.ARMOR).setValue(this.world.purpurConfig.batArmor); ++ this.getAttributeInstance(GenericAttributes.ARMOR_TOUGHNESS).setValue(this.world.purpurConfig.batArmorToughness); ++ this.getAttributeInstance(GenericAttributes.ATTACK_KNOCKBACK).setValue(this.world.purpurConfig.batAttackKnockback); ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityBee.java b/src/main/java/net/minecraft/world/entity/animal/EntityBee.java +index 6086dda5b06f0c0e02734edf7141b13715420d3c..e425e093c233a21e5ef457e3a94defe8b74261d2 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityBee.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityBee.java +@@ -180,6 +180,11 @@ public class EntityBee extends EntityAnimal implements IEntityAngerable, EntityB + public int getPurpurBreedTime() { + return this.world.purpurConfig.beeBreedingTicks; + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.beeMaxHealth); ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityCat.java b/src/main/java/net/minecraft/world/entity/animal/EntityCat.java +index 187047de5530ccec1e9804f8039839246ab248f3..a4e3e36f081803b0588a0e907a3a834b7a3ab3eb 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityCat.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityCat.java +@@ -127,6 +127,11 @@ public class EntityCat extends EntityTameableAnimal { + public int getPurpurBreedTime() { + return this.world.purpurConfig.catBreedingTicks; + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.catMaxHealth); ++ } + // Purpur end + + public MinecraftKey eU() { +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityChicken.java b/src/main/java/net/minecraft/world/entity/animal/EntityChicken.java +index ab54e809f735cea7d84366d2bc205351f8992bef..51fd3d955c866cc09bb09abe1b6d23caad2d7e85 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityChicken.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityChicken.java +@@ -70,6 +70,7 @@ public class EntityChicken extends EntityAnimal { + if (world.purpurConfig.chickenRetaliate) { + this.getAttributeInstance(GenericAttributes.ATTACK_DAMAGE).setValue(2.0D); + } ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.chickenMaxHealth); + } + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityCod.java b/src/main/java/net/minecraft/world/entity/animal/EntityCod.java +index 897e0d5ca44a0c475634f08e7d4fcf129ee197ab..07c6dc6a1b9af7b9662f4dd4b4a2ddfcbe600c34 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityCod.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityCod.java +@@ -4,6 +4,7 @@ import net.minecraft.sounds.SoundEffect; + import net.minecraft.sounds.SoundEffects; + import net.minecraft.world.damagesource.DamageSource; + import net.minecraft.world.entity.EntityTypes; ++import net.minecraft.world.entity.ai.attributes.GenericAttributes; + import net.minecraft.world.item.ItemStack; + import net.minecraft.world.item.Items; + import net.minecraft.world.level.World; +@@ -24,6 +25,11 @@ public class EntityCod extends EntityFishSchool { + public boolean isRidableInWater() { + return true; + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.codMaxHealth); ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityCow.java b/src/main/java/net/minecraft/world/entity/animal/EntityCow.java +index 7ed55ebe1bb768351a5cb4cdc7d4d3b0816d53b1..06af4c63fa05b243b7692cbc41b4f62ca0548def 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityCow.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityCow.java +@@ -59,6 +59,11 @@ public class EntityCow extends EntityAnimal { + public int getPurpurBreedTime() { + return this.world.purpurConfig.cowBreedingTicks; + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.cowMaxHealth); ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityDolphin.java b/src/main/java/net/minecraft/world/entity/animal/EntityDolphin.java +index e4442716b329f3101bfd39fc7ce13d5419b427bf..3ca911cebc01692f63b8731a5df6d9ea3fbad66b 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityDolphin.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityDolphin.java +@@ -128,6 +128,11 @@ public class EntityDolphin extends EntityWaterAnimal { + } + return false; + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.dolphinMaxHealth); ++ } + // Purpur end + + @Nullable +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityFox.java b/src/main/java/net/minecraft/world/entity/animal/EntityFox.java +index 70369d03985250fa5eaf398fa98d35a2c2a06ff1..5a2e624f1b6636f058cc69989324914f174a271a 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityFox.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityFox.java +@@ -162,6 +162,11 @@ public class EntityFox extends EntityAnimal { + public int getPurpurBreedTime() { + return this.world.purpurConfig.foxBreedingTicks; + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.foxMaxHealth); ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityIronGolem.java b/src/main/java/net/minecraft/world/entity/animal/EntityIronGolem.java +index 23e614f0c3cf1178acff8e72e0441c42c658e76b..9ee82c908008190e31034e614c241fc7a66248e1 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityIronGolem.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityIronGolem.java +@@ -80,6 +80,11 @@ public class EntityIronGolem extends EntityGolem implements IEntityAngerable { + public boolean isRidableInWater() { + return world.purpurConfig.ironGolemRidableInWater; + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.ironGolemMaxHealth); ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityMushroomCow.java b/src/main/java/net/minecraft/world/entity/animal/EntityMushroomCow.java +index ab4a8ee6e1912f230cbf3353eb42c3bc8a9db58e..4b7e21a611d87410805722c30c9ee77212b33348 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityMushroomCow.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityMushroomCow.java +@@ -24,6 +24,7 @@ import net.minecraft.world.entity.EntityLightning; + import net.minecraft.world.entity.EntityTypes; + import net.minecraft.world.entity.EnumMobSpawn; + import net.minecraft.world.entity.IShearable; ++import net.minecraft.world.entity.ai.attributes.GenericAttributes; + import net.minecraft.world.entity.item.EntityItem; + import net.minecraft.world.entity.player.EntityHuman; + import net.minecraft.world.item.Item; +@@ -72,6 +73,11 @@ public class EntityMushroomCow extends EntityCow implements IShearable { + public int getPurpurBreedTime() { + return this.world.purpurConfig.mooshroomBreedingTicks; + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.mooshroomMaxHealth); ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityOcelot.java b/src/main/java/net/minecraft/world/entity/animal/EntityOcelot.java +index cff2ff5a8beef739f0515832e072e7e390ac388f..12534673afe0b05868a5f400c9e59c22dfcf12d6 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityOcelot.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityOcelot.java +@@ -79,6 +79,11 @@ public class EntityOcelot extends EntityAnimal { + public int getPurpurBreedTime() { + return this.world.purpurConfig.ocelotBreedingTicks; + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.ocelotMaxHealth); ++ } + // Purpur end + + private boolean isTrusting() { +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityPanda.java b/src/main/java/net/minecraft/world/entity/animal/EntityPanda.java +index e6952c0a8d90eb4b133c517d97299f2c3db7e329..94141b8c1ad62e6d187726734d25dd0ee5535618 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityPanda.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityPanda.java +@@ -34,6 +34,7 @@ import net.minecraft.world.entity.EnumItemSlot; + import net.minecraft.world.entity.EnumMobSpawn; + import net.minecraft.world.entity.GroupDataEntity; + import net.minecraft.world.entity.IEntitySelector; ++import net.minecraft.world.entity.ai.attributes.AttributeModifiable; + import net.minecraft.world.entity.ai.attributes.AttributeProvider; + import net.minecraft.world.entity.ai.attributes.GenericAttributes; + import net.minecraft.world.entity.ai.control.ControllerMove; +@@ -126,6 +127,12 @@ public class EntityPanda extends EntityAnimal { + public int getPurpurBreedTime() { + return this.world.purpurConfig.pandaBreedingTicks; + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.pandaMaxHealth); ++ updateAttributes(); ++ } + // Purpur end + + @Override +@@ -598,9 +605,12 @@ public class EntityPanda extends EntityAnimal { + return this.random.nextBoolean() ? this.getMainGene() : this.getHiddenGene(); + } + +- public void fg() { ++ public void fg() { updateAttributes(); } public void updateAttributes() { // Purpur - OBFHELPER + if (this.isWeak()) { +- this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(10.0D); ++ // Purpur start ++ AttributeModifiable maxHealth = this.getAttributeInstance(GenericAttributes.MAX_HEALTH); ++ maxHealth.setValue(maxHealth.getValue() / 2); ++ // Purpur end + } + + if (this.isLazy()) { +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityParrot.java b/src/main/java/net/minecraft/world/entity/animal/EntityParrot.java +index 7346921a24bdd57aa3814386bc372b082b23b4bc..7500de8bcdd32f08bf6d32e70cfe09baf097cc2b 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityParrot.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityParrot.java +@@ -176,6 +176,11 @@ public class EntityParrot extends EntityPerchable implements EntityBird { + public int getPurpurBreedTime() { + return 6000; + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.parrotMaxHealth); ++ } + // Purpur end + + @Nullable +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityPig.java b/src/main/java/net/minecraft/world/entity/animal/EntityPig.java +index 5aa8806063186bec36b38adc51e2ea82bf6ff21a..8d24855f230a5ca6280f885d5b1c26ecf5b91395 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityPig.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityPig.java +@@ -82,6 +82,11 @@ public class EntityPig extends EntityAnimal implements ISteerable, ISaddleable { + public int getPurpurBreedTime() { + return this.world.purpurConfig.pigBreedingTicks; + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.pigMaxHealth); ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityPolarBear.java b/src/main/java/net/minecraft/world/entity/animal/EntityPolarBear.java +index c9c7c9de638079393bbea86f8069023dcbcbca83..83494d3c989a120297c21a1bd560bc37734dc86a 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityPolarBear.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityPolarBear.java +@@ -121,6 +121,11 @@ public class EntityPolarBear extends EntityAnimal implements IEntityAngerable { + public int getPurpurBreedTime() { + return this.world.purpurConfig.polarBearBreedingTicks; + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.polarBearMaxHealth); ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityPufferFish.java b/src/main/java/net/minecraft/world/entity/animal/EntityPufferFish.java +index b94aa69e2c5f41161e8c21d68078a522d063e03d..c81aa13dff40d41577c7c13f6aef8972bf31d69e 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityPufferFish.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityPufferFish.java +@@ -20,6 +20,7 @@ import net.minecraft.world.entity.EntityPose; + import net.minecraft.world.entity.EntitySize; + import net.minecraft.world.entity.EntityTypes; + import net.minecraft.world.entity.EnumMonsterType; ++import net.minecraft.world.entity.ai.attributes.GenericAttributes; + import net.minecraft.world.entity.ai.goal.PathfinderGoal; + import net.minecraft.world.entity.player.EntityHuman; + import net.minecraft.world.item.ItemStack; +@@ -49,6 +50,11 @@ public class EntityPufferFish extends EntityFish { + public boolean isRidableInWater() { + return true; + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.pufferfishMaxHealth); ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityRabbit.java b/src/main/java/net/minecraft/world/entity/animal/EntityRabbit.java +index 465701232567e4058f9dfc776560ccde33fee66c..ef031ac08b06e78d8826579c49cf5e43683318f9 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityRabbit.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityRabbit.java +@@ -90,6 +90,11 @@ public class EntityRabbit extends EntityAnimal { + public int getPurpurBreedTime() { + return this.world.purpurConfig.rabbitBreedingTicks; + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.rabbitMaxHealth); ++ } + // Purpur end + + // CraftBukkit start - code from constructor +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntitySalmon.java b/src/main/java/net/minecraft/world/entity/animal/EntitySalmon.java +index bf565671c167162b3d935447961f0d44ed4a2779..36e60360193cb0cfd8fef03f964e0fa90002f8bc 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntitySalmon.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntitySalmon.java +@@ -4,6 +4,7 @@ import net.minecraft.sounds.SoundEffect; + import net.minecraft.sounds.SoundEffects; + import net.minecraft.world.damagesource.DamageSource; + import net.minecraft.world.entity.EntityTypes; ++import net.minecraft.world.entity.ai.attributes.GenericAttributes; + import net.minecraft.world.item.ItemStack; + import net.minecraft.world.item.Items; + import net.minecraft.world.level.World; +@@ -24,6 +25,11 @@ public class EntitySalmon extends EntityFishSchool { + public boolean isRidableInWater() { + return true; + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.salmonMaxHealth); ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntitySheep.java b/src/main/java/net/minecraft/world/entity/animal/EntitySheep.java +index ff6fc821085e4430a3b1008140b0b7fcacc59d2e..365f70117a287fab2fbf63ee8d89a10ac70b2f1b 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntitySheep.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntitySheep.java +@@ -126,6 +126,11 @@ public class EntitySheep extends EntityAnimal implements IShearable { + public int getPurpurBreedTime() { + return this.world.purpurConfig.sheepBreedingTicks; + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.sheepMaxHealth); ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntitySnowman.java b/src/main/java/net/minecraft/world/entity/animal/EntitySnowman.java +index 76fe39cf57384602c7422cb340f15ca7cac65ef9..3934966b06eb9880ed316cee84d099edd80c09b9 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntitySnowman.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntitySnowman.java +@@ -61,6 +61,11 @@ public class EntitySnowman extends EntityGolem implements IShearable, IRangedEnt + public boolean isRidableInWater() { + return world.purpurConfig.snowGolemRidableInWater; + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.snowGolemMaxHealth); ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntitySquid.java b/src/main/java/net/minecraft/world/entity/animal/EntitySquid.java +index 7ec3e5d136cbb708b3bb29aa79bdd401d37d56dc..fa629ebc4946a0c3e891e5e2dd881277b3e25347 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntitySquid.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntitySquid.java +@@ -86,6 +86,11 @@ public class EntitySquid extends EntityWaterAnimal { + public boolean isInWater() { + return this.inWater || world.purpurConfig.squidsCanFly; + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.squidMaxHealth); ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityTropicalFish.java b/src/main/java/net/minecraft/world/entity/animal/EntityTropicalFish.java +index 478e55475ccc1410a442f4e30a1cbc08f479dbda..7d0982b8756b9e6c12cf4acae765ff651b846250 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityTropicalFish.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityTropicalFish.java +@@ -14,6 +14,7 @@ import net.minecraft.world.damagesource.DamageSource; + import net.minecraft.world.entity.EntityTypes; + import net.minecraft.world.entity.EnumMobSpawn; + import net.minecraft.world.entity.GroupDataEntity; ++import net.minecraft.world.entity.ai.attributes.GenericAttributes; + import net.minecraft.world.item.EnumColor; + import net.minecraft.world.item.ItemStack; + import net.minecraft.world.item.Items; +@@ -47,6 +48,11 @@ public class EntityTropicalFish extends EntityFishSchool { + public boolean isRidableInWater() { + return true; + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.tropicalFishMaxHealth); ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityTurtle.java b/src/main/java/net/minecraft/world/entity/animal/EntityTurtle.java +index a16f586934f24e599d00bf793f06d3f9134ed29d..2da43c75c5767973c43e42af37c0d0d9d3a27859 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityTurtle.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityTurtle.java +@@ -106,6 +106,11 @@ public class EntityTurtle extends EntityAnimal { + public int getPurpurBreedTime() { + return this.world.purpurConfig.turtleBreedingTicks; + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.turtleMaxHealth); ++ } + // Purpur end + + public void setHomePos(BlockPosition blockposition) { +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityWolf.java b/src/main/java/net/minecraft/world/entity/animal/EntityWolf.java +index e33aadead6e6c5e0a7b39ef95e7aeb0f0092a94e..090903fbc8f6cd1522c7afb358f708f5ae3395f4 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityWolf.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityWolf.java +@@ -188,6 +188,11 @@ public class EntityWolf extends EntityTameableAnimal implements IEntityAngerable + setCollarColor(world.purpurConfig.wolfDefaultCollarColor); + super.tame(entityhuman); + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.wolfMaxHealth); ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorse.java b/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorse.java +index c830bf6e5e38f5ebacc07673c3d67e4157c8c2b5..c6e39fe54cc402869b2e9eaea1830ba1ccc9ffc1 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorse.java ++++ b/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorse.java +@@ -51,6 +51,21 @@ public class EntityHorse extends EntityHorseAbstract { + public int getPurpurBreedTime() { + return this.world.purpurConfig.horseBreedingTicks; + } ++ ++ @Override ++ public float generateMaxHealth() { ++ return (float) generateMaxHealth(this.world.purpurConfig.horseMaxHealthMin, this.world.purpurConfig.horseMaxHealthMax); ++ } ++ ++ @Override ++ public double generateJumpStrength() { ++ return generateJumpStrength(this.world.purpurConfig.horseJumpStrengthMin, this.world.purpurConfig.horseJumpStrengthMax); ++ } ++ ++ @Override ++ public double generateMovementSpeed() { ++ return generateMovementSpeed(this.world.purpurConfig.horseMovementSpeedMin, this.world.purpurConfig.horseMovementSpeedMax); ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseAbstract.java b/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseAbstract.java +index d4556fa190c754406d0c65baae941fb23af3f81f..1d938f324bc08c05b44c72b5a2927016ed599cf2 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseAbstract.java ++++ b/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseAbstract.java +@@ -120,6 +120,32 @@ public abstract class EntityHorseAbstract extends EntityAnimal implements IInven + public boolean isRidableInWater() { + return false; + } ++ ++ protected double generateMaxHealth(double min, double max) { ++ if (min == max) return min; ++ int diff = MathHelper.floor(max - min); ++ double base = max - diff; ++ int first = MathHelper.floor((double) diff / 2); ++ int rest = diff - first; ++ return base + random.nextInt(first + 1) + random.nextInt(rest + 1); ++ } ++ ++ protected double generateJumpStrength(double min, double max) { ++ if (min == max) return min; ++ return min + (max - min) * this.random.nextDouble(); ++ } ++ ++ protected double generateMovementSpeed(double min, double max) { ++ if (min == max) return min; ++ return min + (max - min) * this.random.nextDouble(); ++ } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.generateMaxHealth()); ++ this.getAttributeInstance(GenericAttributes.MOVEMENT_SPEED).setValue(this.generateMovementSpeed()); ++ this.getAttributeInstance(GenericAttributes.JUMP_STRENGTH).setValue(this.generateJumpStrength()); ++ } + // Purpur end + + @Override +@@ -928,15 +954,15 @@ public abstract class EntityHorseAbstract extends EntityAnimal implements IInven + + } + +- protected float fp() { ++ protected float fp() { return generateMaxHealth(); } public float generateMaxHealth() { // Purpur - OBFHELPER + return 15.0F + (float) this.random.nextInt(8) + (float) this.random.nextInt(9); + } + +- protected double fq() { ++ protected double fq() { return generateJumpStrength(); } public double generateJumpStrength() { // Purpur - OBFHELPER + return 0.4000000059604645D + this.random.nextDouble() * 0.2D + this.random.nextDouble() * 0.2D + this.random.nextDouble() * 0.2D; + } + +- protected double fr() { ++ protected double fr() { return generateMovementSpeed(); } public double generateMovementSpeed() { // Purpur - OBFHELPER + return (0.44999998807907104D + this.random.nextDouble() * 0.3D + this.random.nextDouble() * 0.3D + this.random.nextDouble() * 0.3D) * 0.25D; + } + +@@ -1059,7 +1085,7 @@ public abstract class EntityHorseAbstract extends EntityAnimal implements IInven + groupdataentity = new EntityAgeable.a(0.2F); + } + +- this.eK(); ++ //this.eK(); // Purpur + return super.prepare(worldaccess, difficultydamagescaler, enummobspawn, (GroupDataEntity) groupdataentity, nbttagcompound); + } + } +diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseDonkey.java b/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseDonkey.java +index 3b44394dcba8e9905aca46e6e585ee6d7a87de44..589986b36c12dd2774a87e1d22aafd6d3052f123 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseDonkey.java ++++ b/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseDonkey.java +@@ -26,6 +26,21 @@ public class EntityHorseDonkey extends EntityHorseChestedAbstract { + public int getPurpurBreedTime() { + return this.world.purpurConfig.donkeyBreedingTicks; + } ++ ++ @Override ++ public float generateMaxHealth() { ++ return (float) generateMaxHealth(this.world.purpurConfig.donkeyMaxHealthMin, this.world.purpurConfig.donkeyMaxHealthMax); ++ } ++ ++ @Override ++ public double generateJumpStrength() { ++ return generateJumpStrength(this.world.purpurConfig.donkeyJumpStrengthMin, this.world.purpurConfig.donkeyJumpStrengthMax); ++ } ++ ++ @Override ++ public double generateMovementSpeed() { ++ return generateMovementSpeed(this.world.purpurConfig.donkeyMovementSpeedMin, this.world.purpurConfig.donkeyMovementSpeedMax); ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseMule.java b/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseMule.java +index 0536112357e0321dbb902331467b847894a4c11b..9cc1a371dfbb0305fa47e69665a12a6901224edc 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseMule.java ++++ b/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseMule.java +@@ -25,7 +25,23 @@ public class EntityHorseMule extends EntityHorseChestedAbstract { + public int getPurpurBreedTime() { + return this.world.purpurConfig.muleBreedingTicks; + } ++ ++ @Override ++ public float generateMaxHealth() { ++ return (float) generateMaxHealth(this.world.purpurConfig.muleMaxHealthMin, this.world.purpurConfig.muleMaxHealthMax); ++ } ++ ++ @Override ++ public double generateJumpStrength() { ++ return generateJumpStrength(this.world.purpurConfig.muleJumpStrengthMin, this.world.purpurConfig.muleJumpStrengthMax); ++ } ++ ++ @Override ++ public double generateMovementSpeed() { ++ return generateMovementSpeed(this.world.purpurConfig.muleMovementSpeedMin, this.world.purpurConfig.muleMovementSpeedMax); ++ } + // Purpur end ++ + @Override + protected SoundEffect getSoundAmbient() { + super.getSoundAmbient(); +diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseSkeleton.java b/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseSkeleton.java +index 28c6e3745c61d0670bf7f3a324169472250e25f4..0fe21fde809aa72305b1145b994a7aafe3f03112 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseSkeleton.java ++++ b/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseSkeleton.java +@@ -48,6 +48,21 @@ public class EntityHorseSkeleton extends EntityHorseAbstract { + public int getPurpurBreedTime() { + return 6000; + } ++ ++ @Override ++ public float generateMaxHealth() { ++ return (float) generateMaxHealth(this.world.purpurConfig.skeletonHorseMaxHealthMin, this.world.purpurConfig.skeletonHorseMaxHealthMax); ++ } ++ ++ @Override ++ public double generateJumpStrength() { ++ return generateJumpStrength(this.world.purpurConfig.skeletonHorseJumpStrengthMin, this.world.purpurConfig.skeletonHorseJumpStrengthMax); ++ } ++ ++ @Override ++ public double generateMovementSpeed() { ++ return generateMovementSpeed(this.world.purpurConfig.skeletonHorseMovementSpeedMin, this.world.purpurConfig.skeletonHorseMovementSpeedMax); ++ } + // Purpur end + + public static AttributeProvider.Builder eL() { +diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseZombie.java b/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseZombie.java +index c776f18722d1aa73f53da66ef6b37564eeaddd2a..1820c2d225d1fa919de2b1c0593370a8a17b4b6a 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseZombie.java ++++ b/src/main/java/net/minecraft/world/entity/animal/horse/EntityHorseZombie.java +@@ -40,6 +40,21 @@ public class EntityHorseZombie extends EntityHorseAbstract { + public int getPurpurBreedTime() { + return 6000; + } ++ ++ @Override ++ public float generateMaxHealth() { ++ return (float) generateMaxHealth(this.world.purpurConfig.zombieHorseMaxHealthMin, this.world.purpurConfig.zombieHorseMaxHealthMax); ++ } ++ ++ @Override ++ public double generateJumpStrength() { ++ return generateJumpStrength(this.world.purpurConfig.zombieHorseJumpStrengthMin, this.world.purpurConfig.zombieHorseJumpStrengthMax); ++ } ++ ++ @Override ++ public double generateMovementSpeed() { ++ return generateMovementSpeed(this.world.purpurConfig.zombieHorseMovementSpeedMin, this.world.purpurConfig.zombieHorseMovementSpeedMax); ++ } + // Purpur end + + public static AttributeProvider.Builder eL() { +diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/EntityLlama.java b/src/main/java/net/minecraft/world/entity/animal/horse/EntityLlama.java +index 2710c246a147f117d2d90014c37988888010dc36..4bea68fa35177d84a35dc5ced3e501a87e2a5391 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/horse/EntityLlama.java ++++ b/src/main/java/net/minecraft/world/entity/animal/horse/EntityLlama.java +@@ -113,6 +113,21 @@ public class EntityLlama extends EntityHorseChestedAbstract implements IRangedEn + public int getPurpurBreedTime() { + return this.world.purpurConfig.llamaBreedingTicks; + } ++ ++ @Override ++ public float generateMaxHealth() { ++ return (float) generateMaxHealth(this.world.purpurConfig.llamaMaxHealthMin, this.world.purpurConfig.llamaMaxHealthMax); ++ } ++ ++ @Override ++ public double generateJumpStrength() { ++ return generateJumpStrength(this.world.purpurConfig.llamaJumpStrengthMin, this.world.purpurConfig.llamaJumpStrengthMax); ++ } ++ ++ @Override ++ public double generateMovementSpeed() { ++ return generateMovementSpeed(this.world.purpurConfig.llamaMovementSpeedMin, this.world.purpurConfig.llamaMovementSpeedMax); ++ } + // Purpur end + + public void setStrength(int i) { +diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/EntityLlamaTrader.java b/src/main/java/net/minecraft/world/entity/animal/horse/EntityLlamaTrader.java +index 0fb651bcde1109b0eb30b60226d3512648dceb41..73f59982d70093d308c6dc6a9a5693347c2699b7 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/horse/EntityLlamaTrader.java ++++ b/src/main/java/net/minecraft/world/entity/animal/horse/EntityLlamaTrader.java +@@ -42,6 +42,21 @@ public class EntityLlamaTrader extends EntityLlama { + public boolean hasSaddle() { + return super.hasSaddle() || isTamed(); + } ++ ++ @Override ++ public float generateMaxHealth() { ++ return (float) generateMaxHealth(this.world.purpurConfig.llamaTraderMaxHealthMin, this.world.purpurConfig.llamaTraderMaxHealthMax); ++ } ++ ++ @Override ++ public double generateJumpStrength() { ++ return generateJumpStrength(this.world.purpurConfig.llamaTraderJumpStrengthMin, this.world.purpurConfig.llamaTraderJumpStrengthMax); ++ } ++ ++ @Override ++ public double generateMovementSpeed() { ++ return generateMovementSpeed(this.world.purpurConfig.llamaTraderMovementSpeedMin, this.world.purpurConfig.llamaTraderMovementSpeedMax); ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EntityEnderDragon.java b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EntityEnderDragon.java +index b2d1a0144353a1da61221b59a0acc028b0cf746e..aeff46b575a05145fb509b5e5a489b2067776e2f 100644 +--- a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EntityEnderDragon.java ++++ b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EntityEnderDragon.java +@@ -147,6 +147,11 @@ public class EntityEnderDragon extends EntityInsentient implements IMonster { + public double getMaxY() { + return world.purpurConfig.enderDragonMaxY; + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.enderDragonMaxHealth); ++ } + // Purpur end + + public static AttributeProvider.Builder m() { +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityBlaze.java b/src/main/java/net/minecraft/world/entity/monster/EntityBlaze.java +index 6553fd92c26d71ac0a60bd046c7f968f2dfe6667..55b6f483aca8cbb5c30b3759e23c86a699e19569 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityBlaze.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityBlaze.java +@@ -72,6 +72,11 @@ public class EntityBlaze extends EntityMonster { + setMot(mot.a(0.9D)); + } + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.blazeMaxHealth); ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityCaveSpider.java b/src/main/java/net/minecraft/world/entity/monster/EntityCaveSpider.java +index 27baf5cde99d8f25b1e7583c30339fcc71a3786f..72b298642f17c13f0f5959034e345a47f1e7ae26 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityCaveSpider.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityCaveSpider.java +@@ -34,6 +34,11 @@ public class EntityCaveSpider extends EntitySpider { + public boolean isRidableInWater() { + return world.purpurConfig.caveSpiderRidableInWater; + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.caveSpiderMaxHealth); ++ } + // Purpur end + + public static AttributeProvider.Builder m() { +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityCreeper.java b/src/main/java/net/minecraft/world/entity/monster/EntityCreeper.java +index 1daacdd75c709cd5508434b41589bd57032de27c..d049aac0208386198d1da4e9470e64898d27b1c9 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityCreeper.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityCreeper.java +@@ -137,6 +137,11 @@ public class EntityCreeper extends EntityMonster { + } + return getForward() == 0 && getStrafe() == 0; // do not jump if standing still + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.creeperMaxHealth); ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityDrowned.java b/src/main/java/net/minecraft/world/entity/monster/EntityDrowned.java +index 93946f4e3cad07e20189a44ce512682b4cbc163b..926a38adb52b7d99ce2a9fcc52eb4878a2abdbcf 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityDrowned.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityDrowned.java +@@ -97,6 +97,15 @@ public class EntityDrowned extends EntityZombie implements IRangedEntity { + public boolean jockeyTryExistingChickens() { + return world.purpurConfig.drownedJockeyTryExistingChickens; + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.drownedMaxHealth); ++ } ++ ++ protected void generateReinforcementsChance() { ++ this.getAttributeInstance(GenericAttributes.SPAWN_REINFORCEMENTS).setValue(this.random.nextDouble() * this.world.purpurConfig.drownedSpawnReinforcements); ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityEnderman.java b/src/main/java/net/minecraft/world/entity/monster/EntityEnderman.java +index cae2b2139e398dd26e9562636f06e096b3e028ae..7c25a7610a5f18e21afead1290e4d879588845af 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityEnderman.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityEnderman.java +@@ -95,6 +95,11 @@ public class EntityEnderman extends EntityMonster implements IEntityAngerable { + public boolean isRidableInWater() { + return world.purpurConfig.endermanRidableInWater; + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.endermanMaxHealth); ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityEndermite.java b/src/main/java/net/minecraft/world/entity/monster/EntityEndermite.java +index 1c87bea9de812e57f8ccd3c9aa85330af87ed240..0e1d60a744fb41d2c31950572720b8899281df47 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityEndermite.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityEndermite.java +@@ -47,6 +47,11 @@ public class EntityEndermite extends EntityMonster { + public boolean isRidableInWater() { + return world.purpurConfig.endermiteRidableInWater; + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.endermiteMaxHealth); ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityEvoker.java b/src/main/java/net/minecraft/world/entity/monster/EntityEvoker.java +index 55607910183155080e3d96296421438d17f19c8f..8d7b8d2ac9a7340e2cfd0d1b8963e4e4d97e8bc8 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityEvoker.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityEvoker.java +@@ -59,6 +59,11 @@ public class EntityEvoker extends EntityIllagerWizard { + public boolean isRidableInWater() { + return world.purpurConfig.evokerRidableInWater; + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.evokerMaxHealth); ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityGhast.java b/src/main/java/net/minecraft/world/entity/monster/EntityGhast.java +index b6d49740a1c8dfa19e871869b92b307fc8397588..e83d9aae4a04fc67587d40cec1f24ba5ebb58e10 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityGhast.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityGhast.java +@@ -73,6 +73,11 @@ public class EntityGhast extends EntityFlying implements IMonster { + setMot(mot.a(0.9D)); + } + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.ghastMaxHealth); ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityGuardian.java b/src/main/java/net/minecraft/world/entity/monster/EntityGuardian.java +index 66ae664add95f4441724b49a470a2fef569042d6..291b2e0defe4d63d4f746a3879c1fee59d2997d7 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityGuardian.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityGuardian.java +@@ -86,6 +86,11 @@ public class EntityGuardian extends EntityMonster { + public boolean isRidableInWater() { + return true; + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.guardianMaxHealth); ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityGuardianElder.java b/src/main/java/net/minecraft/world/entity/monster/EntityGuardianElder.java +index ef48184f79920f053d62d34cc7b56a98e8aa4274..4ce2880c063e3552febd05dc7f38cb17cbb1b4d7 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityGuardianElder.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityGuardianElder.java +@@ -40,6 +40,11 @@ public class EntityGuardianElder extends EntityGuardian { + public boolean isRidableInWater() { + return true; + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.elderGuardianMaxHealth); ++ } + // Purpur end + + public static AttributeProvider.Builder m() { +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityMagmaCube.java b/src/main/java/net/minecraft/world/entity/monster/EntityMagmaCube.java +index 15ed51a2746c09538a425fce25fa25f2619b7033..626a207cdb727866cb75f4e53a6880867c1ca195 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityMagmaCube.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityMagmaCube.java +@@ -44,6 +44,15 @@ public class EntityMagmaCube extends EntitySlime { + public float getJumpHeight() { + return 0.42F * this.getBlockJumpFactor(); // from EntityLiving + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.generateMaxHealth()); ++ } ++ ++ public String getMaxHealthEquation() { ++ return world.purpurConfig.magmaCubeMaxHealth; ++ } + // Purpur end + + public static AttributeProvider.Builder m() { +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityPhantom.java b/src/main/java/net/minecraft/world/entity/monster/EntityPhantom.java +index 1ea3054cebbf32588219f8915f9fb496495e3a10..437d602cf4a0da52fc61a50321d795290eea11bf 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityPhantom.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityPhantom.java +@@ -120,6 +120,11 @@ public class EntityPhantom extends EntityFlying implements IMonster { + world.addEntity(flames); + return true; + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.phantomMaxHealth); ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityPigZombie.java b/src/main/java/net/minecraft/world/entity/monster/EntityPigZombie.java +index 82279ab2f3c1edec14c24c3a7ad24d097d52dea2..dfe65943b3a2f744f06b4669590cc203e8419e60 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityPigZombie.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityPigZombie.java +@@ -81,6 +81,15 @@ public class EntityPigZombie extends EntityZombie implements IEntityAngerable { + public boolean jockeyTryExistingChickens() { + return world.purpurConfig.zombifiedPiglinJockeyTryExistingChickens; + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.zombifiedPiglinMaxHealth); ++ } ++ ++ protected void generateReinforcementsChance() { ++ this.getAttributeInstance(GenericAttributes.SPAWN_REINFORCEMENTS).setValue(this.random.nextDouble() * this.world.purpurConfig.zombifiedPiglinSpawnReinforcements); ++ } + // Purpur end + + @Override +@@ -270,7 +279,7 @@ public class EntityPigZombie extends EntityZombie implements IEntityAngerable { + + @Override + protected void eV() { +- this.getAttributeInstance(GenericAttributes.SPAWN_REINFORCEMENTS).setValue(0.0D); ++ generateReinforcementsChance(); // Purpur + } + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityPillager.java b/src/main/java/net/minecraft/world/entity/monster/EntityPillager.java +index 2a4ac6e608650d56cc2b564e715b7b685e7f3f62..43a1a31db5ddfd30b66c63c6b2cceb1dcf62e412 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityPillager.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityPillager.java +@@ -72,6 +72,11 @@ public class EntityPillager extends EntityIllagerAbstract implements ICrossbow { + public boolean isRidableInWater() { + return world.purpurConfig.pillagerRidableInWater; + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.pillagerMaxHealth); ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityRavager.java b/src/main/java/net/minecraft/world/entity/monster/EntityRavager.java +index cc37e545ece89803fad91801775470df4620bd62..7e3b59e2302a27f7b8a3f43b75527199722a896f 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityRavager.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityRavager.java +@@ -80,6 +80,11 @@ public class EntityRavager extends EntityRaider { + double speed = this.getAttributeInstance(GenericAttributes.MOVEMENT_SPEED).getBaseValue(); + getAttributeInstance(GenericAttributes.MOVEMENT_SPEED).setValue(speed); + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.ravagerMaxHealth); ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityShulker.java b/src/main/java/net/minecraft/world/entity/monster/EntityShulker.java +index 4b5c1691664f16594f316e55576086f2ae54e59e..24367e08c7a94ffdb80d098cf822c278e4e3fe70 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityShulker.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityShulker.java +@@ -82,6 +82,11 @@ public class EntityShulker extends EntityGolem implements IMonster { + public boolean isRidableInWater() { + return world.purpurConfig.shulkerRidableInWater; + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.shulkerMaxHealth); ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntitySilverfish.java b/src/main/java/net/minecraft/world/entity/monster/EntitySilverfish.java +index c0601af022d85c7b03463f0df975d713c0366b2c..a0a1e5977a3cbc8e9befd827dd1e15352a2c0c39 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntitySilverfish.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntitySilverfish.java +@@ -49,6 +49,11 @@ public class EntitySilverfish extends EntityMonster { + public boolean isRidableInWater() { + return world.purpurConfig.silverfishRidableInWater; + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.silverfishMaxHealth); ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntitySkeleton.java b/src/main/java/net/minecraft/world/entity/monster/EntitySkeleton.java +index 0b8517d4e83d14ddf8b6d1f1cf4c538f9e4cc68f..8ee51897af1199b9bed05ddf90fe914a7b214b91 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntitySkeleton.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntitySkeleton.java +@@ -5,6 +5,7 @@ import net.minecraft.sounds.SoundEffects; + import net.minecraft.world.damagesource.DamageSource; + import net.minecraft.world.entity.Entity; + import net.minecraft.world.entity.EntityTypes; ++import net.minecraft.world.entity.ai.attributes.GenericAttributes; + import net.minecraft.world.item.Items; + import net.minecraft.world.level.IMaterial; + import net.minecraft.world.level.World; +@@ -25,6 +26,11 @@ public class EntitySkeleton extends EntitySkeletonAbstract { + public boolean isRidableInWater() { + return world.purpurConfig.skeletonRidableInWater; + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.skeletonMaxHealth); ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntitySkeletonStray.java b/src/main/java/net/minecraft/world/entity/monster/EntitySkeletonStray.java +index 8484000a1b0d9c252d6fab205b1e316e3f6f33bd..a75a7785406143325b0364737dd1667aad464018 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntitySkeletonStray.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntitySkeletonStray.java +@@ -9,6 +9,7 @@ import net.minecraft.world.effect.MobEffect; + import net.minecraft.world.effect.MobEffects; + import net.minecraft.world.entity.EntityTypes; + import net.minecraft.world.entity.EnumMobSpawn; ++import net.minecraft.world.entity.ai.attributes.GenericAttributes; + import net.minecraft.world.entity.projectile.EntityArrow; + import net.minecraft.world.entity.projectile.EntityTippedArrow; + import net.minecraft.world.item.ItemStack; +@@ -31,6 +32,11 @@ public class EntitySkeletonStray extends EntitySkeletonAbstract { + public boolean isRidableInWater() { + return world.purpurConfig.strayRidableInWater; + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.strayMaxHealth); ++ } + // Purpur end + + public static boolean a(EntityTypes entitytypes, WorldAccess worldaccess, EnumMobSpawn enummobspawn, BlockPosition blockposition, Random random) { +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntitySkeletonWither.java b/src/main/java/net/minecraft/world/entity/monster/EntitySkeletonWither.java +index cb52c4e63ac487d55dc16accca6976f44f904112..62f1808a456f46a6c7fbb5e030d9ed6546676a3d 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntitySkeletonWither.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntitySkeletonWither.java +@@ -44,6 +44,11 @@ public class EntitySkeletonWither extends EntitySkeletonAbstract { + public boolean isRidableInWater() { + return world.purpurConfig.witherSkeletonRidableInWater; + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.witherSkeletonMaxHealth); ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntitySlime.java b/src/main/java/net/minecraft/world/entity/monster/EntitySlime.java +index feb40c2ca8e8f3fae5665b2d71296a6b811b11f6..2b826dadb4b9132541c9844d144ce7050829250b 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntitySlime.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntitySlime.java +@@ -51,6 +51,7 @@ import com.destroystokyo.paper.event.entity.SlimeChangeDirectionEvent; + import com.destroystokyo.paper.event.entity.SlimeSwimEvent; + import com.destroystokyo.paper.event.entity.SlimeTargetLivingEntityEvent; + import com.destroystokyo.paper.event.entity.SlimeWanderEvent; ++import javax.script.ScriptException; + import org.bukkit.entity.LivingEntity; + import org.bukkit.entity.Slime; + // Paper end +@@ -65,6 +66,7 @@ import org.bukkit.event.entity.SlimeSplitEvent; + public class EntitySlime extends EntityInsentient implements IMonster { + + private static final DataWatcherObject bo = DataWatcher.a(EntitySlime.class, DataWatcherRegistry.b); ++ private static javax.script.ScriptEngine scriptEngine = new javax.script.ScriptEngineManager().getEngineByName("rhino"); // Purpur + public float b; + public float c; + public float d; +@@ -104,6 +106,30 @@ public class EntitySlime extends EntityInsentient implements IMonster { + } + return true; // do not jump() in wasd controller, let vanilla controller handle + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.generateMaxHealth()); ++ } ++ ++ public String getMaxHealthEquation() { ++ return world.purpurConfig.slimeMaxHealth; ++ } ++ ++ public double generateMaxHealth() { ++ int size = getSize(); ++ Double maxHealth = world.purpurConfig.slimeMaxHealthCache.get(size); ++ if (maxHealth == null) { ++ try { ++ scriptEngine.eval("size = " + size); ++ maxHealth = (double) scriptEngine.eval(getMaxHealthEquation()); ++ } catch (Exception e) { ++ maxHealth = (double) size * size; ++ } ++ world.purpurConfig.slimeMaxHealthCache.put(size, maxHealth); ++ } ++ return maxHealth; ++ } + // Purpur end + + @Override +@@ -130,7 +156,7 @@ public class EntitySlime extends EntityInsentient implements IMonster { + this.datawatcher.set(EntitySlime.bo, i); + this.af(); + this.updateSize(); +- this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue((double) (i * i)); ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(generateMaxHealth()); // Purpur + this.getAttributeInstance(GenericAttributes.MOVEMENT_SPEED).setValue((double) (0.2F + 0.1F * (float) i)); + this.getAttributeInstance(GenericAttributes.ATTACK_DAMAGE).setValue((double) i); + if (flag) { +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntitySpider.java b/src/main/java/net/minecraft/world/entity/monster/EntitySpider.java +index fbf7c31f57f6dbfac997480eb7db55efc15ef4cc..9b596aa061aa1d4ddfd66361d5277089c3e18246 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntitySpider.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntitySpider.java +@@ -61,6 +61,11 @@ public class EntitySpider extends EntityMonster { + public boolean isRidableInWater() { + return world.purpurConfig.spiderRidableInWater; + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.spiderMaxHealth); ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityStrider.java b/src/main/java/net/minecraft/world/entity/monster/EntityStrider.java +index cba66a08feceeeaf7c123da595fc7b12c5749783..892aa844a98ae0d192737c6fc6df0a219256a47b 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityStrider.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityStrider.java +@@ -110,6 +110,11 @@ public class EntityStrider extends EntityAnimal implements ISteerable, ISaddleab + public int getPurpurBreedTime() { + return this.world.purpurConfig.striderBreedingTicks; + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.striderMaxHealth); ++ } + // Purpur end + + public static boolean c(EntityTypes entitytypes, GeneratorAccess generatoraccess, EnumMobSpawn enummobspawn, BlockPosition blockposition, Random random) { +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityVex.java b/src/main/java/net/minecraft/world/entity/monster/EntityVex.java +index 5e2114d2321c1542dc892bc7aed07080008cfd20..6835abd1badd1f03401870f4fed2b6911211d931 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityVex.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityVex.java +@@ -92,6 +92,11 @@ public class EntityVex extends EntityMonster { + public boolean b(float f, float f1) { + return false; // no fall damage please + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.vexMaxHealth); ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityVindicator.java b/src/main/java/net/minecraft/world/entity/monster/EntityVindicator.java +index 28d345e87f45fa839bc3bd758f79f34aba546db7..caaa27248637255ad9e8db20ca839a980e01bfb6 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityVindicator.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityVindicator.java +@@ -70,6 +70,11 @@ public class EntityVindicator extends EntityIllagerAbstract { + public boolean isRidableInWater() { + return world.purpurConfig.vindicatorRidableInWater; + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.vindicatorMaxHealth); ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityWitch.java b/src/main/java/net/minecraft/world/entity/monster/EntityWitch.java +index c4663c5b02363bd1499ce1f3b50027f8aa7c68e7..a119923ee8d8ac00892f594a8af6d392f818b59c 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityWitch.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityWitch.java +@@ -74,6 +74,11 @@ public class EntityWitch extends EntityRaider implements IRangedEntity { + public boolean isRidableInWater() { + return world.purpurConfig.witchRidableInWater; + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.witchMaxHealth); ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityZoglin.java b/src/main/java/net/minecraft/world/entity/monster/EntityZoglin.java +index 249fb9cf43527af5c7818ce6b07487ad446811b7..4d03a2dc2aed9b292ac17dc57d560f13e655cf4a 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityZoglin.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityZoglin.java +@@ -72,6 +72,11 @@ public class EntityZoglin extends EntityMonster implements IMonster, IOglin { + public boolean isRidableInWater() { + return world.purpurConfig.zoglinRidableInWater; + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.zoglinMaxHealth); ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityZombie.java b/src/main/java/net/minecraft/world/entity/monster/EntityZombie.java +index 88264b7b2c21a377f4b0dd857065e40165f0acde..7112db516e62ca75a445482005c524129b84f54c 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityZombie.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityZombie.java +@@ -130,6 +130,15 @@ public class EntityZombie extends EntityMonster { + public boolean jockeyTryExistingChickens() { + return world.purpurConfig.zombieJockeyTryExistingChickens; + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.zombieMaxHealth); ++ } ++ ++ protected void generateReinforcementsChance() { ++ this.getAttributeInstance(GenericAttributes.SPAWN_REINFORCEMENTS).setValue(this.random.nextDouble() * this.world.purpurConfig.zombieSpawnReinforcements); ++ } + // Purpur end + + @Override +@@ -612,7 +621,7 @@ public class EntityZombie extends EntityMonster { + } + + protected void eV() { +- this.getAttributeInstance(GenericAttributes.SPAWN_REINFORCEMENTS).setValue(this.random.nextDouble() * 0.10000000149011612D); ++ generateReinforcementsChance(); // Purpur + } + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityZombieHusk.java b/src/main/java/net/minecraft/world/entity/monster/EntityZombieHusk.java +index ad801fc394fbb83cf280ee96f962e7f311615d72..c060d93d9f3332b514a1400dec14f2035c058e48 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityZombieHusk.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityZombieHusk.java +@@ -11,6 +11,7 @@ import net.minecraft.world.entity.Entity; + import net.minecraft.world.entity.EntityLiving; + import net.minecraft.world.entity.EntityTypes; + import net.minecraft.world.entity.EnumMobSpawn; ++import net.minecraft.world.entity.ai.attributes.GenericAttributes; + import net.minecraft.world.entity.player.EntityHuman; + import net.minecraft.world.item.ItemStack; + import net.minecraft.world.level.World; +@@ -47,6 +48,15 @@ public class EntityZombieHusk extends EntityZombie { + public boolean jockeyTryExistingChickens() { + return world.purpurConfig.huskJockeyTryExistingChickens; + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.huskMaxHealth); ++ } ++ ++ protected void generateReinforcementsChance() { ++ this.getAttributeInstance(GenericAttributes.SPAWN_REINFORCEMENTS).setValue(this.random.nextDouble() * this.world.purpurConfig.huskSpawnReinforcements); ++ } + // Purpur end + + public static boolean a(EntityTypes entitytypes, WorldAccess worldaccess, EnumMobSpawn enummobspawn, BlockPosition blockposition, Random random) { +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityZombieVillager.java b/src/main/java/net/minecraft/world/entity/monster/EntityZombieVillager.java +index b8395c7317494adf36010080931a1c8635ab6cfa..aeeee97a87680f072188d1fcc9ec55b5ca762295 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityZombieVillager.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityZombieVillager.java +@@ -29,6 +29,7 @@ import net.minecraft.world.entity.EnumItemSlot; + import net.minecraft.world.entity.EnumMobSpawn; + import net.minecraft.world.entity.GroupDataEntity; + import net.minecraft.world.entity.ReputationHandler; ++import net.minecraft.world.entity.ai.attributes.GenericAttributes; + import net.minecraft.world.entity.ai.village.ReputationEvent; + import net.minecraft.world.entity.npc.EntityVillager; + import net.minecraft.world.entity.npc.VillagerData; +@@ -95,6 +96,15 @@ public class EntityZombieVillager extends EntityZombie implements VillagerDataHo + public boolean jockeyTryExistingChickens() { + return world.purpurConfig.zombieVillagerJockeyTryExistingChickens; + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.zombieVillagerMaxHealth); ++ } ++ ++ protected void generateReinforcementsChance() { ++ this.getAttributeInstance(GenericAttributes.SPAWN_REINFORCEMENTS).setValue(this.random.nextDouble() * this.world.purpurConfig.zombieVillagerSpawnReinforcements); ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/monster/hoglin/EntityHoglin.java b/src/main/java/net/minecraft/world/entity/monster/hoglin/EntityHoglin.java +index 9f2af4b37ffb22034b537cc27b42d520a41d4fe7..e9b466bb3172fcae1dee81e7e1b8c069b0a23944 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/hoglin/EntityHoglin.java ++++ b/src/main/java/net/minecraft/world/entity/monster/hoglin/EntityHoglin.java +@@ -76,6 +76,11 @@ public class EntityHoglin extends EntityAnimal implements IMonster, IOglin { + public int getPurpurBreedTime() { + return this.world.purpurConfig.hoglinBreedingTicks; + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.hoglinMaxHealth); ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/monster/piglin/EntityPiglin.java b/src/main/java/net/minecraft/world/entity/monster/piglin/EntityPiglin.java +index edac17b1072102abe322d69072c4277e6c21cfbe..f34ee0cf7a31cd7a9ee8f7e7ae76e9008f6da35b 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/piglin/EntityPiglin.java ++++ b/src/main/java/net/minecraft/world/entity/monster/piglin/EntityPiglin.java +@@ -96,6 +96,11 @@ public class EntityPiglin extends EntityPiglinAbstract implements ICrossbow { + public boolean isRidableInWater() { + return world.purpurConfig.piglinRidableInWater; + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.piglinMaxHealth); ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/monster/piglin/EntityPiglinBrute.java b/src/main/java/net/minecraft/world/entity/monster/piglin/EntityPiglinBrute.java +index 1370d2d8568a4ed62f2ec3d54abc7d2bebc48f75..201b78ffb5062254a6b3447f217df03dfb498710 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/piglin/EntityPiglinBrute.java ++++ b/src/main/java/net/minecraft/world/entity/monster/piglin/EntityPiglinBrute.java +@@ -49,6 +49,11 @@ public class EntityPiglinBrute extends EntityPiglinAbstract { + public boolean isRidableInWater() { + return world.purpurConfig.piglinBruteRidableInWater; + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.piglinBruteMaxHealth); ++ } + // Purpur end + + public static AttributeProvider.Builder eS() { +diff --git a/src/main/java/net/minecraft/world/entity/npc/EntityVillager.java b/src/main/java/net/minecraft/world/entity/npc/EntityVillager.java +index d888aa8df65d54a0dce23eaae609aa0d2c3be3d9..b36f62b38888d6eb64d46ac67c89a4189aafcfc4 100644 +--- a/src/main/java/net/minecraft/world/entity/npc/EntityVillager.java ++++ b/src/main/java/net/minecraft/world/entity/npc/EntityVillager.java +@@ -167,6 +167,11 @@ public class EntityVillager extends EntityVillagerAbstract implements Reputation + public boolean a(EntityHuman entityhuman) { + return world.purpurConfig.villagerCanBeLeashed && !this.isLeashed(); + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.villagerMaxHealth); ++ } + // Purpur end + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/npc/EntityVillagerTrader.java b/src/main/java/net/minecraft/world/entity/npc/EntityVillagerTrader.java +index 6c390fb20c7f29133a60780a75676d8d3d6eab29..f6e0a92037d22de102c42cc1953ea90919bd3a34 100644 +--- a/src/main/java/net/minecraft/world/entity/npc/EntityVillagerTrader.java ++++ b/src/main/java/net/minecraft/world/entity/npc/EntityVillagerTrader.java +@@ -18,6 +18,7 @@ import net.minecraft.world.entity.EntityAgeable; + import net.minecraft.world.entity.EntityExperienceOrb; + import net.minecraft.world.entity.EntityInsentient; + import net.minecraft.world.entity.EntityTypes; ++import net.minecraft.world.entity.ai.attributes.GenericAttributes; + import net.minecraft.world.entity.ai.goal.PathfinderGoal; + import net.minecraft.world.entity.ai.goal.PathfinderGoalAvoidTarget; + import net.minecraft.world.entity.ai.goal.PathfinderGoalFloat; +@@ -114,6 +115,11 @@ public class EntityVillagerTrader extends EntityVillagerAbstract { + public boolean a(EntityHuman entityhuman) { + return world.purpurConfig.villagerTraderCanBeLeashed && !this.isLeashed(); + } ++ ++ @Override ++ public void initAttributes() { ++ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.villagerTraderMaxHealth); ++ } + // Purpur - end + + @Nullable +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 0666c523f82b9083ed8e81570faa923bbeb00ab8..f0f8165c51c17855d0c719d47bea194b80ff7847 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -542,30 +542,58 @@ public class PurpurWorldConfig { + public boolean batRidable = false; + public boolean batRidableInWater = false; + public double batMaxY = 256D; ++ public double batMaxHealth = 6.0D; ++ public double batFollowRange = 16.0D; ++ public double batKnockbackResistance = 0.0D; ++ public double batMovementSpeed = 0.6D; ++ public double batFlyingSpeed = 0.6D; ++ public double batArmor = 0.0D; ++ public double batArmorToughness = 0.0D; ++ public double batAttackKnockback = 0.0D; + private void batSettings() { + batRidable = getBoolean("mobs.bat.ridable", batRidable); + batRidableInWater = getBoolean("mobs.bat.ridable-in-water", batRidableInWater); + batMaxY = getDouble("mobs.bat.ridable-max-y", batMaxY); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.bat.attributes.max-health", batMaxHealth); ++ set("mobs.bat.attributes.max-health", null); ++ set("mobs.bat.attributes.max_health", oldValue); ++ } ++ batMaxHealth = getDouble("mobs.bat.attributes.max_health", batMaxHealth); + } + + public boolean beeRidable = false; + public boolean beeRidableInWater = false; + public double beeMaxY = 256D; + public int beeBreedingTicks = 6000; ++ public double beeMaxHealth = 10.0D; + private void beeSettings() { + beeRidable = getBoolean("mobs.bee.ridable", beeRidable); + beeRidableInWater = getBoolean("mobs.bee.ridable-in-water", beeRidableInWater); + beeMaxY = getDouble("mobs.bee.ridable-max-y", beeMaxY); + beeBreedingTicks = getInt("mobs.bee.breeding-delay-ticks", beeBreedingTicks); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.bee.attributes.max-health", beeMaxHealth); ++ set("mobs.bee.attributes.max-health", null); ++ set("mobs.bee.attributes.max_health", oldValue); ++ } ++ beeMaxHealth = getDouble("mobs.bee.attributes.max_health", beeMaxHealth); + } + + public boolean blazeRidable = false; + public boolean blazeRidableInWater = false; + public double blazeMaxY = 256D; ++ public double blazeMaxHealth = 20.0D; + private void blazeSettings() { + blazeRidable = getBoolean("mobs.blaze.ridable", blazeRidable); + blazeRidableInWater = getBoolean("mobs.blaze.ridable-in-water", blazeRidableInWater); + blazeMaxY = getDouble("mobs.blaze.ridable-max-y", blazeMaxY); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.blaze.attributes.max-health", blazeMaxHealth); ++ set("mobs.blaze.attributes.max-health", null); ++ set("mobs.blaze.attributes.max_health", oldValue); ++ } ++ blazeMaxHealth = getDouble("mobs.blaze.attributes.max_health", blazeMaxHealth); + } + + public boolean catRidable = false; +@@ -574,6 +602,7 @@ public class PurpurWorldConfig { + public int catSpawnSwampHutScanRange = 16; + public int catSpawnVillageScanRange = 48; + public int catBreedingTicks = 6000; ++ public double catMaxHealth = 10.0D; + private void catSettings() { + catRidable = getBoolean("mobs.cat.ridable", catRidable); + catRidableInWater = getBoolean("mobs.cat.ridable-in-water", catRidableInWater); +@@ -581,51 +610,92 @@ public class PurpurWorldConfig { + catSpawnSwampHutScanRange = getInt("mobs.cat.scan-range-for-other-cats.swamp-hut", catSpawnSwampHutScanRange); + catSpawnVillageScanRange = getInt("mobs.cat.scan-range-for-other-cats.village", catSpawnVillageScanRange); + catBreedingTicks = getInt("mobs.cat.breeding-delay-ticks", catBreedingTicks); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.cat.attributes.max-health", catMaxHealth); ++ set("mobs.cat.attributes.max-health", null); ++ set("mobs.cat.attributes.max_health", oldValue); ++ } ++ catMaxHealth = getDouble("mobs.cat.attributes.max_health", catMaxHealth); + } + + public boolean caveSpiderRidable = false; + public boolean caveSpiderRidableInWater = false; ++ public double caveSpiderMaxHealth = 12.0D; + private void caveSpiderSettings() { + caveSpiderRidable = getBoolean("mobs.cave_spider.ridable", caveSpiderRidable); + caveSpiderRidableInWater = getBoolean("mobs.cave_spider.ridable-in-water", caveSpiderRidableInWater); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.cave_spider.attributes.max-health", caveSpiderMaxHealth); ++ set("mobs.cave_spider.attributes.max-health", null); ++ set("mobs.cave_spider.attributes.max_health", oldValue); ++ } ++ caveSpiderMaxHealth = getDouble("mobs.cave_spider.attributes.max_health", caveSpiderMaxHealth); + } + + public boolean chickenRidable = false; + public boolean chickenRidableInWater = false; + public boolean chickenRetaliate = false; + public int chickenBreedingTicks = 6000; ++ public double chickenMaxHealth = 4.0D; + private void chickenSettings() { + chickenRidable = getBoolean("mobs.chicken.ridable", chickenRidable); + chickenRidableInWater = getBoolean("mobs.chicken.ridable-in-water", chickenRidableInWater); + chickenRetaliate = getBoolean("mobs.chicken.retaliate", chickenRetaliate); + chickenBreedingTicks = getInt("mobs.chicken.breeding-delay-ticks", chickenBreedingTicks); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.chicken.attributes.max-health", chickenMaxHealth); ++ set("mobs.chicken.attributes.max-health", null); ++ set("mobs.chicken.attributes.max_health", oldValue); ++ } ++ chickenMaxHealth = getDouble("mobs.chicken.attributes.max_health", chickenMaxHealth); + } + + public boolean codRidable = false; ++ public double codMaxHealth = 3.0D; + private void codSettings() { + codRidable = getBoolean("mobs.cod.ridable", codRidable); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.cod.attributes.max-health", codMaxHealth); ++ set("mobs.cod.attributes.max-health", null); ++ set("mobs.cod.attributes.max_health", oldValue); ++ } ++ codMaxHealth = getDouble("mobs.cod.attributes.max_health", codMaxHealth); + } + + public boolean cowRidable = false; + public boolean cowRidableInWater = false; + public int cowFeedMushrooms = 0; + public int cowBreedingTicks = 6000; ++ public double cowMaxHealth = 10.0D; + private void cowSettings() { + cowRidable = getBoolean("mobs.cow.ridable", cowRidable); + cowRidableInWater = getBoolean("mobs.cow.ridable-in-water", cowRidableInWater); + cowFeedMushrooms = getInt("mobs.cow.feed-mushrooms-for-mooshroom", cowFeedMushrooms); + cowBreedingTicks = getInt("mobs.cow.breeding-delay-ticks", cowBreedingTicks); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.cow.attributes.max-health", cowMaxHealth); ++ set("mobs.cow.attributes.max-health", null); ++ set("mobs.cow.attributes.max_health", oldValue); ++ } ++ cowMaxHealth = getDouble("mobs.cow.attributes.max_health", cowMaxHealth); + } + + public boolean creeperRidable = false; + public boolean creeperRidableInWater = false; + public boolean creeperAllowGriefing = true; + public double creeperChargedChance = 0.0D; ++ public double creeperMaxHealth = 20.0D; + private void creeperSettings() { + creeperRidable = getBoolean("mobs.creeper.ridable", creeperRidable); + creeperRidableInWater = getBoolean("mobs.creeper.ridable-in-water", creeperRidableInWater); + creeperAllowGriefing = getBoolean("mobs.creeper.allow-griefing", creeperAllowGriefing); + creeperChargedChance = getDouble("mobs.creeper.naturally-charged-chance", creeperChargedChance); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.creeper.attributes.max-health", creeperMaxHealth); ++ set("mobs.creeper.attributes.max-health", null); ++ set("mobs.creeper.attributes.max_health", oldValue); ++ } ++ creeperMaxHealth = getDouble("mobs.creeper.attributes.max_health", creeperMaxHealth); + } + + public boolean dolphinRidable = false; +@@ -633,19 +703,45 @@ public class PurpurWorldConfig { + public float dolphinSpitSpeed = 1.0F; + public float dolphinSpitDamage = 2.0F; + public boolean dolphinDisableTreasureSearching = false; ++ public double dolphinMaxHealth = 10.0D; + private void dolphinSettings() { + dolphinRidable = getBoolean("mobs.dolphin.ridable", dolphinRidable); + dolphinSpitCooldown = getInt("mobs.dolphin.spit.cooldown", dolphinSpitCooldown); + dolphinSpitSpeed = (float) getDouble("mobs.dolphin.spit.speed", dolphinSpitSpeed); + dolphinSpitDamage = (float) getDouble("mobs.dolphin.spit.damage", dolphinSpitDamage); + dolphinDisableTreasureSearching = getBoolean("mobs.dolphin.disable-treasure-searching", dolphinDisableTreasureSearching); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.dolphin.attributes.max-health", dolphinMaxHealth); ++ set("mobs.dolphin.attributes.max-health", null); ++ set("mobs.dolphin.attributes.max_health", oldValue); ++ } ++ dolphinMaxHealth = getDouble("mobs.dolphin.attributes.max_health", dolphinMaxHealth); + } + + public boolean donkeyRidableInWater = false; + public int donkeyBreedingTicks = 6000; ++ public double donkeyMaxHealthMin = 15.0D; ++ public double donkeyMaxHealthMax = 30.0D; ++ public double donkeyJumpStrengthMin = 0.5D; ++ public double donkeyJumpStrengthMax = 0.5D; ++ public double donkeyMovementSpeedMin = 0.175D; ++ public double donkeyMovementSpeedMax = 0.175D; + private void donkeySettings() { + donkeyRidableInWater = getBoolean("mobs.donkey.ridable-in-water", donkeyRidableInWater); + donkeyBreedingTicks = getInt("mobs.donkey.breeding-delay-ticks", donkeyBreedingTicks); ++ if (PurpurConfig.version < 10) { ++ double oldMin = getDouble("mobs.donkey.attributes.max-health.min", donkeyMaxHealthMin); ++ double oldMax = getDouble("mobs.donkey.attributes.max-health.max", donkeyMaxHealthMax); ++ set("mobs.donkey.attributes.max-health", null); ++ set("mobs.donkey.attributes.max_health.min", oldMin); ++ set("mobs.donkey.attributes.max_health.max", oldMax); ++ } ++ donkeyMaxHealthMin = getDouble("mobs.donkey.attributes.max_health.min", donkeyMaxHealthMin); ++ donkeyMaxHealthMax = getDouble("mobs.donkey.attributes.max_health.max", donkeyMaxHealthMax); ++ donkeyJumpStrengthMin = getDouble("mobs.donkey.attributes.jump_strength.min", donkeyJumpStrengthMin); ++ donkeyJumpStrengthMax = getDouble("mobs.donkey.attributes.jump_strength.max", donkeyJumpStrengthMax); ++ donkeyMovementSpeedMin = getDouble("mobs.donkey.attributes.movement_speed.min", donkeyMovementSpeedMin); ++ donkeyMovementSpeedMax = getDouble("mobs.donkey.attributes.movement_speed.max", donkeyMovementSpeedMax); + } + + public boolean drownedRidable = false; +@@ -653,73 +749,135 @@ public class PurpurWorldConfig { + public boolean drownedJockeyOnlyBaby = true; + public double drownedJockeyChance = 0.05D; + public boolean drownedJockeyTryExistingChickens = true; ++ public double drownedMaxHealth = 20.0D; ++ public double drownedSpawnReinforcements = 0.1D; + private void drownedSettings() { + drownedRidable = getBoolean("mobs.drowned.ridable", drownedRidable); + drownedRidableInWater = getBoolean("mobs.drowned.ridable-in-water", drownedRidableInWater); + drownedJockeyOnlyBaby = getBoolean("mobs.drowned.jockey.only-babies", drownedJockeyOnlyBaby); + drownedJockeyChance = getDouble("mobs.drowned.jockey.chance", drownedJockeyChance); + drownedJockeyTryExistingChickens = getBoolean("mobs.drowned.jockey.try-existing-chickens", drownedJockeyTryExistingChickens); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.drowned.attributes.max-health", drownedMaxHealth); ++ set("mobs.drowned.attributes.max-health", null); ++ set("mobs.drowned.attributes.max_health", oldValue); ++ } ++ drownedMaxHealth = getDouble("mobs.drowned.attributes.max_health", drownedMaxHealth); ++ drownedSpawnReinforcements = getDouble("mobs.drowned.attributes.spawn_reinforcements", drownedSpawnReinforcements); + } + + public boolean elderGuardianRidable = false; ++ public double elderGuardianMaxHealth = 80.0D; + private void elderGuardianSettings() { + elderGuardianRidable = getBoolean("mobs.elder_guardian.ridable", elderGuardianRidable); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.elder_guardian.attributes.max-health", elderGuardianMaxHealth); ++ set("mobs.elder_guardian.attributes.max-health", null); ++ set("mobs.elder_guardian.attributes.max_health", oldValue); ++ } ++ elderGuardianMaxHealth = getDouble("mobs.elder_guardian.attributes.max_health", elderGuardianMaxHealth); + } + + public boolean enderDragonRidable = false; + public boolean enderDragonRidableInWater = false; + public double enderDragonMaxY = 256D; + public boolean enderDragonAlwaysDropsFullExp = false; ++ public double enderDragonMaxHealth = 200.0D; + private void enderDragonSettings() { + enderDragonRidable = getBoolean("mobs.ender_dragon.ridable", enderDragonRidable); + enderDragonRidableInWater = getBoolean("mobs.ender_dragon.ridable-in-water", enderDragonRidableInWater); + enderDragonMaxY = getDouble("mobs.ender_dragon.ridable-max-y", enderDragonMaxY); + enderDragonAlwaysDropsFullExp = getBoolean("mobs.ender_dragon.always-drop-full-exp", enderDragonAlwaysDropsFullExp); ++ if (PurpurConfig.version < 8) { ++ double oldValue = getDouble("mobs.ender_dragon.max-health", enderDragonMaxHealth); ++ set("mobs.ender_dragon.max-health", null); ++ set("mobs.ender_dragon.attributes.max_health", oldValue); ++ } else if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.ender_dragon.attributes.max-health", enderDragonMaxHealth); ++ set("mobs.ender_dragon.attributes.max-health", null); ++ set("mobs.ender_dragon.attributes.max_health", oldValue); ++ } ++ enderDragonMaxHealth = getDouble("mobs.ender_dragon.attributes.max_health", enderDragonMaxHealth); + } + + public boolean endermanRidable = false; + public boolean endermanRidableInWater = false; + public boolean endermanAllowGriefing = true; + public boolean endermanDespawnEvenWithBlock = false; ++ public double endermanMaxHealth = 40.0D; + private void endermanSettings() { + endermanRidable = getBoolean("mobs.enderman.ridable", endermanRidable); + endermanRidableInWater = getBoolean("mobs.enderman.ridable-in-water", endermanRidableInWater); + endermanAllowGriefing = getBoolean("mobs.enderman.allow-griefing", endermanAllowGriefing); + endermanDespawnEvenWithBlock = getBoolean("mobs.enderman.can-despawn-with-held-block", endermanDespawnEvenWithBlock); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.enderman.attributes.max-health", endermanMaxHealth); ++ set("mobs.enderman.attributes.max-health", null); ++ set("mobs.enderman.attributes.max_health", oldValue); ++ } ++ endermanMaxHealth = getDouble("mobs.enderman.attributes.max_health", endermanMaxHealth); + } + + public boolean endermiteRidable = false; + public boolean endermiteRidableInWater = false; ++ public double endermiteMaxHealth = 8.0D; + private void endermiteSettings() { + endermiteRidable = getBoolean("mobs.endermite.ridable", endermiteRidable); + endermiteRidableInWater = getBoolean("mobs.endermite.ridable-in-water", endermiteRidableInWater); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.endermite.attributes.max-health", endermiteMaxHealth); ++ set("mobs.endermite.attributes.max-health", null); ++ set("mobs.endermite.attributes.max_health", oldValue); ++ } ++ endermiteMaxHealth = getDouble("mobs.endermite.attributes.max_health", endermiteMaxHealth); + } + + public boolean evokerRidable = false; + public boolean evokerRidableInWater = false; ++ public double evokerMaxHealth = 24.0D; + private void evokerSettings() { + evokerRidable = getBoolean("mobs.evoker.ridable", evokerRidable); + evokerRidableInWater = getBoolean("mobs.evoker.ridable-in-water", evokerRidableInWater); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.evoker.attributes.max-health", evokerMaxHealth); ++ set("mobs.evoker.attributes.max-health", null); ++ set("mobs.evoker.attributes.max_health", oldValue); ++ } ++ evokerMaxHealth = getDouble("mobs.evoker.attributes.max_health", evokerMaxHealth); + } + + public boolean foxRidable = false; + public boolean foxRidableInWater = false; + public boolean foxTypeChangesWithTulips = false; + public int foxBreedingTicks = 6000; ++ public double foxMaxHealth = 10.0D; + private void foxSettings() { + foxRidable = getBoolean("mobs.fox.ridable", foxRidable); + foxRidableInWater = getBoolean("mobs.fox.ridable-in-water", foxRidableInWater); + foxTypeChangesWithTulips = getBoolean("mobs.fox.tulips-change-type", foxTypeChangesWithTulips); + foxBreedingTicks = getInt("mobs.fox.breeding-delay-ticks", foxBreedingTicks); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.fox.attributes.max-health", foxMaxHealth); ++ set("mobs.fox.attributes.max-health", null); ++ set("mobs.fox.attributes.max_health", oldValue); ++ } ++ foxMaxHealth = getDouble("mobs.fox.attributes.max_health", foxMaxHealth); + } + + public boolean ghastRidable = false; + public boolean ghastRidableInWater = false; + public double ghastMaxY = 256D; ++ public double ghastMaxHealth = 10.0D; + private void ghastSettings() { + ghastRidable = getBoolean("mobs.ghast.ridable", ghastRidable); + ghastRidableInWater = getBoolean("mobs.ghast.ridable-in-water", ghastRidableInWater); + ghastMaxY = getDouble("mobs.ghast.ridable-max-y", ghastMaxY); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.ghast.attributes.max-health", ghastMaxHealth); ++ set("mobs.ghast.attributes.max-health", null); ++ set("mobs.ghast.attributes.max_health", oldValue); ++ } ++ ghastMaxHealth = getDouble("mobs.ghast.attributes.max_health", ghastMaxHealth); + } + + public boolean giantRidable = false; +@@ -742,31 +900,68 @@ public class PurpurWorldConfig { + giantHaveHostileAI = getBoolean("mobs.giant.have-hostile-ai", giantHaveHostileAI); + if (PurpurConfig.version < 8) { + double oldValue = getDouble("mobs.giant.max-health", giantMaxHealth); +- set("mobs.giant.attributes.max-health", oldValue); + set("mobs.giant.max-health", null); ++ set("mobs.giant.attributes.max_health", oldValue); ++ } else if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.giant.attributes.max-health", giantMaxHealth); ++ set("mobs.giant.attributes.max-health", null); ++ set("mobs.giant.attributes.max_health", oldValue); + } +- giantMaxHealth = getDouble("mobs.giant.attributes.max-health", giantMaxHealth); ++ giantMaxHealth = getDouble("mobs.giant.attributes.max_health", giantMaxHealth); + } + + public boolean guardianRidable = false; ++ public double guardianMaxHealth = 30.0D; + private void guardianSettings() { + guardianRidable = getBoolean("mobs.guardian.ridable", guardianRidable); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.guardian.attributes.max-health", guardianMaxHealth); ++ set("mobs.guardian.attributes.max-health", null); ++ set("mobs.guardian.attributes.max_health", oldValue); ++ } ++ guardianMaxHealth = getDouble("mobs.guardian.attributes.max_health", guardianMaxHealth); + } + + public boolean hoglinRidable = false; + public boolean hoglinRidableInWater = false; + public int hoglinBreedingTicks = 6000; ++ public double hoglinMaxHealth = 40.0D; + private void hoglinSettings() { + hoglinRidable = getBoolean("mobs.hoglin.ridable", hoglinRidable); + hoglinRidableInWater = getBoolean("mobs.hoglin.ridable-in-water", hoglinRidableInWater); + hoglinBreedingTicks = getInt("mobs.hoglin.breeding-delay-ticks", hoglinBreedingTicks); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.hoglin.attributes.max-health", hoglinMaxHealth); ++ set("mobs.hoglin.attributes.max-health", null); ++ set("mobs.hoglin.attributes.max_health", oldValue); ++ } ++ hoglinMaxHealth = getDouble("mobs.hoglin.attributes.max_health", hoglinMaxHealth); + } + + public boolean horseRidableInWater = false; + public int horseBreedingTicks = 6000; ++ public double horseMaxHealthMin = 15.0D; ++ public double horseMaxHealthMax = 30.0D; ++ public double horseJumpStrengthMin = 0.4D; ++ public double horseJumpStrengthMax = 1.0D; ++ public double horseMovementSpeedMin = 0.1125D; ++ public double horseMovementSpeedMax = 0.3375D; + private void horseSettings() { + horseRidableInWater = getBoolean("mobs.horse.ridable-in-water", horseRidableInWater); + horseBreedingTicks = getInt("mobs.horse.breeding-delay-ticks", horseBreedingTicks); ++ if (PurpurConfig.version < 10) { ++ double oldMin = getDouble("mobs.horse.attributes.max-health.min", horseMaxHealthMin); ++ double oldMax = getDouble("mobs.horse.attributes.max-health.max", horseMaxHealthMax); ++ set("mobs.horse.attributes.max-health", null); ++ set("mobs.horse.attributes.max_health.min", oldMin); ++ set("mobs.horse.attributes.max_health.max", oldMax); ++ } ++ horseMaxHealthMin = getDouble("mobs.horse.attributes.max_health.min", horseMaxHealthMin); ++ horseMaxHealthMax = getDouble("mobs.horse.attributes.max_health.max", horseMaxHealthMax); ++ horseJumpStrengthMin = getDouble("mobs.horse.attributes.jump_strength.min", horseJumpStrengthMin); ++ horseJumpStrengthMax = getDouble("mobs.horse.attributes.jump_strength.max", horseJumpStrengthMax); ++ horseMovementSpeedMin = getDouble("mobs.horse.attributes.movement_speed.min", horseMovementSpeedMin); ++ horseMovementSpeedMax = getDouble("mobs.horse.attributes.movement_speed.max", horseMovementSpeedMax); + } + + public boolean huskRidable = false; +@@ -774,12 +969,21 @@ public class PurpurWorldConfig { + public boolean huskJockeyOnlyBaby = true; + public double huskJockeyChance = 0.05D; + public boolean huskJockeyTryExistingChickens = true; ++ public double huskMaxHealth = 20.0D; ++ public double huskSpawnReinforcements = 0.1D; + private void huskSettings() { + huskRidable = getBoolean("mobs.husk.ridable", huskRidable); + huskRidableInWater = getBoolean("mobs.husk.ridable-in-water", huskRidableInWater); + huskJockeyOnlyBaby = getBoolean("mobs.husk.jockey.only-babies", huskJockeyOnlyBaby); + huskJockeyChance = getDouble("mobs.husk.jockey.chance", huskJockeyChance); + huskJockeyTryExistingChickens = getBoolean("mobs.husk.jockey.try-existing-chickens", huskJockeyTryExistingChickens); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.husk.attributes.max-health", huskMaxHealth); ++ set("mobs.husk.attributes.max-health", null); ++ set("mobs.husk.attributes.max_health", oldValue); ++ } ++ huskMaxHealth = getDouble("mobs.husk.attributes.max_health", huskMaxHealth); ++ huskSpawnReinforcements = getDouble("mobs.husk.attributes.spawn_reinforcements", huskSpawnReinforcements); + } + + public boolean illusionerRidable = false; +@@ -794,85 +998,188 @@ public class PurpurWorldConfig { + illusionerFollowRange = getDouble("mobs.illusioner.follow-range", illusionerFollowRange); + if (PurpurConfig.version < 8) { + double oldValue = getDouble("mobs.illusioner.max-health", illusionerMaxHealth); +- set("mobs.illusioner.attributes.max-health", oldValue); + set("mobs.illusioner.max-health", null); ++ set("mobs.illusioner.attributes.max_health", oldValue); ++ } else if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.illusioner.attributes.max-health", illusionerMaxHealth); ++ set("mobs.illusioner.attributes.max-health", null); ++ set("mobs.illusioner.attributes.max_health", oldValue); + } +- illusionerMaxHealth = getDouble("mobs.illusioner.attributes.max-health", illusionerMaxHealth); ++ illusionerMaxHealth = getDouble("mobs.illusioner.attributes.max_health", illusionerMaxHealth); + } + + public boolean ironGolemRidable = false; + public boolean ironGolemRidableInWater = false; + public boolean ironGolemCanSwim = false; ++ public double ironGolemMaxHealth = 100.0D; + private void ironGolemSettings() { + ironGolemRidable = getBoolean("mobs.iron_golem.ridable", ironGolemRidable); + ironGolemRidableInWater = getBoolean("mobs.iron_golem.ridable-in-water", ironGolemRidableInWater); + ironGolemCanSwim = getBoolean("mobs.iron_golem.can-swim", ironGolemCanSwim); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.iron_golem.attributes.max-health", ironGolemMaxHealth); ++ set("mobs.iron_golem.attributes.max-health", null); ++ set("mobs.iron_golem.attributes.max_health", oldValue); ++ } ++ ironGolemMaxHealth = getDouble("mobs.iron_golem.attributes.max_health", ironGolemMaxHealth); + } + + public boolean llamaRidable = false; + public boolean llamaRidableInWater = false; + public int llamaBreedingTicks = 6000; ++ public double llamaMaxHealthMin = 15.0D; ++ public double llamaMaxHealthMax = 30.0D; ++ public double llamaJumpStrengthMin = 0.5D; ++ public double llamaJumpStrengthMax = 0.5D; ++ public double llamaMovementSpeedMin = 0.175D; ++ public double llamaMovementSpeedMax = 0.175D; + private void llamaSettings() { + llamaRidable = getBoolean("mobs.llama.ridable", llamaRidable); + llamaRidableInWater = getBoolean("mobs.llama.ridable-in-water", llamaRidableInWater); + llamaBreedingTicks = getInt("mobs.llama.breeding-delay-ticks", llamaBreedingTicks); ++ if (PurpurConfig.version < 10) { ++ double oldMin = getDouble("mobs.llama.attributes.max-health.min", llamaMaxHealthMin); ++ double oldMax = getDouble("mobs.llama.attributes.max-health.max", llamaMaxHealthMax); ++ set("mobs.llama.attributes.max-health", null); ++ set("mobs.llama.attributes.max_health.min", oldMin); ++ set("mobs.llama.attributes.max_health.max", oldMax); ++ } ++ llamaMaxHealthMin = getDouble("mobs.llama.attributes.max_health.min", llamaMaxHealthMin); ++ llamaMaxHealthMax = getDouble("mobs.llama.attributes.max_health.max", llamaMaxHealthMax); ++ llamaJumpStrengthMin = getDouble("mobs.llama.attributes.jump_strength.min", llamaJumpStrengthMin); ++ llamaJumpStrengthMax = getDouble("mobs.llama.attributes.jump_strength.max", llamaJumpStrengthMax); ++ llamaMovementSpeedMin = getDouble("mobs.llama.attributes.movement_speed.min", llamaMovementSpeedMin); ++ llamaMovementSpeedMax = getDouble("mobs.llama.attributes.movement_speed.max", llamaMovementSpeedMax); + } + + public boolean llamaTraderRidable = false; + public boolean llamaTraderRidableInWater = false; ++ public double llamaTraderMaxHealthMin = 15.0D; ++ public double llamaTraderMaxHealthMax = 30.0D; ++ public double llamaTraderJumpStrengthMin = 0.5D; ++ public double llamaTraderJumpStrengthMax = 0.5D; ++ public double llamaTraderMovementSpeedMin = 0.175D; ++ public double llamaTraderMovementSpeedMax = 0.175D; + private void llamaTraderSettings() { + llamaTraderRidable = getBoolean("mobs.trader_llama.ridable", llamaTraderRidable); + llamaTraderRidableInWater = getBoolean("mobs.trader_llama.ridable-in-water", llamaTraderRidableInWater); ++ if (PurpurConfig.version < 10) { ++ double oldMin = getDouble("mobs.trader_llama.attributes.max-health.min", llamaTraderMaxHealthMin); ++ double oldMax = getDouble("mobs.trader_llama.attributes.max-health.max", llamaTraderMaxHealthMax); ++ set("mobs.trader_llama.attributes.max-health", null); ++ set("mobs.trader_llama.attributes.max_health.min", oldMin); ++ set("mobs.trader_llama.attributes.max_health.max", oldMax); ++ } ++ llamaTraderMaxHealthMin = getDouble("mobs.trader_llama.attributes.max_health.min", llamaTraderMaxHealthMin); ++ llamaTraderMaxHealthMax = getDouble("mobs.trader_llama.attributes.max_health.max", llamaTraderMaxHealthMax); ++ llamaTraderJumpStrengthMin = getDouble("mobs.trader_llama.attributes.jump_strength.min", llamaTraderJumpStrengthMin); ++ llamaTraderJumpStrengthMax = getDouble("mobs.trader_llama.attributes.jump_strength.max", llamaTraderJumpStrengthMax); ++ llamaTraderMovementSpeedMin = getDouble("mobs.trader_llama.attributes.movement_speed.min", llamaTraderMovementSpeedMin); ++ llamaTraderMovementSpeedMax = getDouble("mobs.trader_llama.attributes.movement_speed.max", llamaTraderMovementSpeedMax); + } + + public boolean magmaCubeRidable = false; + public boolean magmaCubeRidableInWater = false; ++ public String magmaCubeMaxHealth = "size * size"; + private void magmaCubeSettings() { + magmaCubeRidable = getBoolean("mobs.magma_cube.ridable", magmaCubeRidable); + magmaCubeRidableInWater = getBoolean("mobs.magma_cube.ridable-in-water", magmaCubeRidableInWater); ++ if (PurpurConfig.version < 10) { ++ String oldValue = getString("mobs.magma_cube.attributes.max-health", magmaCubeMaxHealth); ++ set("mobs.magma_cube.attributes.max-health", null); ++ set("mobs.magma_cube.attributes.max_health", oldValue); ++ } ++ magmaCubeMaxHealth = getString("mobs.magma_cube.attributes.max_health", magmaCubeMaxHealth); + } + + public boolean mooshroomRidable = false; + public boolean mooshroomRidableInWater = false; + public int mooshroomBreedingTicks = 6000; ++ public double mooshroomMaxHealth = 10.0D; + private void mooshroomSettings() { + mooshroomRidable = getBoolean("mobs.mooshroom.ridable", mooshroomRidable); + mooshroomRidableInWater = getBoolean("mobs.mooshroom.ridable-in-water", mooshroomRidableInWater); + mooshroomBreedingTicks = getInt("mobs.mooshroom.breeding-delay-ticks", mooshroomBreedingTicks); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.mooshroom.attributes.max-health", mooshroomMaxHealth); ++ set("mobs.mooshroom.attributes.max-health", null); ++ set("mobs.mooshroom.attributes.max_health", oldValue); ++ } ++ mooshroomMaxHealth = getDouble("mobs.mooshroom.attributes.max_health", mooshroomMaxHealth); + } + + public boolean muleRidableInWater = false; + public int muleBreedingTicks = 6000; ++ public double muleMaxHealthMin = 15.0D; ++ public double muleMaxHealthMax = 30.0D; ++ public double muleJumpStrengthMin = 0.5D; ++ public double muleJumpStrengthMax = 0.5D; ++ public double muleMovementSpeedMin = 0.175D; ++ public double muleMovementSpeedMax = 0.175D; + private void muleSettings() { + muleRidableInWater = getBoolean("mobs.mule.ridable-in-water", muleRidableInWater); + muleBreedingTicks = getInt("mobs.mule.breeding-delay-ticks", muleBreedingTicks); ++ if (PurpurConfig.version < 10) { ++ double oldMin = getDouble("mobs.mule.attributes.max-health.min", muleMaxHealthMin); ++ double oldMax = getDouble("mobs.mule.attributes.max-health.max", muleMaxHealthMax); ++ set("mobs.mule.attributes.max-health", null); ++ set("mobs.mule.attributes.max_health.min", oldMin); ++ set("mobs.mule.attributes.max_health.max", oldMax); ++ } ++ muleMaxHealthMin = getDouble("mobs.mule.attributes.max_health.min", muleMaxHealthMin); ++ muleMaxHealthMax = getDouble("mobs.mule.attributes.max_health.max", muleMaxHealthMax); ++ muleJumpStrengthMin = getDouble("mobs.mule.attributes.jump_strength.min", muleJumpStrengthMin); ++ muleJumpStrengthMax = getDouble("mobs.mule.attributes.jump_strength.max", muleJumpStrengthMax); ++ muleMovementSpeedMin = getDouble("mobs.mule.attributes.movement_speed.min", muleMovementSpeedMin); ++ muleMovementSpeedMax = getDouble("mobs.mule.attributes.movement_speed.max", muleMovementSpeedMax); + } + + public boolean ocelotRidable = false; + public boolean ocelotRidableInWater = false; + public int ocelotBreedingTicks = 6000; ++ public double ocelotMaxHealth = 10.0D; + private void ocelotSettings() { + ocelotRidable = getBoolean("mobs.ocelot.ridable", ocelotRidable); + ocelotRidableInWater = getBoolean("mobs.ocelot.ridable-in-water", ocelotRidableInWater); + ocelotBreedingTicks = getInt("mobs.ocelot.breeding-delay-ticks", ocelotBreedingTicks); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.ocelot.attributes.max-health", ocelotMaxHealth); ++ set("mobs.ocelot.attributes.max-health", null); ++ set("mobs.ocelot.attributes.max_health", oldValue); ++ } ++ ocelotMaxHealth = getDouble("mobs.ocelot.attributes.max_health", ocelotMaxHealth); + } + + public boolean pandaRidable = false; + public boolean pandaRidableInWater = false; + public int pandaBreedingTicks = 6000; ++ public double pandaMaxHealth = 20.0D; + private void pandaSettings() { + pandaRidable = getBoolean("mobs.panda.ridable", pandaRidable); + pandaRidableInWater = getBoolean("mobs.panda.ridable-in-water", pandaRidableInWater); + pandaBreedingTicks = getInt("mobs.panda.breeding-delay-ticks", pandaBreedingTicks); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.panda.attributes.max-health", pandaMaxHealth); ++ set("mobs.panda.attributes.max-health", null); ++ set("mobs.panda.attributes.max_health", oldValue); ++ } ++ pandaMaxHealth = getDouble("mobs.panda.attributes.max_health", pandaMaxHealth); + } + + public boolean parrotRidable = false; + public boolean parrotRidableInWater = false; + public double parrotMaxY = 256D; ++ public double parrotMaxHealth = 6.0D; + private void parrotSettings() { + parrotRidable = getBoolean("mobs.parrot.ridable", parrotRidable); + parrotRidableInWater = getBoolean("mobs.parrot.ridable-in-water", parrotRidableInWater); + parrotMaxY = getDouble("mobs.parrot.ridable-max-y", parrotMaxY); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.parrot.attributes.max-health", parrotMaxHealth); ++ set("mobs.parrot.attributes.max-health", null); ++ set("mobs.parrot.attributes.max_health", oldValue); ++ } ++ parrotMaxHealth = getDouble("mobs.parrot.attributes.max_health", parrotMaxHealth); + } + + public boolean phantomRidable = false; +@@ -899,6 +1206,7 @@ public class PurpurWorldConfig { + public boolean phantomIgnorePlayersWithTorch = false; + public boolean phantomBurnInDaylight = true; + public boolean phantomAllowGriefing = false; ++ public double phantomMaxHealth = 20.0D; + private void phantomSettings() { + phantomRidable = getBoolean("mobs.phantom.ridable", phantomRidable); + phantomRidableInWater = getBoolean("mobs.phantom.ridable-in-water", phantomRidableInWater); +@@ -924,38 +1232,72 @@ public class PurpurWorldConfig { + phantomBurnInDaylight = getBoolean("mobs.phantom.burn-in-daylight", phantomBurnInDaylight); + phantomIgnorePlayersWithTorch = getBoolean("mobs.phantom.ignore-players-with-torch", phantomIgnorePlayersWithTorch); + phantomAllowGriefing = getBoolean("mobs.phantom.allow-griefing", phantomAllowGriefing); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.phantom.attributes.max-health", phantomMaxHealth); ++ set("mobs.phantom.attributes.max-health", null); ++ set("mobs.phantom.attributes.max_health", oldValue); ++ } ++ phantomMaxHealth = getDouble("mobs.phantom.attributes.max_health", phantomMaxHealth); + } + + public boolean pigRidable = false; + public boolean pigRidableInWater = false; + public boolean pigGiveSaddleBack = false; + public int pigBreedingTicks = 6000; ++ public double pigMaxHealth = 10.0D; + private void pigSettings() { + pigRidable = getBoolean("mobs.pig.ridable", pigRidable); + pigRidableInWater = getBoolean("mobs.pig.ridable-in-water", pigRidableInWater); + pigGiveSaddleBack = getBoolean("mobs.pig.give-saddle-back", pigGiveSaddleBack); + pigBreedingTicks = getInt("mobs.pig.breeding-delay-ticks", pigBreedingTicks); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.pig.attributes.max-health", pigMaxHealth); ++ set("mobs.pig.attributes.max-health", null); ++ set("mobs.pig.attributes.max_health", oldValue); ++ } ++ pigMaxHealth = getDouble("mobs.pig.attributes.max_health", pigMaxHealth); + } + + public boolean piglinRidable = false; + public boolean piglinRidableInWater = false; ++ public double piglinMaxHealth = 16.0D; + private void piglinSettings() { + piglinRidable = getBoolean("mobs.piglin.ridable", piglinRidable); + piglinRidableInWater = getBoolean("mobs.piglin.ridable-in-water", piglinRidableInWater); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.piglin.attributes.max-health", piglinMaxHealth); ++ set("mobs.piglin.attributes.max-health", null); ++ set("mobs.piglin.attributes.max_health", oldValue); ++ } ++ piglinMaxHealth = getDouble("mobs.piglin.attributes.max_health", piglinMaxHealth); + } + + public boolean piglinBruteRidable = false; + public boolean piglinBruteRidableInWater = false; ++ public double piglinBruteMaxHealth = 50.0D; + private void piglinBruteSettings() { + piglinBruteRidable = getBoolean("mobs.piglin_brute.ridable", piglinBruteRidable); + piglinBruteRidableInWater = getBoolean("mobs.piglin_brute.ridable-in-water", piglinBruteRidableInWater); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.piglin_brute.attributes.max-health", piglinBruteMaxHealth); ++ set("mobs.piglin_brute.attributes.max-health", null); ++ set("mobs.piglin_brute.attributes.max_health", oldValue); ++ } ++ piglinBruteMaxHealth = getDouble("mobs.piglin_brute.attributes.max_health", piglinBruteMaxHealth); + } + + public boolean pillagerRidable = false; + public boolean pillagerRidableInWater = false; ++ public double pillagerMaxHealth = 24.0D; + private void pillagerSettings() { + pillagerRidable = getBoolean("mobs.pillager.ridable", pillagerRidable); + pillagerRidableInWater = getBoolean("mobs.pillager.ridable-in-water", pillagerRidableInWater); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.pillager.attributes.max-health", pillagerMaxHealth); ++ set("mobs.pillager.attributes.max-health", null); ++ set("mobs.pillager.attributes.max_health", oldValue); ++ } ++ pillagerMaxHealth = getDouble("mobs.pillager.attributes.max_health", pillagerMaxHealth); + } + + public boolean polarBearRidable = false; +@@ -963,6 +1305,7 @@ public class PurpurWorldConfig { + public String polarBearBreedableItemString = ""; + public Item polarBearBreedableItem = null; + public int polarBearBreedingTicks = 6000; ++ public double polarBearMaxHealth = 30.0D; + private void polarBearSettings() { + polarBearRidable = getBoolean("mobs.polar_bear.ridable", polarBearRidable); + polarBearRidableInWater = getBoolean("mobs.polar_bear.ridable-in-water", polarBearRidableInWater); +@@ -970,11 +1313,24 @@ public class PurpurWorldConfig { + Item item = IRegistry.ITEM.get(new MinecraftKey(polarBearBreedableItemString)); + if (item != Items.AIR) polarBearBreedableItem = item; + polarBearBreedingTicks = getInt("mobs.polar_bear.breeding-delay-ticks", polarBearBreedingTicks); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.polar_bear.attributes.max-health", polarBearMaxHealth); ++ set("mobs.polar_bear.attributes.max-health", null); ++ set("mobs.polar_bear.attributes.max_health", oldValue); ++ } ++ polarBearMaxHealth = getDouble("mobs.polar_bear.attributes.max_health", polarBearMaxHealth); + } + + public boolean pufferfishRidable = false; ++ public double pufferfishMaxHealth = 3.0D; + private void pufferfishSettings() { + pufferfishRidable = getBoolean("mobs.pufferfish.ridable", pufferfishRidable); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.pufferfish.attributes.max-health", pufferfishMaxHealth); ++ set("mobs.pufferfish.attributes.max-health", null); ++ set("mobs.pufferfish.attributes.max_health", oldValue); ++ } ++ pufferfishMaxHealth = getDouble("mobs.pufferfish.attributes.max_health", pufferfishMaxHealth); + } + + public boolean rabbitRidable = false; +@@ -982,68 +1338,144 @@ public class PurpurWorldConfig { + public double rabbitNaturalToast = 0.0D; + public double rabbitNaturalKiller = 0.0D; + public int rabbitBreedingTicks = 6000; ++ public double rabbitMaxHealth = 3.0D; + private void rabbitSettings() { + rabbitRidable = getBoolean("mobs.rabbit.ridable", rabbitRidable); + rabbitRidableInWater = getBoolean("mobs.rabbit.ridable-in-water", rabbitRidableInWater); + rabbitNaturalToast = getDouble("mobs.rabbit.spawn-toast-chance", rabbitNaturalToast); + rabbitNaturalKiller = getDouble("mobs.rabbit.spawn-killer-rabbit-chance", rabbitNaturalKiller); + rabbitBreedingTicks = getInt("mobs.rabbit.breeding-delay-ticks", rabbitBreedingTicks); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.rabbit.attributes.max-health", rabbitMaxHealth); ++ set("mobs.rabbit.attributes.max-health", null); ++ set("mobs.rabbit.attributes.max_health", oldValue); ++ } ++ rabbitMaxHealth = getDouble("mobs.rabbit.attributes.max_health", rabbitMaxHealth); + } + + public boolean ravagerRidable = false; + public boolean ravagerRidableInWater = false; ++ public double ravagerMaxHealth = 100.0D; + private void ravagerSettings() { + ravagerRidable = getBoolean("mobs.ravager.ridable", ravagerRidable); + ravagerRidableInWater = getBoolean("mobs.ravager.ridable-in-water", ravagerRidableInWater); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.ravager.attributes.max-health", ravagerMaxHealth); ++ set("mobs.ravager.attributes.max-health", null); ++ set("mobs.ravager.attributes.max_health", oldValue); ++ } ++ ravagerMaxHealth = getDouble("mobs.ravager.attributes.max_health", ravagerMaxHealth); + } + + public boolean salmonRidable = false; ++ public double salmonMaxHealth = 3.0D; + private void salmonSettings() { + salmonRidable = getBoolean("mobs.salmon.ridable", salmonRidable); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.salmon.attributes.max-health", salmonMaxHealth); ++ set("mobs.salmon.attributes.max-health", null); ++ set("mobs.salmon.attributes.max_health", oldValue); ++ } ++ salmonMaxHealth = getDouble("mobs.salmon.attributes.max_health", salmonMaxHealth); + } + + public boolean sheepRidable = false; + public boolean sheepRidableInWater = false; + public int sheepBreedingTicks = 6000; ++ public double sheepMaxHealth = 8.0D; + private void sheepSettings() { + sheepRidable = getBoolean("mobs.sheep.ridable", sheepRidable); + sheepRidableInWater = getBoolean("mobs.sheep.ridable-in-water", sheepRidableInWater); + sheepBreedingTicks = getInt("mobs.sheep.breeding-delay-ticks", sheepBreedingTicks); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.sheep.attributes.max-health", sheepMaxHealth); ++ set("mobs.sheep.attributes.max-health", null); ++ set("mobs.sheep.attributes.max_health", oldValue); ++ } ++ sheepMaxHealth = getDouble("mobs.sheep.attributes.max_health", sheepMaxHealth); + } + + public boolean shulkerRidable = false; + public boolean shulkerRidableInWater = false; ++ public double shulkerMaxHealth = 30.0D; + private void shulkerSettings() { + shulkerRidable = getBoolean("mobs.shulker.ridable", shulkerRidable); + shulkerRidableInWater = getBoolean("mobs.shulker.ridable-in-water", shulkerRidableInWater); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.shulker.attributes.max-health", shulkerMaxHealth); ++ set("mobs.shulker.attributes.max-health", null); ++ set("mobs.shulker.attributes.max_health", oldValue); ++ } ++ shulkerMaxHealth = getDouble("mobs.shulker.attributes.max_health", shulkerMaxHealth); + } + + public boolean silverfishRidable = false; + public boolean silverfishRidableInWater = false; ++ public double silverfishMaxHealth = 8.0D; + private void silverfishSettings() { + silverfishRidable = getBoolean("mobs.silverfish.ridable", silverfishRidable); + silverfishRidableInWater = getBoolean("mobs.silverfish.ridable-in-water", silverfishRidableInWater); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.silverfish.attributes.max-health", silverfishMaxHealth); ++ set("mobs.silverfish.attributes.max-health", null); ++ set("mobs.silverfish.attributes.max_health", oldValue); ++ } ++ silverfishMaxHealth = getDouble("mobs.silverfish.attributes.max_health", silverfishMaxHealth); + } + + public boolean skeletonRidable = false; + public boolean skeletonRidableInWater = false; ++ public double skeletonMaxHealth = 20.0D; + private void skeletonSettings() { + skeletonRidable = getBoolean("mobs.skeleton.ridable", skeletonRidable); + skeletonRidableInWater = getBoolean("mobs.skeleton.ridable-in-water", skeletonRidableInWater); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.skeleton.attributes.max-health", skeletonMaxHealth); ++ set("mobs.skeleton.attributes.max-health", null); ++ set("mobs.skeleton.attributes.max_health", oldValue); ++ } ++ skeletonMaxHealth = getDouble("mobs.skeleton.attributes.max_health", skeletonMaxHealth); + } + + public boolean skeletonHorseCanSwim = false; + public boolean skeletonHorseRidableInWater = true; ++ public double skeletonHorseMaxHealthMin = 15.0D; ++ public double skeletonHorseMaxHealthMax = 15.0D; ++ public double skeletonHorseJumpStrengthMin = 0.4D; ++ public double skeletonHorseJumpStrengthMax = 1.0D; ++ public double skeletonHorseMovementSpeedMin = 0.2D; ++ public double skeletonHorseMovementSpeedMax = 0.2D; + private void skeletonHorseSettings() { + skeletonHorseCanSwim = getBoolean("mobs.skeleton_horse.can-swim", skeletonHorseCanSwim); + skeletonHorseRidableInWater = getBoolean("mobs.skeleton_horse.ridable-in-water", skeletonHorseRidableInWater); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.skeleton_horse.attributes.max-health", skeletonHorseMaxHealthMin); ++ set("mobs.skeleton_horse.attributes.max-health", null); ++ set("mobs.skeleton_horse.attributes.max_health.min", oldValue); ++ set("mobs.skeleton_horse.attributes.max_health.max", oldValue); ++ } ++ skeletonHorseMaxHealthMin = getDouble("mobs.skeleton_horse.attributes.max_health.min", skeletonHorseMaxHealthMin); ++ skeletonHorseMaxHealthMax = getDouble("mobs.skeleton_horse.attributes.max_health.max", skeletonHorseMaxHealthMax); ++ skeletonHorseJumpStrengthMin = getDouble("mobs.skeleton_horse.attributes.jump_strength.min", skeletonHorseJumpStrengthMin); ++ skeletonHorseJumpStrengthMax = getDouble("mobs.skeleton_horse.attributes.jump_strength.max", skeletonHorseJumpStrengthMax); ++ skeletonHorseMovementSpeedMin = getDouble("mobs.skeleton_horse.attributes.movement_speed.min", skeletonHorseMovementSpeedMin); ++ skeletonHorseMovementSpeedMax = getDouble("mobs.skeleton_horse.attributes.movement_speed.max", skeletonHorseMovementSpeedMax); + } + + public boolean slimeRidable = false; + public boolean slimeRidableInWater = false; ++ public String slimeMaxHealth = "size * size"; ++ public Map slimeMaxHealthCache = new HashMap<>(); + private void slimeSettings() { + slimeRidable = getBoolean("mobs.slime.ridable", slimeRidable); + slimeRidableInWater = getBoolean("mobs.slime.ridable-in-water", slimeRidableInWater); ++ if (PurpurConfig.version < 10) { ++ String oldValue = getString("mobs.slime.attributes.max-health", slimeMaxHealth); ++ set("mobs.slime.attributes.max-health", null); ++ set("mobs.slime.attributes.max_health", oldValue); ++ } ++ slimeMaxHealth = getString("mobs.slime.attributes.max_health", slimeMaxHealth); ++ slimeMaxHealthCache.clear(); + } + + public boolean snowGolemRidable = false; +@@ -1055,6 +1487,7 @@ public class PurpurWorldConfig { + public int snowGolemSnowBallMax = 20; + public float snowGolemSnowBallModifier = 10.0F; + public double snowGolemAttackDistance = 1.25D; ++ public double snowGolemMaxHealth = 4.0D; + private void snowGolemSettings() { + snowGolemRidable = getBoolean("mobs.snow_golem.ridable", snowGolemRidable); + snowGolemRidableInWater = getBoolean("mobs.snow_golem.ridable-in-water", snowGolemRidableInWater); +@@ -1065,63 +1498,118 @@ public class PurpurWorldConfig { + snowGolemSnowBallMax = getInt("mobs.snow_golem.max-shoot-interval-ticks", snowGolemSnowBallMax); + snowGolemSnowBallModifier = (float) getDouble("mobs.snow_golem.snow-ball-modifier", snowGolemSnowBallModifier); + snowGolemAttackDistance = getDouble("mobs.snow_golem.attack-distance", snowGolemAttackDistance); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.snow_golem.attributes.max-health", snowGolemMaxHealth); ++ set("mobs.snow_golem.attributes.max-health", null); ++ set("mobs.snow_golem.attributes.max_health", oldValue); ++ } ++ snowGolemMaxHealth = getDouble("mobs.snow_golem.attributes.max_health", snowGolemMaxHealth); + } + + public boolean squidRidable = false; + public boolean squidImmuneToEAR = true; + public double squidOffsetWaterCheck = 0.0D; + public boolean squidsCanFly = false; ++ public double squidMaxHealth = 10.0D; + private void squidSettings() { + squidRidable = getBoolean("mobs.squid.ridable", squidRidable); + squidImmuneToEAR = getBoolean("mobs.squid.immune-to-EAR", squidImmuneToEAR); + squidOffsetWaterCheck = getDouble("mobs.squid.water-offset-check", squidOffsetWaterCheck); + squidsCanFly = getBoolean("mobs.squid.can-fly", squidsCanFly); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.squid.attributes.max-health", squidMaxHealth); ++ set("mobs.squid.attributes.max-health", null); ++ set("mobs.squid.attributes.max_health", oldValue); ++ } ++ squidMaxHealth = getDouble("mobs.squid.attributes.max_health", squidMaxHealth); + } + + public boolean spiderRidable = false; + public boolean spiderRidableInWater = false; ++ public double spiderMaxHealth = 16.0D; + private void spiderSettings() { + spiderRidable = getBoolean("mobs.spider.ridable", spiderRidable); + spiderRidableInWater = getBoolean("mobs.spider.ridable-in-water", spiderRidableInWater); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.spider.attributes.max-health", spiderMaxHealth); ++ set("mobs.spider.attributes.max-health", null); ++ set("mobs.spider.attributes.max_health", oldValue); ++ } ++ spiderMaxHealth = getDouble("mobs.spider.attributes.max_health", spiderMaxHealth); + } + + public boolean strayRidable = false; + public boolean strayRidableInWater = false; ++ public double strayMaxHealth = 20.0D; + private void straySettings() { + strayRidable = getBoolean("mobs.stray.ridable", strayRidable); + strayRidableInWater = getBoolean("mobs.stray.ridable-in-water", strayRidableInWater); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.stray.attributes.max-health", strayMaxHealth); ++ set("mobs.stray.attributes.max-health", null); ++ set("mobs.stray.attributes.max_health", oldValue); ++ } ++ strayMaxHealth = getDouble("mobs.stray.attributes.max_health", strayMaxHealth); + } + + public boolean striderRidable = false; + public boolean striderRidableInWater = false; + public int striderBreedingTicks = 6000; ++ public double striderMaxHealth = 20.0D; + private void striderSettings() { + striderRidable = getBoolean("mobs.strider.ridable", striderRidable); + striderRidableInWater = getBoolean("mobs.strider.ridable-in-water", striderRidableInWater); + striderBreedingTicks = getInt("mobs.strider.breeding-delay-ticks", striderBreedingTicks); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.strider.attributes.max-health", striderMaxHealth); ++ set("mobs.strider.attributes.max-health", null); ++ set("mobs.strider.attributes.max_health", oldValue); ++ } ++ striderMaxHealth = getDouble("mobs.strider.attributes.max_health", striderMaxHealth); + } + + public boolean tropicalFishRidable = false; ++ public double tropicalFishMaxHealth = 3.0D; + private void tropicalFishSettings() { + tropicalFishRidable = getBoolean("mobs.tropical_fish.ridable", tropicalFishRidable); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.tropical_fish.attributes.max-health", tropicalFishMaxHealth); ++ set("mobs.tropical_fish.attributes.max-health", null); ++ set("mobs.tropical_fish.attributes.max_health", oldValue); ++ } ++ tropicalFishMaxHealth = getDouble("mobs.tropical_fish.attributes.max_health", tropicalFishMaxHealth); + } + + public boolean turtleRidable = false; + public boolean turtleRidableInWater = false; + public int turtleBreedingTicks = 6000; ++ public double turtleMaxHealth = 30.0D; + private void turtleSettings() { + turtleRidable = getBoolean("mobs.turtle.ridable", turtleRidable); + turtleRidableInWater = getBoolean("mobs.turtle.ridable-in-water", turtleRidableInWater); + turtleBreedingTicks = getInt("mobs.turtle.breeding-delay-ticks", turtleBreedingTicks); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.turtle.attributes.max-health", turtleMaxHealth); ++ set("mobs.turtle.attributes.max-health", null); ++ set("mobs.turtle.attributes.max_health", oldValue); ++ } ++ turtleMaxHealth = getDouble("mobs.turtle.attributes.max_health", turtleMaxHealth); + } + + public boolean vexRidable = false; + public boolean vexRidableInWater = false; + public double vexMaxY = 256D; ++ public double vexMaxHealth = 14.0D; + private void vexSettings() { + vexRidable = getBoolean("mobs.vex.ridable", vexRidable); + vexRidableInWater = getBoolean("mobs.vex.ridable-in-water", vexRidableInWater); + vexMaxY = getDouble("mobs.vex.ridable-max-y", vexMaxY); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.vex.attributes.max-health", vexMaxHealth); ++ set("mobs.vex.attributes.max-health", null); ++ set("mobs.vex.attributes.max_health", oldValue); ++ } ++ vexMaxHealth = getDouble("mobs.vex.attributes.max_health", vexMaxHealth); + } + + public boolean villagerRidable = false; +@@ -1139,6 +1627,7 @@ public class PurpurWorldConfig { + public int villagerLobotomizeCheck = 60; + public boolean villagerClericsFarmWarts = false; + public boolean villagerClericFarmersThrowWarts = true; ++ public double villagerMaxHealth = 20.0D; + private void villagerSettings() { + villagerRidable = getBoolean("mobs.villager.ridable", villagerRidable); + villagerRidableInWater = getBoolean("mobs.villager.ridable-in-water", villagerRidableInWater); +@@ -1160,33 +1649,60 @@ public class PurpurWorldConfig { + villagerLobotomizeCheck = getInt("mobs.villager.lobotomize.check-interval", villagerLobotomizeCheck); + villagerClericsFarmWarts = getBoolean("mobs.villager.clerics-farm-warts", villagerClericsFarmWarts); + villagerClericFarmersThrowWarts = getBoolean("mobs.villager.cleric-wart-farmers-throw-warts-at-villagers", villagerClericFarmersThrowWarts); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.villager.attributes.max-health", villagerMaxHealth); ++ set("mobs.villager.attributes.max-health", null); ++ set("mobs.villager.attributes.max_health", oldValue); ++ } ++ villagerMaxHealth = getDouble("mobs.villager.attributes.max_health", villagerMaxHealth); + } + + public boolean villagerTraderRidable = false; + public boolean villagerTraderRidableInWater = false; + public boolean villagerTraderCanBeLeashed = false; + public boolean villagerTraderFollowEmeraldBlock = false; ++ public double villagerTraderMaxHealth = 20.0D; + private void villagerTraderSettings() { + villagerTraderRidable = getBoolean("mobs.wandering_trader.ridable", villagerTraderRidable); + villagerTraderRidableInWater = getBoolean("mobs.wandering_trader.ridable-in-water", villagerTraderRidableInWater); + villagerTraderCanBeLeashed = getBoolean("mobs.wandering_trader.can-be-leashed", villagerTraderCanBeLeashed); + villagerTraderFollowEmeraldBlock = getBoolean("mobs.wandering_trader.follow-emerald-blocks", villagerTraderFollowEmeraldBlock); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.wandering_trader.attributes.max-health", villagerTraderMaxHealth); ++ set("mobs.wandering_trader.attributes.max-health", null); ++ set("mobs.wandering_trader.attributes.max_health", oldValue); ++ } ++ villagerTraderMaxHealth = getDouble("mobs.wandering_trader.attributes.max_health", villagerTraderMaxHealth); + } + + public boolean vindicatorRidable = false; + public boolean vindicatorRidableInWater = false; + public double vindicatorJohnnySpawnChance = 0D; ++ public double vindicatorMaxHealth = 24.0D; + private void vindicatorSettings() { + vindicatorRidable = getBoolean("mobs.vindicator.ridable", vindicatorRidable); + vindicatorRidableInWater = getBoolean("mobs.vindicator.ridable-in-water", vindicatorRidableInWater); + vindicatorJohnnySpawnChance = getDouble("mobs.vindicator.johnny.spawn-chance", vindicatorJohnnySpawnChance); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.vindicator.attributes.max-health", vindicatorMaxHealth); ++ set("mobs.vindicator.attributes.max-health", null); ++ set("mobs.vindicator.attributes.max_health", oldValue); ++ } ++ vindicatorMaxHealth = getDouble("mobs.vindicator.attributes.max_health", vindicatorMaxHealth); + } + + public boolean witchRidable = false; + public boolean witchRidableInWater = false; ++ public double witchMaxHealth = 26.0D; + private void witchSettings() { + witchRidable = getBoolean("mobs.witch.ridable", witchRidable); + witchRidableInWater = getBoolean("mobs.witch.ridable-in-water", witchRidableInWater); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.witch.attributes.max-health", witchMaxHealth); ++ set("mobs.witch.attributes.max-health", null); ++ set("mobs.witch.attributes.max_health", oldValue); ++ } ++ witchMaxHealth = getDouble("mobs.witch.attributes.max_health", witchMaxHealth); + } + + public boolean witherRidable = false; +@@ -1203,19 +1719,30 @@ public class PurpurWorldConfig { + witherHealthRegenDelay = getInt("mobs.wither.health-regen-delay", witherHealthRegenDelay); + if (PurpurConfig.version < 8) { + double oldValue = getDouble("mobs.wither.max-health", witherMaxHealth); ++ set("mobs.wither.max_health", null); + set("mobs.wither.attributes.max-health", oldValue); +- set("mobs.wither.max-health", null); ++ } else if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.wither.attributes.max-health", witherMaxHealth); ++ set("mobs.wither.attributes.max-health", null); ++ set("mobs.wither.attributes.max_health", oldValue); + } +- witherMaxHealth = getDouble("mobs.wither.attributes.max-health", witherMaxHealth); ++ witherMaxHealth = getDouble("mobs.wither.attributes.max_health", witherMaxHealth); + } + + public boolean witherSkeletonRidable = false; + public boolean witherSkeletonRidableInWater = false; + public boolean witherSkeletonTakesWitherDamage = false; ++ public double witherSkeletonMaxHealth = 20.0D; + private void witherSkeletonSettings() { + witherSkeletonRidable = getBoolean("mobs.wither_skeleton.ridable", witherSkeletonRidable); + witherSkeletonRidableInWater = getBoolean("mobs.wither_skeleton.ridable-in-water", witherSkeletonRidableInWater); + witherSkeletonTakesWitherDamage = getBoolean("mobs.wither_skeleton.takes-wither-damage", witherSkeletonTakesWitherDamage); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.wither_skeleton.attributes.max-health", witherSkeletonMaxHealth); ++ set("mobs.wither_skeleton.attributes.max-health", null); ++ set("mobs.wither_skeleton.attributes.max_health", oldValue); ++ } ++ witherSkeletonMaxHealth = getDouble("mobs.wither_skeleton.attributes.max_health", witherSkeletonMaxHealth); + } + + public boolean wolfRidable = false; +@@ -1224,6 +1751,7 @@ public class PurpurWorldConfig { + public boolean wolfMilkCuresRabies = true; + public double wolfNaturalRabid = 0.0D; + public int wolfBreedingTicks = 6000; ++ public double wolfMaxHealth = 8.0D; + private void wolfSettings() { + wolfRidable = getBoolean("mobs.wolf.ridable", wolfRidable); + wolfRidableInWater = getBoolean("mobs.wolf.ridable-in-water", wolfRidableInWater); +@@ -1235,13 +1763,26 @@ public class PurpurWorldConfig { + wolfMilkCuresRabies = getBoolean("mobs.wolf.milk-cures-rabid-wolves", wolfMilkCuresRabies); + wolfNaturalRabid = getDouble("mobs.wolf.spawn-rabid-chance", wolfNaturalRabid); + wolfBreedingTicks = getInt("mobs.wolf.breeding-delay-ticks", wolfBreedingTicks); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.wolf.attributes.max-health", wolfMaxHealth); ++ set("mobs.wolf.attributes.max-health", null); ++ set("mobs.wolf.attributes.max_health", oldValue); ++ } ++ wolfMaxHealth = getDouble("mobs.wolf.attributes.max_health", wolfMaxHealth); + } + + public boolean zoglinRidable = false; + public boolean zoglinRidableInWater = false; ++ public double zoglinMaxHealth = 40.0D; + private void zoglinSettings() { + zoglinRidable = getBoolean("mobs.zoglin.ridable", zoglinRidable); + zoglinRidableInWater = getBoolean("mobs.zoglin.ridable-in-water", zoglinRidableInWater); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.zoglin.attributes.max-health", zoglinMaxHealth); ++ set("mobs.zoglin.attributes.max-health", null); ++ set("mobs.zoglin.attributes.max_health", oldValue); ++ } ++ zoglinMaxHealth = getDouble("mobs.zoglin.attributes.max_health", zoglinMaxHealth); + } + + public boolean zombieRidable = false; +@@ -1251,6 +1792,8 @@ public class PurpurWorldConfig { + public boolean zombieJockeyTryExistingChickens = true; + public boolean zombieAggressiveTowardsVillagerWhenLagging = true; + public EnumDifficulty zombieBreakDoorMinDifficulty = EnumDifficulty.HARD; ++ public double zombieMaxHealth = 20.0D; ++ public double zombieSpawnReinforcements = 0.1D; + private void zombieSettings() { + zombieRidable = getBoolean("mobs.zombie.ridable", zombieRidable); + zombieRidableInWater = getBoolean("mobs.zombie.ridable-in-water", zombieRidableInWater); +@@ -1263,15 +1806,40 @@ public class PurpurWorldConfig { + } catch (IllegalArgumentException ignore) { + zombieBreakDoorMinDifficulty = EnumDifficulty.HARD; + } ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.zombie.attributes.max-health", zombieMaxHealth); ++ set("mobs.zombie.attributes.max-health", null); ++ set("mobs.zombie.attributes.max_health", oldValue); ++ } ++ zombieMaxHealth = getDouble("mobs.zombie.attributes.max_health", zombieMaxHealth); ++ zombieSpawnReinforcements = getDouble("mobs.zombie.attributes.spawn_reinforcements", zombieSpawnReinforcements); + } + + public boolean zombieHorseCanSwim = false; + public boolean zombieHorseRidableInWater = false; + public double zombieHorseSpawnChance = 0.0D; ++ public double zombieHorseMaxHealthMin = 15.0D; ++ public double zombieHorseMaxHealthMax = 15.0D; ++ public double zombieHorseJumpStrengthMin = 0.4D; ++ public double zombieHorseJumpStrengthMax = 1.0D; ++ public double zombieHorseMovementSpeedMin = 0.2D; ++ public double zombieHorseMovementSpeedMax = 0.2D; + private void zombieHorseSettings() { + zombieHorseCanSwim = getBoolean("mobs.zombie_horse.can-swim", zombieHorseCanSwim); + zombieHorseRidableInWater = getBoolean("mobs.zombie_horse.ridable-in-water", zombieHorseRidableInWater); + zombieHorseSpawnChance = getDouble("mobs.zombie_horse.spawn-chance", zombieHorseSpawnChance); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.zombie_horse.attributes.max-health", zombieHorseMaxHealthMin); ++ set("mobs.zombie_horse.attributes.max-health", null); ++ set("mobs.zombie_horse.attributes.max_health.min", oldValue); ++ set("mobs.zombie_horse.attributes.max_health.max", oldValue); ++ } ++ zombieHorseMaxHealthMin = getDouble("mobs.zombie_horse.attributes.max_health.min", zombieHorseMaxHealthMin); ++ zombieHorseMaxHealthMax = getDouble("mobs.zombie_horse.attributes.max_health.max", zombieHorseMaxHealthMax); ++ zombieHorseJumpStrengthMin = getDouble("mobs.zombie_horse.attributes.jump_strength.min", zombieHorseJumpStrengthMin); ++ zombieHorseJumpStrengthMax = getDouble("mobs.zombie_horse.attributes.jump_strength.max", zombieHorseJumpStrengthMax); ++ zombieHorseMovementSpeedMin = getDouble("mobs.zombie_horse.attributes.movement_speed.min", zombieHorseMovementSpeedMin); ++ zombieHorseMovementSpeedMax = getDouble("mobs.zombie_horse.attributes.movement_speed.max", zombieHorseMovementSpeedMax); + } + + public boolean zombifiedPiglinRidable = false; +@@ -1280,6 +1848,8 @@ public class PurpurWorldConfig { + public double zombifiedPiglinJockeyChance = 0.05D; + public boolean zombifiedPiglinJockeyTryExistingChickens = true; + public boolean zombifiedPiglinCountAsPlayerKillWhenAngry = true; ++ public double zombifiedPiglinMaxHealth = 20.0D; ++ public double zombifiedPiglinSpawnReinforcements = 0.0D; + private void zombifiedPiglinSettings() { + zombifiedPiglinRidable = getBoolean("mobs.zombified_piglin.ridable", zombifiedPiglinRidable); + zombifiedPiglinRidableInWater = getBoolean("mobs.zombified_piglin.ridable-in-water", zombifiedPiglinRidableInWater); +@@ -1287,6 +1857,13 @@ public class PurpurWorldConfig { + zombifiedPiglinJockeyChance = getDouble("mobs.zombified_piglin.jockey.chance", zombifiedPiglinJockeyChance); + zombifiedPiglinJockeyTryExistingChickens = getBoolean("mobs.zombified_piglin.jockey.try-existing-chickens", zombifiedPiglinJockeyTryExistingChickens); + zombifiedPiglinCountAsPlayerKillWhenAngry = getBoolean("mobs.zombified_piglin.count-as-player-kill-when-angry", zombifiedPiglinCountAsPlayerKillWhenAngry); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.zombified_piglin.attributes.max-health", zombifiedPiglinMaxHealth); ++ set("mobs.zombified_piglin.attributes.max-health", null); ++ set("mobs.zombified_piglin.attributes.max_health", oldValue); ++ } ++ zombifiedPiglinMaxHealth = getDouble("mobs.zombified_piglin.attributes.max_health", zombifiedPiglinMaxHealth); ++ zombifiedPiglinSpawnReinforcements = getDouble("mobs.zombified_piglin.attributes.spawn_reinforcements", zombifiedPiglinSpawnReinforcements); + } + + public boolean zombieVillagerRidable = false; +@@ -1294,11 +1871,20 @@ public class PurpurWorldConfig { + public boolean zombieVillagerJockeyOnlyBaby = true; + public double zombieVillagerJockeyChance = 0.05D; + public boolean zombieVillagerJockeyTryExistingChickens = true; ++ public double zombieVillagerMaxHealth = 20.0D; ++ public double zombieVillagerSpawnReinforcements = 0.1D; + private void zombieVillagerSettings() { + zombieVillagerRidable = getBoolean("mobs.zombie_villager.ridable", zombieVillagerRidable); + zombieVillagerRidableInWater = getBoolean("mobs.zombie_villager.ridable-in-water", zombieVillagerRidableInWater); + zombieVillagerJockeyOnlyBaby = getBoolean("mobs.zombie_villager.jockey.only-babies", zombieVillagerJockeyOnlyBaby); + zombieVillagerJockeyChance = getDouble("mobs.zombie_villager.jockey.chance", zombieVillagerJockeyChance); + zombieVillagerJockeyTryExistingChickens = getBoolean("mobs.zombie_villager.jockey.try-existing-chickens", zombieVillagerJockeyTryExistingChickens); ++ if (PurpurConfig.version < 10) { ++ double oldValue = getDouble("mobs.zombie_villager.attributes.max-health", zombieVillagerMaxHealth); ++ set("mobs.zombie_villager.attributes.max-health", null); ++ set("mobs.zombie_villager.attributes.max_health", oldValue); ++ } ++ zombieVillagerMaxHealth = getDouble("mobs.zombie_villager.attributes.max_health", zombieVillagerMaxHealth); ++ zombieVillagerSpawnReinforcements = getDouble("mobs.zombie_villager.attributes.spawn_reinforcements", zombieVillagerSpawnReinforcements); + } + } diff --git a/patches/Purpur/patches/server/0148-Phantom-flames-on-swoop.patch b/patches/Purpur/patches/server/0148-Phantom-flames-on-swoop.patch new file mode 100644 index 00000000..574a9b30 --- /dev/null +++ b/patches/Purpur/patches/server/0148-Phantom-flames-on-swoop.patch @@ -0,0 +1,38 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Sat, 12 Dec 2020 09:10:59 -0600 +Subject: [PATCH] Phantom flames on swoop + + +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityPhantom.java b/src/main/java/net/minecraft/world/entity/monster/EntityPhantom.java +index 437d602cf4a0da52fc61a50321d795290eea11bf..fe07d9798eaae670e218d25fe23256c87c41d686 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityPhantom.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityPhantom.java +@@ -226,6 +226,7 @@ public class EntityPhantom extends EntityFlying implements IMonster { + this.world.addParticle(Particles.MYCELIUM, this.locX() - (double) f2, this.locY() + (double) f4, this.locZ() - (double) f3, 0.0D, 0.0D, 0.0D); + } + ++ if (world.purpurConfig.phantomFlamesOnSwoop && getAttackPhase() == AttackPhase.SWOOP) shoot(); // Purpur + } + + @Override +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index f0f8165c51c17855d0c719d47bea194b80ff7847..c84a331c157ea1180813cba1107bf901a35b2833 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -1206,6 +1206,7 @@ public class PurpurWorldConfig { + public boolean phantomIgnorePlayersWithTorch = false; + public boolean phantomBurnInDaylight = true; + public boolean phantomAllowGriefing = false; ++ public boolean phantomFlamesOnSwoop = false; + public double phantomMaxHealth = 20.0D; + private void phantomSettings() { + phantomRidable = getBoolean("mobs.phantom.ridable", phantomRidable); +@@ -1232,6 +1233,7 @@ public class PurpurWorldConfig { + phantomBurnInDaylight = getBoolean("mobs.phantom.burn-in-daylight", phantomBurnInDaylight); + phantomIgnorePlayersWithTorch = getBoolean("mobs.phantom.ignore-players-with-torch", phantomIgnorePlayersWithTorch); + phantomAllowGriefing = getBoolean("mobs.phantom.allow-griefing", phantomAllowGriefing); ++ phantomFlamesOnSwoop = getBoolean("mobs.phantom.flames-on-swoop", phantomFlamesOnSwoop); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.phantom.attributes.max-health", phantomMaxHealth); + set("mobs.phantom.attributes.max-health", null); diff --git a/patches/Purpur/patches/server/0149-Option-for-chests-to-open-even-with-a-solid-block-on.patch b/patches/Purpur/patches/server/0149-Option-for-chests-to-open-even-with-a-solid-block-on.patch new file mode 100644 index 00000000..3f720b22 --- /dev/null +++ b/patches/Purpur/patches/server/0149-Option-for-chests-to-open-even-with-a-solid-block-on.patch @@ -0,0 +1,34 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: jmp +Date: Sat, 12 Dec 2020 14:34:18 -0800 +Subject: [PATCH] Option for chests to open even with a solid block on top + + +diff --git a/src/main/java/net/minecraft/world/level/block/BlockChest.java b/src/main/java/net/minecraft/world/level/block/BlockChest.java +index a45ee959f41e7f349ff2c309f21fa44ec671cb87..cddf8e3d34385eb264cd28ba6b4392d682df0360 100644 +--- a/src/main/java/net/minecraft/world/level/block/BlockChest.java ++++ b/src/main/java/net/minecraft/world/level/block/BlockChest.java +@@ -306,6 +306,7 @@ public class BlockChest extends BlockChestAbstract implements I + } + + private static boolean a(IBlockAccess iblockaccess, BlockPosition blockposition) { ++ if (iblockaccess instanceof World && ((World) iblockaccess).purpurConfig.chestOpenWithBlockOnTop) return false; // Purpur + BlockPosition blockposition1 = blockposition.up(); + + return iblockaccess.getType(blockposition1).isOccluding(iblockaccess, blockposition1); +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index c84a331c157ea1180813cba1107bf901a35b2833..3d1cfd550b12c8dd4bd536c518ac169ff6bbfe50 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -439,6 +439,11 @@ public class PurpurWorldConfig { + } + } + ++ public boolean chestOpenWithBlockOnTop = false; ++ private void chestSettings() { ++ chestOpenWithBlockOnTop = getBoolean("blocks.chest.open-with-solid-block-on-top", chestOpenWithBlockOnTop); ++ } ++ + public boolean dispenserApplyCursedArmor = true; + public boolean dispenserPlaceAnvils = false; + private void dispenserSettings() { diff --git a/patches/Purpur/patches/server/0150-Implement-TPSBar.patch b/patches/Purpur/patches/server/0150-Implement-TPSBar.patch new file mode 100644 index 00000000..8b34d028 --- /dev/null +++ b/patches/Purpur/patches/server/0150-Implement-TPSBar.patch @@ -0,0 +1,211 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Sat, 12 Dec 2020 21:19:05 -0600 +Subject: [PATCH] Implement TPSBar + + +diff --git a/src/main/java/net/minecraft/commands/CommandDispatcher.java b/src/main/java/net/minecraft/commands/CommandDispatcher.java +index 0ea56c863a9a1019b36f7f9f9164301aef12637b..4338b459011bf7a083790b7bb76cf1b24471fd19 100644 +--- a/src/main/java/net/minecraft/commands/CommandDispatcher.java ++++ b/src/main/java/net/minecraft/commands/CommandDispatcher.java +@@ -193,6 +193,7 @@ public class CommandDispatcher { + CommandWhitelist.a(this.b); + net.pl3x.purpur.command.DemoCommand.register(getDispatcher()); // Purpur + net.pl3x.purpur.command.PingCommand.register(getDispatcher()); // Purpur ++ net.pl3x.purpur.command.TPSBarCommand.register(getDispatcher()); // Purpur + } + + if (commanddispatcher_servertype.d) { +diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java +index aacc1b82ed178d6c0e499a53ce1aec7e20dad875..ee75fe091f7fd28426b9af329358ea0deb24d589 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -993,6 +993,7 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant dispatcher) { ++ dispatcher.register(CommandDispatcher.literal("tpsbar") ++ .requires((listener) -> { ++ return listener.hasPermission(2); ++ }) ++ .executes((context) -> { ++ return execute(context.getSource(), context.getSource().getPlayerOrException()); ++ }) ++ ).setPermission("bukkit.command.tpsbar"); ++ } ++ ++ private static int execute(CommandListenerWrapper sender, EntityPlayer player) { ++ if (player != null) { ++ TPSBarTask.togglePlayer(player.getBukkitEntity()); ++ return 1; ++ } ++ return 0; ++ } ++} +diff --git a/src/main/java/net/pl3x/purpur/task/TPSBarTask.java b/src/main/java/net/pl3x/purpur/task/TPSBarTask.java +new file mode 100644 +index 0000000000000000000000000000000000000000..a9d71d2b769b8e4e0f5039e997fc5ebc1cc9bfbb +--- /dev/null ++++ b/src/main/java/net/pl3x/purpur/task/TPSBarTask.java +@@ -0,0 +1,116 @@ ++package net.pl3x.purpur.task; ++ ++import org.bukkit.Bukkit; ++import org.bukkit.ChatColor; ++import org.bukkit.NamespacedKey; ++import org.bukkit.boss.BarColor; ++import org.bukkit.boss.BarStyle; ++import org.bukkit.boss.BossBar; ++import org.bukkit.craftbukkit.scheduler.MinecraftInternalPlugin; ++import org.bukkit.entity.Player; ++import org.bukkit.scheduler.BukkitRunnable; ++ ++public class TPSBarTask extends BukkitRunnable { ++ private static TPSBarTask instance; ++ private final NamespacedKey key; ++ private BossBar bossbar; ++ ++ private TPSBarTask() { ++ this.key = new NamespacedKey("purpur", "tpsbar"); ++ } ++ ++ private static TPSBarTask instance() { ++ if (instance == null) { ++ instance = new TPSBarTask(); ++ } ++ return instance; ++ } ++ ++ private BossBar bossbar() { ++ if (bossbar == null) { ++ bossbar = Bukkit.getBossBar(key); ++ if (bossbar == null) { ++ bossbar = Bukkit.createBossBar(key, "TPS: 20.0", BarColor.RED, BarStyle.SEGMENTED_20); ++ } ++ bossbar.setVisible(true); ++ bossbar.setProgress(1.0D); ++ } ++ return bossbar; ++ } ++ ++ @Override ++ public void run() { ++ BossBar bossbar = bossbar(); ++ if (bossbar.getPlayers().isEmpty()) { ++ return; ++ } ++ ++ double tps = Bukkit.getTPS()[0]; ++ if (tps > 20.0D) { ++ tps = 20.0D; ++ } else if (tps < 0.0D) { ++ tps = 0.0D; ++ } ++ ++ bossbar.setVisible(true); ++ bossbar.setProgress(Math.max(Math.min(tps / 20.0D, 1.0D), 0.0D)); ++ ++ String tpsColor; ++ if (tps >= 18) { ++ tpsColor = "&2"; ++ bossbar.setColor(BarColor.GREEN); ++ } else if (tps >= 15) { ++ tpsColor = "&e"; ++ bossbar.setColor(BarColor.YELLOW); ++ } else { ++ tpsColor = "&4"; ++ bossbar.setColor(BarColor.RED); ++ } ++ ++ double mspt = Bukkit.getAverageTickTime(); ++ String msptColor; ++ if (mspt < 40) { ++ msptColor = "&2"; ++ } else if (mspt < 50) { ++ msptColor = "&e"; ++ } else { ++ msptColor = "&4"; ++ } ++ ++ bossbar.setTitle(ChatColor.translateAlternateColorCodes('&', "&eTPS&3: " + tpsColor + String.format("%.2f", tps) + " &eMSPT&3: " + msptColor + String.format("%.3f", mspt))); ++ } ++ ++ @Override ++ public void cancel() { ++ super.cancel(); ++ BossBar bossbar = bossbar(); ++ bossbar.setVisible(false); ++ bossbar.removeAll(); ++ Bukkit.removeBossBar(key); ++ } ++ ++ public static void removePlayer(Player player) { ++ instance().bossbar().removePlayer(player); ++ } ++ ++ public static void togglePlayer(Player player) { ++ BossBar bossbar = instance().bossbar(); ++ if (bossbar.getPlayers().contains(player)) { ++ bossbar.removePlayer(player); ++ } else { ++ bossbar.addPlayer(player); ++ instance.run(); ++ } ++ } ++ ++ public static void start() { ++ stop(); ++ instance().runTaskTimerAsynchronously(new MinecraftInternalPlugin(), 20L, 20L); ++ } ++ ++ public static void stop() { ++ if (instance != null) { ++ instance.cancel(); ++ } ++ } ++} diff --git a/patches/Purpur/patches/server/0151-Striders-give-saddle-back.patch b/patches/Purpur/patches/server/0151-Striders-give-saddle-back.patch new file mode 100644 index 00000000..350d49ac --- /dev/null +++ b/patches/Purpur/patches/server/0151-Striders-give-saddle-back.patch @@ -0,0 +1,47 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ben Kerllenevich +Date: Sun, 13 Dec 2020 20:40:57 -0500 +Subject: [PATCH] Striders give saddle back + + +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityStrider.java b/src/main/java/net/minecraft/world/entity/monster/EntityStrider.java +index 892aa844a98ae0d192737c6fc6df0a219256a47b..5e4cc99a746d98231bbb71672fbc02431e4fab48 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityStrider.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityStrider.java +@@ -448,6 +448,18 @@ public class EntityStrider extends EntityAnimal implements ISteerable, ISaddleab + + if (!flag && this.hasSaddle() && !this.isVehicle() && !entityhuman.eq()) { + if (!this.world.isClientSide) { ++ // Purpur start ++ if (world.purpurConfig.striderGiveSaddleBack && entityhuman.isSneaking()) { ++ this.saddleStorage.setSaddle(false); ++ if (!entityhuman.abilities.canInstantlyBuild) { ++ ItemStack saddle = new ItemStack(Items.SADDLE); ++ if (!entityhuman.inventory.pickup(saddle)) { ++ entityhuman.drop(saddle, false); ++ } ++ } ++ return EnumInteractionResult.SUCCESS; ++ } ++ // Purpur end + entityhuman.startRiding(this); + } + +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 3d1cfd550b12c8dd4bd536c518ac169ff6bbfe50..130dc441be74963c272381e992ea39883804f9f7 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -1562,11 +1562,13 @@ public class PurpurWorldConfig { + public boolean striderRidable = false; + public boolean striderRidableInWater = false; + public int striderBreedingTicks = 6000; ++ public boolean striderGiveSaddleBack = false; + public double striderMaxHealth = 20.0D; + private void striderSettings() { + striderRidable = getBoolean("mobs.strider.ridable", striderRidable); + striderRidableInWater = getBoolean("mobs.strider.ridable-in-water", striderRidableInWater); + striderBreedingTicks = getInt("mobs.strider.breeding-delay-ticks", striderBreedingTicks); ++ striderGiveSaddleBack = getBoolean("mobs.strider.give-saddle-back", striderGiveSaddleBack); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.strider.attributes.max-health", striderMaxHealth); + set("mobs.strider.attributes.max-health", null); diff --git a/patches/Purpur/patches/server/0152-PlayerBookTooLargeEvent.patch b/patches/Purpur/patches/server/0152-PlayerBookTooLargeEvent.patch new file mode 100644 index 00000000..8fc37c1e --- /dev/null +++ b/patches/Purpur/patches/server/0152-PlayerBookTooLargeEvent.patch @@ -0,0 +1,34 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Wed, 23 Dec 2020 00:43:59 -0600 +Subject: [PATCH] PlayerBookTooLargeEvent + + +diff --git a/src/main/java/net/minecraft/server/network/PlayerConnection.java b/src/main/java/net/minecraft/server/network/PlayerConnection.java +index 764ec67150a37f3a18eb1efde9d0c8810a92da6d..04052a43a2025876529d2a6c6f5fc9821c723da6 100644 +--- a/src/main/java/net/minecraft/server/network/PlayerConnection.java ++++ b/src/main/java/net/minecraft/server/network/PlayerConnection.java +@@ -1136,6 +1136,7 @@ public class PlayerConnection implements PacketListenerPlayIn { + NBTTagList pageList = testStack.getTag().getList("pages", 8); + if (pageList.size() > 100) { + PlayerConnection.LOGGER.warn(this.player.getName() + " tried to send a book with too many pages"); ++ net.pl3x.purpur.event.player.PlayerBookTooLargeEvent event = new net.pl3x.purpur.event.player.PlayerBookTooLargeEvent(player.getBukkitEntity(), testStack.asBukkitCopy()); if (event.shouldKickPlayer()) // Purpur + minecraftServer.scheduleOnMain(() -> this.disconnect("Book too large!", org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_ACTION)); // Paper - kick event cause + return; + } +@@ -1148,6 +1149,7 @@ public class PlayerConnection implements PacketListenerPlayIn { + int byteLength = testString.getBytes(java.nio.charset.StandardCharsets.UTF_8).length; + if (byteLength > 256 * 4) { + PlayerConnection.LOGGER.warn(this.player.getName() + " tried to send a book with with a page too large!"); ++ net.pl3x.purpur.event.player.PlayerBookTooLargeEvent event = new net.pl3x.purpur.event.player.PlayerBookTooLargeEvent(player.getBukkitEntity(), testStack.asBukkitCopy()); if (event.shouldKickPlayer()) // Purpur + minecraftServer.scheduleOnMain(() -> this.disconnect("Book too large!", org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_ACTION)); // Paper - kick event cause + return; + } +@@ -1171,6 +1173,7 @@ public class PlayerConnection implements PacketListenerPlayIn { + + if (byteTotal > byteAllowed) { + PlayerConnection.LOGGER.warn(this.player.getName() + " tried to send too large of a book. Book Size: " + byteTotal + " - Allowed: "+ byteAllowed + " - Pages: " + pageList.size()); ++ net.pl3x.purpur.event.player.PlayerBookTooLargeEvent event = new net.pl3x.purpur.event.player.PlayerBookTooLargeEvent(player.getBukkitEntity(), testStack.asBukkitCopy()); if (event.shouldKickPlayer()) // Purpur + minecraftServer.scheduleOnMain(() -> this.disconnect("Book too large!", org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_ACTION)); // Paper - kick event cause + return; + } diff --git a/patches/Purpur/patches/server/0153-Full-netherite-armor-grants-fire-resistance.patch b/patches/Purpur/patches/server/0153-Full-netherite-armor-grants-fire-resistance.patch new file mode 100644 index 00000000..07615da7 --- /dev/null +++ b/patches/Purpur/patches/server/0153-Full-netherite-armor-grants-fire-resistance.patch @@ -0,0 +1,51 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Thu, 24 Dec 2020 11:00:15 -0600 +Subject: [PATCH] Full netherite armor grants fire resistance + + +diff --git a/src/main/java/net/minecraft/world/entity/player/EntityHuman.java b/src/main/java/net/minecraft/world/entity/player/EntityHuman.java +index c2a35fac1065b2b67a0a3ce94432246892f6f4a5..5f4a9ef27ab1a177a048fbf376d1e353be865e6f 100644 +--- a/src/main/java/net/minecraft/world/entity/player/EntityHuman.java ++++ b/src/main/java/net/minecraft/world/entity/player/EntityHuman.java +@@ -339,6 +339,16 @@ public abstract class EntityHuman extends EntityLiving { + this.addEffect(new MobEffect(MobEffects.WATER_BREATHING, 200, 0, false, false, true), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.TURTLE_HELMET); // CraftBukkit + } + ++ // Purpur start ++ if (this.world.purpurConfig.playerNetheriteFireResistanceDuration > 0 && this.world.getTime() % 20 == 0) { ++ if (itemstack.getItem() == Items.NETHERITE_HELMET ++ && this.getEquipment(EnumItemSlot.CHEST).getItem() == Items.NETHERITE_CHESTPLATE ++ && this.getEquipment(EnumItemSlot.LEGS).getItem() == Items.NETHERITE_LEGGINGS ++ && this.getEquipment(EnumItemSlot.FEET).getItem() == Items.NETHERITE_BOOTS) { ++ this.addEffect(new MobEffect(MobEffects.FIRE_RESISTANCE, this.world.purpurConfig.playerNetheriteFireResistanceDuration, this.world.purpurConfig.playerNetheriteFireResistanceAmplifier, this.world.purpurConfig.playerNetheriteFireResistanceAmbient, this.world.purpurConfig.playerNetheriteFireResistanceShowParticles, this.world.purpurConfig.playerNetheriteFireResistanceShowIcon), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.NETHERITE_ARMOR); ++ } ++ } ++ // Purpur end + } + + protected ItemCooldown i() { +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 130dc441be74963c272381e992ea39883804f9f7..318513f5612a694c2b240840b24a39210457c202 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -356,6 +356,19 @@ public class PurpurWorldConfig { + playerDeathExpDropMax = getInt("gameplay-mechanics.player.exp-dropped-on-death.maximum", playerDeathExpDropMax); + } + ++ public int playerNetheriteFireResistanceDuration = 0; ++ public int playerNetheriteFireResistanceAmplifier = 0; ++ public boolean playerNetheriteFireResistanceAmbient = false; ++ public boolean playerNetheriteFireResistanceShowParticles = false; ++ public boolean playerNetheriteFireResistanceShowIcon = true; ++ private void playerNetheriteFireResistance() { ++ playerNetheriteFireResistanceDuration = getInt("gameplay-mechanics.player.netherite-fire-resistance.duration", playerNetheriteFireResistanceDuration); ++ playerNetheriteFireResistanceAmplifier = getInt("gameplay-mechanics.player.netherite-fire-resistance.amplifier", playerNetheriteFireResistanceAmplifier); ++ playerNetheriteFireResistanceAmbient = getBoolean("gameplay-mechanics.player.netherite-fire-resistance.ambient", playerNetheriteFireResistanceAmbient); ++ playerNetheriteFireResistanceShowParticles = getBoolean("gameplay-mechanics.player.netherite-fire-resistance.show-particles", playerNetheriteFireResistanceShowParticles); ++ playerNetheriteFireResistanceShowIcon = getBoolean("gameplay-mechanics.player.netherite-fire-resistance.show-icon", playerNetheriteFireResistanceShowIcon); ++ } ++ + public int playerSpawnInvulnerableTicks = 60; + public boolean playerInvulnerableWhileAcceptingResourcePack = false; + private void playerInvulnerabilities() { diff --git a/patches/Purpur/patches/server/0154-Fix-rotating-UP-DOWN-CW-and-CCW.patch b/patches/Purpur/patches/server/0154-Fix-rotating-UP-DOWN-CW-and-CCW.patch new file mode 100644 index 00000000..187d9306 --- /dev/null +++ b/patches/Purpur/patches/server/0154-Fix-rotating-UP-DOWN-CW-and-CCW.patch @@ -0,0 +1,36 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Wed, 6 Jan 2021 02:19:29 -0600 +Subject: [PATCH] Fix rotating UP/DOWN CW and CCW + + +diff --git a/src/main/java/net/minecraft/core/EnumDirection.java b/src/main/java/net/minecraft/core/EnumDirection.java +index 29d747f7fc5824a222755ebf96dfe053896d43d0..9f1ea11d0bc15b8b0069fcf46ea2f6751c5e3064 100644 +--- a/src/main/java/net/minecraft/core/EnumDirection.java ++++ b/src/main/java/net/minecraft/core/EnumDirection.java +@@ -127,6 +127,12 @@ public enum EnumDirection implements INamable { + return EnumDirection.NORTH; + case EAST: + return EnumDirection.SOUTH; ++ // Purpur start ++ case UP: ++ return EnumDirection.UP; ++ case DOWN: ++ return EnumDirection.DOWN; ++ // Purpur end + default: + throw new IllegalStateException("Unable to get Y-rotated facing of " + this); + } +@@ -143,6 +149,12 @@ public enum EnumDirection implements INamable { + return EnumDirection.SOUTH; + case EAST: + return EnumDirection.NORTH; ++ // Purpur start ++ case UP: ++ return EnumDirection.UP; ++ case DOWN: ++ return EnumDirection.DOWN; ++ // Purpur end + default: + throw new IllegalStateException("Unable to get CCW facing of " + this); + } diff --git a/patches/Purpur/patches/server/0155-Add-MC-4-fix-back.patch b/patches/Purpur/patches/server/0155-Add-MC-4-fix-back.patch new file mode 100644 index 00000000..1c54d461 --- /dev/null +++ b/patches/Purpur/patches/server/0155-Add-MC-4-fix-back.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Thu, 7 Jan 2021 07:51:25 -0600 +Subject: [PATCH] Add MC-4 fix back + + +diff --git a/src/main/java/net/minecraft/world/entity/item/EntityItem.java b/src/main/java/net/minecraft/world/entity/item/EntityItem.java +index be46b8fcbfed932ba96a34c94eee0b237c783bd4..dd4997e7ffac4773e01add88efec7c0dcd7b4df0 100644 +--- a/src/main/java/net/minecraft/world/entity/item/EntityItem.java ++++ b/src/main/java/net/minecraft/world/entity/item/EntityItem.java +@@ -583,7 +583,7 @@ public class EntityItem extends Entity { + + // Paper start - fix MC-4 + public void setPositionRaw(double x, double y, double z) { +- if (false && com.destroystokyo.paper.PaperConfig.fixEntityPositionDesync) { // Tuinity - revert ++ if (com.destroystokyo.paper.PaperConfig.fixEntityPositionDesync) { // Tuinity - revert // Purpur - no + // encode/decode from PacketPlayOutEntity + x = MathHelper.floorLong(x * 4096.0D) * (1 / 4096.0D); + y = MathHelper.floorLong(y * 4096.0D) * (1 / 4096.0D); diff --git a/patches/Purpur/patches/server/0156-Add-mobGriefing-bypass-to-everything-affected.patch b/patches/Purpur/patches/server/0156-Add-mobGriefing-bypass-to-everything-affected.patch new file mode 100644 index 00000000..ff070a97 --- /dev/null +++ b/patches/Purpur/patches/server/0156-Add-mobGriefing-bypass-to-everything-affected.patch @@ -0,0 +1,559 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Encode42 +Date: Tue, 5 Jan 2021 22:21:56 -0500 +Subject: [PATCH] Add mobGriefing bypass to everything affected + +This adds the "bypass-mob-griefing" world config option to everything that is affected by the gamerule. + +diff --git a/src/main/java/net/minecraft/world/entity/EntityLiving.java b/src/main/java/net/minecraft/world/entity/EntityLiving.java +index 3b76a652a3888d7d0b7dfb13f9ebbf0732e71d71..0e46f6b4fedc0e0d65737a3553ab8cd8dbf68e7d 100644 +--- a/src/main/java/net/minecraft/world/entity/EntityLiving.java ++++ b/src/main/java/net/minecraft/world/entity/EntityLiving.java +@@ -1568,7 +1568,7 @@ public abstract class EntityLiving extends Entity { + boolean flag = false; + + if (this.killed && entityliving instanceof EntityWither) { // Paper +- if (this.world.getGameRules().getBoolean(GameRules.MOB_GRIEFING)) { ++ if (this.world.purpurConfig.witherBypassMobGriefing || this.world.getGameRules().getBoolean(GameRules.MOB_GRIEFING)) { // Purpur + BlockPosition blockposition = this.getChunkCoordinates(); + IBlockData iblockdata = Blocks.WITHER_ROSE.getBlockData(); + +diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoalBreakDoor.java b/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoalBreakDoor.java +index d785066e2a52699c18315f7244d80db6cab0c736..6c40b070c674f2b120b860b78a63d0a6635d2f5b 100644 +--- a/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoalBreakDoor.java ++++ b/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoalBreakDoor.java +@@ -34,7 +34,7 @@ public class PathfinderGoalBreakDoor extends PathfinderGoalDoorInteract { + + @Override + public boolean a() { +- return !super.a() ? false : (!this.entity.world.getGameRules().getBoolean(GameRules.MOB_GRIEFING) ? false : this.a(this.entity.world.getDifficulty()) && !this.g()); ++ return !super.a() ? false : ((!this.entity.world.purpurConfig.zombieBypassMobGriefing && !this.entity.world.getGameRules().getBoolean(GameRules.MOB_GRIEFING)) ? false : this.a(this.entity.world.getDifficulty()) && !this.g()); // Purpur + } + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoalEatTile.java b/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoalEatTile.java +index 6737dd77c8f46edf353f951b5adb4399142a1753..06dbce54602d02382e9d47b7e6925cfc686d26f6 100644 +--- a/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoalEatTile.java ++++ b/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoalEatTile.java +@@ -19,7 +19,7 @@ public class PathfinderGoalEatTile extends PathfinderGoal { + + private static final Predicate a = BlockStatePredicate.a(Blocks.GRASS); + private final EntityInsentient b; +- private final World c; ++ private final World c; private final World getWorld() { return c; } // Purpur - OBFHELPER + private int d; + + public PathfinderGoalEatTile(EntityInsentient entityinsentient) { +@@ -68,7 +68,7 @@ public class PathfinderGoalEatTile extends PathfinderGoal { + + if (PathfinderGoalEatTile.a.test(this.c.getType(blockposition))) { + // CraftBukkit +- if (!CraftEventFactory.callEntityChangeBlockEvent(this.b, blockposition, Blocks.AIR.getBlockData(), !this.c.getGameRules().getBoolean(GameRules.MOB_GRIEFING)).isCancelled()) { ++ if (!CraftEventFactory.callEntityChangeBlockEvent(this.b, blockposition, Blocks.AIR.getBlockData(), !this.getWorld().purpurConfig.sheepBypassMobGriefing && !this.c.getGameRules().getBoolean(GameRules.MOB_GRIEFING)).isCancelled()) { // Purpur + this.c.b(blockposition, false); + } + +@@ -78,7 +78,7 @@ public class PathfinderGoalEatTile extends PathfinderGoal { + + if (this.c.getType(blockposition1).a(Blocks.GRASS_BLOCK)) { + // CraftBukkit +- if (!CraftEventFactory.callEntityChangeBlockEvent(this.b, blockposition, Blocks.AIR.getBlockData(), !this.c.getGameRules().getBoolean(GameRules.MOB_GRIEFING)).isCancelled()) { ++ if (!CraftEventFactory.callEntityChangeBlockEvent(this.b, blockposition, Blocks.AIR.getBlockData(), !this.getWorld().purpurConfig.sheepBypassMobGriefing && !this.c.getGameRules().getBoolean(GameRules.MOB_GRIEFING)).isCancelled()) { // Purpur + this.c.triggerEffect(2001, blockposition1, Block.getCombinedId(Blocks.GRASS_BLOCK.getBlockData())); + this.c.setTypeAndData(blockposition1, Blocks.DIRT.getBlockData(), 2); + } +diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoalRemoveBlock.java b/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoalRemoveBlock.java +index 61a62c093b24c43064f116630d85096159e082d3..2519a78f7e5dd759680a1f47a1047885d4ad32f1 100644 +--- a/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoalRemoveBlock.java ++++ b/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoalRemoveBlock.java +@@ -41,7 +41,7 @@ public class PathfinderGoalRemoveBlock extends PathfinderGoalGotoTarget { + + @Override + public boolean a() { +- if (!this.entity.world.getGameRules().getBoolean(GameRules.MOB_GRIEFING)) { ++ if (!this.entity.world.purpurConfig.zombieBypassMobGriefing && !this.entity.world.getGameRules().getBoolean(GameRules.MOB_GRIEFING)) { // Purpur + return false; + } else if (this.c > 0) { + --this.c; +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityFox.java b/src/main/java/net/minecraft/world/entity/animal/EntityFox.java +index 5a2e624f1b6636f058cc69989324914f174a271a..03fee11004b27402ec9da39c617c226175242bb4 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityFox.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityFox.java +@@ -1073,7 +1073,7 @@ public class EntityFox extends EntityAnimal { + } + + protected void n() { +- if (EntityFox.this.world.getGameRules().getBoolean(GameRules.MOB_GRIEFING)) { ++ if (EntityFox.this.world.purpurConfig.foxBypassMobGriefing || EntityFox.this.world.getGameRules().getBoolean(GameRules.MOB_GRIEFING)) { // Purpur + IBlockData iblockdata = EntityFox.this.world.getType(this.e); + + if (iblockdata.a(Blocks.SWEET_BERRY_BUSH)) { +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityRabbit.java b/src/main/java/net/minecraft/world/entity/animal/EntityRabbit.java +index ef031ac08b06e78d8826579c49cf5e43683318f9..a5be1a9d4e6f08f23215b49a30c1121167cc7a89 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityRabbit.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityRabbit.java +@@ -517,7 +517,7 @@ public class EntityRabbit extends EntityAnimal { + @Override + public boolean a() { + if (this.c <= 0) { +- if (!this.entity.world.getGameRules().getBoolean(GameRules.MOB_GRIEFING)) { ++ if (!this.entity.world.purpurConfig.rabbitBypassMobGriefing && !this.entity.world.getGameRules().getBoolean(GameRules.MOB_GRIEFING)) { // Purpur + return false; + } + +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntitySnowman.java b/src/main/java/net/minecraft/world/entity/animal/EntitySnowman.java +index 3934966b06eb9880ed316cee84d099edd80c09b9..b13cd3f344a0e2c4c02b30f80ca9a81d93cc1954 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntitySnowman.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntitySnowman.java +@@ -123,7 +123,7 @@ public class EntitySnowman extends EntityGolem implements IShearable, IRangedEnt + this.damageEntity(CraftEventFactory.MELTING, 1.0F); // CraftBukkit - DamageSource.BURN -> CraftEventFactory.MELTING + } + +- if (!this.world.getGameRules().getBoolean(GameRules.MOB_GRIEFING)) { ++ if (!this.world.purpurConfig.snowGolemBypassMobGriefing && !this.world.getGameRules().getBoolean(GameRules.MOB_GRIEFING)) { // Purpur + return; + } + +diff --git a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EntityEnderDragon.java b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EntityEnderDragon.java +index aeff46b575a05145fb509b5e5a489b2067776e2f..0614483830336f3bbd348319ca3eed8767568852 100644 +--- a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EntityEnderDragon.java ++++ b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EntityEnderDragon.java +@@ -539,7 +539,7 @@ public class EntityEnderDragon extends EntityInsentient implements IMonster { + Block block = iblockdata.getBlock(); + + if (!iblockdata.isAir() && iblockdata.getMaterial() != Material.FIRE) { +- if (this.world.getGameRules().getBoolean(GameRules.MOB_GRIEFING) && !TagsBlock.DRAGON_IMMUNE.isTagged(block)) { ++ if ((this.world.purpurConfig.enderDragonBypassMobGriefing || this.world.getGameRules().getBoolean(GameRules.MOB_GRIEFING)) && !TagsBlock.DRAGON_IMMUNE.isTagged(block)) { // Purpur + // CraftBukkit start - Add blocks to list rather than destroying them + // flag1 = this.world.a(blockposition, false) || flag1; + flag1 = true; +diff --git a/src/main/java/net/minecraft/world/entity/boss/wither/EntityWither.java b/src/main/java/net/minecraft/world/entity/boss/wither/EntityWither.java +index 528161748472b0fb84718268800864e94ceaa079..fea99134e77d7cbc77c89318753e7294d3f6a15a 100644 +--- a/src/main/java/net/minecraft/world/entity/boss/wither/EntityWither.java ++++ b/src/main/java/net/minecraft/world/entity/boss/wither/EntityWither.java +@@ -378,7 +378,7 @@ public class EntityWither extends EntityMonster implements IRangedEntity { + if (this.getInvul() > 0) { + i = this.getInvul() - 1; + if (i <= 0) { +- Explosion.Effect explosion_effect = this.world.getGameRules().getBoolean(GameRules.MOB_GRIEFING) ? Explosion.Effect.DESTROY : Explosion.Effect.NONE; ++ Explosion.Effect explosion_effect = (this.world.purpurConfig.witherBypassMobGriefing || this.world.getGameRules().getBoolean(GameRules.MOB_GRIEFING)) ? Explosion.Effect.DESTROY : Explosion.Effect.NONE; // Purpur + // CraftBukkit start + // this.world.createExplosion(this, this.locX(), this.getHeadY(), this.locZ(), 7.0F, false, explosion_effect); + ExplosionPrimeEvent event = new ExplosionPrimeEvent(this.getBukkitEntity(), 7.0F, false); +@@ -490,7 +490,7 @@ public class EntityWither extends EntityMonster implements IRangedEntity { + + if (this.bw > 0) { + --this.bw; +- if (this.bw == 0 && this.world.getGameRules().getBoolean(GameRules.MOB_GRIEFING)) { ++ if (this.bw == 0 && (this.world.purpurConfig.witherBypassMobGriefing || this.world.getGameRules().getBoolean(GameRules.MOB_GRIEFING))) { // Purpur + i = MathHelper.floor(this.locY()); + j = MathHelper.floor(this.locX()); + int j1 = MathHelper.floor(this.locZ()); +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityEnderman.java b/src/main/java/net/minecraft/world/entity/monster/EntityEnderman.java +index 7c25a7610a5f18e21afead1290e4d879588845af..2992d173dc870eccdfc5f515d162844f19691d11 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityEnderman.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityEnderman.java +@@ -447,7 +447,7 @@ public class EntityEnderman extends EntityMonster implements IEntityAngerable { + @Override + public boolean a() { + if (!enderman.world.purpurConfig.endermanAllowGriefing) return false; // Purpur +- return this.enderman.getCarried() != null ? false : (!this.enderman.world.getGameRules().getBoolean(GameRules.MOB_GRIEFING) ? false : this.enderman.getRandom().nextInt(20) == 0); ++ return this.enderman.getCarried() != null ? false : (!this.enderman.world.purpurConfig.endermanBypassMobGriefing && !this.enderman.world.getGameRules().getBoolean(GameRules.MOB_GRIEFING) ? false : this.enderman.getRandom().nextInt(20) == 0); // Purpur + } + + @Override +@@ -490,7 +490,7 @@ public class EntityEnderman extends EntityMonster implements IEntityAngerable { + @Override + public boolean a() { + if (!getEnderman().world.purpurConfig.endermanAllowGriefing) return false; // Purpur +- return this.a.getCarried() == null ? false : (!this.a.world.getGameRules().getBoolean(GameRules.MOB_GRIEFING) ? false : this.a.getRandom().nextInt(2000) == 0); ++ return this.a.getCarried() == null ? false : (!this.a.world.purpurConfig.endermanBypassMobGriefing && !this.a.world.getGameRules().getBoolean(GameRules.MOB_GRIEFING) ? false : this.a.getRandom().nextInt(2000) == 0); // Purpur + } + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityEvoker.java b/src/main/java/net/minecraft/world/entity/monster/EntityEvoker.java +index 8d7b8d2ac9a7340e2cfd0d1b8963e4e4d97e8bc8..8a219ac18307c715913f5c2a80b1ff35a2ea8b93 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityEvoker.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityEvoker.java +@@ -171,7 +171,7 @@ public class EntityEvoker extends EntityIllagerWizard { + return false; + } else if (EntityEvoker.this.ticksLived < this.c) { + return false; +- } else if (!EntityEvoker.this.world.getGameRules().getBoolean(GameRules.MOB_GRIEFING)) { ++ } else if (!EntityEvoker.this.world.purpurConfig.evokerBypassMobGriefing && !EntityEvoker.this.world.getGameRules().getBoolean(GameRules.MOB_GRIEFING)) { // Purpur + return false; + } else { + List list = EntityEvoker.this.world.a(EntitySheep.class, this.e, EntityEvoker.this, EntityEvoker.this.getBoundingBox().grow(16.0D, 4.0D, 16.0D)); +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityRavager.java b/src/main/java/net/minecraft/world/entity/monster/EntityRavager.java +index 7e3b59e2302a27f7b8a3f43b75527199722a896f..16da85620c067b005ce029c8b9c5ea1642a794f0 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityRavager.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityRavager.java +@@ -178,7 +178,7 @@ public class EntityRavager extends EntityRaider { + this.getAttributeInstance(GenericAttributes.MOVEMENT_SPEED).setValue(MathHelper.d(0.1D, d1, d0)); + } + +- if (this.positionChanged && this.world.getGameRules().getBoolean(GameRules.MOB_GRIEFING)) { ++ if (this.positionChanged && (this.world.purpurConfig.ravagerBypassMobGriefing || this.world.getGameRules().getBoolean(GameRules.MOB_GRIEFING))) { // Purpur + boolean flag = false; + AxisAlignedBB axisalignedbb = this.getBoundingBox().g(0.2D); + Iterator iterator = BlockPosition.b(MathHelper.floor(axisalignedbb.minX), MathHelper.floor(axisalignedbb.minY), MathHelper.floor(axisalignedbb.minZ), MathHelper.floor(axisalignedbb.maxX), MathHelper.floor(axisalignedbb.maxY), MathHelper.floor(axisalignedbb.maxZ)).iterator(); +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntitySilverfish.java b/src/main/java/net/minecraft/world/entity/monster/EntitySilverfish.java +index a0a1e5977a3cbc8e9befd827dd1e15352a2c0c39..cbdb512c924ac54e925f8c52558d24d3286d31ce 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntitySilverfish.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntitySilverfish.java +@@ -172,7 +172,7 @@ public class EntitySilverfish extends EntityMonster { + } else { + Random random = this.a.getRandom(); + +- if (this.a.world.getGameRules().getBoolean(GameRules.MOB_GRIEFING) && random.nextInt(10) == 0) { ++ if ((this.a.world.purpurConfig.silverfishBypassMobGriefing || this.a.world.getGameRules().getBoolean(GameRules.MOB_GRIEFING)) && random.nextInt(10) == 0) { // Purpur + this.h = EnumDirection.a(random); + BlockPosition blockposition = (new BlockPosition(this.a.locX(), this.a.locY() + 0.5D, this.a.locZ())).shift(this.h); + IBlockData iblockdata = this.a.world.getType(blockposition); +@@ -260,7 +260,7 @@ public class EntitySilverfish extends EntityMonster { + continue; + } + // CraftBukkit end +- if (world.getGameRules().getBoolean(GameRules.MOB_GRIEFING)) { ++ if (world.purpurConfig.silverfishBypassMobGriefing || world.getGameRules().getBoolean(GameRules.MOB_GRIEFING)) { // Purpur + world.a(blockposition1, true, this.silverfish); + } else { + world.setTypeAndData(blockposition1, ((BlockMonsterEggs) block).c().getBlockData(), 3); +diff --git a/src/main/java/net/minecraft/world/entity/projectile/EntityLargeFireball.java b/src/main/java/net/minecraft/world/entity/projectile/EntityLargeFireball.java +index e860737bacfea0a1d728dbaaf41d62165658ad89..61f06eacb4ea4ef869b60c9014cc23b25583eead 100644 +--- a/src/main/java/net/minecraft/world/entity/projectile/EntityLargeFireball.java ++++ b/src/main/java/net/minecraft/world/entity/projectile/EntityLargeFireball.java +@@ -19,19 +19,19 @@ public class EntityLargeFireball extends EntityFireballFireball { + + public EntityLargeFireball(EntityTypes entitytypes, World world) { + super(entitytypes, world); +- isIncendiary = this.world.getGameRules().getBoolean(GameRules.MOB_GRIEFING); // CraftBukkit ++ isIncendiary = this.world.purpurConfig.fireballsBypassMobGriefing || this.world.getGameRules().getBoolean(GameRules.MOB_GRIEFING); // CraftBukkit // Purpur + } + + public EntityLargeFireball(World world, EntityLiving entityliving, double d0, double d1, double d2) { + super(EntityTypes.FIREBALL, entityliving, d0, d1, d2, world); +- isIncendiary = this.world.getGameRules().getBoolean(GameRules.MOB_GRIEFING); // CraftBukkit ++ isIncendiary = this.world.purpurConfig.fireballsBypassMobGriefing || this.world.getGameRules().getBoolean(GameRules.MOB_GRIEFING); // CraftBukkit // Purpur + } + + @Override + protected void a(MovingObjectPosition movingobjectposition) { + super.a(movingobjectposition); + if (!this.world.isClientSide) { +- boolean flag = this.world.getGameRules().getBoolean(GameRules.MOB_GRIEFING); ++ boolean flag = this.world.purpurConfig.fireballsBypassMobGriefing || this.world.getGameRules().getBoolean(GameRules.MOB_GRIEFING); // Purpur + + // CraftBukkit start - fire ExplosionPrimeEvent + ExplosionPrimeEvent event = new ExplosionPrimeEvent((org.bukkit.entity.Explosive) this.getBukkitEntity()); +diff --git a/src/main/java/net/minecraft/world/entity/projectile/EntitySmallFireball.java b/src/main/java/net/minecraft/world/entity/projectile/EntitySmallFireball.java +index bf747cbf6e1ef9ea9d1d41d0441b29a46ce874c0..53e02e512b8bcebac105e421991b3554a7ad699a 100644 +--- a/src/main/java/net/minecraft/world/entity/projectile/EntitySmallFireball.java ++++ b/src/main/java/net/minecraft/world/entity/projectile/EntitySmallFireball.java +@@ -26,7 +26,7 @@ public class EntitySmallFireball extends EntityFireballFireball { + super(EntityTypes.SMALL_FIREBALL, entityliving, d0, d1, d2, world); + // CraftBukkit start + if (this.getShooter() != null && this.getShooter() instanceof EntityInsentient) { +- isIncendiary = this.world.getGameRules().getBoolean(GameRules.MOB_GRIEFING); ++ isIncendiary = this.world.purpurConfig.fireballsBypassMobGriefing || this.world.getGameRules().getBoolean(GameRules.MOB_GRIEFING); // Purpur + } + // CraftBukkit end + } +diff --git a/src/main/java/net/minecraft/world/entity/projectile/EntityWitherSkull.java b/src/main/java/net/minecraft/world/entity/projectile/EntityWitherSkull.java +index 2fe0e32a1158cccb3060f5a986c9fc41a0237aa8..616b5267d1d94b2be37ec48983b45e4478502fb5 100644 +--- a/src/main/java/net/minecraft/world/entity/projectile/EntityWitherSkull.java ++++ b/src/main/java/net/minecraft/world/entity/projectile/EntityWitherSkull.java +@@ -94,7 +94,7 @@ public class EntityWitherSkull extends EntityFireball { + protected void a(MovingObjectPosition movingobjectposition) { + super.a(movingobjectposition); + if (!this.world.isClientSide) { +- Explosion.Effect explosion_effect = this.world.getGameRules().getBoolean(GameRules.MOB_GRIEFING) ? Explosion.Effect.DESTROY : Explosion.Effect.NONE; ++ Explosion.Effect explosion_effect = (this.world.purpurConfig.witherBypassMobGriefing || this.world.getGameRules().getBoolean(GameRules.MOB_GRIEFING)) ? Explosion.Effect.DESTROY : Explosion.Effect.NONE; // Purpur + + // CraftBukkit start + // this.world.createExplosion(this, this.locX(), this.locY(), this.locZ(), 1.0F, false, explosion_effect); +diff --git a/src/main/java/net/minecraft/world/entity/raid/EntityRaider.java b/src/main/java/net/minecraft/world/entity/raid/EntityRaider.java +index ff41ee884e3e46af1b1e9fb550f0abc6998fd031..8eec32af12c69e1963dcd304a25ec4811b2f1f5a 100644 +--- a/src/main/java/net/minecraft/world/entity/raid/EntityRaider.java ++++ b/src/main/java/net/minecraft/world/entity/raid/EntityRaider.java +@@ -532,7 +532,7 @@ public abstract class EntityRaider extends EntityMonsterPatrolling { + + @Override + public boolean a() { +- if (!getRaider().world.getGameRules().getBoolean(GameRules.MOB_GRIEFING) || !getRaider().canPickupLoot()) return false; // Paper - respect game and entity rules for picking up items ++ if ((!getRaider().world.purpurConfig.pillagerBypassMobGriefing && !getRaider().world.getGameRules().getBoolean(GameRules.MOB_GRIEFING)) || !getRaider().canPickupLoot()) return false; // Paper - respect game and entity rules for picking up items // Purpur + Raid raid = this.b.fa(); + + if (this.b.fb() && !this.b.fa().a() && this.b.eN() && !ItemStack.matches(this.b.getEquipment(EnumItemSlot.HEAD), Raid.s())) { +diff --git a/src/main/java/net/minecraft/world/level/block/BlockCampfire.java b/src/main/java/net/minecraft/world/level/block/BlockCampfire.java +index 023128e5c737ad26e40e4019e70df856395addcb..bb071b5053442fcbc20b00bd84cd8a37fdf7a314 100644 +--- a/src/main/java/net/minecraft/world/level/block/BlockCampfire.java ++++ b/src/main/java/net/minecraft/world/level/block/BlockCampfire.java +@@ -182,7 +182,7 @@ public class BlockCampfire extends BlockTileEntity implements IBlockWaterlogged + public void a(World world, IBlockData iblockdata, MovingObjectPositionBlock movingobjectpositionblock, IProjectile iprojectile) { + if (!world.isClientSide && iprojectile.isBurning()) { + Entity entity = iprojectile.getShooter(); +- boolean flag = entity == null || entity instanceof EntityHuman || world.getGameRules().getBoolean(GameRules.MOB_GRIEFING); ++ boolean flag = entity == null || entity instanceof EntityHuman || world.purpurConfig.fireballsBypassMobGriefing || world.getGameRules().getBoolean(GameRules.MOB_GRIEFING); // Purpur + + if (flag && !(Boolean) iblockdata.get(BlockCampfire.LIT) && !(Boolean) iblockdata.get(BlockCampfire.d)) { + BlockPosition blockposition = movingobjectpositionblock.getBlockPosition(); +diff --git a/src/main/java/net/minecraft/world/level/block/BlockCrops.java b/src/main/java/net/minecraft/world/level/block/BlockCrops.java +index 32d71b6fc3fd0300386fb80e6d12d5f7c2361efe..55ad7693ced8bab5bc8b36a375c85370e84ccb77 100644 +--- a/src/main/java/net/minecraft/world/level/block/BlockCrops.java ++++ b/src/main/java/net/minecraft/world/level/block/BlockCrops.java +@@ -161,7 +161,7 @@ public class BlockCrops extends BlockPlant implements IBlockFragilePlantElement + @Override + public void a(IBlockData iblockdata, World world, BlockPosition blockposition, Entity entity) { + if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(world, blockposition)).callEvent()) { return; } // Paper +- if (entity instanceof EntityRavager && !CraftEventFactory.callEntityChangeBlockEvent(entity, blockposition, Blocks.AIR.getBlockData(), !world.getGameRules().getBoolean(GameRules.MOB_GRIEFING)).isCancelled()) { // CraftBukkit ++ if (entity instanceof EntityRavager && !CraftEventFactory.callEntityChangeBlockEvent(entity, blockposition, Blocks.AIR.getBlockData(), (!world.purpurConfig.ravagerBypassMobGriefing && !world.getGameRules().getBoolean(GameRules.MOB_GRIEFING))).isCancelled()) { // CraftBukkit // Purpur + world.a(blockposition, true, entity); + } + +diff --git a/src/main/java/net/minecraft/world/level/block/BlockSoil.java b/src/main/java/net/minecraft/world/level/block/BlockSoil.java +index f00eb3cda60f6f8b2534c3da5ffaa6faee334663..386641173bb758c1ba1e80071f68813fec012a93 100644 +--- a/src/main/java/net/minecraft/world/level/block/BlockSoil.java ++++ b/src/main/java/net/minecraft/world/level/block/BlockSoil.java +@@ -99,7 +99,7 @@ public class BlockSoil extends Block { + @Override + public void fallOn(World world, BlockPosition blockposition, Entity entity, float f) { + super.fallOn(world, blockposition, entity, f); // CraftBukkit - moved here as game rules / events shouldn't affect fall damage. +- if (!world.isClientSide && world.random.nextFloat() < f - 0.5F && entity instanceof EntityLiving && (entity instanceof EntityHuman || world.getGameRules().getBoolean(GameRules.MOB_GRIEFING)) && entity.getWidth() * entity.getWidth() * entity.getHeight() > 0.512F) { ++ if (!world.isClientSide && world.random.nextFloat() < f - 0.5F && entity instanceof EntityLiving && (entity instanceof EntityHuman || world.purpurConfig.farmlandBypassMobGriefing || world.getGameRules().getBoolean(GameRules.MOB_GRIEFING)) && entity.getWidth() * entity.getWidth() * entity.getHeight() > 0.512F) { // Purpur + // CraftBukkit start - Interact soil + org.bukkit.event.Cancellable cancellable; + if (entity instanceof EntityHuman) { +diff --git a/src/main/java/net/minecraft/world/level/block/BlockTurtleEgg.java b/src/main/java/net/minecraft/world/level/block/BlockTurtleEgg.java +index 04504901b1933ed760b34b8abb994de8ec340a4e..e18be05c9a9230105ec54395d4391c86132e7930 100644 +--- a/src/main/java/net/minecraft/world/level/block/BlockTurtleEgg.java ++++ b/src/main/java/net/minecraft/world/level/block/BlockTurtleEgg.java +@@ -206,7 +206,7 @@ public class BlockTurtleEgg extends Block { + return false; + } + if (entity instanceof EntityLiving && !(entity instanceof EntityHuman)) { +- return world.getGameRules().getBoolean(GameRules.MOB_GRIEFING); ++ return world.purpurConfig.turtleEggsBypassMobGriefing || world.getGameRules().getBoolean(GameRules.MOB_GRIEFING); // Purpur + } + return true; + // Purpur end +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 318513f5612a694c2b240840b24a39210457c202..6943af6037c1b8832c2fa652b92b9a2badf8bac5 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -296,6 +296,7 @@ public class PurpurWorldConfig { + public boolean disableDropsOnCrammingDeath = false; + public boolean entitiesPickUpLootBypassMobGriefing = false; + public boolean entitiesCanUsePortals = true; ++ public boolean fireballsBypassMobGriefing = false; + public boolean milkCuresBadOmen = true; + public boolean persistentTileEntityDisplayNames = false; + public boolean persistentDroppableEntityDisplayNames = false; +@@ -311,6 +312,7 @@ public class PurpurWorldConfig { + disableDropsOnCrammingDeath = getBoolean("gameplay-mechanics.disable-drops-on-cramming-death", disableDropsOnCrammingDeath); + entitiesPickUpLootBypassMobGriefing = getBoolean("gameplay-mechanics.entities-pick-up-loot-bypass-mob-griefing", entitiesPickUpLootBypassMobGriefing); + entitiesCanUsePortals = getBoolean("gameplay-mechanics.entities-can-use-portals", entitiesCanUsePortals); ++ fireballsBypassMobGriefing = getBoolean("gameplay-mechanics.fireballs-bypass-mob-griefing", fireballsBypassMobGriefing); + milkCuresBadOmen = getBoolean("gameplay-mechanics.milk-cures-bad-omen", milkCuresBadOmen); + persistentTileEntityDisplayNames = getBoolean("gameplay-mechanics.persistent-tileentity-display-names-and-lore", persistentTileEntityDisplayNames); + persistentDroppableEntityDisplayNames = getBoolean("gameplay-mechanics.persistent-droppable-entity-display-names", persistentDroppableEntityDisplayNames); +@@ -464,9 +466,11 @@ public class PurpurWorldConfig { + dispenserPlaceAnvils = getBoolean("blocks.dispenser.place-anvils", dispenserPlaceAnvils); + } + ++ public boolean farmlandBypassMobGriefing = false; + public boolean farmlandGetsMoistFromBelow = false; + public boolean farmlandAlpha = false; + private void farmlandSettings() { ++ farmlandBypassMobGriefing = getBoolean("blocks.farmland.bypass-mob-griefing", farmlandBypassMobGriefing); + farmlandGetsMoistFromBelow = getBoolean("blocks.farmland.gets-moist-from-below", farmlandGetsMoistFromBelow); + farmlandAlpha = getBoolean("blocks.farmland.use-alpha-farmland", farmlandAlpha); + } +@@ -525,10 +529,12 @@ public class PurpurWorldConfig { + stonecutterDamage = (float) getDouble("blocks.stonecutter.damage", stonecutterDamage); + } + ++ public boolean turtleEggsBypassMobGriefing = false; + public boolean turtleEggsBreakFromExpOrbs = true; + public boolean turtleEggsBreakFromItems = true; + public boolean turtleEggsBreakFromMinecarts = true; + private void turtleEggSettings() { ++ turtleEggsBypassMobGriefing = getBoolean("blocks.turtle_egg.bypass-mob-griefing", turtleEggsBypassMobGriefing); + turtleEggsBreakFromExpOrbs = getBoolean("blocks.turtle_egg.break-from-exp-orbs", turtleEggsBreakFromExpOrbs); + turtleEggsBreakFromItems = getBoolean("blocks.turtle_egg.break-from-items", turtleEggsBreakFromItems); + turtleEggsBreakFromMinecarts = getBoolean("blocks.turtle_egg.break-from-minecarts", turtleEggsBreakFromMinecarts); +@@ -800,12 +806,14 @@ public class PurpurWorldConfig { + public boolean enderDragonRidableInWater = false; + public double enderDragonMaxY = 256D; + public boolean enderDragonAlwaysDropsFullExp = false; ++ public boolean enderDragonBypassMobGriefing = false; + public double enderDragonMaxHealth = 200.0D; + private void enderDragonSettings() { + enderDragonRidable = getBoolean("mobs.ender_dragon.ridable", enderDragonRidable); + enderDragonRidableInWater = getBoolean("mobs.ender_dragon.ridable-in-water", enderDragonRidableInWater); + enderDragonMaxY = getDouble("mobs.ender_dragon.ridable-max-y", enderDragonMaxY); + enderDragonAlwaysDropsFullExp = getBoolean("mobs.ender_dragon.always-drop-full-exp", enderDragonAlwaysDropsFullExp); ++ enderDragonBypassMobGriefing = getBoolean("mobs.ender_dragon.bypass-mob-griefing", enderDragonBypassMobGriefing); + if (PurpurConfig.version < 8) { + double oldValue = getDouble("mobs.ender_dragon.max-health", enderDragonMaxHealth); + set("mobs.ender_dragon.max-health", null); +@@ -821,12 +829,14 @@ public class PurpurWorldConfig { + public boolean endermanRidable = false; + public boolean endermanRidableInWater = false; + public boolean endermanAllowGriefing = true; ++ public boolean endermanBypassMobGriefing = false; + public boolean endermanDespawnEvenWithBlock = false; + public double endermanMaxHealth = 40.0D; + private void endermanSettings() { + endermanRidable = getBoolean("mobs.enderman.ridable", endermanRidable); + endermanRidableInWater = getBoolean("mobs.enderman.ridable-in-water", endermanRidableInWater); + endermanAllowGriefing = getBoolean("mobs.enderman.allow-griefing", endermanAllowGriefing); ++ endermanBypassMobGriefing = getBoolean("mobs.enderman.bypass-mob-griefing", endermanBypassMobGriefing); + endermanDespawnEvenWithBlock = getBoolean("mobs.enderman.can-despawn-with-held-block", endermanDespawnEvenWithBlock); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.enderman.attributes.max-health", endermanMaxHealth); +@@ -852,10 +862,12 @@ public class PurpurWorldConfig { + + public boolean evokerRidable = false; + public boolean evokerRidableInWater = false; ++ public boolean evokerBypassMobGriefing = false; + public double evokerMaxHealth = 24.0D; + private void evokerSettings() { + evokerRidable = getBoolean("mobs.evoker.ridable", evokerRidable); + evokerRidableInWater = getBoolean("mobs.evoker.ridable-in-water", evokerRidableInWater); ++ evokerBypassMobGriefing = getBoolean("mobs.evoker.bypass-mob-griefing", evokerBypassMobGriefing); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.evoker.attributes.max-health", evokerMaxHealth); + set("mobs.evoker.attributes.max-health", null); +@@ -866,12 +878,14 @@ public class PurpurWorldConfig { + + public boolean foxRidable = false; + public boolean foxRidableInWater = false; ++ public boolean foxBypassMobGriefing = false; + public boolean foxTypeChangesWithTulips = false; + public int foxBreedingTicks = 6000; + public double foxMaxHealth = 10.0D; + private void foxSettings() { + foxRidable = getBoolean("mobs.fox.ridable", foxRidable); + foxRidableInWater = getBoolean("mobs.fox.ridable-in-water", foxRidableInWater); ++ foxBypassMobGriefing = getBoolean("mobs.fox.bypass-mob-griefing", foxBypassMobGriefing); + foxTypeChangesWithTulips = getBoolean("mobs.fox.tulips-change-type", foxTypeChangesWithTulips); + foxBreedingTicks = getInt("mobs.fox.breeding-delay-ticks", foxBreedingTicks); + if (PurpurConfig.version < 10) { +@@ -1308,10 +1322,12 @@ public class PurpurWorldConfig { + + public boolean pillagerRidable = false; + public boolean pillagerRidableInWater = false; ++ public boolean pillagerBypassMobGriefing = false; + public double pillagerMaxHealth = 24.0D; + private void pillagerSettings() { + pillagerRidable = getBoolean("mobs.pillager.ridable", pillagerRidable); + pillagerRidableInWater = getBoolean("mobs.pillager.ridable-in-water", pillagerRidableInWater); ++ pillagerBypassMobGriefing = getBoolean("mobs.pillager.bypass-mob-griefing", pillagerBypassMobGriefing); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.pillager.attributes.max-health", pillagerMaxHealth); + set("mobs.pillager.attributes.max-health", null); +@@ -1355,6 +1371,7 @@ public class PurpurWorldConfig { + + public boolean rabbitRidable = false; + public boolean rabbitRidableInWater = false; ++ public boolean rabbitBypassMobGriefing = false; + public double rabbitNaturalToast = 0.0D; + public double rabbitNaturalKiller = 0.0D; + public int rabbitBreedingTicks = 6000; +@@ -1362,6 +1379,7 @@ public class PurpurWorldConfig { + private void rabbitSettings() { + rabbitRidable = getBoolean("mobs.rabbit.ridable", rabbitRidable); + rabbitRidableInWater = getBoolean("mobs.rabbit.ridable-in-water", rabbitRidableInWater); ++ rabbitBypassMobGriefing = getBoolean("mobs.rabbit.bypass-mob-griefing", rabbitBypassMobGriefing); + rabbitNaturalToast = getDouble("mobs.rabbit.spawn-toast-chance", rabbitNaturalToast); + rabbitNaturalKiller = getDouble("mobs.rabbit.spawn-killer-rabbit-chance", rabbitNaturalKiller); + rabbitBreedingTicks = getInt("mobs.rabbit.breeding-delay-ticks", rabbitBreedingTicks); +@@ -1375,10 +1393,12 @@ public class PurpurWorldConfig { + + public boolean ravagerRidable = false; + public boolean ravagerRidableInWater = false; ++ public boolean ravagerBypassMobGriefing = false; + public double ravagerMaxHealth = 100.0D; + private void ravagerSettings() { + ravagerRidable = getBoolean("mobs.ravager.ridable", ravagerRidable); + ravagerRidableInWater = getBoolean("mobs.ravager.ridable-in-water", ravagerRidableInWater); ++ ravagerBypassMobGriefing = getBoolean("mobs.ravager.bypass-mob-griefing", ravagerBypassMobGriefing); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.ravager.attributes.max-health", ravagerMaxHealth); + set("mobs.ravager.attributes.max-health", null); +@@ -1402,11 +1422,13 @@ public class PurpurWorldConfig { + public boolean sheepRidable = false; + public boolean sheepRidableInWater = false; + public int sheepBreedingTicks = 6000; ++ public boolean sheepBypassMobGriefing = false; + public double sheepMaxHealth = 8.0D; + private void sheepSettings() { + sheepRidable = getBoolean("mobs.sheep.ridable", sheepRidable); + sheepRidableInWater = getBoolean("mobs.sheep.ridable-in-water", sheepRidableInWater); + sheepBreedingTicks = getInt("mobs.sheep.breeding-delay-ticks", sheepBreedingTicks); ++ sheepBypassMobGriefing = getBoolean("mobs.sheep.bypass-mob-griefing", sheepBypassMobGriefing); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.sheep.attributes.max-health", sheepMaxHealth); + set("mobs.sheep.attributes.max-health", null); +@@ -1431,10 +1453,12 @@ public class PurpurWorldConfig { + + public boolean silverfishRidable = false; + public boolean silverfishRidableInWater = false; ++ public boolean silverfishBypassMobGriefing = false; + public double silverfishMaxHealth = 8.0D; + private void silverfishSettings() { + silverfishRidable = getBoolean("mobs.silverfish.ridable", silverfishRidable); + silverfishRidableInWater = getBoolean("mobs.silverfish.ridable-in-water", silverfishRidableInWater); ++ silverfishBypassMobGriefing = getBoolean("mobs.silverfish.bypass-mob-griefing", silverfishBypassMobGriefing); + if (PurpurConfig.version < 10) { + double oldValue = getDouble("mobs.silverfish.attributes.max-health", silverfishMaxHealth); + set("mobs.silverfish.attributes.max-health", null); +@@ -1501,6 +1525,7 @@ public class PurpurWorldConfig { + public boolean snowGolemRidable = false; + public boolean snowGolemRidableInWater = false; + public boolean snowGolemLeaveTrailWhenRidden = false; ++ public boolean snowGolemBypassMobGriefing = false; + public boolean snowGolemDropsPumpkin = true; + public boolean snowGolemPutPumpkinBack = false; + public int snowGolemSnowBallMin = 20; +@@ -1512,6 +1537,7 @@ public class PurpurWorldConfig { + snowGolemRidable = getBoolean("mobs.snow_golem.ridable", snowGolemRidable); + snowGolemRidableInWater = getBoolean("mobs.snow_golem.ridable-in-water", snowGolemRidableInWater); + snowGolemLeaveTrailWhenRidden = getBoolean("mobs.snow_golem.leave-trail-when-ridden", snowGolemLeaveTrailWhenRidden); ++ snowGolemBypassMobGriefing = getBoolean("mobs.snow_golem.bypass-mob-griefing", snowGolemBypassMobGriefing); + snowGolemDropsPumpkin = getBoolean("mobs.snow_golem.drop-pumpkin-when-sheared", snowGolemDropsPumpkin); + snowGolemPutPumpkinBack = getBoolean("mobs.snow_golem.pumpkin-can-be-added-back", snowGolemPutPumpkinBack); + snowGolemSnowBallMin = getInt("mobs.snow_golem.min-shoot-interval-ticks", snowGolemSnowBallMin); +@@ -1730,6 +1756,7 @@ public class PurpurWorldConfig { + public boolean witherRidable = false; + public boolean witherRidableInWater = false; + public double witherMaxY = 256D; ++ public boolean witherBypassMobGriefing = false; + public float witherHealthRegenAmount = 1.0f; + public int witherHealthRegenDelay = 20; + public double witherMaxHealth = 300.0D; +@@ -1737,6 +1764,7 @@ public class PurpurWorldConfig { + witherRidable = getBoolean("mobs.wither.ridable", witherRidable); + witherRidableInWater = getBoolean("mobs.wither.ridable-in-water", witherRidableInWater); + witherMaxY = getDouble("mobs.wither.ridable-max-y", witherMaxY); ++ witherBypassMobGriefing = getBoolean("mobs.wither.bypass-mob-griefing", witherBypassMobGriefing); + witherHealthRegenAmount = (float) getDouble("mobs.wither.health-regen-amount", witherHealthRegenAmount); + witherHealthRegenDelay = getInt("mobs.wither.health-regen-delay", witherHealthRegenDelay); + if (PurpurConfig.version < 8) { +@@ -1809,6 +1837,7 @@ public class PurpurWorldConfig { + + public boolean zombieRidable = false; + public boolean zombieRidableInWater = false; ++ public boolean zombieBypassMobGriefing = false; + public boolean zombieJockeyOnlyBaby = true; + public double zombieJockeyChance = 0.05D; + public boolean zombieJockeyTryExistingChickens = true; +@@ -1819,6 +1848,7 @@ public class PurpurWorldConfig { + private void zombieSettings() { + zombieRidable = getBoolean("mobs.zombie.ridable", zombieRidable); + zombieRidableInWater = getBoolean("mobs.zombie.ridable-in-water", zombieRidableInWater); ++ zombieBypassMobGriefing = getBoolean("mobs.zombie.bypass-mob-griefing", zombieBypassMobGriefing); + zombieJockeyOnlyBaby = getBoolean("mobs.zombie.jockey.only-babies", zombieJockeyOnlyBaby); + zombieJockeyChance = getDouble("mobs.zombie.jockey.chance", zombieJockeyChance); + zombieJockeyTryExistingChickens = getBoolean("mobs.zombie.jockey.try-existing-chickens", zombieJockeyTryExistingChickens); diff --git a/patches/Purpur/patches/server/0157-Config-to-allow-Note-Block-sounds-when-blocked.patch b/patches/Purpur/patches/server/0157-Config-to-allow-Note-Block-sounds-when-blocked.patch new file mode 100644 index 00000000..5f989a53 --- /dev/null +++ b/patches/Purpur/patches/server/0157-Config-to-allow-Note-Block-sounds-when-blocked.patch @@ -0,0 +1,43 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Encode42 +Date: Fri, 8 Jan 2021 16:07:32 -0500 +Subject: [PATCH] Config to allow Note Block sounds when blocked + +Allows for Note Blocks to ignore whether or not there's air above them to play. + +Normally, the sounds will only play when the block directly above is air. +With this patch enabled, players can place any block above the Note Block and it will still work. + +diff --git a/src/main/java/net/minecraft/world/level/block/BlockNote.java b/src/main/java/net/minecraft/world/level/block/BlockNote.java +index 148718f8f96d94e76a4a7a96d5955b624c2dc661..075987567cd4412c8f0fb4e31b78639415f6adba 100644 +--- a/src/main/java/net/minecraft/world/level/block/BlockNote.java ++++ b/src/main/java/net/minecraft/world/level/block/BlockNote.java +@@ -61,7 +61,7 @@ public class BlockNote extends Block { + } + + private void play(World world, BlockPosition blockposition, IBlockData data) { // CraftBukkit +- if (world.getType(blockposition.up()).isAir()) { ++ if (world.purpurConfig.noteBlockIgnoreAbove || world.getType(blockposition.up()).isAir()) { + // CraftBukkit start + org.bukkit.event.block.NotePlayEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callNotePlayEvent(world, blockposition, data.get(BlockNote.INSTRUMENT), data.get(BlockNote.NOTE)); + if (!event.isCancelled()) { +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 6943af6037c1b8832c2fa652b92b9a2badf8bac5..a0df754d98e4be46720ba0962bdf7bf62f3425bb 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -298,6 +298,7 @@ public class PurpurWorldConfig { + public boolean entitiesCanUsePortals = true; + public boolean fireballsBypassMobGriefing = false; + public boolean milkCuresBadOmen = true; ++ public boolean noteBlockIgnoreAbove = false; + public boolean persistentTileEntityDisplayNames = false; + public boolean persistentDroppableEntityDisplayNames = false; + public double tridentLoyaltyVoidReturnHeight = 0.0D; +@@ -314,6 +315,7 @@ public class PurpurWorldConfig { + entitiesCanUsePortals = getBoolean("gameplay-mechanics.entities-can-use-portals", entitiesCanUsePortals); + fireballsBypassMobGriefing = getBoolean("gameplay-mechanics.fireballs-bypass-mob-griefing", fireballsBypassMobGriefing); + milkCuresBadOmen = getBoolean("gameplay-mechanics.milk-cures-bad-omen", milkCuresBadOmen); ++ noteBlockIgnoreAbove = getBoolean("gameplay-mechanics.note-block-ignore-above", noteBlockIgnoreAbove); + persistentTileEntityDisplayNames = getBoolean("gameplay-mechanics.persistent-tileentity-display-names-and-lore", persistentTileEntityDisplayNames); + persistentDroppableEntityDisplayNames = getBoolean("gameplay-mechanics.persistent-droppable-entity-display-names", persistentDroppableEntityDisplayNames); + tridentLoyaltyVoidReturnHeight = getDouble("gameplay-mechanics.trident-loyalty-void-return-height", tridentLoyaltyVoidReturnHeight); diff --git a/patches/Purpur/patches/server/0158-Add-EntityTeleportHinderedEvent.patch b/patches/Purpur/patches/server/0158-Add-EntityTeleportHinderedEvent.patch new file mode 100644 index 00000000..40d7ad23 --- /dev/null +++ b/patches/Purpur/patches/server/0158-Add-EntityTeleportHinderedEvent.patch @@ -0,0 +1,147 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Mariell Hoversholm +Date: Sat, 9 Jan 2021 15:27:46 +0100 +Subject: [PATCH] Add EntityTeleportHinderedEvent + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +diff --git a/src/main/java/net/minecraft/world/level/block/BlockEnderPortal.java b/src/main/java/net/minecraft/world/level/block/BlockEnderPortal.java +index 9483d75fbe2a8c8f7cce00355e93ff1f943f3444..31eabc40562462f98cc039a55453f200ca4eaa5c 100644 +--- a/src/main/java/net/minecraft/world/level/block/BlockEnderPortal.java ++++ b/src/main/java/net/minecraft/world/level/block/BlockEnderPortal.java +@@ -44,7 +44,15 @@ public class BlockEnderPortal extends BlockTileEntity { + @Override + public void a(IBlockData iblockdata, World world, BlockPosition blockposition, Entity entity) { + if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(world, blockposition)).callEvent()) { return; } // Paper +- if (world instanceof WorldServer && !entity.isPassenger() && !entity.isVehicle() && entity.canPortal() && VoxelShapes.c(VoxelShapes.a(entity.getBoundingBox().d((double) (-blockposition.getX()), (double) (-blockposition.getY()), (double) (-blockposition.getZ()))), iblockdata.getShape(world, blockposition), OperatorBoolean.AND)) { ++ // Purpur start ++ if (world instanceof WorldServer && /*!entity.isPassenger() && !entity.isVehicle() &&*/ entity.canPortal() && VoxelShapes.c(VoxelShapes.a(entity.getBoundingBox().d((double) (-blockposition.getX()), (double) (-blockposition.getY()), (double) (-blockposition.getZ()))), iblockdata.getShape(world, blockposition), OperatorBoolean.AND)) { ++ if (entity.isPassenger() || entity.isVehicle()) { ++ if (new net.pl3x.purpur.event.entity.EntityTeleportHinderedEvent(entity.getBukkitEntity(), entity.isPassenger() ? net.pl3x.purpur.event.entity.EntityTeleportHinderedEvent.Reason.IS_PASSENGER : net.pl3x.purpur.event.entity.EntityTeleportHinderedEvent.Reason.IS_VEHICLE, PlayerTeleportEvent.TeleportCause.END_PORTAL).callEvent()) { ++ this.collideWithBlock(iblockdata, world, blockposition, entity); ++ } ++ return; ++ } ++ // Purpur end + ResourceKey resourcekey = world.getTypeKey() == DimensionManager.THE_END ? World.OVERWORLD : World.THE_END; // CraftBukkit - SPIGOT-6152: send back to main overworld in custom ends + WorldServer worldserver = ((WorldServer) world).getMinecraftServer().getWorldServer(resourcekey); + +diff --git a/src/main/java/net/minecraft/world/level/block/BlockPortal.java b/src/main/java/net/minecraft/world/level/block/BlockPortal.java +index f030aa3ddd001e018539ae93c238f2afb26e0fc2..41733979141ed62523e9058a3f4c4ea753bfbc64 100644 +--- a/src/main/java/net/minecraft/world/level/block/BlockPortal.java ++++ b/src/main/java/net/minecraft/world/level/block/BlockPortal.java +@@ -83,7 +83,15 @@ public class BlockPortal extends Block { + @Override + public void a(IBlockData iblockdata, World world, BlockPosition blockposition, Entity entity) { + if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(world, blockposition)).callEvent()) { return; } // Paper +- if (!entity.isPassenger() && !entity.isVehicle() && entity.canPortal()) { ++ // Purpur start ++ if (/*!entity.isPassenger() && !entity.isVehicle() &&*/ entity.canPortal()) { ++ if (entity.isPassenger() || entity.isVehicle()) { ++ if (new net.pl3x.purpur.event.entity.EntityTeleportHinderedEvent(entity.getBukkitEntity(), entity.isPassenger() ? net.pl3x.purpur.event.entity.EntityTeleportHinderedEvent.Reason.IS_PASSENGER : net.pl3x.purpur.event.entity.EntityTeleportHinderedEvent.Reason.IS_VEHICLE, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.NETHER_PORTAL).callEvent()) { ++ this.collideWithBlock(iblockdata, world, blockposition, entity); ++ } ++ return; ++ } ++ // Purpur end + // CraftBukkit start - Entity in portal + EntityPortalEnterEvent event = new EntityPortalEnterEvent(entity.getBukkitEntity(), new org.bukkit.Location(world.getWorld(), blockposition.getX(), blockposition.getY(), blockposition.getZ())); + world.getServer().getPluginManager().callEvent(event); +diff --git a/src/main/java/net/minecraft/world/level/block/entity/TileEntityEndGateway.java b/src/main/java/net/minecraft/world/level/block/entity/TileEntityEndGateway.java +index d918194e45953764fa3fd286b715714330a60941..70496562faa89e92da34a4f7b891f845d1d55012 100644 +--- a/src/main/java/net/minecraft/world/level/block/entity/TileEntityEndGateway.java ++++ b/src/main/java/net/minecraft/world/level/block/entity/TileEntityEndGateway.java +@@ -151,9 +151,18 @@ public class TileEntityEndGateway extends TileEntityEnderPortal implements ITick + } + } + ++ public final void teleportEntity(Entity entity) { this.b(entity); } // Purpur - OBFHELPER + public void b(Entity entity) { + if (this.world instanceof WorldServer && !this.f()) { + if (!entity.canPortal()) return; // Purpur ++ // Purpur start ++ if (this.world.purpurConfig.imposeTeleportRestrictionsOnGateways && (entity.isVehicle() || entity.isPassenger())) { ++ if (new net.pl3x.purpur.event.entity.EntityTeleportHinderedEvent(entity.getBukkitEntity(), entity.isPassenger() ? net.pl3x.purpur.event.entity.EntityTeleportHinderedEvent.Reason.IS_PASSENGER : net.pl3x.purpur.event.entity.EntityTeleportHinderedEvent.Reason.IS_VEHICLE, PlayerTeleportEvent.TeleportCause.END_GATEWAY).callEvent()) { ++ this.teleportEntity(entity); ++ } ++ return; ++ } ++ // Purpur end + this.c = 100; + if (this.exitPortal == null && this.world.getTypeKey() == DimensionManager.THE_END) { // CraftBukkit - work in alternate worlds + this.a((WorldServer) this.world); +diff --git a/src/main/java/net/minecraft/world/level/block/state/BlockBase.java b/src/main/java/net/minecraft/world/level/block/state/BlockBase.java +index df595dc52858807479584ce8da49390a25695990..0990eb8b2e2d8a5f7c1a2640727d86c37a50298e 100644 +--- a/src/main/java/net/minecraft/world/level/block/state/BlockBase.java ++++ b/src/main/java/net/minecraft/world/level/block/state/BlockBase.java +@@ -303,6 +303,7 @@ public abstract class BlockBase { + return 0; + } + ++ @Deprecated public final void collideWithBlock(IBlockData iblockdata, World world, BlockPosition blockposition, Entity entity) { this.a(iblockdata, world, blockposition, entity); } // Purpur - OBFHELPER + @Deprecated + public void a(IBlockData iblockdata, World world, BlockPosition blockposition, Entity entity) {} + +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index a0df754d98e4be46720ba0962bdf7bf62f3425bb..c8b510a49ba5c299ec38ea1a56f5245ec6161b55 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -1941,4 +1941,9 @@ public class PurpurWorldConfig { + zombieVillagerMaxHealth = getDouble("mobs.zombie_villager.attributes.max_health", zombieVillagerMaxHealth); + zombieVillagerSpawnReinforcements = getDouble("mobs.zombie_villager.attributes.spawn_reinforcements", zombieVillagerSpawnReinforcements); + } ++ ++ public boolean imposeTeleportRestrictionsOnGateways = false; ++ private void imposeTeleportRestrictionsOnGateways() { ++ imposeTeleportRestrictionsOnGateways = getBoolean("gameplay-mechanics.impose-teleport-restrictions-on-gateways", imposeTeleportRestrictionsOnGateways); ++ } + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +index dcdc82b42689b4962323938a62cf7ded49afd6f4..4a70d657fd83627e8d66b52cb5f87381b43ad76a 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +@@ -550,6 +550,10 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { + location.checkFinite(); + + if (entity.isVehicle() || entity.dead) { ++ // Purpur start ++ if (!entity.dead && new net.pl3x.purpur.event.entity.EntityTeleportHinderedEvent(entity.getBukkitEntity(), net.pl3x.purpur.event.entity.EntityTeleportHinderedEvent.Reason.IS_VEHICLE, cause).callEvent()) ++ return teleport(location, cause); ++ // Purpur end + return false; + } + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +index 8cc2b2b83ad3cb74f8cf7916141ae1f4ade27908..0501d5bee249ac35e6344dfa1bed3d802901f377 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +@@ -126,6 +126,7 @@ import org.bukkit.entity.EntityType; + import org.bukkit.entity.Player; + import org.bukkit.event.player.PlayerRegisterChannelEvent; + import org.bukkit.event.player.PlayerTeleportEvent; ++import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; + import org.bukkit.event.player.PlayerUnregisterChannelEvent; + import org.bukkit.inventory.InventoryView.Property; + import org.bukkit.inventory.ItemStack; +@@ -886,6 +887,10 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + } + + if (entity.isVehicle()) { ++ // Purpur start ++ if (new net.pl3x.purpur.event.entity.EntityTeleportHinderedEvent(entity.getBukkitEntity(), net.pl3x.purpur.event.entity.EntityTeleportHinderedEvent.Reason.IS_VEHICLE, cause).callEvent()) ++ return teleport(location, cause); ++ // Purpur end + return false; + } + diff --git a/patches/Purpur/patches/server/0159-Add-StructureGenerateEvent.patch b/patches/Purpur/patches/server/0159-Add-StructureGenerateEvent.patch new file mode 100644 index 00000000..f2aa81f6 --- /dev/null +++ b/patches/Purpur/patches/server/0159-Add-StructureGenerateEvent.patch @@ -0,0 +1,64 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Nahuel +Date: Sat, 9 Jan 2021 15:36:59 +0100 +Subject: [PATCH] Add StructureGenerateEvent + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +Co-authored-by: Mariell Hoversholm + +diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java +index 316287af6e405ff224636255c2964f46003215ce..ff98335155c86803b98d8c67f0b40b8d65214890 100644 +--- a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java ++++ b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java +@@ -287,6 +287,14 @@ public abstract class ChunkGenerator { + if (structuresettingsfeature != null) { + StructureStart structurestart1 = structurefeature.a(iregistrycustom, this, this.b, definedstructuremanager, i, chunkcoordintpair, biomebase, j, structuresettingsfeature); + ++ // Purpur start ++ if (new net.pl3x.purpur.event.world.StructureGenerateEvent( ++ structuremanager.getWorld().getWorld(), ++ org.bukkit.StructureType.getStructureTypes().get(structurefeature.getFeature().getRegistryKey().toLowerCase()), ++ chunkcoordintpair.x, ++ chunkcoordintpair.z ++ ).callEvent()) ++ // Purpur end + structuremanager.a(SectionPosition.a(ichunkaccess.getPos(), 0), structurefeature.d, structurestart1, ichunkaccess); + } + +diff --git a/src/main/java/net/minecraft/world/level/levelgen/feature/StructureFeature.java b/src/main/java/net/minecraft/world/level/levelgen/feature/StructureFeature.java +index 839cc598e6dd87dd77940b5b6dcb8ddcd0b3271e..2d653ba2582c39ac1c7f396c50a7a974aa02a07e 100644 +--- a/src/main/java/net/minecraft/world/level/levelgen/feature/StructureFeature.java ++++ b/src/main/java/net/minecraft/world/level/levelgen/feature/StructureFeature.java +@@ -23,7 +23,7 @@ public class StructureFeature>> b = RegistryFileCodec.a(IRegistry.av, StructureFeature.a); + public static final Codec>>> c = RegistryFileCodec.b(IRegistry.av, StructureFeature.a); +- public final F d; ++ public final F d; public final F getFeature() { return this.d; } // Purpur - OBFHELPER + public final FC e; + + public StructureFeature(F f0, FC fc) { +diff --git a/src/main/java/net/minecraft/world/level/levelgen/feature/StructureGenerator.java b/src/main/java/net/minecraft/world/level/levelgen/feature/StructureGenerator.java +index e5c22e92a305050df0eae2da53217ea2c3249e03..8dffba8abfbda029c8a35ec7262faabd9f76c904 100644 +--- a/src/main/java/net/minecraft/world/level/levelgen/feature/StructureGenerator.java ++++ b/src/main/java/net/minecraft/world/level/levelgen/feature/StructureGenerator.java +@@ -277,6 +277,7 @@ public abstract class StructureGenerator + + public abstract StructureGenerator.a a(); + ++ public final String getRegistryKey() { return this.i(); } // Purpur - OBFHELPER + public String i() { + return (String) StructureGenerator.a.inverse().get(this); + } diff --git a/patches/Purpur/patches/server/0160-Farmland-trampling-changes.patch b/patches/Purpur/patches/server/0160-Farmland-trampling-changes.patch new file mode 100644 index 00000000..65b20f5f --- /dev/null +++ b/patches/Purpur/patches/server/0160-Farmland-trampling-changes.patch @@ -0,0 +1,76 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Mariell Hoversholm +Date: Sat, 9 Jan 2021 16:06:40 +0100 +Subject: [PATCH] Farmland trampling changes + +This lets us choose if farmland trampling is fully disabled or only +players may trample farmland. + +This lets us choose if entities can stop trampling if they fall a +distance equal to their feather falling level, plus the extra block +necessary to trample in the first place. Feather Falling 1 requires +you to fall over 3+ blocks to trample. FF 2 requires 4+, etc. + +diff --git a/src/main/java/net/minecraft/world/level/block/BlockSoil.java b/src/main/java/net/minecraft/world/level/block/BlockSoil.java +index 386641173bb758c1ba1e80071f68813fec012a93..0c7422d9b041341b12f1b8796236b8728b93ff2f 100644 +--- a/src/main/java/net/minecraft/world/level/block/BlockSoil.java ++++ b/src/main/java/net/minecraft/world/level/block/BlockSoil.java +@@ -4,13 +4,17 @@ import java.util.Iterator; + import java.util.Random; + import net.minecraft.core.BlockPosition; + import net.minecraft.core.EnumDirection; ++import net.minecraft.server.level.EntityPlayer; + import net.minecraft.server.level.WorldServer; + import net.minecraft.tags.Tag; + import net.minecraft.tags.TagsFluid; + import net.minecraft.world.entity.Entity; + import net.minecraft.world.entity.EntityLiving; + import net.minecraft.world.entity.player.EntityHuman; ++import net.minecraft.world.item.ItemStack; + import net.minecraft.world.item.context.BlockActionContext; ++import net.minecraft.world.item.enchantment.EnchantmentManager; ++import net.minecraft.world.item.enchantment.Enchantments; + import net.minecraft.world.level.GameRules; + import net.minecraft.world.level.GeneratorAccess; + import net.minecraft.world.level.IBlockAccess; +@@ -114,12 +118,19 @@ public class BlockSoil extends Block { + } + + // Purpur start ++ if (world.purpurConfig.farmlandTramplingDisabled) return; ++ if (world.purpurConfig.farmlandTramplingOnlyPlayers && !(entity instanceof EntityPlayer)) return; + if (world.purpurConfig.farmlandAlpha) { + Block block = world.getType(blockposition.down()).getBlock(); + if (block instanceof BlockFence || block instanceof BlockCobbleWall) { + return; + } + } ++ if (world.purpurConfig.farmlandTramplingFeatherFalling) { ++ Iterator armor = entity.getArmorItems().iterator(); ++ if (armor.hasNext() && EnchantmentManager.getEnchantmentLevel(Enchantments.PROTECTION_FALL, armor.next()) >= (int) entity.fallDistance) ++ return; ++ } + // Purpur end + if (CraftEventFactory.callEntityChangeBlockEvent(entity, blockposition, Blocks.DIRT.getBlockData()).isCancelled()) { + return; +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index c8b510a49ba5c299ec38ea1a56f5245ec6161b55..e639519a78bababc5d8034841e9ab2c20d34e4f7 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -471,10 +471,16 @@ public class PurpurWorldConfig { + public boolean farmlandBypassMobGriefing = false; + public boolean farmlandGetsMoistFromBelow = false; + public boolean farmlandAlpha = false; ++ public boolean farmlandTramplingDisabled = false; ++ public boolean farmlandTramplingOnlyPlayers = false; ++ public boolean farmlandTramplingFeatherFalling = false; + private void farmlandSettings() { + farmlandBypassMobGriefing = getBoolean("blocks.farmland.bypass-mob-griefing", farmlandBypassMobGriefing); + farmlandGetsMoistFromBelow = getBoolean("blocks.farmland.gets-moist-from-below", farmlandGetsMoistFromBelow); + farmlandAlpha = getBoolean("blocks.farmland.use-alpha-farmland", farmlandAlpha); ++ farmlandTramplingDisabled = getBoolean("blocks.farmland.disable-trampling", farmlandTramplingDisabled); ++ farmlandTramplingOnlyPlayers = getBoolean("blocks.farmland.only-players-trample", farmlandTramplingOnlyPlayers); ++ farmlandTramplingFeatherFalling = getBoolean("blocks.farmland.feather-fall-distance-affects-trampling", farmlandTramplingFeatherFalling); + } + + public boolean furnaceInfiniteFuel = false; diff --git a/patches/Purpur/patches/server/0161-Movement-options-for-armor-stands.patch b/patches/Purpur/patches/server/0161-Movement-options-for-armor-stands.patch new file mode 100644 index 00000000..8e9302cb --- /dev/null +++ b/patches/Purpur/patches/server/0161-Movement-options-for-armor-stands.patch @@ -0,0 +1,96 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Mariell Hoversholm +Date: Sat, 9 Jan 2021 22:22:59 +0100 +Subject: [PATCH] Movement options for armor stands + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index ca5afdcc9c5ae7b5f67a2c12f62e89ef5e227e3c..6c5c950b129b5e7e7d0d614cfdbfb5c59fda86de 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -1496,7 +1496,7 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, ne + return this.isInWater() || flag; + } + +- void aL() { ++ public void aL() { updateInWaterStateAndDoWaterCurrentPushing(); } public void updateInWaterStateAndDoWaterCurrentPushing() { // Purpur + if (this.getVehicle() instanceof EntityBoat) { + this.inWater = false; + } else if (this.a((Tag) TagsFluid.WATER, 0.014D)) { +diff --git a/src/main/java/net/minecraft/world/entity/decoration/EntityArmorStand.java b/src/main/java/net/minecraft/world/entity/decoration/EntityArmorStand.java +index 43dc0925887e2e9e86445cccff57be7994ca0d58..ecb797e67554d30e35b3aca4d0fc9b0e3f6c1a50 100644 +--- a/src/main/java/net/minecraft/world/entity/decoration/EntityArmorStand.java ++++ b/src/main/java/net/minecraft/world/entity/decoration/EntityArmorStand.java +@@ -36,6 +36,7 @@ import net.minecraft.world.item.ItemStack; + import net.minecraft.world.item.Items; + import net.minecraft.world.level.World; + import net.minecraft.world.level.block.Block; ++import net.minecraft.world.level.block.BlockFence; + import net.minecraft.world.level.block.Blocks; + import net.minecraft.world.level.material.EnumPistonReaction; + import net.minecraft.world.phys.Vec3D; +@@ -87,10 +88,12 @@ public class EntityArmorStand extends EntityLiving { + private boolean noTickPoseDirty = false; + private boolean noTickEquipmentDirty = false; + // Paper end ++ public boolean canMovementTick = true; // Purpur + + public EntityArmorStand(EntityTypes entitytypes, World world) { + super(entitytypes, world); + if (world != null) this.canTick = world.paperConfig.armorStandTick; // Paper - armour stand ticking ++ if (world != null) this.canMovementTick = world.purpurConfig.armorstandMovement; // Purpur + this.handItems = NonNullList.a(2, ItemStack.b); + this.armorItems = NonNullList.a(4, ItemStack.b); + this.headPose = EntityArmorStand.bj; +@@ -932,4 +935,18 @@ public class EntityArmorStand extends EntityLiving { + return true; + } + // Paper end ++ ++ // Purpur start ++ @Override ++ public void updateInWaterStateAndDoWaterCurrentPushing() { ++ if (this.world.purpurConfig.armorstandWaterMovement && ++ (this.world.purpurConfig.armorstandWaterFence || !(world.getType(getBlockLocation().down()).getBlock() instanceof BlockFence))) ++ super.updateInWaterStateAndDoWaterCurrentPushing(); ++ } ++ ++ @Override ++ public void movementTick() { ++ if (this.canMovementTick && this.canMove) super.movementTick(); ++ } ++ // Purpur end + } +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index e639519a78bababc5d8034841e9ab2c20d34e4f7..9d8056d7766925fec57b17b55f56dd8c67382b0a 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -111,10 +111,16 @@ public class PurpurWorldConfig { + public boolean armorstandSetNameVisible = false; + public boolean armorstandFixNametags = false; + public float armorstandStepHeight = 0.0F; ++ public boolean armorstandMovement = true; ++ public boolean armorstandWaterMovement = true; ++ public boolean armorstandWaterFence = true; + private void armorstandSettings() { + armorstandSetNameVisible = getBoolean("gameplay-mechanics.armorstand.set-name-visible-when-placing-with-custom-name", armorstandSetNameVisible); + armorstandFixNametags = getBoolean("gameplay-mechanics.armorstand.fix-nametags", armorstandFixNametags); + armorstandStepHeight = (float) getDouble("gameplay-mechanics.armorstand.step-height", armorstandStepHeight); ++ armorstandMovement = getBoolean("gameplay-mechanics.armorstand.can-movement-tick", armorstandMovement); ++ armorstandWaterMovement = getBoolean("gameplay-mechanics.armorstand.can-move-in-water", armorstandWaterMovement); ++ armorstandWaterFence = getBoolean("gameplay-mechanics.armorstand.can-move-in-water-over-fence", armorstandWaterFence); + } + + public double minecartMaxSpeed = 0.4D; diff --git a/patches/Purpur/patches/server/0162-Fix-stuck-in-portals.patch b/patches/Purpur/patches/server/0162-Fix-stuck-in-portals.patch new file mode 100644 index 00000000..d790d232 --- /dev/null +++ b/patches/Purpur/patches/server/0162-Fix-stuck-in-portals.patch @@ -0,0 +1,54 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Thu, 14 Jan 2021 16:48:10 -0600 +Subject: [PATCH] Fix stuck in portals + + +diff --git a/src/main/java/net/minecraft/server/level/EntityPlayer.java b/src/main/java/net/minecraft/server/level/EntityPlayer.java +index c631e4d27518a1382869c184af41bec911cce908..2bae88b7b53d38f41808fe0177cd78a9e2bb1ce9 100644 +--- a/src/main/java/net/minecraft/server/level/EntityPlayer.java ++++ b/src/main/java/net/minecraft/server/level/EntityPlayer.java +@@ -1300,6 +1300,7 @@ public class EntityPlayer extends EntityHuman implements ICrafting { + playerlist.d(this); + worldserver1.removePlayer(this); + this.dead = false; ++ this.portalPos = MCUtil.toBlockPosition(exit); // Purpur + + // CraftBukkit end + this.spawnIn(worldserver); +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index 6c5c950b129b5e7e7d0d614cfdbfb5c59fda86de..27cd04a4b6e0c87a300f5868f0b82fc02408a556 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -2552,12 +2552,15 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, ne + return new Vec2F(this.pitch, this.yaw); + } + ++ public BlockPosition portalPos = BlockPosition.ZERO; // Purpur + public void d(BlockPosition blockposition) { + if (this.ai()) { ++ if (!(world.purpurConfig.playerFixStuckPortal && this instanceof EntityPlayer && !blockposition.equals(portalPos))) // Purpur + this.resetPortalCooldown(); + } else if (world.purpurConfig.entitiesCanUsePortals || this instanceof EntityPlayer) { // Purpur + if (!this.world.isClientSide && !blockposition.equals(this.ac)) { + this.ac = blockposition.immutableCopy(); ++ portalPos = BlockPosition.ZERO; // Purpur + } + + this.inPortal = true; +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 9d8056d7766925fec57b17b55f56dd8c67382b0a..742db39c2bcd0a1416108e6ee57bd8156b50c0b8 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -408,6 +408,11 @@ public class PurpurWorldConfig { + }); + } + ++ public boolean playerFixStuckPortal = false; ++ private void playerFixStuckPortal() { ++ playerFixStuckPortal = getBoolean("gameplay-mechanics.player.fix-stuck-in-portal", playerFixStuckPortal); ++ } ++ + public boolean teleportIfOutsideBorder = false; + private void teleportIfOutsideBorder() { + teleportIfOutsideBorder = getBoolean("gameplay-mechanics.player.teleport-if-outside-border", teleportIfOutsideBorder); diff --git a/patches/Purpur/patches/server/0163-Config-to-use-infinity-bows-without-arrows.patch b/patches/Purpur/patches/server/0163-Config-to-use-infinity-bows-without-arrows.patch new file mode 100644 index 00000000..ce6517ee --- /dev/null +++ b/patches/Purpur/patches/server/0163-Config-to-use-infinity-bows-without-arrows.patch @@ -0,0 +1,38 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Encode42 +Date: Mon, 25 Jan 2021 11:36:39 -0500 +Subject: [PATCH] Config to use infinity bows without arrows + +Allows for bows with infinity to be used without any arrows in the player's inventory. +Uses a standard arrow when shot. + +diff --git a/src/main/java/net/minecraft/world/item/ItemBow.java b/src/main/java/net/minecraft/world/item/ItemBow.java +index c7e20b25b4d09463fa54c66e62208e90515013e2..59b803ec4552058f2dda269e9435daf65be10559 100644 +--- a/src/main/java/net/minecraft/world/item/ItemBow.java ++++ b/src/main/java/net/minecraft/world/item/ItemBow.java +@@ -130,7 +130,7 @@ public class ItemBow extends ItemProjectileWeapon implements ItemVanishable { + ItemStack itemstack = entityhuman.b(enumhand); + boolean flag = !entityhuman.f(itemstack).isEmpty(); + +- if (!entityhuman.abilities.canInstantlyBuild && !flag) { ++ if (!(world.purpurConfig.infinityWorksWithoutArrows && EnchantmentManager.getEnchantmentLevel(Enchantments.ARROW_INFINITE, itemstack) > 0) && !entityhuman.abilities.canInstantlyBuild && !flag) { // Purpur + return InteractionResultWrapper.fail(itemstack); + } else { + entityhuman.c(enumhand); +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 742db39c2bcd0a1416108e6ee57bd8156b50c0b8..7b0babbd727421ecd05523eadbff3abb758fab6f 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -253,10 +253,12 @@ public class PurpurWorldConfig { + idleTimeoutUpdateTabList = getBoolean("gameplay-mechanics.player.idle-timeout.update-tab-list", idleTimeoutUpdateTabList); + } + ++ public boolean infinityWorksWithoutArrows = false; + public boolean infinityWorksWithNormalArrows = true; + public boolean infinityWorksWithSpectralArrows = false; + public boolean infinityWorksWithTippedArrows = false; + private void infinityArrowsSettings() { ++ infinityWorksWithoutArrows = getBoolean("gameplay-mechanics.infinity-bow.works-without-arrows", infinityWorksWithoutArrows); + infinityWorksWithNormalArrows = getBoolean("gameplay-mechanics.infinity-bow.normal-arrows", infinityWorksWithNormalArrows); + infinityWorksWithSpectralArrows = getBoolean("gameplay-mechanics.infinity-bow.spectral-arrows", infinityWorksWithSpectralArrows); + infinityWorksWithTippedArrows = getBoolean("gameplay-mechanics.infinity-bow.tipped-arrows", infinityWorksWithTippedArrows); diff --git a/patches/Purpur/patches/server/0164-Toggle-for-water-sensitive-mob-damage.patch b/patches/Purpur/patches/server/0164-Toggle-for-water-sensitive-mob-damage.patch new file mode 100644 index 00000000..bc6f4af8 --- /dev/null +++ b/patches/Purpur/patches/server/0164-Toggle-for-water-sensitive-mob-damage.patch @@ -0,0 +1,152 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: YouHaveTrouble +Date: Fri, 5 Feb 2021 01:11:22 +0100 +Subject: [PATCH] Toggle for water sensitive mob damage + + +diff --git a/src/main/java/net/minecraft/world/entity/EntityInsentient.java b/src/main/java/net/minecraft/world/entity/EntityInsentient.java +index 8c74adf071e1edb640b3f2375bc92567cc2f6086..7cacd2b56fa96411d9fdf96d985d24fe835f9a91 100644 +--- a/src/main/java/net/minecraft/world/entity/EntityInsentient.java ++++ b/src/main/java/net/minecraft/world/entity/EntityInsentient.java +@@ -854,7 +854,8 @@ public abstract class EntityInsentient extends EntityLiving { + if (goalFloat.validConditions()) goalFloat.update(); + this.getControllerJump().jumpIfSet(); + } +- if ((this instanceof EntityBlaze || this instanceof EntityEnderman) && isInWaterOrRainOrBubble()) { ++ ++ if (isSensitiveToWater() && isInWaterOrRainOrBubble()) { // Purpur - Toggle for water sensitive mob damage + damageEntity(DamageSource.DROWN, 1.0F); + } + return; +diff --git a/src/main/java/net/minecraft/world/entity/EntityLiving.java b/src/main/java/net/minecraft/world/entity/EntityLiving.java +index 0e46f6b4fedc0e0d65737a3553ab8cd8dbf68e7d..9b5c42406585ed72a19c52c23f3c8b4c8f15808d 100644 +--- a/src/main/java/net/minecraft/world/entity/EntityLiving.java ++++ b/src/main/java/net/minecraft/world/entity/EntityLiving.java +@@ -2974,6 +2974,7 @@ public abstract class EntityLiving extends Entity { + + } + ++ public boolean isSensitiveToWater() { return dO(); } // Purpur - OBFHELPER + public boolean dO() { + return false; + } +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntitySnowman.java b/src/main/java/net/minecraft/world/entity/animal/EntitySnowman.java +index b13cd3f344a0e2c4c02b30f80ca9a81d93cc1954..d7aa3bd329eef71d58a8ea9be5735c58a598222b 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntitySnowman.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntitySnowman.java +@@ -108,7 +108,7 @@ public class EntitySnowman extends EntityGolem implements IShearable, IRangedEnt + + @Override + public boolean dO() { +- return true; ++ return world.purpurConfig.snowGolemTakeDamageFromWater; // Purpur - Toggle for water sensitive mob damage + } + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityBlaze.java b/src/main/java/net/minecraft/world/entity/monster/EntityBlaze.java +index 55b6f483aca8cbb5c30b3759e23c86a699e19569..09f8f792bb800a274f7b127bc925c07416906ed5 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityBlaze.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityBlaze.java +@@ -143,7 +143,7 @@ public class EntityBlaze extends EntityMonster { + + @Override + public boolean dO() { +- return true; ++ return world.purpurConfig.blazeTakeDamageFromWater; // Purpur - Toggle for water sensitive mob damage + } + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityEnderman.java b/src/main/java/net/minecraft/world/entity/monster/EntityEnderman.java +index 2992d173dc870eccdfc5f515d162844f19691d11..a2e0fed960f6dffb0f00c9d6ce91359e3597231c 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityEnderman.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityEnderman.java +@@ -289,7 +289,7 @@ public class EntityEnderman extends EntityMonster implements IEntityAngerable { + + @Override + public boolean dO() { +- return true; ++ return world.purpurConfig.endermanTakeDamageFromWater; // Purpur - Toggle for water sensitive mob damage + } + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityStrider.java b/src/main/java/net/minecraft/world/entity/monster/EntityStrider.java +index 5e4cc99a746d98231bbb71672fbc02431e4fab48..f52ae7446c16d5b8ac51bd2e12bb51d221ca43ca 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityStrider.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityStrider.java +@@ -405,7 +405,7 @@ public class EntityStrider extends EntityAnimal implements ISteerable, ISaddleab + + @Override + public boolean dO() { +- return true; ++ return world.purpurConfig.striderTakeDamageFromWater; // Purpur - Toggle for water sensitive mob damage + } + + @Override +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 7b0babbd727421ecd05523eadbff3abb758fab6f..faa5df044857f19503b35bbcf7366ac13b2fa2a9 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -629,6 +629,7 @@ public class PurpurWorldConfig { + public boolean blazeRidableInWater = false; + public double blazeMaxY = 256D; + public double blazeMaxHealth = 20.0D; ++ public boolean blazeTakeDamageFromWater = true; + private void blazeSettings() { + blazeRidable = getBoolean("mobs.blaze.ridable", blazeRidable); + blazeRidableInWater = getBoolean("mobs.blaze.ridable-in-water", blazeRidableInWater); +@@ -639,6 +640,7 @@ public class PurpurWorldConfig { + set("mobs.blaze.attributes.max_health", oldValue); + } + blazeMaxHealth = getDouble("mobs.blaze.attributes.max_health", blazeMaxHealth); ++ blazeTakeDamageFromWater = getBoolean("mobs.blaze.takes-damage-from-water", blazeTakeDamageFromWater); + } + + public boolean catRidable = false; +@@ -853,6 +855,7 @@ public class PurpurWorldConfig { + public boolean endermanBypassMobGriefing = false; + public boolean endermanDespawnEvenWithBlock = false; + public double endermanMaxHealth = 40.0D; ++ public boolean endermanTakeDamageFromWater = true; + private void endermanSettings() { + endermanRidable = getBoolean("mobs.enderman.ridable", endermanRidable); + endermanRidableInWater = getBoolean("mobs.enderman.ridable-in-water", endermanRidableInWater); +@@ -865,6 +868,7 @@ public class PurpurWorldConfig { + set("mobs.enderman.attributes.max_health", oldValue); + } + endermanMaxHealth = getDouble("mobs.enderman.attributes.max_health", endermanMaxHealth); ++ endermanTakeDamageFromWater = getBoolean("mobs.enderman.takes-damage-from-water", endermanTakeDamageFromWater); + } + + public boolean endermiteRidable = false; +@@ -1554,6 +1558,7 @@ public class PurpurWorldConfig { + public float snowGolemSnowBallModifier = 10.0F; + public double snowGolemAttackDistance = 1.25D; + public double snowGolemMaxHealth = 4.0D; ++ public boolean snowGolemTakeDamageFromWater = true; + private void snowGolemSettings() { + snowGolemRidable = getBoolean("mobs.snow_golem.ridable", snowGolemRidable); + snowGolemRidableInWater = getBoolean("mobs.snow_golem.ridable-in-water", snowGolemRidableInWater); +@@ -1571,6 +1576,7 @@ public class PurpurWorldConfig { + set("mobs.snow_golem.attributes.max_health", oldValue); + } + snowGolemMaxHealth = getDouble("mobs.snow_golem.attributes.max_health", snowGolemMaxHealth); ++ snowGolemTakeDamageFromWater = getBoolean("mobs.snow_golem.takes-damage-from-water", snowGolemTakeDamageFromWater); + } + + public boolean squidRidable = false; +@@ -1624,6 +1630,7 @@ public class PurpurWorldConfig { + public int striderBreedingTicks = 6000; + public boolean striderGiveSaddleBack = false; + public double striderMaxHealth = 20.0D; ++ public boolean striderTakeDamageFromWater = true; + private void striderSettings() { + striderRidable = getBoolean("mobs.strider.ridable", striderRidable); + striderRidableInWater = getBoolean("mobs.strider.ridable-in-water", striderRidableInWater); +@@ -1635,6 +1642,7 @@ public class PurpurWorldConfig { + set("mobs.strider.attributes.max_health", oldValue); + } + striderMaxHealth = getDouble("mobs.strider.attributes.max_health", striderMaxHealth); ++ striderTakeDamageFromWater = getBoolean("mobs.strider.takes-damage-from-water", striderTakeDamageFromWater); + } + + public boolean tropicalFishRidable = false; diff --git a/patches/Purpur/patches/server/0165-Config-to-always-tame-in-Creative.patch b/patches/Purpur/patches/server/0165-Config-to-always-tame-in-Creative.patch new file mode 100644 index 00000000..97db59cb --- /dev/null +++ b/patches/Purpur/patches/server/0165-Config-to-always-tame-in-Creative.patch @@ -0,0 +1,80 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Encode42 +Date: Tue, 9 Feb 2021 21:23:37 -0500 +Subject: [PATCH] Config to always tame in Creative + +Adds a configuration option that ensures a player in Creative always tames a tameable entity. +This essentially allows Creative mode players to tame animals on their first try. + +diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoalTame.java b/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoalTame.java +index d285f5aa66fa81a2f56920c05afb4506cb82fa54..39e348847bcecd91013452e71ef1672994a1bfa7 100644 +--- a/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoalTame.java ++++ b/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoalTame.java +@@ -63,7 +63,7 @@ public class PathfinderGoalTame extends PathfinderGoal { + int j = this.entity.getMaxDomestication(); + + // CraftBukkit - fire EntityTameEvent +- if (j > 0 && this.entity.getRandom().nextInt(j) < i && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTameEvent(this.entity, ((org.bukkit.craftbukkit.entity.CraftHumanEntity) this.entity.getBukkitEntity().getPassenger()).getHandle()).isCancelled()) { ++ if ((this.entity.world.purpurConfig.alwaysTameInCreative && ((EntityHuman) entity).abilities.canInstantlyBuild) || (j > 0 && this.entity.getRandom().nextInt(j) < i && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTameEvent(this.entity, ((org.bukkit.craftbukkit.entity.CraftHumanEntity) this.entity.getBukkitEntity().getPassenger()).getHandle()).isCancelled())) { // Purpur + this.entity.i((EntityHuman) entity); + return; + } +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityCat.java b/src/main/java/net/minecraft/world/entity/animal/EntityCat.java +index a4e3e36f081803b0588a0e907a3a834b7a3ab3eb..84784e91eb6c4bee7e66a6dee8736b948414a7a5 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityCat.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityCat.java +@@ -439,7 +439,7 @@ public class EntityCat extends EntityTameableAnimal { + } + } else if (this.k(itemstack)) { + this.a(entityhuman, itemstack); +- if (this.random.nextInt(3) == 0 && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTameEvent(this, entityhuman).isCancelled()) { // CraftBukkit ++ if ((this.world.purpurConfig.alwaysTameInCreative && entityhuman.abilities.canInstantlyBuild) || (this.random.nextInt(3) == 0 && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTameEvent(this, entityhuman).isCancelled())) { // CraftBukkit // Purpur + this.tame(entityhuman); + this.setWillSit(true); + this.world.broadcastEntityEffect(this, (byte) 7); +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityParrot.java b/src/main/java/net/minecraft/world/entity/animal/EntityParrot.java +index 7500de8bcdd32f08bf6d32e70cfe09baf097cc2b..2f51e80a02817f1e36c8fe9542809ab881263a16 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityParrot.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityParrot.java +@@ -301,7 +301,7 @@ public class EntityParrot extends EntityPerchable implements EntityBird { + } + + if (!this.world.isClientSide) { +- if (this.random.nextInt(10) == 0 && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTameEvent(this, entityhuman).isCancelled()) { // CraftBukkit ++ if ((this.world.purpurConfig.alwaysTameInCreative && entityhuman.abilities.canInstantlyBuild) || (this.random.nextInt(10) == 0 && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTameEvent(this, entityhuman).isCancelled())) { // CraftBukkit // Purpur + this.tame(entityhuman); + this.world.broadcastEntityEffect(this, (byte) 7); + } else { +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityWolf.java b/src/main/java/net/minecraft/world/entity/animal/EntityWolf.java +index 090903fbc8f6cd1522c7afb358f708f5ae3395f4..884a3f03c73efb8fb0863976615fba5ec10f716c 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityWolf.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityWolf.java +@@ -482,7 +482,7 @@ public class EntityWolf extends EntityTameableAnimal implements IEntityAngerable + } + + // CraftBukkit - added event call and isCancelled check. +- if (this.random.nextInt(3) == 0 && !CraftEventFactory.callEntityTameEvent(this, entityhuman).isCancelled()) { ++ if ((this.world.purpurConfig.alwaysTameInCreative && entityhuman.abilities.canInstantlyBuild) || (this.random.nextInt(3) == 0 && !CraftEventFactory.callEntityTameEvent(this, entityhuman).isCancelled())) { // Purpur + this.tame(entityhuman); + this.navigation.o(); + this.setGoalTarget((EntityLiving) null); +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index faa5df044857f19503b35bbcf7366ac13b2fa2a9..88e28b680e144e1b0bb919e93644b86a48b553e1 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -299,6 +299,7 @@ public class PurpurWorldConfig { + } + + public boolean useBetterMending = false; ++ public boolean alwaysTameInCreative = false; + public boolean boatEjectPlayersOnLand = false; + public boolean boatsDoFallDamage = true; + public boolean disableDropsOnCrammingDeath = false; +@@ -316,6 +317,7 @@ public class PurpurWorldConfig { + public int animalBreedingCooldownSeconds = 0; + private void miscGameplayMechanicsSettings() { + useBetterMending = getBoolean("gameplay-mechanics.use-better-mending", useBetterMending); ++ alwaysTameInCreative = getBoolean("gameplay-mechanics.always-tame-in-creative", alwaysTameInCreative); + boatEjectPlayersOnLand = getBoolean("gameplay-mechanics.boat.eject-players-on-land", boatEjectPlayersOnLand); + boatsDoFallDamage = getBoolean("gameplay-mechanics.boat.do-fall-damage", boatsDoFallDamage); + disableDropsOnCrammingDeath = getBoolean("gameplay-mechanics.disable-drops-on-cramming-death", disableDropsOnCrammingDeath); diff --git a/patches/Purpur/patches/server/0166-End-crystal-explosion-options.patch b/patches/Purpur/patches/server/0166-End-crystal-explosion-options.patch new file mode 100644 index 00000000..3bede61f --- /dev/null +++ b/patches/Purpur/patches/server/0166-End-crystal-explosion-options.patch @@ -0,0 +1,91 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ben Kerllenevich +Date: Sat, 13 Feb 2021 09:28:56 -0500 +Subject: [PATCH] End crystal explosion options + + +diff --git a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EntityEnderCrystal.java b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EntityEnderCrystal.java +index 4cd5d2de76e785e839c3b3a78d55f2304d9aa4c3..f2c4151671806f053ccadaf16c21af429f9c71bb 100644 +--- a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EntityEnderCrystal.java ++++ b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EntityEnderCrystal.java +@@ -130,6 +130,22 @@ public class EntityEnderCrystal extends Entity { + phantomDamageCooldown = 0; + idleCooldown = 60; + } ++ ++ public boolean shouldExplode() { ++ return isShowingBottom() ? world.purpurConfig.baseCrystalExplode : world.purpurConfig.baselessCrystalExplode; ++ } ++ ++ public float getExplosionPower() { ++ return (float) (isShowingBottom() ? world.purpurConfig.baseCrystalExplosionPower : world.purpurConfig.baselessCrystalExplosionPower); ++ } ++ ++ public boolean hasExplosionFire() { ++ return isShowingBottom() ? world.purpurConfig.baseCrystalExplosionFire : world.purpurConfig.baselessCrystalExplosionFire; ++ } ++ ++ public Explosion.Effect getExplosionEffect() { ++ return isShowingBottom() ? world.purpurConfig.baseCrystalExplosionEffect : world.purpurConfig.baselessCrystalExplosionEffect; ++ } + // Purpur end + + @Override +@@ -175,15 +191,17 @@ public class EntityEnderCrystal extends Entity { + // CraftBukkit end + this.die(); + if (!damagesource.isExplosion()) { ++ if (shouldExplode()) { // Purpur + // CraftBukkit start +- ExplosionPrimeEvent event = new ExplosionPrimeEvent(this.getBukkitEntity(), 6.0F, false); ++ ExplosionPrimeEvent event = new ExplosionPrimeEvent(this.getBukkitEntity(), getExplosionPower(), hasExplosionFire()); // Purpur + this.world.getServer().getPluginManager().callEvent(event); + if (event.isCancelled()) { + this.dead = false; + return false; + } +- this.world.createExplosion(this, this.locX(), this.locY(), this.locZ(), event.getRadius(), event.getFire(), Explosion.Effect.DESTROY); ++ this.world.createExplosion(this, this.locX(), this.locY(), this.locZ(), event.getRadius(), event.getFire(), getExplosionEffect()); // Purpur + // CraftBukkit end ++ } else this.dead = false; // Purpur + } + + this.a(damagesource); +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 88e28b680e144e1b0bb919e93644b86a48b553e1..266b64abb949fca2cc667395d175c962c55435db 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -1975,4 +1975,33 @@ public class PurpurWorldConfig { + private void imposeTeleportRestrictionsOnGateways() { + imposeTeleportRestrictionsOnGateways = getBoolean("gameplay-mechanics.impose-teleport-restrictions-on-gateways", imposeTeleportRestrictionsOnGateways); + } ++ ++ public boolean baselessCrystalExplode = true; ++ public double baselessCrystalExplosionPower = 6.0D; ++ public boolean baselessCrystalExplosionFire = false; ++ public Explosion.Effect baselessCrystalExplosionEffect = Explosion.Effect.DESTROY; ++ public boolean baseCrystalExplode = true; ++ public double baseCrystalExplosionPower = 6.0D; ++ public boolean baseCrystalExplosionFire = false; ++ public Explosion.Effect baseCrystalExplosionEffect = Explosion.Effect.DESTROY; ++ private void crystalSettings() { ++ baselessCrystalExplode = getBoolean("blocks.end-crystal.baseless.explode", baselessCrystalExplode); ++ baselessCrystalExplosionPower = getDouble("blocks.end-crystal.baseless.explosion-power", baselessCrystalExplosionPower); ++ baselessCrystalExplosionFire = getBoolean("blocks.end-crystal.baseless.explosion-fire", baselessCrystalExplosionFire); ++ try { ++ baselessCrystalExplosionEffect = Explosion.Effect.valueOf(getString("blocks.end-crystal.baseless.explosion-effect", baselessCrystalExplosionEffect.name())); ++ } catch (IllegalArgumentException e) { ++ log(Level.SEVERE, "Unknown value for `blocks.end-crystal.baseless.explosion-effect`! Using default of `DESTROY`"); ++ baselessCrystalExplosionEffect = Explosion.Effect.DESTROY; ++ } ++ baseCrystalExplode = getBoolean("blocks.end-crystal.base.explode", baseCrystalExplode); ++ baseCrystalExplosionPower = getDouble("blocks.end-crystal.base.explosion-power", baseCrystalExplosionPower); ++ baseCrystalExplosionFire = getBoolean("blocks.end-crystal.base.explosion-fire", baseCrystalExplosionFire); ++ try { ++ baseCrystalExplosionEffect = Explosion.Effect.valueOf(getString("blocks.end-crystal.base.explosion-effect", baseCrystalExplosionEffect.name())); ++ } catch (IllegalArgumentException e) { ++ log(Level.SEVERE, "Unknown value for `blocks.end-crystal.base.explosion-effect`! Using default of `DESTROY`"); ++ baseCrystalExplosionEffect = Explosion.Effect.DESTROY; ++ } ++ } + } diff --git a/patches/Purpur/patches/server/0167-Add-unsafe-Entity-serialization-API.patch b/patches/Purpur/patches/server/0167-Add-unsafe-Entity-serialization-API.patch new file mode 100644 index 00000000..e47fc4b2 --- /dev/null +++ b/patches/Purpur/patches/server/0167-Add-unsafe-Entity-serialization-API.patch @@ -0,0 +1,129 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Mariell Hoversholm +Date: Sat, 9 Jan 2021 21:22:58 +0100 +Subject: [PATCH] Add unsafe Entity serialization API + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +diff --git a/src/main/java/net/minecraft/world/entity/EntityTypes.java b/src/main/java/net/minecraft/world/entity/EntityTypes.java +index 2cf4e8f68fa85c4e09effda0da0c3a3f64ae7ba9..c166e0a8e7eadb4f714078f764ef35f7afca543b 100644 +--- a/src/main/java/net/minecraft/world/entity/EntityTypes.java ++++ b/src/main/java/net/minecraft/world/entity/EntityTypes.java +@@ -532,6 +532,7 @@ public class EntityTypes { + return this.bf.create(this, world); + } + ++ public static Optional loadEntityFixedData(NBTTagCompound nbtTagCompound, World world) { return a(nbtTagCompound, world); } // Purpur - OBFHELPER + public static Optional a(NBTTagCompound nbttagcompound, World world) { + return SystemUtils.a(a(nbttagcompound).map((entitytypes) -> { + return entitytypes.a(world); +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +index 4a70d657fd83627e8d66b52cb5f87381b43ad76a..af69023b241560031f6aa116561d7407b2502578 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +@@ -1196,5 +1196,12 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { + public boolean isRidableInWater() { + return getHandle().isRidableInWater(); + } ++ ++ @Override ++ public boolean spawnAt(Location location, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason spawnReason) { ++ entity.world = ((CraftWorld) location.getWorld()).getHandle(); ++ entity.setLocation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); ++ return !entity.valid && entity.world.addEntity(entity, spawnReason); ++ } + // Purpur end + } +diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +index 6cb8608f8238c4a8c346b92ba672c8cc1c0cbcc4..4674a541374cbf0594a2e79560bbfcce95675dc2 100644 +--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java ++++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +@@ -410,9 +410,14 @@ public final class CraftMagicNumbers implements UnsafeValues { + Preconditions.checkNotNull(item, "null cannot be serialized"); + Preconditions.checkArgument(item.getType() != Material.AIR, "air cannot be serialized"); + ++ // Purpur start - rework NBT <-> bytes ++ return serializeNbtToBytes(CraftItemStack.asNMSCopy(item).save(new NBTTagCompound()), true); ++ } ++ ++ public byte[] serializeNbtToBytes(NBTTagCompound compound, boolean addDataVersion) { ++ if (addDataVersion) compound.setInt("DataVersion", getDataVersion()); + java.io.ByteArrayOutputStream outputStream = new java.io.ByteArrayOutputStream(); +- NBTTagCompound compound = (item instanceof CraftItemStack ? ((CraftItemStack) item).getHandle() : CraftItemStack.asNMSCopy(item)).save(new NBTTagCompound()); +- compound.setInt("DataVersion", getDataVersion()); ++ // Purpur end + try { + net.minecraft.nbt.NBTCompressedStreamTools.writeNBT( + compound, +@@ -425,26 +430,58 @@ public final class CraftMagicNumbers implements UnsafeValues { + return outputStream.toByteArray(); + } + ++ public static DynamicOpsNBT getDynamicOpsNbtInstance() { return DynamicOpsNBT.a; } // Purpur - OBFHELPER - keeping out of the class because it's FULL of decompile errors + @Override + public ItemStack deserializeItem(byte[] data) { + Preconditions.checkNotNull(data, "null cannot be deserialized"); + Preconditions.checkArgument(data.length > 0, "cannot deserialize nothing"); + ++ // Purpur start - rework NBT <-> bytes ++ NBTTagCompound compound = deserializeNbtFromBytes(data, true); ++ Dynamic converted = DataConverterRegistry.getDataFixer().update(DataConverterTypes.ITEM_STACK, new Dynamic<>(getDynamicOpsNbtInstance(), compound), compound.getInt("DataVersion"), getDataVersion()); // TODO: obfhelper ++ return net.minecraft.world.item.ItemStack.fromCompound((NBTTagCompound) converted.getValue()).asBukkitMirror(); ++ } ++ ++ public NBTTagCompound deserializeNbtFromBytes(byte[] data, boolean verifyDataVersion) { ++ // Purpur end + try { + NBTTagCompound compound = net.minecraft.nbt.NBTCompressedStreamTools.readNBT( + new java.io.ByteArrayInputStream(data) + ); ++ if (verifyDataVersion) { // Purpur + int dataVersion = compound.getInt("DataVersion"); + + Preconditions.checkArgument(dataVersion <= getDataVersion(), "Newer version! Server downgrades are not supported!"); +- Dynamic converted = DataConverterRegistry.getDataFixer().update(DataConverterTypes.ITEM_STACK, new Dynamic(DynamicOpsNBT.a, compound), dataVersion, getDataVersion()); +- return CraftItemStack.asCraftMirror(net.minecraft.world.item.ItemStack.fromCompound((NBTTagCompound) converted.getValue())); ++ } // Purpur ++ return compound; // Purpur + } catch (IOException ex) { + com.destroystokyo.paper.util.SneakyThrow.sneaky(ex); + throw new RuntimeException(); + } + } + ++ // Purpur start ++ @Override ++ public byte[] serializeEntity(org.bukkit.entity.Entity entity) { ++ Preconditions.checkNotNull(entity, "null cannot be serialized"); ++ Preconditions.checkArgument(entity instanceof org.bukkit.craftbukkit.entity.CraftEntity, "non-CraftEntity cannot be serialized"); ++ NBTTagCompound compound = new NBTTagCompound(); ++ compound.setString("id", ((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle().getMinecraftKeyString()); ++ return serializeNbtToBytes(((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle().save(compound), true); ++ } ++ ++ @Override ++ public org.bukkit.entity.Entity deserializeEntity(byte[] data, org.bukkit.World world) { ++ NBTTagCompound compound = deserializeNbtFromBytes(data, true); ++ Dynamic converted = DataConverterRegistry.getDataFixer().update(DataConverterTypes.ENTITY, new Dynamic<>(getDynamicOpsNbtInstance(), compound), compound.getInt("DataVersion"), getDataVersion()); ++ compound = (NBTTagCompound) converted.getValue(); ++ compound.remove("UUID"); // Make the server make a new UUID for this entity; makes entities always spawnable. ++ return net.minecraft.world.entity.EntityTypes.loadEntityFixedData(compound, ((org.bukkit.craftbukkit.CraftWorld) world).getHandle()) ++ .orElseThrow(() -> new IllegalArgumentException("unknown ID was found for the data; did you downgrade?")) ++ .getBukkitEntity(); ++ } ++ // Pupur end ++ + @Override + public String getTranslationKey(Material mat) { + if (mat.isBlock()) { diff --git a/patches/Purpur/patches/server/0168-Add-ghast-allow-griefing-option.patch b/patches/Purpur/patches/server/0168-Add-ghast-allow-griefing-option.patch new file mode 100644 index 00000000..fc94c688 --- /dev/null +++ b/patches/Purpur/patches/server/0168-Add-ghast-allow-griefing-option.patch @@ -0,0 +1,59 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Sat, 13 Feb 2021 14:02:43 -0600 +Subject: [PATCH] Add ghast allow-griefing option + + +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityGhast.java b/src/main/java/net/minecraft/world/entity/monster/EntityGhast.java +index e83d9aae4a04fc67587d40cec1f24ba5ebb58e10..5834b38ab206a9db6d3e336074095ce85bdbcc50 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityGhast.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityGhast.java +@@ -230,6 +230,7 @@ public class EntityGhast extends EntityFlying implements IMonster { + } + + EntityLargeFireball entitylargefireball = new EntityLargeFireball(world, this.ghast, d2, d3, d4); ++ entitylargefireball.canCauseGrief = world.purpurConfig.ghastAllowGriefing; // Purpur + + // CraftBukkit - set bukkitYield when setting explosionpower + entitylargefireball.bukkitYield = entitylargefireball.yield = this.ghast.getPower(); +diff --git a/src/main/java/net/minecraft/world/entity/projectile/EntityLargeFireball.java b/src/main/java/net/minecraft/world/entity/projectile/EntityLargeFireball.java +index 61f06eacb4ea4ef869b60c9014cc23b25583eead..627915ee205fdcc93c5424ad7d7ea05783bc07ad 100644 +--- a/src/main/java/net/minecraft/world/entity/projectile/EntityLargeFireball.java ++++ b/src/main/java/net/minecraft/world/entity/projectile/EntityLargeFireball.java +@@ -16,6 +16,7 @@ import org.bukkit.event.entity.ExplosionPrimeEvent; // CraftBukkit + public class EntityLargeFireball extends EntityFireballFireball { + + public int yield = 1; ++ public boolean canCauseGrief = true; // Purpur + + public EntityLargeFireball(EntityTypes entitytypes, World world) { + super(entitytypes, world); +@@ -31,7 +32,7 @@ public class EntityLargeFireball extends EntityFireballFireball { + protected void a(MovingObjectPosition movingobjectposition) { + super.a(movingobjectposition); + if (!this.world.isClientSide) { +- boolean flag = this.world.purpurConfig.fireballsBypassMobGriefing || this.world.getGameRules().getBoolean(GameRules.MOB_GRIEFING); // Purpur ++ boolean flag = isIncendiary = canCauseGrief && (this.world.purpurConfig.fireballsBypassMobGriefing || this.world.getGameRules().getBoolean(GameRules.MOB_GRIEFING)); // Purpur + + // CraftBukkit start - fire ExplosionPrimeEvent + ExplosionPrimeEvent event = new ExplosionPrimeEvent((org.bukkit.entity.Explosive) this.getBukkitEntity()); +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 266b64abb949fca2cc667395d175c962c55435db..23f7a3af8f92fd6e89601b0e1b4b2d1635dfe0b0 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -926,6 +926,7 @@ public class PurpurWorldConfig { + public boolean ghastRidable = false; + public boolean ghastRidableInWater = false; + public double ghastMaxY = 256D; ++ public boolean ghastAllowGriefing = true; + public double ghastMaxHealth = 10.0D; + private void ghastSettings() { + ghastRidable = getBoolean("mobs.ghast.ridable", ghastRidable); +@@ -936,6 +937,7 @@ public class PurpurWorldConfig { + set("mobs.ghast.attributes.max-health", null); + set("mobs.ghast.attributes.max_health", oldValue); + } ++ ghastAllowGriefing = getBoolean("mobs.ghast.allow-griefing", ghastAllowGriefing); + ghastMaxHealth = getDouble("mobs.ghast.attributes.max_health", ghastMaxHealth); + } + diff --git a/patches/Purpur/patches/server/0169-Configs-for-if-Wither-Ender-Dragon-can-ride-vehicles.patch b/patches/Purpur/patches/server/0169-Configs-for-if-Wither-Ender-Dragon-can-ride-vehicles.patch new file mode 100644 index 00000000..f65fab7a --- /dev/null +++ b/patches/Purpur/patches/server/0169-Configs-for-if-Wither-Ender-Dragon-can-ride-vehicles.patch @@ -0,0 +1,79 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: jmp +Date: Sat, 20 Feb 2021 14:47:08 -0800 +Subject: [PATCH] Configs for if Wither/Ender Dragon can ride vehicles + + +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index 27cd04a4b6e0c87a300f5868f0b82fc02408a556..11924a84fd597da38e70aa0ab29c07e60ed8453a 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -2402,7 +2402,7 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, ne + } + } + +- protected boolean n(Entity entity) { ++ protected boolean n(Entity entity) { // Purpur - canRide + return !this.isSneaking() && this.j <= 0; + } + +diff --git a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EntityEnderDragon.java b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EntityEnderDragon.java +index 0614483830336f3bbd348319ca3eed8767568852..d27f61959e924e1ce6c7d76c905d98a762823e91 100644 +--- a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EntityEnderDragon.java ++++ b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EntityEnderDragon.java +@@ -1073,6 +1073,7 @@ public class EntityEnderDragon extends EntityInsentient implements IMonster { + + @Override + protected boolean n(Entity entity) { ++ if (this.world.purpurConfig.enderDragonCanRideVehicles) return this.getRideCooldown() <= 0; // Purpur + return false; + } + +diff --git a/src/main/java/net/minecraft/world/entity/boss/wither/EntityWither.java b/src/main/java/net/minecraft/world/entity/boss/wither/EntityWither.java +index fea99134e77d7cbc77c89318753e7294d3f6a15a..1a764ba0a7402ce71038635f48d4b578457cc255 100644 +--- a/src/main/java/net/minecraft/world/entity/boss/wither/EntityWither.java ++++ b/src/main/java/net/minecraft/world/entity/boss/wither/EntityWither.java +@@ -728,6 +728,7 @@ public class EntityWither extends EntityMonster implements IRangedEntity { + + @Override + protected boolean n(Entity entity) { ++ if (this.world.purpurConfig.witherCanRideVehicles) return this.getRideCooldown() <= 0; // Purpur + return false; + } + +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 23f7a3af8f92fd6e89601b0e1b4b2d1635dfe0b0..b2d7e4ee4ecef476d633278c960130110c862520 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -833,6 +833,7 @@ public class PurpurWorldConfig { + public boolean enderDragonAlwaysDropsFullExp = false; + public boolean enderDragonBypassMobGriefing = false; + public double enderDragonMaxHealth = 200.0D; ++ public boolean enderDragonCanRideVehicles = false; + private void enderDragonSettings() { + enderDragonRidable = getBoolean("mobs.ender_dragon.ridable", enderDragonRidable); + enderDragonRidableInWater = getBoolean("mobs.ender_dragon.ridable-in-water", enderDragonRidableInWater); +@@ -849,6 +850,7 @@ public class PurpurWorldConfig { + set("mobs.ender_dragon.attributes.max_health", oldValue); + } + enderDragonMaxHealth = getDouble("mobs.ender_dragon.attributes.max_health", enderDragonMaxHealth); ++ enderDragonCanRideVehicles = getBoolean("mobs.ender_dragon.can-ride-vehicles", enderDragonCanRideVehicles); + } + + public boolean endermanRidable = false; +@@ -1793,6 +1795,7 @@ public class PurpurWorldConfig { + public float witherHealthRegenAmount = 1.0f; + public int witherHealthRegenDelay = 20; + public double witherMaxHealth = 300.0D; ++ public boolean witherCanRideVehicles = false; + private void witherSettings() { + witherRidable = getBoolean("mobs.wither.ridable", witherRidable); + witherRidableInWater = getBoolean("mobs.wither.ridable-in-water", witherRidableInWater); +@@ -1810,6 +1813,7 @@ public class PurpurWorldConfig { + set("mobs.wither.attributes.max_health", oldValue); + } + witherMaxHealth = getDouble("mobs.wither.attributes.max_health", witherMaxHealth); ++ witherCanRideVehicles = getBoolean("mobs.wither.can-ride-vehicles", witherCanRideVehicles); + } + + public boolean witherSkeletonRidable = false; diff --git a/patches/Purpur/patches/server/0170-Dont-run-with-scissors.patch b/patches/Purpur/patches/server/0170-Dont-run-with-scissors.patch new file mode 100644 index 00000000..3a0afcc0 --- /dev/null +++ b/patches/Purpur/patches/server/0170-Dont-run-with-scissors.patch @@ -0,0 +1,45 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: JustDoom +Date: Fri, 5 Mar 2021 14:23:16 -0500 +Subject: [PATCH] Dont run with scissors! + + +diff --git a/src/main/java/net/minecraft/server/network/PlayerConnection.java b/src/main/java/net/minecraft/server/network/PlayerConnection.java +index 04052a43a2025876529d2a6c6f5fc9821c723da6..d1b708da030326cf22b678df8151536fc13afe00 100644 +--- a/src/main/java/net/minecraft/server/network/PlayerConnection.java ++++ b/src/main/java/net/minecraft/server/network/PlayerConnection.java +@@ -1560,6 +1560,12 @@ public class PlayerConnection implements PacketListenerPlayIn { + this.player.fallDistance = 0.0F; + } + ++ // Purpur Start ++ if (this.player.isSprinting() && this.player.getWorldServer().purpurConfig.dontRunWithScissors && (this.player.getItemInHand(EnumHand.MAIN_HAND).getItem() == Items.SHEARS || this.player.getItemInHand(EnumHand.OFF_HAND).getItem() == Items.SHEARS) && (int) (Math.random() * 10) == 0) { ++ this.player.damageEntity(net.minecraft.world.damagesource.DamageSource.MAGIC, (float) this.player.getWorldServer().purpurConfig.scissorsRunningDamage); ++ } ++ // Purpur End ++ + this.player.checkMovement(this.player.locX() - d0, this.player.locY() - d1, this.player.locZ() - d2); + this.o = this.player.locX(); + this.p = this.player.locY(); +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index b2d7e4ee4ecef476d633278c960130110c862520..02ebb0fc704b5e77cf508893d67feef036df80ed 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -203,6 +203,8 @@ public class PurpurWorldConfig { + public List itemImmuneToExplosion = new ArrayList<>(); + public List itemImmuneToFire = new ArrayList<>(); + public List itemImmuneToLightning = new ArrayList<>(); ++ public boolean dontRunWithScissors = false; ++ public double scissorsRunningDamage = 1D; + private void itemSettings() { + itemImmuneToCactus.clear(); + getList("gameplay-mechanics.item.immune.cactus", new ArrayList<>()).forEach(key -> { +@@ -240,6 +242,8 @@ public class PurpurWorldConfig { + Item item = IRegistry.ITEM.get(new MinecraftKey(key.toString())); + if (item != Items.AIR) itemImmuneToLightning.add(item); + }); ++ dontRunWithScissors = getBoolean("gameplay-mechanics.item.shears.damage-if-sprinting", dontRunWithScissors); ++ scissorsRunningDamage = getDouble("gameplay-mechanics.item.shears.sprinting-damage", scissorsRunningDamage); + } + + public boolean idleTimeoutKick = true; diff --git a/patches/Purpur/patches/server/0171-One-Punch-Man.patch b/patches/Purpur/patches/server/0171-One-Punch-Man.patch new file mode 100644 index 00000000..512592c9 --- /dev/null +++ b/patches/Purpur/patches/server/0171-One-Punch-Man.patch @@ -0,0 +1,66 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Fourmisain <8464472+Fourmisain@users.noreply.github.com> +Date: Fri, 5 Mar 2021 17:42:35 -0500 +Subject: [PATCH] One Punch Man! + + +diff --git a/src/main/java/net/minecraft/world/entity/EntityLiving.java b/src/main/java/net/minecraft/world/entity/EntityLiving.java +index 9b5c42406585ed72a19c52c23f3c8b4c8f15808d..7af455e5472dc2b6ed177494a9da86c59c6ede5f 100644 +--- a/src/main/java/net/minecraft/world/entity/EntityLiving.java ++++ b/src/main/java/net/minecraft/world/entity/EntityLiving.java +@@ -2016,6 +2016,23 @@ public abstract class EntityLiving extends Entity { + ((EntityPlayer) damagesource.getEntity()).a(StatisticList.DAMAGE_DEALT_ABSORBED, Math.round(f2 * 10.0F)); + } + ++ // Purpur start ++ if (damagesource.getEntity() instanceof EntityHuman && damagesource.getEntity().world.purpurConfig.creativeOnePunch) { ++ EntityHuman entityHuman = (EntityHuman) damagesource.getEntity(); ++ if (entityHuman.isCreative()) { ++ double attackDamage = 0; ++ ++ for (AttributeModifier modifier : entityHuman.getItemInMainHand().getAttributeModifiers(EnumItemSlot.MAINHAND).get(GenericAttributes.ATTACK_DAMAGE)) { ++ attackDamage += modifier.getAmount(); ++ } ++ ++ if (attackDamage == 0) { ++ this.setHealth(0); ++ } ++ } ++ } ++ // Purpur end ++ + if (f > 0 || !human) { + if (human) { + // PAIL: Be sure to drag all this code from the EntityHuman subclass each update. +diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java +index a4c41caae425e054db3f40a9abc41f45ccd20730..2e4bc664412feb8657c7b9995d281203a14d48fd 100644 +--- a/src/main/java/net/minecraft/world/item/ItemStack.java ++++ b/src/main/java/net/minecraft/world/item/ItemStack.java +@@ -897,6 +897,7 @@ public final class ItemStack { + this.getOrCreateTag().setInt("RepairCost", i); + } + ++ public Multimap getAttributeModifiers(EnumItemSlot enumitemslot) { return this.a(enumitemslot); } // Purpur - OBFHELPER + public Multimap a(EnumItemSlot enumitemslot) { + Object object; + +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 02ebb0fc704b5e77cf508893d67feef036df80ed..f577b1054f8bdd2be933f7dae3ffe18dfeb87fe5 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -319,6 +319,7 @@ public class PurpurWorldConfig { + public double voidDamageDealt = 4.0D; + public int raidCooldownSeconds = 0; + public int animalBreedingCooldownSeconds = 0; ++ public boolean creativeOnePunch = false; + private void miscGameplayMechanicsSettings() { + useBetterMending = getBoolean("gameplay-mechanics.use-better-mending", useBetterMending); + alwaysTameInCreative = getBoolean("gameplay-mechanics.always-tame-in-creative", alwaysTameInCreative); +@@ -337,6 +338,7 @@ public class PurpurWorldConfig { + voidDamageDealt = getDouble("gameplay-mechanics.void-damage-dealt", voidDamageDealt); + raidCooldownSeconds = getInt("gameplay-mechanics.raid-cooldown-seconds", raidCooldownSeconds); + animalBreedingCooldownSeconds = getInt("gameplay-mechanics.animal-breeding-cooldown-seconds", animalBreedingCooldownSeconds); ++ creativeOnePunch = getBoolean("gameplay-mechanics.player.one-punch-in-creative", creativeOnePunch); + } + + public boolean catSpawning; diff --git a/patches/Purpur/patches/server/0172-Add-config-for-snow-on-blue-ice.patch b/patches/Purpur/patches/server/0172-Add-config-for-snow-on-blue-ice.patch new file mode 100644 index 00000000..45beedc6 --- /dev/null +++ b/patches/Purpur/patches/server/0172-Add-config-for-snow-on-blue-ice.patch @@ -0,0 +1,46 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Fri, 5 Mar 2021 17:59:05 -0600 +Subject: [PATCH] Add config for snow on blue ice + + +diff --git a/src/main/java/net/minecraft/world/level/block/BlockSnow.java b/src/main/java/net/minecraft/world/level/block/BlockSnow.java +index d44b88185ce58346007c6ef70b76f8e0df23e95c..4b7497acc5b26da48375625b4a31fb057805344d 100644 +--- a/src/main/java/net/minecraft/world/level/block/BlockSnow.java ++++ b/src/main/java/net/minecraft/world/level/block/BlockSnow.java +@@ -74,7 +74,18 @@ public class BlockSnow extends Block { + public boolean canPlace(IBlockData iblockdata, IWorldReader iworldreader, BlockPosition blockposition) { + IBlockData iblockdata1 = iworldreader.getType(blockposition.down()); + +- return !iblockdata1.a(Blocks.ICE) && !iblockdata1.a(Blocks.PACKED_ICE) && !iblockdata1.a(Blocks.BARRIER) ? (!iblockdata1.a(Blocks.HONEY_BLOCK) && !iblockdata1.a(Blocks.SOUL_SAND) ? Block.a(iblockdata1.getCollisionShape(iworldreader, blockposition.down()), EnumDirection.UP) || iblockdata1.getBlock() == this && (Integer) iblockdata1.get(BlockSnow.LAYERS) == 8 : true) : false; ++ // Purpur start - rewrite this whole return to make more sense ++ if (iblockdata1.equals(Blocks.ICE) || iblockdata1.equals(Blocks.PACKED_ICE) || iblockdata1.equals(Blocks.BARRIER)) { ++ return false; ++ } ++ if (iblockdata1.equals(Blocks.BLUE_ICE) && !iworldreader.getWorldBorder().world.purpurConfig.snowOnBlueIce) { ++ return false; ++ } ++ if (iblockdata1.equals(Blocks.HONEY_BLOCK) || iblockdata1.equals(Blocks.SOUL_SAND)) { ++ return true; ++ } ++ return Block.a(iblockdata1.getCollisionShape(iworldreader, blockposition.down()), EnumDirection.UP) || iblockdata1.equals(this) && iblockdata1.get(LAYERS) == 8; ++ // Purpur end + } + + @Override +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index f577b1054f8bdd2be933f7dae3ffe18dfeb87fe5..8cf40f10dccd9b4f52507e432dcfd6b2015e90f2 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -477,6 +477,11 @@ public class PurpurWorldConfig { + } + } + ++ public boolean snowOnBlueIce = true; ++ private void iceSettings() { ++ snowOnBlueIce = getBoolean("blocks.blue_ice.allow-snow-formation", snowOnBlueIce); ++ } ++ + public boolean chestOpenWithBlockOnTop = false; + private void chestSettings() { + chestOpenWithBlockOnTop = getBoolean("blocks.chest.open-with-solid-block-on-top", chestOpenWithBlockOnTop); diff --git a/patches/Purpur/patches/server/0173-Configurable-Ender-Pearl-cooldown-damage-and-Endermi.patch b/patches/Purpur/patches/server/0173-Configurable-Ender-Pearl-cooldown-damage-and-Endermi.patch new file mode 100644 index 00000000..e7f886dc --- /dev/null +++ b/patches/Purpur/patches/server/0173-Configurable-Ender-Pearl-cooldown-damage-and-Endermi.patch @@ -0,0 +1,70 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Encode42 +Date: Sun, 7 Mar 2021 19:08:16 -0500 +Subject: [PATCH] Configurable Ender Pearl cooldown, damage, and Endermite RNG + +- Survival and Creative Cooldown speed +- Damage dealt on pearl usage +- Endermite spawn chance + +diff --git a/src/main/java/net/minecraft/world/entity/projectile/EntityEnderPearl.java b/src/main/java/net/minecraft/world/entity/projectile/EntityEnderPearl.java +index cf2c691357c41a7e7044f7a719144db2ffab5dbe..d80c1abefe53e6b20dd2a020f60c11e380b57bb1 100644 +--- a/src/main/java/net/minecraft/world/entity/projectile/EntityEnderPearl.java ++++ b/src/main/java/net/minecraft/world/entity/projectile/EntityEnderPearl.java +@@ -69,7 +69,7 @@ public class EntityEnderPearl extends EntityProjectileThrowable { + Bukkit.getPluginManager().callEvent(teleEvent); + + if (!teleEvent.isCancelled() && !entityplayer.playerConnection.isDisconnected()) { +- if (this.random.nextFloat() < 0.05F && this.world.getGameRules().getBoolean(GameRules.DO_MOB_SPAWNING)) { ++ if (this.random.nextFloat() < this.world.purpurConfig.enderPearlEndermiteChance && this.world.getGameRules().getBoolean(GameRules.DO_MOB_SPAWNING)) { // Purpur + EntityEndermite entityendermite = (EntityEndermite) EntityTypes.ENDERMITE.a(this.world); + + entityendermite.setPlayerSpawned(true); +@@ -84,7 +84,7 @@ public class EntityEnderPearl extends EntityProjectileThrowable { + entityplayer.playerConnection.teleport(teleEvent.getTo()); + entity.fallDistance = 0.0F; + CraftEventFactory.entityDamage = this; +- entity.damageEntity(DamageSource.FALL, 5.0F); ++ entity.damageEntity(DamageSource.FALL, this.world.purpurConfig.enderPearlDamage); // Purpur + CraftEventFactory.entityDamage = null; + } + // CraftBukkit end +diff --git a/src/main/java/net/minecraft/world/item/ItemEnderPearl.java b/src/main/java/net/minecraft/world/item/ItemEnderPearl.java +index 9896d77381e7fadf1ef2619210713e190c1445d0..61512c6755f29cb2c228ae3e80b1e08348d784a5 100644 +--- a/src/main/java/net/minecraft/world/item/ItemEnderPearl.java ++++ b/src/main/java/net/minecraft/world/item/ItemEnderPearl.java +@@ -36,7 +36,7 @@ public class ItemEnderPearl extends Item { + + world.playSound((EntityHuman) null, entityhuman.locX(), entityhuman.locY(), entityhuman.locZ(), SoundEffects.ENTITY_ENDER_PEARL_THROW, SoundCategory.NEUTRAL, 0.5F, 0.4F / (net.minecraft.world.entity.Entity.SHARED_RANDOM.nextFloat() * 0.4F + 0.8F)); + entityhuman.b(StatisticList.ITEM_USED.b(this)); +- entityhuman.getCooldownTracker().setCooldown(this, 20); ++ entityhuman.getCooldownTracker().setCooldown(this, entityhuman.abilities.canInstantlyBuild ? world.purpurConfig.enderPearlCooldownCreative : world.purpurConfig.enderPearlCooldown); // Purpur + } else { + // Paper end + if (entityhuman instanceof net.minecraft.server.level.EntityPlayer) { +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 8cf40f10dccd9b4f52507e432dcfd6b2015e90f2..129fef2e4da94bcd80153379a7246590e4ea9cdd 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -205,6 +205,10 @@ public class PurpurWorldConfig { + public List itemImmuneToLightning = new ArrayList<>(); + public boolean dontRunWithScissors = false; + public double scissorsRunningDamage = 1D; ++ public float enderPearlDamage = 5.0F; ++ public int enderPearlCooldown = 20; ++ public int enderPearlCooldownCreative = 20; ++ public float enderPearlEndermiteChance = 0.05F; + private void itemSettings() { + itemImmuneToCactus.clear(); + getList("gameplay-mechanics.item.immune.cactus", new ArrayList<>()).forEach(key -> { +@@ -244,6 +248,10 @@ public class PurpurWorldConfig { + }); + dontRunWithScissors = getBoolean("gameplay-mechanics.item.shears.damage-if-sprinting", dontRunWithScissors); + scissorsRunningDamage = getDouble("gameplay-mechanics.item.shears.sprinting-damage", scissorsRunningDamage); ++ enderPearlDamage = (float) getDouble("gameplay-mechanics.item.ender-pearl.damage", enderPearlDamage); ++ enderPearlCooldown = getInt("gameplay-mechanics.item.ender-pearl.cooldown", enderPearlCooldown); ++ enderPearlCooldownCreative = getInt("gameplay-mechanics.item.ender-pearl.creative-cooldown", enderPearlCooldownCreative); ++ enderPearlEndermiteChance = (float) getDouble("gameplay-mechanics.item.ender-pearl.endermite-spawn-chance", enderPearlEndermiteChance); + } + + public boolean idleTimeoutKick = true; diff --git a/patches/Purpur/patches/server/0174-Config-to-ignore-nearby-mobs-when-sleeping.patch b/patches/Purpur/patches/server/0174-Config-to-ignore-nearby-mobs-when-sleeping.patch new file mode 100644 index 00000000..3bfd2883 --- /dev/null +++ b/patches/Purpur/patches/server/0174-Config-to-ignore-nearby-mobs-when-sleeping.patch @@ -0,0 +1,39 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Encode42 +Date: Mon, 8 Mar 2021 16:46:54 -0500 +Subject: [PATCH] Config to ignore nearby mobs when sleeping + + +diff --git a/src/main/java/net/minecraft/server/level/EntityPlayer.java b/src/main/java/net/minecraft/server/level/EntityPlayer.java +index 2bae88b7b53d38f41808fe0177cd78a9e2bb1ce9..b8f9678ac9207e099a485c7d5c98f5766f32bd29 100644 +--- a/src/main/java/net/minecraft/server/level/EntityPlayer.java ++++ b/src/main/java/net/minecraft/server/level/EntityPlayer.java +@@ -1464,7 +1464,7 @@ public class EntityPlayer extends EntityHuman implements ICrafting { + return entitymonster.f((EntityHuman) this); + }); + +- if (!list.isEmpty()) { ++ if (!this.world.purpurConfig.playerSleepNearMonsters && !list.isEmpty()) { // Purpur + return Either.left(EntityHuman.EnumBedResult.NOT_SAFE); + } + } +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 129fef2e4da94bcd80153379a7246590e4ea9cdd..eaaaf9e5490095cd70ca892fa927017e6ea9de9d 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -328,6 +328,7 @@ public class PurpurWorldConfig { + public int raidCooldownSeconds = 0; + public int animalBreedingCooldownSeconds = 0; + public boolean creativeOnePunch = false; ++ public boolean playerSleepNearMonsters = false; + private void miscGameplayMechanicsSettings() { + useBetterMending = getBoolean("gameplay-mechanics.use-better-mending", useBetterMending); + alwaysTameInCreative = getBoolean("gameplay-mechanics.always-tame-in-creative", alwaysTameInCreative); +@@ -347,6 +348,7 @@ public class PurpurWorldConfig { + raidCooldownSeconds = getInt("gameplay-mechanics.raid-cooldown-seconds", raidCooldownSeconds); + animalBreedingCooldownSeconds = getInt("gameplay-mechanics.animal-breeding-cooldown-seconds", animalBreedingCooldownSeconds); + creativeOnePunch = getBoolean("gameplay-mechanics.player.one-punch-in-creative", creativeOnePunch); ++ playerSleepNearMonsters = getBoolean("gameplay-mechanics.player.sleep-ignore-nearby-mobs", playerSleepNearMonsters); + } + + public boolean catSpawning; diff --git a/patches/Purpur/patches/server/0175-Config-for-Enderman-to-aggro-spawned-Endermites.patch b/patches/Purpur/patches/server/0175-Config-for-Enderman-to-aggro-spawned-Endermites.patch new file mode 100644 index 00000000..7f1e26ff --- /dev/null +++ b/patches/Purpur/patches/server/0175-Config-for-Enderman-to-aggro-spawned-Endermites.patch @@ -0,0 +1,40 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Encode42 +Date: Tue, 9 Mar 2021 16:10:39 -0500 +Subject: [PATCH] Config for Enderman to aggro spawned Endermites + +By default, Enderman do not attack Endermites unless spawned by an Ender Pearl. + +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityEnderman.java b/src/main/java/net/minecraft/world/entity/monster/EntityEnderman.java +index a2e0fed960f6dffb0f00c9d6ce91359e3597231c..25c49f6ded334ffb2d0c3155692879521ec58c09 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityEnderman.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityEnderman.java +@@ -71,7 +71,7 @@ public class EntityEnderman extends EntityMonster implements IEntityAngerable { + private static final DataWatcherObject bo = DataWatcher.a(EntityEnderman.class, DataWatcherRegistry.i); + private static final DataWatcherObject bp = DataWatcher.a(EntityEnderman.class, DataWatcherRegistry.i); + private static final Predicate bq = (entityliving) -> { +- return entityliving instanceof EntityEndermite && ((EntityEndermite) entityliving).isPlayerSpawned(); ++ return entityliving instanceof EntityEndermite && (((EntityEndermite) entityliving).isPlayerSpawned() || entityliving.world.purpurConfig.endermanAggroSpawnedEndermites); // Purpur + }; + private int br = Integer.MIN_VALUE; + private int bs; +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index eaaaf9e5490095cd70ca892fa927017e6ea9de9d..bb8ad6a4ac87c4c34d12c5fc1dd92f3d63b84bc1 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -881,6 +881,7 @@ public class PurpurWorldConfig { + public boolean endermanDespawnEvenWithBlock = false; + public double endermanMaxHealth = 40.0D; + public boolean endermanTakeDamageFromWater = true; ++ public boolean endermanAggroSpawnedEndermites = false; + private void endermanSettings() { + endermanRidable = getBoolean("mobs.enderman.ridable", endermanRidable); + endermanRidableInWater = getBoolean("mobs.enderman.ridable-in-water", endermanRidableInWater); +@@ -894,6 +895,7 @@ public class PurpurWorldConfig { + } + endermanMaxHealth = getDouble("mobs.enderman.attributes.max_health", endermanMaxHealth); + endermanTakeDamageFromWater = getBoolean("mobs.enderman.takes-damage-from-water", endermanTakeDamageFromWater); ++ endermanAggroSpawnedEndermites = getBoolean("mobs.enderman.aggressive-towards-spawned-endermites", endermanAggroSpawnedEndermites); + } + + public boolean endermiteRidable = false; diff --git a/patches/Purpur/patches/server/0176-Config-to-ignore-Dragon-Head-wearers-and-stare-aggro.patch b/patches/Purpur/patches/server/0176-Config-to-ignore-Dragon-Head-wearers-and-stare-aggro.patch new file mode 100644 index 00000000..58a00170 --- /dev/null +++ b/patches/Purpur/patches/server/0176-Config-to-ignore-Dragon-Head-wearers-and-stare-aggro.patch @@ -0,0 +1,51 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Encode42 +Date: Tue, 9 Mar 2021 16:16:01 -0500 +Subject: [PATCH] Config to ignore Dragon Head wearers and stare aggro + +Prevents Enderman from becoming aggresive towards players that are wearing a Dragon Head. +Adds functionality to a useless item! + +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityEnderman.java b/src/main/java/net/minecraft/world/entity/monster/EntityEnderman.java +index 25c49f6ded334ffb2d0c3155692879521ec58c09..3bb5b360be98ac2f20793c0eb126e39eb2201331 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityEnderman.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityEnderman.java +@@ -50,6 +50,7 @@ import net.minecraft.world.entity.ai.goal.target.PathfinderGoalUniversalAngerRes + import net.minecraft.world.entity.ai.targeting.PathfinderTargetCondition; + import net.minecraft.world.entity.player.EntityHuman; + import net.minecraft.world.item.ItemStack; ++import net.minecraft.world.item.Items; + import net.minecraft.world.level.GameRules; + import net.minecraft.world.level.GeneratorAccess; + import net.minecraft.world.level.IMaterial; +@@ -252,7 +253,7 @@ public class EntityEnderman extends EntityMonster implements IEntityAngerable { + // Paper end + ItemStack itemstack = (ItemStack) entityhuman.inventory.armor.get(3); + +- if (itemstack.getItem() == Blocks.CARVED_PUMPKIN.getItem()) { ++ if (world.purpurConfig.endermanDisableStareAggro || itemstack.getItem() == Blocks.CARVED_PUMPKIN.getItem() || (world.purpurConfig.endermanIgnorePlayerDragonHead && itemstack.getItem() == Items.DRAGON_HEAD)) { // Purpur + return false; + } else { + Vec3D vec3d = entityhuman.f(1.0F).d(); +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index bb8ad6a4ac87c4c34d12c5fc1dd92f3d63b84bc1..838f97829dcb2926a56e3c34c4cbcdb9a13d6d84 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -882,6 +882,8 @@ public class PurpurWorldConfig { + public double endermanMaxHealth = 40.0D; + public boolean endermanTakeDamageFromWater = true; + public boolean endermanAggroSpawnedEndermites = false; ++ public boolean endermanIgnorePlayerDragonHead = false; ++ public boolean endermanDisableStareAggro = false; + private void endermanSettings() { + endermanRidable = getBoolean("mobs.enderman.ridable", endermanRidable); + endermanRidableInWater = getBoolean("mobs.enderman.ridable-in-water", endermanRidableInWater); +@@ -896,6 +898,8 @@ public class PurpurWorldConfig { + endermanMaxHealth = getDouble("mobs.enderman.attributes.max_health", endermanMaxHealth); + endermanTakeDamageFromWater = getBoolean("mobs.enderman.takes-damage-from-water", endermanTakeDamageFromWater); + endermanAggroSpawnedEndermites = getBoolean("mobs.enderman.aggressive-towards-spawned-endermites", endermanAggroSpawnedEndermites); ++ endermanIgnorePlayerDragonHead = getBoolean("mobs.enderman.ignore-players-wearing-dragon-head", endermanIgnorePlayerDragonHead); ++ endermanDisableStareAggro = getBoolean("mobs.enderman.disable-player-stare-aggression", endermanDisableStareAggro); + } + + public boolean endermiteRidable = false; diff --git a/patches/Purpur/patches/server/0177-Tick-fluids-config.patch b/patches/Purpur/patches/server/0177-Tick-fluids-config.patch new file mode 100644 index 00000000..4f9630e5 --- /dev/null +++ b/patches/Purpur/patches/server/0177-Tick-fluids-config.patch @@ -0,0 +1,53 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Mon, 15 Mar 2021 03:52:17 -0500 +Subject: [PATCH] Tick fluids config + + +diff --git a/src/main/java/net/minecraft/world/level/block/BlockFluids.java b/src/main/java/net/minecraft/world/level/block/BlockFluids.java +index 0ed8d938b8fafdb03e01a00a201ba3f8597ac6e9..0eff89bf9e114271c34c37cad1b98691902529ac 100644 +--- a/src/main/java/net/minecraft/world/level/block/BlockFluids.java ++++ b/src/main/java/net/minecraft/world/level/block/BlockFluids.java +@@ -100,7 +100,7 @@ public class BlockFluids extends Block implements IFluidSource { + + @Override + public void onPlace(IBlockData iblockdata, World world, BlockPosition blockposition, IBlockData iblockdata1, boolean flag) { +- if (this.a(world, blockposition, iblockdata)) { ++ if (world.purpurConfig.tickFluids && this.a(world, blockposition, iblockdata)) { // Purpur + world.getFluidTickList().a(blockposition, iblockdata.getFluid().getType(), this.getFlowSpeed(world, blockposition)); // Paper + } + +@@ -125,7 +125,7 @@ public class BlockFluids extends Block implements IFluidSource { + + @Override + public IBlockData updateState(IBlockData iblockdata, EnumDirection enumdirection, IBlockData iblockdata1, GeneratorAccess generatoraccess, BlockPosition blockposition, BlockPosition blockposition1) { +- if (iblockdata.getFluid().isSource() || iblockdata1.getFluid().isSource()) { ++ if (generatoraccess.getMinecraftWorld().purpurConfig.tickFluids && iblockdata.getFluid().isSource() || iblockdata1.getFluid().isSource()) { // Purpur + generatoraccess.getFluidTickList().a(blockposition, iblockdata.getFluid().getType(), this.b.a((IWorldReader) generatoraccess)); + } + +@@ -134,7 +134,7 @@ public class BlockFluids extends Block implements IFluidSource { + + @Override + public void doPhysics(IBlockData iblockdata, World world, BlockPosition blockposition, Block block, BlockPosition blockposition1, boolean flag) { +- if (this.a(world, blockposition, iblockdata)) { ++ if (world.purpurConfig.tickFluids && this.a(world, blockposition, iblockdata)) { // Purpur + world.getFluidTickList().a(blockposition, iblockdata.getFluid().getType(), this.getFlowSpeed(world, blockposition)); // Paper + } + +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 838f97829dcb2926a56e3c34c4cbcdb9a13d6d84..d9fee278a2a5c04cc1a1796df2a6a77b432f47cc 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -305,6 +305,11 @@ public class PurpurWorldConfig { + witherSkullDespawnRate = getInt("gameplay-mechanics.projectile-despawn-rates.wither_skull", witherSkullDespawnRate); + } + ++ public boolean tickFluids = true; ++ private void fluidSettings() { ++ tickFluids = getBoolean("gameplay-mechanics.tick-fluids", tickFluids); ++ } ++ + public int snowballDamage = -1; + private void snowballSettings() { + snowballDamage = getInt("gameplay-mechanics.projectile-damage.snowball", snowballDamage); diff --git a/patches/Purpur/patches/server/0178-Config-to-disable-Llama-caravans.patch b/patches/Purpur/patches/server/0178-Config-to-disable-Llama-caravans.patch new file mode 100644 index 00000000..baaca271 --- /dev/null +++ b/patches/Purpur/patches/server/0178-Config-to-disable-Llama-caravans.patch @@ -0,0 +1,53 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Encode42 +Date: Wed, 17 Mar 2021 10:12:53 -0400 +Subject: [PATCH] Config to disable Llama caravans + +Disables the mechanic where llamas follow leashed llamas. + +diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoalLlamaFollow.java b/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoalLlamaFollow.java +index 34a854131dd939693a6df4d52103714ebe373dc3..ea02a78c31ed43220a2b83be4bd2a896500a70b8 100644 +--- a/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoalLlamaFollow.java ++++ b/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoalLlamaFollow.java +@@ -23,7 +23,7 @@ public class PathfinderGoalLlamaFollow extends PathfinderGoal { + + @Override + public boolean a() { +- if (!getLlama().shouldJoinCaravan) return false; // Purpur ++ if (!getLlama().world.purpurConfig.llamaCaravans || !getLlama().shouldJoinCaravan) return false; // Purpur + if (!this.a.isLeashed() && !this.a.fC()) { + List list = this.a.world.getEntities(this.a, this.a.getBoundingBox().grow(9.0D, 4.0D, 9.0D), (entity) -> { + EntityTypes entitytypes = entity.getEntityType(); +diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/EntityLlama.java b/src/main/java/net/minecraft/world/entity/animal/horse/EntityLlama.java +index 4bea68fa35177d84a35dc5ced3e501a87e2a5391..f91e9dc5ae635329257f6b78b88c9c7c89e2f43d 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/horse/EntityLlama.java ++++ b/src/main/java/net/minecraft/world/entity/animal/horse/EntityLlama.java +@@ -518,7 +518,7 @@ public class EntityLlama extends EntityHorseChestedAbstract implements IRangedEn + + public void joinCaravan(EntityLlama entitiyllama) { a(entitiyllama); } // Purpur - OBFHELPER + public void a(EntityLlama entityllama) { +- if (!shouldJoinCaravan || !new net.pl3x.purpur.event.entity.LlamaJoinCaravanEvent((org.bukkit.entity.Llama) getBukkitEntity(), (org.bukkit.entity.Llama) entityllama.getBukkitEntity()).callEvent()) return; // Purpur ++ if (!this.world.purpurConfig.llamaCaravans || !shouldJoinCaravan || !new net.pl3x.purpur.event.entity.LlamaJoinCaravanEvent((org.bukkit.entity.Llama) getBukkitEntity(), (org.bukkit.entity.Llama) entityllama.getBukkitEntity()).callEvent()) return; // Purpur + this.bB = entityllama; + this.bB.bC = this; + } +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index d9fee278a2a5c04cc1a1796df2a6a77b432f47cc..c58a64f8ff38cde2de70ef9e06c1a6ca9e263669 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -1121,6 +1121,7 @@ public class PurpurWorldConfig { + + public boolean llamaRidable = false; + public boolean llamaRidableInWater = false; ++ public boolean llamaCaravans = true; + public int llamaBreedingTicks = 6000; + public double llamaMaxHealthMin = 15.0D; + public double llamaMaxHealthMax = 30.0D; +@@ -1131,6 +1132,7 @@ public class PurpurWorldConfig { + private void llamaSettings() { + llamaRidable = getBoolean("mobs.llama.ridable", llamaRidable); + llamaRidableInWater = getBoolean("mobs.llama.ridable-in-water", llamaRidableInWater); ++ llamaCaravans = getBoolean("mobs.llama.join-caravans", llamaCaravans); + llamaBreedingTicks = getInt("mobs.llama.breeding-delay-ticks", llamaBreedingTicks); + if (PurpurConfig.version < 10) { + double oldMin = getDouble("mobs.llama.attributes.max-health.min", llamaMaxHealthMin); diff --git a/patches/Purpur/patches/server/0179-Config-to-make-Creepers-explode-on-death.patch b/patches/Purpur/patches/server/0179-Config-to-make-Creepers-explode-on-death.patch new file mode 100644 index 00000000..d2b09623 --- /dev/null +++ b/patches/Purpur/patches/server/0179-Config-to-make-Creepers-explode-on-death.patch @@ -0,0 +1,77 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Encode42 +Date: Tue, 16 Mar 2021 19:50:58 -0400 +Subject: [PATCH] Config to make Creepers explode on death + +Creepers exploded after being killed in the alpha days. This brings that back. + +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityCreeper.java b/src/main/java/net/minecraft/world/entity/monster/EntityCreeper.java +index d049aac0208386198d1da4e9470e64898d27b1c9..27d5e9fc5ec1396e95180fc14e8a61b030cfd1e6 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityCreeper.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityCreeper.java +@@ -7,6 +7,7 @@ import net.minecraft.network.syncher.DataWatcher; + import net.minecraft.network.syncher.DataWatcherObject; + import net.minecraft.network.syncher.DataWatcherRegistry; + import net.minecraft.server.PathfinderGoalHasRider; ++import net.minecraft.server.level.EntityPlayer; + import net.minecraft.server.level.WorldServer; + import net.minecraft.sounds.SoundEffect; + import net.minecraft.sounds.SoundEffects; +@@ -63,6 +64,7 @@ public class EntityCreeper extends EntityMonster { + private int spacebarCharge = 0; + private int prevSpacebarCharge = 0; + private int powerToggleDelay = 0; ++ private boolean exploding = false; + // Purpur end + + public EntityCreeper(EntityTypes entitytypes, World world) { +@@ -142,6 +144,14 @@ public class EntityCreeper extends EntityMonster { + public void initAttributes() { + this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(this.world.purpurConfig.creeperMaxHealth); + } ++ ++ protected org.bukkit.event.entity.EntityDeathEvent d(DamageSource damagesource) { ++ if (!exploding && this.world.purpurConfig.creeperExplodeWhenKilled && damagesource.getEntity() instanceof EntityPlayer) { ++ this.explode(); ++ } ++ ++ return super.d(damagesource); ++ } + // Purpur end + + @Override +@@ -327,6 +337,7 @@ public class EntityCreeper extends EntityMonster { + } + + public void explode() { ++ this.exploding = true; // Purpur + if (!this.world.isClientSide) { + Explosion.Effect explosion_effect = this.world.getGameRules().getBoolean(GameRules.MOB_GRIEFING) && world.purpurConfig.creeperAllowGriefing ? Explosion.Effect.DESTROY : Explosion.Effect.NONE; // Purpur + float f = this.isPowered() ? 2.0F : 1.0F; +@@ -346,6 +357,7 @@ public class EntityCreeper extends EntityMonster { + // CraftBukkit end + } + ++ this.exploding = false; // Purpur + } + + private void createEffectCloud() { +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index c58a64f8ff38cde2de70ef9e06c1a6ca9e263669..1fcd11d5f14458cd42e8ff54d4f244067ab0736e 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -757,12 +757,14 @@ public class PurpurWorldConfig { + + public boolean creeperRidable = false; + public boolean creeperRidableInWater = false; ++ public boolean creeperExplodeWhenKilled = false; + public boolean creeperAllowGriefing = true; + public double creeperChargedChance = 0.0D; + public double creeperMaxHealth = 20.0D; + private void creeperSettings() { + creeperRidable = getBoolean("mobs.creeper.ridable", creeperRidable); + creeperRidableInWater = getBoolean("mobs.creeper.ridable-in-water", creeperRidableInWater); ++ creeperExplodeWhenKilled = getBoolean("mobs.creeper.explode-when-killed", creeperExplodeWhenKilled); + creeperAllowGriefing = getBoolean("mobs.creeper.allow-griefing", creeperAllowGriefing); + creeperChargedChance = getDouble("mobs.creeper.naturally-charged-chance", creeperChargedChance); + if (PurpurConfig.version < 10) { diff --git a/patches/Purpur/patches/server/0180-Configurable-ravager-griefable-blocks-list.patch b/patches/Purpur/patches/server/0180-Configurable-ravager-griefable-blocks-list.patch new file mode 100644 index 00000000..0fa842b4 --- /dev/null +++ b/patches/Purpur/patches/server/0180-Configurable-ravager-griefable-blocks-list.patch @@ -0,0 +1,68 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Wed, 17 Mar 2021 14:54:43 -0500 +Subject: [PATCH] Configurable ravager griefable blocks list + + +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityRavager.java b/src/main/java/net/minecraft/world/entity/monster/EntityRavager.java +index 16da85620c067b005ce029c8b9c5ea1642a794f0..c2a6f1cb399c2cd659e2b2191edbc2a687a40eeb 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityRavager.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityRavager.java +@@ -188,7 +188,7 @@ public class EntityRavager extends EntityRaider { + IBlockData iblockdata = this.world.getType(blockposition); + Block block = iblockdata.getBlock(); + +- if (block instanceof BlockLeaves && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this, blockposition, net.minecraft.world.level.block.Blocks.AIR.getBlockData()).isCancelled()) { // CraftBukkit ++ if (world.purpurConfig.ravagerGriefableBlocks.contains(block) && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this, blockposition, net.minecraft.world.level.block.Blocks.AIR.getBlockData()).isCancelled()) { // CraftBukkit // Purpur + flag = this.world.a(blockposition, true, this) || flag; + } + } +diff --git a/src/main/java/net/minecraft/world/level/block/BlockCrops.java b/src/main/java/net/minecraft/world/level/block/BlockCrops.java +index 55ad7693ced8bab5bc8b36a375c85370e84ccb77..99df890883165c39e0c8190c4729b952af03e1c8 100644 +--- a/src/main/java/net/minecraft/world/level/block/BlockCrops.java ++++ b/src/main/java/net/minecraft/world/level/block/BlockCrops.java +@@ -161,7 +161,7 @@ public class BlockCrops extends BlockPlant implements IBlockFragilePlantElement + @Override + public void a(IBlockData iblockdata, World world, BlockPosition blockposition, Entity entity) { + if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(world, blockposition)).callEvent()) { return; } // Paper +- if (entity instanceof EntityRavager && !CraftEventFactory.callEntityChangeBlockEvent(entity, blockposition, Blocks.AIR.getBlockData(), (!world.purpurConfig.ravagerBypassMobGriefing && !world.getGameRules().getBoolean(GameRules.MOB_GRIEFING))).isCancelled()) { // CraftBukkit // Purpur ++ if (entity instanceof EntityRavager && world.purpurConfig.ravagerGriefableBlocks.contains(world.getType(blockposition).getBlock()) && !CraftEventFactory.callEntityChangeBlockEvent(entity, blockposition, Blocks.AIR.getBlockData(), (!world.purpurConfig.ravagerBypassMobGriefing && !world.getGameRules().getBoolean(GameRules.MOB_GRIEFING))).isCancelled()) { // CraftBukkit // Purpur + world.a(blockposition, true, entity); + } + +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 1fcd11d5f14458cd42e8ff54d4f244067ab0736e..e360409a15feeb793bd3b4be82f9eda89b5660d7 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -1462,6 +1462,7 @@ public class PurpurWorldConfig { + public boolean ravagerRidableInWater = false; + public boolean ravagerBypassMobGriefing = false; + public double ravagerMaxHealth = 100.0D; ++ public List ravagerGriefableBlocks = new ArrayList<>(); + private void ravagerSettings() { + ravagerRidable = getBoolean("mobs.ravager.ridable", ravagerRidable); + ravagerRidableInWater = getBoolean("mobs.ravager.ridable-in-water", ravagerRidableInWater); +@@ -1472,6 +1473,23 @@ public class PurpurWorldConfig { + set("mobs.ravager.attributes.max_health", oldValue); + } + ravagerMaxHealth = getDouble("mobs.ravager.attributes.max_health", ravagerMaxHealth); ++ getList("mobs.ravager.griefable-blocks", new ArrayList(){{ ++ add("minecraft:oak_leaves"); ++ add("minecraft:spruce_leaves"); ++ add("minecraft:birch_leaves"); ++ add("minecraft:jungle_leaves"); ++ add("minecraft:acacia_leaves"); ++ add("minecraft:dark_oak_leaves"); ++ add("minecraft:beetroots"); ++ add("minecraft:carrots"); ++ add("minecraft:potatoes"); ++ add("minecraft:wheat"); ++ }}).forEach(key -> { ++ Block block = IRegistry.BLOCK.get(new MinecraftKey(key.toString())); ++ if (!block.getBlockData().isAir()) { ++ ravagerGriefableBlocks.add(block); ++ } ++ }); + } + + public boolean salmonRidable = false; diff --git a/patches/Purpur/patches/server/0181-Sneak-to-bulk-process-composter.patch b/patches/Purpur/patches/server/0181-Sneak-to-bulk-process-composter.patch new file mode 100644 index 00000000..0e61afad --- /dev/null +++ b/patches/Purpur/patches/server/0181-Sneak-to-bulk-process-composter.patch @@ -0,0 +1,61 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Sun, 21 Mar 2021 15:49:15 -0500 +Subject: [PATCH] Sneak to bulk process composter + + +diff --git a/src/main/java/net/minecraft/world/level/block/BlockComposter.java b/src/main/java/net/minecraft/world/level/block/BlockComposter.java +index e4e519ba773388b8d26a8f794a6eff51e3d8f72e..c0b235d5edf3cd14021696d1b4f76ce3de41f5d5 100644 +--- a/src/main/java/net/minecraft/world/level/block/BlockComposter.java ++++ b/src/main/java/net/minecraft/world/level/block/BlockComposter.java +@@ -44,7 +44,7 @@ import org.bukkit.craftbukkit.util.DummyGeneratorAccess; + + public class BlockComposter extends Block implements IInventoryHolder { + +- public static final BlockStateInteger a = BlockProperties.as; ++ public static final BlockStateInteger a = BlockProperties.as; public static BlockStateInteger level() { return BlockComposter.a; } // Purpur - OBFHELPER + public static final Object2FloatMap b = new Object2FloatOpenHashMap(); + private static final VoxelShape c = VoxelShapes.b(); + private static final VoxelShape[] d = (VoxelShape[]) SystemUtils.a((new VoxelShape[9]), (avoxelshape) -> { // CraftBukkit - decompile error +@@ -203,6 +203,25 @@ public class BlockComposter extends Block implements IInventoryHolder { + public static IBlockData a(IBlockData iblockdata, WorldServer worldserver, ItemStack itemstack, BlockPosition blockposition, Entity entity) { // CraftBukkit + int i = (Integer) iblockdata.get(BlockComposter.a); + ++ // Purpur start ++ IBlockData newState = process(i, iblockdata, worldserver, itemstack, blockposition, entity); ++ ++ if (worldserver.purpurConfig.composterBulkProcess && entity.isSneaking()) { ++ IBlockData oldState; ++ int oldCount, newCount, oldLevel, newLevel; ++ do { ++ oldState = newState; ++ oldCount = itemstack.getCount(); ++ oldLevel = oldState.get(BlockComposter.level()); ++ newState = process(oldLevel, oldState, worldserver, itemstack, blockposition, entity); ++ newCount = itemstack.getCount(); ++ newLevel = newState.get(BlockComposter.level()); ++ } while (newCount > 0 && (newCount != oldCount || newLevel != oldLevel || newState != oldState)); ++ } ++ return newState; ++ } ++ private static IBlockData process(int i, IBlockData iblockdata, WorldServer worldserver, ItemStack itemstack, BlockPosition blockposition, Entity entity) { ++ // Purpur end + if (i < 7 && BlockComposter.b.containsKey(itemstack.getItem())) { + // CraftBukkit start + double rand = worldserver.getRandom().nextDouble(); +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index e360409a15feeb793bd3b4be82f9eda89b5660d7..bb3c5d34b58ccf9bbaa1102e36b82a56f0dda7e3 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -502,6 +502,11 @@ public class PurpurWorldConfig { + chestOpenWithBlockOnTop = getBoolean("blocks.chest.open-with-solid-block-on-top", chestOpenWithBlockOnTop); + } + ++ public boolean composterBulkProcess = false; ++ private void composterSettings() { ++ composterBulkProcess = getBoolean("blocks.composter.sneak-to-bulk-process", composterBulkProcess); ++ } ++ + public boolean dispenserApplyCursedArmor = true; + public boolean dispenserPlaceAnvils = false; + private void dispenserSettings() { diff --git a/patches/Purpur/patches/server/0182-Config-for-skipping-night.patch b/patches/Purpur/patches/server/0182-Config-for-skipping-night.patch new file mode 100644 index 00000000..9f41efd9 --- /dev/null +++ b/patches/Purpur/patches/server/0182-Config-for-skipping-night.patch @@ -0,0 +1,39 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ben Kerllenevich +Date: Thu, 18 Mar 2021 06:22:40 -0400 +Subject: [PATCH] Config for skipping night + + +diff --git a/src/main/java/net/minecraft/server/level/WorldServer.java b/src/main/java/net/minecraft/server/level/WorldServer.java +index ab0e16b8f659ff86f022fef210b97dfa59206b0c..7d0c5d28597c51d332146a82df06ba519711f836 100644 +--- a/src/main/java/net/minecraft/server/level/WorldServer.java ++++ b/src/main/java/net/minecraft/server/level/WorldServer.java +@@ -1028,7 +1028,7 @@ public class WorldServer extends World implements GeneratorAccessSeed { + } + // CraftBukkit end + +- if (this.everyoneSleeping && this.players.stream().noneMatch((entityplayer) -> { ++ if (this.purpurConfig.playersSkipNight && this.everyoneSleeping && this.players.stream().noneMatch((entityplayer) -> { // Purpur + return !entityplayer.isSpectator() && !entityplayer.isDeeplySleeping() && !entityplayer.fauxSleeping && !(purpurConfig.idleTimeoutCountAsSleeping && entityplayer.isAfk()); // CraftBukkit // Purpur + })) { + // CraftBukkit start +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index bb3c5d34b58ccf9bbaa1102e36b82a56f0dda7e3..c87ce9aed539f382e91fcfae956339068a618b79 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -334,6 +334,7 @@ public class PurpurWorldConfig { + public int animalBreedingCooldownSeconds = 0; + public boolean creativeOnePunch = false; + public boolean playerSleepNearMonsters = false; ++ public boolean playersSkipNight = true; + private void miscGameplayMechanicsSettings() { + useBetterMending = getBoolean("gameplay-mechanics.use-better-mending", useBetterMending); + alwaysTameInCreative = getBoolean("gameplay-mechanics.always-tame-in-creative", alwaysTameInCreative); +@@ -354,6 +355,7 @@ public class PurpurWorldConfig { + animalBreedingCooldownSeconds = getInt("gameplay-mechanics.animal-breeding-cooldown-seconds", animalBreedingCooldownSeconds); + creativeOnePunch = getBoolean("gameplay-mechanics.player.one-punch-in-creative", creativeOnePunch); + playerSleepNearMonsters = getBoolean("gameplay-mechanics.player.sleep-ignore-nearby-mobs", playerSleepNearMonsters); ++ playersSkipNight = getBoolean("gameplay-mechanics.player.can-skip-night", playersSkipNight); + } + + public boolean catSpawning; diff --git a/patches/Purpur/patches/server/0183-Add-config-for-villager-trading.patch b/patches/Purpur/patches/server/0183-Add-config-for-villager-trading.patch new file mode 100644 index 00000000..e2aedf6d --- /dev/null +++ b/patches/Purpur/patches/server/0183-Add-config-for-villager-trading.patch @@ -0,0 +1,68 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ben Kerllenevich +Date: Thu, 18 Mar 2021 07:23:27 -0400 +Subject: [PATCH] Add config for villager trading + + +diff --git a/src/main/java/net/minecraft/world/entity/npc/EntityVillager.java b/src/main/java/net/minecraft/world/entity/npc/EntityVillager.java +index b36f62b38888d6eb64d46ac67c89a4189aafcfc4..66863b31687a41f84f722c611064f7ad31e02488 100644 +--- a/src/main/java/net/minecraft/world/entity/npc/EntityVillager.java ++++ b/src/main/java/net/minecraft/world/entity/npc/EntityVillager.java +@@ -369,7 +369,7 @@ public class EntityVillager extends EntityVillagerAbstract implements Reputation + return tryRide(entityhuman, enumhand); // Purpur + } else { + if (world.purpurConfig.villagerRidable && itemstack.isEmpty()) return tryRide(entityhuman, enumhand); // Purpur +- if (!this.world.isClientSide && !this.trades.isEmpty()) { ++ if (!this.world.isClientSide && this.world.purpurConfig.villagerAllowTrading && !this.trades.isEmpty()) { // Purpur + this.h(entityhuman); + } + +diff --git a/src/main/java/net/minecraft/world/entity/npc/EntityVillagerTrader.java b/src/main/java/net/minecraft/world/entity/npc/EntityVillagerTrader.java +index f6e0a92037d22de102c42cc1953ea90919bd3a34..03e811e854034c6ca9cd11d35ed0a2dbd14c6097 100644 +--- a/src/main/java/net/minecraft/world/entity/npc/EntityVillagerTrader.java ++++ b/src/main/java/net/minecraft/world/entity/npc/EntityVillagerTrader.java +@@ -146,7 +146,7 @@ public class EntityVillagerTrader extends EntityVillagerAbstract { + return tryRide(entityhuman, enumhand); // Purpur + } else { + if (world.purpurConfig.villagerTraderRidable && itemstack.isEmpty()) return tryRide(entityhuman, enumhand); // Purpur +- if (!this.world.isClientSide) { ++ if (!this.world.isClientSide && this.world.purpurConfig.villagerTraderAllowTrading) { + this.setTradingPlayer(entityhuman); + this.openTrade(entityhuman, this.getScoreboardDisplayName(), 1); + } +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index c87ce9aed539f382e91fcfae956339068a618b79..c2314380e7064459dd104b09b900c5a28b592b71 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -1772,6 +1772,7 @@ public class PurpurWorldConfig { + public boolean villagerClericsFarmWarts = false; + public boolean villagerClericFarmersThrowWarts = true; + public double villagerMaxHealth = 20.0D; ++ public boolean villagerAllowTrading = true; + private void villagerSettings() { + villagerRidable = getBoolean("mobs.villager.ridable", villagerRidable); + villagerRidableInWater = getBoolean("mobs.villager.ridable-in-water", villagerRidableInWater); +@@ -1799,6 +1800,7 @@ public class PurpurWorldConfig { + set("mobs.villager.attributes.max_health", oldValue); + } + villagerMaxHealth = getDouble("mobs.villager.attributes.max_health", villagerMaxHealth); ++ villagerAllowTrading = getBoolean("mobs.villager.allow-trading", villagerAllowTrading); + } + + public boolean villagerTraderRidable = false; +@@ -1806,6 +1808,7 @@ public class PurpurWorldConfig { + public boolean villagerTraderCanBeLeashed = false; + public boolean villagerTraderFollowEmeraldBlock = false; + public double villagerTraderMaxHealth = 20.0D; ++ public boolean villagerTraderAllowTrading = true; + private void villagerTraderSettings() { + villagerTraderRidable = getBoolean("mobs.wandering_trader.ridable", villagerTraderRidable); + villagerTraderRidableInWater = getBoolean("mobs.wandering_trader.ridable-in-water", villagerTraderRidableInWater); +@@ -1817,6 +1820,7 @@ public class PurpurWorldConfig { + set("mobs.wandering_trader.attributes.max_health", oldValue); + } + villagerTraderMaxHealth = getDouble("mobs.wandering_trader.attributes.max_health", villagerTraderMaxHealth); ++ villagerTraderAllowTrading = getBoolean("mobs.wandering_trader.allow-trading", villagerTraderAllowTrading); + } + + public boolean vindicatorRidable = false; diff --git a/patches/Purpur/patches/server/0184-Allow-infinity-on-crossbows.patch b/patches/Purpur/patches/server/0184-Allow-infinity-on-crossbows.patch new file mode 100644 index 00000000..2887161e --- /dev/null +++ b/patches/Purpur/patches/server/0184-Allow-infinity-on-crossbows.patch @@ -0,0 +1,84 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ben Kerllenevich +Date: Thu, 18 Mar 2021 12:25:29 -0400 +Subject: [PATCH] Allow infinity on crossbows + + +diff --git a/src/main/java/net/minecraft/world/item/ItemCrossbow.java b/src/main/java/net/minecraft/world/item/ItemCrossbow.java +index 4e1e819c8535e8a6b9aa5f76afe568ea171b939f..9cf76f8297c2a44c1df8ce2c4f0813802883a18b 100644 +--- a/src/main/java/net/minecraft/world/item/ItemCrossbow.java ++++ b/src/main/java/net/minecraft/world/item/ItemCrossbow.java +@@ -94,7 +94,7 @@ public class ItemCrossbow extends ItemProjectileWeapon implements ItemVanishable + private static boolean a(EntityLiving entityliving, ItemStack itemstack, boolean consume) { // Paper - add consume + int i = EnchantmentManager.getEnchantmentLevel(Enchantments.MULTISHOT, itemstack); + int j = i == 0 ? 1 : 3; +- boolean flag = !consume || entityliving instanceof EntityHuman && ((EntityHuman) entityliving).abilities.canInstantlyBuild; // Paper - add consme ++ boolean flag = !consume || entityliving instanceof EntityHuman && ((EntityHuman) entityliving).abilities.canInstantlyBuild || (net.pl3x.purpur.PurpurConfig.allowCrossbowInfinity && EnchantmentManager.getEnchantmentLevel(Enchantments.ARROW_INFINITE, itemstack) > 0); // Paper - add consme // Purpur + ItemStack itemstack1 = entityliving.f(itemstack); + ItemStack itemstack2 = itemstack1.cloneItemStack(); + +@@ -285,7 +285,7 @@ public class ItemCrossbow extends ItemProjectileWeapon implements ItemVanishable + + for (int i = 0; i < list.size(); ++i) { + ItemStack itemstack1 = (ItemStack) list.get(i); +- boolean flag = entityliving instanceof EntityHuman && ((EntityHuman) entityliving).abilities.canInstantlyBuild; ++ boolean flag = entityliving instanceof EntityHuman && ((EntityHuman) entityliving).abilities.canInstantlyBuild || (net.pl3x.purpur.PurpurConfig.allowCrossbowInfinity && EnchantmentManager.getEnchantmentLevel(Enchantments.ARROW_INFINITE, itemstack) > 0); // Purpur + + if (!itemstack1.isEmpty()) { + if (i == 0) { +diff --git a/src/main/java/net/minecraft/world/item/enchantment/EnchantmentInfiniteArrows.java b/src/main/java/net/minecraft/world/item/enchantment/EnchantmentInfiniteArrows.java +index 29bebbccf8dd6ff8976d1bfdb4c2ddcfc9de57dc..07980bf0735aab4aaa379b68d6d9b1dc494a0bab 100644 +--- a/src/main/java/net/minecraft/world/item/enchantment/EnchantmentInfiniteArrows.java ++++ b/src/main/java/net/minecraft/world/item/enchantment/EnchantmentInfiniteArrows.java +@@ -5,7 +5,7 @@ import net.minecraft.world.entity.EnumItemSlot; + public class EnchantmentInfiniteArrows extends Enchantment { + + public EnchantmentInfiniteArrows(Enchantment.Rarity enchantment_rarity, EnumItemSlot... aenumitemslot) { +- super(enchantment_rarity, EnchantmentSlotType.BOW, aenumitemslot); ++ super(enchantment_rarity, net.pl3x.purpur.PurpurConfig.allowCrossbowInfinity ? EnchantmentSlotType.BOW_AND_CROSSBOW : EnchantmentSlotType.BOW, aenumitemslot); // Purpur + } + + @Override +diff --git a/src/main/java/net/minecraft/world/item/enchantment/EnchantmentSlotType.java b/src/main/java/net/minecraft/world/item/enchantment/EnchantmentSlotType.java +index cf41863bc8b0be9f2a73ca2dd02a4d414d4f230e..2b75432d74df4f627d08d32c6553bd1a4ecd4a3d 100644 +--- a/src/main/java/net/minecraft/world/item/enchantment/EnchantmentSlotType.java ++++ b/src/main/java/net/minecraft/world/item/enchantment/EnchantmentSlotType.java +@@ -96,9 +96,17 @@ public enum EnchantmentSlotType { + VANISHABLE { + @Override + public boolean canEnchant(Item item) { +- return item instanceof ItemVanishable || Block.asBlock(item) instanceof ItemVanishable || null.BREAKABLE.canEnchant(item); ++ return item instanceof ItemVanishable || Block.asBlock(item) instanceof ItemVanishable || BREAKABLE.canEnchant(item); // Purpur - decompile fix ++ } ++ // Purpur start ++ }, ++ BOW_AND_CROSSBOW { ++ @Override ++ public boolean canEnchant(Item item) { ++ return item instanceof ItemBow || item instanceof ItemCrossbow; + } + }; ++ // Purpur end + + private EnchantmentSlotType() {} + +diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java +index 36cfcd57fa3c3d33d46be5e3f70f4cf9a84f8b77..b44f82517e1e6e1f77144e50716dfb887bf26f70 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java +@@ -231,6 +231,7 @@ public class PurpurConfig { + } + + public static boolean allowInfinityMending = false; ++ public static boolean allowCrossbowInfinity = false; + private static void enchantmentSettings() { + if (version < 5) { + boolean oldValue = getBoolean("settings.enchantment.allow-infinite-and-mending-together", false); +@@ -238,6 +239,7 @@ public class PurpurConfig { + set("settings.enchantment.allow-infinite-and-mending-together", null); + } + allowInfinityMending = getBoolean("settings.enchantment.allow-infinity-and-mending-together", allowInfinityMending); ++ allowCrossbowInfinity = getBoolean("settings.enchantment.allow-infinity-on-crossbow", allowCrossbowInfinity); + } + + public static boolean endermanShortHeight = false; diff --git a/patches/Purpur/patches/server/0185-Drowning-Settings.patch b/patches/Purpur/patches/server/0185-Drowning-Settings.patch new file mode 100644 index 00000000..c3232fa2 --- /dev/null +++ b/patches/Purpur/patches/server/0185-Drowning-Settings.patch @@ -0,0 +1,61 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ben Kerllenevich +Date: Sun, 21 Mar 2021 15:26:52 -0400 +Subject: [PATCH] Drowning Settings + + +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index 11924a84fd597da38e70aa0ab29c07e60ed8453a..778c5ee222d51e35bac51bba42f336780fd153dc 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -2608,7 +2608,7 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, ne + } + + public int getDefaultPortalCooldown() { +- return 300; ++ return this.world.purpurConfig.drowningAirTicks; // Purpur + } + + public Iterable bn() { +diff --git a/src/main/java/net/minecraft/world/entity/EntityLiving.java b/src/main/java/net/minecraft/world/entity/EntityLiving.java +index 7af455e5472dc2b6ed177494a9da86c59c6ede5f..379782d5dcb212419c8df2a9a534749b3bd63f21 100644 +--- a/src/main/java/net/minecraft/world/entity/EntityLiving.java ++++ b/src/main/java/net/minecraft/world/entity/EntityLiving.java +@@ -393,7 +393,7 @@ public abstract class EntityLiving extends Entity { + if (this.a((Tag) TagsFluid.WATER) && !this.world.getType(new BlockPosition(this.locX(), this.getHeadY(), this.locZ())).a(Blocks.BUBBLE_COLUMN)) { + if (!this.canBreatheUnderwater() && !MobEffectUtil.c(this) && !flag1) { // Paper - use OBFHELPER so it can be overridden + this.setAirTicks(this.l(this.getAirTicks())); +- if (this.getAirTicks() == -20) { ++ if (this.getAirTicks() == -this.world.purpurConfig.drowningDamageInterval) { // Purpur + this.setAirTicks(0); + Vec3D vec3d = this.getMot(); + +@@ -405,7 +405,7 @@ public abstract class EntityLiving extends Entity { + this.world.addParticle(Particles.BUBBLE, this.locX() + d2, this.locY() + d3, this.locZ() + d4, vec3d.x, vec3d.y, vec3d.z); + } + +- this.damageEntity(DamageSource.DROWN, 2.0F); ++ this.damageEntity(DamageSource.DROWN, (float) this.world.purpurConfig.damageFromDrowning); // Purpur + } + } + +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index c2314380e7064459dd104b09b900c5a28b592b71..82da1dd5bb8b02c948be51fa941d3b31a3f0dc20 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -2047,6 +2047,15 @@ public class PurpurWorldConfig { + imposeTeleportRestrictionsOnGateways = getBoolean("gameplay-mechanics.impose-teleport-restrictions-on-gateways", imposeTeleportRestrictionsOnGateways); + } + ++ public int drowningAirTicks = 300; ++ public int drowningDamageInterval = 20; ++ public double damageFromDrowning = 2.0F; ++ private void drowningSettings() { ++ drowningAirTicks = getInt("gameplay-mechanics.drowning.air-ticks", drowningAirTicks); ++ drowningDamageInterval = getInt("gameplay-mechanics.drowning.ticks-per-damage", drowningDamageInterval); ++ damageFromDrowning = getDouble("gameplay-mechanics.drowning.damage-from-drowning", damageFromDrowning); ++ } ++ + public boolean baselessCrystalExplode = true; + public double baselessCrystalExplosionPower = 6.0D; + public boolean baselessCrystalExplosionFire = false; diff --git a/patches/Purpur/patches/server/0186-Break-individual-slabs-when-sneaking.patch b/patches/Purpur/patches/server/0186-Break-individual-slabs-when-sneaking.patch new file mode 100644 index 00000000..989dfd74 --- /dev/null +++ b/patches/Purpur/patches/server/0186-Break-individual-slabs-when-sneaking.patch @@ -0,0 +1,74 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Tue, 23 Mar 2021 19:38:53 -0500 +Subject: [PATCH] Break individual slabs when sneaking + + +diff --git a/src/main/java/net/minecraft/server/level/PlayerInteractManager.java b/src/main/java/net/minecraft/server/level/PlayerInteractManager.java +index 1746a8c1750b494c47f9f46e83b248d8129d2630..7302554063ac7b5dedaff895cba33b70234008e6 100644 +--- a/src/main/java/net/minecraft/server/level/PlayerInteractManager.java ++++ b/src/main/java/net/minecraft/server/level/PlayerInteractManager.java +@@ -410,6 +410,8 @@ public class PlayerInteractManager { + } + return false; + } ++ ++ if (this.player.world.purpurConfig.slabHalfBreak && this.player.isSneaking() && iblockdata.getBlock() instanceof net.minecraft.world.level.block.BlockStepAbstract && ((net.minecraft.world.level.block.BlockStepAbstract) iblockdata.getBlock()).halfBreak(iblockdata, blockposition, this.player)) return true; // Purpur + } + // CraftBukkit end + +diff --git a/src/main/java/net/minecraft/world/level/block/BlockStepAbstract.java b/src/main/java/net/minecraft/world/level/block/BlockStepAbstract.java +index 12c0fa5072755fd2a4f575b0cc5e4222617490ce..94965b216d50b29b95f09fa9019c177b9c099e14 100644 +--- a/src/main/java/net/minecraft/world/level/block/BlockStepAbstract.java ++++ b/src/main/java/net/minecraft/world/level/block/BlockStepAbstract.java +@@ -27,7 +27,7 @@ import net.minecraft.world.phys.shapes.VoxelShapes; + + public class BlockStepAbstract extends Block implements IBlockWaterlogged { + +- public static final BlockStateEnum a = BlockProperties.aK; ++ public static final BlockStateEnum a = BlockProperties.aK; public static BlockStateEnum slabType() { return a; } // Purpur - OBFHELPER + public static final BlockStateBoolean b = BlockProperties.C; + protected static final VoxelShape c = Block.a(0.0D, 0.0D, 0.0D, 16.0D, 8.0D, 16.0D); + protected static final VoxelShape d = Block.a(0.0D, 8.0D, 0.0D, 16.0D, 16.0D, 16.0D); +@@ -134,4 +134,25 @@ public class BlockStepAbstract extends Block implements IBlockWaterlogged { + return false; + } + } ++ ++ // Purpur start ++ public boolean halfBreak(IBlockData iblockdata, BlockPosition pos, net.minecraft.server.level.EntityPlayer player) { ++ if (iblockdata.get(BlockStepAbstract.slabType()) != BlockPropertySlabType.DOUBLE) { ++ return false; ++ } ++ net.minecraft.world.phys.MovingObjectPosition result = player.getRayTrace(16); ++ if (result == null) { ++ return false; ++ } ++ double hitY = result.getPos().getY(); ++ int blockY = org.bukkit.util.NumberConversions.floor(hitY); ++ player.world.setTypeAndData(pos, iblockdata.set(BlockStepAbstract.slabType(), (hitY - blockY > 0.5 || blockY - pos.getY() == 1) ? BlockPropertySlabType.BOTTOM : BlockPropertySlabType.TOP), 3); ++ if (!player.abilities.canInstantlyBuild) { ++ net.minecraft.world.entity.item.EntityItem item = new net.minecraft.world.entity.item.EntityItem(player.world, pos.getX(), pos.getY(), pos.getZ(), new ItemStack(getItem())); ++ item.defaultPickupDelay(); ++ player.world.addEntity(item); ++ } ++ return true; ++ } ++ // Purpur end + } +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 82da1dd5bb8b02c948be51fa941d3b31a3f0dc20..accfdc659f97fb75387776326f4d1b6bd1742aaf 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -575,6 +575,11 @@ public class PurpurWorldConfig { + signRightClickEdit = getBoolean("blocks.sign.right-click-edit", signRightClickEdit); + } + ++ public boolean slabHalfBreak = false; ++ private void slabSettings() { ++ slabHalfBreak = getBoolean("blocks.slab.break-individual-slabs-when-sneaking", slabHalfBreak); ++ } ++ + public boolean spawnerDeactivateByRedstone = false; + private void spawnerSettings() { + spawnerDeactivateByRedstone = getBoolean("blocks.spawner.deactivate-by-redstone", spawnerDeactivateByRedstone); diff --git a/patches/Purpur/patches/server/0187-Config-to-disable-hostile-mob-spawn-on-ice.patch b/patches/Purpur/patches/server/0187-Config-to-disable-hostile-mob-spawn-on-ice.patch new file mode 100644 index 00000000..91f4ba15 --- /dev/null +++ b/patches/Purpur/patches/server/0187-Config-to-disable-hostile-mob-spawn-on-ice.patch @@ -0,0 +1,40 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Encode42 +Date: Tue, 23 Mar 2021 15:40:45 -0400 +Subject: [PATCH] Config to disable hostile mob spawn on ice + + +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityMonster.java b/src/main/java/net/minecraft/world/entity/monster/EntityMonster.java +index c484e27650364b6537fe6b2e8e14de98382b86a3..096a7b76e0ae42ba8b859159e20fb72e101fe6de 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityMonster.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityMonster.java +@@ -95,6 +95,12 @@ public abstract class EntityMonster extends EntityCreature implements IMonster { + } + + public static boolean a(WorldAccess worldaccess, BlockPosition blockposition, Random random) { ++ // Purpur start ++ net.minecraft.world.level.block.state.IBlockData spawnBlock = worldaccess.getType(blockposition.down()); ++ if ((!worldaccess.getMinecraftWorld().purpurConfig.mobsSpawnOnPackedIce && spawnBlock.equals(net.minecraft.world.level.block.Blocks.PACKED_ICE)) || (!worldaccess.getMinecraftWorld().purpurConfig.mobsSpawnOnBlueIce && spawnBlock.equals(net.minecraft.world.level.block.Blocks.BLUE_ICE))) { ++ return false; ++ } ++ // Purpur end + if (worldaccess.getBrightness(EnumSkyBlock.SKY, blockposition) > random.nextInt(32)) { + return false; + } else { +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index accfdc659f97fb75387776326f4d1b6bd1742aaf..cb20d4cccbaf52d71df7e1e4f877f6938f2969e3 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -495,8 +495,12 @@ public class PurpurWorldConfig { + } + + public boolean snowOnBlueIce = true; ++ public boolean mobsSpawnOnPackedIce = true; ++ public boolean mobsSpawnOnBlueIce = true; + private void iceSettings() { + snowOnBlueIce = getBoolean("blocks.blue_ice.allow-snow-formation", snowOnBlueIce); ++ mobsSpawnOnPackedIce = getBoolean("blocks.packed_ice.allow-mob-spawns", mobsSpawnOnPackedIce); ++ mobsSpawnOnBlueIce = getBoolean("blocks.blue_ice.allow-mob-spawns", mobsSpawnOnBlueIce); + } + + public boolean chestOpenWithBlockOnTop = false; diff --git a/patches/Purpur/patches/server/0188-Config-to-show-Armor-Stand-arms-on-spawn.patch b/patches/Purpur/patches/server/0188-Config-to-show-Armor-Stand-arms-on-spawn.patch new file mode 100644 index 00000000..9955fb63 --- /dev/null +++ b/patches/Purpur/patches/server/0188-Config-to-show-Armor-Stand-arms-on-spawn.patch @@ -0,0 +1,38 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Encode42 +Date: Tue, 23 Mar 2021 22:42:20 -0400 +Subject: [PATCH] Config to show Armor Stand arms on spawn + + +diff --git a/src/main/java/net/minecraft/world/entity/decoration/EntityArmorStand.java b/src/main/java/net/minecraft/world/entity/decoration/EntityArmorStand.java +index ecb797e67554d30e35b3aca4d0fc9b0e3f6c1a50..ddc1c3383cdc32fa832485f3922c74185731557a 100644 +--- a/src/main/java/net/minecraft/world/entity/decoration/EntityArmorStand.java ++++ b/src/main/java/net/minecraft/world/entity/decoration/EntityArmorStand.java +@@ -103,6 +103,7 @@ public class EntityArmorStand extends EntityLiving { + this.leftLegPose = EntityArmorStand.bn; + this.rightLegPose = EntityArmorStand.bo; + this.G = 0.0F; ++ this.setArms(world != null && world.purpurConfig.armorstandPlaceWithArms); // Purpur + } + + public EntityArmorStand(World world, double d0, double d1, double d2) { +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index cb20d4cccbaf52d71df7e1e4f877f6938f2969e3..295cc5427a1bdc8f89a0b0c34b3c1f1db7c47a2f 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -114,6 +114,7 @@ public class PurpurWorldConfig { + public boolean armorstandMovement = true; + public boolean armorstandWaterMovement = true; + public boolean armorstandWaterFence = true; ++ public boolean armorstandPlaceWithArms = false; + private void armorstandSettings() { + armorstandSetNameVisible = getBoolean("gameplay-mechanics.armorstand.set-name-visible-when-placing-with-custom-name", armorstandSetNameVisible); + armorstandFixNametags = getBoolean("gameplay-mechanics.armorstand.fix-nametags", armorstandFixNametags); +@@ -121,6 +122,7 @@ public class PurpurWorldConfig { + armorstandMovement = getBoolean("gameplay-mechanics.armorstand.can-movement-tick", armorstandMovement); + armorstandWaterMovement = getBoolean("gameplay-mechanics.armorstand.can-move-in-water", armorstandWaterMovement); + armorstandWaterFence = getBoolean("gameplay-mechanics.armorstand.can-move-in-water-over-fence", armorstandWaterFence); ++ armorstandPlaceWithArms = getBoolean("gameplay-mechanics.armorstand.place-with-arms-visible", armorstandPlaceWithArms); + } + + public double minecartMaxSpeed = 0.4D; diff --git a/patches/Purpur/patches/server/0189-Option-to-make-doors-require-redstone.patch b/patches/Purpur/patches/server/0189-Option-to-make-doors-require-redstone.patch new file mode 100644 index 00000000..086353f9 --- /dev/null +++ b/patches/Purpur/patches/server/0189-Option-to-make-doors-require-redstone.patch @@ -0,0 +1,92 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Wed, 24 Mar 2021 04:40:11 -0500 +Subject: [PATCH] Option to make doors require redstone + + +diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/BehaviorInteractDoor.java b/src/main/java/net/minecraft/world/entity/ai/behavior/BehaviorInteractDoor.java +index 4b8df9f05e10b7f42f2b45f31082886d597b3bc9..bde24d90fd1c1dc19fb26bce4e625fab4983e8c2 100644 +--- a/src/main/java/net/minecraft/world/entity/ai/behavior/BehaviorInteractDoor.java ++++ b/src/main/java/net/minecraft/world/entity/ai/behavior/BehaviorInteractDoor.java +@@ -62,7 +62,7 @@ public class BehaviorInteractDoor extends Behavior { + BlockPosition blockposition = pathpoint.a(); + IBlockData iblockdata = worldserver.getType(blockposition); + +- if (iblockdata.a((Tag) TagsBlock.WOODEN_DOORS)) { ++ if (iblockdata.a((Tag) TagsBlock.WOODEN_DOORS) && !BlockDoor.requiresRedstone(entityliving.world, iblockdata, blockposition)) { // Purpur + BlockDoor blockdoor = (BlockDoor) iblockdata.getBlock(); + + if (!blockdoor.h(iblockdata)) { +@@ -82,7 +82,7 @@ public class BehaviorInteractDoor extends Behavior { + BlockPosition blockposition1 = pathpoint1.a(); + IBlockData iblockdata1 = worldserver.getType(blockposition1); + +- if (iblockdata1.a((Tag) TagsBlock.WOODEN_DOORS)) { ++ if (iblockdata1.a((Tag) TagsBlock.WOODEN_DOORS) && !BlockDoor.requiresRedstone(entityliving.world, iblockdata, blockposition1)) { // Purpur + BlockDoor blockdoor1 = (BlockDoor) iblockdata1.getBlock(); + + if (!blockdoor1.h(iblockdata1)) { +@@ -117,7 +117,7 @@ public class BehaviorInteractDoor extends Behavior { + } else { + IBlockData iblockdata = worldserver.getType(blockposition); + +- if (!iblockdata.a((Tag) TagsBlock.WOODEN_DOORS)) { ++ if (!iblockdata.a((Tag) TagsBlock.WOODEN_DOORS) || BlockDoor.requiresRedstone(entityliving.world, iblockdata, blockposition)) { // Purpur + iterator.remove(); + } else { + BlockDoor blockdoor = (BlockDoor) iblockdata.getBlock(); +diff --git a/src/main/java/net/minecraft/world/level/block/BlockDoor.java b/src/main/java/net/minecraft/world/level/block/BlockDoor.java +index 453b46851f021d4285be123bedc8982fc8844da2..2a7695c899b12c87ab89d00116b6f0dd0c9fd9dc 100644 +--- a/src/main/java/net/minecraft/world/level/block/BlockDoor.java ++++ b/src/main/java/net/minecraft/world/level/block/BlockDoor.java +@@ -167,6 +167,10 @@ public class BlockDoor extends Block { + public EnumInteractionResult interact(IBlockData iblockdata, World world, BlockPosition blockposition, EntityHuman entityhuman, EnumHand enumhand, MovingObjectPositionBlock movingobjectpositionblock) { + if (this.material == Material.ORE) { + return EnumInteractionResult.PASS; ++ // Purpur start ++ } else if (requiresRedstone(world, iblockdata, blockposition)) { ++ return EnumInteractionResult.CONSUME; ++ // Purpur end + } else { + iblockdata = (IBlockData) iblockdata.a((IBlockState) BlockDoor.OPEN); + world.setTypeAndData(blockposition, iblockdata, 10); +@@ -254,4 +258,18 @@ public class BlockDoor extends Block { + public static boolean l(IBlockData iblockdata) { + return iblockdata.getBlock() instanceof BlockDoor && (iblockdata.getMaterial() == Material.WOOD || iblockdata.getMaterial() == Material.NETHER_WOOD); + } ++ ++ // Purpur start ++ public static boolean requiresRedstone(World world, IBlockData iblockdata, BlockPosition blockposition) { ++ if (world.purpurConfig.doorRequiresRedstone.contains(iblockdata.getBlock())) { ++ // force update client ++ BlockPosition otherBlockPosition = blockposition.shift(iblockdata.get(BlockDoor.HALF) == BlockPropertyDoubleBlockHalf.LOWER ? EnumDirection.UP : EnumDirection.DOWN); ++ IBlockData otherIBlockData = world.getType(otherBlockPosition); ++ world.notify(blockposition, iblockdata, iblockdata, 3); ++ world.notify(otherBlockPosition, otherIBlockData, otherIBlockData, 3); ++ return true; ++ } ++ return false; ++ } ++ // Purpur end + } +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 295cc5427a1bdc8f89a0b0c34b3c1f1db7c47a2f..9cb06d3e3109c08b2e9f3336365dd14241c4faca 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -496,6 +496,16 @@ public class PurpurWorldConfig { + } + } + ++ public List doorRequiresRedstone = new ArrayList<>(); ++ private void doorSettings() { ++ getList("blocks.door.requires-redstone", new ArrayList()).forEach(key -> { ++ Block block = IRegistry.BLOCK.get(new MinecraftKey(key.toString())); ++ if (!block.getBlockData().isAir()) { ++ doorRequiresRedstone.add(block); ++ } ++ }); ++ } ++ + public boolean snowOnBlueIce = true; + public boolean mobsSpawnOnPackedIce = true; + public boolean mobsSpawnOnBlueIce = true; diff --git a/patches/Purpur/patches/server/0190-Config-to-allow-for-unsafe-enchants.patch b/patches/Purpur/patches/server/0190-Config-to-allow-for-unsafe-enchants.patch new file mode 100644 index 00000000..0b25a6fc --- /dev/null +++ b/patches/Purpur/patches/server/0190-Config-to-allow-for-unsafe-enchants.patch @@ -0,0 +1,77 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Encode42 +Date: Wed, 24 Mar 2021 17:59:54 -0400 +Subject: [PATCH] Config to allow for unsafe enchants + + +diff --git a/src/main/java/net/minecraft/server/commands/CommandEnchant.java b/src/main/java/net/minecraft/server/commands/CommandEnchant.java +index 96991d77cfef2ef0fdada1a831619293ffe37e70..bd035a0f3554fd44f135c23fc92f3411ccf74e0d 100644 +--- a/src/main/java/net/minecraft/server/commands/CommandEnchant.java ++++ b/src/main/java/net/minecraft/server/commands/CommandEnchant.java +@@ -48,7 +48,7 @@ public class CommandEnchant { + } + + private static int a(CommandListenerWrapper commandlistenerwrapper, Collection collection, Enchantment enchantment, int i) throws CommandSyntaxException { +- if (i > enchantment.getMaxLevel()) { ++ if (!net.pl3x.purpur.PurpurConfig.allowUnsafeEnchants && i > enchantment.getMaxLevel()) { // Purpur + throw CommandEnchant.d.create(i, enchantment.getMaxLevel()); + } else { + int j = 0; +@@ -62,7 +62,7 @@ public class CommandEnchant { + ItemStack itemstack = entityliving.getItemInMainHand(); + + if (!itemstack.isEmpty()) { +- if (enchantment.canEnchant(itemstack) && EnchantmentManager.a((Collection) EnchantmentManager.a(itemstack).keySet(), enchantment)) { ++ if ((enchantment.canEnchant(itemstack) && EnchantmentManager.a((Collection) EnchantmentManager.a(itemstack).keySet(), enchantment)) || (net.pl3x.purpur.PurpurConfig.allowUnsafeEnchants && !itemstack.hasEnchantment(enchantment))) { // Purpur + itemstack.addEnchantment(enchantment, i); + ++j; + } else if (collection.size() == 1) { +diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java +index 2e4bc664412feb8657c7b9995d281203a14d48fd..677f866dfaab653b05c693663adaeb2465117a55 100644 +--- a/src/main/java/net/minecraft/world/item/ItemStack.java ++++ b/src/main/java/net/minecraft/world/item/ItemStack.java +@@ -860,6 +860,12 @@ public final class ItemStack { + return this.tag != null && this.tag.hasKeyOfType("Enchantments", 9) ? !this.tag.getList("Enchantments", 10).isEmpty() : false; + } + ++ // Purpur start ++ public boolean hasEnchantment(Enchantment enchantment) { ++ return hasEnchantments() && EnchantmentManager.getEnchantmentMap(getEnchantments()).containsKey(enchantment); ++ } ++ // Purpur end ++ + public void getOrCreateTagAndSet(String s, NBTBase nbtbase) { a(s, nbtbase);} // Paper - OBFHELPER + public void a(String s, NBTBase nbtbase) { + this.getOrCreateTag().set(s, nbtbase); +diff --git a/src/main/java/net/minecraft/world/item/enchantment/EnchantmentManager.java b/src/main/java/net/minecraft/world/item/enchantment/EnchantmentManager.java +index b2d28c2bf0a9e93d38583e2d734c12fed4f63d5d..63a6f63a2d3e03e74c314cdebf7cb61b66fd5108 100644 +--- a/src/main/java/net/minecraft/world/item/enchantment/EnchantmentManager.java ++++ b/src/main/java/net/minecraft/world/item/enchantment/EnchantmentManager.java +@@ -59,6 +59,7 @@ public class EnchantmentManager { + return a(nbttaglist); + } + ++ public static Map getEnchantmentMap(NBTTagList nbttaglist) { return a(nbttaglist); } // Purpur - OBFHELPER + public static Map a(NBTTagList nbttaglist) { + Map map = Maps.newLinkedHashMap(); + +diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java +index b44f82517e1e6e1f77144e50716dfb887bf26f70..0548eb1539aa7469e1762c1e43e6a8368fbf09fa 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java +@@ -232,6 +232,7 @@ public class PurpurConfig { + + public static boolean allowInfinityMending = false; + public static boolean allowCrossbowInfinity = false; ++ public static boolean allowUnsafeEnchants = false; + private static void enchantmentSettings() { + if (version < 5) { + boolean oldValue = getBoolean("settings.enchantment.allow-infinite-and-mending-together", false); +@@ -240,6 +241,7 @@ public class PurpurConfig { + } + allowInfinityMending = getBoolean("settings.enchantment.allow-infinity-and-mending-together", allowInfinityMending); + allowCrossbowInfinity = getBoolean("settings.enchantment.allow-infinity-on-crossbow", allowCrossbowInfinity); ++ allowUnsafeEnchants = getBoolean("settings.enchantment.allow-unsafe-enchants", allowUnsafeEnchants); + } + + public static boolean endermanShortHeight = false; diff --git a/patches/Purpur/patches/server/0191-Configurable-sponge-absorption.patch b/patches/Purpur/patches/server/0191-Configurable-sponge-absorption.patch new file mode 100644 index 00000000..b5c4dbcd --- /dev/null +++ b/patches/Purpur/patches/server/0191-Configurable-sponge-absorption.patch @@ -0,0 +1,62 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Encode42 +Date: Wed, 24 Mar 2021 20:30:37 -0400 +Subject: [PATCH] Configurable sponge absorption + +Allows the total area and radius of water blocks the sponge can absorb to be changed. + +diff --git a/src/main/java/net/minecraft/world/level/block/BlockSponge.java b/src/main/java/net/minecraft/world/level/block/BlockSponge.java +index d80eee47390ab202eea0368571421bbc94655ab1..b36536d4cc95797c59549f5db1f67b34ff7b9be2 100644 +--- a/src/main/java/net/minecraft/world/level/block/BlockSponge.java ++++ b/src/main/java/net/minecraft/world/level/block/BlockSponge.java +@@ -76,13 +76,13 @@ public class BlockSponge extends Block { + if (fluid.a((Tag) TagsFluid.WATER)) { + if (iblockdata.getBlock() instanceof IFluidSource && ((IFluidSource) iblockdata.getBlock()).removeFluid(blockList, blockposition2, iblockdata) != FluidTypes.EMPTY) { // CraftBukkit + ++i; +- if (j < 6) { ++ if (j < world.purpurConfig.spongeAbsorptionRadius) { // Purpur + queue.add(new Tuple<>(blockposition2, j + 1)); + } + } else if (iblockdata.getBlock() instanceof BlockFluids) { + blockList.setTypeAndData(blockposition2, Blocks.AIR.getBlockData(), 3); // CraftBukkit + ++i; +- if (j < 6) { ++ if (j < world.purpurConfig.spongeAbsorptionRadius) { // Purpur + queue.add(new Tuple<>(blockposition2, j + 1)); + } + } else if (material == Material.WATER_PLANT || material == Material.REPLACEABLE_WATER_PLANT) { +@@ -93,14 +93,14 @@ public class BlockSponge extends Block { + blockList.setTypeAndData(blockposition2, Blocks.AIR.getBlockData(), 3); + // CraftBukkit end + ++i; +- if (j < 6) { ++ if (j < world.purpurConfig.spongeAbsorptionRadius) { // Purpur + queue.add(new Tuple<>(blockposition2, j + 1)); + } + } + } + } + +- if (i > 64) { ++ if (i > world.purpurConfig.spongeAbsorptionArea) { // Purpur + break; + } + } +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 9cb06d3e3109c08b2e9f3336365dd14241c4faca..8be800300b6cbbd17ede87f279ebb04e9c9123fc 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -601,6 +601,13 @@ public class PurpurWorldConfig { + spawnerDeactivateByRedstone = getBoolean("blocks.spawner.deactivate-by-redstone", spawnerDeactivateByRedstone); + } + ++ public int spongeAbsorptionArea = 64; ++ public int spongeAbsorptionRadius = 6; ++ private void spongeSettings() { ++ spongeAbsorptionArea = getInt("blocks.sponge.absorption.area", spongeAbsorptionArea); ++ spongeAbsorptionRadius = getInt("blocks.sponge.absorption.radius", spongeAbsorptionRadius); ++ } ++ + public float stonecutterDamage = 0.0F; + private void stonecutterSettings() { + stonecutterDamage = (float) getDouble("blocks.stonecutter.damage", stonecutterDamage); diff --git a/patches/Purpur/patches/server/0192-Projectile-offset-config.patch b/patches/Purpur/patches/server/0192-Projectile-offset-config.patch new file mode 100644 index 00000000..3ffdffca --- /dev/null +++ b/patches/Purpur/patches/server/0192-Projectile-offset-config.patch @@ -0,0 +1,125 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: YouHaveTrouble +Date: Thu, 25 Mar 2021 01:56:38 +0100 +Subject: [PATCH] Projectile offset config + + +diff --git a/src/main/java/net/minecraft/world/item/ItemBow.java b/src/main/java/net/minecraft/world/item/ItemBow.java +index 59b803ec4552058f2dda269e9435daf65be10559..6bf8c0f03acd55f0ea5919609f55e2e6736455c5 100644 +--- a/src/main/java/net/minecraft/world/item/ItemBow.java ++++ b/src/main/java/net/minecraft/world/item/ItemBow.java +@@ -41,7 +41,7 @@ public class ItemBow extends ItemProjectileWeapon implements ItemVanishable { + ItemArrow itemarrow = (ItemArrow) ((ItemArrow) (itemstack1.getItem() instanceof ItemArrow ? itemstack1.getItem() : Items.ARROW)); + EntityArrow entityarrow = itemarrow.a(world, itemstack1, (EntityLiving) entityhuman); + +- entityarrow.a(entityhuman, entityhuman.pitch, entityhuman.yaw, 0.0F, f * 3.0F, 1.0F); ++ entityarrow.a(entityhuman, entityhuman.pitch, entityhuman.yaw, 0.0F, f * 3.0F, (float) world.purpurConfig.bowProjectileOffset); // Purpur - Projectile offset config + if (f == 1.0F) { + entityarrow.setCritical(true); + } +diff --git a/src/main/java/net/minecraft/world/item/ItemCrossbow.java b/src/main/java/net/minecraft/world/item/ItemCrossbow.java +index 9cf76f8297c2a44c1df8ce2c4f0813802883a18b..55815737879ce2c736304754f5131961cdcaaebf 100644 +--- a/src/main/java/net/minecraft/world/item/ItemCrossbow.java ++++ b/src/main/java/net/minecraft/world/item/ItemCrossbow.java +@@ -54,7 +54,7 @@ public class ItemCrossbow extends ItemProjectileWeapon implements ItemVanishable + ItemStack itemstack = entityhuman.b(enumhand); + + if (d(itemstack)) { +- a(world, entityhuman, enumhand, itemstack, m(itemstack), 1.0F); ++ a(world, entityhuman, enumhand, itemstack, m(itemstack), (float) world.purpurConfig.crossbowProjectileOffset); // Purpur - Projectile offset config + a(itemstack, false); + return InteractionResultWrapper.consume(itemstack); + } else if (!entityhuman.f(itemstack).isEmpty()) { +diff --git a/src/main/java/net/minecraft/world/item/ItemEgg.java b/src/main/java/net/minecraft/world/item/ItemEgg.java +index 4b1a6ee784da4595931396a905f1358b7a13f3dd..83c85ad70bbe70f1f3f70b83c842a3eb94d520c6 100644 +--- a/src/main/java/net/minecraft/world/item/ItemEgg.java ++++ b/src/main/java/net/minecraft/world/item/ItemEgg.java +@@ -24,7 +24,7 @@ public class ItemEgg extends Item { + EntityEgg entityegg = new EntityEgg(world, entityhuman); + + entityegg.setItem(itemstack); +- entityegg.a(entityhuman, entityhuman.pitch, entityhuman.yaw, 0.0F, 1.5F, 1.0F); ++ entityegg.a(entityhuman, entityhuman.pitch, entityhuman.yaw, 0.0F, 1.5F, (float) world.purpurConfig.eggProjectileOffset); // Purpur - Projectile offset config + // Paper start + com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) entityhuman.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack), (org.bukkit.entity.Projectile) entityegg.getBukkitEntity()); + if (event.callEvent() && world.addEntity(entityegg)) { +diff --git a/src/main/java/net/minecraft/world/item/ItemEnderPearl.java b/src/main/java/net/minecraft/world/item/ItemEnderPearl.java +index 61512c6755f29cb2c228ae3e80b1e08348d784a5..79367f574d6ad9a45a4a8e9ae040aec4103fac37 100644 +--- a/src/main/java/net/minecraft/world/item/ItemEnderPearl.java ++++ b/src/main/java/net/minecraft/world/item/ItemEnderPearl.java +@@ -24,7 +24,7 @@ public class ItemEnderPearl extends Item { + EntityEnderPearl entityenderpearl = new EntityEnderPearl(world, entityhuman); + + entityenderpearl.setItem(itemstack); +- entityenderpearl.a(entityhuman, entityhuman.pitch, entityhuman.yaw, 0.0F, 1.5F, 1.0F); ++ entityenderpearl.a(entityhuman, entityhuman.pitch, entityhuman.yaw, 0.0F, 1.5F, (float) world.purpurConfig.enderPearlProjectileOffset); // Purpur - Projectile offset config + // Paper start + com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) entityhuman.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack), (org.bukkit.entity.Projectile) entityenderpearl.getBukkitEntity()); + if (event.callEvent() && world.addEntity(entityenderpearl)) { +diff --git a/src/main/java/net/minecraft/world/item/ItemPotionThrowable.java b/src/main/java/net/minecraft/world/item/ItemPotionThrowable.java +index 27c61fc4e61b0d76565ca6893514b3c73247c954..394916baaf0e572d14c54acc68bc45ab04b789e3 100644 +--- a/src/main/java/net/minecraft/world/item/ItemPotionThrowable.java ++++ b/src/main/java/net/minecraft/world/item/ItemPotionThrowable.java +@@ -23,7 +23,7 @@ public class ItemPotionThrowable extends ItemPotion { + EntityPotion entitypotion = new EntityPotion(world, entityhuman); + + entitypotion.setItem(itemstack); +- entitypotion.a(entityhuman, entityhuman.pitch, entityhuman.yaw, -20.0F, 0.5F, 1.0F); ++ entitypotion.a(entityhuman, entityhuman.pitch, entityhuman.yaw, -20.0F, 0.5F, (float) world.purpurConfig.throwablePotionProjectileOffset); // Purpur - Projectile offset config + // Paper start + com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) entityhuman.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack), (org.bukkit.entity.Projectile) entitypotion.getBukkitEntity()); + if (event.callEvent() && world.addEntity(entitypotion)) { +diff --git a/src/main/java/net/minecraft/world/item/ItemSnowball.java b/src/main/java/net/minecraft/world/item/ItemSnowball.java +index 8a1d59cb1ea5a8959c52272aa762ec35307246d7..fcca6eee05f1d6bcc2909c376bfba7b74c33c421 100644 +--- a/src/main/java/net/minecraft/world/item/ItemSnowball.java ++++ b/src/main/java/net/minecraft/world/item/ItemSnowball.java +@@ -25,7 +25,7 @@ public class ItemSnowball extends Item { + EntitySnowball entitysnowball = new EntitySnowball(world, entityhuman); + + entitysnowball.setItem(itemstack); +- entitysnowball.a(entityhuman, entityhuman.pitch, entityhuman.yaw, 0.0F, 1.5F, 1.0F); ++ entitysnowball.a(entityhuman, entityhuman.pitch, entityhuman.yaw, 0.0F, 1.5F, (float) world.purpurConfig.snowballProjectileOffset); // Purpur - Projectile offset config + // Paper start + com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) entityhuman.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack), (org.bukkit.entity.Projectile) entitysnowball.getBukkitEntity()); + if (event.callEvent() && world.addEntity(entitysnowball)) { +diff --git a/src/main/java/net/minecraft/world/item/ItemTrident.java b/src/main/java/net/minecraft/world/item/ItemTrident.java +index 0711d195c654edef5875f587e391bacfdea096da..2341c98859faa61662d7ed343e6ed1575fa2281e 100644 +--- a/src/main/java/net/minecraft/world/item/ItemTrident.java ++++ b/src/main/java/net/minecraft/world/item/ItemTrident.java +@@ -74,7 +74,7 @@ public class ItemTrident extends Item implements ItemVanishable { + if (k == 0) { + EntityThrownTrident entitythrowntrident = new EntityThrownTrident(world, entityhuman, itemstack); + +- entitythrowntrident.a(entityhuman, entityhuman.pitch, entityhuman.yaw, 0.0F, 2.5F + (float) k * 0.5F, 1.0F); ++ entitythrowntrident.a(entityhuman, entityhuman.pitch, entityhuman.yaw, 0.0F, 2.5F + (float) k * 0.5F, (float) world.purpurConfig.tridentProjectileOffset); // Purpur - Projectile offset config + if (entityhuman.abilities.canInstantlyBuild) { + entitythrowntrident.fromPlayer = EntityArrow.PickupStatus.CREATIVE_ONLY; + } +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 8be800300b6cbbd17ede87f279ebb04e9c9123fc..ad2e2ae106295a8ce84b404998de535724fd9427 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -317,6 +317,23 @@ public class PurpurWorldConfig { + snowballDamage = getInt("gameplay-mechanics.projectile-damage.snowball", snowballDamage); + } + ++ public double bowProjectileOffset = 1.0D; ++ public double crossbowProjectileOffset = 1.0D; ++ public double eggProjectileOffset = 1.0D; ++ public double enderPearlProjectileOffset = 1.0D; ++ public double throwablePotionProjectileOffset = 1.0D; ++ public double tridentProjectileOffset = 1.0D; ++ public double snowballProjectileOffset = 1.0D; ++ private void projectileOffsetSettings() { ++ bowProjectileOffset = getDouble("gameplay-mechanics.projectile-offset.bow", bowProjectileOffset); ++ crossbowProjectileOffset = getDouble("gameplay-mechanics.projectile-offset.crossbow", crossbowProjectileOffset); ++ eggProjectileOffset = getDouble("gameplay-mechanics.projectile-offset.egg", eggProjectileOffset); ++ enderPearlProjectileOffset = getDouble("gameplay-mechanics.projectile-offset.ender-pearl", enderPearlProjectileOffset); ++ throwablePotionProjectileOffset = getDouble("gameplay-mechanics.projectile-offset.throwable-potion", throwablePotionProjectileOffset); ++ tridentProjectileOffset = getDouble("gameplay-mechanics.projectile-offset.trident", tridentProjectileOffset); ++ snowballProjectileOffset = getDouble("gameplay-mechanics.projectile-offset.snowball", snowballProjectileOffset); ++ } ++ + public boolean useBetterMending = false; + public boolean alwaysTameInCreative = false; + public boolean boatEjectPlayersOnLand = false; diff --git a/patches/Purpur/patches/server/0193-Config-for-powered-rail-activation-distance.patch b/patches/Purpur/patches/server/0193-Config-for-powered-rail-activation-distance.patch new file mode 100644 index 00000000..a045e194 --- /dev/null +++ b/patches/Purpur/patches/server/0193-Config-for-powered-rail-activation-distance.patch @@ -0,0 +1,35 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Encode42 +Date: Thu, 25 Mar 2021 18:10:03 -0400 +Subject: [PATCH] Config for powered rail activation distance + + +diff --git a/src/main/java/net/minecraft/world/level/block/BlockPoweredRail.java b/src/main/java/net/minecraft/world/level/block/BlockPoweredRail.java +index b26e168fbf49bbe7ec981b5b186c94ca67827f4a..bc91c96a29dcc60c578b342055b8eaf3e620a81d 100644 +--- a/src/main/java/net/minecraft/world/level/block/BlockPoweredRail.java ++++ b/src/main/java/net/minecraft/world/level/block/BlockPoweredRail.java +@@ -24,7 +24,7 @@ public class BlockPoweredRail extends BlockMinecartTrackAbstract { + } + + protected boolean a(World world, BlockPosition blockposition, IBlockData iblockdata, boolean flag, int i) { +- if (i >= 8) { ++ if (i >= world.purpurConfig.railActivationRange) { // Purpur + return false; + } else { + int j = blockposition.getX(); +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index ad2e2ae106295a8ce84b404998de535724fd9427..37835f19ce917b36cb56e0d0d58d9be349919cab 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -585,6 +585,11 @@ public class PurpurWorldConfig { + lavaSpeedNotNether = getInt("blocks.lava.speed.not-nether", lavaSpeedNotNether); + } + ++ public int railActivationRange = 8; ++ private void railSettings() { ++ railActivationRange = getInt("blocks.powered-rail.activation-range", railActivationRange); ++ } ++ + public boolean respawnAnchorExplode = true; + public double respawnAnchorExplosionPower = 5.0D; + public boolean respawnAnchorExplosionFire = true; diff --git a/patches/Purpur/patches/server/0194-Piglin-portal-spawn-modifier.patch b/patches/Purpur/patches/server/0194-Piglin-portal-spawn-modifier.patch new file mode 100644 index 00000000..0d0a814d --- /dev/null +++ b/patches/Purpur/patches/server/0194-Piglin-portal-spawn-modifier.patch @@ -0,0 +1,52 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Tue, 13 Apr 2021 11:19:35 -0500 +Subject: [PATCH] Piglin portal spawn modifier + +Allows changing the modifier for the piglin spawn chance from a portal block +based on the world difficulty. + +For example, with the default vanilla value of 2000 there is a 2 out of 2000 chance +for a piglin to spawn in a portal block each tick in normal mode. + +Equation: random.nextInt(modifier) < difficulty + +Difficulties: +0 - peaceful +1 - easy +2 - normal +3 - hard + +diff --git a/src/main/java/net/minecraft/world/level/block/BlockPortal.java b/src/main/java/net/minecraft/world/level/block/BlockPortal.java +index 41733979141ed62523e9058a3f4c4ea753bfbc64..757e3b56221eca5449ded2d94b93cffe10f3c5d9 100644 +--- a/src/main/java/net/minecraft/world/level/block/BlockPortal.java ++++ b/src/main/java/net/minecraft/world/level/block/BlockPortal.java +@@ -52,7 +52,7 @@ public class BlockPortal extends Block { + + @Override + public void tick(IBlockData iblockdata, WorldServer worldserver, BlockPosition blockposition, Random random) { +- if (worldserver.spigotConfig.enableZombiePigmenPortalSpawns && worldserver.getDimensionManager().isNatural() && worldserver.getGameRules().getBoolean(GameRules.DO_MOB_SPAWNING) && random.nextInt(2000) < worldserver.getDifficulty().a()) { // Spigot ++ if (worldserver.spigotConfig.enableZombiePigmenPortalSpawns && worldserver.getDimensionManager().isNatural() && worldserver.getGameRules().getBoolean(GameRules.DO_MOB_SPAWNING) && random.nextInt(worldserver.purpurConfig.piglinPortalSpawnModifier) < worldserver.getDifficulty().a()) { // Spigot + while (worldserver.getType(blockposition).a((Block) this)) { + blockposition = blockposition.down(); + } +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 37835f19ce917b36cb56e0d0d58d9be349919cab..78e4ef0103e1c9f96ec160e74b870902eda5e842 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -1419,6 +1419,7 @@ public class PurpurWorldConfig { + public boolean piglinRidable = false; + public boolean piglinRidableInWater = false; + public double piglinMaxHealth = 16.0D; ++ public int piglinPortalSpawnModifier = 2000; + private void piglinSettings() { + piglinRidable = getBoolean("mobs.piglin.ridable", piglinRidable); + piglinRidableInWater = getBoolean("mobs.piglin.ridable-in-water", piglinRidableInWater); +@@ -1428,6 +1429,7 @@ public class PurpurWorldConfig { + set("mobs.piglin.attributes.max_health", oldValue); + } + piglinMaxHealth = getDouble("mobs.piglin.attributes.max_health", piglinMaxHealth); ++ piglinPortalSpawnModifier = getInt("mobs.piglin.portal-spawn-modifier", piglinPortalSpawnModifier); + } + + public boolean piglinBruteRidable = false; diff --git a/patches/Purpur/patches/server/0195-Config-to-change-max-number-of-bees.patch b/patches/Purpur/patches/server/0195-Config-to-change-max-number-of-bees.patch new file mode 100644 index 00000000..36a448d4 --- /dev/null +++ b/patches/Purpur/patches/server/0195-Config-to-change-max-number-of-bees.patch @@ -0,0 +1,39 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: DoctaEnkoda +Date: Thu, 29 Apr 2021 19:37:48 +0200 +Subject: [PATCH] Config to change max number of bees + + +diff --git a/src/main/java/net/minecraft/world/level/block/entity/TileEntityBeehive.java b/src/main/java/net/minecraft/world/level/block/entity/TileEntityBeehive.java +index 80083a6666a28372946cf0e68ded44d075357f7d..58bf1008ab19340bce5111e006a8de0e7f39e0e5 100644 +--- a/src/main/java/net/minecraft/world/level/block/entity/TileEntityBeehive.java ++++ b/src/main/java/net/minecraft/world/level/block/entity/TileEntityBeehive.java +@@ -29,7 +29,7 @@ public class TileEntityBeehive extends TileEntity implements ITickable { + private final List bees = Lists.newArrayList(); + @Nullable + public BlockPosition flowerPos = null; +- public int maxBees = 3; // CraftBukkit - allow setting max amount of bees a hive can hold ++ public int maxBees = net.pl3x.purpur.PurpurConfig.beeInsideBeeHive; // CraftBukkit - allow setting max amount of bees a hive can hold // Purpur - Change max bees inside beehive and bee_nest + + public TileEntityBeehive() { + super(TileEntityTypes.BEEHIVE); +diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java +index 0548eb1539aa7469e1762c1e43e6a8368fbf09fa..f15684b5d4764b2cae22c1d12b0b25cc41c04b93 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java +@@ -213,6 +213,7 @@ public class PurpurConfig { + public static boolean enderChestSixRows = false; + public static boolean enderChestPermissionRows = false; + public static boolean cryingObsidianValidForPortalFrame = false; ++ public static int beeInsideBeeHive = 3; + private static void blockSettings() { + if (version < 3) { + boolean oldValue = getBoolean("settings.barrel.packed-barrels", true); +@@ -228,6 +229,7 @@ public class PurpurConfig { + InventoryType.ENDER_CHEST.setDefaultSize(enderChestSixRows ? 54 : 27); + enderChestPermissionRows = getBoolean("settings.blocks.ender_chest.use-permissions-for-rows", enderChestPermissionRows); + cryingObsidianValidForPortalFrame = getBoolean("settings.blocks.crying_obsidian.valid-for-portal-frame", cryingObsidianValidForPortalFrame); ++ beeInsideBeeHive = getInt("settings.blocks.beehive.max-bees-inside", beeInsideBeeHive); + } + + public static boolean allowInfinityMending = false; diff --git a/patches/Purpur/patches/server/0196-Configurable-damage-settings-for-magma-blocks.patch b/patches/Purpur/patches/server/0196-Configurable-damage-settings-for-magma-blocks.patch new file mode 100644 index 00000000..39e34dd6 --- /dev/null +++ b/patches/Purpur/patches/server/0196-Configurable-damage-settings-for-magma-blocks.patch @@ -0,0 +1,61 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ben Kerllenevich +Date: Thu, 29 Apr 2021 14:06:29 -0400 +Subject: [PATCH] Configurable damage settings for magma blocks + + +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index 778c5ee222d51e35bac51bba42f336780fd153dc..dcb8cff2671947140f5853b1f6d75ecc03ef368f 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -890,7 +890,7 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, ne + } + // CraftBukkit end + +- if (this.onGround && (!this.bv() || (block == Blocks.STONECUTTER && world.purpurConfig.stonecutterDamage > 0.0F))) { // Purpur ++ if (this.onGround && (!this.bv() || (block == Blocks.STONECUTTER && world.purpurConfig.stonecutterDamage > 0.0F) || (block == Blocks.MAGMA_BLOCK && world.purpurConfig.magmaBlockDamageWhenSneaking))) { // Purpur + block.stepOn(this.world, blockposition, this); + } + +diff --git a/src/main/java/net/minecraft/world/item/enchantment/EnchantmentManager.java b/src/main/java/net/minecraft/world/item/enchantment/EnchantmentManager.java +index 63a6f63a2d3e03e74c314cdebf7cb61b66fd5108..7ad0035045011737eab536343688ebd333f1b93f 100644 +--- a/src/main/java/net/minecraft/world/item/enchantment/EnchantmentManager.java ++++ b/src/main/java/net/minecraft/world/item/enchantment/EnchantmentManager.java +@@ -242,7 +242,7 @@ public class EnchantmentManager { + return a(Enchantments.WATER_WORKER, entityliving) > 0; + } + +- public static boolean i(EntityLiving entityliving) { ++ public static boolean hasFrostWalker(EntityLiving entityLiving) { return i(entityLiving);} public static boolean i(EntityLiving entityliving) { // Purpur - OBFHELPER + return a(Enchantments.FROST_WALKER, entityliving) > 0; + } + +diff --git a/src/main/java/net/minecraft/world/level/block/BlockMagma.java b/src/main/java/net/minecraft/world/level/block/BlockMagma.java +index 4559085fa4452d3a9f59ed967ccb69a7823718e5..0d9e9f972066c1114971d825468b64f53a4af1d2 100644 +--- a/src/main/java/net/minecraft/world/level/block/BlockMagma.java ++++ b/src/main/java/net/minecraft/world/level/block/BlockMagma.java +@@ -27,7 +27,7 @@ public class BlockMagma extends Block { + + @Override + public void stepOn(World world, BlockPosition blockposition, Entity entity) { +- if (!entity.isFireProof() && entity instanceof EntityLiving && !EnchantmentManager.i((EntityLiving) entity)) { ++ if (!entity.isFireProof() && entity instanceof EntityLiving && (world.purpurConfig.magmaBlockDamageWithFrostWalker || !EnchantmentManager.hasFrostWalker((EntityLiving) entity))) { // Purpur + org.bukkit.craftbukkit.event.CraftEventFactory.blockDamage = world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()); // CraftBukkit + entity.damageEntity(DamageSource.HOT_FLOOR, 1.0F); + org.bukkit.craftbukkit.event.CraftEventFactory.blockDamage = null; // CraftBukkit +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 78e4ef0103e1c9f96ec160e74b870902eda5e842..9ad9d80331ea52c08500cd9155ba6fdc1bc22a3a 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -2136,4 +2136,11 @@ public class PurpurWorldConfig { + baseCrystalExplosionEffect = Explosion.Effect.DESTROY; + } + } ++ ++ public boolean magmaBlockDamageWhenSneaking = false; ++ public boolean magmaBlockDamageWithFrostWalker = false; ++ private void magmaBlockSettings() { ++ magmaBlockDamageWhenSneaking = getBoolean("blocks.magma-block.damage-when-sneaking", magmaBlockDamageWhenSneaking); ++ magmaBlockDamageWithFrostWalker = getBoolean("blocks.magma-block.damage-with-frost-walker", magmaBlockDamageWithFrostWalker); ++ } + } diff --git a/patches/Purpur/patches/server/0197-Config-for-wither-explosion-radius.patch b/patches/Purpur/patches/server/0197-Config-for-wither-explosion-radius.patch new file mode 100644 index 00000000..3ae87def --- /dev/null +++ b/patches/Purpur/patches/server/0197-Config-for-wither-explosion-radius.patch @@ -0,0 +1,39 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ben Kerllenevich +Date: Thu, 29 Apr 2021 14:39:07 -0400 +Subject: [PATCH] Config for wither explosion radius + + +diff --git a/src/main/java/net/minecraft/world/entity/projectile/EntityWitherSkull.java b/src/main/java/net/minecraft/world/entity/projectile/EntityWitherSkull.java +index 616b5267d1d94b2be37ec48983b45e4478502fb5..052cffb156e4e6f31df3935fd8312eb37e3b7019 100644 +--- a/src/main/java/net/minecraft/world/entity/projectile/EntityWitherSkull.java ++++ b/src/main/java/net/minecraft/world/entity/projectile/EntityWitherSkull.java +@@ -98,7 +98,7 @@ public class EntityWitherSkull extends EntityFireball { + + // CraftBukkit start + // this.world.createExplosion(this, this.locX(), this.locY(), this.locZ(), 1.0F, false, explosion_effect); +- ExplosionPrimeEvent event = new ExplosionPrimeEvent(this.getBukkitEntity(), 1.0F, false); ++ ExplosionPrimeEvent event = new ExplosionPrimeEvent(this.getBukkitEntity(), world.purpurConfig.witherExplosionRadius, false); // Purpur + this.world.getServer().getPluginManager().callEvent(event); + + if (!event.isCancelled()) { +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 9ad9d80331ea52c08500cd9155ba6fdc1bc22a3a..3d3e4e686cd74145b002b2df276e61762697918b 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -1913,6 +1913,7 @@ public class PurpurWorldConfig { + public int witherHealthRegenDelay = 20; + public double witherMaxHealth = 300.0D; + public boolean witherCanRideVehicles = false; ++ public float witherExplosionRadius = 1.0F; + private void witherSettings() { + witherRidable = getBoolean("mobs.wither.ridable", witherRidable); + witherRidableInWater = getBoolean("mobs.wither.ridable-in-water", witherRidableInWater); +@@ -1931,6 +1932,7 @@ public class PurpurWorldConfig { + } + witherMaxHealth = getDouble("mobs.wither.attributes.max_health", witherMaxHealth); + witherCanRideVehicles = getBoolean("mobs.wither.can-ride-vehicles", witherCanRideVehicles); ++ witherExplosionRadius = (float) getDouble("mobs.wither.explosion-radius", witherExplosionRadius); + } + + public boolean witherSkeletonRidable = false; diff --git a/patches/Purpur/patches/server/0198-Add-credits-command.patch b/patches/Purpur/patches/server/0198-Add-credits-command.patch new file mode 100644 index 00000000..5f0b14bc --- /dev/null +++ b/patches/Purpur/patches/server/0198-Add-credits-command.patch @@ -0,0 +1,98 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Encode42 +Date: Fri, 30 Apr 2021 14:03:06 -0400 +Subject: [PATCH] Add credits command + + +diff --git a/src/main/java/net/minecraft/commands/CommandDispatcher.java b/src/main/java/net/minecraft/commands/CommandDispatcher.java +index 4338b459011bf7a083790b7bb76cf1b24471fd19..c5babb19a3b4d20c4f9e414d5654d18c570d2b2d 100644 +--- a/src/main/java/net/minecraft/commands/CommandDispatcher.java ++++ b/src/main/java/net/minecraft/commands/CommandDispatcher.java +@@ -191,6 +191,7 @@ public class CommandDispatcher { + CommandIdleTimeout.a(this.b); + CommandStop.a(this.b); + CommandWhitelist.a(this.b); ++ net.pl3x.purpur.command.CreditsCommand.register(getDispatcher()); // Purpur + net.pl3x.purpur.command.DemoCommand.register(getDispatcher()); // Purpur + net.pl3x.purpur.command.PingCommand.register(getDispatcher()); // Purpur + net.pl3x.purpur.command.TPSBarCommand.register(getDispatcher()); // Purpur +diff --git a/src/main/java/net/minecraft/network/protocol/game/PacketPlayOutGameStateChange.java b/src/main/java/net/minecraft/network/protocol/game/PacketPlayOutGameStateChange.java +index 0161657748d398b6827ef8bc2b00b8a63bf37c55..aaff933c5bf619303842ce6b9a9dc979bcfde7bd 100644 +--- a/src/main/java/net/minecraft/network/protocol/game/PacketPlayOutGameStateChange.java ++++ b/src/main/java/net/minecraft/network/protocol/game/PacketPlayOutGameStateChange.java +@@ -12,7 +12,7 @@ public class PacketPlayOutGameStateChange implements Packet dispatcher) { ++ dispatcher.register(CommandDispatcher.literal("credits") ++ .requires((listener) -> { ++ return listener.hasPermission(2); ++ }) ++ .executes((context) -> { ++ return execute(context.getSource(), Collections.singleton(context.getSource().getPlayerOrException())); ++ }) ++ .then(CommandDispatcher.argument("targets", ArgumentEntity.players()) ++ .executes((context) -> { ++ return execute(context.getSource(), ArgumentEntity.getPlayers(context, "targets")); ++ }) ++ ) ++ ).setPermission("bukkit.command.credits"); ++ } ++ ++ private static int execute(CommandListenerWrapper sender, Collection targets) { ++ for (EntityPlayer player : targets) { ++ PacketPlayOutGameStateChange packet = new PacketPlayOutGameStateChange(PacketPlayOutGameStateChange.credits(), 1F); ++ player.viewingCredits = true; ++ player.playerConnection.sendPacket(packet); ++ String output = String.format(PurpurConfig.creditsCommandOutput, player.getProfile().getName()); ++ sender.sendMessage(CraftChatMessage.fromStringOrNull(output), false); ++ } ++ return targets.size(); ++ } ++} diff --git a/patches/Purpur/patches/server/0199-Gamemode-extra-permissions.patch b/patches/Purpur/patches/server/0199-Gamemode-extra-permissions.patch new file mode 100644 index 00000000..1e559e76 --- /dev/null +++ b/patches/Purpur/patches/server/0199-Gamemode-extra-permissions.patch @@ -0,0 +1,107 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Fri, 30 Apr 2021 13:39:39 -0500 +Subject: [PATCH] Gamemode extra permissions + + +diff --git a/src/main/java/net/minecraft/commands/CommandListenerWrapper.java b/src/main/java/net/minecraft/commands/CommandListenerWrapper.java +index 4480fe75cfad35a5104b5116c5ec2c80d18f15f5..d73daa29f784283e03ad2ea3126cca7e572602d4 100644 +--- a/src/main/java/net/minecraft/commands/CommandListenerWrapper.java ++++ b/src/main/java/net/minecraft/commands/CommandListenerWrapper.java +@@ -190,6 +190,21 @@ public class CommandListenerWrapper implements ICompletionProvider, com.destroys + } + // CraftBukkit end + ++ // Purpur start ++ public boolean testPermission(int i, String bukkitPermission) { ++ if (hasPermission(i, bukkitPermission)) { ++ return true; ++ } ++ String permissionMessage = getWorld().getServer().getPermissionMessage(); ++ if (permissionMessage.length() != 0) { ++ for (String line : permissionMessage.replace("", bukkitPermission).split("\n")) { ++ sendFailureMessage(new ChatComponentText(line)); ++ } ++ } ++ return false; ++ } ++ // Purpur end ++ + public Vec3D getPosition() { + return this.d; + } +diff --git a/src/main/java/net/minecraft/server/commands/CommandGamemode.java b/src/main/java/net/minecraft/server/commands/CommandGamemode.java +index 8da48d9cbadfbe83ae8410cf49d78df49f50fb08..323fa988529a7ad316a4dc8d3fc0f62b1478c334 100644 +--- a/src/main/java/net/minecraft/server/commands/CommandGamemode.java ++++ b/src/main/java/net/minecraft/server/commands/CommandGamemode.java +@@ -55,6 +55,21 @@ public class CommandGamemode { + } + + private static int a(CommandContext commandcontext, Collection collection, EnumGamemode enumgamemode) { ++ // Purpur start ++ if (net.pl3x.purpur.PurpurConfig.commandGamemodeRequiresPermission) { ++ String gamemode = enumgamemode.getName(); ++ CommandListenerWrapper sender = commandcontext.getSource(); ++ if (!sender.testPermission(2, "minecraft.command.gamemode." + gamemode)) { ++ return 0; ++ } ++ if (sender.getEntity() instanceof EntityPlayer) { ++ EntityPlayer player = (EntityPlayer) sender.getEntity(); ++ if ((collection.size() > 1 || !collection.contains(player)) && !sender.testPermission(2, "minecraft.command.gamemode." + gamemode + ".other")) { ++ return 0; ++ } ++ } ++ } ++ // Purpur end + int i = 0; + Iterator iterator = collection.iterator(); + +diff --git a/src/main/java/net/minecraft/world/level/EnumGamemode.java b/src/main/java/net/minecraft/world/level/EnumGamemode.java +index eea551a68ba44927cb23560b898dd2c17f041442..1b049bdc897aaf1f0cb9b6dfeaf3a1e44214aef1 100644 +--- a/src/main/java/net/minecraft/world/level/EnumGamemode.java ++++ b/src/main/java/net/minecraft/world/level/EnumGamemode.java +@@ -20,6 +20,7 @@ public enum EnumGamemode { + return this.f; + } + ++ public String getName() { return b(); } // Purpur - OBFHELPER + public String b() { + return this.g; + } +diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java +index 9e384f575cd072aac635eb14209daf68f83fc692..9f5bcec2c41e24310fe9b34bd51050f62164f1b1 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java +@@ -211,6 +211,11 @@ public class PurpurConfig { + disableGiveCommandDrops = getBoolean("settings.disable-give-dropping", disableGiveCommandDrops); + } + ++ public static boolean commandGamemodeRequiresPermission = false; ++ private static void commandSettings() { ++ commandGamemodeRequiresPermission = getBoolean("settings.command.gamemode.requires-specific-permission", commandGamemodeRequiresPermission); ++ } ++ + public static boolean barrelSixRows = false; + public static boolean enderChestSixRows = false; + public static boolean enderChestPermissionRows = false; +diff --git a/src/main/java/org/bukkit/craftbukkit/util/permissions/CommandPermissions.java b/src/main/java/org/bukkit/craftbukkit/util/permissions/CommandPermissions.java +index f0a57d225b81a505ff12425155ba838d8fad990c..9341bba9e48d4def2609d759a0dea7e099d5d777 100644 +--- a/src/main/java/org/bukkit/craftbukkit/util/permissions/CommandPermissions.java ++++ b/src/main/java/org/bukkit/craftbukkit/util/permissions/CommandPermissions.java +@@ -23,7 +23,15 @@ public final class CommandPermissions { + DefaultPermissions.registerPermission(PREFIX + "kick", "Allows the user to kick players", PermissionDefault.OP, commands); + DefaultPermissions.registerPermission(PREFIX + "stop", "Allows the user to stop the server", PermissionDefault.OP, commands); + DefaultPermissions.registerPermission(PREFIX + "list", "Allows the user to list all online players", PermissionDefault.OP, commands); +- DefaultPermissions.registerPermission(PREFIX + "gamemode", "Allows the user to change the gamemode of another player", PermissionDefault.OP, commands); ++ // Purpur start ++ Permission gamemodeVanilla = DefaultPermissions.registerPermission(PREFIX + "gamemode", "Allows the user to change the gamemode", PermissionDefault.OP, commands); ++ for (net.minecraft.world.level.EnumGamemode enumgamemode : net.minecraft.world.level.EnumGamemode.values()) { ++ Permission gamemodeSelf = DefaultPermissions.registerPermission(PREFIX + "gamemode." + enumgamemode.getName(), "Allows the user to set " + enumgamemode.getName() + " gamemode for self", PermissionDefault.OP); ++ Permission gamemodeOther = DefaultPermissions.registerPermission(PREFIX + "gamemode." + enumgamemode.getName() + ".other", "Allows the user to set " + enumgamemode.getName() + " gamemode for other players", PermissionDefault.OP); ++ gamemodeSelf.addParent(gamemodeOther, true); ++ gamemodeVanilla.addParent(gamemodeSelf, true); ++ } ++ // Purpur end + DefaultPermissions.registerPermission(PREFIX + "xp", "Allows the user to give themselves or others arbitrary values of experience", PermissionDefault.OP, commands); + DefaultPermissions.registerPermission(PREFIX + "toggledownfall", "Allows the user to toggle rain on/off for a given world", PermissionDefault.OP, commands); + DefaultPermissions.registerPermission(PREFIX + "defaultgamemode", "Allows the user to change the default gamemode of the server", PermissionDefault.OP, commands); diff --git a/patches/Purpur/patches/server/0200-Config-for-changing-the-blocks-that-turn-into-paths.patch b/patches/Purpur/patches/server/0200-Config-for-changing-the-blocks-that-turn-into-paths.patch new file mode 100644 index 00000000..a4558dd3 --- /dev/null +++ b/patches/Purpur/patches/server/0200-Config-for-changing-the-blocks-that-turn-into-paths.patch @@ -0,0 +1,40 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: 12emin34 +Date: Thu, 29 Apr 2021 23:56:02 +0200 +Subject: [PATCH] Config for changing the blocks that turn into paths + + +diff --git a/src/main/java/net/minecraft/world/item/ItemSpade.java b/src/main/java/net/minecraft/world/item/ItemSpade.java +index 9ba8ae49e18fb8714b434715bd669b8e22004cd7..c0c87d0dc8d6f02597219cd6a74e6ed7856ea229 100644 +--- a/src/main/java/net/minecraft/world/item/ItemSpade.java ++++ b/src/main/java/net/minecraft/world/item/ItemSpade.java +@@ -43,7 +43,7 @@ public class ItemSpade extends ItemTool { + return EnumInteractionResult.PASS; + } else { + EntityHuman entityhuman = itemactioncontext.getEntity(); +- IBlockData iblockdata1 = (IBlockData) ItemSpade.a.get(iblockdata.getBlock()); ++ IBlockData iblockdata1 = world.purpurConfig.shovelTurnsBlockToGrassPath.contains(iblockdata.getBlock()) ? Blocks.GRASS_PATH.getBlockData() : ItemSpade.a.get(iblockdata.getBlock()); // Purpur + IBlockData iblockdata2 = null; + + if (iblockdata1 != null && world.getType(blockposition.up()).isAir()) { +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 3d3e4e686cd74145b002b2df276e61762697918b..e082de2fdbd4803f5c79699b813062291f8e2bb7 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -469,6 +469,16 @@ public class PurpurWorldConfig { + totemOfUndyingWorksInInventory = getBoolean("gameplay-mechanics.player.totem-of-undying-works-in-inventory", totemOfUndyingWorksInInventory); + } + ++ public List shovelTurnsBlockToGrassPath = new ArrayList<>(); ++ private void shovelSettings() { ++ getList("gameplay-mechanics.shovel-turns-block-to-grass-path", new ArrayList(){{ ++ add("minecraft:grass_block"); ++ }}).forEach(key -> { ++ Block block = IRegistry.BLOCK.get(new MinecraftKey(key.toString())); ++ if (block != Blocks.AIR) shovelTurnsBlockToGrassPath.add(block); ++ }); ++ } ++ + public boolean silkTouchEnabled = false; + public String silkTouchSpawnerName = "Spawner"; + public List silkTouchSpawnerLore = new ArrayList<>(); diff --git a/patches/Purpur/patches/server/0201-Allows-you-to-change-the-thrust-limit-of-a-piston-by.patch b/patches/Purpur/patches/server/0201-Allows-you-to-change-the-thrust-limit-of-a-piston-by.patch new file mode 100644 index 00000000..8c5c9d2d --- /dev/null +++ b/patches/Purpur/patches/server/0201-Allows-you-to-change-the-thrust-limit-of-a-piston-by.patch @@ -0,0 +1,60 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: DoctaEnkoda +Date: Sun, 2 May 2021 23:14:54 +0200 +Subject: [PATCH] Allows you to change the thrust limit of a piston by World + + +diff --git a/src/main/java/net/minecraft/world/level/block/piston/PistonExtendsChecker.java b/src/main/java/net/minecraft/world/level/block/piston/PistonExtendsChecker.java +index 6c9c4ab65b7e42efa68027057242e25b70313081..cbe34059659e0f80ff384508b01e516cd7c5e28a 100644 +--- a/src/main/java/net/minecraft/world/level/block/piston/PistonExtendsChecker.java ++++ b/src/main/java/net/minecraft/world/level/block/piston/PistonExtendsChecker.java +@@ -12,7 +12,7 @@ import net.minecraft.world.level.material.EnumPistonReaction; + + public class PistonExtendsChecker { + +- private final World a; ++ private final World a; public World getWorld() { return a; } // Purpur - OBFHELPER + private final BlockPosition b; + private final boolean c; + private final BlockPosition d; +@@ -86,7 +86,7 @@ public class PistonExtendsChecker { + } else { + int i = 1; + +- if (i + this.f.size() > 12) { ++ if (i + this.f.size() > this.getWorld().purpurConfig.pistonBlockPushLimit) { // Purpur + return false; + } else { + while (a(block)) { +@@ -100,7 +100,7 @@ public class PistonExtendsChecker { + } + + ++i; +- if (i + this.f.size() > 12) { ++ if (i + this.f.size() > this.getWorld().purpurConfig.pistonBlockPushLimit) { // Purpur + return false; + } + } +@@ -148,7 +148,7 @@ public class PistonExtendsChecker { + return true; + } + +- if (this.f.size() >= 12) { ++ if (this.f.size() >= this.getWorld().purpurConfig.pistonBlockPushLimit) { // Purpur + return false; + } + +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index e082de2fdbd4803f5c79699b813062291f8e2bb7..07c66f9d41e7a74021dde6702d654710e400e93b 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -2155,4 +2155,9 @@ public class PurpurWorldConfig { + magmaBlockDamageWhenSneaking = getBoolean("blocks.magma-block.damage-when-sneaking", magmaBlockDamageWhenSneaking); + magmaBlockDamageWithFrostWalker = getBoolean("blocks.magma-block.damage-with-frost-walker", magmaBlockDamageWithFrostWalker); + } ++ ++ public int pistonBlockPushLimit = 12; ++ private void pistonSettings() { ++ pistonBlockPushLimit = getInt("blocks.piston.block-push-limit", pistonBlockPushLimit); ++ } + } diff --git a/patches/Purpur/patches/server/0202-Allows-change-broadcast-message-by-player.patch b/patches/Purpur/patches/server/0202-Allows-change-broadcast-message-by-player.patch new file mode 100644 index 00000000..9fe946a9 --- /dev/null +++ b/patches/Purpur/patches/server/0202-Allows-change-broadcast-message-by-player.patch @@ -0,0 +1,68 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: DoctaEnkoda +Date: Mon, 3 May 2021 01:33:14 +0200 +Subject: [PATCH] Allows change broadcast message by player + + +diff --git a/src/main/java/net/minecraft/server/AdvancementDataPlayer.java b/src/main/java/net/minecraft/server/AdvancementDataPlayer.java +index a1ee1066108985a95abddb03ff447b5a14f4f85f..4720644ae82f76f835f14c0b3a00e7b7874fb1e2 100644 +--- a/src/main/java/net/minecraft/server/AdvancementDataPlayer.java ++++ b/src/main/java/net/minecraft/server/AdvancementDataPlayer.java +@@ -60,7 +60,7 @@ public class AdvancementDataPlayer { + private static final TypeToken> c = new TypeToken>() { + }; + private final DataFixer d; +- private final PlayerList e; ++ private final PlayerList e; public PlayerList getPlayerList() { return e; } // Purpur - OBFHELPER + private final File f; + public final Map data = Maps.newLinkedHashMap(); + private final Set h = Sets.newLinkedHashSet(); +@@ -325,7 +325,13 @@ public class AdvancementDataPlayer { + advancement.d().a(this.player); + // Paper start - Add Adventure message to PlayerAdvancementDoneEvent + if (message != null && this.player.world.getGameRules().getBoolean(GameRules.ANNOUNCE_ADVANCEMENTS)) { +- this.e.sendMessage(PaperAdventure.asVanilla(message), ChatMessageType.SYSTEM, SystemUtils.getNullUUID()); ++ // Purpur Start - AdvancementMessage By Player ++ if (net.pl3x.purpur.PurpurConfig.advancementOnlyBroadcastToAffectedPlayer) { ++ this.player.sendMessage(PaperAdventure.asVanilla(message), SystemUtils.getNullUUID()); ++ } else { ++ getPlayerList().sendMessage(PaperAdventure.asVanilla(message), ChatMessageType.SYSTEM, SystemUtils.getNullUUID()); ++ } ++ // Purpur End + // Paper end + } + } +diff --git a/src/main/java/net/minecraft/server/level/EntityPlayer.java b/src/main/java/net/minecraft/server/level/EntityPlayer.java +index b8f9678ac9207e099a485c7d5c98f5766f32bd29..6d67eff4d584c287c97dfe32832c87bb59725bee 100644 +--- a/src/main/java/net/minecraft/server/level/EntityPlayer.java ++++ b/src/main/java/net/minecraft/server/level/EntityPlayer.java +@@ -1038,7 +1038,7 @@ public class EntityPlayer extends EntityHuman implements ICrafting { + + }); + ScoreboardTeamBase scoreboardteambase = this.getScoreboardTeam(); +- ++ if (net.pl3x.purpur.PurpurConfig.deathMessageOnlyBroadcastToAffectedPlayer) this.sendMessage(ichatbasecomponent); else // Purpur + if (scoreboardteambase != null && scoreboardteambase.getDeathMessageVisibility() != ScoreboardTeamBase.EnumNameTagVisibility.ALWAYS) { + if (scoreboardteambase.getDeathMessageVisibility() == ScoreboardTeamBase.EnumNameTagVisibility.HIDE_FOR_OTHER_TEAMS) { + this.server.getPlayerList().a((EntityHuman) this, ichatbasecomponent); +diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java +index 9f5bcec2c41e24310fe9b34bd51050f62164f1b1..3234089f2b6da7d32e0c5c15f2120557a456efd0 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java +@@ -289,4 +289,16 @@ public class PurpurConfig { + private static void tpsCatchup() { + tpsCatchup = getBoolean("settings.tps-catchup", tpsCatchup); + } ++ ++ public static boolean advancementOnlyBroadcastToAffectedPlayer = false; ++ public static boolean deathMessageOnlyBroadcastToAffectedPlayer = false; ++ private static void broadcastSettings() { ++ if (version < 13) { ++ boolean oldValue = getBoolean("settings.advancement.only-broadcast-to-affected-player", false); ++ set("settings.broadcasts.advancement.only-broadcast-to-affected-player", oldValue); ++ set("settings.advancement.only-broadcast-to-affected-player", null); ++ } ++ advancementOnlyBroadcastToAffectedPlayer = getBoolean("settings.broadcasts.advancement.only-broadcast-to-affected-player", advancementOnlyBroadcastToAffectedPlayer); ++ deathMessageOnlyBroadcastToAffectedPlayer = getBoolean("settings.broadcasts.death.only-broadcast-to-affected-player", deathMessageOnlyBroadcastToAffectedPlayer); ++ } + } diff --git a/patches/Purpur/patches/server/0203-Fix-SPIGOT-6278.patch b/patches/Purpur/patches/server/0203-Fix-SPIGOT-6278.patch new file mode 100644 index 00000000..92114fd5 --- /dev/null +++ b/patches/Purpur/patches/server/0203-Fix-SPIGOT-6278.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Mon, 10 May 2021 02:08:53 -0500 +Subject: [PATCH] Fix SPIGOT-6278 + + +diff --git a/src/main/java/net/minecraft/world/entity/monster/piglin/EntityPiglin.java b/src/main/java/net/minecraft/world/entity/monster/piglin/EntityPiglin.java +index f34ee0cf7a31cd7a9ee8f7e7ae76e9008f6da35b..77af7152a2e5ff99e98a0063947427c0d18aabcb 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/piglin/EntityPiglin.java ++++ b/src/main/java/net/minecraft/world/entity/monster/piglin/EntityPiglin.java +@@ -200,7 +200,7 @@ public class EntityPiglin extends EntityPiglinAbstract implements ICrossbow { + + @Override + public boolean isTypeNotPersistent(double d0) { +- return !this.isPersistent(); ++ return true || !this.isPersistent(); // Purpur - fix SPIGOT-6278 + } + + @Override diff --git a/patches/Purpur/patches/server/0204-Implement-Mob-Blindness.patch b/patches/Purpur/patches/server/0204-Implement-Mob-Blindness.patch new file mode 100644 index 00000000..80fc7bb5 --- /dev/null +++ b/patches/Purpur/patches/server/0204-Implement-Mob-Blindness.patch @@ -0,0 +1,46 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Encode42 +Date: Tue, 11 May 2021 21:00:53 -0400 +Subject: [PATCH] Implement Mob Blindness + +Ported from https://github.com/raltsmc/mobblindness + +diff --git a/src/main/java/net/minecraft/world/entity/EntityLiving.java b/src/main/java/net/minecraft/world/entity/EntityLiving.java +index 379782d5dcb212419c8df2a9a534749b3bd63f21..fa8df6ecede6ecb207e0e3390cc96c72d71a8a18 100644 +--- a/src/main/java/net/minecraft/world/entity/EntityLiving.java ++++ b/src/main/java/net/minecraft/world/entity/EntityLiving.java +@@ -922,6 +922,18 @@ public abstract class EntityLiving extends Entity { + if (entitytypes == EntityTypes.SKELETON && item == Items.SKELETON_SKULL || entitytypes == EntityTypes.ZOMBIE && item == Items.ZOMBIE_HEAD || entitytypes == EntityTypes.CREEPER && item == Items.CREEPER_HEAD) { + d0 *= 0.5D; + } ++ ++ // Purpur start ++ if (entity instanceof EntityLiving) { ++ EntityLiving livingEntity = (EntityLiving) entity; ++ if (livingEntity.hasEffect(MobEffects.BLINDNESS)) { ++ int amplifier = livingEntity.getEffect(MobEffects.BLINDNESS).getAmplifier(); ++ for (int i = 0; i < amplifier; i++) { ++ d0 *= world.purpurConfig.mobsBlindnessMultiplier; ++ } ++ } ++ } ++ // Purpur end + } + + return d0; +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 07c66f9d41e7a74021dde6702d654710e400e93b..b8622f687b4fd70aaee5fa44cc50b8ee38582582 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -542,6 +542,11 @@ public class PurpurWorldConfig { + mobsSpawnOnBlueIce = getBoolean("blocks.blue_ice.allow-mob-spawns", mobsSpawnOnBlueIce); + } + ++ public double mobsBlindnessMultiplier = 1; ++ private void blindnessSettings() { ++ mobsBlindnessMultiplier = getDouble("gameplay-mechanics.entity-blindness-multiplier", mobsBlindnessMultiplier); ++ } ++ + public boolean chestOpenWithBlockOnTop = false; + private void chestSettings() { + chestOpenWithBlockOnTop = getBoolean("blocks.chest.open-with-solid-block-on-top", chestOpenWithBlockOnTop); diff --git a/patches/Purpur/patches/server/0205-Hide-hidden-players-from-entity-selector.patch b/patches/Purpur/patches/server/0205-Hide-hidden-players-from-entity-selector.patch new file mode 100644 index 00000000..5044d5de --- /dev/null +++ b/patches/Purpur/patches/server/0205-Hide-hidden-players-from-entity-selector.patch @@ -0,0 +1,76 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Thu, 13 May 2021 16:18:29 -0500 +Subject: [PATCH] Hide hidden players from entity selector + + +diff --git a/src/main/java/net/minecraft/commands/arguments/selector/EntitySelector.java b/src/main/java/net/minecraft/commands/arguments/selector/EntitySelector.java +index ee3123ac8a568d915ca4e1b42fc1196c269b287e..82125185233bdc59ef93d376e7327180c98c794d 100644 +--- a/src/main/java/net/minecraft/commands/arguments/selector/EntitySelector.java ++++ b/src/main/java/net/minecraft/commands/arguments/selector/EntitySelector.java +@@ -169,10 +169,10 @@ public class EntitySelector { + + if (this.j != null) { + entityplayer = commandlistenerwrapper.getServer().getPlayerList().getPlayer(this.j); +- return (List) (entityplayer == null ? Collections.emptyList() : Lists.newArrayList(new EntityPlayer[]{entityplayer})); ++ return entityplayer == null || !canSee(commandlistenerwrapper, entityplayer) ? Collections.emptyList() : Lists.newArrayList(entityplayer); // Purpur + } else if (this.k != null) { + entityplayer = commandlistenerwrapper.getServer().getPlayerList().getPlayer(this.k); +- return (List) (entityplayer == null ? Collections.emptyList() : Lists.newArrayList(new EntityPlayer[]{entityplayer})); ++ return entityplayer == null || !canSee(commandlistenerwrapper, entityplayer) ? Collections.emptyList() : Lists.newArrayList(entityplayer); // Purpur + } else { + Vec3D vec3d = (Vec3D) this.f.apply(commandlistenerwrapper.getPosition()); + Predicate predicate = this.a(vec3d); +@@ -182,7 +182,7 @@ public class EntitySelector { + EntityPlayer entityplayer1 = (EntityPlayer) commandlistenerwrapper.getEntity(); + + if (predicate.test(entityplayer1)) { +- return Lists.newArrayList(new EntityPlayer[]{entityplayer1}); ++ return !canSee(commandlistenerwrapper, entityplayer1) ? Collections.emptyList() : Lists.newArrayList(entityplayer1); // Purpur + } + } + +@@ -195,6 +195,7 @@ public class EntitySelector { + + predicate.getClass(); + object = worldserver.a(predicate::test); ++ ((List) object).removeIf(entityplayer3 -> !canSee(commandlistenerwrapper, (EntityPlayer) entityplayer3)); // Purpur + } else { + object = Lists.newArrayList(); + Iterator iterator = commandlistenerwrapper.getServer().getPlayerList().getPlayers().iterator(); +@@ -202,7 +203,7 @@ public class EntitySelector { + while (iterator.hasNext()) { + EntityPlayer entityplayer2 = (EntityPlayer) iterator.next(); + +- if (predicate.test(entityplayer2)) { ++ if (predicate.test(entityplayer2) && canSee(commandlistenerwrapper, entityplayer2)) { // Purpur + ((List) object).add(entityplayer2); + } + } +@@ -244,4 +245,11 @@ public class EntitySelector { + public static IChatMutableComponent a(List list) { + return ChatComponentUtils.b(list, Entity::getScoreboardDisplayName); + } ++ ++ // Purpur start ++ private boolean canSee(CommandListenerWrapper commandlistenerwrapper, EntityPlayer target) { ++ Entity entity = commandlistenerwrapper.getEntity(); ++ return !net.pl3x.purpur.PurpurConfig.hideHiddenPlayersFromEntitySelector || !(entity instanceof EntityPlayer) || ((EntityPlayer) entity).getBukkitEntity().canSee(target.getBukkitEntity()); ++ } ++ // Purpur end + } +diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java +index 3234089f2b6da7d32e0c5c15f2120557a456efd0..475e7dcf01d3779664a8e5fc4c1c4c7550c50750 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java +@@ -212,8 +212,10 @@ public class PurpurConfig { + } + + public static boolean commandGamemodeRequiresPermission = false; ++ public static boolean hideHiddenPlayersFromEntitySelector = false; + private static void commandSettings() { + commandGamemodeRequiresPermission = getBoolean("settings.command.gamemode.requires-specific-permission", commandGamemodeRequiresPermission); ++ hideHiddenPlayersFromEntitySelector = getBoolean("settings.command.hide-hidden-players-from-entity-selector", hideHiddenPlayersFromEntitySelector); + } + + public static boolean barrelSixRows = false; diff --git a/patches/Purpur/patches/server/0206-Config-for-health-to-impact-Creeper-explosion-radius.patch b/patches/Purpur/patches/server/0206-Config-for-health-to-impact-Creeper-explosion-radius.patch new file mode 100644 index 00000000..3ef06697 --- /dev/null +++ b/patches/Purpur/patches/server/0206-Config-for-health-to-impact-Creeper-explosion-radius.patch @@ -0,0 +1,42 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Encode42 +Date: Thu, 29 Apr 2021 20:28:18 -0400 +Subject: [PATCH] Config for health to impact Creeper explosion radius + + +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityCreeper.java b/src/main/java/net/minecraft/world/entity/monster/EntityCreeper.java +index 27d5e9fc5ec1396e95180fc14e8a61b030cfd1e6..d2ae28bb1a2db6dde2aa7c95589656b6eaf3072d 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityCreeper.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityCreeper.java +@@ -341,9 +341,10 @@ public class EntityCreeper extends EntityMonster { + if (!this.world.isClientSide) { + Explosion.Effect explosion_effect = this.world.getGameRules().getBoolean(GameRules.MOB_GRIEFING) && world.purpurConfig.creeperAllowGriefing ? Explosion.Effect.DESTROY : Explosion.Effect.NONE; // Purpur + float f = this.isPowered() ? 2.0F : 1.0F; ++ float multiplier = this.world.purpurConfig.creeperHealthRadius ? this.getHealth() / this.getMaxHealth() : 1; // Purpur + + // CraftBukkit start +- ExplosionPrimeEvent event = new ExplosionPrimeEvent(this.getBukkitEntity(), this.explosionRadius * f, false); ++ ExplosionPrimeEvent event = new ExplosionPrimeEvent(this.getBukkitEntity(), multiplier * (this.explosionRadius * f), false); // Purpur + this.world.getServer().getPluginManager().callEvent(event); + if (!event.isCancelled()) { + this.killed = true; +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index b8622f687b4fd70aaee5fa44cc50b8ee38582582..5659e75177f3c5acb935b0f6dc0b720853602108 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -830,6 +830,7 @@ public class PurpurWorldConfig { + public boolean creeperRidable = false; + public boolean creeperRidableInWater = false; + public boolean creeperExplodeWhenKilled = false; ++ public boolean creeperHealthRadius = false; + public boolean creeperAllowGriefing = true; + public double creeperChargedChance = 0.0D; + public double creeperMaxHealth = 20.0D; +@@ -837,6 +838,7 @@ public class PurpurWorldConfig { + creeperRidable = getBoolean("mobs.creeper.ridable", creeperRidable); + creeperRidableInWater = getBoolean("mobs.creeper.ridable-in-water", creeperRidableInWater); + creeperExplodeWhenKilled = getBoolean("mobs.creeper.explode-when-killed", creeperExplodeWhenKilled); ++ creeperHealthRadius = getBoolean("mobs.creeper.health-impacts-explosion", creeperHealthRadius); + creeperAllowGriefing = getBoolean("mobs.creeper.allow-griefing", creeperAllowGriefing); + creeperChargedChance = getDouble("mobs.creeper.naturally-charged-chance", creeperChargedChance); + if (PurpurConfig.version < 10) { diff --git a/patches/Purpur/patches/server/0207-Optimize-collisions.patch b/patches/Purpur/patches/server/0207-Optimize-collisions.patch new file mode 100644 index 00000000..e8090696 --- /dev/null +++ b/patches/Purpur/patches/server/0207-Optimize-collisions.patch @@ -0,0 +1,78 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: DoctaEnkoda +Date: Tue, 11 May 2021 00:28:13 +0200 +Subject: [PATCH] Optimize collisions + + +diff --git a/src/main/java/net/minecraft/server/level/WorldServer.java b/src/main/java/net/minecraft/server/level/WorldServer.java +index 7d0c5d28597c51d332146a82df06ba519711f836..fbc7f3e489be0ac5939af29a9aef75a56c38eb4a 100644 +--- a/src/main/java/net/minecraft/server/level/WorldServer.java ++++ b/src/main/java/net/minecraft/server/level/WorldServer.java +@@ -678,16 +678,10 @@ public class WorldServer extends World implements GeneratorAccessSeed { + } + } + +- int minBlockX = MathHelper.floor(axisalignedbb.minX - MCUtil.COLLISION_EPSILON) - 1; +- int maxBlockX = MathHelper.floor(axisalignedbb.maxX + MCUtil.COLLISION_EPSILON) + 1; +- ++ // Purpur Start Rebase - Calculate when needed only + int minBlockY = MathHelper.floor(axisalignedbb.minY - MCUtil.COLLISION_EPSILON) - 1; + int maxBlockY = MathHelper.floor(axisalignedbb.maxY + MCUtil.COLLISION_EPSILON) + 1; + +- int minBlockZ = MathHelper.floor(axisalignedbb.minZ - MCUtil.COLLISION_EPSILON) - 1; +- int maxBlockZ = MathHelper.floor(axisalignedbb.maxZ + MCUtil.COLLISION_EPSILON) + 1; +- +- + BlockPosition.MutableBlockPosition mutablePos = new BlockPosition.MutableBlockPosition(); + net.minecraft.world.phys.shapes.VoxelShapeCollision collisionShape = null; + +@@ -697,6 +691,13 @@ public class WorldServer extends World implements GeneratorAccessSeed { + return ret; + } + ++ int minBlockX = MathHelper.floor(axisalignedbb.minX - MCUtil.COLLISION_EPSILON) - 1; ++ int maxBlockX = MathHelper.floor(axisalignedbb.maxX + MCUtil.COLLISION_EPSILON) + 1; ++ ++ int minBlockZ = MathHelper.floor(axisalignedbb.minZ - MCUtil.COLLISION_EPSILON) - 1; ++ int maxBlockZ = MathHelper.floor(axisalignedbb.maxZ + MCUtil.COLLISION_EPSILON) + 1; ++ // Purpur End ++ + int minYIterate = Math.max(0, minBlockY); + int maxYIterate = Math.min(255, maxBlockY); + +diff --git a/src/main/java/net/minecraft/world/level/ChunkCache.java b/src/main/java/net/minecraft/world/level/ChunkCache.java +index b547eb352f90f68cf36ffb82e43ad7acb1892f6a..f165f39758ef09948b4ce24e2d31f8350f68fcfd 100644 +--- a/src/main/java/net/minecraft/world/level/ChunkCache.java ++++ b/src/main/java/net/minecraft/world/level/ChunkCache.java +@@ -60,16 +60,10 @@ public class ChunkCache implements IBlockAccess, ICollisionAccess { + } + } + +- int minBlockX = net.minecraft.util.MathHelper.floor(axisalignedbb.minX - net.minecraft.server.MCUtil.COLLISION_EPSILON) - 1; +- int maxBlockX = net.minecraft.util.MathHelper.floor(axisalignedbb.maxX + net.minecraft.server.MCUtil.COLLISION_EPSILON) + 1; +- ++ // Purpur Rebase - Calculate when needed only + int minBlockY = net.minecraft.util.MathHelper.floor(axisalignedbb.minY - net.minecraft.server.MCUtil.COLLISION_EPSILON) - 1; + int maxBlockY = net.minecraft.util.MathHelper.floor(axisalignedbb.maxY + net.minecraft.server.MCUtil.COLLISION_EPSILON) + 1; + +- int minBlockZ = net.minecraft.util.MathHelper.floor(axisalignedbb.minZ - net.minecraft.server.MCUtil.COLLISION_EPSILON) - 1; +- int maxBlockZ = net.minecraft.util.MathHelper.floor(axisalignedbb.maxZ + net.minecraft.server.MCUtil.COLLISION_EPSILON) + 1; +- +- + BlockPosition.MutableBlockPosition mutablePos = new BlockPosition.MutableBlockPosition(); + net.minecraft.world.phys.shapes.VoxelShapeCollision collisionShape = null; + +@@ -79,6 +73,13 @@ public class ChunkCache implements IBlockAccess, ICollisionAccess { + return ret; + } + ++ int minBlockX = net.minecraft.util.MathHelper.floor(axisalignedbb.minX - net.minecraft.server.MCUtil.COLLISION_EPSILON) - 1; ++ int maxBlockX = net.minecraft.util.MathHelper.floor(axisalignedbb.maxX + net.minecraft.server.MCUtil.COLLISION_EPSILON) + 1; ++ ++ int minBlockZ = net.minecraft.util.MathHelper.floor(axisalignedbb.minZ - net.minecraft.server.MCUtil.COLLISION_EPSILON) - 1; ++ int maxBlockZ = net.minecraft.util.MathHelper.floor(axisalignedbb.maxZ + net.minecraft.server.MCUtil.COLLISION_EPSILON) + 1; ++ // Purpur End ++ + int minYIterate = Math.max(0, minBlockY); + int maxYIterate = Math.min(255, maxBlockY); + diff --git a/patches/Purpur/patches/server/0208-Iron-golem-poppy-calms-anger.patch b/patches/Purpur/patches/server/0208-Iron-golem-poppy-calms-anger.patch new file mode 100644 index 00000000..3763feae --- /dev/null +++ b/patches/Purpur/patches/server/0208-Iron-golem-poppy-calms-anger.patch @@ -0,0 +1,148 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Thu, 13 May 2021 21:22:51 -0500 +Subject: [PATCH] Iron golem poppy calms anger + + +diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/target/PathfinderGoalReceiveFlower.java b/src/main/java/net/minecraft/world/entity/ai/goal/target/PathfinderGoalReceiveFlower.java +new file mode 100644 +index 0000000000000000000000000000000000000000..6a288fead988d424aa369b8ef6378ab3c9ec16af +--- /dev/null ++++ b/src/main/java/net/minecraft/world/entity/ai/goal/target/PathfinderGoalReceiveFlower.java +@@ -0,0 +1,79 @@ ++package net.minecraft.world.entity.ai.goal.target; ++ ++import net.minecraft.server.level.EntityPlayer; ++import net.minecraft.server.level.WorldServer; ++import net.minecraft.world.entity.Entity; ++import net.minecraft.world.entity.ai.goal.PathfinderGoal; ++import net.minecraft.world.entity.animal.EntityIronGolem; ++import net.minecraft.world.item.ItemStack; ++import net.minecraft.world.level.block.Blocks; ++ ++import java.util.EnumSet; ++import java.util.UUID; ++ ++public class PathfinderGoalReceiveFlower extends PathfinderGoal { ++ private final EntityIronGolem entity; ++ private EntityPlayer target; ++ private int cooldown; ++ ++ public PathfinderGoalReceiveFlower(EntityIronGolem entity) { ++ this.entity = entity; ++ this.setTypes(EnumSet.of(Type.MOVE, Type.LOOK)); ++ } ++ ++ @Override ++ public boolean shouldActivate() { ++ if (this.entity.getHoldingFlowerTick() > 0) { ++ return false; ++ } ++ if (!this.entity.isAngry()) { ++ return false; ++ } ++ UUID uuid = this.entity.getAngerTarget(); ++ if (uuid == null) { ++ return false; ++ } ++ Entity target = ((WorldServer) this.entity.world).getEntity(uuid); ++ if (!(target instanceof EntityPlayer)) { ++ return false; ++ } ++ EntityPlayer player = (EntityPlayer) target; ++ if (!isHoldingFlower(player)) { ++ return false; ++ } ++ this.target = player; ++ return true; ++ } ++ ++ @Override ++ public boolean shouldStayActive() { ++ return this.cooldown > 0; ++ } ++ ++ @Override ++ public void start() { ++ this.cooldown = 100; ++ this.entity.pacify(); ++ this.entity.holdFlower(true); ++ } ++ ++ @Override ++ public void onTaskReset() { ++ this.entity.holdFlower(false); ++ this.target = null; ++ } ++ ++ @Override ++ public void tick() { ++ this.entity.getControllerLook().lookAt(this.target, 30.0F, 30.0F); ++ --this.cooldown; ++ } ++ ++ private boolean isHoldingFlower(EntityPlayer player) { ++ return isPoppy(player.getItemInMainHand()) || isPoppy(player.getItemInOffHand()); ++ } ++ ++ private boolean isPoppy(ItemStack item) { ++ return item.getItem() == Blocks.POPPY.getItem(); ++ } ++} +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityIronGolem.java b/src/main/java/net/minecraft/world/entity/animal/EntityIronGolem.java +index 9ee82c908008190e31034e614c241fc7a66248e1..402a8733905ebbbb9c1d962bafa7fd806a9253cc 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityIronGolem.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityIronGolem.java +@@ -42,6 +42,7 @@ import net.minecraft.world.entity.ai.goal.PathfinderGoalStrollVillageGolem; + import net.minecraft.world.entity.ai.goal.target.PathfinderGoalDefendVillage; + import net.minecraft.world.entity.ai.goal.target.PathfinderGoalHurtByTarget; + import net.minecraft.world.entity.ai.goal.target.PathfinderGoalNearestAttackableTarget; ++import net.minecraft.world.entity.ai.goal.target.PathfinderGoalReceiveFlower; + import net.minecraft.world.entity.ai.goal.target.PathfinderGoalUniversalAngerReset; + import net.minecraft.world.entity.monster.EntityCreeper; + import net.minecraft.world.entity.monster.IMonster; +@@ -60,7 +61,7 @@ public class EntityIronGolem extends EntityGolem implements IEntityAngerable { + + protected static final DataWatcherObject b = DataWatcher.a(EntityIronGolem.class, DataWatcherRegistry.a); + private int c; +- private int d; ++ private int d; public int getHoldingFlowerTick() { return d; } // Purpur - OBFHELPER + private static final IntRange bo = TimeRange.a(20, 39); + private int bp; + private UUID bq; +@@ -91,6 +92,7 @@ public class EntityIronGolem extends EntityGolem implements IEntityAngerable { + protected void initPathfinder() { + if (world.purpurConfig.ironGolemCanSwim) this.goalSelector.a(0, new PathfinderGoalFloat(this)); // Purpur + this.goalSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur ++ if (world.purpurConfig.ironGolemPoppyCalm) this.goalSelector.addGoal(0, new PathfinderGoalReceiveFlower(this)); // Purpur + this.goalSelector.a(1, new PathfinderGoalMeleeAttack(this, 1.0D, true)); + this.goalSelector.a(2, new PathfinderGoalMoveTowardsTarget(this, 0.9D, 32.0F)); + this.goalSelector.a(2, new PathfinderGoalStrollVillage(this, 0.6D, false)); +@@ -241,6 +243,7 @@ public class EntityIronGolem extends EntityGolem implements IEntityAngerable { + return EntityIronGolem.CrackLevel.a(this.getHealth() / this.getMaxHealth()); + } + ++ public void holdFlower(boolean flag) { t(flag); } // Purpur - OBFHELPER + public void t(boolean flag) { + if (flag) { + this.d = 400; +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 5659e75177f3c5acb935b0f6dc0b720853602108..ffb8d505a723d61bd6311f4116524d9a99a27f62 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -1183,6 +1183,7 @@ public class PurpurWorldConfig { + public boolean ironGolemRidableInWater = false; + public boolean ironGolemCanSwim = false; + public double ironGolemMaxHealth = 100.0D; ++ public boolean ironGolemPoppyCalm = false; + private void ironGolemSettings() { + ironGolemRidable = getBoolean("mobs.iron_golem.ridable", ironGolemRidable); + ironGolemRidableInWater = getBoolean("mobs.iron_golem.ridable-in-water", ironGolemRidableInWater); +@@ -1193,6 +1194,7 @@ public class PurpurWorldConfig { + set("mobs.iron_golem.attributes.max_health", oldValue); + } + ironGolemMaxHealth = getDouble("mobs.iron_golem.attributes.max_health", ironGolemMaxHealth); ++ ironGolemPoppyCalm = getBoolean("mobs.iron_golem.poppy-calms-anger", ironGolemPoppyCalm); + } + + public boolean llamaRidable = false; diff --git a/patches/Purpur/patches/server/0209-Breedable-parrots.patch b/patches/Purpur/patches/server/0209-Breedable-parrots.patch new file mode 100644 index 00000000..a14b9507 --- /dev/null +++ b/patches/Purpur/patches/server/0209-Breedable-parrots.patch @@ -0,0 +1,88 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Thu, 13 May 2021 22:17:50 -0500 +Subject: [PATCH] Breedable parrots + + +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityParrot.java b/src/main/java/net/minecraft/world/entity/animal/EntityParrot.java +index 2f51e80a02817f1e36c8fe9542809ab881263a16..abfb08ff562ef4c8971b12f6f64ede08dca15cd0 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityParrot.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityParrot.java +@@ -44,6 +44,7 @@ import net.minecraft.world.entity.GroupDataEntity; + import net.minecraft.world.entity.ai.attributes.AttributeProvider; + import net.minecraft.world.entity.ai.attributes.GenericAttributes; + import net.minecraft.world.entity.ai.control.ControllerMoveFlying; ++import net.minecraft.world.entity.ai.goal.PathfinderGoalBreed; + import net.minecraft.world.entity.ai.goal.PathfinderGoalFloat; + import net.minecraft.world.entity.ai.goal.PathfinderGoalFollowEntity; + import net.minecraft.world.entity.ai.goal.PathfinderGoalFollowOwner; +@@ -75,7 +76,7 @@ public class EntityParrot extends EntityPerchable implements EntityBird { + } + }; + private static final Item bw = Items.COOKIE; +- private static final Set bx = Sets.newHashSet(new Item[]{Items.WHEAT_SEEDS, Items.MELON_SEEDS, Items.PUMPKIN_SEEDS, Items.BEETROOT_SEEDS}); ++ private static final Set bx = Sets.newHashSet(new Item[]{Items.WHEAT_SEEDS, Items.MELON_SEEDS, Items.PUMPKIN_SEEDS, Items.BEETROOT_SEEDS}); public static Set temptItems() { return bx; } // Purpur - OBFHELPER + private static final Map, SoundEffect> by = (Map) SystemUtils.a(Maps.newHashMap(), (hashmap) -> { // CraftBukkit - decompile error + hashmap.put(EntityTypes.BLAZE, SoundEffects.ENTITY_PARROT_IMITATE_BLAZE); + hashmap.put(EntityTypes.CAVE_SPIDER, SoundEffects.ENTITY_PARROT_IMITATE_SPIDER); +@@ -205,6 +206,7 @@ public class EntityParrot extends EntityPerchable implements EntityBird { + this.goalSelector.a(0, new PathfinderGoalFloat(this)); + this.goalSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + this.goalSelector.a(1, new PathfinderGoalPanic(this, 1.25D)); // Purpur ++ if (world.purpurConfig.parrotBreedable) this.goalSelector.addGoal(1, new PathfinderGoalBreed(this, 1.0D)); // Purpur + this.goalSelector.a(1, new PathfinderGoalLookAtPlayer(this, EntityHuman.class, 8.0F)); + this.goalSelector.a(2, new PathfinderGoalSit(this)); + this.goalSelector.a(2, new PathfinderGoalFollowOwner(this, 1.0D, 5.0F, 1.0F, true)); +@@ -309,6 +311,7 @@ public class EntityParrot extends EntityPerchable implements EntityBird { + } + } + ++ if (world.purpurConfig.parrotBreedable) return super.b(entityhuman, enumhand); // Purpur + return EnumInteractionResult.a(this.world.isClientSide); + } else if (itemstack.getItem() == EntityParrot.bw) { + if (!entityhuman.abilities.canInstantlyBuild) { +@@ -334,7 +337,7 @@ public class EntityParrot extends EntityPerchable implements EntityBird { + + @Override + public boolean k(ItemStack itemstack) { +- return false; ++ return world.purpurConfig.parrotBreedable && temptItems().contains(itemstack.getItem()); // Purpur + } + + public static boolean c(EntityTypes entitytypes, GeneratorAccess generatoraccess, EnumMobSpawn enummobspawn, BlockPosition blockposition, Random random) { +@@ -353,13 +356,13 @@ public class EntityParrot extends EntityPerchable implements EntityBird { + + @Override + public boolean mate(EntityAnimal entityanimal) { +- return false; ++ return super.mate(entityanimal); // Purpur + } + + @Nullable + @Override + public EntityAgeable createChild(WorldServer worldserver, EntityAgeable entityageable) { +- return null; ++ return worldserver.purpurConfig.parrotBreedable ? EntityTypes.PARROT.create(worldserver) : null; // Purpur + } + + @Override +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index ffb8d505a723d61bd6311f4116524d9a99a27f62..db8b31972b38f907a53b4f63465c83d1f47f4dc3 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -1345,6 +1345,7 @@ public class PurpurWorldConfig { + public boolean parrotRidableInWater = false; + public double parrotMaxY = 256D; + public double parrotMaxHealth = 6.0D; ++ public boolean parrotBreedable = false; + private void parrotSettings() { + parrotRidable = getBoolean("mobs.parrot.ridable", parrotRidable); + parrotRidableInWater = getBoolean("mobs.parrot.ridable-in-water", parrotRidableInWater); +@@ -1355,6 +1356,7 @@ public class PurpurWorldConfig { + set("mobs.parrot.attributes.max_health", oldValue); + } + parrotMaxHealth = getDouble("mobs.parrot.attributes.max_health", parrotMaxHealth); ++ parrotBreedable = getBoolean("mobs.parrot.can-breed", parrotBreedable); + } + + public boolean phantomRidable = false; diff --git a/patches/Purpur/patches/server/0210-Configurable-powered-rail-boost-modifier.patch b/patches/Purpur/patches/server/0210-Configurable-powered-rail-boost-modifier.patch new file mode 100644 index 00000000..8ca1fab0 --- /dev/null +++ b/patches/Purpur/patches/server/0210-Configurable-powered-rail-boost-modifier.patch @@ -0,0 +1,39 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Callum Seabrook +Date: Fri, 14 May 2021 21:22:57 +0100 +Subject: [PATCH] Configurable powered rail boost modifier + + +diff --git a/src/main/java/net/minecraft/world/entity/vehicle/EntityMinecartAbstract.java b/src/main/java/net/minecraft/world/entity/vehicle/EntityMinecartAbstract.java +index 7b49544210d087f5006a83c2a0d5c47c785c567f..9e91fc85e8f7ebadde239941700282fd820588e4 100644 +--- a/src/main/java/net/minecraft/world/entity/vehicle/EntityMinecartAbstract.java ++++ b/src/main/java/net/minecraft/world/entity/vehicle/EntityMinecartAbstract.java +@@ -705,7 +705,7 @@ public abstract class EntityMinecartAbstract extends Entity { + if (d18 > 0.01D) { + double d20 = 0.06D; + +- this.setMot(vec3d4.add(vec3d4.x / d18 * 0.06D, 0.0D, vec3d4.z / d18 * 0.06D)); ++ this.setMot(vec3d4.add(vec3d4.x / d18 * world.purpurConfig.poweredRailBoostModifier, 0.0D, vec3d4.z / d18 * world.purpurConfig.poweredRailBoostModifier)); // Purpur + } else { + Vec3D vec3d5 = this.getMot(); + double d21 = vec3d5.x; +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index db8b31972b38f907a53b4f63465c83d1f47f4dc3..99c196f1262660b901f84c0ac66d10c9d1e6bcf7 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -133,6 +133,7 @@ public class PurpurWorldConfig { + public boolean minecartControllableFallDamage = true; + public double minecartControllableBaseSpeed = 0.1D; + public Map minecartControllableBlockSpeeds = new HashMap<>(); ++ public double poweredRailBoostModifier = 0.06; + private void minecartSettings() { + if (PurpurConfig.version < 12) { + boolean oldBool = getBoolean("gameplay-mechanics.controllable-minecarts.place-anywhere", minecartPlaceAnywhere); +@@ -185,6 +186,7 @@ public class PurpurWorldConfig { + set("gameplay-mechanics.minecart.controllable.block-speed.grass_block", 0.3D); + set("gameplay-mechanics.minecart.controllable.block-speed.stone", 0.5D); + } ++ poweredRailBoostModifier = getDouble("gameplay-mechanics.minecart.powered-rail.boost-modifier", poweredRailBoostModifier); + } + + public int daytimeTicks = 12000; diff --git a/patches/Purpur/patches/server/0211-Add-config-change-multiplier-critical-damage-value.patch b/patches/Purpur/patches/server/0211-Add-config-change-multiplier-critical-damage-value.patch new file mode 100644 index 00000000..62aa48e3 --- /dev/null +++ b/patches/Purpur/patches/server/0211-Add-config-change-multiplier-critical-damage-value.patch @@ -0,0 +1,39 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: DoctaEnkoda +Date: Mon, 17 May 2021 02:40:13 +0200 +Subject: [PATCH] Add config change multiplier critical damage value + + +diff --git a/src/main/java/net/minecraft/world/entity/player/EntityHuman.java b/src/main/java/net/minecraft/world/entity/player/EntityHuman.java +index 5f4a9ef27ab1a177a048fbf376d1e353be865e6f..24285b1b2264939fdfa6f7d6311772fa67be8680 100644 +--- a/src/main/java/net/minecraft/world/entity/player/EntityHuman.java ++++ b/src/main/java/net/minecraft/world/entity/player/EntityHuman.java +@@ -1188,7 +1188,7 @@ public abstract class EntityHuman extends EntityLiving { + flag2 = flag2 && !this.isSprinting(); + if (flag2) { + this.isCritical = true; // Purpur +- f *= 1.5F; ++ f *= this.world.purpurConfig.playerCriticalDamageMultiplier; // Purpur + } + + f += f1; +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 99c196f1262660b901f84c0ac66d10c9d1e6bcf7..78af40e0fe7faeca45ab7ef1264a02fc2c61f2b6 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -356,6 +356,7 @@ public class PurpurWorldConfig { + public boolean creativeOnePunch = false; + public boolean playerSleepNearMonsters = false; + public boolean playersSkipNight = true; ++ public double playerCriticalDamageMultiplier = 1.5D; + private void miscGameplayMechanicsSettings() { + useBetterMending = getBoolean("gameplay-mechanics.use-better-mending", useBetterMending); + alwaysTameInCreative = getBoolean("gameplay-mechanics.always-tame-in-creative", alwaysTameInCreative); +@@ -377,6 +378,7 @@ public class PurpurWorldConfig { + creativeOnePunch = getBoolean("gameplay-mechanics.player.one-punch-in-creative", creativeOnePunch); + playerSleepNearMonsters = getBoolean("gameplay-mechanics.player.sleep-ignore-nearby-mobs", playerSleepNearMonsters); + playersSkipNight = getBoolean("gameplay-mechanics.player.can-skip-night", playersSkipNight); ++ playerCriticalDamageMultiplier = getDouble("gameplay-mechanics.player.critical-damage-multiplier", playerCriticalDamageMultiplier); + } + + public boolean catSpawning; diff --git a/patches/Purpur/patches/server/0212-Option-to-disable-dragon-egg-teleporting.patch b/patches/Purpur/patches/server/0212-Option-to-disable-dragon-egg-teleporting.patch new file mode 100644 index 00000000..a028be71 --- /dev/null +++ b/patches/Purpur/patches/server/0212-Option-to-disable-dragon-egg-teleporting.patch @@ -0,0 +1,34 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Mon, 17 May 2021 04:46:23 -0500 +Subject: [PATCH] Option to disable dragon egg teleporting + + +diff --git a/src/main/java/net/minecraft/world/level/block/BlockDragonEgg.java b/src/main/java/net/minecraft/world/level/block/BlockDragonEgg.java +index ce2931f6e1304e6d8fe14e86ba7a8e0e8ac54d1d..5f429a4f82d4d3024ba3df10bc9b21d504361602 100644 +--- a/src/main/java/net/minecraft/world/level/block/BlockDragonEgg.java ++++ b/src/main/java/net/minecraft/world/level/block/BlockDragonEgg.java +@@ -42,6 +42,7 @@ public class BlockDragonEgg extends BlockFalling { + } + + private void d(IBlockData iblockdata, World world, BlockPosition blockposition) { ++ if (!world.purpurConfig.dragonEggTeleport) return; // Purpur + for (int i = 0; i < 1000; ++i) { + BlockPosition blockposition1 = blockposition.b(world.random.nextInt(16) - world.random.nextInt(16), world.random.nextInt(8) - world.random.nextInt(8), world.random.nextInt(16) - world.random.nextInt(16)); + +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 78af40e0fe7faeca45ab7ef1264a02fc2c61f2b6..cda80cf8d2556defd1453b473aca76bf7c014794 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -537,6 +537,11 @@ public class PurpurWorldConfig { + }); + } + ++ public boolean dragonEggTeleport = true; ++ private void dragonEggSettings() { ++ dragonEggTeleport = getBoolean("blocks.dragon_egg.teleport", dragonEggTeleport); ++ } ++ + public boolean snowOnBlueIce = true; + public boolean mobsSpawnOnPackedIce = true; + public boolean mobsSpawnOnBlueIce = true; diff --git a/patches/Purpur/patches/server/0213-Config-for-unverified-username-message.patch b/patches/Purpur/patches/server/0213-Config-for-unverified-username-message.patch new file mode 100644 index 00000000..5d2d2f8d --- /dev/null +++ b/patches/Purpur/patches/server/0213-Config-for-unverified-username-message.patch @@ -0,0 +1,39 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ben Kerllenevich +Date: Wed, 19 May 2021 15:33:43 -0400 +Subject: [PATCH] Config for unverified username message + + +diff --git a/src/main/java/net/minecraft/server/network/LoginListener.java b/src/main/java/net/minecraft/server/network/LoginListener.java +index 25437a993c02379fa43e5d46159cd9ba2aebf10f..f378d654a7fdd61ca31ca50ba45eff6acd93c3f1 100644 +--- a/src/main/java/net/minecraft/server/network/LoginListener.java ++++ b/src/main/java/net/minecraft/server/network/LoginListener.java +@@ -280,7 +280,7 @@ public class LoginListener implements PacketLoginInListener { + LoginListener.this.i = LoginListener.this.a(gameprofile); + LoginListener.this.g = LoginListener.EnumProtocolState.READY_TO_ACCEPT; + } else { +- LoginListener.this.disconnect(new ChatMessage("multiplayer.disconnect.unverified_username")); ++ LoginListener.this.disconnect(net.pl3x.purpur.PurpurConfig.unverifiedUsername.equals("default") ? new ChatMessage("multiplayer.disconnect.unverified_username") : PaperAdventure.asVanilla(PaperAdventure.LEGACY_SECTION_UXRC.deserialize(net.pl3x.purpur.PurpurConfig.unverifiedUsername))); // Purpur + LoginListener.LOGGER.error("Username '{}' tried to join with an invalid session", gameprofile.getName()); + } + } catch (AuthenticationUnavailableException authenticationunavailableexception) { +diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java +index 475e7dcf01d3779664a8e5fc4c1c4c7550c50750..b6938f1ff5688454fbbaa14f1acf3430837cbf01 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java +@@ -164,6 +164,7 @@ public class PurpurConfig { + public static String creditsCommandOutput = "§a%s has been shown the end credits"; + public static String pingCommandOutput = "§a%s's ping is %sms"; + public static String cannotRideMob = "§cYou cannot mount that mob"; ++ public static String unverifiedUsername = "default"; + private static void messages() { + afkBroadcastAway = getString("settings.messages.afk-broadcast-away", afkBroadcastAway); + afkBroadcastBack = getString("settings.messages.afk-broadcast-back", afkBroadcastBack); +@@ -173,6 +174,7 @@ public class PurpurConfig { + creditsCommandOutput = getString("settings.messages.credits-command-output", creditsCommandOutput); + pingCommandOutput = getString("settings.messages.ping-command-output", pingCommandOutput); + cannotRideMob = getString("settings.messages.cannot-ride-mob", cannotRideMob); ++ unverifiedUsername = getString("settings.messages.unverified-username", unverifiedUsername); + } + + public static int dungeonSeed = -1; diff --git a/patches/Purpur/patches/server/0214-Make-anvil-cumulative-cost-configurable.patch b/patches/Purpur/patches/server/0214-Make-anvil-cumulative-cost-configurable.patch new file mode 100644 index 00000000..7dc54f1e --- /dev/null +++ b/patches/Purpur/patches/server/0214-Make-anvil-cumulative-cost-configurable.patch @@ -0,0 +1,39 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: 12emin34 +Date: Fri, 21 May 2021 16:58:45 +0200 +Subject: [PATCH] Make anvil cumulative cost configurable + + +diff --git a/src/main/java/net/minecraft/world/inventory/ContainerAnvil.java b/src/main/java/net/minecraft/world/inventory/ContainerAnvil.java +index 77810fbb70bf2e1ad03c28c0d69ceaa63221d94c..e1cc66e382b2251e0fa60f777515d5a110f1684e 100644 +--- a/src/main/java/net/minecraft/world/inventory/ContainerAnvil.java ++++ b/src/main/java/net/minecraft/world/inventory/ContainerAnvil.java +@@ -337,7 +337,7 @@ public class ContainerAnvil extends ContainerAnvilAbstract { + } + + public static int d(int i) { +- return i * 2 + 1; ++ return net.pl3x.purpur.PurpurConfig.anvilCumulativeCost ? i * 2 + 1 : 0; + } + + public void a(String s) { +diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java +index b6938f1ff5688454fbbaa14f1acf3430837cbf01..72c20065e09af656a565c2c1097f26c00b76c1e4 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java +@@ -225,6 +225,7 @@ public class PurpurConfig { + public static boolean enderChestPermissionRows = false; + public static boolean cryingObsidianValidForPortalFrame = false; + public static int beeInsideBeeHive = 3; ++ public static boolean anvilCumulativeCost = true; + private static void blockSettings() { + if (version < 3) { + boolean oldValue = getBoolean("settings.barrel.packed-barrels", true); +@@ -234,6 +235,7 @@ public class PurpurConfig { + set("settings.blocks.ender_chest.six-rows", oldValue); + set("settings.large-ender-chests", null); + } ++ anvilCumulativeCost = getBoolean("settings.blocks.anvil.cumulative-cost", anvilCumulativeCost); + barrelSixRows = getBoolean("settings.blocks.barrel.six-rows", barrelSixRows); + InventoryType.BARREL.setDefaultSize(barrelSixRows ? 54 : 27); + enderChestSixRows = getBoolean("settings.blocks.ender_chest.six-rows", enderChestSixRows); diff --git a/patches/Purpur/patches/server/0215-ShulkerBox-allow-oversized-stacks.patch b/patches/Purpur/patches/server/0215-ShulkerBox-allow-oversized-stacks.patch new file mode 100644 index 00000000..23b79c71 --- /dev/null +++ b/patches/Purpur/patches/server/0215-ShulkerBox-allow-oversized-stacks.patch @@ -0,0 +1,52 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Thu, 27 May 2021 04:04:23 -0500 +Subject: [PATCH] ShulkerBox allow oversized stacks + +This fixes PaperMC/Paper#4748 where breaking a shulkerbox in survival mode +with oversized itemstacks would cause a "chunk ban". This fixes it by always +creating an itemstack using the TileEntity's NBT data (how it handles it for +creative players) instead of routing it through the LootableBuilder. + +diff --git a/src/main/java/net/minecraft/server/level/PlayerInteractManager.java b/src/main/java/net/minecraft/server/level/PlayerInteractManager.java +index 7302554063ac7b5dedaff895cba33b70234008e6..151da6c134f908d9037fddc5b54e71b069680e56 100644 +--- a/src/main/java/net/minecraft/server/level/PlayerInteractManager.java ++++ b/src/main/java/net/minecraft/server/level/PlayerInteractManager.java +@@ -440,7 +440,7 @@ public class PlayerInteractManager { + block.postBreak(this.world, blockposition, iblockdata); + } + +- if (this.isCreative()) { ++ if (this.isCreative() || (world.purpurConfig.shulkerBoxAllowOversizedStacks && block instanceof net.minecraft.world.level.block.BlockShulkerBox)) { // Purpur + // return true; // CraftBukkit + } else { + ItemStack itemstack = this.player.getItemInMainHand(); +diff --git a/src/main/java/net/minecraft/world/level/block/BlockShulkerBox.java b/src/main/java/net/minecraft/world/level/block/BlockShulkerBox.java +index 2c1c6562efe8cdc079b4e353144d20c1e46355c5..af935a03d3677314cd367686d65e89b615af3f4f 100644 +--- a/src/main/java/net/minecraft/world/level/block/BlockShulkerBox.java ++++ b/src/main/java/net/minecraft/world/level/block/BlockShulkerBox.java +@@ -110,7 +110,7 @@ public class BlockShulkerBox extends BlockTileEntity { + if (tileentity instanceof TileEntityShulkerBox) { + TileEntityShulkerBox tileentityshulkerbox = (TileEntityShulkerBox) tileentity; + +- if (!world.isClientSide && entityhuman.isCreative() && !tileentityshulkerbox.isEmpty()) { ++ if (!world.isClientSide && (world.purpurConfig.shulkerBoxAllowOversizedStacks || (entityhuman.isCreative() && !tileentityshulkerbox.isEmpty()))) { + ItemStack itemstack = b(this.c()); + NBTTagCompound nbttagcompound = tileentityshulkerbox.e(new NBTTagCompound()); + +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index cda80cf8d2556defd1453b473aca76bf7c014794..0afe0d9c0b9d4c7abc6f65938d8fd147df52f880 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -630,6 +630,11 @@ public class PurpurWorldConfig { + } + } + ++ public boolean shulkerBoxAllowOversizedStacks = false; ++ private void shulkerBoxSettings() { ++ shulkerBoxAllowOversizedStacks = getBoolean("blocks.shulker_box.allow-oversized-stacks", shulkerBoxAllowOversizedStacks); ++ } ++ + public boolean signAllowColors = false; + public boolean signRightClickEdit = false; + private void signSettings() { diff --git a/patches/Purpur/patches/server/0216-Bee-can-work-when-raining-or-at-night.patch b/patches/Purpur/patches/server/0216-Bee-can-work-when-raining-or-at-night.patch new file mode 100644 index 00000000..78ac47e5 --- /dev/null +++ b/patches/Purpur/patches/server/0216-Bee-can-work-when-raining-or-at-night.patch @@ -0,0 +1,54 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: DoctaEnkoda +Date: Thu, 27 May 2021 06:46:30 +0200 +Subject: [PATCH] Bee can work when raining or at night + + +diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityBee.java b/src/main/java/net/minecraft/world/entity/animal/EntityBee.java +index e425e093c233a21e5ef457e3a94defe8b74261d2..4da4fadbd4a036b316d554de20c0d30d35cc206b 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/EntityBee.java ++++ b/src/main/java/net/minecraft/world/entity/animal/EntityBee.java +@@ -356,7 +356,7 @@ public class EntityBee extends EntityAnimal implements IEntityAngerable, EntityB + + private boolean fd() { + if (this.cannotEnterHiveTicks <= 0 && !this.bC.k() && !this.hasStung() && this.getGoalTarget() == null) { +- boolean flag = this.canPollinate() || this.world.isRaining() || this.world.isNight() || this.hasNectar(); ++ boolean flag = this.canPollinate() || (this.world.isRaining() && !this.world.purpurConfig.beeCanWorkInRain) || (this.world.isNight() && !this.world.purpurConfig.beeCanWorkAtNight) || this.hasNectar(); // Purpur + + return flag && !this.ff(); + } else { +diff --git a/src/main/java/net/minecraft/world/level/block/entity/TileEntityBeehive.java b/src/main/java/net/minecraft/world/level/block/entity/TileEntityBeehive.java +index 58bf1008ab19340bce5111e006a8de0e7f39e0e5..6fbd8ee31c517cd08ce4d1374a278dd748f9933e 100644 +--- a/src/main/java/net/minecraft/world/level/block/entity/TileEntityBeehive.java ++++ b/src/main/java/net/minecraft/world/level/block/entity/TileEntityBeehive.java +@@ -181,7 +181,7 @@ public class TileEntityBeehive extends TileEntity implements ITickable { + } + + private boolean releaseBee(IBlockData iblockdata, TileEntityBeehive.HiveBee tileentitybeehive_hivebee, @Nullable List list, TileEntityBeehive.ReleaseStatus tileentitybeehive_releasestatus, boolean force) { +- if (!force && (this.world.isNight() || this.world.isRaining()) && tileentitybeehive_releasestatus != TileEntityBeehive.ReleaseStatus.EMERGENCY) { ++ if (!force && ((this.world.isNight() && !this.world.purpurConfig.beeCanWorkAtNight) || (this.world.isRaining() && !this.world.purpurConfig.beeCanWorkInRain)) && tileentitybeehive_releasestatus != TileEntityBeehive.ReleaseStatus.EMERGENCY) { // Purpur + // CraftBukkit end + return false; + } else { +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 0afe0d9c0b9d4c7abc6f65938d8fd147df52f880..bd72ed2da22c1d1121ea7ca04e163979baa05b27 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -726,6 +726,8 @@ public class PurpurWorldConfig { + public double beeMaxY = 256D; + public int beeBreedingTicks = 6000; + public double beeMaxHealth = 10.0D; ++ public boolean beeCanWorkAtNight = false; ++ public boolean beeCanWorkInRain = false; + private void beeSettings() { + beeRidable = getBoolean("mobs.bee.ridable", beeRidable); + beeRidableInWater = getBoolean("mobs.bee.ridable-in-water", beeRidableInWater); +@@ -737,6 +739,8 @@ public class PurpurWorldConfig { + set("mobs.bee.attributes.max_health", oldValue); + } + beeMaxHealth = getDouble("mobs.bee.attributes.max_health", beeMaxHealth); ++ beeCanWorkAtNight = getBoolean("mobs.bee.can-work-at-night", beeCanWorkAtNight); ++ beeCanWorkInRain = getBoolean("mobs.bee.can-work-in-rain", beeCanWorkInRain); + } + + public boolean blazeRidable = false; diff --git a/patches/Purpur/patches/server/0217-API-for-any-mob-to-burn-daylight.patch b/patches/Purpur/patches/server/0217-API-for-any-mob-to-burn-daylight.patch new file mode 100644 index 00000000..008a44ba --- /dev/null +++ b/patches/Purpur/patches/server/0217-API-for-any-mob-to-burn-daylight.patch @@ -0,0 +1,369 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ben Kerllenevich +Date: Tue, 25 May 2021 16:31:09 -0400 +Subject: [PATCH] API for any mob to burn daylight + +Co-authored by: Encode42 + +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index dcb8cff2671947140f5853b1f6d75ecc03ef368f..35c15afc3f4bbe10dc7638e926564f51285fda4c 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -1639,7 +1639,7 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, ne + } + } + +- public float aR() { ++ public float getBrightness() { return this.aR(); } public float aR() { // Purpur - OBFHELPER + BlockPosition.MutableBlockPosition blockposition_mutableblockposition = new BlockPosition.MutableBlockPosition(this.locX(), 0.0D, this.locZ()); + + if (this.world.isLoaded(blockposition_mutableblockposition)) { +@@ -3869,5 +3869,17 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, ne + public boolean processClick(EnumHand hand) { + return false; + } ++ ++ // Purpur start - copied from EntityInsentient ++ public boolean isInDaylight() { ++ if (this.world.isDay() && !this.world.isClientSide) { ++ float brightness = this.getBrightness(); ++ BlockPosition blockposition = this.getVehicle() instanceof EntityBoat ? (new BlockPosition(this.locX(), (double) Math.round(this.locY()), this.locZ())).up() : new BlockPosition(this.locX(), (double) Math.round(this.locY()), this.locZ()); ++ ++ return brightness > 0.5F && this.random.nextFloat() * 30.0F < (brightness - 0.4F) * 2.0F && this.world.isSkyVisible(blockposition); ++ } ++ ++ return false; ++ } + // Purpur end + } +diff --git a/src/main/java/net/minecraft/world/entity/EntityInsentient.java b/src/main/java/net/minecraft/world/entity/EntityInsentient.java +index 7cacd2b56fa96411d9fdf96d985d24fe835f9a91..d96630a64f132eecf5cb4c80302cf9dd6176ad7c 100644 +--- a/src/main/java/net/minecraft/world/entity/EntityInsentient.java ++++ b/src/main/java/net/minecraft/world/entity/EntityInsentient.java +@@ -1678,6 +1678,7 @@ public abstract class EntityInsentient extends EntityLiving { + + public boolean isInDaylight() { return this.eG(); } // Paper - OBFHELPER + protected boolean eG() { ++ /* // Purpur start - moved to Entity + if (this.world.isDay() && !this.world.isClientSide) { + float f = this.aR(); + BlockPosition blockposition = this.getVehicle() instanceof EntityBoat ? (new BlockPosition(this.locX(), (double) Math.round(this.locY()), this.locZ())).up() : new BlockPosition(this.locX(), (double) Math.round(this.locY()), this.locZ()); +@@ -1688,6 +1689,9 @@ public abstract class EntityInsentient extends EntityLiving { + } + + return false; ++ */ ++ return super.isInDaylight(); ++ // Purpur end + } + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/EntityLiving.java b/src/main/java/net/minecraft/world/entity/EntityLiving.java +index fa8df6ecede6ecb207e0e3390cc96c72d71a8a18..0eaa7facd7a9348d90721a64427c7fdfb59bf8ea 100644 +--- a/src/main/java/net/minecraft/world/entity/EntityLiving.java ++++ b/src/main/java/net/minecraft/world/entity/EntityLiving.java +@@ -237,6 +237,7 @@ public abstract class EntityLiving extends Entity { + public boolean canPickUpLoot; + public org.bukkit.craftbukkit.entity.CraftLivingEntity getBukkitLivingEntity() { return (org.bukkit.craftbukkit.entity.CraftLivingEntity) super.getBukkitEntity(); } // Paper + public boolean silentDeath = false; // Paper - mark entity as dying silently for cancellable death event ++ protected boolean shouldBurnInDay; public boolean shouldBurnInDay() { return this.shouldBurnInDay; } public void setShouldBurnInDay(boolean shouldBurnInDay) { this.shouldBurnInDay = shouldBurnInDay; } // Purpur + + @Override + public float getBukkitYaw() { +@@ -275,6 +276,8 @@ public abstract class EntityLiving extends Entity { + DynamicOpsNBT dynamicopsnbt = DynamicOpsNBT.a; + + this.bg = this.a(new Dynamic(dynamicopsnbt, dynamicopsnbt.createMap((Map) ImmutableMap.of(dynamicopsnbt.createString("memories"), dynamicopsnbt.emptyMap())))); ++ ++ this.shouldBurnInDay = false; // Purpur + } + + protected void initAttributes() {} // Purpur +@@ -708,6 +711,7 @@ public abstract class EntityLiving extends Entity { + dataresult.resultOrPartial(logger::error).ifPresent((nbtbase) -> { + nbttagcompound.set("Brain", nbtbase); + }); ++ nbttagcompound.setBoolean("Purpur.ShouldBurnInDay", shouldBurnInDay); // Purpur + } + + @Override +@@ -783,6 +787,11 @@ public abstract class EntityLiving extends Entity { + this.bg = this.a(new Dynamic(DynamicOpsNBT.a, nbttagcompound.get("Brain"))); + } + ++ // Purpur start ++ if (nbttagcompound.hasKey("Purpur.ShouldBurnInDay")) { ++ shouldBurnInDay = nbttagcompound.getBoolean("Purpur.ShouldBurnInDay"); ++ } ++ // Purpur end + } + + // CraftBukkit start +@@ -3001,6 +3010,31 @@ public abstract class EntityLiving extends Entity { + this.damageEntity(DamageSource.DROWN, 1.0F); + } + ++ // Purpur start - copied from EntityZombie ++ if (this.isAlive()) { ++ boolean flag = this.shouldBurnInDay() && this.isInDaylight(); ++ ++ if (flag) { ++ ItemStack itemstack = this.getEquipment(EnumItemSlot.HEAD); ++ ++ if (!itemstack.isEmpty()) { ++ if (itemstack.isDamageableItem()) { ++ itemstack.setDamage(itemstack.getDamage() + this.random.nextInt(2)); ++ if (itemstack.getDamage() >= itemstack.getMaxDamage()) { ++ this.broadcastItemBreak(EnumItemSlot.HEAD); ++ this.setSlot(EnumItemSlot.HEAD, ItemStack.NULL_ITEM); ++ } ++ } ++ ++ flag = false; ++ } ++ ++ if (flag) { ++ this.setOnFire(8); ++ } ++ } ++ } ++ // Purpur end + } + + public boolean isSensitiveToWater() { return dO(); } // Purpur - OBFHELPER +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityPhantom.java b/src/main/java/net/minecraft/world/entity/monster/EntityPhantom.java +index fe07d9798eaae670e218d25fe23256c87c41d686..be5837c4f515cd2587bea22b14a3833a81e7b560 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityPhantom.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityPhantom.java +@@ -67,6 +67,7 @@ public class EntityPhantom extends EntityFlying implements IMonster { + this.f = 5; + this.moveController = new EntityPhantom.g(this); + this.lookController = new EntityPhantom.f(this); ++ this.setShouldBurnInDay(true); // Purpur + } + + // Purpur start +@@ -231,7 +232,7 @@ public class EntityPhantom extends EntityFlying implements IMonster { + + @Override + public void movementTick() { +- if (this.isAlive() && !hasPurpurRider() && (((shouldBurnInDay || world.purpurConfig.phantomBurnInDaylight) && this.isInDaylight()) || (world.purpurConfig.phantomBurnInLight > 0 && world.getLightLevel(new BlockPosition(this)) >= world.purpurConfig.phantomBurnInLight))) { // Paper - Configurable Burning // Purpur ++ if (this.isAlive() && !hasPurpurRider() && (((this.shouldBurnInDay() || world.purpurConfig.phantomBurnInDaylight) && this.isInDaylight()) || (world.purpurConfig.phantomBurnInLight > 0 && world.getLightLevel(new BlockPosition(this)) >= world.purpurConfig.phantomBurnInLight))) { // Paper - Configurable Burning // Purpur + this.setOnFire(8); + } + +@@ -262,7 +263,7 @@ public class EntityPhantom extends EntityFlying implements IMonster { + if (nbttagcompound.hasUUID("Paper.SpawningEntity")) { + this.spawningEntity = nbttagcompound.getUUID("Paper.SpawningEntity"); + } +- this.shouldBurnInDay = nbttagcompound.getBoolean("Paper.ShouldBurnInDay"); ++ // this.shouldBurnInDay = nbttagcompound.getBoolean("Paper.ShouldBurnInDay"); // Purpur - implemented in EntityLiving + // Paper end + } + +@@ -277,7 +278,7 @@ public class EntityPhantom extends EntityFlying implements IMonster { + if (this.spawningEntity != null) { + nbttagcompound.setUUID("Paper.SpawningEntity", this.spawningEntity); + } +- nbttagcompound.setBoolean("Paper.ShouldBurnInDay", shouldBurnInDay); ++ // nbttagcompound.setBoolean("Paper.ShouldBurnInDay", shouldBurnInDay); // Purpur - implemented in EntityLiving + // Paper end + } + +@@ -333,7 +334,7 @@ public class EntityPhantom extends EntityFlying implements IMonster { + } + public void setSpawningEntity(java.util.UUID entity) { this.spawningEntity = entity; } + +- private boolean shouldBurnInDay = true; ++ // private boolean shouldBurnInDay = true; // Purpur - moved to EntityLiving - keep methods for ABI compatibility + public boolean shouldBurnInDay() { return shouldBurnInDay; } + public void setShouldBurnInDay(boolean shouldBurnInDay) { this.shouldBurnInDay = shouldBurnInDay; } + // Paper end +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntitySkeletonAbstract.java b/src/main/java/net/minecraft/world/entity/monster/EntitySkeletonAbstract.java +index 81059fc3fc22f251b5b08f0cd6814a992cff6b1e..1676fbb80e5573c2591c1de7a6a858cf4824b48f 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntitySkeletonAbstract.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntitySkeletonAbstract.java +@@ -67,6 +67,7 @@ public abstract class EntitySkeletonAbstract extends EntityMonster implements IR + protected EntitySkeletonAbstract(EntityTypes entitytypes, World world) { + super(entitytypes, world); + this.eL(); ++ this.setShouldBurnInDay(true); // Purpur + } + + @Override +@@ -102,13 +103,14 @@ public abstract class EntitySkeletonAbstract extends EntityMonster implements IR + } + + // Paper start +- private boolean shouldBurnInDay = true; ++ // private boolean shouldBurnInDay = true; // Purpur - moved to EntityLiving - keep methods for ABI compatibility + public boolean shouldBurnInDay() { return shouldBurnInDay; } + public void setShouldBurnInDay(boolean shouldBurnInDay) { this.shouldBurnInDay = shouldBurnInDay; } + // Paper end + + @Override + public void movementTick() { ++ /* // Purpur start - implemented in EntityLiving + boolean flag = shouldBurnInDay && this.eG(); // Paper - Configurable Burning + + if (flag) { +@@ -130,6 +132,7 @@ public abstract class EntitySkeletonAbstract extends EntityMonster implements IR + this.setOnFire(8); + } + } ++ */ // Purpur end + + super.movementTick(); + } +@@ -233,14 +236,14 @@ public abstract class EntitySkeletonAbstract extends EntityMonster implements IR + public void loadData(NBTTagCompound nbttagcompound) { + super.loadData(nbttagcompound); + this.eL(); +- this.shouldBurnInDay = nbttagcompound.getBoolean("Paper.ShouldBurnInDay"); // Paper ++ // this.shouldBurnInDay = nbttagcompound.getBoolean("Paper.ShouldBurnInDay"); // Paper // Purpur - implemented in EntityLiving + } + + // Paper start + @Override + public void saveData(NBTTagCompound nbttagcompound) { + super.saveData(nbttagcompound); +- nbttagcompound.setBoolean("Paper.ShouldBurnInDay", shouldBurnInDay); ++ // nbttagcompound.setBoolean("Paper.ShouldBurnInDay", shouldBurnInDay); // Purpur - implemented in EntityLiving + } + // Paper end + +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityZombie.java b/src/main/java/net/minecraft/world/entity/monster/EntityZombie.java +index 7112db516e62ca75a445482005c524129b84f54c..bce7b674ef4450c1f6e932cba1b06ae8730cedfe 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityZombie.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityZombie.java +@@ -97,11 +97,12 @@ public class EntityZombie extends EntityMonster { + private int bt; + public int drownedConversionTime; + private int lastTick = MinecraftServer.currentTick; // CraftBukkit - add field +- private boolean shouldBurnInDay = true; // Paper ++ // private boolean shouldBurnInDay = true; // Paper // Purpur - implemented in EntityLiving + + public EntityZombie(EntityTypes entitytypes, World world) { + super(entitytypes, world); + this.br = new PathfinderGoalBreakDoor(this, com.google.common.base.Predicates.in(world.paperConfig.zombieBreakDoors)); // Paper ++ this.setShouldBurnInDay(true); // Purpur + } + + public EntityZombie(World world) { +@@ -288,6 +289,7 @@ public class EntityZombie extends EntityMonster { + + @Override + public void movementTick() { ++ /* // Purpur start - implemented in EntityLiving + if (this.isAlive()) { + boolean flag = this.T_() && this.eG(); + +@@ -311,6 +313,7 @@ public class EntityZombie extends EntityMonster { + } + } + } ++ */ // Purpur end + + super.movementTick(); + } +@@ -479,7 +482,7 @@ public class EntityZombie extends EntityMonster { + nbttagcompound.setBoolean("CanBreakDoors", this.eU()); + nbttagcompound.setInt("InWaterTime", this.isInWater() ? this.bt : -1); + nbttagcompound.setInt("DrownedConversionTime", this.isDrownConverting() ? this.drownedConversionTime : -1); +- nbttagcompound.setBoolean("Paper.ShouldBurnInDay", shouldBurnInDay); // Paper ++ // nbttagcompound.setBoolean("Paper.ShouldBurnInDay", shouldBurnInDay); // Paper // Purpur - implemented in EntityLiving + } + + @Override +@@ -491,11 +494,13 @@ public class EntityZombie extends EntityMonster { + if (nbttagcompound.hasKeyOfType("DrownedConversionTime", 99) && nbttagcompound.getInt("DrownedConversionTime") > -1) { + this.startDrownedConversion(nbttagcompound.getInt("DrownedConversionTime")); + } ++ /* // Purpur start - implemented in EntityLiving + // Paper start + if (nbttagcompound.hasKey("Paper.ShouldBurnInDay")) { + shouldBurnInDay = nbttagcompound.getBoolean("Paper.ShouldBurnInDay"); + } + // Paper end ++ */ // Purpur end - implemented in EntityLiving + } + + @Override +diff --git a/src/main/java/net/minecraft/world/entity/monster/EntityZombieHusk.java b/src/main/java/net/minecraft/world/entity/monster/EntityZombieHusk.java +index c060d93d9f3332b514a1400dec14f2035c058e48..2d249337be7f8c1feed204f5a1b47f278d68e867 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/EntityZombieHusk.java ++++ b/src/main/java/net/minecraft/world/entity/monster/EntityZombieHusk.java +@@ -21,6 +21,7 @@ public class EntityZombieHusk extends EntityZombie { + + public EntityZombieHusk(EntityTypes entitytypes, World world) { + super(entitytypes, world); ++ this.setShouldBurnInDay(false); // Purpur + } + + // Purpur start +@@ -65,7 +66,7 @@ public class EntityZombieHusk extends EntityZombie { + + @Override + protected boolean T_() { +- return false; ++ return this.shouldBurnInDay; // Purpur - moved to EntityLiving - keep methods for ABI compatibility + } + + @Override +diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java +index 677f866dfaab653b05c693663adaeb2465117a55..81ceeff37f7e03eead177cbd49f79a74be3aeeb2 100644 +--- a/src/main/java/net/minecraft/world/item/ItemStack.java ++++ b/src/main/java/net/minecraft/world/item/ItemStack.java +@@ -458,7 +458,7 @@ public final class ItemStack { + return this.getMaxStackSize() > 1 && (!this.e() || !this.f()); + } + +- public boolean e() { ++ public boolean isDamageableItem() { return e(); } public boolean e() { // Purpur - OBFHELPER + if (!this.j && this.getItem().getMaxDurability() > 0) { + NBTTagCompound nbttagcompound = this.getTag(); + +@@ -489,7 +489,7 @@ public final class ItemStack { + this.getOrCreateTag().setInt("Damage", Math.max(0, i)); + } + +- public int h() { ++ public int getMaxDamage() { return h(); } public int h() { // Purpur - OBFHELPER + return this.getItem().getMaxDurability(); + } + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +index af69023b241560031f6aa116561d7407b2502578..f0a16fae2ddba2e3deeb09f04c02972495a53137 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +@@ -1203,5 +1203,10 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { + entity.setLocation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); + return !entity.valid && entity.world.addEntity(entity, spawnReason); + } ++ ++ @Override ++ public boolean isInDaylight() { ++ return getHandle().isInDaylight(); ++ } + // Purpur end + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +index 411a84840764ce6f7a83e11655cc04403d6ee5ee..19cea6950872260f603e26857aa82e5e899b2a00 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +@@ -892,5 +892,15 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { + if (slot == null) return; + getHandle().broadcastItemBreak(org.bukkit.craftbukkit.CraftEquipmentSlot.getNMS(slot)); + } ++ ++ @Override ++ public boolean shouldBurnInDay() { ++ return getHandle().shouldBurnInDay(); ++ } ++ ++ @Override ++ public void setShouldBurnInDay(boolean shouldBurnInDay) { ++ getHandle().setShouldBurnInDay(shouldBurnInDay); ++ } + // Purpur end + } diff --git a/patches/Purpur/patches/server/0218-Fix-advancement-triggers-on-entity-death.patch b/patches/Purpur/patches/server/0218-Fix-advancement-triggers-on-entity-death.patch new file mode 100644 index 00000000..5124d14c --- /dev/null +++ b/patches/Purpur/patches/server/0218-Fix-advancement-triggers-on-entity-death.patch @@ -0,0 +1,209 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Fri, 28 May 2021 12:24:45 -0500 +Subject: [PATCH] Fix advancement triggers on entity death + +This fixes PaperMC/Paper#3729 and PaperMC/Paper#4252 + +Paper changes logical order revolving around making the EntityDeathEvent +cancellable. Reordering this logic has ended up with entity equipment being +cleared _before_ advancement criteria can run, causing things like killing +raid captains not giving the voluntary exile advancement. + +This fixes the issue by storing a copy of the equipment in a new field just +before doing the death event logic where the equipment is cleared and then +restoring it back to the entity just before the criterion triggers run and +then finally clearing the equipment again right after the criterion is done. + +diff --git a/src/main/java/net/minecraft/world/entity/EntityInsentient.java b/src/main/java/net/minecraft/world/entity/EntityInsentient.java +index d96630a64f132eecf5cb4c80302cf9dd6176ad7c..b4afd71340a0c7e1b6aa2e3f01a6a4fc998f3f16 100644 +--- a/src/main/java/net/minecraft/world/entity/EntityInsentient.java ++++ b/src/main/java/net/minecraft/world/entity/EntityInsentient.java +@@ -106,9 +106,9 @@ public abstract class EntityInsentient extends EntityLiving { + public PathfinderGoalSelector targetSelector; + private EntityLiving goalTarget; + private final EntitySenses bo; +- private final NonNullList bp; ++ private final NonNullList bp; public List getHandEquipment() { return this.bp; } // Purpur - OBFHELPER + public final float[] dropChanceHand; +- private final NonNullList bq; ++ private final NonNullList bq; public List getArmorEquipment() { return this.bq; } // Purpur - OBFHELPER + public final float[] dropChanceArmor; + // private boolean canPickUpLoot; // CraftBukkit - moved up to EntityLiving + public boolean persistent; +@@ -1004,6 +1004,41 @@ public abstract class EntityInsentient extends EntityLiving { + } + } + ++ // Purpur start ++ public List> cloneEquipment() { ++ List> list = new java.util.ArrayList<>(); ++ List handItems = new java.util.ArrayList<>(); ++ for (ItemStack item : this.getHandEquipment()) { ++ handItems.add(item.cloneItemStack()); ++ } ++ list.add(handItems); ++ List armorItems = new java.util.ArrayList<>(); ++ for (ItemStack item : this.getArmorEquipment()) { ++ armorItems.add(item.cloneItemStack()); ++ } ++ list.add(armorItems); ++ return list; ++ } ++ ++ public void restoreEquipment(List> list) { ++ this.getHandEquipment().clear(); ++ List handItems = list.get(0); ++ for (int i = 0; i < handItems.size(); i++) { ++ this.getHandEquipment().set(i, handItems.get(1)); ++ } ++ this.getArmorEquipment().clear(); ++ List armorItems = list.get(1); ++ for (int i = 0; i < armorItems.size(); i++) { ++ this.getArmorEquipment().set(i, armorItems.get(i)); ++ } ++ } ++ ++ public void clearEquipment() { ++ this.getHandEquipment().clear(); ++ this.getArmorEquipment().clear(); ++ } ++ // Purpur end ++ + @Override + public void setSlot(EnumItemSlot enumitemslot, ItemStack itemstack) { + switch (enumitemslot.a()) { +diff --git a/src/main/java/net/minecraft/world/entity/EntityLiving.java b/src/main/java/net/minecraft/world/entity/EntityLiving.java +index 0eaa7facd7a9348d90721a64427c7fdfb59bf8ea..158388410ea14b2df95635914844952bd52b8f87 100644 +--- a/src/main/java/net/minecraft/world/entity/EntityLiving.java ++++ b/src/main/java/net/minecraft/world/entity/EntityLiving.java +@@ -1557,10 +1557,13 @@ public abstract class EntityLiving extends Entity { + } + + // Paper start ++ List> equipmentSnapshotBefore = this.cloneEquipment(); // Purpur + org.bukkit.event.entity.EntityDeathEvent deathEvent = this.d(damagesource); + if (deathEvent == null || !deathEvent.isCancelled()) { + if (this.getKillCount() >= 0 && entityliving != null) { ++ this.restoreEquipment(equipmentSnapshotBefore); // Purpur + entityliving.runKillTrigger(this, this.getKillCount(), damagesource); ++ this.clearEquipment(); // Purpur + } + if (this.isSleeping()) { + this.entityWakeup(); +@@ -2258,6 +2261,12 @@ public abstract class EntityLiving extends Entity { + + public abstract ItemStack getEquipment(EnumItemSlot enumitemslot); + ++ // Purpur start ++ public abstract List> cloneEquipment(); ++ public abstract void restoreEquipment(List> list); ++ public abstract void clearEquipment(); ++ // Purpur end ++ + // CraftBukkit start + public void setSlot(EnumItemSlot enumitemslot, ItemStack itemstack, boolean silent) { + this.setSlot(enumitemslot, itemstack); +diff --git a/src/main/java/net/minecraft/world/entity/decoration/EntityArmorStand.java b/src/main/java/net/minecraft/world/entity/decoration/EntityArmorStand.java +index ddc1c3383cdc32fa832485f3922c74185731557a..e28a2d983ae7b83f435c9dea606a92e2fbd3391a 100644 +--- a/src/main/java/net/minecraft/world/entity/decoration/EntityArmorStand.java ++++ b/src/main/java/net/minecraft/world/entity/decoration/EntityArmorStand.java +@@ -171,6 +171,41 @@ public class EntityArmorStand extends EntityLiving { + } + } + ++ // Purpur start ++ public List> cloneEquipment() { ++ List> list = new java.util.ArrayList<>(); ++ List handItems = new java.util.ArrayList<>(); ++ for (ItemStack item : this.handItems) { ++ handItems.add(item.cloneItemStack()); ++ } ++ list.add(handItems); ++ List armorItems = new java.util.ArrayList<>(); ++ for (ItemStack item : this.armorItems) { ++ armorItems.add(item.cloneItemStack()); ++ } ++ list.add(armorItems); ++ return list; ++ } ++ ++ public void restoreEquipment(List> list) { ++ this.handItems.clear(); ++ List handItems = list.get(0); ++ for (int i = 0; i < handItems.size(); i++) { ++ this.handItems.set(i, handItems.get(1)); ++ } ++ this.armorItems.clear(); ++ List armorItems = list.get(1); ++ for (int i = 0; i < armorItems.size(); i++) { ++ this.armorItems.set(i, armorItems.get(1)); ++ } ++ } ++ ++ public void clearEquipment() { ++ this.handItems.clear(); ++ this.armorItems.clear(); ++ } ++ // Purpur end ++ + @Override + public void setSlot(EnumItemSlot enumitemslot, ItemStack itemstack) { + // CraftBukkit start +diff --git a/src/main/java/net/minecraft/world/entity/player/EntityHuman.java b/src/main/java/net/minecraft/world/entity/player/EntityHuman.java +index 24285b1b2264939fdfa6f7d6311772fa67be8680..383b4cacc8c9f4fd5d2a83f683e5174ea5025f61 100644 +--- a/src/main/java/net/minecraft/world/entity/player/EntityHuman.java ++++ b/src/main/java/net/minecraft/world/entity/player/EntityHuman.java +@@ -1886,6 +1886,52 @@ public abstract class EntityHuman extends EntityLiving { + return enumitemslot == EnumItemSlot.MAINHAND ? this.inventory.getItemInHand() : (enumitemslot == EnumItemSlot.OFFHAND ? (ItemStack) this.inventory.extraSlots.get(0) : (enumitemslot.a() == EnumItemSlot.Function.ARMOR ? (ItemStack) this.inventory.armor.get(enumitemslot.b()) : ItemStack.b)); + } + ++ // Purpur start ++ public List> cloneEquipment() { ++ List> list = new java.util.ArrayList<>(); ++ List invItems = new java.util.ArrayList<>(); ++ for (ItemStack item : this.inventory.items) { ++ invItems.add(item.cloneItemStack()); ++ } ++ list.add(invItems); ++ List armorItems = new java.util.ArrayList<>(); ++ for (ItemStack item : this.inventory.armor) { ++ armorItems.add(item.cloneItemStack()); ++ } ++ list.add(armorItems); ++ List extraItems = new java.util.ArrayList<>(); ++ for (ItemStack item : this.inventory.extraSlots) { ++ extraItems.add(item.cloneItemStack()); ++ } ++ list.add(extraItems); ++ return list; ++ } ++ ++ public void restoreEquipment(List> list) { ++ this.inventory.items.clear(); ++ List invItems = list.get(0); ++ for (int i = 0; i < invItems.size(); i++) { ++ this.inventory.items.set(i, invItems.get(1)); ++ } ++ this.inventory.armor.clear(); ++ List armorItems = list.get(1); ++ for (int i = 0; i < armorItems.size(); i++) { ++ this.inventory.armor.set(i, armorItems.get(1)); ++ } ++ this.inventory.extraSlots.clear(); ++ List extraItems = list.get(2); ++ for (int i = 0; i < extraItems.size(); i++) { ++ this.inventory.extraSlots.set(i, extraItems.get(1)); ++ } ++ } ++ ++ public void clearEquipment() { ++ this.inventory.items.clear(); ++ this.inventory.armor.clear(); ++ this.inventory.extraSlots.clear(); ++ } ++ // Purpur end ++ + @Override + public void setSlot(EnumItemSlot enumitemslot, ItemStack itemstack) { + // CraftBukkit start diff --git a/patches/Purpur/patches/server/0219-Config-MobEffect-by-world.patch b/patches/Purpur/patches/server/0219-Config-MobEffect-by-world.patch new file mode 100644 index 00000000..b9fd0ce5 --- /dev/null +++ b/patches/Purpur/patches/server/0219-Config-MobEffect-by-world.patch @@ -0,0 +1,65 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: DoctaEnkoda +Date: Mon, 31 May 2021 11:06:54 +0200 +Subject: [PATCH] Config MobEffect by world + + +diff --git a/src/main/java/net/minecraft/world/effect/MobEffectList.java b/src/main/java/net/minecraft/world/effect/MobEffectList.java +index 6dbd54c44ac88025464f78e72069c538d9f43dc3..f0348960e17056ea9dad0f08fe010a7c69123094 100644 +--- a/src/main/java/net/minecraft/world/effect/MobEffectList.java ++++ b/src/main/java/net/minecraft/world/effect/MobEffectList.java +@@ -51,16 +51,16 @@ public class MobEffectList { + public void tick(EntityLiving entityliving, int i) { + if (this == MobEffects.REGENERATION) { + if (entityliving.getHealth() < entityliving.getMaxHealth()) { +- entityliving.heal(1.0F, RegainReason.MAGIC_REGEN); // CraftBukkit ++ entityliving.heal(entityliving.getWorld().purpurConfig.entityHealthRegenAmount, RegainReason.MAGIC_REGEN); // CraftBukkit // Purpur + } + } else if (this == MobEffects.POISON) { +- if (entityliving.getHealth() > 1.0F) { +- entityliving.damageEntity(CraftEventFactory.POISON, 1.0F); // CraftBukkit - DamageSource.MAGIC -> CraftEventFactory.POISON ++ if (entityliving.getHealth() > entityliving.getWorld().purpurConfig.entityMinimalHealthPoison) { // Purpur ++ entityliving.damageEntity(CraftEventFactory.POISON, entityliving.getWorld().purpurConfig.entityPoisonDegenerationAmount); // CraftBukkit - DamageSource.MAGIC -> CraftEventFactory.POISON // Purpur + } + } else if (this == MobEffects.WITHER) { +- entityliving.damageEntity(DamageSource.WITHER, 1.0F); ++ entityliving.damageEntity(DamageSource.WITHER, entityliving.getWorld().purpurConfig.entityWitherDegenerationAmount); + } else if (this == MobEffects.HUNGER && entityliving instanceof EntityHuman) { +- ((EntityHuman) entityliving).applyExhaustion(0.005F * (float) (i + 1), org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.HUNGER_EFFECT); // CraftBukkit - EntityExhaustionEvent ++ ((EntityHuman) entityliving).applyExhaustion(entityliving.getWorld().purpurConfig.humanHungerExhaustionAmount * (float) (i + 1), org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.HUNGER_EFFECT); // CraftBukkit - EntityExhaustionEvent // Purpur + } else if (this == MobEffects.SATURATION && entityliving instanceof EntityHuman) { + if (!entityliving.world.isClientSide) { + // CraftBukkit start +@@ -70,7 +70,7 @@ public class MobEffectList { + org.bukkit.event.entity.FoodLevelChangeEvent event = CraftEventFactory.callFoodLevelChangeEvent(entityhuman, i + 1 + oldFoodLevel); + + if (!event.isCancelled()) { +- entityhuman.getFoodData().eat(event.getFoodLevel() - oldFoodLevel, 1.0F); ++ entityhuman.getFoodData().eat(event.getFoodLevel() - oldFoodLevel, entityliving.getWorld().purpurConfig.humanSaturationRegenAmount); // Purpur + } + + ((EntityPlayer) entityhuman).playerConnection.sendPacket(new PacketPlayOutUpdateHealth(((EntityPlayer) entityhuman).getBukkitEntity().getScaledHealth(), entityhuman.getFoodData().foodLevel, entityhuman.getFoodData().saturationLevel)); +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index bd72ed2da22c1d1121ea7ca04e163979baa05b27..f27c55d8d6dabe7d2cbaf6ab01e1a484e1d96f53 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -2189,4 +2189,19 @@ public class PurpurWorldConfig { + private void pistonSettings() { + pistonBlockPushLimit = getInt("blocks.piston.block-push-limit", pistonBlockPushLimit); + } ++ ++ public float entityHealthRegenAmount = 1.0F; ++ public float entityMinimalHealthPoison = 1.0F; ++ public float entityPoisonDegenerationAmount = 1.0F; ++ public float entityWitherDegenerationAmount = 1.0F; ++ public float humanHungerExhaustionAmount = 0.005F; ++ public float humanSaturationRegenAmount = 1.0F; ++ private void mobEffectSettings() { ++ entityHealthRegenAmount = (float) getDouble("gameplay-mechanics.mob-effects.health-regen-amount", entityHealthRegenAmount); ++ entityMinimalHealthPoison = (float) getDouble("gameplay-mechanics.mob-effects.minimal-health-poison-amount", entityMinimalHealthPoison); ++ entityPoisonDegenerationAmount = (float) getDouble("gameplay-mechanics.mob-effects.poison-degeneration-amount", entityPoisonDegenerationAmount); ++ entityWitherDegenerationAmount = (float) getDouble("gameplay-mechanics.mob-effects.wither-degeneration-amount", entityWitherDegenerationAmount); ++ humanHungerExhaustionAmount = (float) getDouble("gameplay-mechanics.mob-effects.hunger-exhaustion-amount", humanHungerExhaustionAmount); ++ humanSaturationRegenAmount = (float) getDouble("gameplay-mechanics.mob-effects.saturation-regen-amount", humanSaturationRegenAmount); ++ } + } diff --git a/patches/Purpur/patches/server/0220-Beacon-Activation-Range-Configurable.patch b/patches/Purpur/patches/server/0220-Beacon-Activation-Range-Configurable.patch new file mode 100644 index 00000000..acdc626d --- /dev/null +++ b/patches/Purpur/patches/server/0220-Beacon-Activation-Range-Configurable.patch @@ -0,0 +1,49 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: DoctaEnkoda +Date: Wed, 2 Jun 2021 02:45:47 +0200 +Subject: [PATCH] Beacon Activation Range Configurable + + +diff --git a/src/main/java/net/minecraft/world/level/block/entity/TileEntityBeacon.java b/src/main/java/net/minecraft/world/level/block/entity/TileEntityBeacon.java +index f7b210e6d60533d9faf60183a80a562b25f945d0..926e1344a8db4b18caebae77096c2600e0a4958f 100644 +--- a/src/main/java/net/minecraft/world/level/block/entity/TileEntityBeacon.java ++++ b/src/main/java/net/minecraft/world/level/block/entity/TileEntityBeacon.java +@@ -79,6 +79,16 @@ public class TileEntityBeacon extends TileEntity implements ITileInventory, ITic + + public double getEffectRange() { + if (this.effectRange < 0) { ++ // Purpur Start ++ if (this.world != null) { ++ switch (this.levels) { ++ case 1: return this.world.purpurConfig.beaconLevelOne; ++ case 2: return this.world.purpurConfig.beaconLevelTwo; ++ case 3: return this.world.purpurConfig.beaconLevelThree; ++ case 4: return this.world.purpurConfig.beaconLevelFour; ++ } ++ } ++ // Purpur End + return this.levels * 10 + 10; + } else { + return effectRange; +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index f27c55d8d6dabe7d2cbaf6ab01e1a484e1d96f53..69b158b2f0f6d3c11144e5b312ca92d970c791a3 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -511,6 +511,17 @@ public class PurpurWorldConfig { + anvilAllowColors = getBoolean("blocks.anvil.allow-colors", anvilAllowColors); + } + ++ public int beaconLevelOne = 20; ++ public int beaconLevelTwo = 30; ++ public int beaconLevelThree = 40; ++ public int beaconLevelFour = 50; ++ private void beaconSettings() { ++ beaconLevelOne = getInt("blocks.beacon.effect-range.level-1", beaconLevelOne); ++ beaconLevelTwo = getInt("blocks.beacon.effect-range.level-2", beaconLevelTwo); ++ beaconLevelThree = getInt("blocks.beacon.effect-range.level-3", beaconLevelThree); ++ beaconLevelFour = getInt("blocks.beacon.effect-range.level-4", beaconLevelFour); ++ } ++ + public boolean bedExplode = true; + public double bedExplosionPower = 5.0D; + public boolean bedExplosionFire = true; diff --git a/patches/Purpur/patches/server/0221-Add-toggle-for-sand-duping-fix.patch b/patches/Purpur/patches/server/0221-Add-toggle-for-sand-duping-fix.patch new file mode 100644 index 00000000..a60d3571 --- /dev/null +++ b/patches/Purpur/patches/server/0221-Add-toggle-for-sand-duping-fix.patch @@ -0,0 +1,44 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Fri, 4 Jun 2021 09:13:54 -0500 +Subject: [PATCH] Add toggle for sand duping fix + + +diff --git a/src/main/java/net/minecraft/world/entity/item/EntityFallingBlock.java b/src/main/java/net/minecraft/world/entity/item/EntityFallingBlock.java +index 2a61c24dd26edf4c72e977c6024fe233bab08a2f..58d14c70a95057e91766cc6aa060133189e3c096 100644 +--- a/src/main/java/net/minecraft/world/entity/item/EntityFallingBlock.java ++++ b/src/main/java/net/minecraft/world/entity/item/EntityFallingBlock.java +@@ -106,7 +106,7 @@ public class EntityFallingBlock extends Entity { + @Override + public void tick() { + // Paper start - fix sand duping +- if (this.dead) { ++ if (this.world.purpurConfig.fixSandDuping && this.dead) { // Purpur + return; + } + // Paper end - fix sand duping +@@ -143,7 +143,7 @@ public class EntityFallingBlock extends Entity { + this.move(EnumMoveType.SELF, this.getMot()); + + // Paper start - fix sand duping +- if (this.dead) { ++ if (this.world.purpurConfig.fixSandDuping && this.dead) { // Purpur + return; + } + // Paper end - fix sand duping +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index 69b158b2f0f6d3c11144e5b312ca92d970c791a3..bd434559414a209db9e13c49303cab4a9f84ac15 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -641,6 +641,11 @@ public class PurpurWorldConfig { + } + } + ++ public boolean fixSandDuping = true; ++ private void sandSettings() { ++ fixSandDuping = getBoolean("blocks.sand.fix-duping", fixSandDuping); ++ } ++ + public boolean shulkerBoxAllowOversizedStacks = false; + private void shulkerBoxSettings() { + shulkerBoxAllowOversizedStacks = getBoolean("blocks.shulker_box.allow-oversized-stacks", shulkerBoxAllowOversizedStacks); diff --git a/patches/Purpur/patches/server/0222-Add-toggle-for-end-portal-safe-teleporting.patch b/patches/Purpur/patches/server/0222-Add-toggle-for-end-portal-safe-teleporting.patch new file mode 100644 index 00000000..6eab623e --- /dev/null +++ b/patches/Purpur/patches/server/0222-Add-toggle-for-end-portal-safe-teleporting.patch @@ -0,0 +1,62 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Wed, 9 Jun 2021 11:03:40 -0500 +Subject: [PATCH] Add toggle for end portal safe teleporting + + +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index 35c15afc3f4bbe10dc7638e926564f51285fda4c..18e5110047f13c213e70d3e094b94fecb4408d18 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -2603,7 +2603,7 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, ne + } + + this.E(); +- this.tickEndPortal(); // Paper - make end portalling safe ++ if (world.purpurConfig.endPortalSafeTeleporting) this.tickEndPortal(); // Paper - make end portalling safe // Purpur + } + } + +diff --git a/src/main/java/net/minecraft/world/level/block/BlockEnderPortal.java b/src/main/java/net/minecraft/world/level/block/BlockEnderPortal.java +index 31eabc40562462f98cc039a55453f200ca4eaa5c..56e81e3e2bbe87d28440ddb9a6285c781ec6530e 100644 +--- a/src/main/java/net/minecraft/world/level/block/BlockEnderPortal.java ++++ b/src/main/java/net/minecraft/world/level/block/BlockEnderPortal.java +@@ -60,6 +60,22 @@ public class BlockEnderPortal extends BlockTileEntity { + // return; // CraftBukkit - always fire event in case plugins wish to change it + } + ++ // Purpur start ++ if (!world.purpurConfig.endPortalSafeTeleporting) { ++ // CraftBukkit start - Entity in portal ++ EntityPortalEnterEvent event = new EntityPortalEnterEvent(entity.getBukkitEntity(), new org.bukkit.Location(world.getWorld(), blockposition.getX(), blockposition.getY(), blockposition.getZ())); ++ world.getServer().getPluginManager().callEvent(event); ++ ++ if (entity instanceof EntityPlayer) { ++ ((EntityPlayer) entity).changeDimension(worldserver, PlayerTeleportEvent.TeleportCause.END_PORTAL); ++ return; ++ } ++ // CraftBukkit end ++ entity.teleportTo(worldserver, null); ++ return; ++ } ++ // Purpur end ++ + // Paper start - move all of this logic into portal tick + entity.portalWorld = ((WorldServer)world); + entity.portalBlock = blockposition.immutableCopy(); +diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +index bd434559414a209db9e13c49303cab4a9f84ac15..5f1bfe41b9f7f24b86e72ea3b57acb3a7da95ad3 100644 +--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java ++++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java +@@ -553,6 +553,11 @@ public class PurpurWorldConfig { + dragonEggTeleport = getBoolean("blocks.dragon_egg.teleport", dragonEggTeleport); + } + ++ public boolean endPortalSafeTeleporting = true; ++ private void endPortalSettings() { ++ endPortalSafeTeleporting = getBoolean("blocks.end_portal.safe-teleporting", endPortalSafeTeleporting); ++ } ++ + public boolean snowOnBlueIce = true; + public boolean mobsSpawnOnPackedIce = true; + public boolean mobsSpawnOnBlueIce = true; diff --git a/patches/Purpur/patches/server/0223-Flying-Fall-Damage-API.patch b/patches/Purpur/patches/server/0223-Flying-Fall-Damage-API.patch new file mode 100644 index 00000000..25713a6f --- /dev/null +++ b/patches/Purpur/patches/server/0223-Flying-Fall-Damage-API.patch @@ -0,0 +1,51 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: TreyRuffy +Date: Wed, 9 Jun 2021 16:31:14 -0600 +Subject: [PATCH] Flying Fall Damage API + + +diff --git a/src/main/java/net/minecraft/world/entity/player/EntityHuman.java b/src/main/java/net/minecraft/world/entity/player/EntityHuman.java +index 383b4cacc8c9f4fd5d2a83f683e5174ea5025f61..be7c38c54311d6ea99a4ce2eec63863b649de3b2 100644 +--- a/src/main/java/net/minecraft/world/entity/player/EntityHuman.java ++++ b/src/main/java/net/minecraft/world/entity/player/EntityHuman.java +@@ -169,7 +169,10 @@ public abstract class EntityHuman extends EntityLiving { + // Paper start + public boolean affectsSpawning = true; + // Paper end +- public boolean isCritical = false; // Purpur ++ // Purpur start ++ public boolean flyingFallDamage = false; ++ public boolean isCritical = false; ++ // Purpur end + + // CraftBukkit start + public boolean fauxSleeping; +@@ -1651,7 +1654,7 @@ public abstract class EntityHuman extends EntityLiving { + + @Override + public boolean b(float f, float f1) { +- if (this.abilities.canFly) { ++ if (this.abilities.canFly && !flyingFallDamage) { // Purpur - allow fall damage with can fly attribute + return false; + } else { + if (f >= 2.0F) { +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +index 0501d5bee249ac35e6344dfa1bed3d802901f377..9ecad2520740cc1c8f7017eaa935460777d0c191 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +@@ -2541,5 +2541,15 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + public void setSpawnInvulnerableTicks(int invulnerableTicks) { + getHandle().invulnerableTicks = invulnerableTicks; + } ++ ++ @Override ++ public void setFlyingFallDamage(boolean flyingFallDamage) { ++ getHandle().flyingFallDamage = flyingFallDamage; ++ } ++ ++ @Override ++ public boolean hasFlyingFallDamage() { ++ return getHandle().flyingFallDamage; ++ } + // Purpur end + } diff --git a/patches/api/0002-Yatopia-Config-Redirect-Config.patch b/patches/api/0002-Yatopia-Config-Redirect-Config.patch index 05e2b321..5b70e65e 100644 --- a/patches/api/0002-Yatopia-Config-Redirect-Config.patch +++ b/patches/api/0002-Yatopia-Config-Redirect-Config.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Yatopia Config & Redirect Config diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java -index f55ae8275c297c4c86215fba8d7197ffe9715879..c8777df1cba3be24d52454954992f4d4dfcdc681 100644 +index a7fcd00ae37f9a2026759642562b1059c9dd9526..a7f6b64ec01a602230734cdc18d9279addae0e1a 100644 --- a/src/main/java/org/bukkit/Server.java +++ b/src/main/java/org/bukkit/Server.java -@@ -1625,6 +1625,22 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi +@@ -1640,6 +1640,22 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi throw new UnsupportedOperationException("Not supported yet."); } diff --git a/patches/api/0004-Add-last-tick-time-API.patch b/patches/api/0004-Add-last-tick-time-API.patch index 9beb438d..7ab8db3d 100644 --- a/patches/api/0004-Add-last-tick-time-API.patch +++ b/patches/api/0004-Add-last-tick-time-API.patch @@ -7,13 +7,13 @@ Original patch by: Co-authored-by: tr7zw diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java -index e8414592b3afeb1e5db2b817b8fb7c13e073b9aa..a456aa138d148b0d1b5c8b2330422bf66bec59fe 100644 +index 194261bf20bb727d207a2429fa59abf0acf61b19..15203139858b09a5ba75545c0c19c89d48419a2c 100644 --- a/src/main/java/org/bukkit/Bukkit.java +++ b/src/main/java/org/bukkit/Bukkit.java -@@ -1963,4 +1963,14 @@ public final class Bukkit { - public static Server.Spigot spigot() { - return server.spigot(); +@@ -1983,4 +1983,14 @@ public final class Bukkit { + return server.isLagging(); } + // Purpur end + + // Yatopia start + @Deprecated @@ -26,13 +26,13 @@ index e8414592b3afeb1e5db2b817b8fb7c13e073b9aa..a456aa138d148b0d1b5c8b2330422bf6 + // Yatopia end } diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java -index c8777df1cba3be24d52454954992f4d4dfcdc681..cc46fbb96e25f706b5d7c068576cf99ba693b448 100644 +index a7f6b64ec01a602230734cdc18d9279addae0e1a..caabb5ef215e1d25c3ebafacd3476669299f55fa 100644 --- a/src/main/java/org/bukkit/Server.java +++ b/src/main/java/org/bukkit/Server.java -@@ -1740,4 +1740,24 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi - @NotNull - io.papermc.paper.datapack.DatapackManager getDatapackManager(); - // Paper end +@@ -1771,4 +1771,24 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi + */ + boolean isLagging(); + // Purpur end + + // Yatopia start + /** diff --git a/patches/api/0005-Add-NBT-API-as-a-first-class-lib.patch b/patches/api/0005-Add-NBT-API-as-a-first-class-lib.patch index 159c0fc9..bfb3a87e 100644 --- a/patches/api/0005-Add-NBT-API-as-a-first-class-lib.patch +++ b/patches/api/0005-Add-NBT-API-as-a-first-class-lib.patch @@ -98,13 +98,13 @@ index 3b10fcc13893403b29f0260b8605144679e89b82..1e9a96d8b08cc396acf73dc420830093 + // Yatopia end } diff --git a/src/main/java/org/bukkit/entity/Entity.java b/src/main/java/org/bukkit/entity/Entity.java -index 46985eaea3d3b00d1dd88c2dd5a2bc53d518c64f..5b192cde7354eacc2563aa1506b7f180c65421e7 100644 +index 62d8d7dbd4d602ca8cb00ff0cf1331583b398323..7cb395466babc84dd4ce1c91cbab7d130a5437b3 100644 --- a/src/main/java/org/bukkit/entity/Entity.java +++ b/src/main/java/org/bukkit/entity/Entity.java -@@ -704,4 +704,26 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent +@@ -778,4 +778,26 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent */ - public boolean isTicking(); - // Paper end + boolean isInDaylight(); + // Purpur end + + // Yatopia start + /** @@ -129,13 +129,13 @@ index 46985eaea3d3b00d1dd88c2dd5a2bc53d518c64f..5b192cde7354eacc2563aa1506b7f180 + // Yatopia end } diff --git a/src/main/java/org/bukkit/inventory/ItemStack.java b/src/main/java/org/bukkit/inventory/ItemStack.java -index a7909406e9d54c1ab4789b984ed6b1da50837fce..0e4ce183d60ea867c1518b58ccc71b6c1ad71228 100644 +index ac2967eac165d74c8ee7e0e9ac63124a10851a0e..df684f97b6258bfeeccc4e1692a62715a8c12833 100644 --- a/src/main/java/org/bukkit/inventory/ItemStack.java +++ b/src/main/java/org/bukkit/inventory/ItemStack.java -@@ -921,4 +921,42 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, net.kyor - return Bukkit.getUnsafe().isValidRepairItemStack(toBeRepaired, this); +@@ -1555,4 +1555,42 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, net.kyor + return random.nextInt(unbreaking + 1) > 0; } - // Paper end + // Purpur end + + // Yatopia start + /** diff --git a/patches/server/0002-Brandings.patch b/patches/server/0002-Brandings.patch index 2f6934f9..ad9821c6 100644 --- a/patches/server/0002-Brandings.patch +++ b/patches/server/0002-Brandings.patch @@ -5,29 +5,18 @@ Subject: [PATCH] Brandings diff --git a/src/main/java/com/destroystokyo/paper/Metrics.java b/src/main/java/com/destroystokyo/paper/Metrics.java -index 52c0ab1ce46e1f3233ef746d9bc699356fa9fae4..1c7dd62287614f98d26ef23459c17560339ffd0a 100644 +index 4d8740678049aa749b42618470e9cc838555528d..8003c56b1fa3d37a00b93ab2fca9a2c825ae505e 100644 --- a/src/main/java/com/destroystokyo/paper/Metrics.java +++ b/src/main/java/com/destroystokyo/paper/Metrics.java @@ -593,7 +593,7 @@ public class Metrics { boolean logFailedRequests = config.getBoolean("logFailedRequests", false); // Only start Metrics, if it's enabled in the config if (config.getBoolean("enabled", true)) { -- Metrics metrics = new Metrics("Tuinity", serverUUID, logFailedRequests, Bukkit.getLogger()); // Tuinity - we have our own bstats page -+ Metrics metrics = new Metrics("Yatopia", serverUUID, logFailedRequests, Bukkit.getLogger()); // Tuinity - we have our own bstats page // Yatopia +- Metrics metrics = new Metrics("Purpur", serverUUID, logFailedRequests, Bukkit.getLogger()); // Purpur ++ Metrics metrics = new Metrics("Yatopia", serverUUID, logFailedRequests, Bukkit.getLogger()); // Purpur // Yatopia metrics.addCustomChart(new Metrics.SimplePie("minecraft_version", () -> { String minecraftVersion = Bukkit.getVersion(); -@@ -602,8 +602,8 @@ public class Metrics { - })); - - metrics.addCustomChart(new Metrics.SingleLineChart("players", () -> Bukkit.getOnlinePlayers().size())); -- metrics.addCustomChart(new Metrics.SimplePie("online_mode", () -> Bukkit.getOnlineMode() || PaperConfig.isProxyOnlineMode() ? "online" : "offline")); -- metrics.addCustomChart(new Metrics.SimplePie("tuinity_version", () -> (Metrics.class.getPackage().getImplementationVersion() != null) ? Metrics.class.getPackage().getImplementationVersion() : "unknown")); // Tuinity - we have our own bstats page -+ metrics.addCustomChart(new Metrics.SimplePie("online_mode", () -> Bukkit.getOnlineMode() ? "online" : (PaperConfig.isProxyOnlineMode() ? "bungee" : "offline"))); // Yatopia -+ metrics.addCustomChart(new Metrics.SimplePie("yatopia_version", () -> (Metrics.class.getPackage().getImplementationVersion() != null) ? Metrics.class.getPackage().getImplementationVersion() : "unknown"));// Yatopia - - metrics.addCustomChart(new Metrics.DrilldownPie("java_version", () -> { - Map> map = new HashMap<>(); diff --git a/src/main/java/com/destroystokyo/paper/console/PaperConsole.java b/src/main/java/com/destroystokyo/paper/console/PaperConsole.java index ad87b575a0261200b280884e054a59e3ce59c41c..eb0509386feb156ae9c8ca0eb25c0120c9332b19 100644 --- a/src/main/java/com/destroystokyo/paper/console/PaperConsole.java @@ -42,7 +31,7 @@ index ad87b575a0261200b280884e054a59e3ce59c41c..eb0509386feb156ae9c8ca0eb25c0120 .completer(new ConsoleCommandCompleter(this.server)) .option(LineReader.Option.COMPLETE_IN_WORD, true); diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index ca2c46bb22d4aca818f2aad107da42ebe09f2d2f..e6439b95959af5e8761ea818a66344eee6048e90 100644 +index 188365768dcaf0df6805eca065501572f7f9f501..bc0fb823ed6d4adf89c56ea29eefb600039ec0fe 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -230,7 +230,7 @@ import javax.annotation.Nullable; // Paper @@ -55,10 +44,10 @@ index ca2c46bb22d4aca818f2aad107da42ebe09f2d2f..e6439b95959af5e8761ea818a66344ee private final String bukkitVersion = Versioning.getBukkitVersion(); private final Logger logger = Logger.getLogger("Minecraft"); diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java -index 1345ee267a61caf97e5b4f6ee641cadb10698fb6..dfc36958e5b1a1ac82113d2d0929a17d83e4da54 100644 +index cbdcc06c03ea1a206e035a41c13242b00b5062a5..aa70c3e32b006e53b6cf2ad3d3f33008cb480a4a 100644 --- a/src/main/java/org/bukkit/craftbukkit/Main.java +++ b/src/main/java/org/bukkit/craftbukkit/Main.java -@@ -280,7 +280,7 @@ public class Main { +@@ -288,7 +288,7 @@ public class Main { if (buildDate.before(deadline.getTime())) { // Paper start - This is some stupid bullshit System.err.println("*** Warning, you've not updated in a while! ***"); @@ -68,7 +57,7 @@ index 1345ee267a61caf97e5b4f6ee641cadb10698fb6..dfc36958e5b1a1ac82113d2d0929a17d //Thread.sleep(TimeUnit.SECONDS.toMillis(20)); // Paper End diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -index 6cb8608f8238c4a8c346b92ba672c8cc1c0cbcc4..27b3f4272e287920791e3e846d108e0aed63b065 100644 +index 4674a541374cbf0594a2e79560bbfcce95675dc2..5e4f0a216919dc9e622ff2c4b9dd829cd2c71e46 100644 --- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java @@ -397,7 +397,7 @@ public final class CraftMagicNumbers implements UnsafeValues { diff --git a/patches/server/0005-Add-last-tick-time-API.patch b/patches/server/0005-Add-last-tick-time-API.patch index bf204282..686334f3 100644 --- a/patches/server/0005-Add-last-tick-time-API.patch +++ b/patches/server/0005-Add-last-tick-time-API.patch @@ -7,10 +7,10 @@ Original patch by: Co-authored-by: tr7zw diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 4ed2808434d059ad21c01449fb1ca37165061b0a..24b721a8378d57c51cb68376d76f52aea3fe2c67 100644 +index 868c5cf064fe1a47d69a9712f44b1b9ccd7ac9d7..78458b156a59b0394646550bcbde24108e9835ce 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -1065,6 +1065,8 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant list = com.tuinity.tuinity.util.CachedLists.getTempGetEntitiesList(); diff --git a/patches/server/0009-Modify-default-configs.patch b/patches/server/0009-Modify-default-configs.patch index 73e3262b..cf2857ca 100644 --- a/patches/server/0009-Modify-default-configs.patch +++ b/patches/server/0009-Modify-default-configs.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Modify default configs diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java -index 7acf077bc131af718c7548cc29deef558c04e463..2690504fa53edd3e899100957e1f9da109830057 100644 +index 10126cb1c3efa2e6c84f20c0da701a131a5dd4cb..b8cf3d6fd2cad674be936d48317874ade92a6e62 100644 --- a/src/main/java/com/destroystokyo/paper/PaperConfig.java +++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java -@@ -201,7 +201,7 @@ public class PaperConfig { +@@ -206,7 +206,7 @@ public class PaperConfig { public static String timingsServerName; private static void timings() { @@ -18,7 +18,7 @@ index 7acf077bc131af718c7548cc29deef558c04e463..2690504fa53edd3e899100957e1f9da1 TimingsManager.privacy = getBoolean("timings.server-name-privacy", false); TimingsManager.hiddenConfigs = getList("timings.hidden-config-entries", Lists.newArrayList("database", "settings.bungeecord-addresses", "settings.velocity-support.secret")); diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index fcacc08db8f5a58ddd06be7f9f2cb2cf6b2231c3..5d88bbb56e8a25ed45d8e01ad0fba81111a3b420 100644 +index 03c26e4dfb4775bfd9caa4f155bde58e83865388..f3604472ab5fdac2ff3303bb090a648248a319d9 100644 --- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java +++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java @@ -635,7 +635,7 @@ public class PaperWorldConfig { diff --git a/patches/server/0010-lithium-MixinDirection.patch b/patches/server/0010-lithium-MixinDirection.patch index 4e3debda..7dd984e9 100644 --- a/patches/server/0010-lithium-MixinDirection.patch +++ b/patches/server/0010-lithium-MixinDirection.patch @@ -7,7 +7,7 @@ Original code by JellySquid, licensed under GNU Lesser General Public License v3 you can find the original code on https://github.com/CaffeineMC/lithium-fabric/ (Yarn mappings) diff --git a/src/main/java/net/minecraft/core/EnumDirection.java b/src/main/java/net/minecraft/core/EnumDirection.java -index 0a40df2151bd388b6633a6f50b14f1f41ed4ce62..e7f56ae5214af02e5dbcf16b781032545702a0d8 100644 +index 19bc37143140b4e3a06a87297205b702548b0fa3..2cb42df0a29abc28751989dc046f83e0c28ccf79 100644 --- a/src/main/java/net/minecraft/core/EnumDirection.java +++ b/src/main/java/net/minecraft/core/EnumDirection.java @@ -24,7 +24,7 @@ public enum EnumDirection implements INamable { @@ -32,8 +32,8 @@ index 0a40df2151bd388b6633a6f50b14f1f41ed4ce62..e7f56ae5214af02e5dbcf16b78103254 + return getValues()[this.h]; } - public EnumDirection g() { -@@ -199,8 +203,12 @@ public enum EnumDirection implements INamable { + public EnumDirection rotateCW() { return g(); } // Purpur - OBFHELPER +@@ -214,8 +218,12 @@ public enum EnumDirection implements INamable { return (float) ((this.i & 3) * 90); } diff --git a/patches/server/0012-lithium-enum_values.patch b/patches/server/0012-lithium-enum_values.patch index 272b66ce..2998df43 100644 --- a/patches/server/0012-lithium-enum_values.patch +++ b/patches/server/0012-lithium-enum_values.patch @@ -65,10 +65,10 @@ index 8078e4f5b79eaada03508265ba6b81db636e822a..b2d26289a6f501b093ec229394f75864 }; diff --git a/src/main/java/net/minecraft/world/entity/EntityLiving.java b/src/main/java/net/minecraft/world/entity/EntityLiving.java -index 3541a869e85b45d9d5a0c2547357a6200836ee1e..6132c711836908569006a8993973526275c9fb7c 100644 +index fc74e217ec32c3e03c3a2c0af5372a0bbae0845e..2f84f10a3f811b415b62291b91bca7728b163f1e 100644 --- a/src/main/java/net/minecraft/world/entity/EntityLiving.java +++ b/src/main/java/net/minecraft/world/entity/EntityLiving.java -@@ -2708,10 +2708,12 @@ public abstract class EntityLiving extends Entity { +@@ -2779,10 +2779,12 @@ public abstract class EntityLiving extends Entity { } @@ -115,7 +115,7 @@ index 8aa51fb207820a7629d50b80ea821ec6cccf8b54..96ec55a705cf372ba1943710362898b7 if (enumdirection2 != EnumDirection.DOWN && world.isBlockFacePowered(blockposition1.shift(enumdirection2), enumdirection2)) { return true; diff --git a/src/main/java/net/minecraft/world/level/block/piston/PistonExtendsChecker.java b/src/main/java/net/minecraft/world/level/block/piston/PistonExtendsChecker.java -index 6c9c4ab65b7e42efa68027057242e25b70313081..da878edc6a433cfdbbc47201a668fed43543fd1c 100644 +index cbe34059659e0f80ff384508b01e516cd7c5e28a..5813075cd3f2abf53c8a8ed3fa45be89586f25ea 100644 --- a/src/main/java/net/minecraft/world/level/block/piston/PistonExtendsChecker.java +++ b/src/main/java/net/minecraft/world/level/block/piston/PistonExtendsChecker.java @@ -173,10 +173,11 @@ public class PistonExtendsChecker { diff --git a/patches/server/0014-Item-stuck-sleep-config.patch b/patches/server/0014-Item-stuck-sleep-config.patch index 427ae0c7..541cc4ed 100644 --- a/patches/server/0014-Item-stuck-sleep-config.patch +++ b/patches/server/0014-Item-stuck-sleep-config.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Item stuck sleep config diff --git a/src/main/java/net/minecraft/world/entity/item/EntityItem.java b/src/main/java/net/minecraft/world/entity/item/EntityItem.java -index cb5c4379bfd16a74debaf23f840dbf1e5535ad7f..392f51e435021352cf14554361fc6425b70d06e6 100644 +index c207cc8727ba4dc1ed8715720991db0640f63c80..9fa3b110a650796b8d36c5378ff76d2c05d9dd31 100644 --- a/src/main/java/net/minecraft/world/entity/item/EntityItem.java +++ b/src/main/java/net/minecraft/world/entity/item/EntityItem.java -@@ -114,7 +114,7 @@ public class EntityItem extends Entity { +@@ -120,7 +120,7 @@ public class EntityItem extends Entity { if (gg.airplane.AirplaneConfig.simplerItemCollision) { net.minecraft.world.level.block.state.IBlockData block = this.world.getTypeIfLoaded(this.getChunkCoordinates()); this.noclip = block != null && block.isOpaque(); diff --git a/patches/server/0015-Option-for-simpler-Villagers.patch b/patches/server/0015-Option-for-simpler-Villagers.patch index fb757333..b73d92b3 100644 --- a/patches/server/0015-Option-for-simpler-Villagers.patch +++ b/patches/server/0015-Option-for-simpler-Villagers.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Option for simpler Villagers diff --git a/src/main/java/net/minecraft/world/entity/npc/EntityVillager.java b/src/main/java/net/minecraft/world/entity/npc/EntityVillager.java -index ccb568a5e8501ac5e8901ef3a270cc87471d9ea1..d6c078f184b05662df08b074840b16481d638abc 100644 +index df29b574db306fd722d8470db4a5321230c837d5..1b7d4bff019eeddd5eff8230c751f7dda8b30516 100644 --- a/src/main/java/net/minecraft/world/entity/npc/EntityVillager.java +++ b/src/main/java/net/minecraft/world/entity/npc/EntityVillager.java -@@ -100,6 +100,7 @@ import org.bukkit.event.entity.VillagerReplenishTradeEvent; +@@ -103,6 +103,7 @@ import org.bukkit.event.entity.VillagerReplenishTradeEvent; public class EntityVillager extends EntityVillagerAbstract implements ReputationHandler, VillagerDataHolder { @@ -16,7 +16,7 @@ index ccb568a5e8501ac5e8901ef3a270cc87471d9ea1..d6c078f184b05662df08b074840b1648 private static final DataWatcherObject br = DataWatcher.a(EntityVillager.class, DataWatcherRegistry.q); public static final Map bp = ImmutableMap.of(Items.BREAD, 4, Items.POTATO, 1, Items.CARROT, 1, Items.BEETROOT, 1); private static final Set bs = ImmutableSet.of(Items.BREAD, Items.POTATO, Items.CARROT, Items.WHEAT, Items.WHEAT_SEEDS, Items.BEETROOT, new Item[]{Items.BEETROOT_SEEDS}); -@@ -135,12 +136,53 @@ public class EntityVillager extends EntityVillagerAbstract implements Reputation +@@ -139,8 +140,14 @@ public class EntityVillager extends EntityVillagerAbstract implements Reputation public EntityVillager(EntityTypes entitytypes, World world, VillagerType villagertype) { super(entitytypes, world); this.by = new Reputation(); @@ -30,11 +30,12 @@ index ccb568a5e8501ac5e8901ef3a270cc87471d9ea1..d6c078f184b05662df08b074840b1648 + // Yatopia end this.setCanPickupLoot(true); this.setVillagerData(this.getVillagerData().withType(villagertype).withProfession(VillagerProfession.NONE)); - } - -+ // Yatopia start -+ @Override -+ protected void initPathfinder() { + this.brainTickOffset = getRandom().nextInt(100); // Purpur +@@ -161,6 +168,37 @@ public class EntityVillager extends EntityVillagerAbstract implements Reputation + protected void initPathfinder() { + this.goalSelector.a(0, new PathfinderGoalHasRider(this)); // Purpur + if (world.purpurConfig.villagerFollowEmeraldBlock) this.goalSelector.a(3, new PathfinderGoalTempt(this, 1.0D, false, TEMPT_ITEMS)); ++ // Yatopia start + if (!simplerVillagerBehavior) { + return; + } @@ -64,13 +65,11 @@ index ccb568a5e8501ac5e8901ef3a270cc87471d9ea1..d6c078f184b05662df08b074840b1648 + this.goalSelector.a(8, new net.minecraft.world.entity.ai.goal.PathfinderGoalRandomStrollLand(this, 0.35D)); + this.goalSelector.a(9, new net.minecraft.world.entity.ai.goal.PathfinderGoalInteract(this, EntityHuman.class, 3.0F, 1.0F)); + this.goalSelector.a(10, new net.minecraft.world.entity.ai.goal.PathfinderGoalLookAtPlayer(this, EntityInsentient.class, 8.0F)); -+ } -+ // Yatopia end -+ ++ // Yatopia end + } + @Override - public BehaviorController getBehaviorController() { - return (BehaviorController) super.getBehaviorController(); // CraftBukkit - decompile error -@@ -153,6 +195,7 @@ public class EntityVillager extends EntityVillagerAbstract implements Reputation +@@ -186,6 +224,7 @@ public class EntityVillager extends EntityVillagerAbstract implements Reputation @Override protected BehaviorController a(Dynamic dynamic) { @@ -78,7 +77,7 @@ index ccb568a5e8501ac5e8901ef3a270cc87471d9ea1..d6c078f184b05662df08b074840b1648 BehaviorController behaviorcontroller = this.cK().a(dynamic); this.a(behaviorcontroller); -@@ -232,11 +275,39 @@ public class EntityVillager extends EntityVillagerAbstract implements Reputation +@@ -265,6 +304,27 @@ public class EntityVillager extends EntityVillagerAbstract implements Reputation // Spigot End private int behaviorTick = 0; @@ -104,7 +103,9 @@ index ccb568a5e8501ac5e8901ef3a270cc87471d9ea1..d6c078f184b05662df08b074840b1648 + } + // Yatopia end - @Override + // Purpur start + boolean lobotomized = false; +@@ -290,6 +350,14 @@ public class EntityVillager extends EntityVillagerAbstract implements Reputation protected void mobTick() { mobTick(false); } protected void mobTick(boolean inactive) { this.world.getMethodProfiler().enter("villagerBrain"); @@ -115,10 +116,11 @@ index ccb568a5e8501ac5e8901ef3a270cc87471d9ea1..d6c078f184b05662df08b074840b1648 + if (simplerVillagerBehavior && canRefresh()) restUses(); + if (simplerVillagerBehavior) return; + // Yatopia end - if (!inactive) { - if (!gg.airplane.AirplaneConfig.dynamicVillagerBehavior || behaviorTick++ % this.activatedPriority == 0) { - this.getBehaviorController().a((WorldServer) this.world, this); // CraftBukkit - decompile error // Paper -@@ -356,6 +427,7 @@ public class EntityVillager extends EntityVillagerAbstract implements Reputation ++ + // Purpur start + if (world.purpurConfig.villagerLobotomizeEnabled) inactive = inactive || isLobotomized(); + boolean tick = (world.getTime() + brainTickOffset) % world.purpurConfig.villagerBrainTicks == 0; +@@ -418,6 +486,7 @@ public class EntityVillager extends EntityVillagerAbstract implements Reputation this.fl(); } @@ -126,7 +128,7 @@ index ccb568a5e8501ac5e8901ef3a270cc87471d9ea1..d6c078f184b05662df08b074840b1648 private void fl() { Iterator iterator = this.getOffers().iterator(); -@@ -428,6 +500,7 @@ public class EntityVillager extends EntityVillagerAbstract implements Reputation +@@ -492,6 +561,7 @@ public class EntityVillager extends EntityVillagerAbstract implements Reputation return this.fn() && this.fm(); } @@ -134,7 +136,7 @@ index ccb568a5e8501ac5e8901ef3a270cc87471d9ea1..d6c078f184b05662df08b074840b1648 private void fo() { int i = 2 - this.bD; -@@ -660,6 +733,7 @@ public class EntityVillager extends EntityVillagerAbstract implements Reputation +@@ -724,6 +794,7 @@ public class EntityVillager extends EntityVillagerAbstract implements Reputation } private void a(Entity entity) { @@ -142,7 +144,7 @@ index ccb568a5e8501ac5e8901ef3a270cc87471d9ea1..d6c078f184b05662df08b074840b1648 if (this.world instanceof WorldServer) { Optional> optional = this.bg.getMemory(MemoryModuleType.VISIBLE_MOBS); -@@ -676,6 +750,7 @@ public class EntityVillager extends EntityVillagerAbstract implements Reputation +@@ -740,6 +811,7 @@ public class EntityVillager extends EntityVillagerAbstract implements Reputation } public void a(MemoryModuleType memorymoduletype) { diff --git a/patches/server/0016-Heavily-optimize-furnance-fuel-and-recipe-lookups.patch b/patches/server/0016-Heavily-optimize-furnance-fuel-and-recipe-lookups.patch index 3c2bcefe..9e9e041f 100644 --- a/patches/server/0016-Heavily-optimize-furnance-fuel-and-recipe-lookups.patch +++ b/patches/server/0016-Heavily-optimize-furnance-fuel-and-recipe-lookups.patch @@ -6,10 +6,10 @@ Subject: [PATCH] Heavily optimize furnance fuel and recipe lookups Co-authored-by: Mykyta Komarn diff --git a/src/main/java/net/minecraft/world/level/block/entity/TileEntityFurnace.java b/src/main/java/net/minecraft/world/level/block/entity/TileEntityFurnace.java -index 9ce19b89c16eb6edd3d5d5cc87a966a37f66895c..20193ba36c62fdd40ae905d1cea4bfd6d6aebcd7 100644 +index ac42fd627009a87709448354f232d8b5ed7fa6b9..8ec9ed518a3b5f70c5a5d74605a1f17d0f47b300 100644 --- a/src/main/java/net/minecraft/world/level/block/entity/TileEntityFurnace.java +++ b/src/main/java/net/minecraft/world/level/block/entity/TileEntityFurnace.java -@@ -313,7 +313,10 @@ public abstract class TileEntityFurnace extends TileEntityContainer implements I +@@ -331,7 +331,10 @@ public abstract class TileEntityFurnace extends TileEntityContainer implements I this.cookTime = MathHelper.clamp(this.cookTime - 2, 0, this.cookTimeTotal); } } else { @@ -21,7 +21,7 @@ index 9ce19b89c16eb6edd3d5d5cc87a966a37f66895c..20193ba36c62fdd40ae905d1cea4bfd6 if (!this.isBurning() && this.canBurn(irecipe)) { // CraftBukkit start -@@ -643,4 +646,18 @@ public abstract class TileEntityFurnace extends TileEntityContainer implements I +@@ -663,4 +666,18 @@ public abstract class TileEntityFurnace extends TileEntityContainer implements I } } diff --git a/patches/server/0017-Optimize-TileEntity-load-unload.patch b/patches/server/0017-Optimize-TileEntity-load-unload.patch index 9063abbb..47882aaa 100644 --- a/patches/server/0017-Optimize-TileEntity-load-unload.patch +++ b/patches/server/0017-Optimize-TileEntity-load-unload.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Optimize TileEntity load/unload diff --git a/src/main/java/net/minecraft/world/level/World.java b/src/main/java/net/minecraft/world/level/World.java -index 1583c8608a34a84b84873dd10668d6a5f67ab416..b6e11ea50e7bca0c5a7109a8715c0ede15e61e44 100644 +index 8de35f1acf057218e8debcfa4fee66f8cc3ddc2a..801406353fe9cbacea84ec11ca98fe1ef4479a6a 100644 --- a/src/main/java/net/minecraft/world/level/World.java +++ b/src/main/java/net/minecraft/world/level/World.java -@@ -105,8 +105,8 @@ public abstract class World implements GeneratorAccess, AutoCloseable { +@@ -106,8 +106,8 @@ public abstract class World implements GeneratorAccess, AutoCloseable { public static final ResourceKey THE_END = ResourceKey.a(IRegistry.L, new MinecraftKey("the_end")); private static final EnumDirection[] a = EnumDirection.values(); //public final List tileEntityList = Lists.newArrayList(); // Paper - remove unused list diff --git a/patches/server/0019-Redirect-Configs.patch b/patches/server/0019-Redirect-Configs.patch index 22bdb977..f348a213 100644 --- a/patches/server/0019-Redirect-Configs.patch +++ b/patches/server/0019-Redirect-Configs.patch @@ -39,10 +39,10 @@ index a088b8f84f01ce3863ae949f4cd3d7ae9589c27c..4ff5d3d45c1055af148e34d6bfe645a6 for (final Method method : clazz.getDeclaredMethods()) { if (method.getReturnType() != void.class || method.getParameterCount() != 0 || diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -index 87622c770963b1675f4c36f355a3707e0f92727a..70d07a7e1881d02f6d92ea65bcf9bd5a157fb2cf 100644 +index 99efc53a2aca602175ae5ba56f63d689e021f410..158a8f1426c6e7d148a65a4c0805782162726410 100644 --- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java +++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -@@ -227,7 +227,7 @@ public class DedicatedServer extends MinecraftServer implements IMinecraftServer +@@ -236,7 +236,7 @@ public class DedicatedServer extends MinecraftServer implements IMinecraftServer return false; } // Yatopia end @@ -52,10 +52,10 @@ index 87622c770963b1675f4c36f355a3707e0f92727a..70d07a7e1881d02f6d92ea65bcf9bd5a this.setAllowFlight(dedicatedserverproperties.allowFlight); this.setResourcePack(dedicatedserverproperties.resourcePack, this.ba()); diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java -index 0d326b2f27b5191caeecd5fc89fa8498c426885a..a23b0fb8df7418cf60257a7458f56c4dbcb8f7eb 100644 +index e84cfcc65d1b4eab443c7c499289d234ce71b407..51c59ea751902836614faa7ac6ec9e5ed5e7ae38 100644 --- a/src/main/java/org/bukkit/craftbukkit/Main.java +++ b/src/main/java/org/bukkit/craftbukkit/Main.java -@@ -308,7 +308,7 @@ public class Main { +@@ -316,7 +316,7 @@ public class Main { } // Paper end System.setProperty( "library.jansi.version", "Paper" ); // Paper - set meaningless jansi version to prevent git builds from crashing on Windows diff --git a/patches/server/0021-Fix-lead-fall-dmg-config.patch b/patches/server/0021-Fix-lead-fall-dmg-config.patch index ed92f9ec..5b7e1f3f 100644 --- a/patches/server/0021-Fix-lead-fall-dmg-config.patch +++ b/patches/server/0021-Fix-lead-fall-dmg-config.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Fix lead fall dmg config diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 32372e46103958e985582796964a47120ec9c1a3..b742f457d72eee4f00f5df7a2b5b3cfdeb917a86 100644 +index 39677ae033fff7d80eb4e250855cef9fee71b951..a83e0fd5fc895bf1b27c5d12ccd7616eff6773c0 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -1451,6 +1451,8 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, ne +@@ -1457,6 +1457,8 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, ne this.fallDistance = 0.0F; } else if (d0 < 0.0D) { this.fallDistance = (float) ((double) this.fallDistance - d0); diff --git a/patches/server/0022-Optimize-some-stuff-in-WorldServer-ticking.patch b/patches/server/0022-Optimize-some-stuff-in-WorldServer-ticking.patch index f299e2c9..738f400b 100644 --- a/patches/server/0022-Optimize-some-stuff-in-WorldServer-ticking.patch +++ b/patches/server/0022-Optimize-some-stuff-in-WorldServer-ticking.patch @@ -6,10 +6,10 @@ Subject: [PATCH] Optimize some stuff in WorldServer ticking Replaced some streams and some array lists with glue lists diff --git a/src/main/java/net/minecraft/server/level/WorldServer.java b/src/main/java/net/minecraft/server/level/WorldServer.java -index 1553be4263f08ae21447ccf2e19e8a30a2932208..671662c90366351b1bd364a6e29e5a4fe6c19b10 100644 +index 0ec132efc49880d9b230e176bce79732b7231765..bbf7f14edb6e11256aaf6693074ff82dbc333e15 100644 --- a/src/main/java/net/minecraft/server/level/WorldServer.java +++ b/src/main/java/net/minecraft/server/level/WorldServer.java -@@ -996,12 +996,21 @@ public class WorldServer extends World implements GeneratorAccessSeed { +@@ -1024,12 +1024,21 @@ public class WorldServer extends World implements GeneratorAccessSeed { this.server.getPlayerList().sendAll(new PacketPlayOutGameStateChange(PacketPlayOutGameStateChange.i, this.thunderLevel)); } // */ @@ -34,21 +34,21 @@ index 1553be4263f08ae21447ccf2e19e8a30a2932208..671662c90366351b1bd364a6e29e5a4f if (flag != this.isRaining()) { // Only send weather packets to those affected for (int idx = 0; idx < this.players.size(); ++idx) { -@@ -1016,11 +1025,9 @@ public class WorldServer extends World implements GeneratorAccessSeed { +@@ -1044,11 +1053,9 @@ public class WorldServer extends World implements GeneratorAccessSeed { } } // CraftBukkit end + */ // Yatopia end -- if (this.everyoneSleeping && this.players.stream().noneMatch((entityplayer) -> { -- return !entityplayer.isSpectator() && !entityplayer.isDeeplySleeping() && !entityplayer.fauxSleeping; // CraftBukkit +- if (this.purpurConfig.playersSkipNight && this.everyoneSleeping && this.players.stream().noneMatch((entityplayer) -> { // Purpur +- return !entityplayer.isSpectator() && !entityplayer.isDeeplySleeping() && !entityplayer.fauxSleeping && !(purpurConfig.idleTimeoutCountAsSleeping && entityplayer.isAfk()); // CraftBukkit // Purpur - })) { - // CraftBukkit start -+ if (this.everyoneSleeping && sleepyMatch) { // Purpur // Yatopia ++ if (this.purpurConfig.playersSkipNight && this.everyoneSleeping && sleepyMatch) { // Purpur // Yatopia long l = this.worldData.getDayTime() + 24000L; TimeSkipEvent event = new TimeSkipEvent(this.getWorld(), TimeSkipEvent.SkipReason.NIGHT_SKIP, (l - l % 24000L) - this.getDayTime()); if (this.getGameRules().getBoolean(GameRules.DO_DAYLIGHT_CYCLE)) { -@@ -1226,9 +1233,9 @@ public class WorldServer extends World implements GeneratorAccessSeed { +@@ -1274,9 +1281,9 @@ public class WorldServer extends World implements GeneratorAccessSeed { } private void wakeupPlayers() { @@ -60,7 +60,7 @@ index 1553be4263f08ae21447ccf2e19e8a30a2932208..671662c90366351b1bd364a6e29e5a4f } // Paper start - optimise random block ticking -@@ -2055,8 +2062,9 @@ public class WorldServer extends World implements GeneratorAccessSeed { +@@ -2109,8 +2116,9 @@ public class WorldServer extends World implements GeneratorAccessSeed { // Spigot start if ( entity instanceof EntityHuman ) { @@ -71,7 +71,7 @@ index 1553be4263f08ae21447ccf2e19e8a30a2932208..671662c90366351b1bd364a6e29e5a4f for (Object o : worldData.data.values() ) { if ( o instanceof WorldMap ) -@@ -2073,7 +2081,7 @@ public class WorldServer extends World implements GeneratorAccessSeed { +@@ -2127,7 +2135,7 @@ public class WorldServer extends World implements GeneratorAccessSeed { } } } diff --git a/patches/server/0024-Add-timings-for-Pathfinder.patch b/patches/server/0024-Add-timings-for-Pathfinder.patch index acf5a5bc..b91874da 100644 --- a/patches/server/0024-Add-timings-for-Pathfinder.patch +++ b/patches/server/0024-Add-timings-for-Pathfinder.patch @@ -18,7 +18,7 @@ index 67980e1dc186c0b458eca9f00acfea7d2b26d575..e5df5045c7fb9faf692fed894e1a64fe * Gets a timer associated with a plugins tasks. * @param bukkitTask diff --git a/src/main/java/net/minecraft/world/entity/ai/navigation/NavigationAbstract.java b/src/main/java/net/minecraft/world/entity/ai/navigation/NavigationAbstract.java -index 48e6a4c588ef39a4bde067d79b96a656c68750ce..f528968fe6c719fa7fa273355f083ad2142f4b93 100644 +index ac7bad10697c6fde7d512753992d59710aa1e032..0c8f3e424a631aca98f83f570aff91c833aaf4b9 100644 --- a/src/main/java/net/minecraft/world/entity/ai/navigation/NavigationAbstract.java +++ b/src/main/java/net/minecraft/world/entity/ai/navigation/NavigationAbstract.java @@ -51,6 +51,7 @@ public abstract class NavigationAbstract { @@ -37,7 +37,7 @@ index 48e6a4c588ef39a4bde067d79b96a656c68750ce..f528968fe6c719fa7fa273355f083ad2 } public void g() { -@@ -252,6 +254,10 @@ public abstract class NavigationAbstract { +@@ -253,6 +255,10 @@ public abstract class NavigationAbstract { } public void c() { @@ -48,7 +48,7 @@ index 48e6a4c588ef39a4bde067d79b96a656c68750ce..f528968fe6c719fa7fa273355f083ad2 ++this.e; if (this.m) { this.j(); -@@ -279,6 +285,11 @@ public abstract class NavigationAbstract { +@@ -280,6 +286,11 @@ public abstract class NavigationAbstract { this.a.getControllerMove().a(vec3d.x, this.b.getType(blockposition.down()).isAir() ? vec3d.y : PathfinderNormal.a((IBlockAccess) this.b, blockposition), vec3d.z, this.d); } } diff --git a/patches/server/0025-Highly-optimize-VillagePlace-filtering.patch b/patches/server/0025-Highly-optimize-VillagePlace-filtering.patch index c6bde25c..b3874421 100644 --- a/patches/server/0025-Highly-optimize-VillagePlace-filtering.patch +++ b/patches/server/0025-Highly-optimize-VillagePlace-filtering.patch @@ -67,10 +67,10 @@ index 0000000000000000000000000000000000000000..e647624f4c9afe8bc603792ad88c807e + } +} diff --git a/src/main/java/net/minecraft/core/BlockPosition.java b/src/main/java/net/minecraft/core/BlockPosition.java -index 2685a395a2eff9083cd8c654c4b7e2141b0ca99b..902cdf1b2ba56534d80ce270a84b8d3ab0b026dc 100644 +index c2706c752f6ff5c131b6db469ae85dd703d5d381..09978014fcb1a3cb46248fb6a035725c08d70a4a 100644 --- a/src/main/java/net/minecraft/core/BlockPosition.java +++ b/src/main/java/net/minecraft/core/BlockPosition.java -@@ -341,6 +341,16 @@ public class BlockPosition extends BaseBlockPosition { +@@ -347,6 +347,16 @@ public class BlockPosition extends BaseBlockPosition { return a(MathHelper.floor(axisalignedbb.minX), MathHelper.floor(axisalignedbb.minY), MathHelper.floor(axisalignedbb.minZ), MathHelper.floor(axisalignedbb.maxX), MathHelper.floor(axisalignedbb.maxY), MathHelper.floor(axisalignedbb.maxZ)); } @@ -132,19 +132,19 @@ index 427413c668865e1660f1d81daf6a3385f08a0e38..a206a729b3afa01bf591fa4da1e5c149 return StreamSupport.stream(new AbstractSpliterator((long) ((l - i + 1) * (i1 - j + 1) * (j1 - k + 1)), 64) { final CursorPosition a = new CursorPosition(i, j, k, l, i1, j1); diff --git a/src/main/java/net/minecraft/world/entity/ai/village/poi/VillagePlace.java b/src/main/java/net/minecraft/world/entity/ai/village/poi/VillagePlace.java -index 13d94ecd703b3cd0412e138532d2dd74e5bf250d..2fa0a60857039fde85e648e7a190800a8a9c92e7 100644 +index 6082eed2d28f3be65daa7e7eb6f2c2a89bb28ff1..29cd71efe86eea2227f373c15c39dc530e9e8199 100644 --- a/src/main/java/net/minecraft/world/entity/ai/village/poi/VillagePlace.java +++ b/src/main/java/net/minecraft/world/entity/ai/village/poi/VillagePlace.java -@@ -192,7 +192,7 @@ public class VillagePlace extends RegionFileSection { - } +@@ -193,7 +193,7 @@ public class VillagePlace extends RegionFileSection { + public long count(Predicate predicate, BlockPosition blockposition, int i, VillagePlace.Occupancy villageplace_occupancy) { return a(predicate, blockposition, i, villageplace_occupancy); } // Purpur - OBFHELPER public long a(Predicate predicate, BlockPosition blockposition, int i, VillagePlace.Occupancy villageplace_occupancy) { - return this.c(predicate, blockposition, i, villageplace_occupancy).count(); + return this.cList(predicate, blockposition, i, villageplace_occupancy).size(); // Yatopia } public boolean a(VillagePlaceType villageplacetype, BlockPosition blockposition) { -@@ -213,6 +213,39 @@ public class VillagePlace extends RegionFileSection { +@@ -214,6 +214,39 @@ public class VillagePlace extends RegionFileSection { }); } @@ -184,7 +184,7 @@ index 13d94ecd703b3cd0412e138532d2dd74e5bf250d..2fa0a60857039fde85e648e7a190800a public Stream c(Predicate predicate, BlockPosition blockposition, int i, VillagePlace.Occupancy villageplace_occupancy) { int j = i * i; -@@ -229,10 +262,28 @@ public class VillagePlace extends RegionFileSection { +@@ -230,10 +263,28 @@ public class VillagePlace extends RegionFileSection { }); } @@ -213,7 +213,7 @@ index 13d94ecd703b3cd0412e138532d2dd74e5bf250d..2fa0a60857039fde85e648e7a190800a public Stream b(Predicate predicate, Predicate predicate1, BlockPosition blockposition, int i, VillagePlace.Occupancy villageplace_occupancy) { return this.a(predicate, predicate1, blockposition, i, villageplace_occupancy).sorted(Comparator.comparingDouble((blockposition1) -> { return blockposition1.j(blockposition); -@@ -380,7 +431,7 @@ public class VillagePlace extends RegionFileSection { +@@ -381,7 +432,7 @@ public class VillagePlace extends RegionFileSection { } private void a(ChunkSection chunksection, SectionPosition sectionposition, BiConsumer biconsumer) { @@ -222,7 +222,7 @@ index 13d94ecd703b3cd0412e138532d2dd74e5bf250d..2fa0a60857039fde85e648e7a190800a IBlockData iblockdata = chunksection.getType(SectionPosition.b(blockposition.getX()), SectionPosition.b(blockposition.getY()), SectionPosition.b(blockposition.getZ())); VillagePlaceType.b(iblockdata).ifPresent((villageplacetype) -> { -@@ -390,6 +441,16 @@ public class VillagePlace extends RegionFileSection { +@@ -391,6 +442,16 @@ public class VillagePlace extends RegionFileSection { } public void a(IWorldReader iworldreader, BlockPosition blockposition, int i) { @@ -239,7 +239,7 @@ index 13d94ecd703b3cd0412e138532d2dd74e5bf250d..2fa0a60857039fde85e648e7a190800a SectionPosition.b(new ChunkCoordIntPair(blockposition), Math.floorDiv(i, 16)).map((sectionposition) -> { return Pair.of(sectionposition, this.d(sectionposition.s())); }).filter((pair) -> { -@@ -401,6 +462,7 @@ public class VillagePlace extends RegionFileSection { +@@ -402,6 +463,7 @@ public class VillagePlace extends RegionFileSection { }).forEach((chunkcoordintpair) -> { iworldreader.getChunkAt(chunkcoordintpair.x, chunkcoordintpair.z, ChunkStatus.EMPTY); }); @@ -297,10 +297,10 @@ index 41ffad7cbb6c77713736f37b3728b201d315f6d4..866e9a434423702d2edaf9b52fa0e621 return true; } diff --git a/src/main/java/net/minecraft/world/entity/animal/EntityBee.java b/src/main/java/net/minecraft/world/entity/animal/EntityBee.java -index 1d1f71a995a99b2101891a7a5bda7bec5d67f118..c778a735c7653be13af956f9829eb88d21518ce6 100644 +index 4da4fadbd4a036b316d554de20c0d30d35cc206b..4fb72f73ef4a1131ad91b3edea78a79169202720 100644 --- a/src/main/java/net/minecraft/world/entity/animal/EntityBee.java +++ b/src/main/java/net/minecraft/world/entity/animal/EntityBee.java -@@ -794,15 +794,19 @@ public class EntityBee extends EntityAnimal implements IEntityAngerable, EntityB +@@ -856,15 +856,19 @@ public class EntityBee extends EntityAnimal implements IEntityAngerable, EntityB private List j() { BlockPosition blockposition = EntityBee.this.getChunkCoordinates(); VillagePlace villageplace = ((WorldServer) EntityBee.this.world).y(); @@ -324,10 +324,10 @@ index 1d1f71a995a99b2101891a7a5bda7bec5d67f118..c778a735c7653be13af956f9829eb88d } diff --git a/src/main/java/net/minecraft/world/entity/raid/PersistentRaid.java b/src/main/java/net/minecraft/world/entity/raid/PersistentRaid.java -index c939ca087af4588e14669a2d53d7c116dcb59f16..d5113b5c555157d00c845a3735258490d1471476 100644 +index 11271762dcf5783c3179de1afc6a882c5330b4dd..a0321663a1cb410505e2b57397c6d0020433e6e1 100644 --- a/src/main/java/net/minecraft/world/entity/raid/PersistentRaid.java +++ b/src/main/java/net/minecraft/world/entity/raid/PersistentRaid.java -@@ -86,7 +86,7 @@ public class PersistentRaid extends PersistentBase { +@@ -98,7 +98,7 @@ public class PersistentRaid extends PersistentBase { return null; } else { BlockPosition blockposition = entityplayer.getChunkCoordinates(); diff --git a/patches/server/0026-Nuke-streams-off-BlockPosition.patch b/patches/server/0026-Nuke-streams-off-BlockPosition.patch index 471d950a..b0be2972 100644 --- a/patches/server/0026-Nuke-streams-off-BlockPosition.patch +++ b/patches/server/0026-Nuke-streams-off-BlockPosition.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Nuke streams off BlockPosition diff --git a/src/main/java/net/minecraft/core/BlockPosition.java b/src/main/java/net/minecraft/core/BlockPosition.java -index 902cdf1b2ba56534d80ce270a84b8d3ab0b026dc..84e753804f58cbbe1b3b30aa1fe1fecd739a1551 100644 +index 09978014fcb1a3cb46248fb6a035725c08d70a4a..8cb42aa7fede543ea33d2ff945ad75df26b37f4e 100644 --- a/src/main/java/net/minecraft/core/BlockPosition.java +++ b/src/main/java/net/minecraft/core/BlockPosition.java -@@ -318,7 +318,15 @@ public class BlockPosition extends BaseBlockPosition { +@@ -324,7 +324,15 @@ public class BlockPosition extends BaseBlockPosition { } public static Optional a(BlockPosition blockposition, int i, int j, Predicate predicate) { @@ -26,10 +26,10 @@ index 902cdf1b2ba56534d80ce270a84b8d3ab0b026dc..84e753804f58cbbe1b3b30aa1fe1fecd public static Stream b(BlockPosition blockposition, int i, int j, int k) { diff --git a/src/main/java/net/minecraft/world/level/block/state/BlockBase.java b/src/main/java/net/minecraft/world/level/block/state/BlockBase.java -index 9465bce44f5ac4b448736d9c029ea411c27843ac..59dcb83f04bebb4f3b28b5e0e01da5fb7f03be34 100644 +index d894e7f16d232596ec308f3de3ea5da410588cbe..81cf123cf445716ecaa8496b56b763cb4ae02d68 100644 --- a/src/main/java/net/minecraft/world/level/block/state/BlockBase.java +++ b/src/main/java/net/minecraft/world/level/block/state/BlockBase.java -@@ -732,6 +732,7 @@ public abstract class BlockBase { +@@ -735,6 +735,7 @@ public abstract class BlockBase { return this.getBlock().getInventory(this.p(), world, blockposition); } diff --git a/patches/server/0028-Stop-wasting-resources-on-JsonList-get.patch b/patches/server/0028-Stop-wasting-resources-on-JsonList-get.patch index 533e979f..b9891d5a 100644 --- a/patches/server/0028-Stop-wasting-resources-on-JsonList-get.patch +++ b/patches/server/0028-Stop-wasting-resources-on-JsonList-get.patch @@ -55,10 +55,10 @@ index c960852dc60d0598012c5eef0d139fe38bde63fb..96fbb1a3d216302aa937e07bf88fdb19 Throwable throwable = null; diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index b10b1960260d89b5e5c7b960f5bc18ecc9f09d99..3e89b266240c32e36a7b2eb49fb87fcd8b3659e5 100644 +index 36d53df60dfad980119eefa4499f4cb7280f55b1..bc3adc076870cc7cfb61ac1fa9e4c939b714ef57 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -738,6 +738,7 @@ public abstract class PlayerList { +@@ -740,6 +740,7 @@ public abstract class PlayerList { GameProfileBanEntry gameprofilebanentry; if (getProfileBans().isBanned(gameprofile) && (gameprofilebanentry = getProfileBans().get(gameprofile)) != null) { // Paper end @@ -66,7 +66,7 @@ index b10b1960260d89b5e5c7b960f5bc18ecc9f09d99..3e89b266240c32e36a7b2eb49fb87fcd chatmessage = new ChatMessage("multiplayer.disconnect.banned.reason", new Object[]{gameprofilebanentry.getReason()}); if (gameprofilebanentry.getExpires() != null) { -@@ -745,7 +746,11 @@ public abstract class PlayerList { +@@ -747,7 +748,11 @@ public abstract class PlayerList { } // return chatmessage; diff --git a/patches/server/0029-Fix-LightEngineThreaded-memory-leak.patch b/patches/server/0029-Fix-LightEngineThreaded-memory-leak.patch index e40725af..c982ca98 100644 --- a/patches/server/0029-Fix-LightEngineThreaded-memory-leak.patch +++ b/patches/server/0029-Fix-LightEngineThreaded-memory-leak.patch @@ -18,10 +18,10 @@ index 76ac408021c5124fd634682cba97dc63392642f5..b8f8fe2ed501efdccc0398fdf9923191 return this.size == 0 && this.pendingTasks.isEmpty(); } diff --git a/src/main/java/net/minecraft/server/level/WorldServer.java b/src/main/java/net/minecraft/server/level/WorldServer.java -index 671662c90366351b1bd364a6e29e5a4fe6c19b10..13b00ae4e2a9fd2714b9bfd6ca9015f27b492399 100644 +index bbf7f14edb6e11256aaf6693074ff82dbc333e15..f78cb4d6ec1ae77f01bad4b2339b955fa5014263 100644 --- a/src/main/java/net/minecraft/server/level/WorldServer.java +++ b/src/main/java/net/minecraft/server/level/WorldServer.java -@@ -2041,6 +2041,7 @@ public class WorldServer extends World implements GeneratorAccessSeed { +@@ -2095,6 +2095,7 @@ public class WorldServer extends World implements GeneratorAccessSeed { } // Paper end diff --git a/patches/server/0031-Optimize-Villagers.patch b/patches/server/0031-Optimize-Villagers.patch index fee7a0a5..319d32cb 100644 --- a/patches/server/0031-Optimize-Villagers.patch +++ b/patches/server/0031-Optimize-Villagers.patch @@ -69,7 +69,7 @@ index 09133c5822bc1386bc3d8a5f3c94196420bbfaea..5397a74e244e9cd6886068e0dfe283ec } } diff --git a/src/main/java/net/minecraft/world/entity/ai/village/poi/VillagePlaceType.java b/src/main/java/net/minecraft/world/entity/ai/village/poi/VillagePlaceType.java -index db1ddce5774754891dc8a3ea5b66951ebc3a07a8..05dd193c47d88223e4ca9c4dffaff3cbd1b31132 100644 +index 6a45ab049a4beeeaf7b3b5acf2946767f6e1198f..4af526ecbed506161cb021ea320b0f21112d7bf0 100644 --- a/src/main/java/net/minecraft/world/entity/ai/village/poi/VillagePlaceType.java +++ b/src/main/java/net/minecraft/world/entity/ai/village/poi/VillagePlaceType.java @@ -23,11 +23,20 @@ import net.minecraft.world.level.block.state.properties.BlockPropertyBedPart; @@ -95,7 +95,7 @@ index db1ddce5774754891dc8a3ea5b66951ebc3a07a8..05dd193c47d88223e4ca9c4dffaff3cb public static final Predicate b = (villageplacetype) -> { return true; diff --git a/src/main/java/net/minecraft/world/entity/npc/VillagerProfession.java b/src/main/java/net/minecraft/world/entity/npc/VillagerProfession.java -index 69de7588eebba7557cdaec129f19ec1fc2c675c5..24d0c97ed06ed52a4adc50db11fd47ec0536e08b 100644 +index dd9b678481620856fb7eaaa04c3b812c861e892a..d8fc1795b07945b41bd7368529db92fe5cdc4c19 100644 --- a/src/main/java/net/minecraft/world/entity/npc/VillagerProfession.java +++ b/src/main/java/net/minecraft/world/entity/npc/VillagerProfession.java @@ -44,6 +44,7 @@ public class VillagerProfession { diff --git a/patches/server/0032-Optimize-whitelist-command-for-multiple-additions-re.patch b/patches/server/0032-Optimize-whitelist-command-for-multiple-additions-re.patch index 270e5424..af8e983a 100644 --- a/patches/server/0032-Optimize-whitelist-command-for-multiple-additions-re.patch +++ b/patches/server/0032-Optimize-whitelist-command-for-multiple-additions-re.patch @@ -10,10 +10,10 @@ added. These changes aim to reduce that load whenever you are using the /whitelist command. diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 24b721a8378d57c51cb68376d76f52aea3fe2c67..e026ec3920936223864538974151ae53a393e86f 100644 +index 78458b156a59b0394646550bcbde24108e9835ce..4a2ccb7a25fd3377627b7e68588fced89c923405 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -2106,6 +2106,7 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant Co-authored-by: ishland diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java -index 366ceb65d40c685117d1c79a933864ab91d8aa11..d82347b7bb90abcdeefd4725a5e3ac860bfa2b7a 100644 +index 81ceeff37f7e03eead177cbd49f79a74be3aeeb2..3bda167c4436a4f926850b2f3c06d1a0dce7c171 100644 --- a/src/main/java/net/minecraft/world/item/ItemStack.java +++ b/src/main/java/net/minecraft/world/item/ItemStack.java -@@ -625,6 +625,7 @@ public final class ItemStack { +@@ -640,6 +640,7 @@ public final class ItemStack { return !this.e() ? this.doMaterialsMatch(itemstack) : !itemstack.isEmpty() && this.getItem() == itemstack.getItem(); } diff --git a/patches/server/0040-Optimize-advancement-loading.patch b/patches/server/0040-Optimize-advancement-loading.patch index eddb49a9..5bc35fc5 100644 --- a/patches/server/0040-Optimize-advancement-loading.patch +++ b/patches/server/0040-Optimize-advancement-loading.patch @@ -6,7 +6,7 @@ Subject: [PATCH] Optimize advancement loading Removed some object allocations and reduced loops diff --git a/src/main/java/net/minecraft/advancements/Advancement.java b/src/main/java/net/minecraft/advancements/Advancement.java -index 2f3d9e5b849093027d3c2ef434494cd600f52a31..67e6e802191acdc9f7289edc333f3b0e5626b5ae 100644 +index 23567430901284ab9d4d4873e53a1c8a06da6862..33771338bbf7e409da7210dc096c63b74a2d215f 100644 --- a/src/main/java/net/minecraft/advancements/Advancement.java +++ b/src/main/java/net/minecraft/advancements/Advancement.java @@ -82,6 +82,7 @@ public class Advancement { @@ -18,7 +18,7 @@ index 2f3d9e5b849093027d3c2ef434494cd600f52a31..67e6e802191acdc9f7289edc333f3b0e return this.rewards; } diff --git a/src/main/java/net/minecraft/server/AdvancementDataPlayer.java b/src/main/java/net/minecraft/server/AdvancementDataPlayer.java -index dfdbc028f68ced197ad179248ed3b1e9d70ba057..7702ffa40c538d1c9ebcdd925a2c7a295bab9acf 100644 +index 4720644ae82f76f835f14c0b3a00e7b7874fb1e2..9d1879e2fd502c939b9f5caeab8a47ed9ced90d8 100644 --- a/src/main/java/net/minecraft/server/AdvancementDataPlayer.java +++ b/src/main/java/net/minecraft/server/AdvancementDataPlayer.java @@ -180,11 +180,16 @@ public class AdvancementDataPlayer { @@ -38,7 +38,7 @@ index dfdbc028f68ced197ad179248ed3b1e9d70ba057..7702ffa40c538d1c9ebcdd925a2c7a29 Advancement advancement = advancementdataworld.a((MinecraftKey) entry.getKey()); if (advancement == null) { -@@ -221,11 +226,37 @@ public class AdvancementDataPlayer { +@@ -222,11 +227,37 @@ public class AdvancementDataPlayer { } } @@ -76,7 +76,7 @@ index dfdbc028f68ced197ad179248ed3b1e9d70ba057..7702ffa40c538d1c9ebcdd925a2c7a29 public void b() { if (org.spigotmc.SpigotConfig.disableAdvancementSaving) return; // Spigot Map map = Maps.newHashMap(); -@@ -358,6 +389,11 @@ public class AdvancementDataPlayer { +@@ -365,6 +396,11 @@ public class AdvancementDataPlayer { AdvancementProgress advancementprogress = this.getProgress(advancement); if (!advancementprogress.isDone()) { @@ -88,7 +88,7 @@ index dfdbc028f68ced197ad179248ed3b1e9d70ba057..7702ffa40c538d1c9ebcdd925a2c7a29 Iterator iterator = advancement.getCriteria().entrySet().iterator(); while (iterator.hasNext()) { -@@ -377,7 +413,7 @@ public class AdvancementDataPlayer { +@@ -384,7 +420,7 @@ public class AdvancementDataPlayer { } } @@ -97,7 +97,7 @@ index dfdbc028f68ced197ad179248ed3b1e9d70ba057..7702ffa40c538d1c9ebcdd925a2c7a29 } private void d(Advancement advancement) { -@@ -472,6 +508,7 @@ public class AdvancementDataPlayer { +@@ -479,6 +515,7 @@ public class AdvancementDataPlayer { this.data.put(advancement, advancementprogress); } diff --git a/patches/server/0044-lithium-reduce-allocations.patch b/patches/server/0044-lithium-reduce-allocations.patch index aa9da605..15a6d131 100644 --- a/patches/server/0044-lithium-reduce-allocations.patch +++ b/patches/server/0044-lithium-reduce-allocations.patch @@ -11,10 +11,10 @@ Portions of this patch that were sourced from Lithium were remapped from Yarn ma Co-authored-by: Mykyta Komarnytskyy diff --git a/src/main/java/net/minecraft/world/level/block/BlockComposter.java b/src/main/java/net/minecraft/world/level/block/BlockComposter.java -index e4e519ba773388b8d26a8f794a6eff51e3d8f72e..01e315d145160efcd437063afd7566a4213834ce 100644 +index c0b235d5edf3cd14021696d1b4f76ce3de41f5d5..0b58efe27878f1a07579f2e02d3939edefb47933 100644 --- a/src/main/java/net/minecraft/world/level/block/BlockComposter.java +++ b/src/main/java/net/minecraft/world/level/block/BlockComposter.java -@@ -337,7 +337,7 @@ public class BlockComposter extends Block implements IInventoryHolder { +@@ -356,7 +356,7 @@ public class BlockComposter extends Block implements IInventoryHolder { @Override public int[] getSlotsForFace(EnumDirection enumdirection) { @@ -23,7 +23,7 @@ index e4e519ba773388b8d26a8f794a6eff51e3d8f72e..01e315d145160efcd437063afd7566a4 } @Override -@@ -387,7 +387,7 @@ public class BlockComposter extends Block implements IInventoryHolder { +@@ -406,7 +406,7 @@ public class BlockComposter extends Block implements IInventoryHolder { @Override public int[] getSlotsForFace(EnumDirection enumdirection) { @@ -32,7 +32,7 @@ index e4e519ba773388b8d26a8f794a6eff51e3d8f72e..01e315d145160efcd437063afd7566a4 } @Override -@@ -423,7 +423,7 @@ public class BlockComposter extends Block implements IInventoryHolder { +@@ -442,7 +442,7 @@ public class BlockComposter extends Block implements IInventoryHolder { @Override public int[] getSlotsForFace(EnumDirection enumdirection) { diff --git a/patches/server/0045-Smarter-statistics-ticking.patch b/patches/server/0045-Smarter-statistics-ticking.patch index 9e67d686..66ef5503 100644 --- a/patches/server/0045-Smarter-statistics-ticking.patch +++ b/patches/server/0045-Smarter-statistics-ticking.patch @@ -8,10 +8,10 @@ In vanilla, statistics that count time spent for an action (i.e. time played or With an interval of 20, this patch saves roughly 3ms per tick on a server w/ 80 players online. diff --git a/src/main/java/net/minecraft/world/entity/player/EntityHuman.java b/src/main/java/net/minecraft/world/entity/player/EntityHuman.java -index 587eb3a9fd8a155fcb8acc6c5850cfa4de77d626..8e6fd7ed9d79e61b8b82b853bf0017057ff74269 100644 +index 057109a9971795e8ddcfb455ca32f2d03d381b9b..b4f1fa1b873e66b843f2f4673691b72e7ad3e93b 100644 --- a/src/main/java/net/minecraft/world/entity/player/EntityHuman.java +++ b/src/main/java/net/minecraft/world/entity/player/EntityHuman.java -@@ -266,18 +266,23 @@ public abstract class EntityHuman extends EntityLiving { +@@ -282,18 +282,23 @@ public abstract class EntityHuman extends EntityLiving { this.p(); if (!this.world.isClientSide) { this.foodData.a(this); diff --git a/patches/server/0046-Configurable-criterion-triggers.patch b/patches/server/0046-Configurable-criterion-triggers.patch index 61a839a4..b2219714 100644 --- a/patches/server/0046-Configurable-criterion-triggers.patch +++ b/patches/server/0046-Configurable-criterion-triggers.patch @@ -6,7 +6,7 @@ Subject: [PATCH] Configurable criterion triggers This patch adds toggles for three criterion triggers that are called every tick. These can be very unnecessary, and especially in the case of CriterionTriggerEnterBlock, quite heavy. diff --git a/src/main/java/net/minecraft/server/level/EntityPlayer.java b/src/main/java/net/minecraft/server/level/EntityPlayer.java -index c813077455a463dd558076d1d7474829f76b905a..742d802d63963778454e41e5b19a3d889c544efc 100644 +index 6d67eff4d584c287c97dfe32832c87bb59725bee..c2e41f856eb1bd948bfa2597a15c6494cf7dbb7c 100644 --- a/src/main/java/net/minecraft/server/level/EntityPlayer.java +++ b/src/main/java/net/minecraft/server/level/EntityPlayer.java @@ -577,6 +577,7 @@ public class EntityPlayer extends EntityHuman implements ICrafting { @@ -17,7 +17,7 @@ index c813077455a463dd558076d1d7474829f76b905a..742d802d63963778454e41e5b19a3d88 CriterionTriggers.d.a(this, iblockdata); } -@@ -898,7 +899,7 @@ public class EntityPlayer extends EntityHuman implements ICrafting { +@@ -907,7 +908,7 @@ public class EntityPlayer extends EntityHuman implements ICrafting { this.playerConnection.sendPacket(new PacketPlayOutExperience(this.exp, this.expTotal, this.expLevel)); } diff --git a/patches/server/0047-Configurable-BlockPhysicsEvent.patch b/patches/server/0047-Configurable-BlockPhysicsEvent.patch index 1a104131..12db32cb 100644 --- a/patches/server/0047-Configurable-BlockPhysicsEvent.patch +++ b/patches/server/0047-Configurable-BlockPhysicsEvent.patch @@ -8,18 +8,18 @@ Paper does alleviate this quite well by only firing if plugins are listening, bu This patch implements a hard toggle for the event. diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index e026ec3920936223864538974151ae53a393e86f..88bb4e47b5def2ba1543cd73411fbcffd570e11d 100644 +index 4a2ccb7a25fd3377627b7e68588fced89c923405..baf8fafe95868944887ea00896f43c8f1485b860 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -1536,7 +1536,7 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant 0; // Paper + worldserver.hasPhysicsEvent = org.yatopiamc.yatopia.server.YatopiaConfig.fireBlockPhysicsEvent && org.bukkit.event.block.BlockPhysicsEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper // Yatopia worldserver.hasEntityMoveEvent = EntityMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper + worldserver.hasRidableMoveEvent = net.pl3x.purpur.event.entity.RidableMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Purpur TileEntityHopper.skipHopperEvents = worldserver.paperConfig.disableHopperMoveEvents || org.bukkit.event.inventory.InventoryMoveItemEvent.getHandlerList().getRegisteredListeners().length == 0; // Paper - diff --git a/src/main/java/org/yatopiamc/yatopia/server/YatopiaConfig.java b/src/main/java/org/yatopiamc/yatopia/server/YatopiaConfig.java index 5b22f33462dea5491f752d4f50f55d037b381bd3..d20fc029e51f9fbb1dc1da6be242b23490dcebe4 100644 --- a/src/main/java/org/yatopiamc/yatopia/server/YatopiaConfig.java diff --git a/patches/server/0049-Configurable-movement-checks.patch b/patches/server/0049-Configurable-movement-checks.patch index 19d938d1..c38fbf05 100644 --- a/patches/server/0049-Configurable-movement-checks.patch +++ b/patches/server/0049-Configurable-movement-checks.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Configurable movement checks diff --git a/src/main/java/net/minecraft/server/network/PlayerConnection.java b/src/main/java/net/minecraft/server/network/PlayerConnection.java -index 660f7006690d2eb7e16239faffabfd88a841f426..8d592d79bf994b01c331e8090012c60098266f8c 100644 +index bd4672b2ba737e3b69a16aca4dc27e6b5d964cab..43ade0309a35771fd79caee86e7f1f4dc2e81155 100644 --- a/src/main/java/net/minecraft/server/network/PlayerConnection.java +++ b/src/main/java/net/minecraft/server/network/PlayerConnection.java -@@ -592,7 +592,7 @@ public class PlayerConnection implements PacketListenerPlayIn { +@@ -614,7 +614,7 @@ public class PlayerConnection implements PacketListenerPlayIn { } // Paper end @@ -17,7 +17,7 @@ index 660f7006690d2eb7e16239faffabfd88a841f426..8d592d79bf994b01c331e8090012c600 // CraftBukkit end PlayerConnection.LOGGER.warn("{} (vehicle of {}) moved too quickly! {},{},{}", entity.getDisplayName().getString(), this.player.getDisplayName().getString(), d6, d7, d8); this.networkManager.sendPacket(new PacketPlayOutVehicleMove(entity)); -@@ -619,7 +619,7 @@ public class PlayerConnection implements PacketListenerPlayIn { +@@ -641,7 +641,7 @@ public class PlayerConnection implements PacketListenerPlayIn { d10 = d6 * d6 + d7 * d7 + d8 * d8; boolean flag1 = false; @@ -26,7 +26,7 @@ index 660f7006690d2eb7e16239faffabfd88a841f426..8d592d79bf994b01c331e8090012c600 flag1 = true; // Tuinity - diff on change, this should be moved wrongly PlayerConnection.LOGGER.warn("{} (vehicle of {}) moved wrongly! {}", entity.getDisplayName().getString(), this.player.getDisplayName().getString(), Math.sqrt(d10)); } -@@ -1361,7 +1361,7 @@ public class PlayerConnection implements PacketListenerPlayIn { +@@ -1400,7 +1400,7 @@ public class PlayerConnection implements PacketListenerPlayIn { if (!this.player.H() && (!this.player.getWorldServer().getGameRules().getBoolean(GameRules.DISABLE_ELYTRA_MOVEMENT_CHECK) || !this.player.isGliding())) { float f2 = this.player.isGliding() ? 300.0F : 100.0F; @@ -35,14 +35,14 @@ index 660f7006690d2eb7e16239faffabfd88a841f426..8d592d79bf994b01c331e8090012c600 // CraftBukkit end PlayerConnection.LOGGER.warn("{} moved too quickly! {},{},{}", this.player.getDisplayName().getString(), d7, d8, d9); this.a(this.player.locX(), this.player.locY(), this.player.locZ(), this.player.yaw, this.player.pitch); -@@ -1427,7 +1427,7 @@ public class PlayerConnection implements PacketListenerPlayIn { +@@ -1466,7 +1466,7 @@ public class PlayerConnection implements PacketListenerPlayIn { d11 = d7 * d7 + d8 * d8 + d9 * d9; boolean flag1 = false; - if (!this.player.H() && d11 > org.spigotmc.SpigotConfig.movedWronglyThreshold && !this.player.isSleeping() && !this.player.playerInteractManager.isCreative() && this.player.playerInteractManager.getGameMode() != EnumGamemode.SPECTATOR) { // Spigot + if (org.yatopiamc.yatopia.server.YatopiaConfig.checkMovedWrongly && !this.player.H() && d11 > org.spigotmc.SpigotConfig.movedWronglyThreshold && !this.player.isSleeping() && !this.player.playerInteractManager.isCreative() && this.player.playerInteractManager.getGameMode() != EnumGamemode.SPECTATOR) { // Spigot // Yatopia - Configurable movement checks flag1 = true; // Tuinity - diff on change, this should be moved wrongly - PlayerConnection.LOGGER.warn("{} moved wrongly!", this.player.getDisplayName().getString()); + PlayerConnection.LOGGER.warn("{} moved wrongly! ({})", this.player.getDisplayName().getString(), d11); // Purpur } diff --git a/src/main/java/org/yatopiamc/yatopia/server/YatopiaConfig.java b/src/main/java/org/yatopiamc/yatopia/server/YatopiaConfig.java index d20fc029e51f9fbb1dc1da6be242b23490dcebe4..2329a3d4c3aaa660a0c824bb44be0b563949b917 100644 diff --git a/patches/server/0050-Configurable-enchanting-table-tick.patch b/patches/server/0050-Configurable-enchanting-table-tick.patch index 0f802995..b78138ee 100644 --- a/patches/server/0050-Configurable-enchanting-table-tick.patch +++ b/patches/server/0050-Configurable-enchanting-table-tick.patch @@ -7,7 +7,7 @@ Also don't tick blockentity beehive if there are no bees in it. This patch is a leftover from the original tile entity optimisations, which was majorly flawed. diff --git a/src/main/java/net/minecraft/world/level/block/entity/TileEntityBeehive.java b/src/main/java/net/minecraft/world/level/block/entity/TileEntityBeehive.java -index 80083a6666a28372946cf0e68ded44d075357f7d..cacef4349a8dba02c2faee77e30f7c938f3d31af 100644 +index 6fbd8ee31c517cd08ce4d1374a278dd748f9933e..95479df9fb009c5ca1872f8ee89b13e9c66d0bb6 100644 --- a/src/main/java/net/minecraft/world/level/block/entity/TileEntityBeehive.java +++ b/src/main/java/net/minecraft/world/level/block/entity/TileEntityBeehive.java @@ -309,6 +309,7 @@ public class TileEntityBeehive extends TileEntity implements ITickable { diff --git a/patches/server/0051-Optimised-hallowen-checker.patch b/patches/server/0051-Optimised-hallowen-checker.patch index 328f13a6..b15548b4 100644 --- a/patches/server/0051-Optimised-hallowen-checker.patch +++ b/patches/server/0051-Optimised-hallowen-checker.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Optimised hallowen checker diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 88bb4e47b5def2ba1543cd73411fbcffd570e11d..95d570bf29ca213808fd8382161a7437bcea4283 100644 +index baf8fafe95868944887ea00896f43c8f1485b860..291757692747bad94ac503641508ad8b330b0b07 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -1464,6 +1464,7 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant= generatoraccess.getSeaLevel()) { return false; } else { @@ -17,7 +17,7 @@ index b3acd9518791488a2206f28182a6401c8e3db722..9baa0cca1dc2a39cc38772e596c0ca0c byte b0 = 4; if (eJ()) { -@@ -243,6 +243,7 @@ public class EntityBat extends EntityAmbient { +@@ -302,6 +302,7 @@ public class EntityBat extends EntityAmbient { return false; } diff --git a/patches/server/0053-add-config-for-logging-login-location.patch b/patches/server/0053-add-config-for-logging-login-location.patch index 5cbc0ace..99a8f9b0 100644 --- a/patches/server/0053-add-config-for-logging-login-location.patch +++ b/patches/server/0053-add-config-for-logging-login-location.patch @@ -5,7 +5,7 @@ Subject: [PATCH] add config for logging login location diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 3e89b266240c32e36a7b2eb49fb87fcd8b3659e5..d825c6b8e46e2a699bdc22d081d627edb2f0c840 100644 +index bc3adc076870cc7cfb61ac1fa9e4c939b714ef57..27fdce74d3ff886ceea4b74cb5465b20c74ebe93 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java @@ -480,7 +480,14 @@ public abstract class PlayerList { diff --git a/patches/server/0054-Preload-ProtocolLib-EnumWrappers.patch b/patches/server/0054-Preload-ProtocolLib-EnumWrappers.patch index d66874b8..8ffba55d 100644 --- a/patches/server/0054-Preload-ProtocolLib-EnumWrappers.patch +++ b/patches/server/0054-Preload-ProtocolLib-EnumWrappers.patch @@ -6,10 +6,10 @@ Subject: [PATCH] Preload ProtocolLib EnumWrappers Currently, ProtocolLib load EnumWrappers lazily and causing memory effects issues. This patch preloads EnumWrappers to prevent further NPE. diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 95d570bf29ca213808fd8382161a7437bcea4283..c3955c0c48861ead0b0ea1724257ec8c20711dcf 100644 +index 291757692747bad94ac503641508ad8b330b0b07..3cb48706cd29ce8ea440ca60dc59c15844c3ceb6 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -1089,6 +1089,7 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index c3955c0c48861ead0b0ea1724257ec8c20711dcf..3be963f4a278da028ed36f0caeb4ed35c45978ae 100644 +index 3cb48706cd29ce8ea440ca60dc59c15844c3ceb6..dfab858e1cc9842922740a0dbd3a4d936db61647 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -954,7 +954,9 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant> { @@ -75,10 +75,10 @@ index 71a000edfab27c9965d1929af78582821d5af97a..5c5ac70b4dae5d51303ab974261055aa LOGGER.error("Error whilst processing packet {} for {}[{}]", packet, networkmanager.getPlayer().getName(), networkmanager.getSocketAddress(), e); } else { diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 3be963f4a278da028ed36f0caeb4ed35c45978ae..d5d05d4a9376b7954f206dde22aba1fb053b00c4 100644 +index dfab858e1cc9842922740a0dbd3a4d936db61647..b685357b7161c8051c2fd5ff7b3f98e8c418fe8a 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -1158,7 +1158,11 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant { // CraftBukkit end @@ -226,7 +226,7 @@ index b742f457d72eee4f00f5df7a2b5b3cfdeb917a86..c4d3f716dda0e33b444de6caa6f336d8 }); vec3d = this.a(enumdirection_enumaxis, blockutil_rectangle1); -@@ -3443,6 +3456,7 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, ne +@@ -3484,6 +3497,7 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, ne } public boolean cl() { @@ -234,7 +234,7 @@ index b742f457d72eee4f00f5df7a2b5b3cfdeb917a86..c4d3f716dda0e33b444de6caa6f336d8 boolean flag = this.au; this.au = false; -@@ -3641,7 +3655,7 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, ne +@@ -3687,7 +3701,7 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, ne for (int i2 = k; i2 < l; ++i2) { for (int j2 = i1; j2 < j1; ++j2) { blockposition_mutableblockposition.d(l1, i2, j2); @@ -244,10 +244,10 @@ index b742f457d72eee4f00f5df7a2b5b3cfdeb917a86..c4d3f716dda0e33b444de6caa6f336d8 if (fluid.a(tag)) { double d2 = (double) ((float) i2 + fluid.getHeight(this.world, blockposition_mutableblockposition)); diff --git a/src/main/java/net/minecraft/world/entity/EntityLiving.java b/src/main/java/net/minecraft/world/entity/EntityLiving.java -index 6132c711836908569006a8993973526275c9fb7c..02f7a588f883c0ed8b5daef6839e385b4ce1334b 100644 +index 2f84f10a3f811b415b62291b91bca7728b163f1e..ce9f7b13d22dd616d94fb251cfd8b136a5d7371a 100644 --- a/src/main/java/net/minecraft/world/entity/EntityLiving.java +++ b/src/main/java/net/minecraft/world/entity/EntityLiving.java -@@ -139,6 +139,7 @@ import org.bukkit.event.entity.EntityTeleportEvent; +@@ -140,6 +140,7 @@ import org.bukkit.event.entity.EntityTeleportEvent; import org.bukkit.event.player.PlayerItemConsumeEvent; // CraftBukkit end @@ -255,7 +255,7 @@ index 6132c711836908569006a8993973526275c9fb7c..02f7a588f883c0ed8b5daef6839e385b public abstract class EntityLiving extends Entity { -@@ -387,7 +388,7 @@ public abstract class EntityLiving extends Entity { +@@ -396,7 +397,7 @@ public abstract class EntityLiving extends Entity { boolean flag1 = flag && ((EntityHuman) this).abilities.isInvulnerable; if (this.isAlive()) { @@ -263,8 +263,8 @@ index 6132c711836908569006a8993973526275c9fb7c..02f7a588f883c0ed8b5daef6839e385b + if (this.a((Tag) TagsFluid.WATER) && !this.world.getBlockStateIfLoaded(new BlockPosition(this.locX(), this.getHeadY(), this.locZ())).a(Blocks.BUBBLE_COLUMN)) { // Yatopia if (!this.canBreatheUnderwater() && !MobEffectUtil.c(this) && !flag1) { // Paper - use OBFHELPER so it can be overridden this.setAirTicks(this.l(this.getAirTicks())); - if (this.getAirTicks() == -20) { -@@ -480,7 +481,7 @@ public abstract class EntityLiving extends Entity { + if (this.getAirTicks() == -this.world.purpurConfig.drowningDamageInterval) { // Purpur +@@ -489,7 +490,7 @@ public abstract class EntityLiving extends Entity { } protected boolean cP() { @@ -273,7 +273,7 @@ index 6132c711836908569006a8993973526275c9fb7c..02f7a588f883c0ed8b5daef6839e385b } @Override -@@ -528,6 +529,8 @@ public abstract class EntityLiving extends Entity { +@@ -537,6 +538,8 @@ public abstract class EntityLiving extends Entity { } protected void c(BlockPosition blockposition) { @@ -282,7 +282,7 @@ index 6132c711836908569006a8993973526275c9fb7c..02f7a588f883c0ed8b5daef6839e385b int i = EnchantmentManager.a(Enchantments.FROST_WALKER, this); if (i > 0) { -@@ -1561,7 +1564,7 @@ public abstract class EntityLiving extends Entity { +@@ -1604,7 +1607,7 @@ public abstract class EntityLiving extends Entity { BlockPosition blockposition = this.getChunkCoordinates(); IBlockData iblockdata = Blocks.WITHER_ROSE.getBlockData(); @@ -291,7 +291,7 @@ index 6132c711836908569006a8993973526275c9fb7c..02f7a588f883c0ed8b5daef6839e385b this.world.setTypeAndData(blockposition, iblockdata, 3); flag = true; } -@@ -1764,12 +1767,12 @@ public abstract class EntityLiving extends Entity { +@@ -1809,12 +1812,12 @@ public abstract class EntityLiving extends Entity { // Airplane end public IBlockData ds() { @@ -306,7 +306,7 @@ index 6132c711836908569006a8993973526275c9fb7c..02f7a588f883c0ed8b5daef6839e385b if (iblockdata1.a(Blocks.LADDER) && iblockdata1.get(BlockLadder.FACING) == iblockdata.get(BlockTrapdoor.FACING)) { return true; -@@ -1816,7 +1819,7 @@ public abstract class EntityLiving extends Entity { +@@ -1861,7 +1864,7 @@ public abstract class EntityLiving extends Entity { int i = MathHelper.floor(this.locX()); int j = MathHelper.floor(this.locY() - 0.20000000298023224D); int k = MathHelper.floor(this.locZ()); @@ -315,7 +315,7 @@ index 6132c711836908569006a8993973526275c9fb7c..02f7a588f883c0ed8b5daef6839e385b if (!iblockdata.isAir()) { SoundEffectType soundeffecttype = iblockdata.getStepSound(); -@@ -2289,7 +2292,7 @@ public abstract class EntityLiving extends Entity { +@@ -2358,7 +2361,7 @@ public abstract class EntityLiving extends Entity { private void a(Entity entity) { Vec3D vec3d; @@ -324,7 +324,7 @@ index 6132c711836908569006a8993973526275c9fb7c..02f7a588f883c0ed8b5daef6839e385b vec3d = entity.b(this); } else { vec3d = new Vec3D(entity.locX(), entity.locY() + (double) entity.getHeight(), entity.locZ()); -@@ -2343,7 +2346,7 @@ public abstract class EntityLiving extends Entity { +@@ -2412,7 +2415,7 @@ public abstract class EntityLiving extends Entity { this.fallDistance = 0.0F; } @@ -333,7 +333,7 @@ index 6132c711836908569006a8993973526275c9fb7c..02f7a588f883c0ed8b5daef6839e385b double d1; float f; -@@ -2459,7 +2462,7 @@ public abstract class EntityLiving extends Entity { +@@ -2528,7 +2531,7 @@ public abstract class EntityLiving extends Entity { } } else { BlockPosition blockposition = this.as(); @@ -342,7 +342,7 @@ index 6132c711836908569006a8993973526275c9fb7c..02f7a588f883c0ed8b5daef6839e385b f = this.onGround ? f5 * 0.91F : 0.91F; Vec3D vec3d6 = this.a(vec3d, f5); -@@ -3505,7 +3508,7 @@ public abstract class EntityLiving extends Entity { +@@ -3628,7 +3631,7 @@ public abstract class EntityLiving extends Entity { while (!flag2 && blockposition.getY() > 0) { BlockPosition blockposition1 = blockposition.down(); @@ -351,7 +351,7 @@ index 6132c711836908569006a8993973526275c9fb7c..02f7a588f883c0ed8b5daef6839e385b if (iblockdata.getMaterial().isSolid()) { flag2 = true; -@@ -3617,7 +3620,7 @@ public abstract class EntityLiving extends Entity { +@@ -3740,7 +3743,7 @@ public abstract class EntityLiving extends Entity { this.stopRiding(); } @@ -360,7 +360,7 @@ index 6132c711836908569006a8993973526275c9fb7c..02f7a588f883c0ed8b5daef6839e385b if (iblockdata.getBlock() instanceof BlockBed) { this.world.setTypeAndData(blockposition, (IBlockData) iblockdata.set(BlockBed.OCCUPIED, true), 3); -@@ -3636,7 +3639,7 @@ public abstract class EntityLiving extends Entity { +@@ -3759,7 +3762,7 @@ public abstract class EntityLiving extends Entity { private boolean x() { return (Boolean) this.getBedPosition().map((blockposition) -> { @@ -369,7 +369,7 @@ index 6132c711836908569006a8993973526275c9fb7c..02f7a588f883c0ed8b5daef6839e385b }).orElse(false); } -@@ -3646,7 +3649,7 @@ public abstract class EntityLiving extends Entity { +@@ -3769,7 +3772,7 @@ public abstract class EntityLiving extends Entity { this.world.getClass(); optional.filter(world::isLoaded).ifPresent((blockposition) -> { @@ -379,10 +379,10 @@ index 6132c711836908569006a8993973526275c9fb7c..02f7a588f883c0ed8b5daef6839e385b if (iblockdata.getBlock() instanceof BlockBed) { this.world.setTypeAndData(blockposition, (IBlockData) iblockdata.set(BlockBed.OCCUPIED, false), 3); diff --git a/src/main/java/net/minecraft/world/level/World.java b/src/main/java/net/minecraft/world/level/World.java -index d571624244bf3db54ec266cb760407889fc33bf4..b04a785c70126ad3cc60eff47dffc4a913e0dd87 100644 +index f8a647c68342f7e0a936637cb674d66b6a714fe4..e90ce5f608236bb5a4758e04a9eb2e29e93069e2 100644 --- a/src/main/java/net/minecraft/world/level/World.java +++ b/src/main/java/net/minecraft/world/level/World.java -@@ -96,7 +96,9 @@ import org.bukkit.craftbukkit.block.data.CraftBlockData; +@@ -97,7 +97,9 @@ import org.bukkit.craftbukkit.block.data.CraftBlockData; import org.bukkit.event.block.BlockPhysicsEvent; // CraftBukkit end diff --git a/patches/server/0061-lithium-optimize-BlockPos.iterateOutwards-by-caching.patch b/patches/server/0061-lithium-optimize-BlockPos.iterateOutwards-by-caching.patch index 0b34ff35..bf432ef7 100644 --- a/patches/server/0061-lithium-optimize-BlockPos.iterateOutwards-by-caching.patch +++ b/patches/server/0061-lithium-optimize-BlockPos.iterateOutwards-by-caching.patch @@ -140,7 +140,7 @@ index 0000000000000000000000000000000000000000..e2e4f7968a399b4641df07b2931fff6d +} \ No newline at end of file diff --git a/src/main/java/net/minecraft/core/BlockPosition.java b/src/main/java/net/minecraft/core/BlockPosition.java -index 84e753804f58cbbe1b3b30aa1fe1fecd739a1551..e3ac546214793cb9c5af19046d20216095c6cc02 100644 +index 8cb42aa7fede543ea33d2ff945ad75df26b37f4e..24807295892cad990b100b0e70577e7450febfbc 100644 --- a/src/main/java/net/minecraft/core/BlockPosition.java +++ b/src/main/java/net/minecraft/core/BlockPosition.java @@ -18,10 +18,16 @@ import net.minecraft.world.phys.Vec3D; @@ -160,7 +160,7 @@ index 84e753804f58cbbe1b3b30aa1fe1fecd739a1551..e3ac546214793cb9c5af19046d202160 public static final Codec a = Codec.INT_STREAM.comapFlatMap((intstream) -> { return SystemUtils.a(intstream, 3).map((aint) -> { return new BlockPosition(aint[0], aint[1], aint[2]); -@@ -71,14 +77,17 @@ public class BlockPosition extends BaseBlockPosition { +@@ -77,14 +83,17 @@ public class BlockPosition extends BaseBlockPosition { return a((int) (i >> 38) + j, (int) ((i << 52) >> 52) + k, (int) ((i << 26) >> 38) + l); // Paper - simplify/inline } @@ -178,7 +178,7 @@ index 84e753804f58cbbe1b3b30aa1fe1fecd739a1551..e3ac546214793cb9c5af19046d202160 public static int d(long i) { return (int) ((i << 26) >> 38); // Paper - simplify/inline } -@@ -259,7 +268,15 @@ public class BlockPosition extends BaseBlockPosition { +@@ -265,7 +274,15 @@ public class BlockPosition extends BaseBlockPosition { }; } diff --git a/patches/server/0062-lithium-block.patch b/patches/server/0062-lithium-block.patch index 8bcaaa1c..12e39ea9 100644 --- a/patches/server/0062-lithium-block.patch +++ b/patches/server/0062-lithium-block.patch @@ -32,7 +32,7 @@ index 0000000000000000000000000000000000000000..f78927e71258e859154cca8ba78d1713 + } +} diff --git a/src/main/java/net/minecraft/core/EnumDirection.java b/src/main/java/net/minecraft/core/EnumDirection.java -index e7f56ae5214af02e5dbcf16b781032545702a0d8..25b3b60abe2cb701675c359c57b4793162574ccc 100644 +index 2cb42df0a29abc28751989dc046f83e0c28ccf79..17c335e83a898303bfe419465abc8e7d0f67c45d 100644 --- a/src/main/java/net/minecraft/core/EnumDirection.java +++ b/src/main/java/net/minecraft/core/EnumDirection.java @@ -100,6 +100,7 @@ public enum EnumDirection implements INamable { diff --git a/patches/server/0063-lithium-entity.patch b/patches/server/0063-lithium-entity.patch index 83eb9b5d..19f81144 100644 --- a/patches/server/0063-lithium-entity.patch +++ b/patches/server/0063-lithium-entity.patch @@ -6,12 +6,12 @@ Subject: [PATCH] lithium entity Co-authored-by: Hugo Planque diff --git a/src/main/java/net/minecraft/world/entity/EntityLiving.java b/src/main/java/net/minecraft/world/entity/EntityLiving.java -index 02f7a588f883c0ed8b5daef6839e385b4ce1334b..81ad2ad6494f4808c4d240342a5d1d2971fa52ca 100644 +index ce9f7b13d22dd616d94fb251cfd8b136a5d7371a..e1ed7b8cceb6cc05618ba014bb27f0ba753c1f8e 100644 --- a/src/main/java/net/minecraft/world/entity/EntityLiving.java +++ b/src/main/java/net/minecraft/world/entity/EntityLiving.java -@@ -276,6 +276,9 @@ public abstract class EntityLiving extends Entity { - this.bg = this.a(new Dynamic(dynamicopsnbt, dynamicopsnbt.createMap((Map) ImmutableMap.of(dynamicopsnbt.createString("memories"), dynamicopsnbt.emptyMap())))); - } +@@ -284,6 +284,9 @@ public abstract class EntityLiving extends Entity { + + protected void initAttributes() {} // Purpur + private IBlockData lastStateAtFeet = null; + @@ -19,7 +19,7 @@ index 02f7a588f883c0ed8b5daef6839e385b4ce1334b..81ad2ad6494f4808c4d240342a5d1d29 public BehaviorController getBehaviorController() { return this.bg; } -@@ -350,6 +353,10 @@ public abstract class EntityLiving extends Entity { +@@ -358,6 +361,10 @@ public abstract class EntityLiving extends Entity { @Override public void entityBaseTick() { @@ -30,7 +30,7 @@ index 02f7a588f883c0ed8b5daef6839e385b4ce1334b..81ad2ad6494f4808c4d240342a5d1d29 this.ar = this.as; if (this.justCreated) { this.getBedPosition().ifPresent(this::a); -@@ -1767,7 +1774,24 @@ public abstract class EntityLiving extends Entity { +@@ -1812,7 +1819,24 @@ public abstract class EntityLiving extends Entity { // Airplane end public IBlockData ds() { diff --git a/patches/server/0064-lithium-shape.patch b/patches/server/0064-lithium-shape.patch index 2f02099e..8acff1c0 100644 --- a/patches/server/0064-lithium-shape.patch +++ b/patches/server/0064-lithium-shape.patch @@ -270,10 +270,10 @@ index b95115aca72ba0cf6451096ddbd8b50a8f3bb5c6..0afb8c643cb3e5938e12183c6132797d int j = i - 1; diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index c4d3f716dda0e33b444de6caa6f336d8d33daf5b..d212e9c4ffe44b6fdcb78d0cf2a7547bc98f57a3 100644 +index c80698dc000eb9ef5d3710894c21c0020b329e65..a67341ae2bda644999cedd75ee392309fda3fb77 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -2687,6 +2687,7 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, ne +@@ -2713,6 +2713,7 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, ne return this.isSneaking(); } @@ -282,10 +282,10 @@ index c4d3f716dda0e33b444de6caa6f336d8d33daf5b..d212e9c4ffe44b6fdcb78d0cf2a7547b return this.isSneaking(); } diff --git a/src/main/java/net/minecraft/world/level/block/Block.java b/src/main/java/net/minecraft/world/level/block/Block.java -index 96d7990c66bd569b1b5ee287c0238c7dbb4c503e..505d760b7c2e9aea29d76d0f3b3f1d1d14a3e961 100644 +index a835285d230ea0dffa1b28c2a7a006041f2e6b2a..ccb35c1ddbf83a7e644f88ed17b8881ff305685a 100644 --- a/src/main/java/net/minecraft/world/level/block/Block.java +++ b/src/main/java/net/minecraft/world/level/block/Block.java -@@ -49,6 +49,7 @@ import net.minecraft.world.phys.shapes.VoxelShape; +@@ -54,6 +54,7 @@ import net.minecraft.world.phys.shapes.VoxelShape; import net.minecraft.world.phys.shapes.VoxelShapes; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -293,7 +293,7 @@ index 96d7990c66bd569b1b5ee287c0238c7dbb4c503e..505d760b7c2e9aea29d76d0f3b3f1d1d public class Block extends BlockBase implements IMaterial { -@@ -209,8 +210,14 @@ public class Block extends BlockBase implements IMaterial { +@@ -216,8 +217,14 @@ public class Block extends BlockBase implements IMaterial { return a(voxelshape1); } diff --git a/patches/server/0065-lithium-skip-ticking-block-entities-that-are-doing-n.patch b/patches/server/0065-lithium-skip-ticking-block-entities-that-are-doing-n.patch index 2ba123f9..9ac4d31a 100644 --- a/patches/server/0065-lithium-skip-ticking-block-entities-that-are-doing-n.patch +++ b/patches/server/0065-lithium-skip-ticking-block-entities-that-are-doing-n.patch @@ -621,10 +621,10 @@ index 0000000000000000000000000000000000000000..4e765ab19ffb300b6c810333b2dc7976 +} \ No newline at end of file diff --git a/src/main/java/net/minecraft/world/level/World.java b/src/main/java/net/minecraft/world/level/World.java -index b04a785c70126ad3cc60eff47dffc4a913e0dd87..0ac2e6a5d2492599fad179c60e67369fd2f65647 100644 +index e90ce5f608236bb5a4758e04a9eb2e29e93069e2..b093d79e3eaa472d041c9edb3db2dc2e8f5c5c43 100644 --- a/src/main/java/net/minecraft/world/level/World.java +++ b/src/main/java/net/minecraft/world/level/World.java -@@ -97,8 +97,11 @@ import org.bukkit.event.block.BlockPhysicsEvent; +@@ -98,8 +98,11 @@ import org.bukkit.event.block.BlockPhysicsEvent; // CraftBukkit end import net.gegy1000.tictacs.NonBlockingWorldAccess; // Yatopia @@ -637,7 +637,7 @@ index b04a785c70126ad3cc60eff47dffc4a913e0dd87..0ac2e6a5d2492599fad179c60e67369f protected static final Logger LOGGER = LogManager.getLogger(); public static final Codec> f = MinecraftKey.a.xmap(ResourceKey.b(IRegistry.L), ResourceKey::a); -@@ -107,9 +110,17 @@ public abstract class World implements GeneratorAccess, AutoCloseable, NonBlocki +@@ -108,9 +111,17 @@ public abstract class World implements GeneratorAccess, AutoCloseable, NonBlocki public static final ResourceKey THE_END = ResourceKey.a(IRegistry.L, new MinecraftKey("the_end")); private static final EnumDirection[] a = EnumDirection.values(); //public final List tileEntityList = Lists.newArrayList(); // Paper - remove unused list @@ -656,7 +656,7 @@ index b04a785c70126ad3cc60eff47dffc4a913e0dd87..0ac2e6a5d2492599fad179c60e67369f public final Thread serverThread; private final boolean debugWorld; private int d; -@@ -330,6 +341,8 @@ public abstract class World implements GeneratorAccess, AutoCloseable, NonBlocki +@@ -376,6 +387,8 @@ public abstract class World implements GeneratorAccess, AutoCloseable, NonBlocki this.keepSpawnInMemory = this.paperConfig.keepSpawnInMemory; // Paper this.entityLimiter = new org.spigotmc.TickLimiter(spigotConfig.entityMaxTickTime); this.tileLimiter = new org.spigotmc.TickLimiter(spigotConfig.tileMaxTickTime); @@ -665,7 +665,7 @@ index b04a785c70126ad3cc60eff47dffc4a913e0dd87..0ac2e6a5d2492599fad179c60e67369f } // Paper start -@@ -994,6 +1007,15 @@ public abstract class World implements GeneratorAccess, AutoCloseable, NonBlocki +@@ -1040,6 +1053,15 @@ public abstract class World implements GeneratorAccess, AutoCloseable, NonBlocki } @@ -681,7 +681,7 @@ index b04a785c70126ad3cc60eff47dffc4a913e0dd87..0ac2e6a5d2492599fad179c60e67369f public void tickBlockEntities() { GameProfilerFiller gameprofilerfiller = this.getMethodProfiler(); -@@ -1016,11 +1038,19 @@ public abstract class World implements GeneratorAccess, AutoCloseable, NonBlocki +@@ -1062,11 +1084,19 @@ public abstract class World implements GeneratorAccess, AutoCloseable, NonBlocki this.tickingTileEntities = true; // Spigot start @@ -701,7 +701,7 @@ index b04a785c70126ad3cc60eff47dffc4a913e0dd87..0ac2e6a5d2492599fad179c60e67369f // Spigot start if (tileentity == null) { getServer().getLogger().severe("Spigot has detected a null entity and has removed it, preventing a crash"); -@@ -1058,8 +1088,7 @@ public abstract class World implements GeneratorAccess, AutoCloseable, NonBlocki +@@ -1104,8 +1134,7 @@ public abstract class World implements GeneratorAccess, AutoCloseable, NonBlocki throwable.printStackTrace(); getServer().getPluginManager().callEvent(new ServerExceptionEvent(new ServerInternalException(msg, throwable))); // Paper end @@ -711,7 +711,7 @@ index b04a785c70126ad3cc60eff47dffc4a913e0dd87..0ac2e6a5d2492599fad179c60e67369f continue; // Paper end // Spigot start -@@ -1072,8 +1101,7 @@ public abstract class World implements GeneratorAccess, AutoCloseable, NonBlocki +@@ -1118,8 +1147,7 @@ public abstract class World implements GeneratorAccess, AutoCloseable, NonBlocki if (tileentity.isRemoved()) { // Spigot start @@ -722,10 +722,10 @@ index b04a785c70126ad3cc60eff47dffc4a913e0dd87..0ac2e6a5d2492599fad179c60e67369f //this.tileEntityList.remove(tileentity); // Paper - remove unused list // Paper - prevent double chunk lookups diff --git a/src/main/java/net/minecraft/world/level/block/entity/TileEntity.java b/src/main/java/net/minecraft/world/level/block/entity/TileEntity.java -index 93d02ccb87c17404c55884f52ae40c7b7ddfb103..cc9e6b9e5f550f9e633ea124f3dd8cbcf0e43e12 100644 +index 35c4d5414db66b977a354ac50d35a6aa0fcd4cf8..35aef3647c025eaa763e2b9a5a4e266d556725f5 100644 --- a/src/main/java/net/minecraft/world/level/block/entity/TileEntity.java +++ b/src/main/java/net/minecraft/world/level/block/entity/TileEntity.java -@@ -26,8 +26,9 @@ import org.bukkit.inventory.InventoryHolder; +@@ -28,8 +28,9 @@ import org.bukkit.inventory.InventoryHolder; import org.spigotmc.CustomTimingsHandler; // Spigot import co.aikar.timings.MinecraftTimings; // Paper import co.aikar.timings.Timing; // Paper @@ -737,7 +737,7 @@ index 93d02ccb87c17404c55884f52ae40c7b7ddfb103..cc9e6b9e5f550f9e633ea124f3dd8cbc public Timing tickTimer = MinecraftTimings.getTileEntityTimings(this); // Paper // CraftBukkit start - data containers diff --git a/src/main/java/net/minecraft/world/level/block/entity/TileEntityBeehive.java b/src/main/java/net/minecraft/world/level/block/entity/TileEntityBeehive.java -index cacef4349a8dba02c2faee77e30f7c938f3d31af..a1651a7155f7fe2f01882a1eee4fbb5a067e1b38 100644 +index 95479df9fb009c5ca1872f8ee89b13e9c66d0bb6..52243bce89b28572efae9af54348502f599fb896 100644 --- a/src/main/java/net/minecraft/world/level/block/entity/TileEntityBeehive.java +++ b/src/main/java/net/minecraft/world/level/block/entity/TileEntityBeehive.java @@ -23,6 +23,9 @@ import net.minecraft.world.level.block.BlockBeehive; @@ -753,7 +753,7 @@ index cacef4349a8dba02c2faee77e30f7c938f3d31af..a1651a7155f7fe2f01882a1eee4fbb5a @@ -30,11 +33,24 @@ public class TileEntityBeehive extends TileEntity implements ITickable { @Nullable public BlockPosition flowerPos = null; - public int maxBees = 3; // CraftBukkit - allow setting max amount of bees a hive can hold + public int maxBees = net.pl3x.purpur.PurpurConfig.beeInsideBeeHive; // CraftBukkit - allow setting max amount of bees a hive can hold // Purpur - Change max bees inside beehive and bee_nest + public boolean doInit = true; // Yatopia + public boolean isTicking = true; // Yatopia @@ -1105,10 +1105,10 @@ index 4b1cb089355b455c6210f2df1af797cc363997cf..0049a675557cbc05e361c12e9fb84a38 this.l = this.k; EntityHuman entityhuman = this.world.a((double) this.position.getX() + 0.5D, (double) this.position.getY() + 0.5D, (double) this.position.getZ() + 0.5D, 3.0D, false); diff --git a/src/main/java/net/minecraft/world/level/block/entity/TileEntityFurnace.java b/src/main/java/net/minecraft/world/level/block/entity/TileEntityFurnace.java -index 20193ba36c62fdd40ae905d1cea4bfd6d6aebcd7..b0f1c4f1660f3485303f0148bbc06dce4181e6b2 100644 +index 8ec9ed518a3b5f70c5a5d74605a1f17d0f47b300..d8ef6d464ed32fe61dd9d1d5ff7c70994998f934 100644 --- a/src/main/java/net/minecraft/world/level/block/entity/TileEntityFurnace.java +++ b/src/main/java/net/minecraft/world/level/block/entity/TileEntityFurnace.java -@@ -51,9 +51,11 @@ import org.bukkit.event.inventory.FurnaceBurnEvent; +@@ -53,9 +53,11 @@ import org.bukkit.event.inventory.FurnaceBurnEvent; import org.bukkit.event.inventory.FurnaceExtractEvent; import org.bukkit.event.inventory.FurnaceSmeltEvent; // CraftBukkit end @@ -1120,7 +1120,7 @@ index 20193ba36c62fdd40ae905d1cea4bfd6d6aebcd7..b0f1c4f1660f3485303f0148bbc06dce private static final int[] g = new int[]{0}; private static final int[] h = new int[]{2, 1}; private static final int[] i = new int[]{1}; -@@ -195,6 +197,17 @@ public abstract class TileEntityFurnace extends TileEntityContainer implements I +@@ -197,6 +199,17 @@ public abstract class TileEntityFurnace extends TileEntityContainer implements I private int maxStack = MAX_STACK; public List transaction = new java.util.ArrayList(); @@ -1138,7 +1138,7 @@ index 20193ba36c62fdd40ae905d1cea4bfd6d6aebcd7..b0f1c4f1660f3485303f0148bbc06dce public List getContents() { return this.items; } -@@ -257,6 +270,12 @@ public abstract class TileEntityFurnace extends TileEntityContainer implements I +@@ -259,6 +272,12 @@ public abstract class TileEntityFurnace extends TileEntityContainer implements I @Override public void load(IBlockData iblockdata, NBTTagCompound nbttagcompound) { super.load(iblockdata, nbttagcompound); @@ -1151,7 +1151,7 @@ index 20193ba36c62fdd40ae905d1cea4bfd6d6aebcd7..b0f1c4f1660f3485303f0148bbc06dce this.items = NonNullList.a(this.getSize(), ItemStack.b); ContainerUtil.b(nbttagcompound, this.items); this.burnTime = nbttagcompound.getShort("BurnTime"); -@@ -369,7 +388,12 @@ public abstract class TileEntityFurnace extends TileEntityContainer implements I +@@ -389,7 +408,12 @@ public abstract class TileEntityFurnace extends TileEntityContainer implements I if (flag1) { this.update(); } diff --git a/upstream/Origami b/upstream/Origami index 756162fb..f112c6d5 160000 --- a/upstream/Origami +++ b/upstream/Origami @@ -1 +1 @@ -Subproject commit 756162fbd31a5566db7efcdc544f67b347b782d5 +Subproject commit f112c6d52901bd93ceab7d8dbc025db8f2a73040 diff --git a/upstream/Purpur b/upstream/Purpur new file mode 160000 index 00000000..650d472b --- /dev/null +++ b/upstream/Purpur @@ -0,0 +1 @@ +Subproject commit 650d472ba151f4451951e745f97085584550216c diff --git a/upstreamCommits/Origami b/upstreamCommits/Origami index 6f69f5b9..0f449db6 100644 --- a/upstreamCommits/Origami +++ b/upstreamCommits/Origami @@ -1 +1 @@ -756162fbd31a5566db7efcdc544f67b347b782d5 \ No newline at end of file +f112c6d52901bd93ceab7d8dbc025db8f2a73040 \ No newline at end of file diff --git a/upstreamCommits/Purpur b/upstreamCommits/Purpur new file mode 100644 index 00000000..9a6b5a32 --- /dev/null +++ b/upstreamCommits/Purpur @@ -0,0 +1 @@ +650d472ba151f4451951e745f97085584550216c \ No newline at end of file diff --git a/upstreamConfig/0002-Purpur.properties b/upstreamConfig/0002-Purpur.properties new file mode 100644 index 00000000..18fef4f4 --- /dev/null +++ b/upstreamConfig/0002-Purpur.properties @@ -0,0 +1,4 @@ +name=Purpur +useBlackList=True +list=api/Tuinity-API-Changes.patch,server/Tuinity-Server-Changes.patch,server/Re-enable-timings-by-default.patch,server/Rebrand.patch +branch=origin/ver/1.16.5