├── .gitattributes ├── .github ├── CONTRIBUTING.md ├── FUNDING.yml ├── ISSUE_TEMPLATE.md ├── ISSUE_TEMPLATE │ ├── api-question.md │ ├── bug_report.md │ └── feature_request.md └── workflows │ ├── build.yml │ └── codeql-analysis.yml ├── .gitignore ├── License.txt ├── Readme.md ├── TinyProtocol ├── pom.xml └── src │ └── main │ ├── java │ └── com │ │ └── comphenix │ │ └── tinyprotocol │ │ ├── ExamplePlugin.java │ │ ├── Reflection.java │ │ └── TinyProtocol.java │ └── resources │ └── plugin.yml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── jitpack.yml ├── pom.xml ├── settings.gradle └── src ├── main ├── java │ └── com │ │ └── comphenix │ │ └── protocol │ │ ├── AsynchronousManager.java │ │ ├── CommandBase.java │ │ ├── CommandFilter.java │ │ ├── CommandPacket.java │ │ ├── CommandProtocol.java │ │ ├── MultipleLinesPrompt.java │ │ ├── PacketLogging.java │ │ ├── PacketStream.java │ │ ├── PacketType.java │ │ ├── PacketTypeEnum.java │ │ ├── PacketTypeLookup.java │ │ ├── PacketTypeParser.java │ │ ├── ProtocolConfig.java │ │ ├── ProtocolLib.java │ │ ├── ProtocolLibrary.java │ │ ├── ProtocolLogger.java │ │ ├── ProtocolManager.java │ │ ├── RangeParser.java │ │ ├── async │ │ ├── AsyncFilterManager.java │ │ ├── AsyncListenerHandler.java │ │ ├── AsyncMarker.java │ │ ├── AsyncRunnable.java │ │ ├── NullPacketListener.java │ │ ├── PacketEventHolder.java │ │ ├── PacketProcessingQueue.java │ │ ├── PacketSendingQueue.java │ │ ├── PlayerSendingHandler.java │ │ └── Synchronization.java │ │ ├── collections │ │ ├── ExpireHashMap.java │ │ └── IntegerMap.java │ │ ├── concurrency │ │ ├── AbstractConcurrentListenerMultimap.java │ │ ├── AbstractIntervalTree.java │ │ ├── BlockingHashMap.java │ │ ├── ConcurrentPlayerMap.java │ │ ├── PacketTypeSet.java │ │ └── SortedCopyOnWriteArray.java │ │ ├── error │ │ ├── BasicErrorReporter.java │ │ ├── DelegatedErrorReporter.java │ │ ├── DetailedErrorReporter.java │ │ ├── ErrorReporter.java │ │ ├── PluginContext.java │ │ ├── Report.java │ │ ├── ReportType.java │ │ └── RethrowErrorReporter.java │ │ ├── events │ │ ├── AbstractStructure.java │ │ ├── ConnectionSide.java │ │ ├── InternalStructure.java │ │ ├── ListenerOptions.java │ │ ├── ListenerPriority.java │ │ ├── ListeningWhitelist.java │ │ ├── MonitorAdapter.java │ │ ├── NetworkMarker.java │ │ ├── PacketAdapter.java │ │ ├── PacketContainer.java │ │ ├── PacketEvent.java │ │ ├── PacketListener.java │ │ ├── PacketMetadata.java │ │ ├── PacketOutputAdapter.java │ │ ├── PacketOutputHandler.java │ │ ├── PacketPostAdapter.java │ │ ├── PacketPostListener.java │ │ ├── ScheduledPacket.java │ │ └── SerializedOfflinePlayer.java │ │ ├── injector │ │ ├── BukkitUnwrapper.java │ │ ├── EntityUtilities.java │ │ ├── GamePhase.java │ │ ├── InternalManager.java │ │ ├── ListenerInvoker.java │ │ ├── NetworkProcessor.java │ │ ├── PacketConstructor.java │ │ ├── PacketFilterBuilder.java │ │ ├── PacketFilterManager.java │ │ ├── PluginVerifier.java │ │ ├── PrioritizedListener.java │ │ ├── SortedPacketListenerList.java │ │ ├── StructureCache.java │ │ ├── netty │ │ │ ├── ChannelListener.java │ │ │ ├── Injector.java │ │ │ ├── NettyByteBufAdapter.java │ │ │ ├── WirePacket.java │ │ │ ├── channel │ │ │ │ ├── EmptyInjector.java │ │ │ │ ├── InboundPacketInterceptor.java │ │ │ │ ├── InjectionFactory.java │ │ │ │ ├── NettyChannelInjector.java │ │ │ │ ├── NettyChannelMinimalInjector.java │ │ │ │ ├── NettyChannelProxy.java │ │ │ │ ├── NettyEventLoopProxy.java │ │ │ │ └── WirePacketEncoder.java │ │ │ └── manager │ │ │ │ ├── InjectionChannelInboundHandler.java │ │ │ │ ├── InjectionChannelInitializer.java │ │ │ │ ├── ListeningList.java │ │ │ │ ├── NetworkManagerInjector.java │ │ │ │ ├── NetworkManagerPacketInjector.java │ │ │ │ └── NetworkManagerPlayerInjector.java │ │ ├── packet │ │ │ ├── AbstractPacketInjector.java │ │ │ ├── MapContainer.java │ │ │ ├── PacketInjector.java │ │ │ └── PacketRegistry.java │ │ ├── player │ │ │ ├── AbstractPlayerInjectionHandler.java │ │ │ └── PlayerInjectionHandler.java │ │ └── temporary │ │ │ ├── MinimalInjector.java │ │ │ ├── TemporaryPlayer.java │ │ │ └── TemporaryPlayerFactory.java │ │ ├── metrics │ │ ├── Metrics.java │ │ └── Statistics.java │ │ ├── package-info.java │ │ ├── reflect │ │ ├── EquivalentConverter.java │ │ ├── ExactReflection.java │ │ ├── FieldAccessException.java │ │ ├── FuzzyReflection.java │ │ ├── MethodInfo.java │ │ ├── ObjectWriter.java │ │ ├── PrettyPrinter.java │ │ ├── StructureModifier.java │ │ ├── accessors │ │ │ ├── Accessors.java │ │ │ ├── ConstructorAccessor.java │ │ │ ├── DefaultConstrutorAccessor.java │ │ │ ├── DefaultFieldAccessor.java │ │ │ ├── DefaultMethodAccessor.java │ │ │ ├── FieldAccessor.java │ │ │ ├── MemorizingFieldAccessor.java │ │ │ ├── MethodAccessor.java │ │ │ └── MethodHandleHelper.java │ │ ├── cloning │ │ │ ├── AggregateCloner.java │ │ │ ├── BukkitCloner.java │ │ │ ├── Cloner.java │ │ │ ├── CollectionCloner.java │ │ │ ├── FieldCloner.java │ │ │ ├── GuavaOptionalCloner.java │ │ │ ├── ImmutableDetector.java │ │ │ ├── JavaOptionalCloner.java │ │ │ ├── NullableCloner.java │ │ │ └── SerializableCloner.java │ │ ├── fuzzy │ │ │ ├── AbstractFuzzyMatcher.java │ │ │ ├── AbstractFuzzyMember.java │ │ │ ├── ClassRegexMatcher.java │ │ │ ├── ClassSetMatcher.java │ │ │ ├── ClassTypeMatcher.java │ │ │ ├── FuzzyClassContract.java │ │ │ ├── FuzzyFieldContract.java │ │ │ ├── FuzzyMatchers.java │ │ │ └── FuzzyMethodContract.java │ │ └── instances │ │ │ ├── BannedGenerator.java │ │ │ ├── CollectionGenerator.java │ │ │ ├── DefaultInstances.java │ │ │ ├── ExistingGenerator.java │ │ │ ├── InstanceProvider.java │ │ │ ├── MinecraftGenerator.java │ │ │ ├── NotConstructableException.java │ │ │ └── PrimitiveGenerator.java │ │ ├── timing │ │ ├── HistogramStream.java │ │ ├── OnlineComputation.java │ │ ├── StatisticsStream.java │ │ ├── TimedListenerManager.java │ │ ├── TimedTracker.java │ │ └── TimingReportGenerator.java │ │ ├── updater │ │ ├── SpigotUpdater.java │ │ └── Updater.java │ │ ├── utility │ │ ├── ByteBuddyFactory.java │ │ ├── ByteBuddyGenerated.java │ │ ├── CachedPackage.java │ │ ├── ChatExtensions.java │ │ ├── ClassSource.java │ │ ├── Closer.java │ │ ├── HexDumper.java │ │ ├── MinecraftFields.java │ │ ├── MinecraftMethods.java │ │ ├── MinecraftProtocolVersion.java │ │ ├── MinecraftReflection.java │ │ ├── MinecraftVersion.java │ │ ├── Optionals.java │ │ ├── SafeCacheBuilder.java │ │ ├── SnapshotVersion.java │ │ ├── StreamSerializer.java │ │ ├── Util.java │ │ └── ZeroBuffer.java │ │ └── wrappers │ │ ├── AbstractWrapper.java │ │ ├── AdventureComponentConverter.java │ │ ├── AutoWrapper.java │ │ ├── BlockPosition.java │ │ ├── BukkitConverters.java │ │ ├── ChunkCoordIntPair.java │ │ ├── ClonableWrapper.java │ │ ├── ComponentConverter.java │ │ ├── ComponentParser.java │ │ ├── Converters.java │ │ ├── Either.java │ │ ├── EnumWrappers.java │ │ ├── GuavaReflection.java │ │ ├── GuavaWrappers.java │ │ ├── MinecraftKey.java │ │ ├── MovingObjectPositionBlock.java │ │ ├── MultiBlockChangeInfo.java │ │ ├── Pair.java │ │ ├── PlayerInfoData.java │ │ ├── TroveWrapper.java │ │ ├── Vector3F.java │ │ ├── WrappedAttribute.java │ │ ├── WrappedAttributeModifier.java │ │ ├── WrappedBlockData.java │ │ ├── WrappedChatComponent.java │ │ ├── WrappedDataValue.java │ │ ├── WrappedDataWatcher.java │ │ ├── WrappedEnumEntityUseAction.java │ │ ├── WrappedGameProfile.java │ │ ├── WrappedIntHashMap.java │ │ ├── WrappedLevelChunkData.java │ │ ├── WrappedMessageSignature.java │ │ ├── WrappedParticle.java │ │ ├── WrappedProfilePublicKey.java │ │ ├── WrappedRegistrable.java │ │ ├── WrappedRegistry.java │ │ ├── WrappedRemoteChatSessionData.java │ │ ├── WrappedSaltedSignature.java │ │ ├── WrappedServerPing.java │ │ ├── WrappedSignedProperty.java │ │ ├── WrappedStatistic.java │ │ ├── WrappedVillagerData.java │ │ ├── WrappedWatchableObject.java │ │ ├── codecs │ │ ├── WrappedCodec.java │ │ ├── WrappedDataResult.java │ │ └── WrappedDynamicOps.java │ │ ├── collection │ │ ├── AbstractConverted.java │ │ ├── BiFunction.java │ │ ├── CachedCollection.java │ │ ├── CachedSet.java │ │ ├── ConvertedCollection.java │ │ ├── ConvertedList.java │ │ ├── ConvertedMap.java │ │ ├── ConvertedMultimap.java │ │ └── ConvertedSet.java │ │ ├── nbt │ │ ├── MemoryElement.java │ │ ├── NameProperty.java │ │ ├── NbtBase.java │ │ ├── NbtCompound.java │ │ ├── NbtFactory.java │ │ ├── NbtList.java │ │ ├── NbtType.java │ │ ├── NbtVisitor.java │ │ ├── NbtWrapper.java │ │ ├── TileEntityAccessor.java │ │ ├── WrappedCompound.java │ │ ├── WrappedElement.java │ │ ├── WrappedList.java │ │ └── io │ │ │ ├── NbtBinarySerializer.java │ │ │ ├── NbtConfigurationSerializer.java │ │ │ └── NbtTextSerializer.java │ │ └── ping │ │ ├── LegacyServerPing.java │ │ ├── ServerPingImpl.java │ │ └── ServerPingRecord.java └── resources │ ├── config.yml │ └── plugin.yml └── test ├── java └── com │ └── comphenix │ ├── integration │ └── protocol │ │ ├── SimpleCraftBukkitITCase.java │ │ ├── SimpleMinecraftClient.java │ │ └── TestPingPacket.java │ └── protocol │ ├── BukkitInitialization.java │ ├── MinecraftVersionTest.java │ ├── PacketTypeTest.java │ ├── concurrency │ └── BlockingHashMapTest.java │ ├── events │ ├── PacketContainerTest.java │ └── SerializedOfflinePlayerTest.java │ ├── injector │ ├── EntityUtilitiesTest.java │ ├── PluginVerifierTest.java │ ├── SortedCopyOnWriteArrayTest.java │ ├── WirePacketTest.java │ └── temporary │ │ └── TemporaryPlayerFactoryTest.java │ ├── reflect │ ├── accessors │ │ └── AccessorsTest.java │ └── cloning │ │ └── AggregateClonerTest.java │ ├── updater │ └── UpdaterTest.java │ ├── utility │ ├── CachedPackageTest.java │ ├── MinecraftMethodsTest.java │ ├── MinecraftReflectionTest.java │ ├── MinecraftReflectionTestUtil.java │ ├── SnapshotVersionTest.java │ ├── StreamSerializerTest.java │ └── TestUtils.java │ └── wrappers │ ├── AutoWrapperTest.java │ ├── BukkitConvertersTest.java │ ├── ChunkCoordIntPairTest.java │ ├── CloningTest.java │ ├── ConverterTest.java │ ├── EitherTest.java │ ├── EnumWrappersTest.java │ ├── MultiBlockChangeTest.java │ ├── PlayerInfoDataTest.java │ ├── WrappedAttributeTest.java │ ├── WrappedBlockDataTest.java │ ├── WrappedChatComponentTest.java │ ├── WrappedDataWatcherTest.java │ ├── WrappedGameProfileTest.java │ ├── WrappedLevelChunkDataTest.java │ ├── WrappedParticleTest.java │ ├── WrappedProfilePublicKeyTest.java │ ├── WrappedRegistryTest.java │ ├── WrappedSaltedSignatureTest.java │ ├── WrappedServerPingTest.java │ └── nbt │ ├── NbtCompoundTest.java │ ├── NbtFactoryTest.java │ ├── TileEntityTest.java │ └── io │ └── NbtConfigurationSerializerTest.java └── resources ├── mockito-extensions └── org.mockito.plugins.MockMaker └── tux.png /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Contributing to ProtocolLib 2 | =========================== 3 | This page will detail specific things that must be done if you intend to contribute to this project. 4 | 5 | ## Updating ProtocolLib to a New Protocol Version 6 | #### Before we get started: 7 | 1. **When do we need to update the protocol version?** 8 | _A Minecraft protocol version is a number for each specification of the Minecraft protocol. 9 | This means it is incremented when there is a change to the [Protocol Specification](http://wiki.vg/Protocol), 10 | but not necessarily for each Minecraft version update. If the latest Minecraft version contains a protocol change, 11 | that means ProtocolLib needs to be updated._ 12 | 2. **When do we need to update other parts of ProtocolLib?** 13 | _When the package version guard changes. The package version guard is the version string inserted 14 | into the package identifier for CraftBukkit and net.minecraft.server (e.g. v1_9_R2). It is incremented 15 | by Spigot if there is a major breaking change in the internal server code. This is to encourage plugins 16 | that interact directly with CraftBukkit/nms code to update more specifically. However, since most of 17 | ProtocolLib uses reflection, and the structure of packet classes is generally static, one will have 18 | to go through the code and change imports from nms/CraftBukkit._ 19 | 20 | #### Ready? Let's get started! 21 | 1. Read the [Protocol Changes](http://wiki.vg/Protocol_History). Always make sure the list is both 22 | complete and correct. If you're unsure, don't hesitate to ask in #mcdevs (the people who maintain wiki.vg) on [libera.chat](http://libera.chat) 23 | or #spigot on [irc.spi.gt](http://irc.spi.gt) ([webchat](https://irc.spi.gt/iris/?channels=spigot)). 24 | 2. Search for usages of the now-defunct NMS package guard and change them. 25 | 3. The class `com.comphenix.protocol.PacketType` contains a list of all the packets. If any packets were added or removed 26 | (or had their ID changed), make sure to update this list. If a packet was removed 27 | in favor of usage of another packet, instead of removing it, move it to the bottom of the list 28 | in its section, add a deprecation warning to it, and redirect it to the packet that replaced it. 29 | 4. `mvn` in the root directory to build the project. 30 | 5. If tests fail in the maven build, go through the tests to make sure you removed references to any removed packets 31 | and changed the NMS version guards. 32 | 6. Increment the package version in `com.comphenix.protocol.utility.Constants`. 33 | 7. `com.comphenix.protocol.ProtocolLibrary` contains several constants that must be updated, including the Minecraft version 34 | and the release date. 35 | 8. `com.comphenix.protocol.utility.MinecraftProtocolVersion` contains a map of all the protocol version integers. 36 | If the protocol version has been incremented, add a new line to the map. 37 | 9. `mvn` in root directory again. If it builds successfully, test on the appropriate version of a Spigot server. If 38 | the build fails, debug! 39 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [dmulloy2] 2 | custom: ["https://paypal.me/dmulloy2"] 3 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | _Follow this template except for feature requests. Use pastebin when providing /protocol dump and any relevant errors._ 2 | 3 | Make sure you've done the following: 4 | - [ ] You're using the latest build for your server version 5 | - [ ] This isn't fixed in a recent development build 6 | - [ ] This isn't an issue caused by another plugin 7 | - [ ] You've checked for duplicate issues 8 | - [ ] You didn't use `/reload` 9 | 10 | Debug paste link: 11 | 12 | Description and relevant errors: 13 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/api-question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: API question 3 | about: Questions related to using ProtocolLib in your plugins 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Make sure you're doing the following** 11 | - [ ] You're using the latest build for your server version 12 | - [ ] This isn't an issue caused by another plugin 13 | - [ ] You've checked for duplicate issues 14 | - [ ] You didn't use `/reload` 15 | 16 | **Describe the question** 17 | A clear and concise description of what your question is. 18 | 19 | **API method(s) used** 20 | List what API method(s) you're using 21 | 22 | **Expected behavior** 23 | A clear and concise description of what you expected to happen. 24 | 25 | **Code** 26 | If applicable, add relevant code from your project 27 | 28 | **Additional context** 29 | Add any other context about the problem here. 30 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | - [ ] This issue is not solved in a development build 11 | 12 | **Describe the bug** 13 | A clear and concise description of what the bug is. 14 | 15 | **To Reproduce** 16 | Steps to reproduce the behavior: 17 | 1. Go to '...' 18 | 2. Click on '....' 19 | 3. Scroll down to '....' 20 | 4. See error 21 | 22 | **Expected behavior** 23 | A clear and concise description of what you expected to happen. 24 | 25 | **Screenshots** 26 | If applicable, add screenshots to help explain your problem. 27 | 28 | **Version Info** 29 | Provide your ProtocolLib install info with `/protocol dump` through pastebin. 30 | 31 | **Additional context** 32 | Add any other context about the problem here. 33 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | - [ ] This feature is not currently present in a development build 11 | 12 | **Is your feature request related to a problem? Please describe.** 13 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 14 | 15 | **Describe the solution you'd like** 16 | A clear and concise description of what you want to happen. 17 | 18 | **Describe alternatives you've considered** 19 | A clear and concise description of any alternative solutions or features you've considered. 20 | 21 | **Additional context** 22 | Add any other context or screenshots about the feature request here. 23 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: ProtocolLib full build lifecycle 2 | 3 | on: 4 | - push 5 | - pull_request 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Checkout repository 12 | uses: actions/checkout@v3 13 | 14 | - name: Setup java 15 | uses: actions/setup-java@v3 16 | with: 17 | distribution: 'temurin' 18 | java-version: '19' 19 | cache: 'gradle' 20 | 21 | - name: Run gradle build lifecycle 22 | run: ./gradlew build shadowJar --no-daemon 23 | 24 | - name: Upload plugin file 25 | uses: actions/upload-artifact@v2 26 | with: 27 | name: ProtocolLib 28 | path: build/libs/ProtocolLib.jar 29 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | name: "CodeQL" 2 | 3 | on: 4 | push: 5 | branches: [ "master" ] 6 | pull_request: 7 | # The branches below must be a subset of the branches above 8 | branches: [ "master" ] 9 | schedule: 10 | - cron: '28 9 * * 1' 11 | 12 | jobs: 13 | analyze: 14 | name: Analyze 15 | runs-on: ubuntu-latest 16 | permissions: 17 | actions: read 18 | contents: read 19 | security-events: write 20 | 21 | steps: 22 | - name: Checkout repository 23 | uses: actions/checkout@v3 24 | 25 | - name: Setup java 26 | uses: actions/setup-java@v3 27 | with: 28 | distribution: 'temurin' 29 | java-version: '19' 30 | cache: 'gradle' 31 | 32 | - name: Initialize CodeQL 33 | uses: github/codeql-action/init@v2 34 | with: 35 | languages: 'java' 36 | 37 | - name: Run gradle build lifecycle 38 | run: ./gradlew build -x test --no-daemon 39 | 40 | - name: Perform CodeQL Analysis 41 | uses: github/codeql-action/analyze@v2 42 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ################# 2 | ## Eclipse 3 | ################# 4 | 5 | # Generic project files 6 | .project 7 | .classpath 8 | .settings/ 9 | bin/ 10 | .idea/ 11 | *.iml 12 | .ipr 13 | .iws 14 | 15 | *.pydevproject 16 | .metadata 17 | tmp/ 18 | *.tmp 19 | *.bak 20 | *.swp 21 | *~.nib 22 | local.properties 23 | .loadpath 24 | 25 | # External tool builders 26 | .externalToolBuilders/ 27 | 28 | # Locally stored "Eclipse launch configurations" 29 | *.launch 30 | 31 | # CDT-specific 32 | .cproject 33 | 34 | # PDT-specific 35 | .buildpath 36 | 37 | ################# 38 | ## Maven 39 | ################# 40 | 41 | target/ 42 | dependency-reduced-pom.xml 43 | 44 | ################# 45 | ## Visual Studio 46 | ################# 47 | 48 | ## Ignore Visual Studio temporary files, build results, and 49 | ## files generated by popular Visual Studio add-ons. 50 | 51 | # User-specific files 52 | *.suo 53 | *.user 54 | *.sln.docstates 55 | 56 | # Build results 57 | [Dd]ebug/ 58 | [Rr]elease/ 59 | *_i.c 60 | *_p.c 61 | *.ilk 62 | *.meta 63 | *.obj 64 | *.pch 65 | *.pdb 66 | *.pgc 67 | *.pgd 68 | *.rsp 69 | *.sbr 70 | *.tlb 71 | *.tli 72 | *.tlh 73 | *.tmp 74 | *.vspscc 75 | .builds 76 | *.dotCover 77 | 78 | ## TODO: If you have NuGet Package Restore enabled, uncomment this 79 | #packages/ 80 | 81 | # Visual C++ cache files 82 | ipch/ 83 | *.aps 84 | *.ncb 85 | *.opensdf 86 | *.sdf 87 | 88 | # Visual Studio profiler 89 | *.psess 90 | *.vsp 91 | 92 | # ReSharper is a .NET coding add-in 93 | _ReSharper* 94 | 95 | # Installshield output folder 96 | [Ee]xpress 97 | 98 | # DocProject is a documentation generator add-in 99 | DocProject/buildhelp/ 100 | DocProject/Help/*.HxT 101 | DocProject/Help/*.HxC 102 | DocProject/Help/*.hhc 103 | DocProject/Help/*.hhk 104 | DocProject/Help/*.hhp 105 | DocProject/Help/Html2 106 | DocProject/Help/html 107 | 108 | # Click-Once directory 109 | publish 110 | 111 | # Others 112 | [Bb]in 113 | [Oo]bj 114 | sql 115 | TestResults 116 | *.Cache 117 | ClientBin 118 | stylecop.* 119 | ~$* 120 | *.dbmdl 121 | Generated_Code #added for RIA/Silverlight projects 122 | 123 | # Backup & report files from converting an old project file to a newer 124 | # Visual Studio version. Backup files are not needed, because we have git ;-) 125 | _UpgradeReport_Files/ 126 | Backup*/ 127 | UpgradeLog*.XML 128 | 129 | 130 | 131 | ############ 132 | ## Windows 133 | ############ 134 | 135 | # Windows image file caches 136 | Thumbs.db 137 | 138 | # Folder config file 139 | Desktop.ini 140 | 141 | 142 | ############# 143 | ## Python 144 | ############# 145 | 146 | *.py[co] 147 | 148 | # Packages 149 | *.egg 150 | *.egg-info 151 | dist 152 | build 153 | eggs 154 | parts 155 | bin 156 | var 157 | sdist 158 | develop-eggs 159 | .installed.cfg 160 | 161 | # Installer logs 162 | pip-log.txt 163 | 164 | # Unit test / coverage reports 165 | .coverage 166 | .tox 167 | 168 | # Translations 169 | *.mo 170 | 171 | # Mr Developer 172 | .mr.developer.cfg 173 | 174 | # Mac crap 175 | .DS_Store 176 | 177 | # Log4J files 178 | logs/ 179 | 180 | .gradle/ 181 | build/ 182 | logs/ 183 | .java-version 184 | -------------------------------------------------------------------------------- /TinyProtocol/src/main/resources/plugin.yml: -------------------------------------------------------------------------------- 1 | name: TinyProtocol 2 | version: 0.1.0 3 | description: Intercept packets without ProtocolLib 4 | author: Comphenix 5 | 6 | load: startup 7 | 8 | main: com.comphenix.tinyprotocol.ExamplePlugin 9 | database: false 10 | 11 | commands: 12 | toggleinjection: 13 | description: Toggle the TinyProtocol injection of the current player. 14 | usage: / -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | nexusUsername="" 2 | nexusPassword="" 3 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aadnk/ProtocolLib/e77ed96957f0479f68f93a6ac685bdc2e54d279d/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip 4 | networkTimeout=10000 5 | zipStoreBase=GRADLE_USER_HOME 6 | zipStorePath=wrapper/dists 7 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 48 | echo. 49 | echo Please set the JAVA_HOME variable in your environment to match the 50 | echo location of your Java installation. 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 62 | echo. 63 | echo Please set the JAVA_HOME variable in your environment to match the 64 | echo location of your Java installation. 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /jitpack.yml: -------------------------------------------------------------------------------- 1 | before_install: 2 | - source "$HOME/.sdkman/bin/sdkman-init.sh" 3 | - sdk update 4 | - sdk install java 17.0.4-tem 5 | - sdk use java 17.0.4-tem 6 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * This file was generated by the Gradle 'init' task. 3 | */ 4 | 5 | rootProject.name = 'ProtocolLib' 6 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/async/AsyncRunnable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. 3 | * Copyright (C) 2012 Kristian S. Stangeland 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; either version 2 of 7 | * the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 15 | * 02111-1307 USA 16 | */ 17 | 18 | package com.comphenix.protocol.async; 19 | 20 | /** 21 | * A runnable representing a asynchronous event listener. 22 | * 23 | * @author Kristian 24 | */ 25 | public interface AsyncRunnable extends Runnable { 26 | 27 | /** 28 | * Retrieve a unique worker ID. 29 | * @return Unique worker ID. 30 | */ 31 | public int getID(); 32 | 33 | /** 34 | * Stop the given runnable. 35 | *

36 | * This may not occur right away. 37 | * @return TRUE if the thread was stopped, FALSE if it was already stopped. 38 | * @throws InterruptedException if it is interrupted 39 | */ 40 | public boolean stop() throws InterruptedException; 41 | 42 | /** 43 | * Determine if we're running or not. 44 | * @return TRUE if we're running, FALSE otherwise. 45 | */ 46 | public boolean isRunning(); 47 | 48 | /** 49 | * Determine if this runnable has already run its course. 50 | * @return TRUE if it has been stopped, FALSE otherwise. 51 | */ 52 | boolean isFinished(); 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/async/NullPacketListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. 3 | * Copyright (C) 2012 Kristian S. Stangeland 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; either version 2 of 7 | * the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 15 | * 02111-1307 USA 16 | */ 17 | 18 | package com.comphenix.protocol.async; 19 | 20 | import com.comphenix.protocol.events.*; 21 | 22 | import org.bukkit.plugin.Plugin; 23 | 24 | /** 25 | * Represents a NO OPERATION listener. 26 | * 27 | * @author Kristian 28 | */ 29 | class NullPacketListener implements PacketListener { 30 | 31 | private ListeningWhitelist sendingWhitelist; 32 | private ListeningWhitelist receivingWhitelist; 33 | private Plugin plugin; 34 | 35 | /** 36 | * Create a no-op listener with the same whitelist and plugin as the given listener. 37 | * @param original - the packet listener to copy. 38 | */ 39 | public NullPacketListener(PacketListener original) { 40 | this.sendingWhitelist = cloneWhitelist(ListenerPriority.LOW, original.getSendingWhitelist()); 41 | this.receivingWhitelist = cloneWhitelist(ListenerPriority.LOW, original.getReceivingWhitelist()); 42 | this.plugin = original.getPlugin(); 43 | } 44 | 45 | @Override 46 | public void onPacketSending(PacketEvent event) { 47 | // NULL 48 | } 49 | 50 | @Override 51 | public void onPacketReceiving(PacketEvent event) { 52 | // NULL 53 | } 54 | 55 | @Override 56 | public ListeningWhitelist getSendingWhitelist() { 57 | return sendingWhitelist; 58 | } 59 | 60 | @Override 61 | public ListeningWhitelist getReceivingWhitelist() { 62 | return receivingWhitelist; 63 | } 64 | 65 | private ListeningWhitelist cloneWhitelist(ListenerPriority priority, ListeningWhitelist whitelist) { 66 | if (whitelist != null) 67 | // We don't use the Bukkit API, so don't engage the ProtocolLib synchronization code 68 | return ListeningWhitelist.newBuilder(whitelist).priority(priority).mergeOptions(ListenerOptions.ASYNC).build(); 69 | else 70 | return null; 71 | } 72 | 73 | @Override 74 | public Plugin getPlugin() { 75 | return plugin; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/async/PacketEventHolder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. 3 | * Copyright (C) 2012 Kristian S. Stangeland 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; either version 2 of 7 | * the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 15 | * 02111-1307 USA 16 | */ 17 | 18 | package com.comphenix.protocol.async; 19 | 20 | import com.comphenix.protocol.events.PacketEvent; 21 | import com.google.common.base.Preconditions; 22 | import com.google.common.collect.ComparisonChain; 23 | import com.google.common.primitives.Longs; 24 | 25 | /** 26 | * Provides a comparable to a packet event. 27 | * 28 | * @author Kristian 29 | */ 30 | class PacketEventHolder implements Comparable { 31 | 32 | private PacketEvent event; 33 | private long sendingIndex = 0; 34 | 35 | /** 36 | * A wrapper that ensures the packet event is ordered by sending index. 37 | * @param event - packet event to wrap. 38 | */ 39 | public PacketEventHolder(PacketEvent event) { 40 | this.event = Preconditions.checkNotNull(event, "Event must be non-null"); 41 | 42 | if (event.getAsyncMarker() != null) 43 | this.sendingIndex = event.getAsyncMarker().getNewSendingIndex(); 44 | } 45 | 46 | /** 47 | * Retrieve the stored event. 48 | * @return The stored event. 49 | */ 50 | public PacketEvent getEvent() { 51 | return event; 52 | } 53 | 54 | @Override 55 | public int compareTo(PacketEventHolder other) { 56 | return ComparisonChain.start(). 57 | compare(sendingIndex, other.sendingIndex). 58 | result(); 59 | } 60 | 61 | @Override 62 | public boolean equals(Object other) { 63 | // Standard equals 64 | if (other == this) 65 | return true; 66 | if (other instanceof PacketEventHolder) 67 | return sendingIndex == ((PacketEventHolder) other).sendingIndex; 68 | else 69 | return false; 70 | } 71 | 72 | @Override 73 | public int hashCode() { 74 | return Longs.hashCode(sendingIndex); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/error/DelegatedErrorReporter.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.error; 2 | 3 | import com.comphenix.protocol.error.Report.ReportBuilder; 4 | 5 | import org.bukkit.plugin.Plugin; 6 | 7 | /** 8 | * Construct an error reporter that delegates to another error reporter. 9 | * @author Kristian 10 | */ 11 | public class DelegatedErrorReporter implements ErrorReporter { 12 | private final ErrorReporter delegated; 13 | 14 | /** 15 | * Construct a new error reporter that forwards all reports to a given reporter. 16 | * @param delegated - the delegated reporter. 17 | */ 18 | public DelegatedErrorReporter(ErrorReporter delegated) { 19 | this.delegated = delegated; 20 | } 21 | 22 | /** 23 | * Retrieve the underlying error reporter. 24 | * @return Underlying error reporter. 25 | */ 26 | public ErrorReporter getDelegated() { 27 | return delegated; 28 | } 29 | 30 | @Override 31 | public void reportMinimal(Plugin sender, String methodName, Throwable error) { 32 | delegated.reportMinimal(sender, methodName, error); 33 | } 34 | 35 | @Override 36 | public void reportMinimal(Plugin sender, String methodName, Throwable error, Object... parameters) { 37 | delegated.reportMinimal(sender, methodName, error, parameters); 38 | } 39 | 40 | @Override 41 | public void reportDebug(Object sender, Report report) { 42 | Report transformed = filterReport(sender, report, false); 43 | 44 | if (transformed != null) { 45 | delegated.reportDebug(sender, transformed); 46 | } 47 | } 48 | 49 | @Override 50 | public void reportWarning(Object sender, Report report) { 51 | Report transformed = filterReport(sender, report, false); 52 | 53 | if (transformed != null) { 54 | delegated.reportWarning(sender, transformed); 55 | } 56 | } 57 | 58 | @Override 59 | public void reportDetailed(Object sender, Report report) { 60 | Report transformed = filterReport(sender, report, true); 61 | 62 | if (transformed != null) { 63 | delegated.reportDetailed(sender, transformed); 64 | } 65 | } 66 | 67 | /** 68 | * Invoked before an error report is passed on to the underlying error reporter. 69 | *

70 | * To cancel a report, return NULL. 71 | * @param sender - the sender instance or class. 72 | * @param report - the error report. 73 | * @param detailed - whether or not the report will be displayed in detail. 74 | * @return The report to pass on, or NULL to cancel it. 75 | */ 76 | protected Report filterReport(Object sender, Report report, boolean detailed) { 77 | return report; 78 | } 79 | 80 | @Override 81 | public void reportWarning(Object sender, ReportBuilder reportBuilder) { 82 | reportWarning(sender, reportBuilder.build()); 83 | } 84 | 85 | @Override 86 | public void reportDetailed(Object sender, ReportBuilder reportBuilder) { 87 | reportDetailed(sender, reportBuilder.build()); 88 | } 89 | 90 | @Override 91 | public void reportDebug(Object sender, ReportBuilder builder) { 92 | reportDebug(sender, builder.build()); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/error/RethrowErrorReporter.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.error; 2 | 3 | import com.comphenix.protocol.error.Report.ReportBuilder; 4 | import com.google.common.base.Joiner; 5 | 6 | import org.bukkit.plugin.Plugin; 7 | 8 | /** 9 | * Represents an error reporter that rethrows every exception instead. 10 | * @author Kristian 11 | */ 12 | public class RethrowErrorReporter implements ErrorReporter { 13 | @Override 14 | public void reportMinimal(Plugin sender, String methodName, Throwable error) { 15 | throw new RuntimeException("Minimal error by " + sender + " in " + methodName, error); 16 | } 17 | 18 | @Override 19 | public void reportMinimal(Plugin sender, String methodName, Throwable error, Object... parameters) { 20 | throw new RuntimeException( 21 | "Minimal error by " + sender + " in " + methodName + " with " + Joiner.on(",").join(parameters), error); 22 | } 23 | 24 | @Override 25 | public void reportDebug(Object sender, Report report) { 26 | // Do nothing - this is just a debug 27 | } 28 | 29 | @Override 30 | public void reportDebug(Object sender, ReportBuilder builder) { 31 | // As above 32 | } 33 | 34 | @Override 35 | public void reportWarning(Object sender, ReportBuilder reportBuilder) { 36 | reportWarning(sender, reportBuilder.build()); 37 | } 38 | 39 | @Override 40 | public void reportWarning(Object sender, Report report) { 41 | throw new RuntimeException("Warning by " + sender + ": " + report); 42 | } 43 | 44 | @Override 45 | public void reportDetailed(Object sender, ReportBuilder reportBuilder) { 46 | reportDetailed(sender, reportBuilder.build()); 47 | } 48 | 49 | @Override 50 | public void reportDetailed(Object sender, Report report) { 51 | throw new RuntimeException("Detailed error " + sender + ": " + report, report.getException()); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/events/ConnectionSide.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. 3 | * Copyright (C) 2012 Kristian S. Stangeland 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; either version 2 of 7 | * the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 15 | * 02111-1307 USA 16 | */ 17 | 18 | package com.comphenix.protocol.events; 19 | 20 | import com.comphenix.protocol.PacketType.Sender; 21 | 22 | /** 23 | * Used to set a packet filter. 24 | * 25 | * @author Kristian 26 | */ 27 | public enum ConnectionSide { 28 | /** 29 | * Listen for server side packets that will invoke onPacketSending(). 30 | */ 31 | SERVER_SIDE, 32 | 33 | /** 34 | * Listen for client side packets that will invoke onPacketReceiving(). 35 | */ 36 | CLIENT_SIDE, 37 | 38 | /** 39 | * Listen for both client and server side packets. 40 | */ 41 | BOTH; 42 | 43 | public boolean isForClient() { 44 | return this == CLIENT_SIDE || this == BOTH; 45 | } 46 | 47 | public boolean isForServer() { 48 | return this == SERVER_SIDE || this == BOTH; 49 | } 50 | 51 | /** 52 | * Retrieve the sender of this connection side. 53 | *

54 | * This is NULL for {@link #BOTH}. 55 | * @return The sender. 56 | */ 57 | public Sender getSender() { 58 | if (this == SERVER_SIDE) 59 | return Sender.SERVER; 60 | else if (this == CLIENT_SIDE) 61 | return Sender.CLIENT; 62 | return null; 63 | } 64 | 65 | /** 66 | * If both connection sides are present, return {@link #BOTH} - otherwise, return the one valud connection side. 67 | *

68 | * NULL is not a valid connection side. 69 | * @param a - the first connection side. 70 | * @param b - the second connection side. 71 | * @return BOTH or the one valid side, or NULL. 72 | */ 73 | public static ConnectionSide add(ConnectionSide a, ConnectionSide b) { 74 | if (a == null) 75 | return b; 76 | if (b == null) 77 | return a; 78 | 79 | // Now merge them together 80 | boolean client = a.isForClient() || b.isForClient(); 81 | boolean server = a.isForServer() || b.isForServer(); 82 | 83 | if (client && server) 84 | return BOTH; 85 | else if (client) 86 | return CLIENT_SIDE; 87 | else 88 | return SERVER_SIDE; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/events/InternalStructure.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.events; 2 | 3 | import java.util.Optional; 4 | 5 | import com.comphenix.protocol.reflect.EquivalentConverter; 6 | import com.comphenix.protocol.reflect.StructureModifier; 7 | import com.comphenix.protocol.wrappers.Converters; 8 | 9 | public class InternalStructure extends AbstractStructure { 10 | 11 | public InternalStructure(Object handle, StructureModifier structureModifier) { 12 | super(handle, structureModifier); 13 | } 14 | 15 | protected static final EquivalentConverter CONVERTER = new EquivalentConverter() { 16 | @Override 17 | public Object getGeneric(InternalStructure specific) { 18 | return specific.handle; 19 | } 20 | 21 | @Override 22 | public InternalStructure getSpecific(Object generic) { 23 | return new InternalStructure(generic, new StructureModifier<>(generic.getClass()).withTarget(generic)); 24 | } 25 | 26 | @Override 27 | public Class getSpecificType() { 28 | return InternalStructure.class; 29 | } 30 | }; 31 | 32 | public static EquivalentConverter getConverter() { 33 | return CONVERTER; 34 | } 35 | 36 | public StructureModifier getStructures() { 37 | return structureModifier.withType(Object.class, CONVERTER); 38 | } 39 | 40 | public StructureModifier> getOptionalStructures() { 41 | return structureModifier.withType(Optional.class, Converters.optional(CONVERTER)); 42 | } 43 | 44 | @Override 45 | public String toString() { 46 | return "InternalStructure[handle=" + handle + " (" + handle.getClass().getSimpleName() + ")]"; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/events/ListenerOptions.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.events; 2 | 3 | import com.comphenix.protocol.injector.GamePhase; 4 | 5 | /** 6 | * Represents additional options a listener may require. 7 | * 8 | * @author Kristian 9 | */ 10 | public enum ListenerOptions { 11 | 12 | /** 13 | * Disable the automatic game phase detection that will normally force {@link GamePhase#LOGIN} when a packet ID is 14 | * known to be transmitted during login. 15 | */ 16 | DISABLE_GAMEPHASE_DETECTION, 17 | 18 | /** 19 | * Do not verify that the owning plugin has a vaid plugin.yml. 20 | */ 21 | SKIP_PLUGIN_VERIFIER, 22 | 23 | /** 24 | * Notify ProtocolLib that {@link PacketListener#onPacketSending(PacketEvent)} is thread safe. 25 | */ 26 | ASYNC, 27 | 28 | /** 29 | * Notify ProtocolLib that {@link PacketListener#onPacketReceiving(PacketEvent)} must be executed on the main server 30 | * thread. 31 | */ 32 | SYNC 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/events/ListenerPriority.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. 3 | * Copyright (C) 2012 Kristian S. Stangeland 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; either version 2 of 7 | * the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 15 | * 02111-1307 USA 16 | */ 17 | 18 | package com.comphenix.protocol.events; 19 | 20 | /** 21 | * Represents a packet event priority, similar to the Bukkit EventPriority. 22 | * 23 | * @author Kristian 24 | */ 25 | public enum ListenerPriority { 26 | /** 27 | * Event call is of very low importance and should be ran first, to allow 28 | * other plugins to further customise the outcome. 29 | */ 30 | LOWEST(0), 31 | /** 32 | * Event call is of low importance. 33 | */ 34 | LOW(1), 35 | /** 36 | * Event call is neither important or unimportant, and may be ran normally. 37 | */ 38 | NORMAL(2), 39 | /** 40 | * Event call is of high importance. 41 | */ 42 | HIGH(3), 43 | /** 44 | * Event call is critical and must have the final say in what happens to the 45 | * event. 46 | */ 47 | HIGHEST(4), 48 | /** 49 | * Event is listened to purely for monitoring the outcome of an event. 50 | *

51 | * No modifications to the event should be made under this priority. 52 | */ 53 | MONITOR(5); 54 | 55 | private final int slot; 56 | 57 | private ListenerPriority(int slot) { 58 | this.slot = slot; 59 | } 60 | 61 | /** 62 | * A low slot represents a low priority. 63 | * @return Integer representation of this priorty. 64 | */ 65 | public int getSlot() { 66 | return slot; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/events/MonitorAdapter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. 3 | * Copyright (C) 2012 Kristian S. Stangeland 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; either version 2 of 7 | * the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 15 | * 02111-1307 USA 16 | */ 17 | 18 | package com.comphenix.protocol.events; 19 | 20 | import java.util.Collection; 21 | import java.util.logging.Logger; 22 | 23 | import com.comphenix.protocol.PacketType; 24 | import com.comphenix.protocol.injector.packet.PacketRegistry; 25 | import org.bukkit.plugin.Plugin; 26 | 27 | /** 28 | * Represents a listener that is notified of every sent and received packet. 29 | * 30 | * @author Kristian 31 | */ 32 | public abstract class MonitorAdapter implements PacketListener { 33 | 34 | private final Plugin plugin; 35 | private final ListeningWhitelist sending; 36 | private final ListeningWhitelist receiving; 37 | 38 | public MonitorAdapter(Plugin plugin, ConnectionSide side) { 39 | this.plugin = plugin; 40 | 41 | // check the connection side and register the packets for the given side 42 | this.sending = side.isForServer() ? buildWhitelist(PacketRegistry.getServerPacketTypes()) : ListeningWhitelist.EMPTY_WHITELIST; 43 | this.receiving = side.isForClient() ? buildWhitelist(PacketRegistry.getClientPacketTypes()) : ListeningWhitelist.EMPTY_WHITELIST; 44 | } 45 | 46 | @Deprecated 47 | public MonitorAdapter(Plugin plugin, ConnectionSide side, Logger logger) { 48 | this(plugin, side); 49 | } 50 | 51 | private static ListeningWhitelist buildWhitelist(Collection packetTypes) { 52 | return ListeningWhitelist.newBuilder().monitor().gamePhaseBoth().types(packetTypes).build(); 53 | } 54 | 55 | @Override 56 | public ListeningWhitelist getSendingWhitelist() { 57 | return this.sending; 58 | } 59 | 60 | @Override 61 | public ListeningWhitelist getReceivingWhitelist() { 62 | return this.receiving; 63 | } 64 | 65 | @Override 66 | public Plugin getPlugin() { 67 | return this.plugin; 68 | } 69 | 70 | @Override 71 | public void onPacketSending(PacketEvent event) { 72 | } 73 | 74 | @Override 75 | public void onPacketReceiving(PacketEvent event) { 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/events/PacketListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. 3 | * Copyright (C) 2012 Kristian S. Stangeland 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; either version 2 of 7 | * the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 15 | * 02111-1307 USA 16 | */ 17 | 18 | package com.comphenix.protocol.events; 19 | 20 | import org.bukkit.plugin.Plugin; 21 | 22 | /** 23 | * Represents a listener that receives notifications when packets are sending or being received. 24 | *

25 | * Use {@link PacketAdapter} for a simple wrapper around this interface. 26 | * 27 | * @author Kristian 28 | */ 29 | public interface PacketListener { 30 | 31 | /** 32 | * Invoked right before a packet is transmitted from the server to the client. 33 | *

34 | * Note that the packet may be replaced, if needed. 35 | *

36 | * This method is executed on the main server thread by default. However, some spigot forks (like paper) schedule 37 | * specific packets off the main thread. If the {@link ListenerOptions#ASYNC} option is not specified any invocation 38 | * of this method will be on the main server thread. 39 | * 40 | * @param event - the packet that should be sent. 41 | */ 42 | void onPacketSending(PacketEvent event); 43 | 44 | /** 45 | * Invoked right before a received packet from a client is being processed. 46 | *

47 | * This method will be called asynchronously (or on the netty event loop) by default. If the 48 | * {@link ListenerOptions#SYNC} option is specified, the invocation of this method will be synced to the main server 49 | * thread which might cause issues due to delayed packets. 50 | * 51 | * @param event - the packet that has been received. 52 | */ 53 | void onPacketReceiving(PacketEvent event); 54 | 55 | /** 56 | * Retrieve which packets sent by the server this listener will observe. 57 | * 58 | * @return List of server packets to observe, along with the priority. 59 | */ 60 | ListeningWhitelist getSendingWhitelist(); 61 | 62 | /** 63 | * Retrieve which packets sent by the client this listener will observe. 64 | * 65 | * @return List of server packets to observe, along with the priority. 66 | */ 67 | ListeningWhitelist getReceivingWhitelist(); 68 | 69 | /** 70 | * Retrieve the plugin that created list packet listener. 71 | * 72 | * @return The plugin, or NULL if not available. 73 | */ 74 | Plugin getPlugin(); 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/events/PacketOutputAdapter.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.events; 2 | 3 | import org.bukkit.plugin.Plugin; 4 | 5 | /** 6 | * Represents an adapter version of the output handler interface. 7 | * @author Kristian 8 | */ 9 | public abstract class PacketOutputAdapter implements PacketOutputHandler { 10 | private final Plugin plugin; 11 | private final ListenerPriority priority; 12 | 13 | /** 14 | * Construct a new packet output adapter with the given values. 15 | * @param priority - the output handler priority. 16 | * @param plugin - the owner plugin. 17 | */ 18 | public PacketOutputAdapter(Plugin plugin, ListenerPriority priority) { 19 | this.priority = priority; 20 | this.plugin = plugin; 21 | } 22 | 23 | @Override 24 | public Plugin getPlugin() { 25 | return plugin; 26 | } 27 | 28 | @Override 29 | public ListenerPriority getPriority() { 30 | return priority; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/events/PacketOutputHandler.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.events; 2 | 3 | import org.bukkit.plugin.Plugin; 4 | 5 | /** 6 | * Represents a custom packet serializer onto the network stream. 7 | * 8 | * @author Kristian 9 | */ 10 | public interface PacketOutputHandler { 11 | /** 12 | * Retrieve the priority that decides the order each network handler is allowed to manipulate the output buffer. 13 | *

14 | * Higher priority is executed before lower. 15 | * @return The handler priority. 16 | */ 17 | public ListenerPriority getPriority(); 18 | 19 | /** 20 | * The plugin that owns this output handler. 21 | * @return The owner plugin. 22 | */ 23 | public Plugin getPlugin(); 24 | 25 | /** 26 | * Invoked when a given packet is to be written to the output stream. 27 | *

28 | * Note that the buffer is initially filled with the output from the default write method. 29 | *

30 | * In Minecraft 1.6.4, the header is always excluded, whereas it MUST be included in Minecraft 1.7.2. Call 31 | * NetworkMarker#requireOutputHeader() to determine this. 32 | * @param event - the packet that will be outputted. 33 | * @param buffer - the data that is currently scheduled to be outputted. 34 | * @return The modified byte array to write. NULL is not permitted. 35 | */ 36 | public byte[] handle(PacketEvent event, byte[] buffer); 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/events/PacketPostAdapter.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.events; 2 | 3 | import com.google.common.base.Preconditions; 4 | 5 | import org.bukkit.plugin.Plugin; 6 | 7 | /** 8 | * Represents an adapter version of a post listener. 9 | * @author Kristian 10 | */ 11 | public abstract class PacketPostAdapter implements PacketPostListener { 12 | private Plugin plugin; 13 | 14 | public PacketPostAdapter(Plugin plugin) { 15 | this.plugin = Preconditions.checkNotNull(plugin, "plugin cannot be NULL"); 16 | } 17 | 18 | @Override 19 | public Plugin getPlugin() { 20 | return plugin; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/events/PacketPostListener.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.events; 2 | 3 | import org.bukkit.plugin.Plugin; 4 | 5 | /** 6 | * Represents a packet listener that is invoked after a packet has been sent or received. 7 | * @author Kristian 8 | */ 9 | public interface PacketPostListener { 10 | /** 11 | * Retrieve the plugin this listener belongs to. 12 | * @return The assoicated plugin. 13 | */ 14 | public Plugin getPlugin(); 15 | 16 | /** 17 | * Invoked after a packet has been sent or received. 18 | *

19 | * Note that this is invoked asynchronously. 20 | * @param event - the packet event. 21 | */ 22 | public void onPostEvent(PacketEvent event); 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/injector/GamePhase.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. 3 | * Copyright (C) 2012 Kristian S. Stangeland 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; either version 2 of 7 | * the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 15 | * 02111-1307 USA 16 | */ 17 | 18 | package com.comphenix.protocol.injector; 19 | 20 | /** 21 | * The current player phase. This is used to limit the number of different injections. 22 | * 23 | * @author Kristian 24 | */ 25 | public enum GamePhase { 26 | /** 27 | * Only listen for packets sent or received before a player has logged in. 28 | */ 29 | LOGIN, 30 | 31 | /** 32 | * Only listen for packets sent or received after a player has logged in. 33 | */ 34 | PLAYING, 35 | 36 | /** 37 | * Listen for every sent and received packet. 38 | */ 39 | BOTH; 40 | 41 | /** 42 | * Determine if the current value represents the login phase. 43 | * 44 | * @return TRUE if it does, FALSE otherwise. 45 | */ 46 | public boolean hasLogin() { 47 | return this == LOGIN || this == BOTH; 48 | } 49 | 50 | /** 51 | * Determine if the current value represents the playing phase. 52 | * 53 | * @return TRUE if it does, FALSE otherwise. 54 | */ 55 | public boolean hasPlaying() { 56 | return this == PLAYING || this == BOTH; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/injector/InternalManager.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.injector; 2 | 3 | import com.comphenix.protocol.ProtocolManager; 4 | import org.bukkit.plugin.Plugin; 5 | import org.bukkit.plugin.PluginManager; 6 | 7 | /** 8 | * Yields access to the internal hook configuration. 9 | * 10 | * @author Kristian 11 | */ 12 | public interface InternalManager extends ProtocolManager { 13 | 14 | /** 15 | * Register this protocol manager on Bukkit. 16 | * 17 | * @param manager - Bukkit plugin manager that provides player join/leave events. 18 | * @param plugin - the parent plugin. 19 | */ 20 | void registerEvents(PluginManager manager, final Plugin plugin); 21 | 22 | /** 23 | * Called when ProtocolLib is closing. 24 | */ 25 | void close(); 26 | 27 | /** 28 | * Determine if debug mode is enabled. 29 | * 30 | * @return TRUE if it is, FALSE otherwise. 31 | */ 32 | boolean isDebug(); 33 | 34 | /** 35 | * Set whether or not debug mode is enabled. 36 | * 37 | * @param debug - TRUE if it is, FALSE otherwise. 38 | */ 39 | void setDebug(boolean debug); 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/injector/ListenerInvoker.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. 3 | * Copyright (C) 2012 Kristian S. Stangeland 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; either version 2 of 7 | * the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 15 | * 02111-1307 USA 16 | */ 17 | 18 | package com.comphenix.protocol.injector; 19 | 20 | import com.comphenix.protocol.PacketType; 21 | import com.comphenix.protocol.events.PacketEvent; 22 | 23 | /** 24 | * Represents an object that initiate the packet listeners. 25 | * 26 | * @author Kristian 27 | */ 28 | public interface ListenerInvoker { 29 | 30 | /** 31 | * Invokes the given packet event for every registered listener. 32 | * 33 | * @param event - the packet event to invoke. 34 | */ 35 | void invokePacketReceiving(PacketEvent event); 36 | 37 | /** 38 | * Invokes the given packet event for every registered listener. 39 | * 40 | * @param event - the packet event to invoke. 41 | */ 42 | void invokePacketSending(PacketEvent event); 43 | 44 | /** 45 | * Retrieve the associated type of a packet. 46 | * 47 | * @param packet - the packet. 48 | * @return The packet type. 49 | */ 50 | PacketType getPacketType(Object packet); 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/injector/NetworkProcessor.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.injector; 2 | 3 | import com.comphenix.protocol.ProtocolLibrary; 4 | import com.comphenix.protocol.ProtocolManager; 5 | import com.comphenix.protocol.error.ErrorReporter; 6 | import com.comphenix.protocol.events.NetworkMarker; 7 | import com.comphenix.protocol.events.PacketEvent; 8 | import com.comphenix.protocol.events.PacketPostListener; 9 | import com.comphenix.protocol.events.ScheduledPacket; 10 | import java.util.Deque; 11 | 12 | /** 13 | * Represents a processor for network markers. 14 | * 15 | * @author Kristian 16 | */ 17 | public class NetworkProcessor { 18 | 19 | private final ErrorReporter reporter; 20 | 21 | /** 22 | * Construct a new network processor. 23 | * 24 | * @param reporter - the reporter. 25 | */ 26 | public NetworkProcessor(ErrorReporter reporter) { 27 | this.reporter = reporter; 28 | } 29 | 30 | /** 31 | * Invoke the post listeners and packet transmission, if any. 32 | * 33 | * @param event - PacketEvent 34 | * @param marker - the network marker, or NULL. 35 | */ 36 | public void invokePostEvent(PacketEvent event, NetworkMarker marker) { 37 | if (marker == null) { 38 | return; 39 | } 40 | 41 | if (event != null && NetworkMarker.hasPostListeners(marker)) { 42 | // Invoke every sent listener 43 | for (PacketPostListener listener : marker.getPostListeners()) { 44 | try { 45 | listener.onPostEvent(event); 46 | } catch (OutOfMemoryError | ThreadDeath e) { 47 | throw e; 48 | } catch (Throwable e) { 49 | this.reporter.reportMinimal(listener.getPlugin(), "SentListener.run()", e); 50 | } 51 | } 52 | } 53 | 54 | this.sendScheduledPackets(marker); 55 | } 56 | 57 | /** 58 | * Send any scheduled packets. 59 | * 60 | * @param marker - the network marker. 61 | */ 62 | private void sendScheduledPackets(NetworkMarker marker) { 63 | // Next, invoke post packet transmission 64 | Deque scheduled = NetworkMarker.readScheduledPackets(marker); 65 | ProtocolManager manager = ProtocolLibrary.getProtocolManager(); 66 | 67 | if (scheduled != null) { 68 | ScheduledPacket packet; 69 | while ((packet = scheduled.poll()) != null) { 70 | packet.schedule(manager); 71 | } 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/injector/PrioritizedListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. 3 | * Copyright (C) 2012 Kristian S. Stangeland 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; either version 2 of 7 | * the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 15 | * 02111-1307 USA 16 | */ 17 | 18 | package com.comphenix.protocol.injector; 19 | 20 | import com.comphenix.protocol.events.ListenerPriority; 21 | import com.google.common.base.Objects; 22 | import com.google.common.primitives.Ints; 23 | 24 | /** 25 | * Represents a listener with a priority. 26 | * 27 | * @author Kristian 28 | */ 29 | public class PrioritizedListener implements Comparable> { 30 | 31 | private TListener listener; 32 | private ListenerPriority priority; 33 | 34 | public PrioritizedListener(TListener listener, ListenerPriority priority) { 35 | this.listener = listener; 36 | this.priority = priority; 37 | } 38 | 39 | @Override 40 | public int compareTo(PrioritizedListener other) { 41 | // This ensures that lower priority listeners are executed first 42 | return Ints.compare( 43 | this.getPriority().getSlot(), 44 | other.getPriority().getSlot()); 45 | } 46 | 47 | // Note that this equals() method is NOT consistent with compareTo(). 48 | // But, it's a private class so who cares. 49 | @SuppressWarnings("unchecked") 50 | @Override 51 | public boolean equals(Object obj) { 52 | // We only care about the listener - priority itself should not make a difference 53 | if (obj instanceof PrioritizedListener) { 54 | final PrioritizedListener other = (PrioritizedListener) obj; 55 | return Objects.equal(listener, other.listener); 56 | } else { 57 | return false; 58 | } 59 | } 60 | 61 | @Override 62 | public int hashCode() { 63 | return Objects.hashCode(listener); 64 | } 65 | 66 | /** 67 | * Retrieve the underlying listener. 68 | * @return Underlying listener. 69 | */ 70 | public TListener getListener() { 71 | return listener; 72 | } 73 | 74 | /** 75 | * Retrieve the priority of this listener. 76 | * @return Listener priority. 77 | */ 78 | public ListenerPriority getPriority() { 79 | return priority; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/injector/netty/ChannelListener.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.injector.netty; 2 | 3 | import com.comphenix.protocol.PacketType; 4 | import com.comphenix.protocol.error.ErrorReporter; 5 | import com.comphenix.protocol.events.NetworkMarker; 6 | import com.comphenix.protocol.events.PacketEvent; 7 | 8 | /** 9 | * Represents a listener for received or sent packets. 10 | * 11 | * @author Kristian 12 | */ 13 | public interface ChannelListener { 14 | 15 | /** 16 | * Invoked when a packet is being sent to the client. 17 | *

18 | * This is invoked on the main thread. 19 | * 20 | * @param injector - the channel injector. 21 | * @param packet - the packet. 22 | * @param marker - the network marker. 23 | * @return The packet even that was passed to the listeners, with a possible packet change, or NULL. 24 | */ 25 | PacketEvent onPacketSending(Injector injector, Object packet, NetworkMarker marker); 26 | 27 | /** 28 | * Invoked when a packet is being received from a client. 29 | *

30 | * This is invoked on an asynchronous worker thread. 31 | * 32 | * @param injector - the channel injector. 33 | * @param packet - the packet. 34 | * @param marker - the associated network marker, if any. 35 | * @return The packet even that was passed to the listeners, with a possible packet change, or NULL. 36 | */ 37 | PacketEvent onPacketReceiving(Injector injector, Object packet, NetworkMarker marker); 38 | 39 | /** 40 | * Determine if there is a packet listener for the given packet. 41 | * 42 | * @param packetClass - the packet class to check. 43 | * @return TRUE if there is such a listener, FALSE otherwise. 44 | */ 45 | boolean hasListener(Class packetClass); 46 | 47 | /** 48 | * Determine if there is a server packet listener that must be executed on the main thread. 49 | * 50 | * @param packetClass - the packet class to check. 51 | * @return TRUE if there is, FALSE otherwise. 52 | */ 53 | boolean hasMainThreadListener(Class packetClass); 54 | 55 | boolean hasMainThreadListener(PacketType type); 56 | 57 | /** 58 | * Retrieve the current error reporter. 59 | * 60 | * @return The error reporter. 61 | */ 62 | ErrorReporter getReporter(); 63 | 64 | /** 65 | * Determine if debug mode is enabled. 66 | * 67 | * @return TRUE if it is, FALSE otherwise. 68 | */ 69 | boolean isDebug(); 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/injector/netty/Injector.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.injector.netty; 2 | 3 | import com.comphenix.protocol.PacketType.Protocol; 4 | import com.comphenix.protocol.events.NetworkMarker; 5 | import org.bukkit.entity.Player; 6 | 7 | /** 8 | * Represents an injected client connection. 9 | * 10 | * @author Kristian 11 | */ 12 | public interface Injector { 13 | 14 | /** 15 | * Retrieve the current protocol version of the player. 16 | * 17 | * @return Protocol version. 18 | */ 19 | int getProtocolVersion(); 20 | 21 | /** 22 | * Inject the current channel. 23 | *

24 | * Note that only active channels can be injected. 25 | * 26 | * @return TRUE if we injected the channel, false if we could not inject or it was already injected. 27 | */ 28 | boolean inject(); 29 | 30 | void uninject(); 31 | 32 | /** 33 | * Close the current injector. 34 | */ 35 | void close(); 36 | 37 | /** 38 | * Send a packet to a player's client. 39 | * 40 | * @param packet - the packet to send. 41 | * @param marker - the network marker. 42 | * @param filtered - whether or not the packet is filtered. 43 | */ 44 | void sendServerPacket(Object packet, NetworkMarker marker, boolean filtered); 45 | 46 | void receiveClientPacket(Object packet); 47 | 48 | /** 49 | * Retrieve the current protocol state. 50 | * 51 | * @return The current protocol. 52 | */ 53 | Protocol getCurrentProtocol(); 54 | 55 | /** 56 | * Retrieve the network marker associated with a given packet. 57 | * 58 | * @param packet - the packet. 59 | * @return The network marker. 60 | */ 61 | NetworkMarker getMarker(Object packet); 62 | 63 | /** 64 | * Associate a given network marker with a specific packet. 65 | * 66 | * @param packet - the NMS packet. 67 | * @param marker - the associated marker. 68 | */ 69 | void saveMarker(Object packet, NetworkMarker marker); 70 | 71 | /** 72 | * Retrieve the current player or temporary player associated with the injector. 73 | * 74 | * @return The current player. 75 | */ 76 | Player getPlayer(); 77 | 78 | /** 79 | * Set the current player instance. 80 | * 81 | * @param player - the current player. 82 | */ 83 | void setPlayer(Player player); 84 | 85 | void disconnect(String message); 86 | 87 | /** 88 | * Determine if the channel has already been injected. 89 | * 90 | * @return TRUE if it has, FALSE otherwise. 91 | */ 92 | boolean isInjected(); 93 | 94 | /** 95 | * Determine if this channel has been closed and cleaned up. 96 | * 97 | * @return TRUE if it has, FALSE otherwise. 98 | */ 99 | boolean isClosed(); 100 | } 101 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/injector/netty/channel/EmptyInjector.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.injector.netty.channel; 2 | 3 | import com.comphenix.protocol.PacketType.Protocol; 4 | import com.comphenix.protocol.events.NetworkMarker; 5 | import com.comphenix.protocol.injector.netty.Injector; 6 | import org.bukkit.entity.Player; 7 | 8 | final class EmptyInjector implements Injector { 9 | 10 | public static final Injector WITHOUT_PLAYER = new EmptyInjector(null); 11 | 12 | private Player player; 13 | 14 | public EmptyInjector(Player player) { 15 | this.player = player; 16 | } 17 | 18 | @Override 19 | public int getProtocolVersion() { 20 | return Integer.MIN_VALUE; 21 | } 22 | 23 | @Override 24 | public boolean inject() { 25 | return false; 26 | } 27 | 28 | @Override 29 | public void uninject() { 30 | } 31 | 32 | @Override 33 | public void close() { 34 | } 35 | 36 | @Override 37 | public void sendServerPacket(Object packet, NetworkMarker marker, boolean filtered) { 38 | } 39 | 40 | @Override 41 | public void receiveClientPacket(Object packet) { 42 | } 43 | 44 | @Override 45 | public Protocol getCurrentProtocol() { 46 | return Protocol.HANDSHAKING; 47 | } 48 | 49 | @Override 50 | public NetworkMarker getMarker(Object packet) { 51 | return null; 52 | } 53 | 54 | @Override 55 | public void saveMarker(Object packet, NetworkMarker marker) { 56 | } 57 | 58 | @Override 59 | public Player getPlayer() { 60 | return this.player; 61 | } 62 | 63 | @Override 64 | public void setPlayer(Player player) { 65 | this.player = player; 66 | } 67 | 68 | @Override 69 | public void disconnect(String message) { 70 | } 71 | 72 | @Override 73 | public boolean isInjected() { 74 | return false; 75 | } 76 | 77 | @Override 78 | public boolean isClosed() { 79 | return true; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/injector/netty/channel/InboundPacketInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.injector.netty.channel; 2 | 3 | import com.comphenix.protocol.injector.netty.ChannelListener; 4 | import com.comphenix.protocol.utility.MinecraftReflection; 5 | import io.netty.channel.ChannelHandlerContext; 6 | import io.netty.channel.ChannelInboundHandlerAdapter; 7 | 8 | final class InboundPacketInterceptor extends ChannelInboundHandlerAdapter { 9 | 10 | private final NettyChannelInjector injector; 11 | private final ChannelListener channelListener; 12 | 13 | public InboundPacketInterceptor(NettyChannelInjector injector, ChannelListener listener) { 14 | this.injector = injector; 15 | this.channelListener = listener; 16 | } 17 | 18 | @Override 19 | public void channelRead(ChannelHandlerContext ctx, Object msg) { 20 | Class messageClass = msg.getClass(); 21 | if (this.shouldInterceptMessage(messageClass)) { 22 | // process the login if the packet is one before posting the packet to any handler to provide "real" data 23 | // the method invocation will do nothing if the packet is not a login packet 24 | this.injector.tryProcessLogin(msg); 25 | 26 | // check if there are any listeners bound for the packet - if not just post the packet down the pipeline 27 | if (!this.channelListener.hasListener(messageClass)) { 28 | ctx.fireChannelRead(msg); 29 | return; 30 | } 31 | 32 | // call all inbound listeners 33 | this.injector.processInboundPacket(ctx, msg, messageClass); 34 | } else { 35 | // just pass the message down the pipeline 36 | ctx.fireChannelRead(msg); 37 | } 38 | } 39 | 40 | private boolean shouldInterceptMessage(Class messageClass) { 41 | // only intercept minecraft packets and no garbage from other stuff in the channel 42 | return MinecraftReflection.getPacketClass().isAssignableFrom(messageClass); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/injector/netty/channel/NettyChannelMinimalInjector.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.injector.netty.channel; 2 | 3 | import com.comphenix.protocol.events.NetworkMarker; 4 | import com.comphenix.protocol.injector.temporary.MinimalInjector; 5 | import java.net.SocketAddress; 6 | import org.bukkit.entity.Player; 7 | 8 | final class NettyChannelMinimalInjector implements MinimalInjector { 9 | 10 | private final NettyChannelInjector injector; 11 | 12 | public NettyChannelMinimalInjector(NettyChannelInjector injector) { 13 | this.injector = injector; 14 | } 15 | 16 | @Override 17 | public SocketAddress getAddress() { 18 | return this.injector.getWrappedChannel().remoteAddress(); 19 | } 20 | 21 | @Override 22 | public void disconnect(String message) { 23 | this.injector.disconnect(message); 24 | } 25 | 26 | @Override 27 | public void sendServerPacket(Object packet, NetworkMarker marker, boolean filtered) { 28 | this.injector.sendServerPacket(packet, marker, filtered); 29 | } 30 | 31 | @Override 32 | public Player getPlayer() { 33 | return this.injector.getPlayer(); 34 | } 35 | 36 | @Override 37 | public boolean isConnected() { 38 | return this.injector.getWrappedChannel().isActive(); 39 | } 40 | 41 | public NettyChannelInjector getInjector() { 42 | return this.injector; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/injector/netty/channel/WirePacketEncoder.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.injector.netty.channel; 2 | 3 | import com.comphenix.protocol.injector.netty.WirePacket; 4 | import io.netty.buffer.ByteBuf; 5 | import io.netty.channel.ChannelHandlerContext; 6 | import io.netty.handler.codec.MessageToByteEncoder; 7 | 8 | final class WirePacketEncoder extends MessageToByteEncoder { 9 | 10 | @Override 11 | protected void encode(ChannelHandlerContext ctx, WirePacket msg, ByteBuf out) throws Exception { 12 | msg.writeFully(out); 13 | } 14 | 15 | @Override 16 | public boolean acceptOutboundMessage(Object msg) { 17 | return msg instanceof WirePacket; 18 | } 19 | 20 | @Override 21 | public boolean isSharable() { 22 | // we do it this way to prevent the lookup overheat 23 | return true; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/injector/netty/manager/InjectionChannelInboundHandler.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.injector.netty.manager; 2 | 3 | import com.comphenix.protocol.error.Report; 4 | import com.comphenix.protocol.error.ReportType; 5 | import com.comphenix.protocol.injector.netty.channel.InjectionFactory; 6 | import com.comphenix.protocol.injector.temporary.TemporaryPlayerFactory; 7 | import io.netty.channel.ChannelHandlerContext; 8 | import io.netty.channel.ChannelInboundHandlerAdapter; 9 | 10 | final class InjectionChannelInboundHandler extends ChannelInboundHandlerAdapter { 11 | 12 | private static final ReportType CANNOT_INJECT_CHANNEL = new ReportType("Unable to inject incoming channel %s."); 13 | 14 | private final InjectionFactory factory; 15 | private final NetworkManagerInjector listener; 16 | private final TemporaryPlayerFactory playerFactory; 17 | 18 | public InjectionChannelInboundHandler( 19 | InjectionFactory factory, 20 | NetworkManagerInjector listener, 21 | TemporaryPlayerFactory playerFactory 22 | ) { 23 | this.factory = factory; 24 | this.listener = listener; 25 | this.playerFactory = playerFactory; 26 | } 27 | 28 | @Override 29 | public void channelActive(ChannelHandlerContext ctx) { 30 | // call the minecraft channelActive method first 31 | ctx.fireChannelActive(); 32 | 33 | // the channel is now active, at this point minecraft has eventually prepared everything in the connection 34 | // of the player so that we can come in and hook as we are after the minecraft handler. 35 | // We're first checking if the factory is still open, just might be a delay between accepting the connection 36 | // (which adds this handler to the pipeline) and the actual channelActive call. If the injector is closed at 37 | // that point we might accidentally trigger class loads which result in exceptions. 38 | if (!this.factory.isClosed()) { 39 | try { 40 | this.factory.fromChannel(ctx.channel(), this.listener, this.playerFactory).inject(); 41 | } catch (Exception exception) { 42 | this.listener.getReporter().reportDetailed(this, Report.newBuilder(CANNOT_INJECT_CHANNEL) 43 | .messageParam(ctx.channel()) 44 | .error(exception) 45 | .build()); 46 | } 47 | } 48 | 49 | // remove this handler from the pipeline now to prevent multiple injections 50 | ctx.channel().pipeline().remove(this); 51 | } 52 | 53 | @Override 54 | public boolean isSharable() { 55 | // we do it this way to prevent the lookup overheat 56 | return true; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/injector/netty/manager/InjectionChannelInitializer.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.injector.netty.manager; 2 | 3 | import io.netty.channel.Channel; 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.channel.ChannelInboundHandler; 6 | import io.netty.channel.ChannelInboundHandlerAdapter; 7 | 8 | final class InjectionChannelInitializer extends ChannelInboundHandlerAdapter { 9 | 10 | private final String inboundHandlerName; 11 | private final ChannelInboundHandler handler; 12 | 13 | public InjectionChannelInitializer(String inboundHandlerName, ChannelInboundHandler handler) { 14 | this.inboundHandlerName = inboundHandlerName; 15 | this.handler = handler; 16 | } 17 | 18 | @Override 19 | public void channelRead(ChannelHandlerContext ctx, Object msg) { 20 | if (msg instanceof Channel) { 21 | Channel channel = (Channel) msg; 22 | channel.pipeline().addLast(this.inboundHandlerName, this.handler); 23 | } 24 | 25 | // forward to all other handlers in the pipeline 26 | ctx.fireChannelRead(msg); 27 | } 28 | 29 | @Override 30 | public boolean isSharable() { 31 | // we do it this way to prevent the lookup overheat 32 | return true; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/injector/netty/manager/NetworkManagerPacketInjector.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.injector.netty.manager; 2 | 3 | import java.util.Set; 4 | 5 | import com.comphenix.protocol.PacketType; 6 | import com.comphenix.protocol.concurrency.PacketTypeSet; 7 | import com.comphenix.protocol.events.ListenerOptions; 8 | import com.comphenix.protocol.events.PacketContainer; 9 | import com.comphenix.protocol.events.PacketEvent; 10 | import com.comphenix.protocol.injector.ListenerInvoker; 11 | import com.comphenix.protocol.injector.netty.ChannelListener; 12 | import com.comphenix.protocol.injector.packet.AbstractPacketInjector; 13 | import org.bukkit.entity.Player; 14 | 15 | final class NetworkManagerPacketInjector extends AbstractPacketInjector { 16 | 17 | private final ListenerInvoker invoker; 18 | private final ChannelListener channelListener; 19 | private final PacketTypeSet mainThreadListeners; 20 | 21 | public NetworkManagerPacketInjector( 22 | PacketTypeSet inboundFilters, 23 | ListenerInvoker invoker, 24 | ChannelListener listener, 25 | PacketTypeSet mainThreadListeners 26 | ) { 27 | super(inboundFilters); 28 | 29 | this.invoker = invoker; 30 | this.channelListener = listener; 31 | this.mainThreadListeners = mainThreadListeners; 32 | } 33 | 34 | @Override 35 | public boolean addPacketHandler(PacketType type, Set options) { 36 | if (!type.isAsyncForced() && options != null && options.contains(ListenerOptions.SYNC)) { 37 | this.mainThreadListeners.addType(type); 38 | } 39 | 40 | return super.addPacketHandler(type, options); 41 | } 42 | 43 | @Override 44 | public boolean removePacketHandler(PacketType type) { 45 | this.mainThreadListeners.removeType(type); 46 | return super.removePacketHandler(type); 47 | } 48 | 49 | @Override 50 | public PacketEvent packetReceived(PacketContainer packet, Player client) { 51 | PacketEvent event = PacketEvent.fromClient(this.channelListener, packet, null, client); 52 | this.invoker.invokePacketReceiving(event); 53 | 54 | return event; 55 | } 56 | 57 | @Override 58 | public boolean hasMainThreadListener(PacketType type) { 59 | return this.mainThreadListeners.contains(type); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/injector/packet/AbstractPacketInjector.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.injector.packet; 2 | 3 | import com.comphenix.protocol.PacketType; 4 | import com.comphenix.protocol.concurrency.PacketTypeSet; 5 | import com.comphenix.protocol.events.ListenerOptions; 6 | import java.util.Set; 7 | 8 | public abstract class AbstractPacketInjector implements PacketInjector { 9 | 10 | private final PacketTypeSet inboundFilters; 11 | 12 | public AbstractPacketInjector(PacketTypeSet inboundFilters) { 13 | this.inboundFilters = inboundFilters; 14 | } 15 | 16 | @Override 17 | public boolean addPacketHandler(PacketType type, Set options) { 18 | this.inboundFilters.addType(type); 19 | return true; 20 | } 21 | 22 | @Override 23 | public boolean removePacketHandler(PacketType type) { 24 | this.inboundFilters.removeType(type); 25 | return true; 26 | } 27 | 28 | @Override 29 | public boolean hasPacketHandler(PacketType type) { 30 | return this.inboundFilters.contains(type); 31 | } 32 | 33 | @Override 34 | public Set getPacketHandlers() { 35 | return this.inboundFilters.values(); 36 | } 37 | 38 | @Override 39 | public void cleanupAll() { 40 | this.inboundFilters.clear(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/injector/packet/MapContainer.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.injector.packet; 2 | 3 | import com.comphenix.protocol.reflect.accessors.Accessors; 4 | import com.comphenix.protocol.reflect.accessors.FieldAccessor; 5 | 6 | import static com.google.common.base.Preconditions.checkNotNull; 7 | 8 | /** 9 | * Represents a class that can detect if a map has changed. 10 | * @author Kristian 11 | */ 12 | public class MapContainer { 13 | // For detecting changes 14 | private final FieldAccessor modCountField; 15 | private int lastModCount; 16 | 17 | // The object along with whether or not this is the initial run 18 | private final Object source; 19 | private boolean changed; 20 | 21 | public MapContainer(Object source) { 22 | this.source = source; 23 | this.changed = false; 24 | 25 | this.modCountField = Accessors.getFieldAccessorOrNull(source.getClass(), "modCount", int.class); 26 | checkNotNull(this.modCountField, "unable to retrieve modCount field for " + source.getClass()); 27 | 28 | this.lastModCount = getModificationCount(); 29 | } 30 | 31 | /** 32 | * Determine if the map has changed. 33 | * @return TRUE if it has, FALSE otherwise. 34 | */ 35 | public boolean hasChanged() { 36 | // Check if unchanged 37 | checkChanged(); 38 | return changed; 39 | } 40 | 41 | /** 42 | * Mark the map as changed or unchanged. 43 | * @param changed - TRUE if the map has changed, FALSE otherwise. 44 | */ 45 | public void setChanged(boolean changed) { 46 | this.changed = changed; 47 | } 48 | 49 | /** 50 | * Check for modifications to the current map. 51 | */ 52 | protected void checkChanged() { 53 | if (!changed) { 54 | if (getModificationCount() != lastModCount) { 55 | lastModCount = getModificationCount(); 56 | changed = true; 57 | } 58 | } 59 | } 60 | 61 | /** 62 | * Retrieve the current modification count. 63 | * @return The current count 64 | */ 65 | private int getModificationCount() { 66 | return (int) modCountField.get(source); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/injector/packet/PacketInjector.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.injector.packet; 2 | 3 | import java.util.Set; 4 | 5 | import com.comphenix.protocol.PacketType; 6 | import com.comphenix.protocol.events.ListenerOptions; 7 | import com.comphenix.protocol.events.PacketContainer; 8 | import com.comphenix.protocol.events.PacketEvent; 9 | import org.bukkit.entity.Player; 10 | 11 | /** 12 | * Represents an incoming packet injector. 13 | * 14 | * @author Kristian 15 | */ 16 | public interface PacketInjector { 17 | 18 | /** 19 | * Start intercepting packets with the given packet type. 20 | * 21 | * @param type - the type of the packets to start intercepting. 22 | * @param options - any listener options. 23 | * @return TRUE if we didn't already intercept these packets, FALSE otherwise. 24 | */ 25 | boolean addPacketHandler(PacketType type, Set options); 26 | 27 | /** 28 | * Stop intercepting packets with the given packet type. 29 | * 30 | * @param type - the type of the packets to stop intercepting. 31 | * @return TRUE if we successfuly stopped intercepting a given packet ID, FALSE otherwise. 32 | */ 33 | boolean removePacketHandler(PacketType type); 34 | 35 | /** 36 | * Determine if packets with the given packet type is being intercepted. 37 | * 38 | * @param type - the packet type to lookup. 39 | * @return TRUE if we do, FALSE otherwise. 40 | */ 41 | boolean hasPacketHandler(PacketType type); 42 | 43 | /** 44 | * Retrieve every intercepted packet type. 45 | * 46 | * @return Every intercepted packet type. 47 | */ 48 | Set getPacketHandlers(); 49 | 50 | /** 51 | * Let the packet listeners process the given packet. 52 | * 53 | * @param packet - a packet to process. 54 | * @param client - the client that sent the packet. 55 | * @return The resulting packet event. 56 | */ 57 | PacketEvent packetReceived(PacketContainer packet, Player client); 58 | 59 | /** 60 | * Determine if we have packet listeners with the given type that must be executed on the main thread. 61 | * 62 | * @param type - the packet type. 63 | * @return TRUE if we do, FALSE otherwise. 64 | */ 65 | boolean hasMainThreadListener(PacketType type); 66 | 67 | /** 68 | * Perform any necessary cleanup before unloading ProtocolLib. 69 | */ 70 | void cleanupAll(); 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/injector/player/AbstractPlayerInjectionHandler.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.injector.player; 2 | 3 | import com.comphenix.protocol.PacketType; 4 | import com.comphenix.protocol.concurrency.PacketTypeSet; 5 | import com.comphenix.protocol.events.ListenerOptions; 6 | import com.comphenix.protocol.events.PacketListener; 7 | import java.util.Set; 8 | 9 | public abstract class AbstractPlayerInjectionHandler implements PlayerInjectionHandler { 10 | 11 | private final PacketTypeSet sendingFilters; 12 | 13 | public AbstractPlayerInjectionHandler(PacketTypeSet sendingFilters) { 14 | this.sendingFilters = sendingFilters; 15 | } 16 | 17 | @Override 18 | public void addPacketHandler(PacketType type, Set options) { 19 | this.sendingFilters.addType(type); 20 | } 21 | 22 | @Override 23 | public void removePacketHandler(PacketType type) { 24 | this.sendingFilters.removeType(type); 25 | } 26 | 27 | @Override 28 | public Set getSendingFilters() { 29 | return this.sendingFilters.values(); 30 | } 31 | 32 | @Override 33 | public void close() { 34 | this.sendingFilters.clear(); 35 | } 36 | 37 | @Override 38 | public boolean canReceivePackets() { 39 | return true; 40 | } 41 | 42 | @Override 43 | public void checkListener(PacketListener listener) { 44 | // They're all fine! 45 | } 46 | 47 | @Override 48 | public void checkListener(Set listeners) { 49 | // Yes, really 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/injector/temporary/MinimalInjector.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.injector.temporary; 2 | 3 | import com.comphenix.protocol.events.NetworkMarker; 4 | import java.net.SocketAddress; 5 | import org.bukkit.entity.Player; 6 | 7 | /** 8 | * Represents an injector that only gives access to a player's socket. 9 | * 10 | * @author Kristian 11 | */ 12 | public interface MinimalInjector { 13 | 14 | /** 15 | * Retrieve the associated address of this player. 16 | * 17 | * @return The associated address. 18 | */ 19 | SocketAddress getAddress(); 20 | 21 | /** 22 | * Attempt to disconnect the current client. 23 | * 24 | * @param message - the message to display. 25 | */ 26 | void disconnect(String message); 27 | 28 | /** 29 | * Send a packet to the client. 30 | * 31 | * @param packet - server packet to send. 32 | * @param marker - the network marker. 33 | * @param filtered - whether or not the packet will be filtered by our listeners. 34 | */ 35 | void sendServerPacket(Object packet, NetworkMarker marker, boolean filtered); 36 | 37 | /** 38 | * Retrieve the hooked player. 39 | * 40 | * @return The hooked player. 41 | */ 42 | Player getPlayer(); 43 | 44 | /** 45 | * Determines if the player is currently connected. 46 | * 47 | * @return true if the player is connected. 48 | */ 49 | boolean isConnected(); 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/injector/temporary/TemporaryPlayer.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.injector.temporary; 2 | 3 | /** 4 | * A temporary player created by ProtocolLib when a true player instance does not exist. 5 | *

6 | * Also able to store a socket injector 7 | *

8 | */ 9 | public class TemporaryPlayer { 10 | 11 | private volatile MinimalInjector injector; 12 | 13 | MinimalInjector getInjector() { 14 | return this.injector; 15 | } 16 | 17 | void setInjector(MinimalInjector injector) { 18 | if (injector == null) { 19 | throw new IllegalArgumentException("Injector cannot be NULL."); 20 | } 21 | 22 | this.injector = injector; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Contains classes for retrieving the main ProtocolMananger object. 3 | *

4 | * This allows plugins to reliably and easily read and modify the packet stream of any CraftBukkit-derivative 5 | * (or specifically compatible) Minecraft-server. 6 | *

7 | * This manager can be retrieved throught a static method in ProtocolLibrary: 8 | *

 9 |  * {@code
10 |  * ProtocolManager manager = ProtocolLibrary.getProtocolManager();
11 |  * }
12 |  * 
13 | */ 14 | package com.comphenix.protocol; 15 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/reflect/EquivalentConverter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. 3 | * Copyright (C) 2012 Kristian S. Stangeland 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; either version 2 of 7 | * the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 15 | * 02111-1307 USA 16 | */ 17 | 18 | package com.comphenix.protocol.reflect; 19 | 20 | /** 21 | * Interface that converts generic objects into types and back. 22 | * 23 | * @param The specific type. 24 | * @author Kristian 25 | */ 26 | public interface EquivalentConverter { 27 | 28 | /** 29 | * Retrieve a copy of the generic type from a specific type. 30 | *

31 | * This is usually a native net.minecraft.server type in Minecraft. 32 | * 33 | * @param specific - the specific type we need to copy. 34 | * @return A copy of the specific type. 35 | */ 36 | Object getGeneric(T specific); 37 | 38 | /** 39 | * Retrieve a copy of the specific type using an instance of the generic type. 40 | *

41 | * This is usually a wrapper type in the Bukkit API or ProtocolLib API. 42 | * 43 | * @param generic - the generic type. 44 | * @return The new specific type. 45 | */ 46 | T getSpecific(Object generic); 47 | 48 | /** 49 | * Due to type erasure, we need to explicitly keep a reference to the specific type. 50 | * 51 | * @return The specific type. 52 | */ 53 | Class getSpecificType(); 54 | } -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/reflect/FieldAccessException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. 3 | * Copyright (C) 2012 Kristian S. Stangeland 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; either version 2 of 7 | * the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 15 | * 02111-1307 USA 16 | */ 17 | 18 | package com.comphenix.protocol.reflect; 19 | 20 | /** 21 | * Invoked when a field is inaccessible due to security limitations, or when it simply doesn't exist. 22 | * 23 | * @author Kristian 24 | */ 25 | public class FieldAccessException extends RuntimeException { 26 | 27 | /** 28 | * Generated by Eclipse. 29 | */ 30 | private static final long serialVersionUID = 1911011681494034617L; 31 | 32 | public FieldAccessException() { 33 | super(); 34 | } 35 | 36 | public FieldAccessException(String message, Throwable cause) { 37 | super(message, cause); 38 | } 39 | 40 | public FieldAccessException(String message) { 41 | super(message); 42 | } 43 | 44 | public FieldAccessException(Throwable cause) { 45 | super(cause); 46 | } 47 | 48 | public static FieldAccessException fromFormat(String message, Object... params) { 49 | return new FieldAccessException(String.format(message, params)); 50 | } 51 | 52 | @Override 53 | public String toString() { 54 | String message = getMessage(); 55 | return "FieldAccessException" + (message != null ? ": " + message : ""); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/reflect/accessors/ConstructorAccessor.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.reflect.accessors; 2 | 3 | import java.lang.reflect.Constructor; 4 | 5 | public interface ConstructorAccessor { 6 | 7 | /** 8 | * Invoke the underlying constructor. 9 | * 10 | * @param args - the arguments to pass to the method. 11 | * @return The return value, or NULL for void methods. 12 | */ 13 | Object invoke(Object... args); 14 | 15 | /** 16 | * Retrieve the underlying constructor. 17 | * 18 | * @return The method. 19 | */ 20 | Constructor getConstructor(); 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/reflect/accessors/DefaultConstrutorAccessor.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.reflect.accessors; 2 | 3 | import java.lang.invoke.MethodHandle; 4 | import java.lang.reflect.Constructor; 5 | 6 | final class DefaultConstrutorAccessor implements ConstructorAccessor { 7 | 8 | private final Constructor constructor; 9 | private final MethodHandle constructorAccessor; 10 | 11 | public DefaultConstrutorAccessor(Constructor constructor, MethodHandle constructorAccessor) { 12 | this.constructor = constructor; 13 | this.constructorAccessor = constructorAccessor; 14 | } 15 | 16 | @Override 17 | public Object invoke(Object... args) { 18 | try { 19 | return this.constructorAccessor.invokeExact(args); 20 | } catch (Throwable throwable) { 21 | throw new IllegalStateException("Unable to construct new instance using " + this.constructor, throwable); 22 | } 23 | } 24 | 25 | @Override 26 | public Constructor getConstructor() { 27 | return this.constructor; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/reflect/accessors/DefaultFieldAccessor.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.reflect.accessors; 2 | 3 | import java.lang.invoke.MethodHandle; 4 | import java.lang.reflect.Field; 5 | import java.lang.reflect.Modifier; 6 | 7 | import com.google.common.base.Preconditions; 8 | 9 | final class DefaultFieldAccessor implements FieldAccessor { 10 | 11 | private final Field field; 12 | private final boolean staticField; 13 | 14 | private final MethodHandle setter; 15 | private final MethodHandle getter; 16 | 17 | public DefaultFieldAccessor(Field field, MethodHandle setter, MethodHandle getter, boolean staticField) { 18 | this.field = Preconditions.checkNotNull(field, "field"); 19 | this.setter = Preconditions.checkNotNull(setter, "setter"); 20 | this.getter = Preconditions.checkNotNull(getter, "getter"); 21 | this.staticField = staticField; 22 | } 23 | 24 | @Override 25 | public Object get(Object instance) { 26 | try { 27 | // we need this check to as the handle will treat "null" as an instance too 28 | return this.staticField ? this.getter.invokeExact() : this.getter.invokeExact(instance); 29 | } catch (Throwable throwable) { 30 | throw new IllegalStateException("Unable to read field value of " + this.field, throwable); 31 | } 32 | } 33 | 34 | @Override 35 | public void set(Object instance, Object value) { 36 | try { 37 | // we need this check to as the handle will treat "null" as an instance too 38 | if (this.staticField) { 39 | this.setter.invokeExact(value); 40 | } else { 41 | this.setter.invokeExact(instance, value); 42 | } 43 | } catch (Throwable throwable) { 44 | throw new IllegalStateException("Unable to set value of field " + this.field, throwable); 45 | } 46 | } 47 | 48 | @Override 49 | public Field getField() { 50 | return this.field; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/reflect/accessors/DefaultMethodAccessor.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.reflect.accessors; 2 | 3 | import java.lang.invoke.MethodHandle; 4 | import java.lang.reflect.Method; 5 | import java.lang.reflect.Modifier; 6 | 7 | final class DefaultMethodAccessor implements MethodAccessor { 8 | 9 | private final Method method; 10 | private final boolean staticMethod; 11 | 12 | private final MethodHandle methodHandle; 13 | 14 | public DefaultMethodAccessor(Method method, MethodHandle methodHandle, boolean staticMethod) { 15 | this.method = method; 16 | this.methodHandle = methodHandle; 17 | this.staticMethod = staticMethod; 18 | } 19 | 20 | @Override 21 | public Object invoke(Object target, Object... args) { 22 | try { 23 | return this.methodHandle.invoke(target, args); 24 | } catch (Throwable throwable) { 25 | throw new IllegalStateException("Unable to invoke method " + this.method, throwable); 26 | } 27 | } 28 | 29 | @Override 30 | public Method getMethod() { 31 | return this.method; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/reflect/accessors/FieldAccessor.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.reflect.accessors; 2 | 3 | import java.lang.reflect.Field; 4 | 5 | /** 6 | * Represents an interface for accessing a field. 7 | * 8 | * @author Kristian 9 | */ 10 | public interface FieldAccessor { 11 | 12 | /** 13 | * Retrieve the value of a field for a particular instance. 14 | * 15 | * @param instance - the instance, or NULL for a static field. 16 | * @return The value of the field. 17 | * @throws IllegalStateException If the current security context prohibits reflection. 18 | */ 19 | Object get(Object instance); 20 | 21 | /** 22 | * Set the value of a field for a particular instance. 23 | * 24 | * @param instance - the instance, or NULL for a static field. 25 | * @param value - the new value of the field. 26 | */ 27 | void set(Object instance, Object value); 28 | 29 | /** 30 | * Retrieve the underlying field. 31 | * 32 | * @return The field. 33 | */ 34 | Field getField(); 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/reflect/accessors/MemorizingFieldAccessor.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.reflect.accessors; 2 | 3 | import java.lang.reflect.Field; 4 | 5 | final class MemorizingFieldAccessor implements FieldAccessor { 6 | 7 | // a marker object which indicates the value of the field wasn't yet read 8 | private static final Object NIL = new Object(); 9 | 10 | private final FieldAccessor inner; 11 | private volatile Object fieldValue = NIL; 12 | 13 | public MemorizingFieldAccessor(FieldAccessor inner) { 14 | this.inner = inner; 15 | } 16 | 17 | @Override 18 | public Object get(Object instance) { 19 | if (this.fieldValue == NIL) { 20 | this.fieldValue = this.inner.get(instance); 21 | } 22 | 23 | return this.fieldValue; 24 | } 25 | 26 | @Override 27 | public void set(Object instance, Object value) { 28 | this.inner.set(instance, value); 29 | this.fieldValue = value; 30 | } 31 | 32 | @Override 33 | public Field getField() { 34 | return this.inner.getField(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/reflect/accessors/MethodAccessor.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.reflect.accessors; 2 | 3 | import java.lang.reflect.Method; 4 | 5 | /** 6 | * Represents an interface for invoking a method. 7 | * 8 | * @author Kristian 9 | */ 10 | public interface MethodAccessor { 11 | 12 | /** 13 | * Invoke the underlying method. 14 | * 15 | * @param target - the target instance, or NULL for a static method. 16 | * @param args - the arguments to pass to the method. 17 | * @return The return value, or NULL for void methods. 18 | */ 19 | Object invoke(Object target, Object... args); 20 | 21 | /** 22 | * Retrieve the underlying method. 23 | * 24 | * @return The method. 25 | */ 26 | Method getMethod(); 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/reflect/cloning/Cloner.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. 3 | * Copyright (C) 2012 Kristian S. Stangeland 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; either version 2 of 7 | * the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 15 | * 02111-1307 USA 16 | */ 17 | 18 | package com.comphenix.protocol.reflect.cloning; 19 | 20 | /** 21 | * Represents an object that is capable of cloning other objects. 22 | * 23 | * @author Kristian 24 | */ 25 | public interface Cloner { 26 | /** 27 | * Determine whether or not the current cloner can clone the given object. 28 | * @param source - the object that is being considered. 29 | * @return TRUE if this cloner can actually clone the given object, FALSE otherwise. 30 | */ 31 | public boolean canClone(Object source); 32 | 33 | /** 34 | * Perform the clone. 35 | *

36 | * This method should never be called unless a corresponding {@link #canClone(Object)} returns TRUE. 37 | * @param source - the value to clone. 38 | * @return A cloned value. 39 | * @throws IllegalArgumentException If this cloner cannot perform the clone. 40 | */ 41 | public Object clone(Object source); 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/reflect/cloning/GuavaOptionalCloner.java: -------------------------------------------------------------------------------- 1 | /** 2 | * (c) 2016 dmulloy2 3 | */ 4 | package com.comphenix.protocol.reflect.cloning; 5 | 6 | import com.google.common.base.Optional; 7 | 8 | /** 9 | * A cloner that can clone Guava Optional objects 10 | * @author dmulloy2 11 | */ 12 | 13 | public class GuavaOptionalCloner implements Cloner { 14 | protected Cloner wrapped; 15 | 16 | public GuavaOptionalCloner(Cloner wrapped) { 17 | this.wrapped = wrapped; 18 | } 19 | 20 | @Override 21 | public boolean canClone(Object source) { 22 | return source instanceof Optional; 23 | } 24 | 25 | @Override 26 | public Object clone(Object source) { 27 | Optional optional = (Optional) source; 28 | if (!optional.isPresent()) { 29 | return Optional.absent(); 30 | } 31 | 32 | // Clone the inner value 33 | return Optional.of(wrapped.clone(optional.get())); 34 | } 35 | 36 | public Cloner getWrapped() { 37 | return wrapped; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/reflect/cloning/JavaOptionalCloner.java: -------------------------------------------------------------------------------- 1 | /** 2 | * (c) 2018 dmulloy2 3 | */ 4 | package com.comphenix.protocol.reflect.cloning; 5 | 6 | import java.util.Optional; 7 | import java.util.OptionalInt; 8 | 9 | /** 10 | * A cloner that can clone Java Optional objects 11 | * @author dmulloy2 12 | */ 13 | public class JavaOptionalCloner implements Cloner { 14 | protected Cloner wrapped; 15 | 16 | public JavaOptionalCloner(Cloner wrapped) { 17 | this.wrapped = wrapped; 18 | } 19 | 20 | @Override 21 | public boolean canClone(Object source) { 22 | return source instanceof Optional || source instanceof OptionalInt; 23 | } 24 | 25 | @Override 26 | public Object clone(Object source) { 27 | if (source instanceof Optional) { 28 | Optional optional = (Optional) source; 29 | return optional.map(o -> wrapped.clone(o)); 30 | } else if (source instanceof OptionalInt) { 31 | // why Java felt the need to make each optional class distinct is beyond me 32 | // like why couldn't they have given us at least a common interface or something 33 | OptionalInt optional = (OptionalInt) source; 34 | return optional.isPresent() ? OptionalInt.of(optional.getAsInt()) : OptionalInt.empty(); 35 | } 36 | 37 | return null; 38 | } 39 | 40 | public Cloner getWrapped() { 41 | return wrapped; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/reflect/cloning/NullableCloner.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. 3 | * Copyright (C) 2012 Kristian S. Stangeland 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; either version 2 of 7 | * the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 15 | * 02111-1307 USA 16 | */ 17 | 18 | package com.comphenix.protocol.reflect.cloning; 19 | 20 | /** 21 | * Creates a cloner wrapper that accepts and clones NULL values. 22 | * 23 | * @author Kristian 24 | */ 25 | public class NullableCloner implements Cloner { 26 | protected Cloner wrapped; 27 | 28 | public NullableCloner(Cloner wrapped) { 29 | this.wrapped = wrapped; 30 | } 31 | 32 | @Override 33 | public boolean canClone(Object source) { 34 | return true; 35 | } 36 | 37 | @Override 38 | public Object clone(Object source) { 39 | // Don't pass the NULL value to the cloner 40 | if (source == null) 41 | return null; 42 | else 43 | return wrapped.clone(source); 44 | } 45 | 46 | public Cloner getWrapped() { 47 | return wrapped; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/reflect/cloning/SerializableCloner.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.reflect.cloning; 2 | 3 | import java.io.ByteArrayInputStream; 4 | import java.io.ByteArrayOutputStream; 5 | import java.io.ObjectInputStream; 6 | import java.io.ObjectOutputStream; 7 | import java.io.Serializable; 8 | 9 | /** 10 | * Represents a cloner that can clone any class that implements Serializable. 11 | * @author Kristian Stangeland 12 | */ 13 | public class SerializableCloner implements Cloner { 14 | 15 | @Override 16 | public boolean canClone(Object source) { 17 | if (source == null) 18 | return false; 19 | return source instanceof Serializable; 20 | } 21 | 22 | @Override 23 | public Object clone(Object source) { 24 | return SerializableCloner.clone((Serializable) source); 25 | } 26 | 27 | /** 28 | * Clone the given object using serialization. 29 | * @param Type 30 | * @param obj - the object to clone. 31 | * @return The cloned object. 32 | * @throws RuntimeException If we were unable to clone the object. 33 | */ 34 | @SuppressWarnings("unchecked") 35 | public static T clone(final T obj) { 36 | try { 37 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 38 | ObjectOutputStream oout = new ObjectOutputStream(out); 39 | 40 | oout.writeObject(obj); 41 | ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(out.toByteArray())); 42 | return (T) in.readObject(); 43 | } catch (Exception e) { 44 | throw new RuntimeException("Unable to clone object " + obj + " (" + obj.getClass().getName() + ")", e); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/reflect/fuzzy/AbstractFuzzyMatcher.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.reflect.fuzzy; 2 | 3 | /** 4 | * Represents a matcher for fields, methods, constructors and classes. 5 | *

6 | * This class should ideally never expose mutable state. Its round number must be immutable. 7 | * 8 | * @author Kristian 9 | */ 10 | @FunctionalInterface 11 | public interface AbstractFuzzyMatcher { 12 | 13 | /** 14 | * Determine if the given value is a match. 15 | * 16 | * @param value - the value to match. 17 | * @param parent - the parent container, or NULL if this value is the root. 18 | * @return TRUE if it is a match, FALSE otherwise. 19 | */ 20 | boolean isMatch(T value, Object parent); 21 | 22 | /** 23 | * Create a fuzzy matcher that returns the opposite result of the current matcher. 24 | * 25 | * @return An inverted fuzzy matcher. 26 | */ 27 | default AbstractFuzzyMatcher inverted() { 28 | return (value, parent) -> !this.isMatch(value, parent); 29 | } 30 | 31 | /** 32 | * Require that this and the given matcher be TRUE. 33 | * 34 | * @param other - the other fuzzy matcher. 35 | * @return A combined fuzzy matcher. 36 | */ 37 | default AbstractFuzzyMatcher and(final AbstractFuzzyMatcher other) { 38 | // They both have to be true 39 | return (value, parent) -> this.isMatch(value, parent) && other.isMatch(value, parent); 40 | } 41 | 42 | /** 43 | * Require that either this or the other given matcher be TRUE. 44 | * 45 | * @param other - the other fuzzy matcher. 46 | * @return A combined fuzzy matcher. 47 | */ 48 | default AbstractFuzzyMatcher or(final AbstractFuzzyMatcher other) { 49 | // Either can be true 50 | return (value, parent) -> this.isMatch(value, parent) || other.isMatch(value, parent); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/reflect/fuzzy/ClassRegexMatcher.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.reflect.fuzzy; 2 | 3 | import java.util.regex.Pattern; 4 | 5 | /** 6 | * Determine if a class matches based on its name using a regular expression. 7 | * 8 | * @author Kristian 9 | */ 10 | final class ClassRegexMatcher implements AbstractFuzzyMatcher> { 11 | 12 | private final Pattern regex; 13 | 14 | public ClassRegexMatcher(Pattern regex) { 15 | this.regex = regex; 16 | } 17 | 18 | @Override 19 | public boolean isMatch(Class value, Object parent) { 20 | if (value != null && this.regex != null) { 21 | return this.regex.matcher(value.getCanonicalName()).matches(); 22 | } else { 23 | return false; 24 | } 25 | } 26 | 27 | @Override 28 | public String toString() { 29 | return "{ type matches \"" + this.regex.pattern() + "\" }"; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/reflect/fuzzy/ClassSetMatcher.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.reflect.fuzzy; 2 | 3 | import java.util.Set; 4 | 5 | /** 6 | * Represents a class matcher that checks for equality using a given set of classes. 7 | * 8 | * @author Kristian 9 | */ 10 | final class ClassSetMatcher implements AbstractFuzzyMatcher> { 11 | 12 | private final Set> classes; 13 | 14 | public ClassSetMatcher(Set> classes) { 15 | this.classes = classes; 16 | } 17 | 18 | @Override 19 | public boolean isMatch(Class value, Object parent) { 20 | return this.classes.contains(value); 21 | } 22 | 23 | @Override 24 | public String toString() { 25 | return "{ type any of " + this.classes + " }"; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/reflect/instances/BannedGenerator.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.reflect.instances; 2 | 3 | import javax.annotation.Nullable; 4 | 5 | import com.comphenix.protocol.reflect.fuzzy.AbstractFuzzyMatcher; 6 | import com.comphenix.protocol.reflect.fuzzy.FuzzyMatchers; 7 | 8 | /** 9 | * Generator that ensures certain types will never be created. 10 | * 11 | * @author Kristian 12 | */ 13 | public class BannedGenerator implements InstanceProvider { 14 | private AbstractFuzzyMatcher> classMatcher; 15 | 16 | /** 17 | * Construct a generator that ensures any class that matches the given matcher is never constructed. 18 | * @param classMatcher - a class matcher. 19 | */ 20 | public BannedGenerator(AbstractFuzzyMatcher> classMatcher) { 21 | this.classMatcher = classMatcher; 22 | } 23 | 24 | public BannedGenerator(Class... classes) { 25 | this.classMatcher = FuzzyMatchers.matchAnyOf(classes); 26 | } 27 | 28 | @Override 29 | public Object create(@Nullable Class type) { 30 | // Prevent these types from being constructed 31 | if (classMatcher.isMatch(type, null)) { 32 | throw new NotConstructableException(); 33 | } 34 | return null; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/reflect/instances/CollectionGenerator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. 3 | * Copyright (C) 2012 Kristian S. Stangeland 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; either version 2 of 7 | * the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 15 | * 02111-1307 USA 16 | */ 17 | 18 | package com.comphenix.protocol.reflect.instances; 19 | 20 | import java.util.ArrayList; 21 | import java.util.Collection; 22 | import java.util.HashMap; 23 | import java.util.HashSet; 24 | import java.util.LinkedList; 25 | import java.util.List; 26 | import java.util.Map; 27 | import java.util.Queue; 28 | import java.util.Set; 29 | import java.util.SortedMap; 30 | import java.util.SortedSet; 31 | import java.util.TreeMap; 32 | import java.util.TreeSet; 33 | 34 | import javax.annotation.Nullable; 35 | 36 | /** 37 | * Provides simple constructors for collection interfaces. 38 | * @author Kristian 39 | */ 40 | public class CollectionGenerator implements InstanceProvider { 41 | 42 | /** 43 | * Shared instance of this generator. 44 | */ 45 | public static final CollectionGenerator INSTANCE = new CollectionGenerator(); 46 | 47 | @Override 48 | public Object create(@Nullable Class type) { 49 | // Standard collection types 50 | if (type != null && type.isInterface()) { 51 | if (type.equals(Collection.class) || type.equals(List.class)) return new ArrayList<>(); 52 | else if (type.equals(Set.class)) return new HashSet<>(); 53 | else if (type.equals(Map.class)) return new HashMap<>(); 54 | else if (type.equals(SortedSet.class)) return new TreeSet<>(); 55 | else if (type.equals(SortedMap.class)) return new TreeMap<>(); 56 | else if (type.equals(Queue.class)) return new LinkedList<>(); 57 | } 58 | 59 | // Cannot provide an instance 60 | return null; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/reflect/instances/InstanceProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. 3 | * Copyright (C) 2012 Kristian S. Stangeland 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; either version 2 of 7 | * the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 15 | * 02111-1307 USA 16 | */ 17 | 18 | package com.comphenix.protocol.reflect.instances; 19 | 20 | import javax.annotation.Nullable; 21 | 22 | /** 23 | * Represents a type generator for specific types. 24 | * 25 | * @author Kristian 26 | */ 27 | public interface InstanceProvider { 28 | /** 29 | * Create an instance given a type, if possible. 30 | * @param type - type to create. 31 | * @return The instance, or NULL if the type cannot be created. 32 | * @throws NotConstructableException Thrown to indicate that this type cannot or should never be constructed. 33 | */ 34 | public abstract Object create(@Nullable Class type); 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/reflect/instances/NotConstructableException.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.reflect.instances; 2 | 3 | /** 4 | * Invoked when a instance provider indicates that a given type cannot or should not be 5 | * constructed under any circumstances. 6 | * 7 | * @author Kristian 8 | */ 9 | public class NotConstructableException extends IllegalArgumentException { 10 | /** 11 | * Generated by Eclipse. 12 | */ 13 | private static final long serialVersionUID = -1144171604744845463L; 14 | 15 | /** 16 | * Construct a new not constructable exception. 17 | */ 18 | public NotConstructableException() { 19 | super("This object should never be constructed."); 20 | } 21 | 22 | /** 23 | * Construct a new not constructable exception with a custom message. 24 | * @param message - detail message 25 | */ 26 | public NotConstructableException(String message) { 27 | super(message); 28 | } 29 | 30 | /** 31 | * Construct a new not constructable exception with a custom message and cause. 32 | * @param message - detail message 33 | * @param cause - cause 34 | */ 35 | public NotConstructableException(String message, Throwable cause) { 36 | super(message, cause); 37 | } 38 | 39 | /** 40 | * Construct a new not constructable exception with a custom cause. 41 | * @param cause - cause 42 | */ 43 | public NotConstructableException(Throwable cause) { 44 | super( cause); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/reflect/instances/PrimitiveGenerator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. 3 | * Copyright (C) 2012 Kristian S. Stangeland 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; either version 2 of 7 | * the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 15 | * 02111-1307 USA 16 | */ 17 | 18 | package com.comphenix.protocol.reflect.instances; 19 | 20 | import java.lang.reflect.Array; 21 | import java.util.Optional; 22 | 23 | import com.google.common.base.Defaults; 24 | import com.google.common.primitives.Primitives; 25 | import javax.annotation.Nullable; 26 | 27 | /** 28 | * Provides constructors for primitive java types and wrappers. 29 | * 30 | * @author Kristian 31 | */ 32 | public class PrimitiveGenerator implements InstanceProvider { 33 | 34 | /** 35 | * Default value for Strings. 36 | */ 37 | @Deprecated 38 | public static final String STRING_DEFAULT = ""; 39 | 40 | /** 41 | * Shared instance of this generator. 42 | */ 43 | public static PrimitiveGenerator INSTANCE = new PrimitiveGenerator(); 44 | 45 | // Our default string value 46 | private final String stringDefault; 47 | 48 | public PrimitiveGenerator() { 49 | this.stringDefault = ""; 50 | } 51 | 52 | @Deprecated 53 | public PrimitiveGenerator(String stringDefault) { 54 | this.stringDefault = stringDefault; 55 | } 56 | 57 | /** 58 | * Retrieve the string default. 59 | * 60 | * @return Default instance of a string. 61 | */ 62 | @Deprecated 63 | public String getStringDefault() { 64 | return stringDefault; 65 | } 66 | 67 | @Override 68 | public Object create(@Nullable Class type) { 69 | if (type == null) { 70 | return null; 71 | } else if (type.isPrimitive()) { 72 | return Defaults.defaultValue(type); 73 | } else if (Primitives.isWrapperType(type)) { 74 | return Defaults.defaultValue(Primitives.unwrap(type)); 75 | } else if (type.isArray()) { 76 | Class arrayType = type.getComponentType(); 77 | return Array.newInstance(arrayType, 0); 78 | } else if (type.isEnum()) { 79 | Object[] values = type.getEnumConstants(); 80 | if (values != null && values.length > 0) { 81 | return values[0]; 82 | } 83 | } else if (type.equals(String.class)) { 84 | return this.stringDefault; 85 | } else if (type.equals(Optional.class)) { 86 | return Optional.empty(); 87 | } 88 | 89 | // Cannot handle this type 90 | return null; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/timing/OnlineComputation.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.timing; 2 | 3 | /** 4 | * Represents an online computation. 5 | * 6 | * @author Kristian 7 | */ 8 | public abstract class OnlineComputation { 9 | 10 | /** 11 | * Retrieve a wrapper for another online computation that is synchronized. 12 | * 13 | * @param computation - the computation. 14 | * @return The synchronized wrapper. 15 | */ 16 | public static OnlineComputation synchronizedComputation(final OnlineComputation computation) { 17 | return new OnlineComputation() { 18 | @Override 19 | public synchronized void observe(double value) { 20 | computation.observe(value); 21 | } 22 | 23 | @Override 24 | public synchronized int getCount() { 25 | return computation.getCount(); 26 | } 27 | 28 | @Override 29 | public synchronized OnlineComputation copy() { 30 | return computation.copy(); 31 | } 32 | }; 33 | } 34 | 35 | /** 36 | * Retrieve the number of observations. 37 | * 38 | * @return Number of observations. 39 | */ 40 | public abstract int getCount(); 41 | 42 | /** 43 | * Observe a value. 44 | * 45 | * @param value - the observed value. 46 | */ 47 | public abstract void observe(double value); 48 | 49 | /** 50 | * Construct a copy of the current online computation. 51 | * 52 | * @return The new copy. 53 | */ 54 | public abstract OnlineComputation copy(); 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/timing/TimedTracker.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.timing; 2 | 3 | import com.comphenix.protocol.PacketType; 4 | import java.util.HashMap; 5 | import java.util.Map; 6 | import java.util.Map.Entry; 7 | import java.util.concurrent.atomic.AtomicInteger; 8 | 9 | /** 10 | * Tracks the invocation time for a particular plugin against a list of packets. 11 | * 12 | * @author Kristian 13 | */ 14 | public class TimedTracker { 15 | 16 | // Table of packets and invocations 17 | private final AtomicInteger observations = new AtomicInteger(); 18 | private final Map packets = new HashMap<>(); 19 | 20 | /** 21 | * Begin tracking an execution time. 22 | * 23 | * @return The current tracking token. 24 | */ 25 | public long beginTracking() { 26 | return System.nanoTime(); 27 | } 28 | 29 | /** 30 | * Stop and record the execution time since the creation of the given tracking token. 31 | * 32 | * @param trackingToken - the tracking token. 33 | * @param type - the packet type. 34 | */ 35 | public synchronized void endTracking(long trackingToken, PacketType type) { 36 | StatisticsStream stream = this.packets.get(type); 37 | 38 | // Lazily create a stream 39 | if (stream == null) { 40 | this.packets.put(type, stream = new StatisticsStream()); 41 | } 42 | // Store this observation 43 | stream.observe(System.nanoTime() - trackingToken); 44 | this.observations.incrementAndGet(); 45 | } 46 | 47 | /** 48 | * Retrieve the total number of observations. 49 | * 50 | * @return Total number of observations. 51 | */ 52 | public int getObservations() { 53 | return this.observations.get(); 54 | } 55 | 56 | /** 57 | * Retrieve an map (indexed by packet type) of all relevant statistics. 58 | * 59 | * @return The map of statistics. 60 | */ 61 | public synchronized Map getStatistics() { 62 | final Map clone = new HashMap<>(); 63 | 64 | for (Entry entry : this.packets.entrySet()) { 65 | clone.put( 66 | entry.getKey(), 67 | new StatisticsStream(entry.getValue()) 68 | ); 69 | } 70 | return clone; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/utility/ByteBuddyFactory.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.utility; 2 | 3 | import net.bytebuddy.ByteBuddy; 4 | import net.bytebuddy.dynamic.DynamicType; 5 | import net.bytebuddy.dynamic.scaffold.subclass.ConstructorStrategy; 6 | 7 | /** 8 | * Represents a shared ByteBuddy factory. 9 | * 10 | * @author Kristian 11 | */ 12 | public final class ByteBuddyFactory { 13 | 14 | private static final ByteBuddyFactory INSTANCE = new ByteBuddyFactory(); 15 | 16 | // The current class loader 17 | private ClassLoader loader = ByteBuddyFactory.class.getClassLoader(); 18 | 19 | public static ByteBuddyFactory getInstance() { 20 | return INSTANCE; 21 | } 22 | 23 | /** 24 | * Get the current class loader we are using. 25 | * 26 | * @return The current class loader. 27 | */ 28 | public ClassLoader getClassLoader() { 29 | return this.loader; 30 | } 31 | 32 | /** 33 | * Set the current class loader to use when constructing enhancers. 34 | * 35 | * @param loader - the class loader 36 | */ 37 | public void setClassLoader(ClassLoader loader) { 38 | this.loader = loader; 39 | } 40 | 41 | /** 42 | * Creates a type builder for a subclass of a given {@link Class}. 43 | * 44 | * @param clz The class for which to create a subclass. 45 | * @return A type builder for creating a new class extending the provided clz and implementing {@link 46 | * ByteBuddyGenerated}. 47 | */ 48 | public DynamicType.Builder.MethodDefinition.ImplementationDefinition.Optional createSubclass(Class clz) { 49 | return new ByteBuddy() 50 | .subclass(clz) 51 | .implement(ByteBuddyGenerated.class); 52 | } 53 | 54 | /** 55 | * Creates a type builder for a subclass of a given {@link Class}. 56 | * 57 | * @param clz The class for which to create a subclass. 58 | * @param constructorStrategy The constructor strategy to use. 59 | * @return A type builder for creating a new class extending the provided clz and implementing {@link 60 | * ByteBuddyGenerated}. 61 | */ 62 | public DynamicType.Builder.MethodDefinition.ImplementationDefinition.Optional createSubclass( 63 | Class clz, 64 | ConstructorStrategy.Default constructorStrategy 65 | ) { 66 | return new ByteBuddy() 67 | .subclass(clz, constructorStrategy) 68 | .implement(ByteBuddyGenerated.class); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/utility/ByteBuddyGenerated.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.utility; 2 | 3 | /** 4 | * Represents an object that has been generated using ByteBuddy. 5 | * 6 | * @author Pim 7 | */ 8 | public interface ByteBuddyGenerated { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/utility/Closer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. Copyright (C) 2015 dmulloy2 3 | *

4 | * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public 5 | * License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later 6 | * version. 7 | *

8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied 9 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 10 | * details. 11 | *

12 | * You should have received a copy of the GNU General Public License along with this program; if not, write to the Free 13 | * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 14 | */ 15 | package com.comphenix.protocol.utility; 16 | 17 | import java.io.Closeable; 18 | import java.util.ArrayList; 19 | import java.util.List; 20 | 21 | /** 22 | * @author dmulloy2 23 | */ 24 | 25 | // TODO Switch to AutoCloseable w/ Java 7 26 | @Deprecated 27 | public class Closer implements AutoCloseable { 28 | private final List list; 29 | 30 | private Closer() { 31 | this.list = new ArrayList<>(); 32 | } 33 | 34 | public static Closer create() { 35 | return new Closer(); 36 | } 37 | 38 | public static void closeQuietly(Closeable close) { 39 | try { 40 | close.close(); 41 | } catch (Throwable ex) { 42 | } 43 | } 44 | 45 | public C register(C close) { 46 | list.add(close); 47 | return close; 48 | } 49 | 50 | @Override 51 | public void close() { 52 | for (Closeable close : list) { 53 | closeQuietly(close); 54 | } 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/utility/Optionals.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.utility; 2 | 3 | import java.util.Optional; 4 | import java.util.function.Predicate; 5 | import java.util.function.Supplier; 6 | 7 | /** 8 | * Utility methods for operating with Optionals 9 | */ 10 | public final class Optionals { 11 | 12 | /** 13 | * Chains two optionals together by returning the secondary 14 | * optional if the primary does not contain a value 15 | * @param primary Primary optional 16 | * @param secondary Supplier of secondary optional 17 | * @return The resulting optional 18 | * @param Type 19 | */ 20 | public static Optional or(Optional primary, Supplier> secondary) { 21 | return primary.isPresent() ? primary : secondary.get(); 22 | } 23 | 24 | /** 25 | * Evaluates the provided predicate against the optional only if it is present 26 | * @param optional Optional 27 | * @param predicate Test to run against potential value 28 | * @return True if the optional is present and the predicate passes 29 | * @param Type 30 | */ 31 | public static boolean TestIfPresent(Optional optional, Predicate predicate) { 32 | return optional.isPresent() && predicate.test(optional.get()); 33 | } 34 | 35 | /** 36 | * Check if the optional has a value and its value equals the provided value 37 | * @param optional Optional 38 | * @param contents Contents to test for 39 | * @return True if the optional has a value and that value equals the parameter 40 | * @param Type 41 | */ 42 | public static boolean Equals(Optional optional, Class contents) { 43 | return optional.isPresent() && contents.equals(optional.get()); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/utility/Util.java: -------------------------------------------------------------------------------- 1 | /** 2 | * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. Copyright (C) 2015 dmulloy2 3 | *

4 | * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public 5 | * License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later 6 | * version. 7 | *

8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied 9 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 10 | * details. 11 | *

12 | * You should have received a copy of the GNU General Public License along with this program; if not, write to the Free 13 | * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 14 | */ 15 | package com.comphenix.protocol.utility; 16 | 17 | /** 18 | * General utility class 19 | * 20 | * @author dmulloy2 21 | */ 22 | public final class Util { 23 | 24 | private static final boolean SPIGOT = classExists("org.spigotmc.SpigotConfig"); 25 | private static Class cachedBundleClass; 26 | 27 | public static boolean classExists(String className) { 28 | try { 29 | Class.forName(className); 30 | return true; 31 | } catch (ClassNotFoundException ex) { 32 | return false; 33 | } 34 | } 35 | 36 | /** 37 | * Whether this server is running Spigot or a Spigot fork. This works by checking if the SpigotConfig exists, which 38 | * should be true of all forks. 39 | * 40 | * @return True if it is, false if not. 41 | */ 42 | public static boolean isUsingSpigot() { 43 | return SPIGOT; 44 | } 45 | 46 | /** 47 | * Checks if the server is getting reloaded by walking down the current thread stack trace. 48 | * 49 | * @return true if the server is getting reloaded, false otherwise. 50 | */ 51 | public static boolean isCurrentlyReloading() { 52 | StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); 53 | for (StackTraceElement element : stackTrace) { 54 | String clazz = element.getClassName(); 55 | if (clazz.startsWith("org.bukkit.craftbukkit.") 56 | && clazz.endsWith(".CraftServer") 57 | && element.getMethodName().equals("reload")) { 58 | return true; 59 | } 60 | } 61 | return false; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/wrappers/AbstractWrapper.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.wrappers; 2 | 3 | import com.google.common.base.Preconditions; 4 | 5 | /** 6 | * Represents a wrapper for an NMS object. 7 | * @author Kristian 8 | */ 9 | public abstract class AbstractWrapper { 10 | protected Object handle; 11 | protected Class handleType; 12 | 13 | /** 14 | * Construct a new NMS wrapper. 15 | * @param handleType - the NMS handle type. 16 | */ 17 | public AbstractWrapper(Class handleType) { 18 | this.handleType = Preconditions.checkNotNull(handleType, "handleType cannot be NULL"); 19 | } 20 | 21 | /** 22 | * Set the underlying NMS object. 23 | * @param handle - the NMS object. 24 | * @throws IllegalArgumentException If the handle is NULL. 25 | * @throws IllegalArgumentException If the handle is not assignable to {@link #getHandleType()}. 26 | */ 27 | protected void setHandle(Object handle) { 28 | if (handle == null) 29 | throw new IllegalArgumentException("handle cannot be NULL."); 30 | if (!handleType.isAssignableFrom(handle.getClass())) 31 | throw new IllegalArgumentException("handle (" + handle + ") is not a " + handleType + ", but " + handle.getClass()); 32 | this.handle = handle; 33 | } 34 | 35 | /** 36 | * Retrieves the underlying NMS object. 37 | * @return The underlying NMS object. 38 | */ 39 | public Object getHandle() { 40 | return handle; 41 | } 42 | 43 | /** 44 | * Retrieve the type of the handle. 45 | * @return The type of the handle. 46 | */ 47 | public Class getHandleType() { 48 | return handleType; 49 | } 50 | 51 | @Override 52 | public boolean equals(Object obj) { 53 | if (obj == this) return true; 54 | 55 | if (obj instanceof AbstractWrapper) { 56 | AbstractWrapper that = (AbstractWrapper) obj; 57 | return this.handle.equals(that.handle); 58 | } 59 | 60 | return false; 61 | } 62 | 63 | @Override 64 | public int hashCode() { 65 | return handle.hashCode(); 66 | } 67 | 68 | @Override 69 | public String toString() { 70 | return getClass().getName() + "[handle=" + handle + "]"; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/wrappers/AdventureComponentConverter.java: -------------------------------------------------------------------------------- 1 | /** 2 | * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. 3 | * Copyright (C) 2015 dmulloy2 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; either version 2 of 7 | * the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 15 | * 02111-1307 USA 16 | */ 17 | package com.comphenix.protocol.wrappers; 18 | 19 | import net.kyori.adventure.text.Component; 20 | import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; 21 | 22 | /** 23 | * Utility class for converting between the Adventure API Component and ProtocolLib's wrapper 24 | *

25 | * Note: The Adventure API Component is not included in CraftBukkit, Bukkit or Spigot and but is present in PaperMC. 26 | */ 27 | public class AdventureComponentConverter { 28 | 29 | private AdventureComponentConverter() { 30 | } 31 | 32 | /** 33 | * Converts a {@link WrappedChatComponent} into a {@link Component} 34 | * @param wrapper ProtocolLib wrapper 35 | * @return Component 36 | */ 37 | public static Component fromWrapper(WrappedChatComponent wrapper) { 38 | return GsonComponentSerializer.gson().deserialize(wrapper.getJson()); 39 | } 40 | 41 | /** 42 | * Converts a {@link Component} into a ProtocolLib wrapper 43 | * @param component Component 44 | * @return ProtocolLib wrapper 45 | */ 46 | public static WrappedChatComponent fromComponent(Component component) { 47 | return WrappedChatComponent.fromJson(GsonComponentSerializer.gson().serialize(component)); 48 | } 49 | 50 | public static Class getComponentClass() { 51 | return Component.class; 52 | } 53 | 54 | public static Component clone(Object component) { 55 | return (Component) component; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/wrappers/ClonableWrapper.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.wrappers; 2 | 3 | public interface ClonableWrapper { 4 | Object getHandle(); 5 | ClonableWrapper deepClone(); 6 | 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/wrappers/ComponentConverter.java: -------------------------------------------------------------------------------- 1 | /** 2 | * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. 3 | * Copyright (C) 2015 dmulloy2 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; either version 2 of 7 | * the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 15 | * 02111-1307 USA 16 | */ 17 | package com.comphenix.protocol.wrappers; 18 | 19 | import net.md_5.bungee.api.chat.BaseComponent; 20 | import net.md_5.bungee.chat.ComponentSerializer; 21 | 22 | /** 23 | * Utility class for converting between the BungeeCord Chat API and ProtocolLib's wrapper 24 | *

25 | * Note: The BungeeCord Chat API is not included in CraftBukkit. 26 | * @author dmulloy2 27 | */ 28 | public final class ComponentConverter { 29 | 30 | private ComponentConverter() { 31 | } 32 | 33 | /** 34 | * Converts a {@link WrappedChatComponent} into an array of {@link BaseComponent}s 35 | * @param wrapper ProtocolLib wrapper 36 | * @return BaseComponent array 37 | */ 38 | public static BaseComponent[] fromWrapper(WrappedChatComponent wrapper) { 39 | return ComponentSerializer.parse(wrapper.getJson()); 40 | } 41 | 42 | /** 43 | * Converts an array of {@link BaseComponent}s into a ProtocolLib wrapper 44 | * @param components BaseComponent array 45 | * @return ProtocolLib wrapper 46 | */ 47 | public static WrappedChatComponent fromBaseComponent(BaseComponent... components) { 48 | return WrappedChatComponent.fromJson(ComponentSerializer.toString(components)); 49 | } 50 | 51 | public static Class getBaseComponentArrayClass() { 52 | return BaseComponent[].class; 53 | } 54 | 55 | public static BaseComponent[] clone(BaseComponent... components) { 56 | return ComponentSerializer.parse(ComponentSerializer.toString(components)); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/wrappers/Pair.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.wrappers; 2 | 3 | import java.util.Objects; 4 | 5 | public class Pair { 6 | private A first; 7 | private B second; 8 | 9 | public Pair(A first, B second) { 10 | this.first = first; 11 | this.second = second; 12 | } 13 | 14 | public A getFirst() { 15 | return first; 16 | } 17 | 18 | public B getSecond() { 19 | return second; 20 | } 21 | 22 | public void setFirst(A first) { 23 | this.first = first; 24 | } 25 | 26 | public void setSecond(B second) { 27 | this.second = second; 28 | } 29 | 30 | @Override 31 | public boolean equals(Object o) { 32 | if (this == o) return true; 33 | if (o == null || getClass() != o.getClass()) return false; 34 | Pair pair = (Pair) o; 35 | return Objects.equals(first, pair.first) && 36 | Objects.equals(second, pair.second); 37 | } 38 | 39 | @Override 40 | public int hashCode() { 41 | return Objects.hash(first, second); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/wrappers/WrappedDataValue.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.wrappers; 2 | 3 | import com.comphenix.protocol.reflect.StructureModifier; 4 | import com.comphenix.protocol.reflect.accessors.Accessors; 5 | import com.comphenix.protocol.reflect.accessors.ConstructorAccessor; 6 | import com.comphenix.protocol.utility.MinecraftReflection; 7 | import com.comphenix.protocol.wrappers.WrappedDataWatcher.Registry; 8 | import com.comphenix.protocol.wrappers.WrappedDataWatcher.Serializer; 9 | 10 | /** 11 | * Represents a DataValue in 1.19.3+. 12 | */ 13 | public class WrappedDataValue extends AbstractWrapper { 14 | 15 | private static final Class HANDLE_TYPE = MinecraftReflection.getNullableNMS("network.syncher.DataWatcher$b", "network.syncher.SynchedEntityData$DataValue"); 16 | 17 | private static ConstructorAccessor constructor; 18 | 19 | private final StructureModifier modifier; 20 | 21 | /** 22 | * Construct a new NMS wrapper. 23 | * 24 | * @param handle the wrapped data value. 25 | */ 26 | public WrappedDataValue(Object handle) { 27 | super(HANDLE_TYPE); 28 | this.setHandle(handle); 29 | this.modifier = new StructureModifier<>(this.handleType).withTarget(handle); 30 | } 31 | 32 | public WrappedDataValue(int index, Serializer serializer, Object value) { 33 | this(newHandle(index, serializer, value)); 34 | } 35 | 36 | private static Object newHandle(int index, Serializer serializer, Object value) { 37 | if (constructor == null) { 38 | constructor = Accessors.getConstructorAccessor(HANDLE_TYPE.getConstructors()[0]); 39 | } 40 | 41 | return constructor.invoke(index, serializer.getHandle(), value); 42 | } 43 | 44 | public int getIndex() { 45 | return this.modifier.withType(int.class).read(0); 46 | } 47 | 48 | public void setIndex(int index) { 49 | this.modifier.withType(int.class).write(0, index); 50 | } 51 | 52 | public Serializer getSerializer() { 53 | Object serializer = this.modifier.readSafely(1); 54 | if (serializer != null) { 55 | Serializer wrapper = Registry.fromHandle(serializer); 56 | if (wrapper != null) { 57 | return wrapper; 58 | } else { 59 | return new Serializer(null, serializer, false); 60 | } 61 | } else { 62 | return null; 63 | } 64 | } 65 | 66 | public void setSerializer(Serializer serializer) { 67 | this.modifier.writeSafely(1, serializer == null ? null : serializer.getHandle()); 68 | } 69 | 70 | public Object getValue() { 71 | return WrappedWatchableObject.getWrapped(getRawValue()); 72 | } 73 | 74 | public void setValue(Object value) { 75 | setRawValue(WrappedWatchableObject.getUnwrapped(value)); 76 | } 77 | 78 | public Object getRawValue() { 79 | return this.modifier.readSafely(2); 80 | } 81 | 82 | public void setRawValue(Object value) { 83 | this.modifier.writeSafely(2, value); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/wrappers/WrappedMessageSignature.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.wrappers; 2 | 3 | import com.comphenix.protocol.reflect.StructureModifier; 4 | import com.comphenix.protocol.reflect.accessors.Accessors; 5 | import com.comphenix.protocol.reflect.accessors.ConstructorAccessor; 6 | import com.comphenix.protocol.utility.MinecraftReflection; 7 | 8 | /** 9 | * @author Lukas Alt 10 | * @since 24.04.2023 11 | */ 12 | public class WrappedMessageSignature extends AbstractWrapper { 13 | private final static Class HANDLE_TYPE = MinecraftReflection.getMessageSignatureClass(); 14 | private static ConstructorAccessor CONSTRUCTOR; 15 | private StructureModifier modifier; 16 | 17 | /** 18 | * Construct a new NMS wrapper. 19 | * 20 | * @param handle - the NMS handle 21 | */ 22 | public WrappedMessageSignature(Object handle) { 23 | super(HANDLE_TYPE); 24 | this.setHandle(handle); 25 | } 26 | 27 | public WrappedMessageSignature(byte[] bytes) { 28 | super(HANDLE_TYPE); 29 | if(CONSTRUCTOR == null) { 30 | CONSTRUCTOR = Accessors.getConstructorAccessor(HANDLE_TYPE, byte[].class); 31 | } 32 | this.setHandle(CONSTRUCTOR.invoke(bytes)); 33 | } 34 | 35 | @Override 36 | protected void setHandle(Object handle) { 37 | super.setHandle(handle); 38 | this.modifier = new StructureModifier<>(HANDLE_TYPE).withTarget(handle); 39 | } 40 | 41 | public byte[] getBytes() { 42 | return modifier.withType(byte[].class).read(0); 43 | } 44 | 45 | public void setBytes(byte[] bytes) { 46 | modifier.withType(byte[].class).write(0, bytes); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/wrappers/WrappedStatistic.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.wrappers; 2 | 3 | import java.util.Map; 4 | import java.util.stream.Collectors; 5 | 6 | import com.comphenix.protocol.reflect.FuzzyReflection; 7 | import com.comphenix.protocol.reflect.accessors.Accessors; 8 | import com.comphenix.protocol.reflect.accessors.FieldAccessor; 9 | import com.comphenix.protocol.reflect.accessors.MethodAccessor; 10 | import com.comphenix.protocol.utility.MinecraftReflection; 11 | 12 | /** 13 | * Represents a Minecraft statistics. 14 | * @author Kristian 15 | */ 16 | public class WrappedStatistic extends AbstractWrapper { 17 | private static final Class STATISTIC = MinecraftReflection.getStatisticClass(); 18 | private static final Class STATISTIC_LIST = MinecraftReflection.getStatisticListClass(); 19 | 20 | 21 | static { 22 | try { 23 | FIND_STATISTICS = Accessors.getMethodAccessor( 24 | FuzzyReflection.fromClass(STATISTIC_LIST).getMethodByReturnTypeAndParameters( 25 | "findStatistic", STATISTIC, new Class[]{String.class})); 26 | MAP_ACCESSOR = Accessors.getFieldAccessor(STATISTIC_LIST, Map.class, true); 27 | GET_NAME = Accessors.getFieldAccessor(STATISTIC, String.class, true); 28 | } catch (Exception ex) { 29 | // TODO - find an alternative 30 | } 31 | } 32 | 33 | private static MethodAccessor FIND_STATISTICS; 34 | private static FieldAccessor MAP_ACCESSOR; 35 | private static FieldAccessor GET_NAME; 36 | 37 | private final String name; 38 | 39 | private WrappedStatistic(Object handle) { 40 | super(STATISTIC); 41 | setHandle(handle); 42 | 43 | this.name = (String) GET_NAME.get(handle); 44 | } 45 | 46 | /** 47 | * Construct a new wrapper from a given underlying statistics. 48 | * @param handle - the statistics. 49 | * @return The wrapped statistics. 50 | */ 51 | public static WrappedStatistic fromHandle(Object handle) { 52 | return new WrappedStatistic(handle); 53 | } 54 | 55 | /** 56 | * Construct a wrapper around an existing game profile. 57 | * @param name - statistic name. 58 | * @return The wrapped statistics, or NULL if not found. 59 | */ 60 | public static WrappedStatistic fromName(String name) { 61 | Object handle = FIND_STATISTICS.invoke(null, name); 62 | return handle != null ? fromHandle(handle) : null; 63 | } 64 | 65 | /** 66 | * Retrieve every known statistics. 67 | * @return Every statistics. 68 | */ 69 | public static Iterable values() { 70 | @SuppressWarnings("unchecked") 71 | Map map = (Map) MAP_ACCESSOR.get(null); 72 | 73 | return map.values().stream().map(WrappedStatistic::fromHandle).collect(Collectors.toList()); 74 | } 75 | 76 | /** 77 | * Retrieve the unique name of this statistic. 78 | * @return The name. 79 | */ 80 | public String getName() { 81 | return name; 82 | } 83 | 84 | @Override 85 | public String toString() { 86 | return String.valueOf(handle); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/wrappers/codecs/WrappedCodec.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.wrappers.codecs; 2 | 3 | import com.comphenix.protocol.reflect.accessors.Accessors; 4 | import com.comphenix.protocol.reflect.accessors.MethodAccessor; 5 | import com.comphenix.protocol.utility.MinecraftReflection; 6 | import com.comphenix.protocol.wrappers.AbstractWrapper; 7 | 8 | public class WrappedCodec extends AbstractWrapper { 9 | private static final Class HANDLE_TYPE = MinecraftReflection.getCodecClass(); 10 | private static final Class ENCODER_CLASS = MinecraftReflection.getLibraryClass("com.mojang.serialization.Encoder"); 11 | private static final Class DECODER_CLASS = MinecraftReflection.getLibraryClass("com.mojang.serialization.Decoder"); 12 | private static final MethodAccessor ENCODE_START_ACCESSOR = Accessors.getMethodAccessor(ENCODER_CLASS, "encodeStart", MinecraftReflection.getDynamicOpsClass(), Object.class); 13 | private static final MethodAccessor PARSE_ACCESSOR = Accessors.getMethodAccessor(DECODER_CLASS, "parse", MinecraftReflection.getDynamicOpsClass(), Object.class); 14 | 15 | private WrappedCodec(Object handle) { 16 | super(HANDLE_TYPE); 17 | this.setHandle(handle); 18 | } 19 | 20 | public static WrappedCodec fromHandle(Object handle) { 21 | return new WrappedCodec(handle); 22 | } 23 | 24 | public WrappedDataResult encode(Object object, WrappedDynamicOps ops) { 25 | return WrappedDataResult.fromHandle(ENCODE_START_ACCESSOR.invoke(handle, ops.getHandle(), object)); 26 | } 27 | 28 | public WrappedDataResult parse(Object value, WrappedDynamicOps ops) { 29 | return WrappedDataResult.fromHandle(PARSE_ACCESSOR.invoke(handle, ops.getHandle(), value)); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/wrappers/codecs/WrappedDataResult.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.wrappers.codecs; 2 | 3 | import com.comphenix.protocol.reflect.accessors.Accessors; 4 | import com.comphenix.protocol.reflect.accessors.MethodAccessor; 5 | import com.comphenix.protocol.utility.MinecraftReflection; 6 | import com.comphenix.protocol.wrappers.AbstractWrapper; 7 | 8 | import java.util.NoSuchElementException; 9 | import java.util.Optional; 10 | import java.util.function.Function; 11 | 12 | public class WrappedDataResult extends AbstractWrapper { 13 | private final static Class HANDLE_TYPE = MinecraftReflection.getLibraryClass("com.mojang.serialization.DataResult"); 14 | private final static Class PARTIAL_DATA_RESULT_CLASS = MinecraftReflection.getLibraryClass("com.mojang.serialization.DataResult$PartialResult"); 15 | private final static MethodAccessor ERROR_ACCESSOR = Accessors.getMethodAccessor(HANDLE_TYPE, "error"); 16 | private final static MethodAccessor RESULT_ACCESSOR = Accessors.getMethodAccessor(HANDLE_TYPE, "result"); 17 | private final static MethodAccessor PARTIAL_RESULT_MESSAGE_ACCESSOR = Accessors.getMethodAccessor(PARTIAL_DATA_RESULT_CLASS, "message"); 18 | 19 | /** 20 | * Construct a new NMS wrapper. 21 | **/ 22 | public WrappedDataResult(Object handle) { 23 | super(HANDLE_TYPE); 24 | this.setHandle(handle); 25 | } 26 | 27 | public static WrappedDataResult fromHandle(Object handle) { 28 | return new WrappedDataResult(handle); 29 | } 30 | 31 | public Optional getResult() { 32 | return (Optional) RESULT_ACCESSOR.invoke(this.handle); 33 | } 34 | 35 | public Optional getErrorMessage() { 36 | return (Optional) ERROR_ACCESSOR.invoke(this.handle); 37 | } 38 | 39 | public Object getOrThrow(Function errorHandler) { 40 | Optional err = getErrorMessage(); 41 | if(err.isPresent()) { 42 | return errorHandler.apply((String) PARTIAL_RESULT_MESSAGE_ACCESSOR.invoke(err.get())); 43 | } 44 | Optional result = getResult(); 45 | if(result.isPresent()) { 46 | return result.get(); 47 | } 48 | throw new NoSuchElementException(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/wrappers/codecs/WrappedDynamicOps.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.wrappers.codecs; 2 | 3 | import com.comphenix.protocol.reflect.accessors.Accessors; 4 | import com.comphenix.protocol.reflect.accessors.FieldAccessor; 5 | import com.comphenix.protocol.utility.MinecraftReflection; 6 | import com.comphenix.protocol.wrappers.AbstractWrapper; 7 | 8 | public class WrappedDynamicOps extends AbstractWrapper { 9 | private static final Class HANDLE_TYPE = MinecraftReflection.getDynamicOpsClass(); 10 | public static final FieldAccessor NBT_ACCESSOR = Accessors.getFieldAccessor(MinecraftReflection.getNbtOpsClass(), MinecraftReflection.getNbtOpsClass(), false); 11 | public static final FieldAccessor[] JSON_ACCESSORS = Accessors.getFieldAccessorArray(MinecraftReflection.getJsonOpsClass(), MinecraftReflection.getJsonOpsClass(), false); 12 | private WrappedDynamicOps(Object handle) { 13 | super(HANDLE_TYPE); 14 | this.setHandle(handle); 15 | } 16 | public static WrappedDynamicOps fromHandle(Object handle) { 17 | return new WrappedDynamicOps(handle); 18 | } 19 | public static WrappedDynamicOps json(boolean compressed) { 20 | return fromHandle(JSON_ACCESSORS[compressed ? 1 : 0].get(null)); 21 | } 22 | 23 | public static WrappedDynamicOps nbt() { 24 | return fromHandle(NBT_ACCESSOR); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/wrappers/collection/AbstractConverted.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. 3 | * Copyright (C) 2012 Kristian S. Stangeland 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; either version 2 of 7 | * the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 15 | * 02111-1307 USA 16 | */ 17 | 18 | package com.comphenix.protocol.wrappers.collection; 19 | 20 | import com.google.common.base.Function; 21 | 22 | /** 23 | * Represents an object that transform elements of type VInner to type VOuter and back again. 24 | * 25 | * @author Kristian 26 | * 27 | * @param - the first type. 28 | * @param - the second type. 29 | */ 30 | public abstract class AbstractConverted { 31 | // Inner conversion 32 | private final Function innerConverter = this::toInner; 33 | 34 | // Outer conversion 35 | private final Function outerConverter = this::toOuter; 36 | 37 | /** 38 | * Convert a value from the inner map to the outer visible map. 39 | * @param inner - the inner value. 40 | * @return The outer value. 41 | */ 42 | protected abstract VOuter toOuter(VInner inner); 43 | 44 | /** 45 | * Convert a value from the outer map to the internal inner map. 46 | * @param outer - the outer value. 47 | * @return The inner value. 48 | */ 49 | protected abstract VInner toInner(VOuter outer); 50 | 51 | /** 52 | * Retrieve a function delegate that converts outer objects to inner objects. 53 | * @return A function delegate. 54 | */ 55 | protected Function getInnerConverter() { 56 | return innerConverter; 57 | } 58 | 59 | /** 60 | * Retrieve a function delegate that converts inner objects to outer objects. 61 | * @return A function delegate. 62 | */ 63 | protected Function getOuterConverter() { 64 | return outerConverter; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/wrappers/collection/BiFunction.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.wrappers.collection; 2 | 3 | /** 4 | * Represents a function that accepts two parameters. 5 | * @author Kristian 6 | * @param - type of the first parameter. 7 | * @param - type of the second parameter. 8 | * @param - type of the return value. 9 | */ 10 | public interface BiFunction { 11 | public TResult apply(T1 arg1, T2 arg2); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/wrappers/collection/CachedSet.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.wrappers.collection; 2 | 3 | import java.util.Set; 4 | 5 | /** 6 | * Represents a cached set. Enumeration of the set will use a cached inner list. 7 | * 8 | * @author Kristian 9 | * @param - the element type. 10 | */ 11 | public class CachedSet extends CachedCollection implements Set { 12 | /** 13 | * Construct a cached set from the given delegate. 14 | * @param delegate - the set delegate. 15 | */ 16 | public CachedSet(Set delegate) { 17 | super(delegate); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/wrappers/collection/ConvertedSet.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. 3 | * Copyright (C) 2012 Kristian S. Stangeland 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; either version 2 of 7 | * the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 15 | * 02111-1307 USA 16 | */ 17 | 18 | package com.comphenix.protocol.wrappers.collection; 19 | 20 | import java.util.Collection; 21 | import java.util.Set; 22 | 23 | /** 24 | * Represents a set that wraps another set by transforming the items going in and out. 25 | * 26 | * @author Kristian 27 | * 28 | * @param - type of the element in the inner invisible set. 29 | * @param - type of the elements publically accessible in the outer set. 30 | */ 31 | public abstract class ConvertedSet extends ConvertedCollection implements Set { 32 | public ConvertedSet(Collection inner) { 33 | super(inner); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/wrappers/nbt/MemoryElement.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.wrappers.nbt; 2 | 3 | class MemoryElement implements NbtBase { 4 | private String name; 5 | private TType value; 6 | private NbtType type; 7 | 8 | public MemoryElement(String name, TType value) { 9 | if (name == null) 10 | throw new IllegalArgumentException("Name cannot be NULL."); 11 | if (value == null) 12 | throw new IllegalArgumentException("Element cannot be NULL."); 13 | 14 | this.name = name; 15 | this.value = value; 16 | this.type = NbtType.getTypeFromClass(value.getClass()); 17 | } 18 | 19 | public MemoryElement(String name, TType value, NbtType type) { 20 | if (name == null) 21 | throw new IllegalArgumentException("Name cannot be NULL."); 22 | if (type == null) 23 | throw new IllegalArgumentException("Type cannot be NULL."); 24 | 25 | this.name = name; 26 | this.value = value; 27 | this.type = type; 28 | } 29 | 30 | @Override 31 | public boolean accept(NbtVisitor visitor) { 32 | return visitor.visit(this); 33 | } 34 | 35 | @Override 36 | public NbtType getType() { 37 | return type; 38 | } 39 | 40 | @Override 41 | public String getName() { 42 | return name; 43 | } 44 | 45 | @Override 46 | public void setName(String name) { 47 | this.name = name; 48 | } 49 | 50 | @Override 51 | public TType getValue() { 52 | return value; 53 | } 54 | 55 | @Override 56 | public void setValue(TType newValue) { 57 | this.value = newValue; 58 | } 59 | 60 | @Override 61 | public NbtBase deepClone() { 62 | // This assumes value is an immutable object 63 | return new MemoryElement(name, value, type); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/wrappers/nbt/NameProperty.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.wrappers.nbt; 2 | 3 | import java.util.Map; 4 | import java.util.concurrent.ConcurrentHashMap; 5 | 6 | import com.comphenix.protocol.reflect.StructureModifier; 7 | 8 | public abstract class NameProperty { 9 | private static final Map, StructureModifier> MODIFIERS = new ConcurrentHashMap<>(); 10 | 11 | /** 12 | * Retrieve the name. 13 | * @return The name. 14 | */ 15 | public abstract String getName(); 16 | 17 | /** 18 | * Set the name. 19 | * @param name - the new value of the name. 20 | */ 21 | public abstract void setName(String name); 22 | 23 | /** 24 | * Retrieve the string modifier for a particular class. 25 | * @param baseClass - the base class. 26 | * @return The string modifier, with no target. 27 | */ 28 | private static StructureModifier getModifier(Class baseClass) { 29 | StructureModifier modifier = MODIFIERS.get(baseClass); 30 | 31 | // Share modifier 32 | if (modifier == null) { 33 | modifier = new StructureModifier(baseClass, Object.class, false).withType(String.class); 34 | MODIFIERS.put(baseClass, modifier); 35 | } 36 | return modifier; 37 | } 38 | 39 | /** 40 | * Determine if a string of the given index exists in the base class. 41 | * @param baseClass - the base class. 42 | * @param index - the index to check. 43 | * @return TRUE if it does, FALSE otherwise. 44 | */ 45 | public static boolean hasStringIndex(Class baseClass, int index) { 46 | if (index < 0) 47 | return false; 48 | return index < getModifier(baseClass).size(); 49 | } 50 | 51 | /** 52 | * Retrieve a name property that delegates all read and write operations to a field of the given target. 53 | * @param baseClass - the base class. 54 | * @param target - the target 55 | * @param index - the index of the field. 56 | * @return The name property. 57 | */ 58 | public static NameProperty fromStringIndex(Class baseClass, Object target, final int index) { 59 | final StructureModifier modifier = getModifier(baseClass).withTarget(target); 60 | 61 | return new NameProperty() { 62 | @Override 63 | public String getName() { 64 | return modifier.read(index); 65 | } 66 | 67 | @Override 68 | public void setName(String name) { 69 | modifier.write(index, name); 70 | } 71 | }; 72 | } 73 | 74 | /** 75 | * Retrieve a new name property around a simple field, forming a Java bean. 76 | * @return The name property. 77 | */ 78 | public static NameProperty fromBean() { 79 | return new NameProperty() { 80 | private String name; 81 | 82 | @Override 83 | public void setName(String name) { 84 | this.name = name; 85 | } 86 | 87 | @Override 88 | public String getName() { 89 | return name; 90 | } 91 | }; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/wrappers/nbt/NbtVisitor.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.wrappers.nbt; 2 | 3 | /** 4 | * A visitor that can enumerate a NBT tree structure. 5 | * 6 | * @author Kristian 7 | */ 8 | public interface NbtVisitor { 9 | /** 10 | * Visit a leaf node, which is a NBT tag with a primitive or String value. 11 | * @param node - the visited leaf node. 12 | * @return TRUE to continue visiting children at this level, FALSE otherwise. 13 | */ 14 | public boolean visit(NbtBase node); 15 | 16 | /** 17 | * Begin visiting a list node that contains multiple child nodes of the same type. 18 | * @param list - the NBT tag to process. 19 | * @return TRUE to visit the child nodes of this list, FALSE otherwise. 20 | */ 21 | public boolean visitEnter(NbtList list); 22 | 23 | /** 24 | * Begin visiting a compound node that contains multiple child nodes of different types. 25 | * @param compound - the NBT tag to process. 26 | * @return TRUE to visit the child nodes of this compound, FALSE otherwise. 27 | */ 28 | public boolean visitEnter(NbtCompound compound); 29 | 30 | /** 31 | * Stop visiting a list node. 32 | * @param list - the list we're done visiting. 33 | * @return TRUE for the parent to visit any subsequent sibling nodes, FALSE otherwise. 34 | */ 35 | public boolean visitLeave(NbtList list); 36 | 37 | /** 38 | * Stop visiting a compound node. 39 | * @param compound - the compound we're done visting. 40 | * @return TRUE for the parent to visit any subsequent sibling nodes, FALSE otherwise 41 | */ 42 | public boolean visitLeave(NbtCompound compound); 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/wrappers/nbt/NbtWrapper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. 3 | * Copyright (C) 2012 Kristian S. Stangeland 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; either version 2 of 7 | * the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 15 | * 02111-1307 USA 16 | */ 17 | 18 | package com.comphenix.protocol.wrappers.nbt; 19 | 20 | import java.io.DataOutput; 21 | 22 | import com.comphenix.protocol.wrappers.ClonableWrapper; 23 | 24 | /** 25 | * Indicates that this NBT wraps an underlying net.minecraft.server instance. 26 | *

27 | * Use {@link NbtFactory} to load or create instances. 28 | * 29 | * @author Kristian 30 | * 31 | * @param - type of the value that is stored. 32 | */ 33 | public interface NbtWrapper extends NbtBase, ClonableWrapper { 34 | /** 35 | * Retrieve the underlying net.minecraft.server instance. 36 | * @return The NMS instance. 37 | */ 38 | public Object getHandle(); 39 | 40 | /** 41 | * Write the current NBT tag to an output stream. 42 | * @param destination - the destination stream. 43 | */ 44 | public void write(DataOutput destination); 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/comphenix/protocol/wrappers/ping/ServerPingImpl.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.wrappers.ping; 2 | 3 | import com.comphenix.protocol.wrappers.WrappedChatComponent; 4 | import com.comphenix.protocol.wrappers.WrappedGameProfile; 5 | import com.google.common.collect.ImmutableList; 6 | 7 | public interface ServerPingImpl extends Cloneable { 8 | WrappedChatComponent getMotD(); 9 | void setMotD(WrappedChatComponent description); 10 | int getPlayersMaximum(); 11 | void setPlayersMaximum(int maxPlayers); 12 | int getPlayersOnline(); 13 | void setPlayersOnline(int onlineCount); 14 | ImmutableList getPlayers(); 15 | void setPlayers(Iterable playerSample); 16 | String getVersionName(); 17 | void setVersionName(String versionName); 18 | int getVersionProtocol(); 19 | void setVersionProtocol(int protocolVersion); 20 | String getFavicon(); 21 | void setFavicon(String favicon); 22 | boolean isEnforceSecureChat(); 23 | void setEnforceSecureChat(boolean safeChat); 24 | 25 | void resetPlayers(); 26 | void resetVersion(); 27 | 28 | default boolean isChatPreviewEnabled() { 29 | return false; 30 | } 31 | 32 | default void setChatPreviewEnabled(boolean enabled) { 33 | 34 | } 35 | 36 | boolean arePlayersVisible(); 37 | void setPlayersVisible(boolean visible); 38 | String getJson(); 39 | 40 | Object getHandle(); 41 | } -------------------------------------------------------------------------------- /src/main/resources/config.yml: -------------------------------------------------------------------------------- 1 | global: 2 | # Settings for the automatic version updater 3 | auto updater: 4 | notify: true 5 | download: false 6 | 7 | # Number of seconds to wait until a new update is downloaded 8 | delay: 43200 # 12 hours 9 | 10 | metrics: true 11 | 12 | # Prints certain warnings to players with the protocol.info permission 13 | chat warnings: true 14 | 15 | # Automatically compile structure modifiers 16 | background compiler: true 17 | 18 | # Disable version checking for the given Minecraft version. Backup your world first! 19 | ignore version check: 20 | 21 | # Whether or not to enable the filter command 22 | debug: false 23 | 24 | # Whether or not to print a stack trace for every warning 25 | detailed error: false 26 | 27 | # The engine used by the filter command 28 | script engine: JavaScript 29 | 30 | suppressed reports: -------------------------------------------------------------------------------- /src/main/resources/plugin.yml: -------------------------------------------------------------------------------- 1 | name: ProtocolLib 2 | version: ${version} 3 | description: Provides read/write access to the Minecraft protocol. 4 | authors: [dmulloy2, comphenix] 5 | 6 | main: com.comphenix.protocol.ProtocolLib 7 | load: STARTUP 8 | database: false 9 | api-version: "1.13" 10 | 11 | commands: 12 | protocol: 13 | description: Performs administrative tasks regarding ProtocolLib. 14 | usage: / config|check|update|timings|listeners|version|dump 15 | permission: protocol.admin 16 | permission-message: You don't have 17 | packet: 18 | description: Add or remove a simple packet listener. 19 | usage: / add|remove|names client|server [ID start]-[ID stop] [detailed] 20 | permission: protocol.admin 21 | permission-message: You don't have 22 | filter: 23 | description: Add or remove programmable filters to the packet listeners. 24 | usage: / add|remove name [ID start]-[ID stop] 25 | aliases: [packet_filter] 26 | permission: protocol.admin 27 | permission-message: You don't have 28 | packetlog: 29 | description: Logs hex representations of packets to a file or console 30 | usage: / [location] 31 | permission: protocol.admin 32 | permission-message: You don't have 33 | 34 | permissions: 35 | protocol.*: 36 | description: Gives access to everything. 37 | children: 38 | protocol.admin: true 39 | protocol.info: true 40 | protocol.admin: 41 | description: Able to initiate the update process, and can configure debug mode. 42 | default: op 43 | protocol.info: 44 | description: Can read update notifications and error reports. 45 | default: op -------------------------------------------------------------------------------- /src/test/java/com/comphenix/integration/protocol/TestPingPacket.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.integration.protocol; 2 | 3 | import com.comphenix.protocol.PacketType; 4 | import com.comphenix.protocol.ProtocolLibrary; 5 | import com.comphenix.protocol.events.PacketAdapter; 6 | import com.comphenix.protocol.events.PacketEvent; 7 | import org.bukkit.plugin.Plugin; 8 | 9 | import java.util.concurrent.CountDownLatch; 10 | import java.util.concurrent.ExecutionException; 11 | import java.util.concurrent.Executors; 12 | import java.util.concurrent.Future; 13 | import java.util.concurrent.TimeUnit; 14 | 15 | import static org.junit.jupiter.api.Assertions.assertEquals; 16 | 17 | public class TestPingPacket { 18 | 19 | // Current versions 20 | private static final int PROTOCOL_VERSION = 4; 21 | 22 | // Timeout 23 | private static final int TIMEOUT_PING_MS = 10000; 24 | 25 | private volatile String source; 26 | 27 | private TestPingPacket() { 28 | // Prevent external constructors 29 | } 30 | 31 | /** 32 | * Create a new test ping packet test. 33 | * 34 | * @return The new test. 35 | */ 36 | public static TestPingPacket newTest() { 37 | return new TestPingPacket(); 38 | } 39 | 40 | /** 41 | * Invoked when the test should be started. 42 | * 43 | * @param plugin - the current plugin. 44 | * @throws Throwable Anything went wrong. 45 | */ 46 | public void startTest(Plugin plugin) throws Throwable { 47 | try { 48 | String transmitted = this.testInterception(plugin). 49 | get(TIMEOUT_PING_MS, TimeUnit.MILLISECONDS); 50 | 51 | // Make sure it's the same 52 | System.out.println("Server string: " + transmitted); 53 | assertEquals(this.source, transmitted); 54 | } catch (ExecutionException e) { 55 | throw e.getCause(); 56 | } 57 | } 58 | 59 | private Future testInterception(Plugin test) { 60 | final CountDownLatch latch = new CountDownLatch(1); 61 | 62 | ProtocolLibrary.getProtocolManager().addPacketListener( 63 | new PacketAdapter(test, PacketType.Status.Server.SERVER_INFO) { 64 | @Override 65 | public void onPacketSending(PacketEvent event) { 66 | TestPingPacket.this.source = event.getPacket().getServerPings().read(0).toJson(); 67 | latch.countDown(); 68 | } 69 | }); 70 | 71 | // Invoke the client on a separate thread 72 | return Executors.newSingleThreadExecutor().submit(() -> { 73 | SimpleMinecraftClient client = new SimpleMinecraftClient(PROTOCOL_VERSION); 74 | String information = client.queryLocalPing(); 75 | 76 | // Wait for the listener to catch up 77 | latch.await(1, TimeUnit.SECONDS); 78 | return information; 79 | }); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/test/java/com/comphenix/protocol/MinecraftVersionTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. 3 | * Copyright (C) 2012 Kristian S. Stangeland 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; either version 2 of 7 | * the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 15 | * 02111-1307 USA 16 | */ 17 | 18 | package com.comphenix.protocol; 19 | 20 | import static org.junit.jupiter.api.Assertions.assertEquals; 21 | import static org.junit.jupiter.api.Assertions.assertFalse; 22 | import static org.junit.jupiter.api.Assertions.assertTrue; 23 | 24 | import com.comphenix.protocol.utility.MinecraftVersion; 25 | import org.junit.jupiter.api.Test; 26 | 27 | public class MinecraftVersionTest { 28 | 29 | @Test 30 | public void testComparision() { 31 | MinecraftVersion within = new MinecraftVersion(1, 2, 5); 32 | MinecraftVersion outside = new MinecraftVersion(1, 7, 0); 33 | 34 | MinecraftVersion lower = new MinecraftVersion(1, 0, 0); 35 | MinecraftVersion highest = new MinecraftVersion(1, 4, 5); 36 | 37 | MinecraftVersion atLeast = new MinecraftVersion(1, 8, 8); 38 | 39 | // Make sure this is valid 40 | assertTrue(lower.compareTo(within) < 0 && within.compareTo(highest) < 0); 41 | assertFalse(outside.compareTo(within) < 0 && outside.compareTo(highest) < 0); 42 | assertTrue(atLeast.isAtLeast(MinecraftVersion.BOUNTIFUL_UPDATE)); 43 | } 44 | 45 | /* @Test 46 | public void testSnapshotVersion() { 47 | MinecraftVersion version = MinecraftVersion.fromServerVersion("git-Spigot-1119 (MC: 13w39b)"); 48 | assertEquals(version.getSnapshot(), new SnapshotVersion("13w39b")); 49 | } */ 50 | 51 | @Test 52 | public void testParsing() { 53 | assertEquals(MinecraftVersion.extractVersion("CraftBukkit R3.0 (MC: 1.4.3)"), "1.4.3"); 54 | assertEquals(MinecraftVersion.extractVersion("CraftBukkit Test Beta 1 (MC: 1.10.01 )"), "1.10.01"); 55 | assertEquals(MinecraftVersion.extractVersion("Hello (MC: 2.3.4)"), "2.3.4"); 56 | 57 | assertEquals(MinecraftVersion.fromServerVersion("git-Cauldron-Reloaded-1.7.10-1.1388.1.0 (MC: 1.7.10)"), 58 | new MinecraftVersion(1, 7, 10)); 59 | assertEquals(MinecraftVersion.fromServerVersion("git-Bukkit-18fbb24 (MC: 1.8.8)"), new MinecraftVersion(1, 8, 8)); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/test/java/com/comphenix/protocol/concurrency/BlockingHashMapTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. 3 | * Copyright (C) 2012 Kristian S. Stangeland 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under the terms of the 6 | * GNU General Public License as published by the Free Software Foundation; either version 2 of 7 | * the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 10 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | * See the GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with this program; 14 | * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 15 | * 02111-1307 USA 16 | */ 17 | 18 | package com.comphenix.protocol.concurrency; 19 | 20 | import static org.junit.jupiter.api.Assertions.assertEquals; 21 | 22 | import java.util.concurrent.ExecutionException; 23 | import java.util.concurrent.ExecutorService; 24 | import java.util.concurrent.Executors; 25 | import java.util.concurrent.Future; 26 | import org.junit.jupiter.api.Test; 27 | 28 | public class BlockingHashMapTest { 29 | 30 | @Test 31 | public void test() throws InterruptedException, ExecutionException { 32 | 33 | final BlockingHashMap map = BlockingHashMap.create(); 34 | 35 | ExecutorService service = Executors.newSingleThreadExecutor(); 36 | 37 | // Create a reader 38 | Future future = service.submit(() -> { 39 | // Combine for easy reading 40 | return map.get(0) + map.get(1); 41 | }); 42 | 43 | // Wait a bit 44 | Thread.sleep(50); 45 | 46 | // Insert values 47 | map.put(0, "hello "); 48 | map.put(1, "world"); 49 | 50 | // Wait for the other thread to complete 51 | assertEquals(future.get(), "hello world"); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/test/java/com/comphenix/protocol/events/SerializedOfflinePlayerTest.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.events; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertEquals; 4 | import static org.junit.jupiter.api.Assertions.assertNotNull; 5 | import static org.junit.jupiter.api.Assertions.assertThrows; 6 | import static org.mockito.Mockito.when; 7 | 8 | import java.util.UUID; 9 | import org.bukkit.OfflinePlayer; 10 | import org.bukkit.entity.Player; 11 | import org.junit.jupiter.api.BeforeEach; 12 | import org.junit.jupiter.api.Test; 13 | import org.mockito.Mock; 14 | import org.mockito.MockitoAnnotations; 15 | 16 | public class SerializedOfflinePlayerTest { 17 | 18 | private static final String name = "playerName"; 19 | private static final long firstPlayed = 1000L; 20 | private static final long lastPlayed = firstPlayed + 100L; 21 | private static final boolean isOp = false; 22 | private static final boolean playedBefore = true; 23 | private static final boolean whitelisted = true; 24 | @Mock 25 | static OfflinePlayer offlinePlayer; 26 | private static UUID uuid; 27 | private static SerializedOfflinePlayer serializedOfflinePlayer; 28 | 29 | @BeforeEach 30 | public void initMocks() { 31 | MockitoAnnotations.openMocks(this); 32 | 33 | uuid = UUID.randomUUID(); 34 | when(offlinePlayer.getName()).thenReturn(name); 35 | when(offlinePlayer.getUniqueId()).thenReturn(uuid); 36 | when(offlinePlayer.getFirstPlayed()).thenReturn(firstPlayed); 37 | when(offlinePlayer.getLastPlayed()).thenReturn(lastPlayed); 38 | when(offlinePlayer.isOp()).thenReturn(isOp); 39 | when(offlinePlayer.hasPlayedBefore()).thenReturn(playedBefore); 40 | when(offlinePlayer.isWhitelisted()).thenReturn(whitelisted); 41 | 42 | serializedOfflinePlayer = new SerializedOfflinePlayer(offlinePlayer); 43 | } 44 | 45 | @Test 46 | public void getProxyPlayer() { 47 | Player player = serializedOfflinePlayer.getProxyPlayer(); 48 | assertNotNull(player); 49 | 50 | // getDisplayName only works for online players. 51 | assertThrows(UnsupportedOperationException.class, player::getDisplayName); 52 | 53 | assertEquals(uuid, player.getUniqueId()); 54 | assertEquals(name, player.getName()); 55 | assertEquals(firstPlayed, player.getFirstPlayed()); 56 | assertEquals(lastPlayed, player.getLastPlayed()); 57 | assertEquals(isOp, player.isOp()); 58 | assertEquals(playedBefore, player.hasPlayedBefore()); 59 | assertEquals(whitelisted, player.isWhitelisted()); 60 | } 61 | 62 | @Test 63 | public void getSecondProxyPlayer() { 64 | // Make sure that the proxyPlayer generation doesn't work only once. 65 | Player player = serializedOfflinePlayer.getProxyPlayer(); 66 | assertNotNull(player); 67 | 68 | assertEquals(uuid, player.getUniqueId()); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/test/java/com/comphenix/protocol/injector/EntityUtilitiesTest.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.injector; 2 | 3 | import java.lang.reflect.Field; 4 | 5 | import com.comphenix.protocol.BukkitInitialization; 6 | import com.comphenix.protocol.reflect.FuzzyReflection; 7 | import com.comphenix.protocol.reflect.fuzzy.FuzzyFieldContract; 8 | import it.unimi.dsi.fastutil.ints.Int2ObjectMap; 9 | import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; 10 | import net.minecraft.server.level.ChunkProviderServer; 11 | import net.minecraft.server.level.PlayerChunkMap; 12 | import net.minecraft.server.level.PlayerChunkMap.EntityTracker; 13 | import net.minecraft.server.level.WorldServer; 14 | import net.minecraft.world.entity.Entity; 15 | import org.bukkit.craftbukkit.v1_19_R3.CraftWorld; 16 | import org.bukkit.craftbukkit.v1_19_R3.entity.CraftEntity; 17 | import org.junit.jupiter.api.BeforeAll; 18 | import org.junit.jupiter.api.Test; 19 | 20 | import static com.comphenix.protocol.utility.TestUtils.setFinalField; 21 | import static org.mockito.Mockito.mock; 22 | import static org.mockito.Mockito.when; 23 | 24 | public class EntityUtilitiesTest { 25 | 26 | @BeforeAll 27 | public static void beforeClass() { 28 | BukkitInitialization.initializeAll(); 29 | } 30 | 31 | @Test 32 | public void testReflection() { 33 | CraftWorld bukkit = mock(CraftWorld.class); 34 | WorldServer world = mock(WorldServer.class); 35 | when(bukkit.getHandle()).thenReturn(world); 36 | 37 | ChunkProviderServer provider = mock(ChunkProviderServer.class); 38 | when(world.k()).thenReturn(provider); 39 | 40 | PlayerChunkMap chunkMap = mock(PlayerChunkMap.class); 41 | Field chunkMapField = FuzzyReflection.fromClass(ChunkProviderServer.class, true) 42 | .getField(FuzzyFieldContract.newBuilder().typeExact(PlayerChunkMap.class).build()); 43 | setFinalField(provider, chunkMapField, chunkMap); 44 | 45 | CraftEntity bukkitEntity = mock(CraftEntity.class); 46 | Entity fakeEntity = mock(Entity.class); 47 | when(fakeEntity.getBukkitEntity()).thenReturn(bukkitEntity); 48 | 49 | EntityTracker tracker = mock(EntityTracker.class); 50 | Field trackerField = FuzzyReflection.fromClass(EntityTracker.class, true) 51 | .getField(FuzzyFieldContract.newBuilder().typeExact(Entity.class).build()); 52 | setFinalField(tracker, trackerField, fakeEntity); 53 | 54 | Int2ObjectMap trackerMap = new Int2ObjectOpenHashMap<>(); 55 | trackerMap.put(1, tracker); 56 | Field trackedEntitiesField = FuzzyReflection.fromClass(PlayerChunkMap.class, true) 57 | .getField(FuzzyFieldContract.newBuilder().typeExact(Int2ObjectMap.class).build()); 58 | setFinalField(chunkMap, trackedEntitiesField, trackerMap); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/test/java/com/comphenix/protocol/injector/WirePacketTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * (c) 2016 dmulloy2 3 | */ 4 | package com.comphenix.protocol.injector; 5 | 6 | import static org.junit.jupiter.api.Assertions.assertArrayEquals; 7 | import static org.junit.jupiter.api.Assertions.assertEquals; 8 | 9 | import com.comphenix.protocol.BukkitInitialization; 10 | import com.comphenix.protocol.PacketType; 11 | import com.comphenix.protocol.events.PacketContainer; 12 | import com.comphenix.protocol.injector.netty.WirePacket; 13 | import io.netty.buffer.ByteBuf; 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | import org.junit.jupiter.api.BeforeAll; 17 | import org.junit.jupiter.api.Test; 18 | 19 | /** 20 | * @author dmulloy2 21 | */ 22 | public class WirePacketTest { 23 | 24 | @BeforeAll 25 | public static void beforeClass() { 26 | BukkitInitialization.initializeAll(); 27 | } 28 | 29 | // @Test 30 | public void testPackets() { 31 | List failures = new ArrayList<>(); 32 | 33 | for (PacketType type : PacketType.values()) { 34 | if (type.isDeprecated()) { 35 | continue; 36 | } 37 | 38 | try { 39 | PacketContainer packet = new PacketContainer(type); 40 | WirePacket wire = WirePacket.fromPacket(packet); 41 | WirePacket handle = WirePacket.fromPacket(packet.getHandle()); 42 | assertEquals(wire, handle); 43 | } catch (Exception ex) { 44 | failures.add(type + " :: " + ex.getMessage()); 45 | System.out.println(type); 46 | ex.printStackTrace(); 47 | } 48 | } 49 | 50 | assertEquals(failures, new ArrayList<>()); 51 | } 52 | 53 | @Test 54 | public void testSerialization() { 55 | int id = 42; 56 | byte[] array = {1, 3, 7, 21, 88, 67, 8}; 57 | 58 | WirePacket packet = new WirePacket(id, array); 59 | 60 | ByteBuf buf = packet.serialize(); 61 | 62 | int backId = WirePacket.readVarInt(buf); 63 | byte[] backArray = new byte[buf.readableBytes()]; 64 | buf.readBytes(backArray); 65 | 66 | assertEquals(id, backId); 67 | assertArrayEquals(array, backArray); 68 | } 69 | } -------------------------------------------------------------------------------- /src/test/java/com/comphenix/protocol/injector/temporary/TemporaryPlayerFactoryTest.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.injector.temporary; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertEquals; 4 | import static org.junit.jupiter.api.Assertions.assertThrows; 5 | 6 | import org.bukkit.Server; 7 | import org.bukkit.entity.Player; 8 | import org.junit.jupiter.api.BeforeEach; 9 | import org.junit.jupiter.api.Test; 10 | import org.mockito.Mock; 11 | import org.mockito.MockitoAnnotations; 12 | 13 | public class TemporaryPlayerFactoryTest { 14 | 15 | private static final TemporaryPlayerFactory temporaryPlayerFactory = new TemporaryPlayerFactory(); 16 | 17 | @Mock 18 | Server server; 19 | @Mock 20 | MinimalInjector minimalInjector; 21 | 22 | @BeforeEach 23 | public void initMocks() { 24 | MockitoAnnotations.openMocks(this); 25 | } 26 | 27 | @Test 28 | public void testUnavailableSocketInjector() { 29 | Player player = temporaryPlayerFactory.createTemporaryPlayer(this.server); 30 | assertThrows(IllegalStateException.class, player::getPlayer); 31 | } 32 | 33 | @Test 34 | public void createTemporaryPlayer() { 35 | 36 | Player player = temporaryPlayerFactory.createTemporaryPlayer(this.server, this.minimalInjector); 37 | assertEquals(this.server, player.getServer()); 38 | 39 | // May seem dumb, but this makes sure that the .equals method is still instact. 40 | assertEquals(player, player); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/test/java/com/comphenix/protocol/reflect/accessors/AccessorsTest.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.reflect.accessors; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; 4 | import static org.junit.jupiter.api.Assertions.assertEquals; 5 | 6 | import com.comphenix.protocol.reflect.ExactReflection; 7 | import java.lang.reflect.Field; 8 | import org.junit.jupiter.api.Test; 9 | 10 | public class AccessorsTest { 11 | 12 | @Test 13 | public void testField() { 14 | Player player = new Player(123, "ABC"); 15 | 16 | Field id = assertDoesNotThrow(() -> ExactReflection.fromClass(Player.class, true).getField("id")); 17 | Field name = assertDoesNotThrow(() -> ExactReflection.fromClass(Player.class, true).getField("name")); 18 | 19 | assertDoesNotThrow(() -> Accessors.getFieldAccessor(id).set(player, 15)); 20 | assertDoesNotThrow(() -> Accessors.getFieldAccessor(name).set(player, "MODIFIED")); 21 | 22 | assertEquals(15, player.getId()); 23 | assertEquals("MODIFIED", player.getName()); 24 | } 25 | 26 | @Test 27 | public void testMethod() { 28 | Player player = new Player(123, "ABC"); 29 | 30 | assertDoesNotThrow(() -> Accessors.getMethodAccessor(player.getClass(), "setId", int.class).invoke(player, 0)); 31 | assertEquals(0, player.getId()); 32 | } 33 | 34 | @Test 35 | public void testConstructor() { 36 | Player player = (Player) assertDoesNotThrow(() -> Accessors 37 | .getConstructorAccessor(Player.class, int.class, String.class) 38 | .invoke(12, "hi")); 39 | assertEquals(12, player.getId()); 40 | assertEquals("hi", player.getName()); 41 | } 42 | 43 | // --- Some classes we can use for testing --- 44 | private static class Entity { 45 | 46 | private int id; 47 | 48 | public Entity(int id) { 49 | this.id = id; 50 | } 51 | 52 | public int getId() { 53 | return this.id; 54 | } 55 | 56 | @SuppressWarnings("unused") 57 | private void setId(int value) { 58 | this.id = value; 59 | } 60 | } 61 | 62 | private static class Player extends Entity { 63 | 64 | private final String name; 65 | 66 | public Player(int id, String name) { 67 | super(id); 68 | this.name = name; 69 | } 70 | 71 | public String getName() { 72 | return this.name; 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/test/java/com/comphenix/protocol/reflect/cloning/AggregateClonerTest.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.reflect.cloning; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertEquals; 4 | 5 | import com.comphenix.protocol.BukkitInitialization; 6 | import com.comphenix.protocol.PacketType; 7 | import com.comphenix.protocol.events.PacketContainer; 8 | import java.util.Arrays; 9 | import java.util.List; 10 | import net.minecraft.core.NonNullList; 11 | import net.minecraft.world.item.ItemStack; 12 | import org.junit.jupiter.api.Assertions; 13 | import org.junit.jupiter.api.BeforeAll; 14 | import org.junit.jupiter.api.Test; 15 | 16 | public class AggregateClonerTest { 17 | 18 | @BeforeAll 19 | public static void initializeBukkit() { 20 | BukkitInitialization.initializeAll(); 21 | } 22 | 23 | @Test 24 | public void testArrays() { 25 | List input = Arrays.asList(1, 2, 3); 26 | assertEquals(input, AggregateCloner.DEFAULT.clone(input)); 27 | } 28 | 29 | // @Test 30 | // Usages of NonNullList were removed in 1.17.1 31 | public void testNonNullList() { 32 | PacketContainer packet = new PacketContainer(PacketType.Play.Server.WINDOW_ITEMS); 33 | 34 | NonNullList list = NonNullList.a(16, ItemStack.b); 35 | packet.getModifier().write(1, list); 36 | 37 | PacketContainer cloned = packet.deepClone(); 38 | 39 | @SuppressWarnings("unchecked") 40 | NonNullList list1 = (NonNullList) cloned.getModifier().read(1); 41 | 42 | assertEquals(list.size(), list1.size()); 43 | Assertions.assertArrayEquals(list.toArray(), list1.toArray()); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/test/java/com/comphenix/protocol/updater/UpdaterTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * (c) 2016 dmulloy2 3 | */ 4 | package com.comphenix.protocol.updater; 5 | 6 | import static org.junit.jupiter.api.Assertions.assertEquals; 7 | import static org.junit.jupiter.api.Assertions.fail; 8 | import static org.mockito.Mockito.mock; 9 | import static org.mockito.Mockito.when; 10 | 11 | import com.comphenix.protocol.updater.Updater.UpdateType; 12 | import java.util.logging.Logger; 13 | import org.bukkit.Server; 14 | import org.bukkit.plugin.Plugin; 15 | import org.bukkit.plugin.PluginDescriptionFile; 16 | import org.junit.jupiter.api.BeforeAll; 17 | import org.junit.jupiter.api.Test; 18 | 19 | /** 20 | * @author dmulloy2 21 | */ 22 | public class UpdaterTest { 23 | 24 | private static final int BUKKIT_DEV_ID = 45564; 25 | private static Plugin plugin; 26 | 27 | @BeforeAll 28 | public static void preparePlugin() { 29 | Server server = mock(Server.class); 30 | when(server.getUpdateFolder()).thenReturn(null); 31 | 32 | plugin = mock(Plugin.class); 33 | String version = System.getProperty("projectVersion"); 34 | if (version == null) { 35 | version = "4.4.0"; 36 | } 37 | when(plugin.getDescription()).thenReturn(new PluginDescriptionFile("ProtocolLib", version, null)); 38 | when(plugin.getLogger()).thenReturn(Logger.getLogger("ProtocolLib")); 39 | when(plugin.getDataFolder()).thenReturn(null); 40 | when(plugin.getServer()).thenReturn(server); 41 | } 42 | 43 | @Test 44 | public void testUpdaterType() { 45 | assertEquals(Updater.create(plugin, BUKKIT_DEV_ID, null, UpdateType.NO_DOWNLOAD, true).getClass(), 46 | SpigotUpdater.class); 47 | } 48 | 49 | // @Test 50 | public void testSpigotUpdater() { 51 | SpigotUpdater updater = new SpigotUpdater(plugin, UpdateType.NO_DOWNLOAD, true); 52 | 53 | String remote = null; 54 | 55 | try { 56 | remote = updater.getSpigotVersion(); 57 | } catch (Throwable ex) { 58 | fail("Failed to check for updates", ex); 59 | } 60 | 61 | System.out.println("Determined remote Spigot version: " + remote); 62 | System.out.println("Update available: " + updater.versionCheck(remote)); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/test/java/com/comphenix/protocol/utility/CachedPackageTest.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.utility; 2 | 3 | import java.util.Optional; 4 | 5 | import org.junit.jupiter.api.BeforeEach; 6 | import org.junit.jupiter.api.Test; 7 | 8 | import static org.junit.jupiter.api.Assertions.assertEquals; 9 | import static org.junit.jupiter.api.Assertions.assertTrue; 10 | 11 | public class CachedPackageTest { 12 | private CachedPackage pack; 13 | 14 | @BeforeEach 15 | public void prepare() { 16 | ClassSource source = ClassSource.fromClassLoader(); 17 | this.pack = new CachedPackage("java.lang", source); 18 | } 19 | 20 | @Test 21 | public void testGetPackageClass() { 22 | Optional> result = pack.getPackageClass("Object"); 23 | assertTrue(result.isPresent()); 24 | assertEquals(result.get(), Object.class); 25 | } 26 | 27 | @Test 28 | public void testUsingAliases() { 29 | Optional> result = pack.getPackageClass("NOT_A_CLASS", "Object"); 30 | assertTrue(result.isPresent()); 31 | assertEquals(result.get(), Object.class); 32 | 33 | result = pack.getPackageClass("NOT_A_CLASS", "STILL_NOT_A_CLASS", "Object"); 34 | assertTrue(result.isPresent()); 35 | assertEquals(result.get(), Object.class); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/test/java/com/comphenix/protocol/utility/MinecraftMethodsTest.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.utility; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertNotNull; 4 | 5 | import com.comphenix.protocol.BukkitInitialization; 6 | import java.lang.reflect.Field; 7 | import org.junit.jupiter.api.BeforeAll; 8 | import org.junit.jupiter.api.Test; 9 | 10 | public class MinecraftMethodsTest { 11 | 12 | @BeforeAll 13 | public static void initializeReflection() { 14 | BukkitInitialization.initializeAll(); 15 | } 16 | 17 | @Test 18 | public void testSendPacketMethods() { 19 | assertNotNull(MinecraftMethods.getSendPacketMethod()); 20 | assertNotNull(MinecraftMethods.getNetworkManagerHandleMethod()); 21 | } 22 | 23 | private void setNull(final String fieldName) throws NoSuchFieldException, IllegalAccessException { 24 | Field field = MinecraftMethods.class.getDeclaredField(fieldName); 25 | field.setAccessible(true); 26 | field.set(null, null); 27 | } 28 | 29 | @Test 30 | public void initializePacket() throws NoSuchFieldException, IllegalAccessException { 31 | this.setNull("packetReadByteBuf"); 32 | this.setNull("packetWriteByteBuf"); 33 | 34 | assertNotNull(MinecraftMethods.getPacketWriteByteBufMethod()); 35 | // TODO it's now a constructor 36 | // assertNotNull(MinecraftMethods.getPacketReadByteBufMethod()); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/test/java/com/comphenix/protocol/utility/MinecraftReflectionTestUtil.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.utility; 2 | 3 | public class MinecraftReflectionTestUtil { 4 | 5 | public static final String RELEASE_TARGET = "1.19.3"; 6 | public static final String PACKAGE_VERSION = "v1_19_R3"; 7 | public static final String NMS = "net.minecraft"; 8 | public static final String OBC = "org.bukkit.craftbukkit." + PACKAGE_VERSION; 9 | 10 | public static void init() { 11 | MinecraftReflection.setMinecraftPackage(NMS, OBC); 12 | MinecraftVersion.setCurrentVersion(MinecraftVersion.LATEST); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/test/java/com/comphenix/protocol/utility/SnapshotVersionTest.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.utility; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertEquals; 4 | import static org.junit.jupiter.api.Assertions.assertThrows; 5 | 6 | import java.util.Calendar; 7 | import java.util.Date; 8 | import java.util.Locale; 9 | import org.junit.jupiter.api.Test; 10 | 11 | public class SnapshotVersionTest { 12 | 13 | @Test 14 | public void testDates() { 15 | SnapshotVersion a = new SnapshotVersion("12w50b"); 16 | SnapshotVersion b = new SnapshotVersion("13w05a"); 17 | 18 | this.expect(a.getSnapshotDate(), 12, 50); 19 | this.expect(b.getSnapshotDate(), 13, 5); 20 | 21 | // Test equality 22 | assertEquals(a, new SnapshotVersion("12w50b")); 23 | } 24 | 25 | @Test 26 | public void testDateParsingProblem() { 27 | // This date is not valid 28 | assertThrows(IllegalArgumentException.class, () -> new SnapshotVersion("12w80a")); 29 | } 30 | 31 | @Test 32 | public void testMissingWeekVersion() { 33 | assertThrows(IllegalArgumentException.class, () -> new SnapshotVersion("13w05")); 34 | } 35 | 36 | private void expect(Date date, int year, int week) { 37 | Calendar calendar = Calendar.getInstance(Locale.US); 38 | calendar.setTime(date); 39 | assertEquals(year, calendar.get(Calendar.YEAR) % 100); 40 | assertEquals(week, calendar.get(Calendar.WEEK_OF_YEAR)); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/test/java/com/comphenix/protocol/utility/TestUtils.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.utility; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertEquals; 4 | import static org.junit.jupiter.api.Assertions.assertNotNull; 5 | import static org.junit.jupiter.api.Assertions.assertNull; 6 | import static org.junit.jupiter.api.Assertions.assertTrue; 7 | 8 | import com.comphenix.protocol.reflect.accessors.Accessors; 9 | import java.lang.reflect.Field; 10 | import java.security.KeyPair; 11 | import java.security.KeyPairGenerator; 12 | import java.time.Instant; 13 | import java.util.List; 14 | import java.util.Random; 15 | import java.util.UUID; 16 | 17 | import com.comphenix.protocol.wrappers.WrappedProfilePublicKey; 18 | import com.comphenix.protocol.wrappers.WrappedRemoteChatSessionData; 19 | import org.bukkit.Bukkit; 20 | import org.bukkit.inventory.ItemStack; 21 | 22 | public class TestUtils { 23 | 24 | public static void assertItemCollectionsEqual(List first, List second) { 25 | assertEquals(first.size(), second.size()); 26 | for (int i = 0; i < first.size(); i++) { 27 | assertItemsEqual(first.get(i), second.get(i)); 28 | } 29 | } 30 | 31 | public static void assertItemsEqual(ItemStack first, ItemStack second) { 32 | if (first == null) { 33 | assertNull(second); 34 | } else { 35 | assertNotNull(first); 36 | 37 | // The legacy check in ItemStack#isSimilar causes a null pointer 38 | assertEquals(first.getType(), second.getType()); 39 | assertEquals(first.getDurability(), second.getDurability()); 40 | assertEquals(first.hasItemMeta(), second.hasItemMeta()); 41 | if (first.hasItemMeta()) { 42 | assertTrue(Bukkit.getItemFactory().equals(first.getItemMeta(), second.getItemMeta())); 43 | } 44 | } 45 | } 46 | 47 | public static boolean equivalentItem(ItemStack first, ItemStack second) { 48 | if (first == null) { 49 | return second == null; 50 | } else if (second == null) { 51 | return false; 52 | } else { 53 | return first.getType().equals(second.getType()); 54 | } 55 | } 56 | 57 | public static void setFinalField(Object obj, Field field, Object newValue) { 58 | Accessors.getFieldAccessor(field).set(obj, newValue); 59 | } 60 | 61 | public static KeyPair generateKeyPair() throws Exception { 62 | KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); 63 | keyPairGenerator.initialize(1024); 64 | return keyPairGenerator.generateKeyPair(); 65 | } 66 | 67 | public static WrappedRemoteChatSessionData creteDummyRemoteChatSessionData() throws Exception { 68 | byte[] signature = new byte[256]; 69 | new Random().nextBytes(signature); 70 | 71 | return new WrappedRemoteChatSessionData(UUID.randomUUID(), new WrappedProfilePublicKey.WrappedProfileKeyData(Instant.now(), TestUtils.generateKeyPair().getPublic(), signature)); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/test/java/com/comphenix/protocol/wrappers/ChunkCoordIntPairTest.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.wrappers; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertEquals; 4 | 5 | import com.comphenix.protocol.BukkitInitialization; 6 | import org.junit.jupiter.api.BeforeAll; 7 | import org.junit.jupiter.api.Test; 8 | 9 | public class ChunkCoordIntPairTest { 10 | 11 | @BeforeAll 12 | public static void initializeBukkit() { 13 | BukkitInitialization.initializeAll(); 14 | } 15 | 16 | @Test 17 | public void test() { 18 | net.minecraft.world.level.ChunkCoordIntPair pair = new net.minecraft.world.level.ChunkCoordIntPair(1, 2); 19 | ChunkCoordIntPair specific = ChunkCoordIntPair.getConverter().getSpecific(pair); 20 | 21 | assertEquals(1, specific.getChunkX()); 22 | assertEquals(2, specific.getChunkZ()); 23 | 24 | net.minecraft.world.level.ChunkCoordIntPair roundtrip = 25 | (net.minecraft.world.level.ChunkCoordIntPair) ChunkCoordIntPair.getConverter(). 26 | getGeneric(specific); 27 | 28 | assertEquals(1, roundtrip.e); 29 | assertEquals(2, roundtrip.f); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/test/java/com/comphenix/protocol/wrappers/CloningTest.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.wrappers; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertEquals; 4 | 5 | import com.comphenix.protocol.BukkitInitialization; 6 | import com.comphenix.protocol.reflect.cloning.AggregateCloner; 7 | import org.junit.jupiter.api.BeforeAll; 8 | import org.junit.jupiter.api.Test; 9 | 10 | public class CloningTest { 11 | 12 | @BeforeAll 13 | public static void initializeBukkit() { 14 | BukkitInitialization.initializeAll(); 15 | } 16 | 17 | @Test 18 | public void cloneGameProfile() { 19 | WrappedGameProfile profile = new WrappedGameProfile("8817d9ec-72e6-4abe-a496-cda667c3efe1", "name"); 20 | WrappedGameProfile copy = WrappedGameProfile.fromHandle( 21 | AggregateCloner.DEFAULT.clone(profile.getHandle()) 22 | ); 23 | 24 | assertEquals(profile, copy); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/test/java/com/comphenix/protocol/wrappers/ConverterTest.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.wrappers; 2 | 3 | import com.comphenix.protocol.reflect.EquivalentConverter; 4 | import org.apache.commons.lang.builder.EqualsBuilder; 5 | import org.junit.jupiter.api.Test; 6 | 7 | import java.util.ArrayList; 8 | import java.util.Arrays; 9 | import java.util.List; 10 | 11 | import static org.junit.jupiter.api.Assertions.assertEquals; 12 | import static org.junit.jupiter.api.Assertions.assertTrue; 13 | 14 | /** 15 | * @author Lukas Alt 16 | * @since 26.03.2023 17 | */ 18 | public class ConverterTest { 19 | @Test 20 | public void testIterableConverter() { 21 | EquivalentConverter> converter = Converters.iterable(Converters.passthrough(String.class), ArrayList::new, ArrayList::new); 22 | List l = Arrays.asList("a", "b", "c"); 23 | Object generic = converter.getGeneric(l); 24 | Object specific = converter.getSpecific(generic); 25 | assertEquals(l, specific); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/test/java/com/comphenix/protocol/wrappers/EitherTest.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.wrappers; 2 | 3 | import com.comphenix.protocol.wrappers.Either.Left; 4 | import com.comphenix.protocol.wrappers.Either.Right; 5 | 6 | import java.util.Optional; 7 | 8 | import org.junit.jupiter.api.Test; 9 | 10 | import static org.junit.jupiter.api.Assertions.assertEquals; 11 | 12 | class EitherTest { 13 | 14 | @Test 15 | void testLeft() { 16 | Left left = new Left<>("left"); 17 | 18 | assertEquals(left.left(), Optional.of("left")); 19 | assertEquals(left.right(), Optional.empty()); 20 | 21 | String map = left.map(l -> l + "left", r -> r + "right"); 22 | assertEquals("leftleft", map); 23 | } 24 | 25 | @Test 26 | void testRight() { 27 | Right right = new Right<>("right"); 28 | 29 | assertEquals(right.left(), Optional.empty()); 30 | assertEquals(right.right(), Optional.of("right")); 31 | 32 | String map = right.map(l -> l + "left", r -> r + "right"); 33 | assertEquals("rightright", map); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/test/java/com/comphenix/protocol/wrappers/EnumWrappersTest.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.wrappers; 2 | 3 | import java.util.Map; 4 | import java.util.Map.Entry; 5 | import java.util.Set; 6 | 7 | import com.comphenix.protocol.BukkitInitialization; 8 | import com.comphenix.protocol.reflect.EquivalentConverter; 9 | import com.google.common.collect.Sets; 10 | import org.junit.jupiter.api.BeforeAll; 11 | import org.junit.jupiter.api.Test; 12 | 13 | import static org.junit.jupiter.api.Assertions.assertEquals; 14 | import static org.junit.jupiter.api.Assertions.assertNotNull; 15 | import static org.junit.jupiter.api.Assertions.fail; 16 | 17 | public class EnumWrappersTest { 18 | 19 | private static final Set KNOWN_INVALID = Sets.newHashSet( 20 | "Particle", "WorldBorderAction", "CombatEventType", "TitleAction", "ChatType", "TitleAction" 21 | ); 22 | 23 | @BeforeAll 24 | public static void initializeBukkit() { 25 | BukkitInitialization.initializeAll(); 26 | EnumWrappers.getPlayerInfoActionClass(); // just to initialize the classes and converters 27 | } 28 | 29 | @Test 30 | @SuppressWarnings("unchecked") 31 | public void validateAllEnumFieldsAreWrapped() { 32 | Map, EquivalentConverter> nativeEnums = EnumWrappers.getFromNativeMap(); 33 | for (Entry, EquivalentConverter> entry : nativeEnums.entrySet()) { 34 | for (Object nativeConstant : entry.getKey().getEnumConstants()) { 35 | try { 36 | // yay, generics 37 | EquivalentConverter converter = (EquivalentConverter) entry.getValue(); 38 | 39 | // try to convert the native constant to a wrapper and back 40 | Object wrappedValue = converter.getSpecific(nativeConstant); 41 | assertNotNull(wrappedValue); 42 | 43 | Object unwrappedValue = converter.getGeneric(wrappedValue); 44 | assertNotNull(unwrappedValue); 45 | 46 | assertEquals(nativeConstant, unwrappedValue); 47 | } catch (Exception exception) { 48 | fail(exception); 49 | } 50 | } 51 | } 52 | } 53 | 54 | @Test 55 | public void testValidity() { 56 | assertEquals(EnumWrappers.INVALID, KNOWN_INVALID); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/test/java/com/comphenix/protocol/wrappers/MultiBlockChangeTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. Copyright (C) 2015 dmulloy2 3 | *

4 | * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public 5 | * License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later 6 | * version. 7 | *

8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied 9 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 10 | * details. 11 | *

12 | * You should have received a copy of the GNU General Public License along with this program; if not, write to the Free 13 | * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 14 | */ 15 | package com.comphenix.protocol.wrappers; 16 | 17 | import static org.junit.jupiter.api.Assertions.assertEquals; 18 | 19 | import com.comphenix.protocol.BukkitInitialization; 20 | import com.comphenix.protocol.reflect.EquivalentConverter; 21 | import com.comphenix.protocol.utility.MinecraftReflection; 22 | import org.bukkit.Location; 23 | import org.bukkit.Material; 24 | 25 | /** 26 | * @author dmulloy2 27 | */ 28 | public class MultiBlockChangeTest { 29 | 30 | // @BeforeAll 31 | public static void initializeBukkit() { 32 | BukkitInitialization.initializeAll(); 33 | } 34 | 35 | // @Test 36 | public void test() { 37 | int x = 42; 38 | int y = 64; 39 | int z = 70; 40 | 41 | Location loc = new Location(null, x, y, z); 42 | ChunkCoordIntPair chunk = new ChunkCoordIntPair(x >> 4, z >> 4); 43 | WrappedBlockData blockData = WrappedBlockData.createData(Material.STONE); 44 | MultiBlockChangeInfo info = new MultiBlockChangeInfo(loc, blockData); 45 | 46 | // Make sure the location is correct 47 | assertEquals(loc, info.getLocation(null)); 48 | 49 | MultiBlockChangeInfo[] array = {info, info}; 50 | 51 | EquivalentConverter converter = Converters.array( 52 | MinecraftReflection.getMultiBlockChangeInfoClass(), 53 | MultiBlockChangeInfo.getConverter(chunk) 54 | ); 55 | Object generic = converter.getGeneric(array); 56 | MultiBlockChangeInfo[] back = converter.getSpecific(generic); 57 | 58 | // Make sure our conversions are correct 59 | assertEquals(info.getX(), back[0].getX()); 60 | assertEquals(info.getY(), back[0].getY()); 61 | assertEquals(info.getZ(), back[0].getZ()); 62 | assertEquals(info.getData(), back[0].getData()); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/test/java/com/comphenix/protocol/wrappers/PlayerInfoDataTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. Copyright (C) 2015 dmulloy2 3 | *

4 | * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public 5 | * License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later 6 | * version. 7 | *

8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied 9 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 10 | * details. 11 | *

12 | * You should have received a copy of the GNU General Public License along with this program; if not, write to the Free 13 | * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 14 | */ 15 | package com.comphenix.protocol.wrappers; 16 | 17 | import static org.junit.jupiter.api.Assertions.assertEquals; 18 | 19 | import com.comphenix.protocol.BukkitInitialization; 20 | import com.comphenix.protocol.utility.TestUtils; 21 | import com.comphenix.protocol.wrappers.EnumWrappers.NativeGameMode; 22 | import java.util.UUID; 23 | import org.junit.jupiter.api.BeforeAll; 24 | import org.junit.jupiter.api.Test; 25 | 26 | /** 27 | * @author dmulloy2 28 | */ 29 | public class PlayerInfoDataTest { 30 | 31 | @BeforeAll 32 | public static void initializeBukkit() { 33 | BukkitInitialization.initializeAll(); 34 | } 35 | 36 | @Test 37 | public void test() throws Exception { 38 | WrappedGameProfile profile = new WrappedGameProfile(UUID.randomUUID(), "Name"); 39 | WrappedChatComponent displayName = WrappedChatComponent.fromText("Name's Name"); 40 | 41 | testWriteBack(new PlayerInfoData(profile, 42, NativeGameMode.CREATIVE, displayName)); 42 | testWriteBack(new PlayerInfoData(profile.getUUID(), 42, false, NativeGameMode.CREATIVE, profile, displayName, TestUtils.creteDummyRemoteChatSessionData())); 43 | testWriteBack(new PlayerInfoData(profile.getUUID(), 42, false, NativeGameMode.CREATIVE, null, null, TestUtils.creteDummyRemoteChatSessionData())); 44 | testWriteBack(new PlayerInfoData(profile.getUUID(), 42, true, NativeGameMode.CREATIVE, null, displayName)); 45 | } 46 | 47 | private static void testWriteBack(PlayerInfoData data) { 48 | Object generic = PlayerInfoData.getConverter().getGeneric(data); 49 | PlayerInfoData back = PlayerInfoData.getConverter().getSpecific(generic); 50 | assertEquals(data, back); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/test/java/com/comphenix/protocol/wrappers/WrappedBlockDataTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. Copyright (C) 2015 dmulloy2 3 | *

4 | * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public 5 | * License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later 6 | * version. 7 | *

8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied 9 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 10 | * details. 11 | *

12 | * You should have received a copy of the GNU General Public License along with this program; if not, write to the Free 13 | * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 14 | */ 15 | package com.comphenix.protocol.wrappers; 16 | 17 | import com.comphenix.protocol.BukkitInitialization; 18 | import net.minecraft.world.level.block.state.IBlockData; 19 | import org.bukkit.Material; 20 | import org.bukkit.block.BlockFace; 21 | import org.bukkit.block.data.type.GlassPane; 22 | import org.bukkit.craftbukkit.v1_19_R3.block.data.CraftBlockData; 23 | import org.bukkit.craftbukkit.v1_19_R3.block.impl.CraftStainedGlassPane; 24 | import org.bukkit.craftbukkit.v1_19_R3.util.CraftMagicNumbers; 25 | import org.junit.jupiter.api.BeforeAll; 26 | import org.junit.jupiter.api.Test; 27 | 28 | import static org.junit.jupiter.api.Assertions.assertEquals; 29 | 30 | /** 31 | * @author dmulloy2 32 | */ 33 | 34 | public class WrappedBlockDataTest { 35 | 36 | @BeforeAll 37 | public static void initializeBukkit() { 38 | BukkitInitialization.initializeAll(); 39 | } 40 | 41 | @Test 42 | public void testMaterialCreation() { 43 | Material type = Material.BLUE_WOOL; 44 | 45 | WrappedBlockData wrapper = WrappedBlockData.createData(type); 46 | 47 | assertEquals(wrapper.getType(), type); 48 | //assertEquals(wrapper.getData(), data); 49 | 50 | Object generic = BukkitConverters.getWrappedBlockDataConverter().getGeneric(wrapper); 51 | WrappedBlockData back = BukkitConverters.getWrappedBlockDataConverter().getSpecific(generic); 52 | 53 | assertEquals(wrapper.getType(), back.getType()); 54 | assertEquals(wrapper.getData(), back.getData()); 55 | } 56 | 57 | @Test 58 | public void testDataCreation() { 59 | IBlockData nmsData = CraftMagicNumbers.getBlock(Material.CYAN_STAINED_GLASS_PANE).o(); 60 | GlassPane data = (GlassPane) CraftBlockData.fromData(nmsData); 61 | data.setFace(BlockFace.EAST, true); 62 | 63 | WrappedBlockData wrapper = WrappedBlockData.createData(data); 64 | assertEquals(wrapper.getType(), Material.CYAN_STAINED_GLASS_PANE); 65 | 66 | GlassPane back = new CraftStainedGlassPane((IBlockData) wrapper.getHandle()); 67 | assertEquals(back.hasFace(BlockFace.EAST), data.hasFace(BlockFace.EAST)); 68 | assertEquals(back.hasFace(BlockFace.SOUTH), data.hasFace(BlockFace.SOUTH)); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/test/java/com/comphenix/protocol/wrappers/WrappedChatComponentTest.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.wrappers; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertEquals; 4 | import static org.junit.jupiter.api.Assertions.assertNotNull; 5 | 6 | import com.comphenix.protocol.BukkitInitialization; 7 | import org.junit.jupiter.api.BeforeAll; 8 | import org.junit.jupiter.api.Test; 9 | 10 | public class WrappedChatComponentTest { 11 | 12 | @BeforeAll 13 | public static void initializeBukkit() { 14 | BukkitInitialization.initializeAll(); 15 | } 16 | 17 | @Test 18 | public void testText() { 19 | WrappedChatComponent test = WrappedChatComponent.fromText("Hello."); 20 | String json = test.getJson(); 21 | assertNotNull(json); 22 | 23 | WrappedChatComponent clone = WrappedChatComponent.fromJson(json); 24 | assertEquals(json, clone.getJson()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/test/java/com/comphenix/protocol/wrappers/WrappedParticleTest.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.wrappers; 2 | 3 | import static com.comphenix.protocol.utility.TestUtils.assertItemsEqual; 4 | import static org.junit.jupiter.api.Assertions.assertEquals; 5 | 6 | import com.comphenix.protocol.BukkitInitialization; 7 | import com.comphenix.protocol.PacketType; 8 | import com.comphenix.protocol.events.PacketContainer; 9 | import org.bukkit.Color; 10 | import org.bukkit.Material; 11 | import org.bukkit.Particle; 12 | import org.bukkit.Particle.DustOptions; 13 | import org.bukkit.inventory.ItemStack; 14 | import org.junit.jupiter.api.BeforeAll; 15 | import org.junit.jupiter.api.Test; 16 | 17 | public class WrappedParticleTest { 18 | 19 | @BeforeAll 20 | public static void beforeClass() { 21 | BukkitInitialization.initializeAll(); 22 | } 23 | 24 | @Test 25 | public void testBlockData() { 26 | PacketContainer packet = new PacketContainer(PacketType.Play.Server.WORLD_PARTICLES); 27 | 28 | WrappedParticle before = WrappedParticle.create(Particle.BLOCK_CRACK, 29 | WrappedBlockData.createData(Material.LAPIS_BLOCK)); 30 | packet.getNewParticles().write(0, before); 31 | 32 | WrappedParticle after = packet.getNewParticles().read(0); 33 | assertEquals(before.getParticle(), after.getParticle()); 34 | assertEquals(before.getData(), after.getData()); 35 | } 36 | 37 | @Test 38 | public void testItemStacks() { 39 | PacketContainer packet = new PacketContainer(PacketType.Play.Server.WORLD_PARTICLES); 40 | WrappedParticle before = WrappedParticle.create(Particle.ITEM_CRACK, new ItemStack(Material.FLINT_AND_STEEL)); 41 | packet.getNewParticles().write(0, before); 42 | 43 | WrappedParticle after = packet.getNewParticles().read(0); 44 | assertEquals(before.getParticle(), after.getParticle()); 45 | assertItemsEqual((ItemStack) before.getData(), (ItemStack) after.getData()); 46 | } 47 | 48 | @Test 49 | public void testRedstone() { 50 | PacketContainer packet = new PacketContainer(PacketType.Play.Server.WORLD_PARTICLES); 51 | WrappedParticle before = WrappedParticle.create(Particle.REDSTONE, new DustOptions(Color.BLUE, 1)); 52 | packet.getNewParticles().write(0, before); 53 | 54 | WrappedParticle after = packet.getNewParticles().read(0); 55 | assertEquals(before.getParticle(), after.getParticle()); 56 | 57 | DustOptions beforeDust = (DustOptions) before.getData(); 58 | DustOptions afterDust = (DustOptions) after.getData(); 59 | assertEquals(beforeDust.getColor(), afterDust.getColor()); 60 | assertEquals(beforeDust.getSize(), afterDust.getSize(), 0); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/test/java/com/comphenix/protocol/wrappers/WrappedRegistryTest.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.wrappers; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertEquals; 4 | import static org.junit.jupiter.api.Assertions.assertInstanceOf; 5 | import static org.junit.jupiter.api.Assertions.assertNotEquals; 6 | import static org.junit.jupiter.api.Assertions.assertNotNull; 7 | 8 | import com.comphenix.protocol.BukkitInitialization; 9 | import com.comphenix.protocol.utility.MinecraftReflection; 10 | import org.bukkit.Material; 11 | import org.bukkit.NamespacedKey; 12 | import org.bukkit.Sound; 13 | import org.bukkit.attribute.Attribute; 14 | import org.bukkit.entity.EntityType; 15 | import org.bukkit.potion.PotionEffectType; 16 | import org.junit.jupiter.api.BeforeAll; 17 | import org.junit.jupiter.api.Test; 18 | 19 | public class WrappedRegistryTest { 20 | 21 | @BeforeAll 22 | static void initialize() { 23 | BukkitInitialization.initializeAll(); 24 | } 25 | 26 | @Test 27 | void testRegistries() { 28 | // some randomly selected registries which we can proof to work using the bukkit api 29 | validate(MinecraftReflection.getEntityTypes(), EntityType.WARDEN.getKey()); 30 | validate(MinecraftReflection.getItemClass(), Material.DIAMOND_AXE.getKey()); 31 | validate(MinecraftReflection.getAttributeBase(), Attribute.GENERIC_MAX_HEALTH.getKey()); 32 | validate(MinecraftReflection.getSoundEffectClass(), Sound.ENTITY_WARDEN_SNIFF.getKey()); 33 | validate(MinecraftReflection.getMobEffectListClass(), PotionEffectType.REGENERATION.getKey()); 34 | } 35 | 36 | void validate(Class registryType, NamespacedKey key) { 37 | WrappedRegistry registry = WrappedRegistry.getRegistry(registryType); 38 | assertNotNull(registry); 39 | 40 | Object registryEntry = registry.get(key.getKey()); 41 | assertNotNull(registryEntry); 42 | assertInstanceOf(registryType, registryEntry); 43 | 44 | MinecraftKey entryKey = registry.getKey(registryEntry); 45 | assertEquals(key.getNamespace(), entryKey.getPrefix()); 46 | assertEquals(key.getKey(), entryKey.getKey()); 47 | 48 | int soundId = registry.getId(registryEntry); 49 | assertNotEquals(-1, soundId); 50 | assertEquals(soundId, registry.getId(entryKey)); 51 | } 52 | } 53 | 54 | -------------------------------------------------------------------------------- /src/test/java/com/comphenix/protocol/wrappers/nbt/TileEntityTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. Copyright (C) 2016 dmulloy2 3 | *

4 | * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public 5 | * License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later 6 | * version. 7 | *

8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied 9 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 10 | * details. 11 | *

12 | * You should have received a copy of the GNU General Public License along with this program; if not, write to the Free 13 | * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 14 | */ 15 | package com.comphenix.protocol.wrappers.nbt; 16 | 17 | import com.comphenix.protocol.BukkitInitialization; 18 | import org.bukkit.block.BlockState; 19 | import org.junit.jupiter.api.BeforeAll; 20 | import org.junit.jupiter.api.Test; 21 | 22 | /** 23 | * @author dmulloy2 24 | */ 25 | public class TileEntityTest { 26 | 27 | @BeforeAll 28 | public static void beforeClass() { 29 | BukkitInitialization.initializeAll(); 30 | } 31 | 32 | @Test 33 | public void test() { 34 | // Ensure the read and write methods exist 35 | TileEntityAccessor accessor = new TileEntityAccessor<>(); 36 | accessor.findMethods(null, null); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/test/java/com/comphenix/protocol/wrappers/nbt/io/NbtConfigurationSerializerTest.java: -------------------------------------------------------------------------------- 1 | package com.comphenix.protocol.wrappers.nbt.io; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertEquals; 4 | 5 | import com.comphenix.protocol.BukkitInitialization; 6 | import com.comphenix.protocol.wrappers.nbt.NbtCompound; 7 | import com.comphenix.protocol.wrappers.nbt.NbtFactory; 8 | import org.bukkit.configuration.file.YamlConfiguration; 9 | import org.junit.jupiter.api.BeforeAll; 10 | import org.junit.jupiter.api.Test; 11 | 12 | public class NbtConfigurationSerializerTest { 13 | 14 | @BeforeAll 15 | public static void initializeBukkit() { 16 | BukkitInitialization.initializeAll(); 17 | } 18 | 19 | @Test 20 | public void testSerialization() { 21 | NbtCompound compound = NbtFactory.ofCompound("hello"); 22 | compound.put("age", (short) 30); 23 | compound.put("name", "test"); 24 | compound.put("values", new int[]{1, 2, 3}); 25 | compound.put(NbtFactory.ofList("telephone", "12345678", "81549300")); 26 | 27 | compound.put(NbtFactory.ofList("lists", NbtFactory.ofList("", "a", "a", "b", "c"))); 28 | 29 | YamlConfiguration yaml = new YamlConfiguration(); 30 | NbtConfigurationSerializer.DEFAULT.serialize(compound, yaml); 31 | 32 | NbtCompound result = NbtConfigurationSerializer.DEFAULT.deserializeCompound(yaml, "hello"); 33 | 34 | assertEquals(compound, result); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker: -------------------------------------------------------------------------------- 1 | mock-maker-inline -------------------------------------------------------------------------------- /src/test/resources/tux.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aadnk/ProtocolLib/e77ed96957f0479f68f93a6ac685bdc2e54d279d/src/test/resources/tux.png --------------------------------------------------------------------------------