Switch to paperweight

This commit is contained in:
Tofik 2021-06-13 23:05:30 +02:00
parent 22be9f2d6f
commit 34106bb1fe
481 changed files with 75 additions and 38855 deletions

View File

@ -6,9 +6,9 @@ on:
- '*.md'
- 'Jenkinsfile'
branches:
- ver/1.16.5
- ver/1.17
- dev/*
- staging/1.16.5
- staging/1.17
pull_request:
paths-ignore:
- '*.md'
@ -27,7 +27,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
java: [ '8', '11', '15', '16' ]
java: [ '16' ]
fail-fast: false
steps:
- uses: actions/checkout@v2
@ -44,30 +44,21 @@ jobs:
path: ~/.gradle
key: ${{ runner.os }}-mavenCache-${{ hashFiles('gradle/wrapper/gradle-wrapper.properties') }}-openjdk-${{ matrix.java }}
- name: Setup Yatopia Project
- name: Configure git
run: |
git config --global user.email "ci@github.com"
git config --global user.name "Github CI"
git config --global gc.auto 0
sudo chmod -R -f 777 ./gradlew
./gradlew initGitSubmodules
- name: Get MC Version
run: echo "::set-output name=mcver::$(cat "Paper/work/BuildData/info.json" | grep minecraftVersion | cut -d '"' -f 4)"
id: mcver
- name: Pull Minecraft Decompile Cache
uses: actions/cache@v2
id: decompile-cache
with:
path: Paper/work/Minecraft/${{ steps.mcver.outputs.mcver }}
key: ${{ hashFiles('Paper/work/BuildData/mappings/bukkit-$STEPS_MCVER_OUTPUTS_MCVER-cl.csrg') }}-${{ steps.mcver.outputs.mcver }}-${{ runner.os }}-openjdk-${{ matrix.java }}-minecraft-decomp
- name: Apply Patches
run: |
./gradlew setupUpstream
./gradlew applyPatches
- name: Get MC Version
run: echo "::set-output name=mcver::$(cat "Paper/work/BuildData/info.json" | grep minecraftVersion | cut -d '"' -f 4)"
id: mcver
- name: Pull Maven Cache
uses: actions/cache@v2
id: maven-cache
@ -77,7 +68,7 @@ jobs:
- name: Build Yatopia
run: |
./gradlew clean build paperclip
./gradlew generatePaperclipPatch --no-build-cache
- name: Upload Artifact
uses: actions/upload-artifact@v2

39
.gitmodules vendored
View File

@ -1,39 +0,0 @@
[submodule "Paper"]
path = Paper
url = https://github.com/PaperMC/Paper.git
[submodule "upstream/Tuinity"]
path = upstream/Tuinity
url = https://github.com/Spottedleaf/Tuinity
branch = master
[submodule "upstream/Purpur"]
path = upstream/Purpur
url = https://github.com/pl3xgaming/Purpur.git
branch = ver/1.16.5
[submodule "upstream/Airplane"]
path = upstream/Airplane
url = https://github.com/Technove/Airplane.git
branch = master
[submodule "upstream/Akarin"]
path = upstream/Akarin
url = https://github.com/Akarin-project/Akarin.git
branch = ver/1.16.5
[submodule "upstream/Empirecraft"]
path = upstream/Empirecraft
url = https://github.com/starlis/empirecraft.git
branch = master
[submodule "upstream/Origami"]
path = upstream/Origami
url = https://github.com/Minebench/Origami.git
branch = 1.16
[submodule "Yatopia-API"]
path = Yatopia-API
[submodule "Yatopia-Server"]
path = Yatopia-Server

View File

@ -1,473 +0,0 @@
# Patches
<!---
This file is autogenerated! Modify the .template.md to make changes!
--->
This is an overview of all the patches that are currently used.
| Side | Patch | Author | CoAuthors |
| ----- | ------------- |:-------------:| -----:|
| api | AFK API | William Blake Galbreath | |
| server | AFK API | William Blake Galbreath | |
| api | API for any mob to burn daylight | Ben Kerllenevich | |
| server | 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 | |
| api | Add EntityTeleportHinderedEvent | Mariell Hoversholm | |
| server | 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 | |
| api | Add StructureGenerateEvent | Nahuel | Mariell Hoversholm |
| server | 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 | |
| api | Add critical hit check to EntityDamagedByEntityEvent | BillyGalbreath | |
| server | 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 dolphin treasure searching | William Blake Galbreath | |
| server | Add option to disable mushroom and note block updates | William Blake Galbreath | |
| server | Add option to disable observer clocks | Phoenix616 | |
| api | Add option to disable zombie aggressiveness towards villagers | nitricspace | |
| server | 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 | |
| api | Add predicate to recipe&#39;s ExactChoice ingredient | William Blake Galbreath | |
| server | Add predicate to recipe&#39;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 twisting and weeping vines growth rates | BillyGalbreath | |
| api | Add unsafe Entity serialization API | Mariell Hoversholm | |
| server | 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 | |
| api | Advancement API | William Blake Galbreath | |
| server | Advancement API | William Blake Galbreath | |
| server | Airplane Branding Changes | Paul Sauve | |
| 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 | |
| api | Anvil API | William Blake Galbreath | |
| server | 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 | 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 | |
| api | Bring back server name | William Blake Galbreath | |
| server | 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 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 -&gt; | 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 | |
| server | Do not copy visible chunks | Spottedleaf | |
| server | Do not load chunks during a crash report | Spottedleaf | |
| server | Do not retain playerchunkmap instance in light thread factory | Spottedleaf | |
| server | Do not run close logic for inventories on chunk unload | Spottedleaf | |
| server | Do not run raytrace logic for AIR | Spottedleaf | |
| server | Do not update TE&#39;s in generating chunks | Spottedleaf | |
| server | Don&#39;t allow StructureLocateEvent to change worlds | Spottedleaf | |
| server | Don&#39;t get entity equipment if not needed | Paul Sauve | |
| server | Don&#39;t lookup fluid state when raytracing | Spottedleaf | |
| server | Don&#39;t read neighbour chunk data off disk when converting | Spottedleaf | |
| server | Don&#39;t trigger Lootable Refresh for non player interaction | Aikar | |
| server | Don&#39;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 | |
| api | EMC - MonsterEggSpawnEvent | Aikar | |
| server | 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 &#39;outdated server&#39; 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 squids! Oh my! | William Blake Galbreath | |
| api | Full netherite armor grants fire resistance | BillyGalbreath | |
| server | 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 | |
| api | Iron golem poppy calms anger | BillyGalbreath | |
| server | Iron golem poppy calms anger | BillyGalbreath | |
| api | Item entity immunities | William Blake Galbreath | |
| server | Item entity immunities | William Blake Galbreath | |
| server | Item stuck sleep config | tr7zw | |
| api | ItemFactory#getMonsterEgg | William Blake Galbreath | |
| server | 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 | |
| api | Lagging threshold | William Blake Galbreath | |
| server | Lagging threshold | William Blake Galbreath | |
| api | Left handed API | BillyGalbreath | |
| server | Left handed API | BillyGalbreath | |
| server | Lithium: CompactSineLUT | JellySquid | |
| api | LivingEntity safeFallDistance | William Blake Galbreath | |
| server | LivingEntity safeFallDistance | William Blake Galbreath | |
| api | LivingEntity#broadcastItemBreak | William Blake Galbreath | |
| server | LivingEntity#broadcastItemBreak | William Blake Galbreath | |
| api | Llama API | William Blake Galbreath | |
| server | 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 WorldServer#notify | Spottedleaf | |
| server | Optimise chunk tick iteration | Spottedleaf | |
| server | Optimise closest entity lookup | Spottedleaf | |
| server | Optimise collision checking in player move packet handling | Spottedleaf | |
| server | Optimise entity hard collision checking | Spottedleaf | |
| server | Optimise general POI access | Spottedleaf | |
| server | Optimise nearby player lookups | Spottedleaf | |
| server | Optimise non-flush packet sending | Spottedleaf | |
| server | Optimise snow &amp; ice in chunk ticking | Spottedleaf | |
| server | Optimise tab complete | Spottedleaf | |
| server | Optimised hallowen checker | Ivan Pekov | |
| server | Optimize BehaviorController | MrIvanPlays | |
| 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 | 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 | |
| api | Phantoms attracted to crystals and crystals shoot phantoms | William Blake Galbreath | |
| server | 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 | |
| api | Player invulnerabilities | William Blake Galbreath | |
| server | Player invulnerabilities | William Blake Galbreath | |
| api | PlayerAttackEntityEvent | Ivan Pekov | |
| server | PlayerAttackEntityEvent | Ivan Pekov | |
| api | PlayerSetSpawnerTypeWithEggEvent | William Blake Galbreath | |
| server | 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 | |
| api | Purpur config files | William Blake Galbreath | |
| server | 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 | Rebrand | William Blake Galbreath | |
| server | Redirect Configs | tr7zw | |
| server | Redstone deactivates spawners | draycia | |
| server | Reduce allocation rate from crammed entities | Spottedleaf | |
| server | Reduce allocs &amp; improve perf of StructureManager | Paul Sauve | |
| server | Reduce chunk loading &amp; lookups | Paul Sauve | |
| server | Reduce frequency of checking for entity despawn | Paul Sauve | |
| server | Reduce iterator allocation from chunk gen | Spottedleaf | |
| server | Reduce pathfinder branches | Spottedleaf | |
| server | Reduce projectile chunk loading | Paul Sauve | |
| server | Remove chunk lookup &amp; lambda allocation from counting mobs | Spottedleaf | |
| server | Remove iterators from inventory contains | Paul Sauve | |
| server | Remove some streams and object allocations | Phoenix616 | |
| server | Remove streams | Paul Sauve | |
| server | Remove streams for villager AI | Spottedleaf | |
| server | Replace player chunk loader system | Spottedleaf | |
| server | Replace ticket level propagator | Spottedleaf | |
| server | Revert MC-4 fix | Spottedleaf | |
| server | Revert getChunkAt(Async) retaining chunks for long periods of | Spottedleaf | |
| server | Rework PlayerChunk main thread checks | Spottedleaf | |
| server | Rewrite the light engine | Spottedleaf | |
| api | Ridables | William Blake Galbreath | |
| server | 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 | 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&#39;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 &amp; 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 |
| server | lithium HashedList | JellySquid | |
| server | lithium MixinBox | JellySquid | |
| server | lithium MixinDirection | JellySquid | |
| server | lithium NoiseChunkGeneratorMixin | JellySquid | |
| server | lithium PerlinNoiseSamplerMixin | JellySquid | Bud Gidiere |
| server | lithium VoronoiBiomeAccessTypeMixin | JellySquid | |
| server | lithium block | JellySquid | Hugo Planque |
| server | lithium entity | JellySquid | Hugo Planque |
| server | lithium enum_values | JellySquid | |
| server | lithium reduce allocations | JellySquid | Mykyta Komarnytskyy |
| server | lithium shape | JellySquid | Hugo Planque |
| server | lithium: cache chunk gen sea level | SuperCoder7979 | |
| server | lithium: optimize &#96;BlockPos.iterateOutwards&#96; by caching | 2No2Name | |
| server | lithium: skip ticking block entities that are doing nothing | 2No2Name | |
| server | tic-tacs: unblocking | Gegy | |

1
Paper

@ -1 +0,0 @@
Subproject commit 525d0e3d3752fa78e7c136a4d4bf13c3278691d9

View File

@ -1,11 +0,0 @@
repositories {
mavenCentral()
maven("https://jitpack.io/")
}
dependencies {
implementation("com.github.ishlandbukkit:jbsdiff:deff66b794")
implementation("com.google.code.gson:gson:2.8.6")
implementation("commons-io:commons-io:2.8.0")
}

View File

@ -1,28 +0,0 @@
package org.yatopiamc.yatoclip;
import java.lang.instrument.Instrumentation;
import java.nio.file.Path;
import java.util.jar.JarFile;
public class YatoclipLaunch {
private static Instrumentation inst = null;
public static void premain(String args, Instrumentation inst) {
YatoclipLaunch.inst = inst;
}
public static void agentmain(final String agentArgs, final Instrumentation inst) {
YatoclipLaunch.inst = inst;
}
@SuppressWarnings("unused")
static void injectClasspath(Path setup) throws Throwable {
if(inst == null) {
throw new RuntimeException("Instrumentation API handle not found");
}
inst.appendToSystemClassLoaderSearch(new JarFile(setup.toFile()));
inst = null;
}
}

View File

@ -1,51 +0,0 @@
package org.yatopiamc.yatoclip;
import java.io.Serializable;
import java.util.Collections;
import java.util.Objects;
import java.util.Set;
public class PatchesMetadata {
public final Set<PatchMetadata> patches;
public final Set<Relocation> relocations;
public final Set<String> copyExcludes;
public PatchesMetadata(Set<PatchMetadata> patches, Set<Relocation> relocations, Set<String> copyExcludes) {
Objects.requireNonNull(copyExcludes);
this.copyExcludes = Collections.unmodifiableSet(copyExcludes);
Objects.requireNonNull(relocations);
this.relocations = Collections.unmodifiableSet(relocations);
Objects.requireNonNull(patches);
this.patches = Collections.unmodifiableSet(patches);
}
public static class PatchMetadata {
public final String name;
public final String originalHash;
public final String targetHash;
public final String patchHash;
public PatchMetadata(String name, String originalHash, String targetHash, String patchHash) {
this.name = name;
this.originalHash = originalHash;
this.targetHash = targetHash;
this.patchHash = patchHash;
}
}
public static class Relocation implements Serializable {
public final String from;
public final String to;
public final boolean includeSubPackages;
public Relocation(String from, String to, boolean includeSubPackages) {
Objects.requireNonNull(from);
Objects.requireNonNull(to);
this.from = from.replaceAll("\\.", "/");
this.to = to.replaceAll("\\.", "/");
this.includeSubPackages = includeSubPackages;
}
}
}

View File

@ -1,360 +0,0 @@
package org.yatopiamc.yatoclip;
import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.net.URL;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.ReadableByteChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import static java.nio.file.StandardOpenOption.CREATE;
import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING;
import static java.nio.file.StandardOpenOption.WRITE;
public class ServerSetup {
private static final String minecraftVersion;
private static final Path cacheDirectory;
private static final Gson gson = new Gson();
private static VersionInfo versionInfo = null;
private static BuildDataInfo buildDataInfo = null;
static {
Properties prop = new Properties();
try (InputStream inputStream = ServerSetup.class.getClassLoader().getResourceAsStream("yatoclip-launch.properties")) {
prop.load(inputStream);
} catch (IOException e) {
throw new RuntimeException(e);
}
minecraftVersion = prop.getProperty("minecraftVersion");
cacheDirectory = Paths.get("cache", minecraftVersion);
cacheDirectory.toFile().mkdirs();
}
public static Path setup() throws IOException {
long startTime = System.nanoTime();
checkBuildData();
applyMappingsAndPatches();
System.err.println(String.format("Yatoclip server setup completed in %.2fms", (System.nanoTime() - startTime) / 1_000_000.0));
return cacheDirectory.resolve("Minecraft").resolve(minecraftVersion + "-patched.jar");
}
private static void applyMappingsAndPatches() throws IOException {
final Path minecraftDir = cacheDirectory.resolve("Minecraft");
minecraftDir.toFile().mkdirs();
final Path vanillaJar = minecraftDir.resolve(minecraftVersion + ".jar");
if (!isValidZip(vanillaJar)) {
System.err.println("Downloading vanilla jar...");
download(new URL(buildDataInfo.serverUrl), vanillaJar);
if (!isValidZip(vanillaJar)) throw new RuntimeException("Invalid vanilla jar");
}
final Path classMappedJar = minecraftDir.resolve(minecraftVersion + "-cl.jar");
final Path memberMappedJar = minecraftDir.resolve(minecraftVersion + "-m.jar");
final Path patchedJar = minecraftDir.resolve(minecraftVersion + "-patched.jar");
if (!isValidZip(classMappedJar) || !isValidZip(memberMappedJar)) {
SpecialSourceLauncher.resetSpecialSourceClassloader();
final Path buildData = cacheDirectory.resolve("BuildData");
SpecialSourceLauncher.setSpecialSourceJar(buildData.resolve("bin").resolve("SpecialSource-2.jar").toFile());
System.err.println("Applying class mapping...");
SpecialSourceLauncher.runProcess(
"map", "--only", ".", "--only", "net/minecraft", "--auto-lvt", "BASIC", "--auto-member", "SYNTHETIC",
"-i", vanillaJar.toAbsolutePath().toString(),
"-m", buildData.resolve("mappings").resolve(buildDataInfo.classMappings).toAbsolutePath().toString(),
"-o", classMappedJar.toAbsolutePath().toString()
);
System.err.println("Applying member mapping...");
SpecialSourceLauncher.runProcess(
"map", "--only", ".", "--only", "net/minecraft", "--auto-member", "LOGGER", "--auto-member", "TOKENS",
"-i", classMappedJar.toAbsolutePath().toString(),
"-m", buildData.resolve("mappings").resolve(buildDataInfo.memberMappings).toAbsolutePath().toString(),
"-o", memberMappedJar.toAbsolutePath().toString()
);
SpecialSourceLauncher.resetSpecialSourceClassloader();
if (!isValidZip(classMappedJar) || !isValidZip(memberMappedJar))
throw new RuntimeException("Unable to apply mappings");
}
if (!YatoclipPatcher.isJarUpToDate(patchedJar)){
System.err.println("Applying patches...");
YatoclipPatcher.patchJar(memberMappedJar, patchedJar);
if(!YatoclipPatcher.isJarUpToDate(patchedJar))
throw new RuntimeException("Unable to apply patches");
}
}
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
private static boolean isValidZip(Path zipPath) {
try {
ZipFile zipFile = new ZipFile(zipPath.toFile());
zipFile.close();
} catch (Throwable t) {
return false;
}
return true;
}
private static void checkBuildData() throws IOException {
final Path buildDataDir = cacheDirectory.resolve("BuildData");
buildDataDir.toFile().mkdirs();
final Path versionInfoFile = buildDataDir.resolve("version.json");
if (!tryParseVersionInfo(versionInfoFile)) {
System.err.println("Downloading version.json...");
final URL versionInfoURI = new URL("https://hub.spigotmc.org/versions/" + minecraftVersion + ".json");
download(versionInfoURI, versionInfoFile);
if (!tryParseVersionInfo(versionInfoFile)) throw new RuntimeException("Unable to parse versionInfo");
}
final Path buildDataArchive = buildDataDir.resolve("BuildData.zip");
if (!tryParseBuildData(buildDataArchive)) {
System.err.println("Downloading BuildData...");
final URL buildDataURL = new URL("https://hub.spigotmc.org/stash/rest/api/latest/projects/SPIGOT/repos/builddata/archive?at=" + ServerSetup.versionInfo.refs.buildData + "&format=zip");
download(buildDataURL, buildDataArchive);
if (!tryParseBuildData(buildDataArchive)) throw new RuntimeException("Unable to parse BuildData");
}
}
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
private static boolean tryParseBuildData(Path buildData) {
try {
ZipFile zipFile = new ZipFile(buildData.toFile());
((Iterator<ZipEntry>) zipFile.entries()).forEachRemaining(zipEntry -> {
if (zipEntry.isDirectory()) return;
buildData.getParent().resolve(zipEntry.getName()).getParent().toFile().mkdirs();
try (
final ReadableByteChannel source = Channels.newChannel(zipFile.getInputStream(zipEntry));
final FileChannel fileChannel = FileChannel.open(buildData.getParent().resolve(zipEntry.getName()), CREATE, WRITE, TRUNCATE_EXISTING)
) {
fileChannel.transferFrom(source, 0, Long.MAX_VALUE);
} catch (Throwable t) {
throw new RuntimeException(t);
}
});
zipFile.close();
try (Reader reader = Files.newBufferedReader(buildData.getParent().resolve("info.json"))){
ServerSetup.buildDataInfo = gson.fromJson(reader, BuildDataInfo.class);
}
} catch (Throwable t) {
return false;
}
return true;
}
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
private static boolean tryParseVersionInfo(Path versionInfo) {
try (Reader reader = Files.newBufferedReader(versionInfo)) {
ServerSetup.versionInfo = gson.fromJson(reader, VersionInfo.class);
} catch (Throwable t) {
return false;
}
return true;
}
private static void download(URL url, Path downloadTo) throws IOException {
try (
final ReadableByteChannel source = Channels.newChannel(url.openStream());
final FileChannel fileChannel = FileChannel.open(downloadTo, CREATE, WRITE, TRUNCATE_EXISTING)
) {
downloadTo.getParent().toFile().mkdirs();
fileChannel.transferFrom(source, 0, Long.MAX_VALUE);
}
}
static String toHex(final byte[] hash) {
final StringBuilder sb = new StringBuilder(hash.length * 2);
for (byte aHash : hash) {
sb.append(String.format("%02X", aHash & 0xFF));
}
return sb.toString();
}
public static class VersionInfo {
@SerializedName("refs")
private Refs refs;
@SerializedName("name")
private String name;
@SerializedName("description")
private String description;
@SerializedName("toolsVersion")
private int toolsVersion;
@SerializedName("javaVersions")
private List<Integer> javaVersions;
public Refs getRefs() {
return refs;
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
public int getToolsVersion() {
return toolsVersion;
}
public List<Integer> getJavaVersions() {
return javaVersions;
}
@Override
public String toString() {
return
"VersionInfo{" +
"refs = '" + refs + '\'' +
",name = '" + name + '\'' +
",description = '" + description + '\'' +
",toolsVersion = '" + toolsVersion + '\'' +
",javaVersions = '" + javaVersions + '\'' +
"}";
}
public static class Refs {
@SerializedName("BuildData")
private String buildData;
@SerializedName("CraftBukkit")
private String craftBukkit;
@SerializedName("Bukkit")
private String bukkit;
@SerializedName("Spigot")
private String spigot;
public String getBuildData() {
return buildData;
}
public String getCraftBukkit() {
return craftBukkit;
}
public String getBukkit() {
return bukkit;
}
public String getSpigot() {
return spigot;
}
@Override
public String toString() {
return
"Refs{" +
"buildData = '" + buildData + '\'' +
",craftBukkit = '" + craftBukkit + '\'' +
",bukkit = '" + bukkit + '\'' +
",spigot = '" + spigot + '\'' +
"}";
}
}
}
public static class BuildDataInfo {
@SerializedName("memberMapCommand")
private String memberMapCommand;
@SerializedName("packageMappings")
private String packageMappings;
@SerializedName("classMapCommand")
private String classMapCommand;
@SerializedName("finalMapCommand")
private String finalMapCommand;
@SerializedName("serverUrl")
private String serverUrl;
@SerializedName("toolsVersion")
private int toolsVersion;
@SerializedName("minecraftHash")
private String minecraftHash;
@SerializedName("minecraftVersion")
private String minecraftVersion;
@SerializedName("accessTransforms")
private String accessTransforms;
@SerializedName("memberMappings")
private String memberMappings;
@SerializedName("decompileCommand")
private String decompileCommand;
@SerializedName("classMappings")
private String classMappings;
public String getMemberMapCommand() {
return memberMapCommand;
}
public String getPackageMappings() {
return packageMappings;
}
public String getClassMapCommand() {
return classMapCommand;
}
public String getFinalMapCommand() {
return finalMapCommand;
}
public String getServerUrl() {
return serverUrl;
}
public int getToolsVersion() {
return toolsVersion;
}
public String getMinecraftHash() {
return minecraftHash;
}
public String getMinecraftVersion() {
return minecraftVersion;
}
public String getAccessTransforms() {
return accessTransforms;
}
public String getMemberMappings() {
return memberMappings;
}
public String getDecompileCommand() {
return decompileCommand;
}
public String getClassMappings() {
return classMappings;
}
}
}

View File

@ -1,89 +0,0 @@
package org.yatopiamc.yatoclip;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicReference;
public class SpecialSourceLauncher {
private static final AtomicReference<SpecialSourceClassLoader> classLoader = new AtomicReference<>(new SpecialSourceClassLoader(new URL[0], SpecialSourceLauncher.class.getClassLoader().getParent()));
private static final AtomicReference<String> mainClass = new AtomicReference<>("");
static void setSpecialSourceJar(File specialSourceJar) {
synchronized (classLoader) {
System.err.println("Setting up SpecialSource: " + specialSourceJar);
try {
classLoader.get().addURL(specialSourceJar.toURI().toURL());
mainClass.set(Yatoclip.getMainClass(specialSourceJar.toPath()));
} catch (IOException e) {
throw new IllegalArgumentException(e);
}
}
}
static void resetSpecialSourceClassloader() {
synchronized (classLoader) {
if(!classLoader.get().isLoaded) return;
System.err.println("Releasing SpecialSource");
try {
classLoader.get().close();
classLoader.set(new SpecialSourceClassLoader(new URL[0], SpecialSourceLauncher.class.getClassLoader().getParent()));
mainClass.set("");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
public static void runProcess(String... command) throws IOException {
if (!(command != null && command.length > 0)) throw new IllegalArgumentException();
System.err.println("Invoking SpecialSource with arguments: " + Arrays.toString(command));
AtomicReference<Throwable> thrown = new AtomicReference<>(null);
final Thread thread = new Thread(() -> {
try {
final Class<?> mainClass = Class.forName(SpecialSourceLauncher.mainClass.get(), true, classLoader.get());
final Method mainMethod = mainClass.getMethod("main", String[].class);
if (!Modifier.isStatic(mainMethod.getModifiers()) || !Modifier.isPublic(mainMethod.getModifiers()))
throw new IllegalArgumentException();
mainMethod.invoke(null, new Object[]{command});
} catch (Throwable t) {
thrown.set(t);
}
});
thread.setName("SpecialSource Thread");
thread.setContextClassLoader(classLoader.get());
thread.start();
while (thread.isAlive())
try {
thread.join();
} catch (InterruptedException ignored) {
}
if (thrown.get() != null)
throw new RuntimeException(thrown.get());
}
private static class SpecialSourceClassLoader extends URLClassLoader {
private volatile boolean isLoaded = false;
public SpecialSourceClassLoader(URL[] urls, ClassLoader parent) {
super(urls, parent);
}
@Override
protected synchronized void addURL(URL url) {
if (isLoaded) throw new IllegalStateException();
this.isLoaded = true;
super.addURL(url);
}
}
}

View File

@ -1,41 +0,0 @@
package org.yatopiamc.yatoclip;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.jar.JarInputStream;
public class Yatoclip {
public static void main(String... args) throws Throwable {
final Path setup = ServerSetup.setup();
launch(setup, args);
}
private static void launch(Path setup, String[] args) throws Throwable {
YatoclipLaunch.injectClasspath(setup);
final Class<?> mainClassInstance = Class.forName("org.bukkit.craftbukkit.Main", true, ClassLoader.getSystemClassLoader());
final Method mainMethod = mainClassInstance.getMethod("main", String[].class);
if(!Modifier.isPublic(mainMethod.getModifiers()) || !Modifier.isStatic(mainMethod.getModifiers())) throw new IllegalArgumentException();
mainMethod.invoke(null, new Object[]{args});
}
static String getMainClass(Path jarPath) throws IOException {
final String mainClass;
try (
InputStream inputStream = Files.newInputStream(jarPath);
JarInputStream jar = new JarInputStream(inputStream)
) {
mainClass = jar.getManifest().getMainAttributes().getValue("Main-Class");
}
return mainClass;
}
}

View File

@ -1,24 +0,0 @@
package org.yatopiamc.yatoclip;
import java.lang.instrument.Instrumentation;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Path;
public class YatoclipLaunch {
public static void premain(String args, Instrumentation inst) {
}
static void injectClasspath(Path setup) throws Throwable {
final ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
if(!(systemClassLoader instanceof URLClassLoader))
throw new ClassCastException("SystemClassLoader is not an instance of URLClassLoader");
final URLClassLoader classLoader = (URLClassLoader) systemClassLoader;
final Method addURL = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
addURL.setAccessible(true);
addURL.invoke(classLoader, setup.toUri().toURL());
}
}

View File

@ -1,236 +0,0 @@
package org.yatopiamc.yatoclip;
import com.google.gson.Gson;
import io.sigpipe.jbsdiff.InvalidHeaderException;
import io.sigpipe.jbsdiff.Patch;
import org.apache.commons.compress.compressors.CompressorException;
import org.apache.commons.io.IOUtils;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.file.Path;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.zip.Deflater;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;
import static java.util.Objects.requireNonNull;
public class YatoclipPatcher {
private static final PatchesMetadata patchesMetadata;
static {
try (
final InputStream in = YatoclipPatcher.class.getClassLoader().getResourceAsStream("patches/metadata.json");
final InputStreamReader reader = new InputStreamReader(in);
) {
patchesMetadata = new Gson().fromJson(reader, PatchesMetadata.class);
} catch (Throwable t) {
throw new RuntimeException(t);
}
}
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
static boolean isJarUpToDate(Path patchedJar) {
requireNonNull(patchedJar);
if (!patchedJar.toFile().isFile()) return false;
try {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
try (ZipFile patchedZip = new ZipFile(patchedJar.toFile())) {
for (PatchesMetadata.PatchMetadata patchMetadata : patchesMetadata.patches) {
ZipEntry zipEntry = patchedZip.getEntry(patchMetadata.name);
if (zipEntry == null || !patchMetadata.targetHash.equals(ServerSetup.toHex(digest.digest(IOUtils.toByteArray(patchedZip.getInputStream(zipEntry))))))
return false;
}
}
return true;
} catch (Throwable t) {
System.out.println(t.toString());
return false;
}
}
static void patchJar(Path memberMappedJar, Path patchedJar) {
requireNonNull(memberMappedJar);
requireNonNull(patchedJar);
if(!memberMappedJar.toFile().isFile()) throw new IllegalArgumentException(new FileNotFoundException());
try {
patchedJar.toFile().getParentFile().mkdirs();
final ThreadLocal<ZipFile> classMappedZip = ThreadLocal.withInitial(() -> {
try {
return new ZipFile(memberMappedJar.toFile());
} catch (IOException e) {
throw new RuntimeException(e);
}
});
final ThreadLocal<MessageDigest> digest = ThreadLocal.withInitial(() -> {
try {
return MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
});
ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors(), new ThreadFactory() {
private AtomicInteger serial = new AtomicInteger(0);
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(() -> {
try {
r.run();
} finally {
try {
classMappedZip.get().close();
} catch (IOException e) {
e.printStackTrace();
}
}
});
thread.setName("YatoClip Worker #" + serial.incrementAndGet());
thread.setDaemon(true);
return thread;
}
});
try {
final Set<PatchData> patchDataSet = patchesMetadata.patches.stream().map((PatchesMetadata.PatchMetadata metadata) -> new PatchData(CompletableFuture.supplyAsync(() -> {
try {
return getPatchedBytes(classMappedZip.get(), digest.get(), metadata);
} catch (IOException | CompressorException | InvalidHeaderException e) {
throw new RuntimeException(e);
}
}, executorService), metadata)).collect(Collectors.toSet());
try (ZipOutputStream patchedZip = new ZipOutputStream(new FileOutputStream(patchedJar.toFile()))) {
patchedZip.setMethod(ZipOutputStream.DEFLATED);
patchedZip.setLevel(Deflater.BEST_SPEED);
Set<String> processed = new HashSet<>();
for (PatchData patchData : patchDataSet) {
putNextEntrySafe(patchedZip, patchData.metadata.name);
final byte[] patchedBytes = patchData.patchedBytesFuture.join();
patchedZip.write(patchedBytes);
patchedZip.closeEntry();
processed.add(patchData.metadata.name);
}
((Iterator<ZipEntry>) classMappedZip.get().entries()).forEachRemaining(zipEntry -> {
if (zipEntry.isDirectory() || processed.contains(applyRelocations(zipEntry.getName())) || patchesMetadata.copyExcludes.contains(zipEntry.getName()))
return;
try {
InputStream in = classMappedZip.get().getInputStream(zipEntry);
putNextEntrySafe(patchedZip, zipEntry.getName());
patchedZip.write(IOUtils.toByteArray(in));
patchedZip.closeEntry();
} catch (Throwable t) {
throw new RuntimeException(t);
}
});
}
} catch (IOException e) {
throw new RuntimeException(e);
}
executorService.shutdown();
} catch (Throwable t) {
throw new RuntimeException(t);
}
}
private static byte[] getPatchedBytes(ZipFile classMappedZip, MessageDigest digest, PatchesMetadata.PatchMetadata patchMetadata) throws IOException, CompressorException, InvalidHeaderException {
final byte[] originalBytes;
final ZipEntry originalEntry = classMappedZip.getEntry(applyRelocationsReverse(patchMetadata.name));
if (originalEntry != null)
try (final InputStream in = classMappedZip.getInputStream(originalEntry)) {
originalBytes = IOUtils.toByteArray(in);
}
else originalBytes = new byte[0];
final byte[] patchBytes;
try (final InputStream in = YatoclipPatcher.class.getClassLoader().getResourceAsStream("patches/" + patchMetadata.name + ".patch")) {
if (in == null)
throw new FileNotFoundException();
patchBytes = IOUtils.toByteArray(in);
}
if (!patchMetadata.originalHash.equals(ServerSetup.toHex(digest.digest(originalBytes))) || !patchMetadata.patchHash.equals(ServerSetup.toHex(digest.digest(patchBytes))))
throw new FileNotFoundException("Hash do not match");
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
Patch.patch(originalBytes, patchBytes, byteOut);
final byte[] patchedBytes = byteOut.toByteArray();
if (!patchMetadata.targetHash.equals(ServerSetup.toHex(digest.digest(patchedBytes))))
throw new FileNotFoundException("Hash do not match");
return patchedBytes;
}
private static void putNextEntrySafe(ZipOutputStream patchedZip, String name) throws IOException {
String[] split = name.split("/");
split = Arrays.copyOfRange(split, 0, split.length - 1);
StringBuilder sb = new StringBuilder();
for (String s : split) {
sb.append(s).append("/");
try {
patchedZip.putNextEntry(new ZipEntry(sb.toString()));
} catch (ZipException e) {
if (e.getMessage().startsWith("duplicate entry"))
continue;
throw e;
}
}
final ZipEntry entry = new ZipEntry(name);
patchedZip.putNextEntry(entry);
}
private static String applyRelocations(String name) {
if (!name.endsWith(".class")) return name;
if (name.indexOf('/') == -1)
name = "/" + name;
for (PatchesMetadata.Relocation relocation : patchesMetadata.relocations) {
if (name.startsWith(relocation.from) && (relocation.includeSubPackages || name.split("/").length == name.split("/").length - 1)) {
return relocation.to + name.substring(relocation.from.length());
}
}
return name;
}
private static String applyRelocationsReverse(String name) {
if (!name.endsWith(".class")) return name;
if (name.indexOf('/') == -1)
name = "/" + name;
for (PatchesMetadata.Relocation relocation : patchesMetadata.relocations) {
if (name.startsWith(relocation.to) && (relocation.includeSubPackages || name.split("/").length == name.split("/").length - 1)) {
return relocation.from + name.substring(relocation.to.length());
}
}
return name;
}
private static class PatchData {
public final CompletableFuture<byte[]> patchedBytesFuture;
public final PatchesMetadata.PatchMetadata metadata;
private PatchData(CompletableFuture<byte[]> patchedBytesFuture, PatchesMetadata.PatchMetadata metadata) {
Objects.requireNonNull(patchedBytesFuture);
Objects.requireNonNull(metadata);
this.patchedBytesFuture = patchedBytesFuture.thenApply(Objects::requireNonNull);
this.metadata = metadata;
}
}
}

1
api
View File

@ -1 +0,0 @@
Yatopia-API/

View File

@ -1,69 +1,64 @@
plugins {
`java-library`
`maven-publish`
toothpick
java
id("com.github.johnrengelman.shadow") version "7.0.0" apply false
id("io.papermc.paperweight.patcher") version "1.0.0-SNAPSHOT"
}
toothpick {
forkName = "Yatopia"
groupId = "org.yatopiamc"
val versionTag = System.getenv("BUILD_NUMBER")
?: "\"${gitCmd("rev-parse", "--short", "HEAD").output}\""
if(!System.getenv("BRANCH_NAME").isNullOrEmpty()) {
currentBranch = System.getenv("BRANCH_NAME")
} else if (!System.getenv("GITHUB_HEAD_REF").isNullOrEmpty()) {
currentBranch = System.getenv("GITHUB_HEAD_REF")
} else if (!System.getenv("GITHUB_REF").isNullOrEmpty()) {
currentBranch = System.getenv("GITHUB_REF").substring("refs/heads/".length)
} else {
currentBranch = gitCmd("rev-parse", "--abbrev-ref", "HEAD").output.toString().trim()
if(currentBranch == "HEAD") logger.warn("You are currently in \'detached HEAD\' state, branch information isn\'t available")
repositories {
mavenCentral()
maven("https://wav.jfrog.io/artifactory/repo/") {
content {
onlyForConfigurations("paperclip")
}
}
forkVersion = "git-$forkName-$currentBranch-$versionTag"
forkUrl = "https://github.com/YatopiaMC/Yatopia"
minecraftVersion = "1.16.5"
nmsPackage = "1_16_R3"
nmsRevision = "R0.1-SNAPSHOT"
upstream = "Paper"
upstreamBranch = "origin/master"
paperclipName = "yatopia-$minecraftVersion-paperclip.jar"
patchCreditsOutput = "PATCHES.md"
patchCreditsTemplate = ".template.md"
server {
project = project(":$forkNameLowercase-server")
patchesDir = rootProject.projectDir.resolve("patches/server")
}
api {
project = project(":$forkNameLowercase-api")
patchesDir = rootProject.projectDir.resolve("patches/api")
maven("https://maven.quiltmc.org/repository/release/") {
content {
onlyForConfigurations("remapper")
}
}
}
logger.lifecycle("Configured version string: $calcVersionString")
dependencies {
remapper("org.quiltmc:tiny-remapper:0.4.1")
paperclip("io.papermc:paperclip:2.0.0-SNAPSHOT@jar")
}
subprojects {
repositories {
mavenCentral()
maven("https://repo.aikar.co/content/groups/aikar/")
maven("https://nexus.velocitypowered.com/repository/velocity-artifacts-snapshots/")
maven("https://libraries.minecraft.net")
maven("https://repo.codemc.io/repository/maven-public/")
maven("https://jitpack.io")
mavenLocal()
maven("${rootProjectDir}/.repository")
}
apply(plugin = "java")
java {
if(JavaVersion.VERSION_1_8 > JavaVersion.current()){
error("This build must be run with Java 8 or better")
toolchain {
languageVersion.set(JavaLanguageVersion.of(16))
}
}
tasks.withType<JavaCompile>().configureEach {
options.encoding = "UTF-8"
options.release.set(16)
}
repositories {
mavenCentral()
maven("https://oss.sonatype.org/content/groups/public/")
maven("https://papermc.io/repo/repository/maven-public/")
maven("https://ci.emc.gs/nexus/content/groups/aikar/")
maven("https://repo.aikar.co/content/groups/aikar")
maven("https://repo.md-5.net/content/repositories/releases/")
maven("https://hub.spigotmc.org/nexus/content/groups/public/")
maven("https://nexus.velocitypowered.com/repository/velocity-artifacts-snapshots/")
maven("https://oss.sonatype.org/content/repositories/snapshots/")
}
}
paperweight {
serverProject.set(project(":Yatopia-Server"))
usePaperUpstream(providers.gradleProperty("paperCommit")) {
withPaperPatcher {
apiPatchDir.set(layout.projectDirectory.dir("patches/api"))
apiOutputDir.set(layout.projectDirectory.dir("Yatopia-API"))
serverPatchDir.set(layout.projectDirectory.dir("patches/server"))
serverOutputDir.set(layout.projectDirectory.dir("Yatopia-Server"))
}
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.current()
withSourcesJar()
}
}

View File

@ -1,39 +0,0 @@
val kotlinxDomVersion = "0.0.10"
val shadowVersion = "7.0.0"
val mustacheVersion = "0.9.6"
val javaxMailVersion = "1.4.4"
plugins {
`kotlin-dsl`
}
repositories {
mavenCentral()
maven("https://plugins.gradle.org/m2/")
maven("https://jitpack.io/")
}
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx.dom:$kotlinxDomVersion")
implementation("com.github.johnrengelman:shadow:$shadowVersion")
implementation("com.github.spullara.mustache.java:compiler:$mustacheVersion")
implementation("javax.mail:mail:$javaxMailVersion")
implementation("com.github.ishlandbukkit:jbsdiff:deff66b794")
implementation("com.google.code.gson:gson:2.8.6")
implementation("com.google.guava:guava:30.0-jre")
implementation("commons-io:commons-io:2.8.0")
}
tasks.withType<JavaCompile> {
options.encoding = "UTF-8"
sourceCompatibility = "1.8"
}
gradlePlugin {
plugins {
register("Toothpick") {
id = "toothpick"
implementationClass = "Toothpick"
}
}
}

View File

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2020-2021 Jason Penilla & Contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,269 +0,0 @@
package org.yatopiamc.yatoclip.gradle;
import com.google.common.base.Preconditions;
import com.google.common.base.Throwables;
import com.google.common.collect.Sets;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.google.gson.Gson;
import io.sigpipe.jbsdiff.Diff;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.gradle.api.DefaultTask;
import org.gradle.api.internal.project.ProjectInternal;
import org.gradle.api.tasks.Copy;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.InputFile;
import org.gradle.api.tasks.OutputDirectory;
import org.gradle.api.tasks.TaskAction;
import org.gradle.internal.logging.progress.ProgressLogger;
import org.gradle.internal.logging.progress.ProgressLoggerFactory;
import org.gradle.work.Incremental;
import org.gradle.workers.WorkerExecutor;
import javax.inject.Inject;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
public class MakePatchesTask extends DefaultTask {
@OutputDirectory
private final File outputDir = ((Copy) getProject().getTasks().getByPath("processResources")).getDestinationDir().toPath().resolve("patches").toFile();
@InputFile
@Incremental
public File originalJar = null;
@InputFile
@Incremental
public File targetJar = null;
public Set<PatchesMetadata.Relocation> getRelocations() {
return relocations;
}
public void setRelocations(Set<PatchesMetadata.Relocation> relocations) {
this.relocations = relocations;
}
@Input
public Set<PatchesMetadata.Relocation> relocations;
public File getOriginalJar() {
return originalJar;
}
public void setOriginalJar(File originalJar) {
this.originalJar = originalJar;
}
public File getTargetJar() {
return targetJar;
}
public void setTargetJar(File targetJar) {
this.targetJar = targetJar;
}
public File getOutputDir() {
return outputDir;
}
private ProgressLoggerFactory getProgressLoggerFactory() {
return ((ProjectInternal) getProject()).getServices().get(ProgressLoggerFactory.class);
}
@Inject
public WorkerExecutor getWorkerExecutor() {
throw new UnsupportedOperationException();
}
@TaskAction
public void genPatches() throws IOException, InterruptedException {
Preconditions.checkNotNull(originalJar);
Preconditions.checkNotNull(targetJar);
getLogger().lifecycle("Generating patches for " + originalJar + " -> " + targetJar);
final ProgressLogger genPatches = getProgressLoggerFactory().newOperation(getClass()).setDescription("Generate patches");
genPatches.started();
genPatches.progress("Cleanup");
outputDir.mkdirs();
FileUtils.cleanDirectory(outputDir);
genPatches.progress("Reading files");
ThreadLocal<ZipFile> originalZip = ThreadLocal.withInitial(() -> {
try {
return new ZipFile(originalJar);
} catch (IOException e) {
throw new RuntimeException(e);
}
});
ThreadLocal<ZipFile> targetZip = ThreadLocal.withInitial(() -> {
try {
return new ZipFile(targetJar);
} catch (IOException e) {
throw new RuntimeException(e);
}
});
Set<PatchesMetadata.PatchMetadata> patchMetadata = Sets.newConcurrentHashSet();
ThreadLocal<MessageDigest> digestThreadLocal = ThreadLocal.withInitial(() -> {
try {
return MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
});
ThreadLocal<ProgressLogger> progressLoggerThreadLocal = ThreadLocal.withInitial(() -> {
final ProgressLogger progressLogger = getProgressLoggerFactory().newOperation(this.getClass());
progressLogger.setDescription("Patch worker");
progressLogger.started("Idle");
return progressLogger;
});
final ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors(),
new ThreadFactoryBuilder().setNameFormat("MakePatches-%d").setThreadFactory(r -> new Thread(() -> {
boolean isExceptionOccurred = false;
try {
r.run();
} catch (Throwable t) {
isExceptionOccurred = true;
progressLoggerThreadLocal.get().completed(t.toString(), true);
throw t;
} finally {
digestThreadLocal.remove();
if (!isExceptionOccurred)
progressLoggerThreadLocal.get().completed();
progressLoggerThreadLocal.remove();
try {
originalZip.get().close();
targetZip.get().close();
} catch (IOException e) {
e.printStackTrace();
}
}
})).build());
AtomicInteger current = new AtomicInteger(0);
final int size = targetZip.get().size();
((Iterator<ZipEntry>) targetZip.get().entries()).forEachRemaining(zipEntryT -> {
genPatches.progress("Submitting tasks (" + current.incrementAndGet() + "/" + size + ")");
if (zipEntryT.isDirectory()) return;
executorService.execute(() -> {
ZipEntry zipEntry = targetZip.get().getEntry(zipEntryT.getName());
final String child = zipEntry.getName();
progressLoggerThreadLocal.get().progress("Reading " + zipEntry.getName());
File outputFile = new File(outputDir, child + ".patch");
outputFile.getParentFile().mkdirs();
final byte[] originalBytes;
final byte[] targetBytes;
final ZipEntry oEntry = originalZip.get().getEntry(applyRelocationsReverse(child));
try (
final InputStream oin = oEntry != null ? originalZip.get().getInputStream(oEntry) : null;
final InputStream tin = targetZip.get().getInputStream(zipEntry);
) {
originalBytes = oin != null ? IOUtils.toByteArray(oin) : new byte[0];
targetBytes = IOUtils.toByteArray(tin);
} catch (Throwable e) {
Throwables.throwIfUnchecked(e);
throw new RuntimeException(e);
}
if (Arrays.equals(originalBytes, targetBytes)) return;
progressLoggerThreadLocal.get().progress("GenPatch " + zipEntry.getName());
try (final OutputStream out = new FileOutputStream(outputFile)) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
Diff.diff(originalBytes, targetBytes, byteArrayOutputStream);
patchMetadata.add(new PatchesMetadata.PatchMetadata(child, toHex(digestThreadLocal.get().digest(originalBytes)), toHex(digestThreadLocal.get().digest(targetBytes)), toHex(digestThreadLocal.get().digest(byteArrayOutputStream.toByteArray()))));
out.write(byteArrayOutputStream.toByteArray());
} catch (Throwable t) {
Throwables.throwIfUnchecked(t);
throw new RuntimeException(t);
}
progressLoggerThreadLocal.get().progress("Idle");
});
});
genPatches.progress("Calculating exclusions");
Set<String> copyExcludes = new HashSet<>();
((Iterator<ZipEntry>) originalZip.get().entries()).forEachRemaining(zipEntry -> {
if(targetZip.get().getEntry(applyRelocations(zipEntry.getName())) == null)
copyExcludes.add(zipEntry.getName());
});
originalZip.get().close();
targetZip.get().close();
genPatches.progress("Waiting for patching to finish");
executorService.shutdown();
while (!executorService.awaitTermination(1, TimeUnit.SECONDS)) ;
digestThreadLocal.remove();
genPatches.progress("Writing patches metadata");
try (final OutputStream out = new FileOutputStream(new File(outputDir, "metadata.json"));
final Writer writer = new OutputStreamWriter(out)) {
new Gson().toJson(new PatchesMetadata(patchMetadata, relocations, copyExcludes), writer);
}
/*
genPatches.progress("Reading jar files into memory");
byte[] origin = Files.readAllBytes(originalJar.toPath());
byte[] target = Files.readAllBytes(targetJar.toPath());
genPatches.progress("Generating patch");
try(final OutputStream out = new BufferedOutputStream(new FileOutputStream(output))){
Diff.diff(origin, target, out);
}
*/
genPatches.completed();
}
private String applyRelocations(String name) {
if(!name.endsWith(".class")) return name;
if (name.indexOf('/') == -1)
name = "/" + name;
for (PatchesMetadata.Relocation relocation : relocations) {
if (name.startsWith(relocation.from) && (relocation.includeSubPackages || name.split("/").length == name.split("/").length - 1)) {
return relocation.to + name.substring(relocation.from.length());
}
}
return name;
}
private String applyRelocationsReverse(String name) {
if(!name.endsWith(".class")) return name;
if (name.indexOf('/') == -1)
name = "/" + name;
for (PatchesMetadata.Relocation relocation : relocations) {
if (name.startsWith(relocation.to) && (relocation.includeSubPackages || name.split("/").length == name.split("/").length - 1)) {
return relocation.from + name.substring(relocation.to.length());
}
}
return name;
}
public static String toHex(final byte[] hash) {
final StringBuilder sb = new StringBuilder(hash.length * 2);
for (byte aHash : hash) {
sb.append(String.format("%02X", aHash & 0xFF));
}
return sb.toString();
}
}

View File

@ -1,51 +0,0 @@
package org.yatopiamc.yatoclip.gradle;
import java.io.Serializable;
import java.util.Collections;
import java.util.Objects;
import java.util.Set;
public class PatchesMetadata {
public final Set<PatchMetadata> patches;
public final Set<Relocation> relocations;
public final Set<String> copyExcludes;
public PatchesMetadata(Set<PatchMetadata> patches, Set<Relocation> relocations, Set<String> copyExcludes) {
Objects.requireNonNull(copyExcludes);
this.copyExcludes = Collections.unmodifiableSet(copyExcludes);
Objects.requireNonNull(relocations);
this.relocations = Collections.unmodifiableSet(relocations);
Objects.requireNonNull(patches);
this.patches = Collections.unmodifiableSet(patches);
}
public static class PatchMetadata {
public final String name;
public final String originalHash;
public final String targetHash;
public final String patchHash;
public PatchMetadata(String name, String originalHash, String targetHash, String patchHash) {
this.name = name;
this.originalHash = originalHash;
this.targetHash = targetHash;
this.patchHash = patchHash;
}
}
public static class Relocation implements Serializable {
public final String from;
public final String to;
public final boolean includeSubPackages;
public Relocation(String from, String to, boolean includeSubPackages) {
Objects.requireNonNull(from);
Objects.requireNonNull(to);
this.from = from.replaceAll("\\.", "/");
this.to = to.replaceAll("\\.", "/");
this.includeSubPackages = includeSubPackages;
}
}
}

View File

@ -1,22 +0,0 @@
package org.yatopiamc.yatoclip.gradle;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Path;
import java.util.Properties;
public class PropertiesUtils {
public static void saveProperties(Properties prop, Path file, String comments){
System.out.println("Saving properties file to " + file);
file.toFile().getParentFile().mkdirs();
file.toFile().delete();
try(final OutputStream out = new FileOutputStream(file.toFile())) {
prop.store(out, comments);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}

View File

@ -1,253 +0,0 @@
import com.github.jengelman.gradle.plugins.shadow.ShadowPlugin
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
// import com.github.jengelman.gradle.plugins.shadow.transformers.Log4j2PluginsCacheFileTransformer
import transformer.ModifiedLog4j2PluginsCacheFileTransformer
import relocation.ToothpickRelocator
import kotlinx.dom.elements
import kotlinx.dom.search
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.UnknownDomainObjectException
import org.gradle.api.plugins.JavaLibraryPlugin
import org.gradle.api.plugins.JavaPluginExtension
import org.gradle.api.publish.PublishingExtension
import org.gradle.api.publish.maven.MavenPublication
import org.gradle.api.publish.maven.plugins.MavenPublishPlugin
import org.gradle.api.publish.maven.tasks.GenerateMavenPom
import org.gradle.api.tasks.Copy
import org.gradle.api.tasks.bundling.Jar
import org.gradle.api.tasks.compile.JavaCompile
import org.gradle.api.tasks.javadoc.Javadoc
import org.gradle.api.tasks.testing.Test
import org.gradle.kotlin.dsl.*
import org.yatopiamc.yatoclip.gradle.MakePatchesTask
import org.yatopiamc.yatoclip.gradle.PatchesMetadata
import org.yatopiamc.yatoclip.gradle.PropertiesUtils
import java.nio.charset.StandardCharsets.UTF_8
import java.text.SimpleDateFormat
import java.util.*
import kotlin.collections.HashSet
internal fun Project.configureSubprojects() {
subprojects {
apply<JavaLibraryPlugin>()
apply<MavenPublishPlugin>()
tasks.withType<JavaCompile> {
options.encoding = UTF_8.name()
}
tasks.withType<Javadoc> {
options.encoding = UTF_8.name()
}
extensions.configure<PublishingExtension> {
publications {
create<MavenPublication>("mavenJava") {
groupId = rootProject.group as String
version = rootProject.version as String
pom {
name.set(project.name)
url.set(toothpick.forkUrl)
}
}
}
}
when {
project.name.endsWith("server") -> configureServerProject()
project.name.endsWith("api") -> configureApiProject()
}
}
rootProject.project("Yatoclip") {
configureYatoclipProject()
}
}
private fun Project.configureYatoclipProject() {
try {
rootProject.toothpick.serverProject.project.extensions.getByName("relocations")
} catch (e: UnknownDomainObjectException) {
return
}
apply<JavaLibraryPlugin>()
apply<ShadowPlugin>()
tasks.register<MakePatchesTask>("genPatches") {
originalJar = rootProject.toothpick.paperDir.resolve("work").resolve("Minecraft")
.resolve(rootProject.toothpick.minecraftVersion).resolve("${rootProject.toothpick.minecraftVersion}-m.jar")
targetJar = rootProject.toothpick.serverProject.project.tasks.getByName("shadowJar").outputs.files.singleFile
setRelocations(rootProject.toothpick.serverProject.project.extensions.getByName("relocations") as HashSet<PatchesMetadata.Relocation>)
dependsOn(rootProject.toothpick.serverProject.project.tasks.getByName("shadowJar"))
doLast {
val prop = Properties()
prop.setProperty("minecraftVersion", rootProject.toothpick.minecraftVersion)
PropertiesUtils.saveProperties(
prop,
outputDir.toPath().parent.resolve("yatoclip-launch.properties"),
"Yatoclip launch values"
)
}
}
val sourceSets = extensions.getByName("sourceSets") as org.gradle.api.tasks.SourceSetContainer
sourceSets.create("java9") {
java {
srcDir("src/java9")
}
}
val shadowJar by tasks.getting(ShadowJar::class) {
manifest {
attributes(
"Main-Class" to "org.yatopiamc.yatoclip.Yatoclip",
"Launcher-Agent-Class" to "org.yatopiamc.yatoclip.YatoclipLaunch",
"Premain-Class" to "org.yatopiamc.yatoclip.YatoclipLaunch",
"Multi-Release" to "true"
)
}
into("META-INF/versions/9") {
from(sourceSets.getByName("java9").output)
}
}
tasks.register<Copy>("copyJar") {
val targetName = "yatopia-${rootProject.toothpick.minecraftVersion}-yatoclip.jar"
from(shadowJar.outputs.files.singleFile) {
rename { targetName }
}
into(rootProject.projectDir)
doLast {
logger.lifecycle(">>> $targetName saved to root project directory")
}
dependsOn(shadowJar)
}
tasks.getByName("processResources").dependsOn(tasks.getByName("genPatches"))
tasks.getByName("assemble").dependsOn(tasks.getByName("copyJar"))
tasks.getByName("jar").enabled = false
val buildTask = tasks.getByName("build")
val buildTaskDependencies = HashSet(buildTask.dependsOn)
buildTask.setDependsOn(HashSet<Task>())
buildTask.onlyIf { false }
tasks.register("yatoclip") {
buildTaskDependencies.forEach {
dependsOn(it)
}
}
}
private fun Project.configureServerProject() {
apply<ShadowPlugin>()
val generatePomFileForMavenJavaPublication by tasks.getting(GenerateMavenPom::class) {
destination = project.buildDir.resolve("tmp/pom.xml")
}
tasks.withType<Test> {
// didn't bother to look into why these fail. paper excludes them in paperweight as well though
exclude("org/bukkit/craftbukkit/inventory/ItemStack*Test.class")
}
val shadowJar by tasks.getting(ShadowJar::class) {
archiveClassifier.set("") // ShadowJar is the main server artifact
dependsOn(generatePomFileForMavenJavaPublication)
transform(ModifiedLog4j2PluginsCacheFileTransformer::class.java)
mergeServiceFiles()
manifest {
attributes(
"Main-Class" to "org.bukkit.craftbukkit.Main",
"Implementation-Title" to "CraftBukkit",
"Implementation-Version" to toothpick.forkVersion,
"Implementation-Vendor" to SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'").format(Date()),
"Specification-Title" to "Bukkit",
"Specification-Version" to "${project.rootProject.toothpick.minecraftVersion}-${project.rootProject.toothpick.nmsRevision}",
"Specification-Vendor" to "Bukkit Team"
)
}
from(project.buildDir.resolve("tmp/pom.xml")) {
// dirty hack to make "java -Dpaperclip.install=true -jar paperclip.jar" work without forking paperclip
into("META-INF/maven/io.papermc.paper/paper")
}
val relocationSet = HashSet<PatchesMetadata.Relocation>()
// Don't like to do this but sadly have to do this for compatibility reasons
relocate("org.bukkit.craftbukkit", "org.bukkit.craftbukkit.v${toothpick.nmsPackage}") {
exclude("org.bukkit.craftbukkit.Main*")
}
relocationSet.add(PatchesMetadata.Relocation("", "net.minecraft.server.v${toothpick.nmsPackage}", false))
// Make sure we relocate deps the same as Paper et al.
val dom = project.parsePom() ?: return@getting
val buildSection = dom.search("build").first()
val plugins = buildSection.search("plugins").first()
plugins.elements("plugin").filter {
val artifactId = it.search("artifactId").first().textContent
artifactId == "maven-shade-plugin"
}.forEach {
it.search("executions").first()
.search("execution").first()
.search("configuration").first()
.search("relocations").first()
.elements("relocation").forEach { relocation ->
val pattern = relocation.search("pattern").first().textContent
val shadedPattern = relocation.search("shadedPattern").first().textContent
val rawString = relocation.search("rawString").firstOrNull()?.textContent?.toBoolean() ?: false
if (pattern != "org.bukkit.craftbukkit") { // We handle cb ourselves
val excludes = if (rawString) listOf("net/minecraft/data/Main*") else emptyList()
relocate(
ToothpickRelocator(
pattern,
shadedPattern.replace("\${minecraft_version}", toothpick.nmsPackage),
rawString,
excludes = excludes
)
)
relocationSet.add(PatchesMetadata.Relocation(pattern, shadedPattern, true))
}
}
}
project.extensions.add("relocations", relocationSet)
}
tasks.getByName("build") {
dependsOn(shadowJar)
}
extensions.configure<PublishingExtension> {
publications {
create<MavenPublication>("shadow") {
artifact(project.tasks.named("shadowJar"))
}
}
}
}
@Suppress("UNUSED_VARIABLE")
private fun Project.configureApiProject() {
val jar by this.tasks.getting(Jar::class) {
doFirst {
buildDir.resolve("tmp/pom.properties")
.writeText("version=${project.rootProject.toothpick.minecraftVersion}-${project.rootProject.toothpick.nmsRevision}")
}
from(buildDir.resolve("tmp/pom.properties")) {
into("META-INF/maven/${project.group}/${project.name}")
}
manifest {
attributes("Automatic-Module-Name" to "org.bukkit")
}
}
extensions.configure<PublishingExtension> {
publications {
getByName<MavenPublication>("mavenJava") {
artifactId = project.name
from(components["java"])
}
}
}
}

View File

@ -1,2 +0,0 @@
const val taskGroup = "toothpick"
const val internalTaskGroup = "toothpick_internal"

View File

@ -1,72 +0,0 @@
import kotlinx.dom.elements
import kotlinx.dom.search
import org.gradle.api.Project
import org.gradle.api.artifacts.dsl.RepositoryHandler
import org.gradle.kotlin.dsl.DependencyHandlerScope
import org.gradle.kotlin.dsl.maven
import org.gradle.kotlin.dsl.project
import org.w3c.dom.Element
fun RepositoryHandler.loadRepositories(project: Project) {
val dom = project.parsePom() ?: return
val repositoriesBlock = dom.search("repositories").firstOrNull() ?: return
// Load repositories
repositoriesBlock.elements("repository").forEach { repositoryElem ->
val url = repositoryElem.search("url").firstOrNull()?.textContent ?: return@forEach
maven(url)
}
}
fun DependencyHandlerScope.loadDependencies(project: Project) {
val dom = project.parsePom() ?: return
// Load dependencies
dom.search("dependencies").forEach {
loadDependencies(project, it)
}
}
private fun DependencyHandlerScope.loadDependencies(project: Project, dependenciesBlock: Element) {
dependenciesBlock.elements("dependency").forEach { dependencyElem ->
val groupId = dependencyElem.search("groupId").first().textContent
val artifactId = dependencyElem.search("artifactId").first().textContent
val version = dependencyElem.search("version").firstOrNull()?.textContent
val scope = dependencyElem.search("scope").firstOrNull()?.textContent
val classifier = dependencyElem.search("classifier").firstOrNull()?.textContent
val dependencyString =
"$groupId:$artifactId${processOptionalDependencyElement(version)}${processOptionalDependencyElement(classifier)}"
project.logger.debug("Read $scope scope dependency '$dependencyString' from '${project.name}' pom.xml")
// Special case API
if (artifactId == project.toothpick.apiProject.project.name
|| artifactId == "${project.toothpick.upstreamLowercase}-api"
) {
if (project == project.toothpick.serverProject.project) {
add("api", project(":${project.toothpick.forkNameLowercase}-api"))
}
return@forEach
}
when (scope) {
"import" -> add("api", platform(dependencyString))
"compile", null -> {
add("api", dependencyString)
if (version != null) {
add("annotationProcessor", dependencyString)
}
}
"provided" -> {
add("compileOnly", dependencyString)
add("testImplementation", dependencyString)
add("annotationProcessor", dependencyString)
}
"runtime" -> add("runtimeOnly", dependencyString)
"test" -> add("testImplementation", dependencyString)
}
}
}
private fun processOptionalDependencyElement(element: String?): String =
element?.run { ":$this" } ?: ""

View File

@ -1,74 +0,0 @@
import org.gradle.api.Project
import org.gradle.api.tasks.javadoc.Javadoc
import org.gradle.api.tasks.testing.Test
import org.gradle.kotlin.dsl.withType
import task.*
@Suppress("UNUSED_VARIABLE")
internal fun Project.initToothpickTasks() {
gradle.taskGraph.whenReady {
val fast = project.hasProperty("fast")
tasks.withType<Test> {
onlyIf { !fast }
}
tasks.withType<Javadoc> {
onlyIf { !fast || gradle.taskGraph.allTasks.any { it.name.contains("publish", ignoreCase = true) } }
}
}
tasks.getByName("build") {
doFirst {
val readyToBuild =
upstreamDir.resolve(".git").exists()
&& toothpick.subprojects.values.all { it.projectDir.exists() && it.baseDir.exists() }
if (!readyToBuild) {
error("Workspace has not been setup. Try running `./gradlew applyPatches` first")
}
}
}
val initGitSubmodules = createInitGitSubmodulesTask()
val setupUpstream = createSetupUpstreamTask {
dependsOn(initGitSubmodules)
}
val importMCDev = createImportMCDevTask {
mustRunAfter(setupUpstream)
}
val paperclip = createPaperclipTask {
val shadowJar = toothpick.serverProject.project.tasks.getByName("shadowJar")
dependsOn(shadowJar)
inputs.file(shadowJar.outputs.files.singleFile)
}
val applyPatches = createApplyPatchesTask {
// If Paper has not been setup yet or if we modified the submodule (i.e. upstream update), patch
if (!lastUpstream.exists()
|| !upstreamDir.resolve(".git").exists()
|| lastUpstream.readText() != gitHash(upstreamDir)
) {
dependsOn(setupUpstream)
}
mustRunAfter(setupUpstream)
dependsOn(importMCDev)
}
val patchCredits = createPatchCreditsTask()
val fixBranch = createFixBranchesTask()
val rebuildPatches = createRebuildPatchesTask {
dependsOn(fixBranch)
finalizedBy(patchCredits)
}
val updateUpstream = createUpdateUpstreamTask {
finalizedBy(setupUpstream)
}
val upstreamCommit = createUpstreamCommitTask()
val repackageNMS = createRepackageNMSTask()
}

View File

@ -1,45 +0,0 @@
/**
* This is the set of extra NMS files which will be imported as part of the patch process
*
* See `./Paper/work/Minecraft/$MCVER/spigot/net/minecraft/server` for a list of possible files
*
* The `.java` extension is always assumed and should be excluded
*
* NOTE: Do not commit changes to this set! Instead make changes, rebuild patches, and commit the modified patches.
* Files already modified in existing patches will be imported automatically.
*/
val nmsImports = setOf<String>(
// ex:
//"EntityZombieVillager"
)
data class LibraryImport(val group: String, val library: String, val prefix: String, val file: String)
/**
* This is the set of extra files to import into the server workspace from libraries
*
* Changes to this set should be committed to the repo, as these won't be automatically imported.
*/
val libraryImports = setOf<LibraryImport>(
LibraryImport("com.mojang", "brigadier", "com/mojang/brigadier", "CommandDispatcher"),
LibraryImport("com.mojang", "brigadier", "com/mojang/brigadier/tree", "LiteralCommandNode"),
LibraryImport("com.mojang", "brigadier", "com/mojang/brigadier/suggestion", "SuggestionsBuilder"),
LibraryImport("com.mojang", "brigadier", "com/mojang/brigadier/arguments", "BoolArgumentType"),
LibraryImport("com.mojang", "datafixerupper", "com/mojang/datafixers", "FieldFinder"),
LibraryImport("com.mojang", "datafixerupper", "com/mojang/datafixers", "DataFixUtils"),
LibraryImport("com.mojang", "datafixerupper", "com/mojang/datafixers", "TypeRewriteRule"),
LibraryImport("com.mojang", "datafixerupper", "com/mojang/datafixers", "Typed"),
LibraryImport("com.mojang", "datafixerupper", "com/mojang/datafixers", "TypedOptic"),
LibraryImport("com.mojang", "datafixerupper", "com/mojang/datafixers", "View"),
LibraryImport("com.mojang", "datafixerupper", "com/mojang/datafixers/functions", "Apply"),
LibraryImport("com.mojang", "datafixerupper", "com/mojang/datafixers/functions", "Comp"),
LibraryImport("com.mojang", "datafixerupper", "com/mojang/datafixers/functions", "PointFree"),
LibraryImport("com.mojang", "datafixerupper", "com/mojang/datafixers/functions", "PointFreeRule"),
LibraryImport("com.mojang", "datafixerupper", "com/mojang/datafixers/optics", "IdAdapter"),
LibraryImport("com.mojang", "datafixerupper", "com/mojang/datafixers/optics", "Inj1"),
LibraryImport("com.mojang", "datafixerupper", "com/mojang/datafixers/optics", "Inj2"),
LibraryImport("com.mojang", "datafixerupper", "com/mojang/datafixers/optics", "Optics"),
LibraryImport("com.mojang", "datafixerupper", "com/mojang/datafixers/optics", "Proj1"),
LibraryImport("com.mojang", "datafixerupper", "com/mojang/datafixers/optics", "Proj2"),
LibraryImport("com.mojang", "datafixerupper", "com/mojang/datafixers/types", "Type")
)

View File

@ -1,77 +0,0 @@
import java.io.File
import java.io.IOException
import java.io.UnsupportedEncodingException
import java.nio.charset.StandardCharsets
import java.nio.file.Files
import java.util.*
import java.util.function.Function
import javax.mail.internet.MimeUtility
/**
* Rudimentary parser to get Author, subject and coAuthors of a patch file
*
* @author tr7zw
*/
object PatchParser {
fun parsePatch(file: File): PatchInfo {
val lines: List<String> = Files.readAllLines(file.toPath(), StandardCharsets.UTF_8)
var from: String = "Unknown"
var subject: String = "Unknown"
val coAuthors: MutableList<String> = ArrayList()
for (line: String in lines) {
when {
line.startsWith("From: ") -> {
from =
decodeStringIfNeeded(line.replace("From: ", "").split("<").toTypedArray()[0].trim { it <= ' ' })
}
line.startsWith("Subject: ") -> {
subject = line.replace("Subject: ", "").replace("[PATCH]", "").trim { it <= ' ' }
}
line.startsWith("Co-authored-by: ") -> {
coAuthors.add(
decodeStringIfNeeded(
line.replace("Co-authored-by: ", "").split("<").toTypedArray()[0].trim { it <= ' ' })
)
}
}
}
return PatchInfo(file.parentFile.name, from, subject, coAuthors)
}
private fun decodeStringIfNeeded(org: String): String {
if (org.contains("=") || org.startsWith("=?UTF-8")) {
try {
return MimeUtility.decodeText(org)
} catch (ex: UnsupportedEncodingException) {
throw IOException(ex)
}
}
return org
}
class PatchInfo(val parent: String, val from: String, val subject: String, val coAuthors: List<String>) {
val coAuthorString: Function<String, String>
get() = Function {
java.lang.String.join(
", ",
coAuthors
)
}
override fun toString(): String {
return ("PatchInfo{"
+ "parent='"
+ parent
+ '\''
+ ", from='"
+ from
+ '\''
+ ", subject='"
+ subject
+ '\''
+ ", coAuthors="
+ coAuthors
+ '}')
}
}
}

View File

@ -1,55 +0,0 @@
/*
* This file is part of Toothpick, licensed under the MIT License.
*
* Copyright (c) 2020-2021 Jason Penilla & Contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import kotlinx.dom.elements
import kotlinx.dom.parseXml
import kotlinx.dom.search
import org.gradle.api.Project
import org.w3c.dom.Document
internal fun Project.parsePom(): Document? {
val file = file("pom.xml")
if (!file.exists()) {
return null
}
val contents = file.readText()
val dom = parseXml(contents.byteInputStream())
val properties = dom.search("properties").firstOrNull()?.elements() ?: emptyList()
val propertiesMap = properties.associateBy({ it.nodeName }, { it.textContent }).toMutableMap()
propertiesMap["project.version"] = project.version.toString()
propertiesMap["minecraft.version"] = toothpick.minecraftVersion
propertiesMap["minecraft_version"] = toothpick.nmsPackage
return parseXml(contents.replaceProperties(propertiesMap).byteInputStream())
}
private fun String.replaceProperties(
properties: Map<String, String>
): String {
var result = this
for ((key, value) in properties) {
result = result.replace("\${$key}", value)
}
return result
}

View File

@ -1,9 +0,0 @@
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.create
class Toothpick : Plugin<Project> {
override fun apply(project: Project) {
project.extensions.create<ToothpickExtension>("toothpick", project.objects)
}
}

View File

@ -1,93 +0,0 @@
import org.gradle.api.Project
import org.gradle.api.model.ObjectFactory
import java.io.File
import java.io.FileInputStream
import java.util.*
import java.util.stream.Collectors
import kotlin.collections.ArrayList
@Suppress("UNUSED_PARAMETER")
open class ToothpickExtension(objects: ObjectFactory) {
lateinit var project: Project
lateinit var forkName: String
val forkNameLowercase
get() = forkName.toLowerCase(Locale.ENGLISH)
lateinit var forkUrl: String
lateinit var forkVersion: String
lateinit var groupId: String
lateinit var minecraftVersion: String
lateinit var nmsRevision: String
lateinit var nmsPackage: String
lateinit var upstream: String
val upstreamLowercase
get() = upstream.toLowerCase(Locale.ENGLISH)
var upstreamBranch: String = "origin/master"
var paperclipName: String? = null
val calcPaperclipName
get() = paperclipName ?: "${forkNameLowercase}-paperclip.jar"
lateinit var serverProject: ToothpickSubproject
lateinit var patchCreditsOutput: String
lateinit var patchCreditsTemplate: String
lateinit var currentBranch : String
val currentBranchDisplayName
get() = currentBranch.replace("/${minecraftVersion}", "")
val calcVersionString
get() = "${minecraftVersion}-${nmsRevision}"
fun server(receiver: ToothpickSubproject.() -> Unit) {
serverProject = ToothpickSubproject()
receiver(serverProject)
}
lateinit var apiProject: ToothpickSubproject
fun api(receiver: ToothpickSubproject.() -> Unit) {
apiProject = ToothpickSubproject()
receiver(apiProject)
}
val subprojects: Map<String, ToothpickSubproject>
get() = if (::forkName.isInitialized) mapOf(
"$forkName-API" to apiProject,
"$forkName-Server" to serverProject
) else emptyMap()
val paperDir: File by lazy {
if (upstream == "Paper") {
project.upstreamDir
} else {
project.upstreamDir.walk().find {
it.name == "Paper" && it.isDirectory
&& it.resolve("work/Minecraft/${minecraftVersion}").exists()
} ?: error("Failed to find Paper directory!")
}
}
val paperDecompDir: File
get() = paperDir.resolve("work/Minecraft/${minecraftVersion}")
val paperWorkDir: File
get() = paperDir.resolve("work")
fun getUpstreams(rootProjectDir: File): MutableList<Upstream>? {
val configDir = rootProjectDir.resolve("$rootProjectDir/upstreamConfig")
val upstreams = configDir.listFiles()
val upstreamArray = ArrayList<Upstream>()
val prop = Properties()
for (upstream in upstreams) {
prop.load(FileInputStream(upstream))
upstreamArray.add(Upstream(prop.getProperty("name"),
prop.getProperty("useBlackList")!!.toBoolean(),
(prop.getProperty("list")),
rootProjectDir,
prop.getProperty("branch"),
Integer.parseInt(upstream.name.substring(0,4)),
project))
}
return upstreamArray.stream().sorted { upstream1, upstream2 -> upstream1.id - upstream2.id}.collect(Collectors.toList())
}
}

View File

@ -1,41 +0,0 @@
import org.gradle.api.Project
import org.gradle.kotlin.dsl.findByType
import java.io.File
val Project.toothpick: ToothpickExtension
get() = rootProject.extensions.findByType(ToothpickExtension::class)!!
fun Project.toothpick(receiver: ToothpickExtension.() -> Unit) {
toothpick.project = this
receiver(toothpick)
allprojects {
group = toothpick.groupId
version = toothpick.calcVersionString
}
configureSubprojects()
initToothpickTasks()
}
val Project.lastUpstream: File
get() = rootProject.projectDir.resolve("last-${toothpick.upstreamLowercase}")
val Project.rootProjectDir: File
get() = rootProject.projectDir
val Project.upstreamDir: File
get() = rootProject.projectDir.resolve(toothpick.upstream)
val Project.upstream: String
get() = toothpick.upstream
val Project.upstreams: MutableList<Upstream>
get() = toothpick.getUpstreams(rootProject.projectDir) as MutableList<Upstream>
val Project.forkName: String
get() = toothpick.forkName
val Project.patchCreditsOutput: String
get() = toothpick.patchCreditsOutput
val Project.patchCreditsTemplate: String
get() = toothpick.patchCreditsTemplate

View File

@ -1,20 +0,0 @@
import org.gradle.api.Project
import java.io.File
class ToothpickSubproject {
lateinit var project: Project
val baseDir: File by lazy {
val name = project.name
val upstream = project.toothpick.upstream
val suffix = if (name.endsWith("server")) "Server" else "API"
project.upstreamDir.resolve("$upstream-$suffix")
}
val projectDir: File
get() = project.projectDir
lateinit var patchesDir: File
operator fun component1(): File = baseDir
operator fun component2(): File = projectDir
operator fun component3(): File = patchesDir
}

View File

@ -1,88 +0,0 @@
import org.gradle.api.Project
import java.io.File
import java.io.FileWriter
import java.nio.file.Files
import java.nio.file.Paths
import java.util.stream.Collectors
open class Upstream(in_name: String, in_useBlackList: Boolean, in_list: String, in_rootProjectDir: File, in_branch: String, in_id: Int, in_project: Project) {
var name: String = in_name
var useBlackList: Boolean = in_useBlackList
private var list: ArrayList<String> = ArrayList(in_list.split(",".toRegex()))
private var rootProjectDir: File = in_rootProjectDir
var branch = in_branch
var id = in_id
var serverList = list.stream().filter { patch -> patch.startsWith("server/") }
?.sorted()?.map { patch -> patch.substring(7, patch.length) }?.collect(Collectors.toList())
var apiList = list.stream().filter { patch -> patch.startsWith("api/") }
?.sorted()?.map { patch -> patch.substring(4, patch.length) }?.collect(Collectors.toList())
var patchPath = Paths.get("$rootProjectDir/patches/$name/patches")
var repoPath = Paths.get("$rootProjectDir/upstream/$name")
var project = in_project
var upstreamCommit = getUpstreamCommitHash()
private fun getUpstreamCommitHash(): String {
val commitFileFolder = Paths.get("$rootProjectDir/upstreamCommits")
val commitFilePath = Paths.get("$commitFileFolder/$name")
val commitFile = commitFilePath.toFile()
var commitHash: String
if (commitFile.isFile) {
commitHash = Files.readAllLines(commitFilePath).toString()
commitHash = commitHash.substring(1, commitHash.length - 1)
if (commitHash == "") {
commitHash = updateHashFile(commitFile)
}
} else {
Files.createFile(commitFilePath)
commitHash = updateHashFile(commitFile)
}
return commitHash;
}
public fun updateUpstreamCommitHash() {
val commitFileFoler = Paths.get("$rootProjectDir/upstreamCommits")
val commitFilePath = Paths.get("$commitFileFoler/$name")
val commitFile = commitFilePath.toFile()
updateHashFile(commitFile)
upstreamCommit = getUpstreamCommitHash()
}
public fun getCurrentCommitHash(): String {
return project.getCommitHash()
}
private fun updateHashFile(commitFile: File): String {
var commitHash: String
commitHash = project.getCommitHash()
val fileWriter = FileWriter(commitFile)
fileWriter.use { out -> out.write(commitHash) }
fileWriter.close()
return commitHash
}
private fun Project.getCommitHash(): String = gitHash(repo = repoPath.toFile())
public fun getRepoServerPatches(): MutableList<String>? {
return getRepoPatches(rootProjectDir.resolve("$repoPath/patches/server")).stream()
.sorted().map {patch -> patch.substring(5, patch.length) }.collect(Collectors.toList())
}
public fun getRepoAPIPatches(): MutableList<String>? {
return getRepoPatches(rootProjectDir.resolve("$repoPath/patches/api")).stream()
.sorted().map {patch -> patch.substring(5, patch.length) }.collect(Collectors.toList())
}
private fun getRepoPatches(path: File): ArrayList<String> {
val files = path.listFiles()
val filesList = ArrayList<String>()
for (patch in files) {
filesList.add(patch.name)
}
return filesList
}
}

View File

@ -1,92 +0,0 @@
import org.gradle.api.Project
import java.io.File
import java.util.*
import kotlin.streams.asSequence
data class CmdResult(val exitCode: Int, val output: String?)
fun Project.cmd(
vararg args: String,
dir: File = rootProject.projectDir,
printOut: Boolean = false,
environment: Map<String, String> = emptyMap()
): CmdResult {
val process = ProcessBuilder().apply {
command(*args)
redirectErrorStream(true)
directory(dir)
environment().putAll(environment)
}.start()
val output = process.inputStream.bufferedReader().use { reader ->
reader.lines().asSequence()
.onEach {
if (printOut) {
logger.lifecycle(it)
} else {
logger.debug(it)
}
}
.toCollection(LinkedList())
.joinToString(separator = "\n")
}
val exit = process.waitFor()
return CmdResult(exit, output)
}
fun ensureSuccess(
cmd: CmdResult,
errorHandler: CmdResult.() -> Unit = {}
): String? {
val (exit, output) = cmd
if (exit != 0) {
errorHandler(cmd)
error("Failed to run command, exit code is $exit")
}
return output
}
fun Project.gitCmd(
vararg args: String,
dir: File = rootProject.projectDir,
printOut: Boolean = false,
environment: Map<String, String> = emptyMap()
): CmdResult =
cmd("git", *args, dir = dir, printOut = printOut)
fun Project.bashCmd(
vararg args: String,
dir: File = rootProject.projectDir,
printOut: Boolean = false,
environment: Map<String, String> = emptyMap()
): CmdResult =
cmd("bash", "-c", *args, dir = dir, printOut = printOut)
internal fun String.applyReplacements(
vararg replacements: Pair<String, String>
): String {
var result = this
for ((key, value) in replacements) {
result = result.replace("\${$key}", value)
}
return result
}
private fun Project.gitSigningEnabled(repo: File): Boolean =
gitCmd("config", "commit.gpgsign", dir = repo).output?.toBoolean() == true
internal fun Project.temporarilyDisableGitSigning(repo: File): Boolean {
val isCurrentlyEnabled = gitSigningEnabled(repo)
if (isCurrentlyEnabled) {
gitCmd("config", "commit.gpgsign", "false", dir = repo)
}
return isCurrentlyEnabled
}
internal fun Project.reEnableGitSigning(repo: File) {
gitCmd("config", "commit.gpgsign", "true", dir = repo)
}
fun Project.gitHash(repo: File): String =
gitCmd("rev-parse", "HEAD", dir = repo).output ?: ""
val jenkins = System.getenv("JOB_NAME") != null

View File

@ -1,58 +0,0 @@
/*
* This file is part of Toothpick, licensed under the MIT License.
*
* Copyright (c) 2020-2021 Jason Penilla & Contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package relocation
import com.github.jengelman.gradle.plugins.shadow.relocation.Relocator
import com.github.jengelman.gradle.plugins.shadow.relocation.SimpleRelocator
import java.lang.reflect.Method
import java.util.regex.Pattern
internal class ToothpickRelocator(
pattern: String,
shadedPattern: String,
rawString: Boolean = false,
includes: List<String> = emptyList(),
excludes: List<String> = emptyList(),
private val simpleRelocator: SimpleRelocator = SimpleRelocator(pattern, shadedPattern, includes, excludes, rawString)
) : Relocator by simpleRelocator {
override fun canRelocatePath(path: String): Boolean {
// Respect includes/excludes for rawString too
if (simpleRelocator.rawString) {
return isIncludedMethod(simpleRelocator, path) as Boolean
&& !(isExcludedMethod(simpleRelocator, path) as Boolean)
&& Pattern.compile(simpleRelocator.pathPattern).matcher(path).find()
}
return simpleRelocator.canRelocatePath(path)
}
companion object {
private val isExcludedMethod: Method = SimpleRelocator::class.java.getDeclaredMethod("isExcluded", String::class.java)
private val isIncludedMethod: Method = SimpleRelocator::class.java.getDeclaredMethod("isIncluded", String::class.java)
init {
isExcludedMethod.isAccessible = true
isIncludedMethod.isAccessible = true
}
}
}

View File

@ -1,102 +0,0 @@
package task
import ensureSuccess
import forkName
import gitCmd
import org.gradle.api.Project
import org.gradle.api.Task
import reEnableGitSigning
import taskGroup
import temporarilyDisableGitSigning
import toothpick
import upstreams
import java.io.File
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths
internal fun Project.createApplyPatchesTask(
receiver: Task.() -> Unit = {}
): Task = tasks.create("applyPatches") {
receiver(this)
group = taskGroup
fun checkCursed(project: Project): Boolean {
return project.properties.getOrDefault("cursed", "false").toString().toBoolean()
}
fun applyPatches(patchDir: Path, applyName: String, name: String, wasGitSigningEnabled: Boolean, projectDir: File): Boolean {
if (Files.notExists(patchDir)) return true
val patchPaths = Files.newDirectoryStream(patchDir)
.map { it.toFile() }
.filter { it.name.endsWith(".patch") }
.sorted()
.takeIf { it.isNotEmpty() } ?: return true
val patches = patchPaths.map { it.absolutePath }.toTypedArray()
logger.lifecycle(">>> Applying $applyName patches to $name")
gitCmd("am", "--abort")
//Cursed Apply Mode that makes fixing stuff a lot easier
if (checkCursed(project)) {
for (patch in patches) {
val gitCommand = arrayListOf("am", "--3way", "--ignore-whitespace",
"--rerere-autoupdate", "--whitespace=fix", "--reject", "-C0", patch)
if (gitCmd(*gitCommand.toTypedArray(), dir = projectDir, printOut = true).exitCode != 0) {
gitCmd("add", ".", dir = projectDir, printOut = true)
gitCmd("am", "--continue", dir = projectDir, printOut = true)
}
}
} else {
val gitCommand = arrayListOf("am", "--3way", "--ignore-whitespace",
"--rerere-autoupdate", "--whitespace=fix", *patches)
ensureSuccess(gitCmd(*gitCommand.toTypedArray(), dir = projectDir, printOut = true)) {
if (wasGitSigningEnabled) reEnableGitSigning(projectDir)
}
}
return false;
}
doLast {
for ((name, subproject) in toothpick.subprojects) {
val (sourceRepo, projectDir, patchesDir) = subproject
val folder = (if (patchesDir.endsWith("server")) "server" else "api")
// Reset or initialize subproject
logger.lifecycle(">>> Resetting subproject $name")
if (projectDir.exists()) {
ensureSuccess(gitCmd("fetch", "origin", dir = projectDir))
ensureSuccess(gitCmd("reset", "--hard", "origin/master", dir = projectDir))
} else {
ensureSuccess(gitCmd("clone", sourceRepo.absolutePath, projectDir.absolutePath, printOut = true))
}
logger.lifecycle(">>> Done resetting subproject $name")
val wasGitSigningEnabled = temporarilyDisableGitSigning(projectDir)
for (upstream in upstreams) {
if (((folder == "server" && upstream.serverList?.isEmpty() != false) || (folder == "api" && upstream.apiList?.isEmpty() != false)) && !upstream.useBlackList) continue
if (((folder == "server" && upstream.getRepoServerPatches()?.isEmpty() != false) || (folder == "api" && upstream.getRepoAPIPatches()?.isEmpty() != false)) && upstream.useBlackList) continue
project.gitCmd("branch", "-D", "${upstream.name}-$folder", dir = projectDir)
project.gitCmd("checkout", "-b", "${upstream.name}-$folder", dir = projectDir)
// Apply patches
val patchDir = Paths.get("${upstream.patchPath}/$folder")
if (applyPatches(patchDir, upstream.name, name, wasGitSigningEnabled, projectDir)) continue
}
// project.gitCmd("branch", "-D", "$forkName-$folder", dir = projectDir)
// project.gitCmd("checkout", "-b", "$forkName-$folder", dir = projectDir)
project.gitCmd("branch", "-D", "master", dir = projectDir)
project.gitCmd("checkout", "-b", "master", dir = projectDir)
val patchDir = patchesDir.toPath()
// Apply patches
if (applyPatches(patchDir, forkName, name, wasGitSigningEnabled, projectDir)) continue
if (wasGitSigningEnabled) reEnableGitSigning(projectDir)
logger.lifecycle(">>> Done applying patches to $name")
}
}
}

View File

@ -1,55 +0,0 @@
package task
import org.gradle.api.Project
import org.gradle.api.Task
import taskGroup
import upstreams
import gitCmd
import toothpick
import java.nio.file.Paths
import java.util.concurrent.ConcurrentHashMap
import ensureSuccess
internal fun Project.createFixBranchesTask(
receiver: Task.() -> Unit = {}
): Task = tasks.create("fixBranches") {
receiver(this)
group = taskGroup
val folderArray = arrayListOf("api", "server")
doLast {
for (folder in folderArray) {
val subprojectWorkDir = Paths.get("${toothpick.forkName}-${if (folder == "api") {"API"} else {"Server"}}").toFile()
// val currentBranchCommits = gitCmd("--no-pager", "log", "${toothpick.forkName}-$folder...${toothpick.upstreamBranch}", "--pretty=oneline",
val currentBranchCommits = gitCmd("--no-pager", "log", "master...${toothpick.upstreamBranch}", "--pretty=oneline",
dir = subprojectWorkDir).output.toString()
val nameMap = ConcurrentHashMap<String, String>()
for (upstream in upstreams) {
val patchPath = Paths.get("${upstream.patchPath}/$folder").toFile()
if (patchPath.listFiles()?.isEmpty() != false) continue
val commitName = gitCmd("--no-pager", "log", "${upstream.name}-$folder", "-1", "--format=\"%s\"",
dir = subprojectWorkDir).output.toString()
val branchName = "${upstream.name}-$folder"
val commitNameFiltered = commitName.substring(1, commitName.length-1)
for (line in currentBranchCommits.split("\\n".toRegex()).stream().parallel()) {
val commitNameIterator = line.substring(41, line.length)
if (commitNameIterator == commitNameFiltered) {
val hash = line.substring(0, 40)
nameMap.put(branchName, hash)
continue
}
}
}
for (upstream in upstreams) {
val patchPath = Paths.get("${upstream.patchPath}/$folder").toFile()
if (patchPath.listFiles()?.isEmpty() != false) continue
val branchName = "${upstream.name}-$folder"
ensureSuccess(gitCmd("checkout", branchName, dir = subprojectWorkDir, printOut = true))
ensureSuccess(gitCmd("reset", "--hard", nameMap.get(branchName) as String, dir = subprojectWorkDir,
printOut = true))
}
// ensureSuccess(gitCmd("checkout", "${toothpick.forkName}-$folder", dir = subprojectWorkDir,
ensureSuccess(gitCmd("checkout", "master", dir = subprojectWorkDir,
printOut = true))
}
}
}

View File

@ -1,118 +0,0 @@
package task
import LibraryImport
import ensureSuccess
import gitCmd
import internalTaskGroup
import libraryImports
import nmsImports
import org.gradle.api.Project
import org.gradle.api.Task
import toothpick
import upstreams
import java.io.File
import java.nio.file.Files
import kotlin.streams.toList
internal fun Project.createImportMCDevTask(
receiver: Task.() -> Unit = {}
): Task = tasks.create("importMCDev") {
receiver(this)
group = internalTaskGroup
val upstreamServer = toothpick.serverProject.baseDir
val importLog = arrayListOf("Extra mc-dev imports")
fun isDuplicateImport(target: File, className: String): Boolean {
if (!target.exists()) return false
val message = "Skipped import for $className, a class with that name already exists in the source tree. Is there an extra entry in mcdevimports.json?"
project.gradle.taskGraph.allTasks.last().doLast {
logger.warn(message)
}
logger.warn(message)
return true
}
fun importNMS(className: String) {
logger.lifecycle("Importing $className")
val classPath = "${className.replace(".", "/")}.java"
val source = toothpick.paperDecompDir.resolve("spigot/$classPath")
importLog.add("Importing $className")
if (!source.exists()) error("Missing NMS: $className")
val target = upstreamServer.resolve("src/main/java/$classPath")
if (isDuplicateImport(target, className)) return
target.parentFile.mkdirs()
source.copyTo(target)
}
fun importLibrary(import: LibraryImport) {
val (group, lib, prefix, file) = import
val className = "${prefix.replace("/", ".")}.$file"
importLog.add("Imported $className from $group.$lib")
logger.lifecycle("Importing $className from $group.$lib")
val source = toothpick.paperDecompDir.resolve("libraries/$group/$lib/$prefix/$file.java")
if (!source.exists()) error("Missing Base: $lib $prefix/$file")
val targetDir = upstreamServer.resolve("src/main/java/$prefix")
val target = targetDir.resolve("$file.java")
if (isDuplicateImport(target, className)) return
targetDir.mkdirs()
source.copyTo(target)
}
fun findNeededImports(patches: List<File>): Set<String> = patches.asSequence()
.flatMap { it.readLines().asSequence() }
.filter { line ->
line.startsWith("+++ b/src/main/java/net/minecraft/")
|| line.startsWith("+++ b/src/main/java/com/mojang/math/")
}
.distinct()
.map { it.substringAfter("+++ b/src/main/java/") }
.filter { !upstreamServer.resolve("src/main/java/$it").exists() }
.filter {
val sourceFile = toothpick.paperDecompDir.resolve("spigot/$it")
val exists = sourceFile.exists()
if (!sourceFile.exists()) logger.lifecycle("$it is either missing, or is a new file added through a patch")
exists
}
.map { it.replace("/", ".").substringBefore(".java") }
.toSet()
fun getAndApplyNMS(patchesDir: File) {
findNeededImports(patchesDir.listFiles().toList()).toList().forEach(::importNMS)
}
doLast {
logger.lifecycle(">>> Importing mc-dev")
val lastCommitIsMCDev = gitCmd(
"log", "-1", "--oneline",
dir = upstreamServer
).output?.contains("Extra mc-dev imports") == true
if (lastCommitIsMCDev) {
ensureSuccess(
gitCmd(
"reset", "--hard", "HEAD~1",
dir = upstreamServer,
printOut = true
)
)
}
for (upstream in upstreams) {
val patchesDir = rootProject.projectDir.resolve("${upstream.patchPath}/server")
getAndApplyNMS(patchesDir)
}
val patchesDir = toothpick.serverProject.patchesDir
getAndApplyNMS(patchesDir)
// Imports from MCDevImports.kt
nmsImports.forEach(::importNMS)
libraryImports.forEach(::importLibrary)
val add = gitCmd("add", ".", "-A", dir = upstreamServer).exitCode == 0
val commit = gitCmd("commit", "-m", importLog.joinToString("\n"), dir = upstreamServer).exitCode == 0
if (!add || !commit) {
logger.lifecycle(">>> Didn't import any extra files")
}
logger.lifecycle(">>> Done importing mc-dev")
}
}

View File

@ -1,25 +0,0 @@
package task
import gitCmd
import org.gradle.api.Project
import org.gradle.api.Task
import taskGroup
import upstreamDir
import upstreams
internal fun Project.createInitGitSubmodulesTask(
receiver: Task.() -> Unit = {}
): Task = tasks.create("initGitSubmodules") {
receiver(this)
group = taskGroup
var upstreamNotInit = false
for (upstream in upstreams) { upstreamNotInit = upstreamNotInit || upstream.repoPath.toFile().resolve(".git").exists() }
onlyIf { !upstreamDir.resolve(".git").exists() || upstreamNotInit }
doLast {
var exit = gitCmd("submodule", "update", "--init", printOut = true).exitCode
exit += gitCmd("submodule", "update", "--init", "--recursive", dir = upstreamDir, printOut = true).exitCode
if (exit != 0) {
error("Failed to checkout git submodules: git exited with code $exit")
}
}
}

View File

@ -1,38 +0,0 @@
package task
import cmd
import ensureSuccess
import jenkins
import org.gradle.api.Project
import org.gradle.api.Task
import rootProjectDir
import taskGroup
import toothpick
internal fun Project.createPaperclipTask(
receiver: Task.() -> Unit = {}
): Task = tasks.create("paperclip") {
receiver(this)
group = taskGroup
doLast {
val workDir = toothpick.paperDir.resolve("work")
val paperclipDir = workDir.resolve("Paperclip")
val vanillaJarPath =
workDir.resolve("Minecraft/${toothpick.minecraftVersion}/${toothpick.minecraftVersion}.jar").absolutePath
val patchedJarPath = inputs.files.singleFile.absolutePath
logger.lifecycle(">>> Building paperclip")
val paperclipCmd = arrayListOf(
"mvn", "-T", "2C", "clean", "package",
"-Dmcver=${toothpick.minecraftVersion}",
"-Dpaperjar=$patchedJarPath",
"-Dvanillajar=$vanillaJarPath"
)
if (System.getProperty("os.name").startsWith("Windows")) paperclipCmd[0] = "mvn.cmd"
if (jenkins) paperclipCmd.add("-Dstyle.color=never")
ensureSuccess(cmd(*paperclipCmd.toTypedArray(), dir = paperclipDir, printOut = true))
val paperClip = paperclipDir.resolve("assembly/target/paperclip-${toothpick.minecraftVersion}.jar")
val destination = rootProjectDir.resolve(toothpick.calcPaperclipName)
paperClip.copyTo(destination, overwrite = true)
logger.lifecycle(">>> ${toothpick.calcPaperclipName} saved to root project directory")
}
}

View File

@ -1,100 +0,0 @@
package task
import PatchParser
import PatchParser.PatchInfo
import com.github.mustachejava.DefaultMustacheFactory
import com.github.mustachejava.MustacheFactory
import org.gradle.api.Project
import org.gradle.api.Task
import taskGroup
import java.io.*
import java.nio.charset.StandardCharsets
import java.nio.file.Paths
import java.util.*
import patchCreditsOutput
import patchCreditsTemplate
internal fun Project.createPatchCreditsTask(
receiver: Task.() -> Unit = {}
): Task = tasks.create("patchCredits") {
receiver(this)
group = taskGroup
val projectDirectory: File = rootDir
val patchDirectory: File? = Paths.get("$rootDir/patches").toFile()
val outputFileName: String = patchCreditsOutput
val srcFileName: String = patchCreditsTemplate
doLast {
val src = File(projectDirectory, srcFileName)
if (!src.exists()) {
logger.warn("Unable to find src at '" + src.absolutePath + "'! Skipping!")
return@doLast
}
if (!patchDirectory!!.exists()) {
logger
.warn(
"Unable to find patch directory at '"
+ patchDirectory.absolutePath
+ "'! Skipping!"
)
return@doLast
}
logger.lifecycle("Scanning '$patchDirectory' for patches!")
val patches: MutableList<PatchInfo> = ArrayList()
scanFolder(patchDirectory, patches, project)
if (patches.isEmpty()) {
logger.warn("Unable to find any patches! Skipping!")
return@doLast
}
patches.sortWith { a: PatchInfo, b: PatchInfo -> a.subject.compareTo(b.subject) }
val output = Output()
output.patches = patches
try {
val mf: MustacheFactory = DefaultMustacheFactory()
FileReader(src).use { srcReader ->
val mustache = mf.compile(srcReader, "template")
val outputFile = File(projectDirectory, outputFileName)
if (outputFile.exists()) {
outputFile.delete()
}
OutputStreamWriter(FileOutputStream(outputFile), StandardCharsets.UTF_8).use { writer ->
mustache.execute(
writer,
output
).flush()
}
}
} catch (ex: IOException) {
error("Error while writing the output file!")
}
}
}
fun scanFolder(folder: File?, patches: MutableList<PatchInfo>, project: Project) {
val files = folder!!.listFiles { dir: File, name: String ->
if (dir.isDirectory) {
return@listFiles !name.equals("removed", ignoreCase = true)
} else {
return@listFiles true
}
} ?: return
for (f: File in files) {
if (f.isDirectory) {
scanFolder(f, patches, project)
} else if (f.name.endsWith(".patch")) {
try {
patches.add(PatchParser.parsePatch(f))
} catch (ex: IOException) {
project.logger.warn("Exception while parsing '" + f.absolutePath + "'!", ex)
}
}
}
}
class Output {
var patches: List<PatchInfo>? = null
}

View File

@ -1,89 +0,0 @@
package task
import ensureSuccess
import forkName
import gitCmd
import org.gradle.api.Project
import org.gradle.api.Task
import taskGroup
import toothpick
import upstreams
import java.io.File
import java.nio.file.Paths
import Upstream
@Suppress("UNUSED_VARIABLE")
internal fun Project.createRebuildPatchesTask(
receiver: Task.() -> Unit = {}
): Task = tasks.create("rebuildPatches") {
receiver(this)
group = taskGroup
doLast {
for ((name, subproject) in toothpick.subprojects) {
val (sourceRepo, projectDir, patchesDir) = subproject
var previousUpstreamName = "origin/master"
val folder = (if (patchesDir.endsWith("server")) "server" else "api")
for (upstream in upstreams) {
val patchPath = Paths.get("${upstream.patchPath}/$folder").toFile()
if (patchPath.listFiles()?.isEmpty() != false) continue
updatePatches(patchPath, upstream.name, folder, projectDir, previousUpstreamName)
previousUpstreamName = "${upstream.name}-$folder"
}
// ensureSuccess(gitCmd("checkout", "$forkName-$folder", dir = projectDir,
ensureSuccess(gitCmd("checkout", "master", dir = projectDir,
printOut = true))
updatePatches(patchesDir, toothpick.forkName, folder, projectDir, previousUpstreamName)
logger.lifecycle(">>> Done rebuilding patches for $name")
}
}
}
private fun Project.updatePatches(
patchPath: File,
name: String,
folder: String,
projectDir: File,
previousUpstreamName: String
) {
logger.lifecycle(">>> Rebuilding patches for $name-$folder")
if (!patchPath.exists()) {
patchPath.mkdirs()
}
// Nuke old patches
patchPath.listFiles()
?.filter { it -> it.name.endsWith(".patch") }
?.forEach { it -> it.delete() }
ensureSuccess(
if (name != "Yatopia") {
gitCmd(
"checkout", "$name-$folder", dir = projectDir,
printOut = true
)
} else {
gitCmd(
"checkout", "master", dir = projectDir,
printOut = true
)
}
)
ensureSuccess(
gitCmd(
"format-patch",
"--no-stat", "--zero-commit", "--full-index", "--no-signature", "-N",
"-o", patchPath.absolutePath, previousUpstreamName,
dir = projectDir,
printOut = false
)
)
gitCmd(
"add", patchPath.canonicalPath,
dir = patchPath,
printOut = true
)
}

View File

@ -1,108 +0,0 @@
/*
* This file is part of Toothpick, licensed under the MIT License.
*
* Copyright (c) 2020-2021 Jason Penilla & Contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package task
import org.gradle.api.tasks.TaskAction
import java.io.File
import org.gradle.api.Project
import org.gradle.api.Task
import taskGroup
import upstreams
import gitCmd
import toothpick
import java.nio.file.Paths
import java.util.concurrent.ConcurrentHashMap
import ensureSuccess
import java.net.URL
@Suppress("UNUSED_VARIABLE")
internal fun Project.createRepackageNMSTask(
receiver: Task.() -> Unit = {}
): Task = tasks.create("repackageNMS") {
receiver(this)
group = taskGroup
class Mapping(fullyQualifiedClassName: String) {
val className = fullyQualifiedClassName.substringAfterLast(".")
val oldFQName = "net.minecraft.server.$className"
val oldJavaFileName = "net/minecraft/server/$className.java"
val newFQName = fullyQualifiedClassName
val newJavaFileName = "${fullyQualifiedClassName.replace(".", "/")}.java"
}
class Remapper(private val mappings: Set<Mapping>) {
fun remapFile(file: File): String =
file.readLines().joinToString("\n") { remapLine(it) } + "\n"
private fun remapLine(line: String): String {
if (
line.startsWith("diff --git ")
|| line.startsWith("+++ ")
|| line.startsWith("--- ")
) {
var text = line
mappings.forEach { text = text.replace(it.oldJavaFileName, it.newJavaFileName) }
return text
}
if (line.startsWith("+")) {
var text = line
mappings.forEach { text = text.replace(it.oldFQName, it.newFQName) }
return text
}
return line
}
}
doLast {
logger.lifecycle("Downloading class mappings from spigot...")
val mappingsFileText = URL("https://hub.spigotmc.org/stash/projects/SPIGOT/repos/builddata/raw/mappings/bukkit-1.16.5-cl.csrg?at=80d35549ec67b87a0cdf0d897abbe826ba34ac27").readText()
logger.lifecycle("Done downloading class mappings.")
logger.lifecycle(">>> Preparing patches for NMS repackage")
val mappings = mappingsFileText
.split("\n")
.asSequence()
.filter { !it.startsWith("#") && !it.contains("$") && it.trim().isNotEmpty() }
.map { it.split(" ")[1].replace("/", ".") }
.map { Mapping(it) }
.filter { it.newFQName != it.oldFQName }
.toSet()
val remapper = Remapper(mappings)
toothpick.subprojects.values
.map { it.patchesDir }
.forEach { patchesDir ->
val repackagedPatchesDir =
patchesDir.parentFile.resolve("${patchesDir.name}_repackaged-${System.currentTimeMillis()}")
repackagedPatchesDir.mkdir()
val patchFiles = patchesDir.listFiles()?.toList() ?: error("Could not list patch files")
patchFiles.parallelStream().forEach { patch ->
logger.lifecycle("Processing ${patchesDir.name}/${patch.name}...")
val newPatch = repackagedPatchesDir.resolve(patch.name)
newPatch.writeText(remapper.remapFile(patch))
}
}
logger.lifecycle(">>> Done preparing patches")
}
}

View File

@ -1,35 +0,0 @@
package task
import bashCmd
import gitHash
import lastUpstream
import org.gradle.api.Project
import org.gradle.api.Task
import taskGroup
import toothpick
import upstreamDir
internal fun Project.createSetupUpstreamTask(
receiver: Task.() -> Unit = {}
): Task = tasks.create("setupUpstream") {
receiver(this)
group = taskGroup
doLast {
val setupUpstreamCommand = if (upstreamDir.resolve(toothpick.upstreamLowercase).exists()) {
"./${toothpick.upstreamLowercase} patch"
} else if (
upstreamDir.resolve("build.gradle.kts").exists()
&& upstreamDir.resolve("subprojects/server.gradle.kts").exists()
&& upstreamDir.resolve("subprojects/api.gradle.kts").exists()
) {
"./gradlew applyPatches"
} else {
error("Don't know how to setup upstream!")
}
val result = bashCmd(setupUpstreamCommand, dir = upstreamDir, printOut = true)
if (result.exitCode != 0) {
error("Failed to apply upstream patches: script exited with code ${result.exitCode}")
}
lastUpstream.writeText(gitHash(upstreamDir))
}
}

View File

@ -1,155 +0,0 @@
package task
import Upstream
import ensureSuccess
import gitCmd
import org.apache.tools.ant.util.FileUtils
import org.gradle.api.Project
import org.gradle.api.Task
import rootProjectDir
import taskGroup
import toothpick
import upstreamDir
import upstreams
import java.io.File
import java.nio.charset.StandardCharsets
import java.nio.file.Files
import java.nio.file.Paths
import java.util.stream.Collectors
internal fun Project.createUpdateUpstreamTask(
receiver: Task.() -> Unit = {}
): Task = tasks.create("updateUpstream") {
receiver(this)
group = taskGroup
doLast {
ensureSuccess(gitCmd("fetch", dir = upstreamDir, printOut = true))
ensureSuccess(gitCmd("reset", "--hard", toothpick.upstreamBranch, dir = upstreamDir, printOut = true))
ensureSuccess(gitCmd("add", toothpick.upstream, dir = rootProjectDir, printOut = true))
for (upstream in upstreams) {
ensureSuccess(gitCmd("fetch", dir = upstream.repoPath.toFile(), printOut = true))
ensureSuccess(gitCmd("reset", "--hard", upstream.branch, dir = upstream.repoPath.toFile(), printOut = true))
ensureSuccess(gitCmd("add", "upstream/${upstream.name}", dir = rootProjectDir, printOut = true))
}
ensureSuccess(gitCmd("submodule", "update", "--init", "--recursive", dir = upstreamDir, printOut = true))
val fileUtils = FileUtils.getFileUtils()
for (upstream in upstreams) {
val serverRepoPatches = upstream.getRepoServerPatches()
val apiRepoPatches = upstream.getRepoAPIPatches()
val serverPatches = upstream.serverList
val apiPatches = upstream.apiList
logger.lifecycle(">>> Pulling ${upstream.name} patches")
updatePatches(serverRepoPatches, upstream, fileUtils, serverPatches, "server")
updatePatches(apiRepoPatches, upstream, fileUtils, apiPatches, "api")
upstream.updateUpstreamCommitHash()
}
}
}
private fun updatePatches(
repoPatches: MutableList<String>?,
upstream: Upstream,
fileUtils: FileUtils,
patches: MutableList<String>?,
folder: String
) {
if (repoPatches != null) {
var i = 0
val currentPatchList = Paths.get("${upstream.patchPath}/$folder").toFile().listFiles() as Array<File>?
val tmpFolder = Paths.get("${upstream.patchPath}/tmp/$folder").toFile()
tmpFolder.mkdirs()
if (currentPatchList != null) {
for (patch in currentPatchList) {
if (patch.exists()) {
fileUtils.copyFile(
"${upstream.patchPath}/$folder/${patch.name}",
"${upstream.patchPath}/tmp/$folder/${patch.name}"
)
patch.delete()
}
}
}
val currentPatchListFiltered = currentPatchList?.toList()
?.stream()?.sorted()?.map { patch -> patch.name.substring(5, patch.name.length) }
?.collect(Collectors.toList())
for (patch in repoPatches) {
if (patches != null) {
if ((patches.contains(patch) && upstream.useBlackList) || (!patches.contains(patch) && !upstream.useBlackList)) {
continue
} else {
i++
updatePatch(fileUtils, upstream, repoPatches, patch, i, folder, currentPatchListFiltered)
}
}
}
val tmpFolderList = tmpFolder.listFiles()
if (tmpFolderList != null) {
for (patch in tmpFolderList) {
patch.delete()
}
}
}
}
private fun updatePatch(
fileUtils: FileUtils,
upstream: Upstream,
serverRepoPatches: MutableList<String>,
patch: String,
i: Int,
folder: String,
currentPatchListFiltered: MutableList<String>?
) {
if (currentPatchListFiltered == null || patchHasDiff(upstream, serverRepoPatches, patch, folder, currentPatchListFiltered)) {
fileUtils.copyFile("${upstream.repoPath}/patches/$folder/" +
"${String.format("%04d", serverRepoPatches.indexOf(patch) + 1)}-$patch",
"${upstream.patchPath}/$folder/${String.format("%04d", i)}-$patch"
)
} else {
fileUtils.copyFile("${upstream.patchPath}/tmp/$folder/" +
"${String.format("%04d", currentPatchListFiltered.indexOf(patch) + 1)}-$patch",
"${upstream.patchPath}/$folder/${String.format("%04d", i)}-$patch"
)
}
}
fun patchHasDiff(
upstream: Upstream,
serverRepoPatches: MutableList<String>,
patch: String,
folder: String,
currentPatchListFiltered: MutableList<String>
): Boolean {
if (!Paths.get("${upstream.patchPath}/tmp/$folder/${String.format("%04d", currentPatchListFiltered.indexOf(patch) + 1)}-$patch").toFile().isFile) return true
if (!patchChanged(upstream, serverRepoPatches, patch, folder)) return false
val upstreamFile = Files.readAllLines(Paths.get("${upstream.repoPath}/patches/$folder/${String.format("%04d", serverRepoPatches.indexOf(patch) + 1)}-$patch"), StandardCharsets.UTF_8)
val repoFile = Files.readAllLines(Paths.get("${upstream.patchPath}/tmp/$folder/${String.format("%04d", currentPatchListFiltered.indexOf(patch) + 1)}-$patch"), StandardCharsets.UTF_8)
return upstreamFile.stream().filter {line -> line.startsWith("+") || line.startsWith("-")}
.filter {line -> if (line.startsWith("---") || line.startsWith("+++")) {
line.substring(3, line.length).trim().isNotBlank()
}
else if (line.startsWith("--") || line.startsWith("++")) {
line.substring(2, line.length).trim().isNotBlank()
}
else {
line.substring(1, line.length).trim().isNotBlank()
} }
.filter {line -> if (repoFile.contains(line)) {
repoFile.remove(line)
return@filter false
} else { return@filter true } }.collect(Collectors.toList()).isNotEmpty()
}
fun patchChanged(
upstream: Upstream,
serverRepoPatches: MutableList<String>,
patch: String,
folder: String
): Boolean {
val diffCheckCmdResult = upstream.project.gitCmd("diff", "--name-only", upstream.upstreamCommit, upstream.getCurrentCommitHash(), dir = upstream.repoPath.toFile() )
val diffCheckResult = diffCheckCmdResult.output.toString()
if (diffCheckResult.isBlank()) return false
val diffCheckChangeFiles = diffCheckResult.split("\\n".toRegex()).toTypedArray().toList()
return diffCheckChangeFiles.contains("patches/$folder/${String.format("%04d", serverRepoPatches.indexOf(patch) + 1)}-$patch")
}

View File

@ -1,82 +0,0 @@
package task
import ensureSuccess
import gitCmd
import org.gradle.api.Project
import org.gradle.api.Task
import taskGroup
import toothpick
import upstreamDir
import upstreams
import java.io.File
import Upstream
import java.util.concurrent.CopyOnWriteArrayList
internal fun Project.createUpstreamCommitTask(
receiver: Task.() -> Unit = {}
): Task = tasks.create("upstreamCommit") {
receiver(this)
group = taskGroup
doLast {
gitChangelog = getUpstreamChanges(project,this, toothpick.upstream,
upstreamDir, toothpick.upstream)
for (upstream in upstreams) {
gitChangelog = getUpstreamChanges(project,this, upstream.name,
upstream.repoPath.toFile(), "upstream/${upstream.name}")
}
var changedUpstreamsString = ""
for (upstreamName in changedUpstreams) {
if (changedUpstreamsString.isNotEmpty()) {
changedUpstreamsString += "/"
}
changedUpstreamsString += upstreamName
}
if (changedUpstreamsString.isNotEmpty()) {
val commitMessage = """
|Updated Upstream and Sidestream(s) ($changedUpstreamsString)
|
|Upstream/An Sidestream has released updates that appears to apply and compile correctly
|This update has NOT been tested by YatopiaMC and as with ANY update, please do your own testing.
|
|
|$gitChangelog
""".trimMargin()
ensureSuccess(gitCmd("commit", "-m", commitMessage, printOut = true))
}
}
}
private fun getUpstreamChanges(
project: Project,
task: Task,
name: String,
dir: File,
path: String
): String {
var gitChangelog1 = gitChangelog
val oldRev = ensureSuccess(project.gitCmd("ls-tree", "HEAD", path))
?.substringAfter("commit ")?.substringBefore("\t")
val upstreamTmp = ensureSuccess(
project.gitCmd(
"log",
"--oneline",
"$oldRev...HEAD",
printOut = true,
dir = dir
)
) {
task.logger.lifecycle("No $name changes to commit.")
}
if (!upstreamTmp.isNullOrBlank()) {
changedUpstreams.add(name)
gitChangelog1 += "$name Changes:\n$upstreamTmp\n\n"
}
return gitChangelog1
}
val changedUpstreams = CopyOnWriteArrayList<String>()
var gitChangelog = ""

View File

@ -1,39 +0,0 @@
/*
* This file is part of Toothpick, licensed under the MIT License.
*
* Copyright (c) 2020-2021 Jason Penilla & Contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package transformer
import com.github.jengelman.gradle.plugins.shadow.transformers.Log4j2PluginsCacheFileTransformer
import com.github.jengelman.gradle.plugins.shadow.transformers.Transformer
import org.gradle.api.file.FileTreeElement
import shadow.org.apache.logging.log4j.core.config.plugins.processor.PluginProcessor.PLUGIN_CACHE_FILE
internal class ModifiedLog4j2PluginsCacheFileTransformer : Transformer by Log4j2PluginsCacheFileTransformer() {
/**
* For some reason we have a file with name matching simply 'Log4j2Plugins.dat' and not PLUGIN_CACHE_FILE.
* That file also needs to be merged.
*/
override fun canTransformResource(element: FileTreeElement): Boolean {
return PLUGIN_CACHE_FILE == element.name || element.name == "Log4j2Plugins.dat"
}
}

View File

@ -1,3 +1,11 @@
# Paperweight
group=org.yatopiamc.yatopia
version=1.17-R0.1-SNAPSHOT
packageVersion=1_17_R1
paperCommit=123a41d1325e6361e547af7c29327fa319e06fb3
# Gradle
org.gradle.daemon=true
org.gradle.jvmargs=-Xms1G -Xmx3G
org.gradle.parallel=true

View File

@ -1,23 +0,0 @@
The MIT License (MIT)
=====================
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the “Software”), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,29 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
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 d1a9322cf54f57f0d213145aa50c219f0eb2a90b..1a319e2842f4b99951f1cddce8b2b4be9f5373a0 100644
--- a/src/main/java/org/bukkit/Server.java
+++ b/src/main/java/org/bukkit/Server.java
@@ -1603,6 +1603,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
*

View File

@ -1,113 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
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<String> mobs = new HashSet<>();
+
+ private PurpurPermissions() {
+ for (EntityType mob : EntityType.values()) {
+ Class<? extends Entity> 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;
+ }
+}

View File

@ -1,32 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
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;
}

View File

@ -1,123 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
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<String> 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
+ * <p>
+ * 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 + "]";
+ }
+}

View File

@ -1,191 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
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.
+ * <p>
+ * 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
+ * <p>
+ * 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
}

View File

@ -1,112 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
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
}

View File

@ -1,44 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
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 33f04d57b7df3a6f9743246ba9af6d67f4fa4b54..45c64a9e4f20428a9a448194f22697a17dfb8e1f 100644
--- a/src/main/java/org/bukkit/Bukkit.java
+++ b/src/main/java/org/bukkit/Bukkit.java
@@ -1951,4 +1951,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 1a319e2842f4b99951f1cddce8b2b4be9f5373a0..91641c358b10219d4098f40b53ea56f1cfa5defc 100644
--- a/src/main/java/org/bukkit/Server.java
+++ b/src/main/java/org/bukkit/Server.java
@@ -1725,4 +1725,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
}

View File

@ -1,175 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
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

View File

@ -1,31 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
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 9f0645dc5f76ee9ef73d88f768025429e5a9edf7..4ccbb3ef3c597ef9da2c6744f410283a1dc2538c 100644
--- a/src/main/java/org/bukkit/entity/LivingEntity.java
+++ b/src/main/java/org/bukkit/entity/LivingEntity.java
@@ -850,4 +850,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
}

View File

@ -1,42 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
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 45c64a9e4f20428a9a448194f22697a17dfb8e1f..b3cd3e5288bdcdd928efb8cba97f504d8e3ec58e 100644
--- a/src/main/java/org/bukkit/Bukkit.java
+++ b/src/main/java/org/bukkit/Bukkit.java
@@ -1961,5 +1961,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 91641c358b10219d4098f40b53ea56f1cfa5defc..f546e3422539d91f1fcb98c94a722c4b17ef0170 100644
--- a/src/main/java/org/bukkit/Server.java
+++ b/src/main/java/org/bukkit/Server.java
@@ -1733,5 +1733,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
}

View File

@ -1,26 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
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
}

View File

@ -1,97 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
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;
+ }
+}

View File

@ -1,79 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
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;
+ }
+}

View File

@ -1,24 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
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.

View File

@ -1,37 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
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
}

View File

@ -1,124 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
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
}

View File

@ -1,701 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
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 {
// </editor-fold>
}
}
+
+ // Purpur start
+ public boolean isArmor() {
+ switch (this) {
+ // <editor-fold defaultstate="collapsed" desc="isarmor">
+ 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 3e2c08641edffcf00b230ad624685aaff30af0e5..fceba6780a15c274c4689eccbeb6dfb2eee25ed9 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.
@@ -914,4 +926,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.
+ * <p>
+ * Plugins should check that hasDisplayName() returns <code>true</code>
+ * 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.
+ * <p>
+ * Plugins should check that hasLocalizedName() returns <code>true</code>
+ * 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. <br>
+ * Returns an empty map if none.
+ *
+ * @return An immutable copy of the enchantments
+ */
+ @NotNull
+ public Map<Enchantment, Integer> 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.
+ * <p>
+ * 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.
+ * <p>
+ * CustomModelData is an integer that may be associated client side with a
+ * custom item model.
+ * <p>
+ * Plugins should check that hasCustomModelData() returns <code>true</code>
+ * before calling this method.
+ *
+ * @return the localized name that is set
+ */
+ public int getCustomModelData() {
+ return getItemMeta().getCustomModelData();
+ }
+
+ /**
+ * Checks for existence of custom model data.
+ * <p>
+ * 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.<br>
+ * Returns null if none exist.
+ *
+ * @return an immutable {@link Multimap} of Attributes
+ * and their AttributeModifiers, or null if none exist
+ */
+ @Nullable
+ public Multimap<Attribute, AttributeModifier> getAttributeModifiers() {
+ return getItemMeta().getAttributeModifiers();
+ }
+
+ /**
+ * Return an immutable copy of all {@link Attribute}s and their
+ * {@link AttributeModifier}s for a given {@link EquipmentSlot}.<br>
+ * 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.<br>
+ * 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<Attribute, AttributeModifier> 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<AttributeModifier> 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.
+ * <br>
+ * 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<Attribute, AttributeModifier> 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}.<br>
+ * 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<Namespaced> 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<Namespaced> 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<Namespaced> 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<Namespaced> 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
}

View File

@ -1,19 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
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<T extends Mob> extends Goal<T> {
GoalKey<Zombie> ZOMBIE_ATTACK = GoalKey.of(Zombie.class, NamespacedKey.minecraft("zombie_attack"));
GoalKey<Creature> STROLL_VILLAGE_GOLEM = GoalKey.of(Creature.class, NamespacedKey.minecraft("stroll_village_golem"));
GoalKey<Mob> UNIVERSAL_ANGER_RESET = GoalKey.of(Mob.class, NamespacedKey.minecraft("universal_anger_reset"));
+ // Purpur start
+ GoalKey<Phantom> FIND_CRYSTAL_GOAL = GoalKey.of(Phantom.class, NamespacedKey.minecraft("find_crystal_goal"));
+ GoalKey<Phantom> ORBIT_CRYSTAL_GOAL = GoalKey.of(Phantom.class, NamespacedKey.minecraft("orbit_crystal_goal"));
+ // Purpur end
}

View File

@ -1,41 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
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
}

View File

@ -1,210 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
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<T extends Mob> extends Goal<T> {
// Purpur start
GoalKey<Phantom> FIND_CRYSTAL_GOAL = GoalKey.of(Phantom.class, NamespacedKey.minecraft("find_crystal_goal"));
GoalKey<Phantom> ORBIT_CRYSTAL_GOAL = GoalKey.of(Phantom.class, NamespacedKey.minecraft("orbit_crystal_goal"));
+ GoalKey<Mob> HAS_RIDER = GoalKey.of(Mob.class, NamespacedKey.minecraft("has_rider"));
+ GoalKey<AbstractHorse> 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
}

View File

@ -1,27 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
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>", permission).split("\n")) {
target.sendMessage(line);
}

View File

@ -1,23 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
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 4ccbb3ef3c597ef9da2c6744f410283a1dc2538c..42811d18ff304082f74f45794344891208599c04 100644
--- a/src/main/java/org/bukkit/entity/LivingEntity.java
+++ b/src/main/java/org/bukkit/entity/LivingEntity.java
@@ -865,5 +865,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
}

View File

@ -1,73 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
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
}

View File

@ -1,114 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Parker Hawke <hawkeboyz2@hotmail.com>
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<String> 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
}

View File

@ -1,19 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: nitricspace <nitricspace@users.noreply.github.com>
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<T extends Mob> extends Goal<T> {
GoalKey<Phantom> ORBIT_CRYSTAL_GOAL = GoalKey.of(Phantom.class, NamespacedKey.minecraft("orbit_crystal_goal"));
GoalKey<Mob> HAS_RIDER = GoalKey.of(Mob.class, NamespacedKey.minecraft("has_rider"));
GoalKey<AbstractHorse> HORSE_HAS_RIDER = GoalKey.of(AbstractHorse.class, NamespacedKey.minecraft("horse_has_rider"));
+ GoalKey<Drowned> DROWNED_ATTACK_VILLAGER = GoalKey.of(Drowned.class, NamespacedKey.minecraft("drowned_attack_villager"));
+ GoalKey<Zombie> ZOMBIE_ATTACK_VILLAGER = GoalKey.of(Zombie.class, NamespacedKey.minecraft("zombie_attack_villager"));
// Purpur end
}

View File

@ -1,52 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
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<ItemStack>, Cloneable {
public static class ExactChoice implements RecipeChoice {
private List<ItemStack> choices;
+ private Predicate<ItemStack> predicate; // Purpur
public ExactChoice(@NotNull ItemStack stack) {
this(Arrays.asList(stack));
@@ -196,6 +198,7 @@ public interface RecipeChoice extends Predicate<ItemStack>, 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<ItemStack>, Cloneable {
return false;
}
+ // Purpur start
+ @Nullable
+ public Predicate<ItemStack> getPredicate() {
+ return predicate;
+ }
+
+ public void setPredicate(@Nullable Predicate<ItemStack> predicate) {
+ this.predicate = predicate;
+ }
+ // Purpur end
+
@Override
public int hashCode() {
int hash = 7;

View File

@ -1,56 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: BillyGalbreath <blake.galbreath@gmail.com>
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<DamageModifier, Double> modifiers, @NotNull final Map<DamageModifier, ? extends Function<? super Double, Double>> 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<DamageModifier, Double> modifiers, @NotNull final Map<DamageModifier, ? extends Function<? super Double, Double>> 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
}

View File

@ -1,31 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: BillyGalbreath <blake.galbreath@gmail.com>
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
}

View File

@ -1,27 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: BillyGalbreath <blake.galbreath@gmail.com>
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;

View File

@ -1,42 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Encode42 <me@encode42.dev>
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<T extends Mob> extends Goal<T> {
GoalKey<AbstractHorse> HORSE_HAS_RIDER = GoalKey.of(AbstractHorse.class, NamespacedKey.minecraft("horse_has_rider"));
GoalKey<Drowned> DROWNED_ATTACK_VILLAGER = GoalKey.of(Drowned.class, NamespacedKey.minecraft("drowned_attack_villager"));
GoalKey<Zombie> ZOMBIE_ATTACK_VILLAGER = GoalKey.of(Zombie.class, NamespacedKey.minecraft("zombie_attack_villager"));
+ GoalKey<Wolf> 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
}

View File

@ -1,23 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: BillyGalbreath <blake.galbreath@gmail.com>
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.
*/

View File

@ -1,141 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Mariell Hoversholm <proximyst@proximyst.com>
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 <https://www.gnu.org/licenses/>.
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.
+ * <p>
+ * 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.
+ * </p>
+ *
+ * @return whether the teleport should be retried.
+ */
+ public boolean shouldRetry() {
+ return retry;
+ }
+
+ /**
+ * Sets whether the teleport should be retried.
+ * <p>
+ * 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.
+ * </p>
+ *
+ * @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.
+ * <p>
+ * This is only caused by players teleporting.
+ * </p>
+ */
+ EVENT_CANCELLED,
+ }
+}

View File

@ -1,112 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Nahuel <nahueldolores@hotmail.com>
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 <https://www.gnu.org/licenses/>.
Co-authored-by: Mariell Hoversholm <proximyst@proximyst.com>
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;
}

View File

@ -1,80 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Mariell Hoversholm <proximyst@proximyst.com>
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 <https://www.gnu.org/licenses/>.
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
+ * <p>
+ * 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
}

View File

@ -1,867 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: BillyGalbreath <blake.galbreath@gmail.com>
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 b3cd3e5288bdcdd928efb8cba97f504d8e3ec58e..8036c66af0bc6b11ffd0f716138901bcfea007e1 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#sendMessage(net.kyori.adventure.text.Component)}
*/
- @Deprecated // Paper
+ @Deprecated // Paper // Purpur - conflict on change
public static int broadcastMessage(@NotNull String message) {
return server.broadcastMessage(message);
}
@@ -935,7 +935,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);
}
@@ -1212,7 +1212,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);
@@ -1262,7 +1262,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);
@@ -1289,7 +1289,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);
}
@@ -1378,7 +1378,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();
}
@@ -1400,7 +1400,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 a126581c74da8fae4c86fde2f28a850150c408cd..0f66655541dbb0dbb05a13a3612bb46cfb2b538a 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 {@code sendMessage} methods that accept {@link 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
/**
@@ -1024,7 +1024,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);
@@ -1068,7 +1068,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;
@@ -1091,7 +1091,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);
/**
@@ -1164,7 +1164,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
@@ -1182,7 +1182,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<Player>
* @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<Player>
* @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 7357c166115f346a1efebd0f0f2d5491de6a9a39..b90cb7aa98ea40573557a80ca5c7be7c5c494956 100644
--- a/src/main/java/org/bukkit/inventory/meta/BookMeta.java
+++ b/src/main/java/org/bukkit/inventory/meta/BookMeta.java
@@ -242,7 +242,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);
/**
@@ -258,7 +258,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);
/**
@@ -268,7 +268,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<String> getPages();
/**
@@ -278,7 +278,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<String> pages);
/**
@@ -288,7 +288,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);
/**
@@ -298,7 +298,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<String> 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<String> 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);
/**

View File

@ -1,29 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: BillyGalbreath <blake.galbreath@gmail.com>
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
};
/**

View File

@ -1,17 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: BillyGalbreath <blake.galbreath@gmail.com>
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<T extends Mob> extends Goal<T> {
GoalKey<Drowned> DROWNED_ATTACK_VILLAGER = GoalKey.of(Drowned.class, NamespacedKey.minecraft("drowned_attack_villager"));
GoalKey<Zombie> ZOMBIE_ATTACK_VILLAGER = GoalKey.of(Zombie.class, NamespacedKey.minecraft("zombie_attack_villager"));
GoalKey<Wolf> AVOID_RABID_WOLVES = GoalKey.of(Wolf.class, NamespacedKey.minecraft("avoid_rabid_wolves"));
+ GoalKey<IronGolem> RECEIVE_FLOWER = GoalKey.of(IronGolem.class, NamespacedKey.minecraft("receive_flower"));
// Purpur end
}

View File

@ -1,48 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Ben Kerllenevich <me@notom3ga.me>
Date: Tue, 25 May 2021 16:30:30 -0400
Subject: [PATCH] API for any mob to burn daylight
Co-authored by: Encode42 <me@encode42.dev>
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 42811d18ff304082f74f45794344891208599c04..ebe10b5612835d22dfcf8b30b0f028022e47216e 100644
--- a/src/main/java/org/bukkit/entity/LivingEntity.java
+++ b/src/main/java/org/bukkit/entity/LivingEntity.java
@@ -872,5 +872,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
}

File diff suppressed because it is too large Load Diff

View File

@ -1,424 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
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 b480bd3044370b8eb733166f0c4b737344475993..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("Airplane", serverUUID, logFailedRequests, Bukkit.getLogger()); // Tuinity - we have our own bstats page // Airplane
+ 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("airplane_version", () -> (Metrics.class.getPackage().getImplementationVersion() != null) ? Metrics.class.getPackage().getImplementationVersion() : "unknown")); // Tuinity - we have our own bstats page // Airplane
+ 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<String, Map<String, Integer>> map = new HashMap<>();
diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java
index efc1e42d606e1c9feb1a4871c0714933ae92a1b2..a0ed8ed1d6b89a4f10dff645e09eaff303fb3f8a 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 3e21bd029131ceeaac9cb46bef8d238617ca76ea..c2932e739a607e4ed3f94632ca45bdb2b0954ecb 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 f8d11a1f0337acf60f2d9f94bd4bbbf6eb77c6de..0ede4766117e0bc28127baf1b14535370d8ea878 100644
--- a/src/main/java/net/minecraft/world/level/World.java
+++ b/src/main/java/net/minecraft/world/level/World.java
@@ -158,6 +158,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
@@ -259,6 +260,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<String, Command> 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<String, Command> 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 <T> 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 <T> 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<String> 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 c8e2f682746cd94c2f02a452bbeb672c36a916a1..f53389a49e62f54faa6af19226589305b597d1ae 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -882,6 +882,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);
@@ -917,6 +918,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
@@ -935,6 +937,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");
@@ -2385,6 +2388,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 57180e164ac51b1aac070c00d820792d13d67258..09168bced10094c2058ffe7a10613b83360d998b 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()

View File

@ -1,73 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
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");
+ }
}

View File

@ -1,189 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
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<TileEntityEnderChest> 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");
}

View File

@ -1,180 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
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<T extends CriterionInstance> {
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<String> 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();
+ }
+}

View File

@ -1,156 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
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<Entity> 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<? extends EntityLlama> 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
}

View File

@ -1,302 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
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 32e400632ec1e61374f772c6262580f84a5b2288..aee1946f96ec6007caef63b2183c5218ffe71836 100644
--- a/src/main/java/net/minecraft/server/level/EntityPlayer.java
+++ b/src/main/java/net/minecraft/server/level/EntityPlayer.java
@@ -2102,8 +2102,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 b11af463045bbd3bab8d269fde34071ca5f026af..6433ce5a5b951334efb3d8d7199f784f23392e0e 100644
--- a/src/main/java/net/minecraft/server/level/WorldServer.java
+++ b/src/main/java/net/minecraft/server/level/WorldServer.java
@@ -1018,7 +1018,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;
@@ -1363,7 +1363,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<Entity> a = Entity::isAlive;
+ public static Predicate<EntityLiving> isLivingAlive() { return b; } // Purpur - OBFHELPER
public static final Predicate<EntityLiving> b = EntityLiving::isAlive;
public static final Predicate<Entity> c = (entity) -> {
return entity.isAlive() && !entity.isVehicle() && !entity.isPassenger();
@@ -35,6 +36,7 @@ public final class IEntitySelector {
return !entity.isSpectator();
};
public static Predicate<EntityHuman> isInsomniac = (player) -> MathHelper.clamp(((EntityPlayer) player).getStatisticManager().getStatisticValue(StatisticList.CUSTOM.get(StatisticList.TIME_SINCE_REST)), 1, Integer.MAX_VALUE) >= 72000; // Paper
+ public static Predicate<EntityHuman> notAfk = (player) -> !player.isAfk(); // Purpur
// Paper start
public static final Predicate<Entity> 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 5f9e64df007ebc40f7bcb50be495b10e51d5b87a..17e6f476e60a4f5dc278894a0a874ca5ae45ee22 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,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 94910bf0c53c79588c55b89e4a023273d6c859ef..a57473fb8815545977ff08bf46d6463d2b7a9d78 100644
--- a/src/main/java/org/spigotmc/ActivationRange.java
+++ b/src/main/java/org/spigotmc/ActivationRange.java
@@ -207,6 +207,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 );

View File

@ -1,34 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
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<DedicatedServerPr
public final boolean onlineMode = this.getBoolean("online-mode", true);
public final boolean preventProxyConnections = this.getBoolean("prevent-proxy-connections", false);
public final String serverIp = this.getString("server-ip", "");
+ public final String serverName = this.getString("server-name", "Unknown Server"); // Purpur
public final boolean spawnAnimals = this.getBoolean("spawn-animals", true);
public final boolean spawnNpcs = this.getBoolean("spawn-npcs", true);
public final boolean pvp = this.getBoolean("pvp", true);
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index f53389a49e62f54faa6af19226589305b597d1ae..3efe2a4eff95349107134b097033bf978f083d56 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -2554,4 +2554,11 @@ public final class CraftServer implements Server {
}
// Paper end
+
+ // Purpur start
+ @Override
+ public String getServerName() {
+ return getProperties().serverName;
+ }
+ // Purpur end
}

View File

@ -1,35 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
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 53eca53bfcb1ea66d8cc2ecad34466f932a23866..3d42dbf9008f63cdd1458366fd87c7994cf722ca 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<TickTas
}
public String getServerModName() {
- return "Purpur"; // Purpur // Airplane // Tuinity // Paper // Spigot // CraftBukkit
+ return net.pl3x.purpur.PurpurConfig.serverModName; // Purpur // Airplane // 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);

View File

@ -1,84 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
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 a49dbcffecc971f797651984cb72c455d40f9331..bb030f5b258d82a1a3e60151b42a113b8f8022f1 100644
--- a/src/main/java/net/minecraft/world/entity/EntityLiving.java
+++ b/src/main/java/net/minecraft/world/entity/EntityLiving.java
@@ -228,6 +228,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<org.bukkit.inventory.ItemStack> drops = new ArrayList<org.bukkit.inventory.ItemStack>();
public final org.bukkit.craftbukkit.attribute.CraftAttributeMap craftAttributes;
@@ -322,8 +323,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);
@@ -1803,7 +1804,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<? extends EntityGiantZombie> 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 4545bac9309f5a3aad617f48f7808d8ae829602d..d99ab01298c7e35eae806af8fc60d5beba89c826 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
@@ -859,4 +859,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
}

View File

@ -1,57 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
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 3d42dbf9008f63cdd1458366fd87c7994cf722ca..4a5290a4d9bf8cf0ad48af135231cbef2d8d36f8 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<TickTas
public static final int TICK_TIME = 1000000000 / TPS;
private static final int SAMPLE_INTERVAL = 20; // Paper
public final double[] recentTps = new double[ 3 ];
+ public boolean lagging = false; // Purpur
public final SlackActivityAccountant slackActivityAccountant = new SlackActivityAccountant();
// Spigot end
@@ -1118,6 +1119,7 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant<TickTas
recentTps[1] = tps5.getAverage();
recentTps[2] = tps15.getAverage();
// Paper end
+ lagging = recentTps[0] < net.pl3x.purpur.PurpurConfig.laggingThreshold; // Purpur
tickSection = curTime;
}
// Tuinity - replace logic
diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java
index 2442309843bb62e08ae13c46d335c65f7d072510..089ae62c2189fe774796ecc6caf9961d3edb5ea3 100644
--- a/src/main/java/net/pl3x/purpur/PurpurConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java
@@ -150,6 +150,11 @@ public class PurpurConfig {
if (!TimingsManager.hiddenConfigs.contains("server-ip")) TimingsManager.hiddenConfigs.add("server-ip");
}
+ public static double laggingThreshold = 19.0D;
+ private static void tickLoopSettings() {
+ laggingThreshold = getDouble("settings.lagging-threshold", laggingThreshold);
+ }
+
public static boolean barrelSixRows = false;
public static boolean enderChestSixRows = false;
public static boolean enderChestPermissionRows = false;
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 3efe2a4eff95349107134b097033bf978f083d56..d46e5819bd0bc6ac16b536ee3abe5a0142995bf3 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -2560,5 +2560,10 @@ public final class CraftServer implements Server {
public String getServerName() {
return getProperties().serverName;
}
+
+ @Override
+ public boolean isLagging() {
+ return getServer().lagging;
+ }
// Purpur end
}

View File

@ -1,42 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
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<EntityTypes<?>, ItemMonsterEgg> a = Maps.newIdentityHashMap();
+ public static final Map<EntityTypes<?>, 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
}

View File

@ -1,86 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
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<T extends Entity> {
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<T extends Entity> {
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<T extends Entity> {
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<EntityTypes<?>, 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);

View File

@ -1,63 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
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<T extends Entity> {
@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<T extends Entity> {
}
}
// 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<T> 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

Some files were not shown because too many files have changed in this diff Show More