Compare commits
	
		
			44 commits
		
	
	
		
			3b3bee5209
			...
			25823e4cf2
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 25823e4cf2 | |||
| b2d6cd6d93 | |||
| 
							 | 
						bff89d2fac | ||
| 
							 | 
						acbb438325 | ||
| 
							 | 
						9ea8e9c1b4 | ||
| 
							 | 
						d6a3cb72a4 | ||
| 
							 | 
						64021bb0dc | ||
| 
							 | 
						56e64cde5b | ||
| 
							 | 
						9dec1374d6 | ||
| 
							 | 
						3d803fd4d7 | ||
| 
							 | 
						d69eeb3932 | ||
| 
							 | 
						38d858f5b3 | ||
| 
							 | 
						7ea339a69e | ||
| 
							 | 
						fe6161613f | ||
| 
							 | 
						6af48b98e7 | ||
| 
							 | 
						4682ddd581 | ||
| 
							 | 
						a4ce05886d | ||
| 
							 | 
						49943c9515 | ||
| 
							 | 
						8bc8bfb76a | ||
| 
							 | 
						8478e87a38 | ||
| 
							 | 
						34db96d434 | ||
| 
							 | 
						239f736d9d | ||
| 
							 | 
						e89c025545 | ||
| 
							 | 
						2a15c882db | ||
| 
							 | 
						26cccce9a8 | ||
| 
							 | 
						1fc7a00ec7 | ||
| 
							 | 
						b5481f783d | ||
| 
							 | 
						2e05530f36 | ||
| 
							 | 
						630837fc06 | ||
| 
							 | 
						9032d33058 | ||
| 
							 | 
						a9fc4125da | ||
| 
							 | 
						74871b38bb | ||
| 
							 | 
						5a5c7c8dc1 | ||
| 
							 | 
						d9aae45571 | ||
| 
							 | 
						9e7ecf310e | ||
| 
							 | 
						d7eda34611 | ||
| 
							 | 
						35111c0149 | ||
| 
							 | 
						0868a75617 | ||
| 
							 | 
						53e4d917cd | ||
| 
							 | 
						7298de0bb7 | ||
| 
							 | 
						e181b979a0 | ||
| 
							 | 
						6fba8ea5fd | ||
| 
							 | 
						244145e07a | ||
| 
							 | 
						f819cdb893 | 
					 30 changed files with 958 additions and 186 deletions
				
			
		
							
								
								
									
										47
									
								
								.github/workflows/dev-build-release.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								.github/workflows/dev-build-release.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,47 @@
 | 
				
			||||||
 | 
					name: Build
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					on:
 | 
				
			||||||
 | 
					  workflow_dispatch:
 | 
				
			||||||
 | 
					  push:
 | 
				
			||||||
 | 
					    branches: ['*']
 | 
				
			||||||
 | 
					  pull_request:
 | 
				
			||||||
 | 
					    branches: ['*']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					permissions:
 | 
				
			||||||
 | 
					  contents: write
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					jobs:
 | 
				
			||||||
 | 
					  build:
 | 
				
			||||||
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
 | 
					    env:
 | 
				
			||||||
 | 
					      TYCOONS_REPO_USER: ${{ secrets.EVOKE_REPO_USERNAME }}
 | 
				
			||||||
 | 
					      TYCOONS_REPO_PASS: ${{ secrets.EVOKE_REPO_PASSWORD }}
 | 
				
			||||||
 | 
					    steps:
 | 
				
			||||||
 | 
					      - name: Clone project
 | 
				
			||||||
 | 
					        uses: actions/checkout@v4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      - name: Install JDK 8
 | 
				
			||||||
 | 
					        uses: actions/setup-java@v4
 | 
				
			||||||
 | 
					        with:
 | 
				
			||||||
 | 
					          java-version: '8'
 | 
				
			||||||
 | 
					          distribution: 'temurin'
 | 
				
			||||||
 | 
					          check-latest: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      - name: Setup gradle
 | 
				
			||||||
 | 
					        uses: gradle/actions/setup-gradle@v4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      - name: Run build & publish with Gradle Wrapper
 | 
				
			||||||
 | 
					        if: github.ref == 'refs/heads/master'
 | 
				
			||||||
 | 
					        run: chmod +x ./gradlew && ./gradlew publishAllPublicationsToMavenRepository
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      - name: Run build with Gradle Wrapper
 | 
				
			||||||
 | 
					        if: github.ref != 'refs/heads/master'
 | 
				
			||||||
 | 
					        run: chmod +x ./gradlew && ./gradlew build
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      - name: Create Release
 | 
				
			||||||
 | 
					        if: github.ref != 'refs/heads/master'
 | 
				
			||||||
 | 
					        uses: softprops/action-gh-release@v2
 | 
				
			||||||
 | 
					        with:
 | 
				
			||||||
 | 
					          name: '${{ github.ref_name }}: ${{ github.event.head_commit.message }} (${{ github.sha }})'
 | 
				
			||||||
 | 
					          prerelease: ${{ github.ref != 'refs/heads/master' }}
 | 
				
			||||||
 | 
					          tag_name: ${{ github.ref_name }}-${{ github.sha }}
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,7 @@
 | 
				
			||||||
plugins {
 | 
					plugins {
 | 
				
			||||||
    entitylib.`shadow-conventions`
 | 
					    entitylib.`shadow-conventions`
 | 
				
			||||||
    entitylib.`library-conventions`
 | 
					    entitylib.`library-conventions`
 | 
				
			||||||
 | 
					    `el-version`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
dependencies {
 | 
					dependencies {
 | 
				
			||||||
| 
						 | 
					@ -8,4 +9,23 @@ dependencies {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    compileOnly(libs.bundles.adventure)
 | 
					    compileOnly(libs.bundles.adventure)
 | 
				
			||||||
    compileOnly(libs.packetevents.api)
 | 
					    compileOnly(libs.packetevents.api)
 | 
				
			||||||
 | 
					    testCompileOnly(libs.packetevents.api)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tasks {
 | 
				
			||||||
 | 
					    javadoc {
 | 
				
			||||||
 | 
					        mustRunAfter(generateVersionsFile)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sourcesJar {
 | 
				
			||||||
 | 
					        mustRunAfter(generateVersionsFile)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    withType<JavaCompile> {
 | 
				
			||||||
 | 
					        dependsOn(generateVersionsFile)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    generateVersionsFile {
 | 
				
			||||||
 | 
					        packageName = "me.tofaa.entitylib.utils"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,14 +1,9 @@
 | 
				
			||||||
package me.tofaa.entitylib;
 | 
					package me.tofaa.entitylib;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.github.retrooper.packetevents.PacketEventsAPI;
 | 
					import com.github.retrooper.packetevents.PacketEventsAPI;
 | 
				
			||||||
import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
 | 
					 | 
				
			||||||
import com.github.retrooper.packetevents.protocol.player.UserProfile;
 | 
					 | 
				
			||||||
import com.github.retrooper.packetevents.protocol.world.Location;
 | 
					 | 
				
			||||||
import me.tofaa.entitylib.container.EntityContainer;
 | 
					import me.tofaa.entitylib.container.EntityContainer;
 | 
				
			||||||
import me.tofaa.entitylib.tick.TickContainer;
 | 
					import me.tofaa.entitylib.tick.TickContainer;
 | 
				
			||||||
import me.tofaa.entitylib.wrapper.WrapperEntity;
 | 
					import me.tofaa.entitylib.wrapper.WrapperEntity;
 | 
				
			||||||
import me.tofaa.entitylib.wrapper.WrapperPlayer;
 | 
					 | 
				
			||||||
import org.jetbrains.annotations.ApiStatus;
 | 
					 | 
				
			||||||
import org.jetbrains.annotations.NotNull;
 | 
					import org.jetbrains.annotations.NotNull;
 | 
				
			||||||
import org.jetbrains.annotations.Nullable;
 | 
					import org.jetbrains.annotations.Nullable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -58,4 +53,6 @@ public interface EntityLibAPI<T> {
 | 
				
			||||||
    @NotNull
 | 
					    @NotNull
 | 
				
			||||||
    EntityContainer getDefaultContainer();
 | 
					    EntityContainer getDefaultContainer();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @NotNull
 | 
				
			||||||
 | 
					    UserLocaleProvider getUserLocaleProvider();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26,6 +26,13 @@ public interface Platform<P> {
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    @NotNull EntityUuidProvider getEntityUuidProvider();
 | 
					    @NotNull EntityUuidProvider getEntityUuidProvider();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Gets the provider responsible for retrieving the locale of a user.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return a non-null {@link UserLocaleProvider} instance.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    @NotNull UserLocaleProvider getUserLocaleProvider();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Sets the entityId integer provider. This can be provided by a platform if needed.
 | 
					     * Sets the entityId integer provider. This can be provided by a platform if needed.
 | 
				
			||||||
     * @param provider the entityId integer provider.
 | 
					     * @param provider the entityId integer provider.
 | 
				
			||||||
| 
						 | 
					@ -38,6 +45,12 @@ public interface Platform<P> {
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    void setEntityUuidProvider(@NotNull EntityUuidProvider provider);
 | 
					    void setEntityUuidProvider(@NotNull EntityUuidProvider provider);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Sets the provider responsible for retrieving the locale of a user.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param provider the {@link UserLocaleProvider} instance to be set. Must not be null.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    void setUserLocaleProvider(@NotNull UserLocaleProvider provider);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * @return the logger EntityLib uses internally.
 | 
					     * @return the logger EntityLib uses internally.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,8 @@
 | 
				
			||||||
 | 
					package me.tofaa.entitylib;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.Locale;
 | 
				
			||||||
 | 
					import java.util.UUID;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public interface UserLocaleProvider {
 | 
				
			||||||
 | 
					    Locale locale(UUID user);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -228,6 +228,7 @@ public class EntityMeta implements EntityMetadataProvider {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Annoying java 8 not letting me do OFFSET + amount in the method call so this is a workaround
 | 
					     * Annoying java 8 not letting me do OFFSET + amount in the method call so this is a workaround
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
     * @param value the value to offset
 | 
					     * @param value the value to offset
 | 
				
			||||||
     * @param amount the amount to offset by
 | 
					     * @param amount the amount to offset by
 | 
				
			||||||
     * @return the offset value
 | 
					     * @return the offset value
 | 
				
			||||||
| 
						 | 
					@ -271,12 +272,12 @@ public class EntityMeta implements EntityMetadataProvider {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public List<EntityData> entityData(ClientVersion clientVersion) {
 | 
					    public @NotNull List<EntityData<?>> entityData(@NotNull ClientVersion clientVersion) {
 | 
				
			||||||
        return metadata.getEntries(); // TODO: Atm this is useless cause of the way the api works. Might change in the future
 | 
					        return metadata.getEntries(); // TODO: Atm this is useless cause of the way the api works. Might change in the future
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public List<EntityData> entityData() {
 | 
					    public @NotNull List<EntityData<?>> entityData() {
 | 
				
			||||||
        return metadata.getEntries();
 | 
					        return metadata.getEntries();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,6 @@
 | 
				
			||||||
package me.tofaa.entitylib.meta;
 | 
					package me.tofaa.entitylib.meta;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
 | 
					import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
 | 
				
			||||||
import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
 | 
					 | 
				
			||||||
import me.tofaa.entitylib.meta.display.BlockDisplayMeta;
 | 
					import me.tofaa.entitylib.meta.display.BlockDisplayMeta;
 | 
				
			||||||
import me.tofaa.entitylib.meta.display.ItemDisplayMeta;
 | 
					import me.tofaa.entitylib.meta.display.ItemDisplayMeta;
 | 
				
			||||||
import me.tofaa.entitylib.meta.display.TextDisplayMeta;
 | 
					import me.tofaa.entitylib.meta.display.TextDisplayMeta;
 | 
				
			||||||
| 
						 | 
					@ -50,9 +49,9 @@ final class MetaConverterRegistry {
 | 
				
			||||||
    MetaConverterRegistry() {
 | 
					    MetaConverterRegistry() {
 | 
				
			||||||
        put(ABSTRACT_WIND_CHARGE, SmallFireballMeta.class, SmallFireballMeta::new); // TODO: Verify correctness
 | 
					        put(ABSTRACT_WIND_CHARGE, SmallFireballMeta.class, SmallFireballMeta::new); // TODO: Verify correctness
 | 
				
			||||||
        put(AREA_EFFECT_CLOUD, AreaEffectCloudMeta.class, AreaEffectCloudMeta::new);
 | 
					        put(AREA_EFFECT_CLOUD, AreaEffectCloudMeta.class, AreaEffectCloudMeta::new);
 | 
				
			||||||
 | 
					        put(ALLAY, LivingEntityMeta.class, LivingEntityMeta::new); // TODO: Implement
 | 
				
			||||||
        put(ARMADILLO, ArmadilloMeta.class, ArmadilloMeta::new); // TODO: Verify correctness
 | 
					        put(ARMADILLO, ArmadilloMeta.class, ArmadilloMeta::new); // TODO: Verify correctness
 | 
				
			||||||
        put(ARMOR_STAND, ArmorStandMeta.class, ArmorStandMeta::new);
 | 
					        put(ARMOR_STAND, ArmorStandMeta.class, ArmorStandMeta::new);
 | 
				
			||||||
        put(ALLAY, LivingEntityMeta.class, LivingEntityMeta::new); // TODO: Implement
 | 
					 | 
				
			||||||
        put(ARROW, ArrowMeta.class, ArrowMeta::new);
 | 
					        put(ARROW, ArrowMeta.class, ArrowMeta::new);
 | 
				
			||||||
        put(AXOLOTL, AxolotlMeta.class, AxolotlMeta::new);
 | 
					        put(AXOLOTL, AxolotlMeta.class, AxolotlMeta::new);
 | 
				
			||||||
        put(BAT, BatMeta.class, BatMeta::new);
 | 
					        put(BAT, BatMeta.class, BatMeta::new);
 | 
				
			||||||
| 
						 | 
					@ -69,8 +68,9 @@ final class MetaConverterRegistry {
 | 
				
			||||||
        put(CHEST_MINECART, ChestMinecartMeta.class, ChestMinecartMeta::new);
 | 
					        put(CHEST_MINECART, ChestMinecartMeta.class, ChestMinecartMeta::new);
 | 
				
			||||||
        put(CHICKEN, ChickenMeta.class, ChickenMeta::new);
 | 
					        put(CHICKEN, ChickenMeta.class, ChickenMeta::new);
 | 
				
			||||||
        put(COD, CodMeta.class, CodMeta::new);
 | 
					        put(COD, CodMeta.class, CodMeta::new);
 | 
				
			||||||
        put(COW, CowMeta.class, CowMeta::new);
 | 
					 | 
				
			||||||
        put(COMMAND_BLOCK_MINECART, CommandBlockMinecartMeta.class, CommandBlockMinecartMeta::new);
 | 
					        put(COMMAND_BLOCK_MINECART, CommandBlockMinecartMeta.class, CommandBlockMinecartMeta::new);
 | 
				
			||||||
 | 
					        put(COW, CowMeta.class, CowMeta::new);
 | 
				
			||||||
 | 
					        put(CREAKING, LivingEntityMeta.class, LivingEntityMeta::new); // TODO: Implement
 | 
				
			||||||
        put(CREEPER, CreeperMeta.class, CreeperMeta::new);
 | 
					        put(CREEPER, CreeperMeta.class, CreeperMeta::new);
 | 
				
			||||||
        put(DOLPHIN, DolphinMeta.class, DolphinMeta::new);
 | 
					        put(DOLPHIN, DolphinMeta.class, DolphinMeta::new);
 | 
				
			||||||
        put(DONKEY, DonkeyMeta.class, DonkeyMeta::new);
 | 
					        put(DONKEY, DonkeyMeta.class, DonkeyMeta::new);
 | 
				
			||||||
| 
						 | 
					@ -80,11 +80,12 @@ final class MetaConverterRegistry {
 | 
				
			||||||
        put(ELDER_GUARDIAN, ElderGuardianMeta.class, ElderGuardianMeta::new);
 | 
					        put(ELDER_GUARDIAN, ElderGuardianMeta.class, ElderGuardianMeta::new);
 | 
				
			||||||
        put(END_CRYSTAL, EndCrystalMeta.class, EndCrystalMeta::new);
 | 
					        put(END_CRYSTAL, EndCrystalMeta.class, EndCrystalMeta::new);
 | 
				
			||||||
        put(ENDER_DRAGON, EnderDragonMeta.class, EnderDragonMeta::new);
 | 
					        put(ENDER_DRAGON, EnderDragonMeta.class, EnderDragonMeta::new);
 | 
				
			||||||
 | 
					        put(ENDER_PEARL, ThrownEnderPearlMeta.class, ThrownEnderPearlMeta::new);
 | 
				
			||||||
        put(ENDERMAN, EndermanMeta.class, EndermanMeta::new);
 | 
					        put(ENDERMAN, EndermanMeta.class, EndermanMeta::new);
 | 
				
			||||||
        put(ENDERMITE, EndermiteMeta.class, EndermiteMeta::new);
 | 
					        put(ENDERMITE, EndermiteMeta.class, EndermiteMeta::new);
 | 
				
			||||||
        put(EVOKER, EvokerMeta.class, EvokerMeta::new);
 | 
					        put(EVOKER, EvokerMeta.class, EvokerMeta::new);
 | 
				
			||||||
        put(EYE_OF_ENDER, EyeOfEnderMeta.class, EyeOfEnderMeta::new);
 | 
					 | 
				
			||||||
        put(EVOKER_FANGS, EvokerFangsMeta.class, EvokerFangsMeta::new);
 | 
					        put(EVOKER_FANGS, EvokerFangsMeta.class, EvokerFangsMeta::new);
 | 
				
			||||||
 | 
					        put(EYE_OF_ENDER, EyeOfEnderMeta.class, EyeOfEnderMeta::new);
 | 
				
			||||||
        put(FALLING_BLOCK, FallingBlockMeta.class, FallingBlockMeta::new);
 | 
					        put(FALLING_BLOCK, FallingBlockMeta.class, FallingBlockMeta::new);
 | 
				
			||||||
        put(FIREBALL, LargeFireballMeta.class, LargeFireballMeta::new); // TODO: Verify correctness
 | 
					        put(FIREBALL, LargeFireballMeta.class, LargeFireballMeta::new); // TODO: Verify correctness
 | 
				
			||||||
        put(FIREWORK_ROCKET, FireworkRocketMeta.class, FireworkRocketMeta::new);
 | 
					        put(FIREWORK_ROCKET, FireworkRocketMeta.class, FireworkRocketMeta::new);
 | 
				
			||||||
| 
						 | 
					@ -92,11 +93,13 @@ final class MetaConverterRegistry {
 | 
				
			||||||
        put(FOX, FoxMeta.class, FoxMeta::new);
 | 
					        put(FOX, FoxMeta.class, FoxMeta::new);
 | 
				
			||||||
        put(FROG, FrogMeta.class, FrogMeta::new);
 | 
					        put(FROG, FrogMeta.class, FrogMeta::new);
 | 
				
			||||||
        put(FURNACE_MINECART, FurnaceMinecartMeta.class, FurnaceMinecartMeta::new);
 | 
					        put(FURNACE_MINECART, FurnaceMinecartMeta.class, FurnaceMinecartMeta::new);
 | 
				
			||||||
 | 
					        put(GHAST, GhastMeta.class, GhastMeta::new);
 | 
				
			||||||
        put(GIANT, GiantMeta.class, GiantMeta::new);
 | 
					        put(GIANT, GiantMeta.class, GiantMeta::new);
 | 
				
			||||||
        put(GLOW_ITEM_FRAME, GlowItemFrameMeta.class, GlowItemFrameMeta::new);
 | 
					        put(GLOW_ITEM_FRAME, GlowItemFrameMeta.class, GlowItemFrameMeta::new);
 | 
				
			||||||
        put(GLOW_SQUID, GlowSquidMeta.class, GlowSquidMeta::new);
 | 
					        put(GLOW_SQUID, GlowSquidMeta.class, GlowSquidMeta::new);
 | 
				
			||||||
        put(GOAT, GoatMeta.class, GoatMeta::new);
 | 
					        put(GOAT, GoatMeta.class, GoatMeta::new);
 | 
				
			||||||
        put(GUARDIAN, GuardianMeta.class, GuardianMeta::new);
 | 
					        put(GUARDIAN, GuardianMeta.class, GuardianMeta::new);
 | 
				
			||||||
 | 
					        put(HAPPY_GHAST, GhastMeta.class, GhastMeta::new); // TODO: Implement
 | 
				
			||||||
        put(HOGLIN, HoglinMeta.class, HoglinMeta::new);
 | 
					        put(HOGLIN, HoglinMeta.class, HoglinMeta::new);
 | 
				
			||||||
        put(HOPPER_MINECART, FurnaceMinecartMeta.class, FurnaceMinecartMeta::new);
 | 
					        put(HOPPER_MINECART, FurnaceMinecartMeta.class, FurnaceMinecartMeta::new);
 | 
				
			||||||
        put(HORSE, HorseMeta.class, HorseMeta::new);
 | 
					        put(HORSE, HorseMeta.class, HorseMeta::new);
 | 
				
			||||||
| 
						 | 
					@ -104,35 +107,35 @@ final class MetaConverterRegistry {
 | 
				
			||||||
        put(ILLUSIONER, IllusionerMeta.class, IllusionerMeta::new);
 | 
					        put(ILLUSIONER, IllusionerMeta.class, IllusionerMeta::new);
 | 
				
			||||||
        put(INTERACTION, InteractionMeta.class, InteractionMeta::new);
 | 
					        put(INTERACTION, InteractionMeta.class, InteractionMeta::new);
 | 
				
			||||||
        put(IRON_GOLEM, IronGolemMeta.class, IronGolemMeta::new);
 | 
					        put(IRON_GOLEM, IronGolemMeta.class, IronGolemMeta::new);
 | 
				
			||||||
 | 
					        put(ITEM, ItemEntityMeta.class, ItemEntityMeta::new);
 | 
				
			||||||
        put(ITEM_DISPLAY, ItemDisplayMeta.class, ItemDisplayMeta::new);
 | 
					        put(ITEM_DISPLAY, ItemDisplayMeta.class, ItemDisplayMeta::new);
 | 
				
			||||||
        put(ITEM_FRAME, ItemFrameMeta.class, ItemFrameMeta::new);
 | 
					        put(ITEM_FRAME, ItemFrameMeta.class, ItemFrameMeta::new);
 | 
				
			||||||
        put(ITEM, ItemEntityMeta.class, ItemEntityMeta::new);
 | 
					 | 
				
			||||||
        put(LEASH_KNOT, LeashKnotMeta.class, LeashKnotMeta::new);
 | 
					        put(LEASH_KNOT, LeashKnotMeta.class, LeashKnotMeta::new);
 | 
				
			||||||
        put(LIGHTNING_BOLT, LightningBoltMeta.class, LightningBoltMeta::new);
 | 
					        put(LIGHTNING_BOLT, LightningBoltMeta.class, LightningBoltMeta::new);
 | 
				
			||||||
        put(LLAMA, LlamaMeta.class, LlamaMeta::new);
 | 
					        put(LLAMA, LlamaMeta.class, LlamaMeta::new);
 | 
				
			||||||
        put(LLAMA_SPIT, LlamaSpitMeta.class, LlamaSpitMeta::new);
 | 
					        put(LLAMA_SPIT, LlamaSpitMeta.class, LlamaSpitMeta::new);
 | 
				
			||||||
        put(MAGMA_CUBE, MagmaCubeMeta.class, MagmaCubeMeta::new);
 | 
					        put(MAGMA_CUBE, MagmaCubeMeta.class, MagmaCubeMeta::new);
 | 
				
			||||||
        put(MARKER, MarkerMeta.class, MarkerMeta::new);
 | 
					        put(MARKER, MarkerMeta.class, MarkerMeta::new);
 | 
				
			||||||
 | 
					        put(MOOSHROOM, MooshroomMeta.class, MooshroomMeta::new);
 | 
				
			||||||
        put(MULE, MuleMeta.class, MuleMeta::new);
 | 
					        put(MULE, MuleMeta.class, MuleMeta::new);
 | 
				
			||||||
        put(OCELOT, OcelotMeta.class, OcelotMeta::new);
 | 
					        put(OCELOT, OcelotMeta.class, OcelotMeta::new);
 | 
				
			||||||
        put(PAINTING, PaintingMeta.class, PaintingMeta::new);
 | 
					        put(PAINTING, PaintingMeta.class, PaintingMeta::new);
 | 
				
			||||||
        put(PANDA, PandaMeta.class, PandaMeta::new);
 | 
					        put(PANDA, PandaMeta.class, PandaMeta::new);
 | 
				
			||||||
        put(POTION, ThrownPotionMeta.class, ThrownPotionMeta::new);
 | 
					 | 
				
			||||||
        put(PARROT, ParrotMeta.class, ParrotMeta::new);
 | 
					        put(PARROT, ParrotMeta.class, ParrotMeta::new);
 | 
				
			||||||
 | 
					        put(PHANTOM, PhantomMeta.class, PhantomMeta::new);
 | 
				
			||||||
        put(PIG, PigMeta.class, PigMeta::new);
 | 
					        put(PIG, PigMeta.class, PigMeta::new);
 | 
				
			||||||
        put(PIGLIN, PiglinMeta.class, PiglinMeta::new);
 | 
					        put(PIGLIN, PiglinMeta.class, PiglinMeta::new);
 | 
				
			||||||
        put(PIGLIN_BRUTE, PiglinBruteMeta.class, PiglinBruteMeta::new);
 | 
					        put(PIGLIN_BRUTE, PiglinBruteMeta.class, PiglinBruteMeta::new);
 | 
				
			||||||
        put(PILLAGER, PillagerMeta.class, PillagerMeta::new);
 | 
					        put(PILLAGER, PillagerMeta.class, PillagerMeta::new);
 | 
				
			||||||
        put(PLAYER, PlayerMeta.class, PlayerMeta::new);
 | 
					        put(PLAYER, PlayerMeta.class, PlayerMeta::new);
 | 
				
			||||||
        put(POLAR_BEAR, PolarBearMeta.class, PolarBearMeta::new);
 | 
					        put(POLAR_BEAR, PolarBearMeta.class, PolarBearMeta::new);
 | 
				
			||||||
        put(POTION, ThrownTridentMeta.class, ThrownTridentMeta::new);
 | 
					        put(POTION, ThrownPotionMeta.class, ThrownPotionMeta::new);
 | 
				
			||||||
        put(PRIMED_TNT, PrimedTntMeta.class, PrimedTntMeta::new);
 | 
					        put(PRIMED_TNT, PrimedTntMeta.class, PrimedTntMeta::new);
 | 
				
			||||||
        put(PUFFERFISH, PufferFishMeta.class, PufferFishMeta::new);
 | 
					        put(PUFFERFISH, PufferFishMeta.class, PufferFishMeta::new);
 | 
				
			||||||
        put(RABBIT, RabbitMeta.class, RabbitMeta::new);
 | 
					        put(RABBIT, RabbitMeta.class, RabbitMeta::new);
 | 
				
			||||||
        put(RAVAGER, RavagerMeta.class, RavagerMeta::new);
 | 
					        put(RAVAGER, RavagerMeta.class, RavagerMeta::new);
 | 
				
			||||||
        put(SALMON, SalmonMeta.class, SalmonMeta::new);
 | 
					        put(SALMON, SalmonMeta.class, SalmonMeta::new);
 | 
				
			||||||
        put(SHEEP, SheepMeta.class, SheepMeta::new);
 | 
					        put(SHEEP, SheepMeta.class, SheepMeta::new);
 | 
				
			||||||
        put(SNOWBALL, SnowballMeta.class, SnowballMeta::new);
 | 
					 | 
				
			||||||
        put(SHULKER, ShulkerMeta.class, ShulkerMeta::new);
 | 
					        put(SHULKER, ShulkerMeta.class, ShulkerMeta::new);
 | 
				
			||||||
        put(SHULKER_BULLET, ShulkerBulletMeta.class, ShulkerBulletMeta::new);
 | 
					        put(SHULKER_BULLET, ShulkerBulletMeta.class, ShulkerBulletMeta::new);
 | 
				
			||||||
        put(SILVERFISH, SilverfishMeta.class, SilverfishMeta::new);
 | 
					        put(SILVERFISH, SilverfishMeta.class, SilverfishMeta::new);
 | 
				
			||||||
| 
						 | 
					@ -142,14 +145,16 @@ final class MetaConverterRegistry {
 | 
				
			||||||
        put(SMALL_FIREBALL, SmallFireballMeta.class, SmallFireballMeta::new);
 | 
					        put(SMALL_FIREBALL, SmallFireballMeta.class, SmallFireballMeta::new);
 | 
				
			||||||
        put(SNIFFER, SnifferMeta.class, SnifferMeta::new);
 | 
					        put(SNIFFER, SnifferMeta.class, SnifferMeta::new);
 | 
				
			||||||
        put(SNOW_GOLEM, SnowGolemMeta.class, SnowGolemMeta::new);
 | 
					        put(SNOW_GOLEM, SnowGolemMeta.class, SnowGolemMeta::new);
 | 
				
			||||||
 | 
					        put(SNOWBALL, SnowballMeta.class, SnowballMeta::new);
 | 
				
			||||||
        put(SPAWNER_MINECART, SpawnerMinecartMeta.class, SpawnerMinecartMeta::new);
 | 
					        put(SPAWNER_MINECART, SpawnerMinecartMeta.class, SpawnerMinecartMeta::new);
 | 
				
			||||||
        put(SPIDER, SpiderMeta.class, SpiderMeta::new);
 | 
					        put(SPIDER, SpiderMeta.class, SpiderMeta::new);
 | 
				
			||||||
 | 
					        put(SQUID, SquidMeta.class, SquidMeta::new);
 | 
				
			||||||
        put(STRAY, StrayMeta.class, StrayMeta::new);
 | 
					        put(STRAY, StrayMeta.class, StrayMeta::new);
 | 
				
			||||||
        put(STRIDER, StriderMeta.class, StriderMeta::new);
 | 
					        put(STRIDER, StriderMeta.class, StriderMeta::new);
 | 
				
			||||||
        put(TADPOLE, LivingEntityMeta.class, LivingEntityMeta::new); // TODO: Implement
 | 
					        put(TADPOLE, LivingEntityMeta.class, LivingEntityMeta::new); // TODO: Implement
 | 
				
			||||||
        put(TEXT_DISPLAY, TextDisplayMeta.class, TextDisplayMeta::new);
 | 
					        put(TEXT_DISPLAY, TextDisplayMeta.class, TextDisplayMeta::new);
 | 
				
			||||||
        put(THROWN_EXP_BOTTLE, ThrownExpBottleMeta.class, ThrownExpBottleMeta::new);
 | 
					        put(THROWN_EXP_BOTTLE, ThrownExpBottleMeta.class, ThrownExpBottleMeta::new);
 | 
				
			||||||
        put(ENDER_PEARL, ThrownEnderPearlMeta.class, ThrownEnderPearlMeta::new);
 | 
					        put(TNT, TntMeta.class, TntMeta::new);
 | 
				
			||||||
        put(TNT_MINECART, TntMinecartMeta.class, TntMinecartMeta::new);
 | 
					        put(TNT_MINECART, TntMinecartMeta.class, TntMinecartMeta::new);
 | 
				
			||||||
        put(TRADER_LLAMA, TraderLlamaMeta.class, TraderLlamaMeta::new);
 | 
					        put(TRADER_LLAMA, TraderLlamaMeta.class, TraderLlamaMeta::new);
 | 
				
			||||||
        put(TRIDENT, ThrownTridentMeta.class, ThrownTridentMeta::new);
 | 
					        put(TRIDENT, ThrownTridentMeta.class, ThrownTridentMeta::new);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -19,8 +19,8 @@ public class Metadata {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private final int entityId;
 | 
					    private final int entityId;
 | 
				
			||||||
    private volatile boolean notifyAboutChanges = true;
 | 
					    private volatile boolean notifyAboutChanges = true;
 | 
				
			||||||
    private final HashMap<Byte, EntityData> notNotifiedChanges = new HashMap<>();
 | 
					    private final HashMap<Byte, EntityData<?>> notNotifiedChanges = new HashMap<>();
 | 
				
			||||||
    private final ConcurrentHashMap<Byte, EntityData> metadataMap = new ConcurrentHashMap<>();
 | 
					    private final ConcurrentHashMap<Byte, EntityData<?>> metadataMap = new ConcurrentHashMap<>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public Metadata(int entityId) {
 | 
					    public Metadata(int entityId) {
 | 
				
			||||||
        this.entityId = entityId;
 | 
					        this.entityId = entityId;
 | 
				
			||||||
| 
						 | 
					@ -47,13 +47,13 @@ public class Metadata {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public <T> T getIndex(byte index, @Nullable T defaultValue) {
 | 
					    public <T> T getIndex(byte index, @Nullable T defaultValue) {
 | 
				
			||||||
        EntityData value = this.metadataMap.get(index);
 | 
					        EntityData<?> value = this.metadataMap.get(index);
 | 
				
			||||||
        return value != null ? (T) value.getValue() : defaultValue;
 | 
					        return value != null ? (T) value.getValue() : defaultValue;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public <T> void setIndex(byte index, @NotNull EntityDataType<T> dataType, T value) {
 | 
					    public <T> void setIndex(byte index, @NotNull EntityDataType<T> dataType, T value) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        final EntityData entry = new EntityData(index, dataType, value);
 | 
					        final EntityData<?> entry = new EntityData<>(index, dataType, value);
 | 
				
			||||||
        this.metadataMap.put(index, entry);
 | 
					        this.metadataMap.put(index, entry);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        final Optional<EntityLibAPI<?>> optionalApi = EntityLib.getOptionalApi();
 | 
					        final Optional<EntityLibAPI<?>> optionalApi = EntityLib.getOptionalApi();
 | 
				
			||||||
| 
						 | 
					@ -75,7 +75,7 @@ public class Metadata {
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        List<EntityData> entries = null;
 | 
					        List<EntityData<?>> entries = null;
 | 
				
			||||||
        synchronized (this.notNotifiedChanges) {
 | 
					        synchronized (this.notNotifiedChanges) {
 | 
				
			||||||
            this.notifyAboutChanges = notifyAboutChanges;
 | 
					            this.notifyAboutChanges = notifyAboutChanges;
 | 
				
			||||||
            if (notifyAboutChanges) {
 | 
					            if (notifyAboutChanges) {
 | 
				
			||||||
| 
						 | 
					@ -96,7 +96,7 @@ public class Metadata {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public void setMetaFromPacket(WrapperPlayServerEntityMetadata wrapper) {
 | 
					    public void setMetaFromPacket(WrapperPlayServerEntityMetadata wrapper) {
 | 
				
			||||||
        for (EntityData data : wrapper.getEntityMetadata()) {
 | 
					        for (EntityData<?> data : wrapper.getEntityMetadata()) {
 | 
				
			||||||
            metadataMap.put((byte) data.getIndex(), data);
 | 
					            metadataMap.put((byte) data.getIndex(), data);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -105,7 +105,7 @@ public class Metadata {
 | 
				
			||||||
        return notifyAboutChanges;
 | 
					        return notifyAboutChanges;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @NotNull List<EntityData> getEntries() {
 | 
					    @NotNull List<EntityData<?>> getEntries() {
 | 
				
			||||||
        return Collections.unmodifiableList(new ArrayList<>(metadataMap.values()));
 | 
					        return Collections.unmodifiableList(new ArrayList<>(metadataMap.values()));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,8 @@
 | 
				
			||||||
package me.tofaa.entitylib.meta.display;
 | 
					package me.tofaa.entitylib.meta.display;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.github.retrooper.packetevents.PacketEvents;
 | 
				
			||||||
import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
 | 
					import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
 | 
				
			||||||
 | 
					import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
 | 
				
			||||||
import me.tofaa.entitylib.meta.Metadata;
 | 
					import me.tofaa.entitylib.meta.Metadata;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class BlockDisplayMeta extends AbstractDisplayMeta {
 | 
					public class BlockDisplayMeta extends AbstractDisplayMeta {
 | 
				
			||||||
| 
						 | 
					@ -20,4 +22,11 @@ public class BlockDisplayMeta extends AbstractDisplayMeta {
 | 
				
			||||||
        super.metadata.setIndex(OFFSET, EntityDataTypes.BLOCK_STATE, blockId);
 | 
					        super.metadata.setIndex(OFFSET, EntityDataTypes.BLOCK_STATE, blockId);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public WrappedBlockState getBlockState() {
 | 
				
			||||||
 | 
					        return WrappedBlockState.getByGlobalId(PacketEvents.getAPI().getServerManager().getVersion().toClientVersion(), getBlockId());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void setBlockState(WrappedBlockState blockState) {
 | 
				
			||||||
 | 
					        setBlockId(blockState.getGlobalId());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,10 +1,12 @@
 | 
				
			||||||
package me.tofaa.entitylib.meta.mobs.golem;
 | 
					package me.tofaa.entitylib.meta.mobs.golem;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.github.retrooper.packetevents.protocol.color.DyeColor;
 | 
				
			||||||
import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
 | 
					import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
 | 
				
			||||||
import com.github.retrooper.packetevents.protocol.world.Direction;
 | 
					import com.github.retrooper.packetevents.protocol.world.Direction;
 | 
				
			||||||
import com.github.retrooper.packetevents.util.Vector3i;
 | 
					import com.github.retrooper.packetevents.util.Vector3i;
 | 
				
			||||||
import me.tofaa.entitylib.meta.Metadata;
 | 
					import me.tofaa.entitylib.meta.Metadata;
 | 
				
			||||||
import me.tofaa.entitylib.meta.types.MobMeta;
 | 
					import me.tofaa.entitylib.meta.types.MobMeta;
 | 
				
			||||||
 | 
					import net.kyori.adventure.text.format.NamedTextColor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.Optional;
 | 
					import java.util.Optional;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -13,42 +15,43 @@ public class ShulkerMeta extends MobMeta {
 | 
				
			||||||
    public static final byte OFFSET = MobMeta.MAX_OFFSET;
 | 
					    public static final byte OFFSET = MobMeta.MAX_OFFSET;
 | 
				
			||||||
    public static final byte MAX_OFFSET = OFFSET + 1;
 | 
					    public static final byte MAX_OFFSET = OFFSET + 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static final DyeColor[] DYE_COLORS = DyeColor.values();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public ShulkerMeta(int entityId, Metadata metadata) {
 | 
					    public ShulkerMeta(int entityId, Metadata metadata) {
 | 
				
			||||||
        super(entityId, metadata);
 | 
					        super(entityId, metadata);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public Direction getAttachFace() {
 | 
					    public Direction getAttachFace() {
 | 
				
			||||||
        return super.metadata.getIndex(OFFSET, Direction.DOWN);
 | 
					        return super.metadata.getIndex((byte)16, Direction.DOWN);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public void setAttachFace(Direction value) {
 | 
					    public void setAttachFace(Direction value) {
 | 
				
			||||||
        super.metadata.setIndex(OFFSET, EntityDataTypes.INT, value.ordinal());
 | 
					        super.metadata.setIndex((byte)16, EntityDataTypes.INT, value.ordinal());
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public Optional<Vector3i> getAttachmentPosition() {
 | 
					 | 
				
			||||||
        return super.metadata.getIndex(offset(OFFSET, 1), Optional.empty());
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public void setAttachmentPosition(Vector3i value) {
 | 
					 | 
				
			||||||
        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.OPTIONAL_BLOCK_POSITION, Optional.of(value));
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public byte getShieldHeight() {
 | 
					    public byte getShieldHeight() {
 | 
				
			||||||
        return super.metadata.getIndex(offset(OFFSET, 2), (byte) 0);
 | 
					        return super.metadata.getIndex(offset(OFFSET, 1), (byte) 0);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public void setShieldHeight(byte value) {
 | 
					    public void setShieldHeight(byte value) {
 | 
				
			||||||
        super.metadata.setIndex(offset(OFFSET, 2), EntityDataTypes.BYTE, value);
 | 
					        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.BYTE, value);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public byte getColor() {
 | 
					    public byte getColor() {
 | 
				
			||||||
        return super.metadata.getIndex(offset(OFFSET, 3), (byte) 10);
 | 
					        return super.metadata.getIndex(offset(OFFSET, 2), (byte) 16);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public DyeColor getColorEnum() {
 | 
				
			||||||
 | 
					        return DYE_COLORS[getColor()];
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public void setColor(byte value) {
 | 
					    public void setColor(byte value) {
 | 
				
			||||||
        super.metadata.setIndex(offset(OFFSET, 3), EntityDataTypes.BYTE, value);
 | 
					        super.metadata.setIndex(offset(OFFSET, 2), EntityDataTypes.BYTE, value);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void setColor(DyeColor color) {
 | 
				
			||||||
 | 
					        setColor((byte)color.ordinal());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,16 +1,12 @@
 | 
				
			||||||
package me.tofaa.entitylib.meta.mobs.horse;
 | 
					package me.tofaa.entitylib.meta.mobs.horse;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
 | 
					 | 
				
			||||||
import me.tofaa.entitylib.meta.Metadata;
 | 
					import me.tofaa.entitylib.meta.Metadata;
 | 
				
			||||||
import me.tofaa.entitylib.meta.types.MobMeta;
 | 
					import me.tofaa.entitylib.meta.types.AgeableMeta;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.Optional;
 | 
					public abstract class BaseHorseMeta extends AgeableMeta {
 | 
				
			||||||
import java.util.UUID;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
public abstract class BaseHorseMeta extends MobMeta {
 | 
					    public static final byte OFFSET = AgeableMeta.MAX_OFFSET;
 | 
				
			||||||
 | 
					    public static final byte MAX_OFFSET = OFFSET + 1;
 | 
				
			||||||
    public static final byte OFFSET = MobMeta.MAX_OFFSET;
 | 
					 | 
				
			||||||
    public static final byte MAX_OFFSET = OFFSET + 2;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private final static byte TAMED_BIT = 0x02;
 | 
					    private final static byte TAMED_BIT = 0x02;
 | 
				
			||||||
    private final static byte SADDLED_BIT = 0x04;
 | 
					    private final static byte SADDLED_BIT = 0x04;
 | 
				
			||||||
| 
						 | 
					@ -70,13 +66,4 @@ public abstract class BaseHorseMeta extends MobMeta {
 | 
				
			||||||
    public void setMouthOpen(boolean value) {
 | 
					    public void setMouthOpen(boolean value) {
 | 
				
			||||||
        setMaskBit(OFFSET, MOUTH_OPEN_BIT, value);
 | 
					        setMaskBit(OFFSET, MOUTH_OPEN_BIT, value);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    public Optional<UUID> getOwner() {
 | 
					 | 
				
			||||||
        return super.metadata.getIndex(offset(OFFSET, 1), Optional.empty());
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public void setOwner(UUID value) {
 | 
					 | 
				
			||||||
        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.OPTIONAL_UUID, Optional.of(value));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,11 +1,12 @@
 | 
				
			||||||
package me.tofaa.entitylib.meta.mobs.monster;
 | 
					package me.tofaa.entitylib.meta.mobs.monster;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.github.retrooper.packetevents.PacketEvents;
 | 
				
			||||||
import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
 | 
					import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
 | 
				
			||||||
 | 
					import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
 | 
				
			||||||
import me.tofaa.entitylib.meta.Metadata;
 | 
					import me.tofaa.entitylib.meta.Metadata;
 | 
				
			||||||
import me.tofaa.entitylib.meta.types.MobMeta;
 | 
					import me.tofaa.entitylib.meta.types.MobMeta;
 | 
				
			||||||
import org.jetbrains.annotations.Nullable;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import java.util.Optional;
 | 
					import java.util.Optional;
 | 
				
			||||||
 | 
					import org.jetbrains.annotations.Nullable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class EndermanMeta extends MobMeta {
 | 
					public class EndermanMeta extends MobMeta {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -24,6 +25,20 @@ public class EndermanMeta extends MobMeta {
 | 
				
			||||||
        super.metadata.setIndex(OFFSET, EntityDataTypes.OPTIONAL_INT, Optional.ofNullable(value));
 | 
					        super.metadata.setIndex(OFFSET, EntityDataTypes.OPTIONAL_INT, Optional.ofNullable(value));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public WrappedBlockState getCarriedBlockState() {
 | 
				
			||||||
 | 
					        Integer carriedBlockID = getCarriedBlockID();
 | 
				
			||||||
 | 
					        if (carriedBlockID == null) return null;
 | 
				
			||||||
 | 
					        return WrappedBlockState.getByGlobalId(PacketEvents.getAPI().getServerManager().getVersion().toClientVersion(), carriedBlockID);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void setCarriedBlockState(WrappedBlockState blockState) {
 | 
				
			||||||
 | 
					        if (blockState == null) {
 | 
				
			||||||
 | 
					            setCarriedBlockID(null);
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        setCarriedBlockID(blockState.getGlobalId());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public boolean isScreaming() {
 | 
					    public boolean isScreaming() {
 | 
				
			||||||
        return super.metadata.getIndex(offset(OFFSET, 1), false);
 | 
					        return super.metadata.getIndex(offset(OFFSET, 1), false);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,8 @@
 | 
				
			||||||
package me.tofaa.entitylib.meta.other;
 | 
					package me.tofaa.entitylib.meta.other;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.github.retrooper.packetevents.PacketEvents;
 | 
				
			||||||
import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
 | 
					import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
 | 
				
			||||||
 | 
					import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
 | 
				
			||||||
import com.github.retrooper.packetevents.util.Vector3i;
 | 
					import com.github.retrooper.packetevents.util.Vector3i;
 | 
				
			||||||
import me.tofaa.entitylib.meta.EntityMeta;
 | 
					import me.tofaa.entitylib.meta.EntityMeta;
 | 
				
			||||||
import me.tofaa.entitylib.meta.Metadata;
 | 
					import me.tofaa.entitylib.meta.Metadata;
 | 
				
			||||||
| 
						 | 
					@ -34,6 +36,14 @@ public class FallingBlockMeta extends EntityMeta implements ObjectData {
 | 
				
			||||||
        this.blockStateId = blockStateId;
 | 
					        this.blockStateId = blockStateId;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public WrappedBlockState getBlockState() {
 | 
				
			||||||
 | 
					        return WrappedBlockState.getByGlobalId(PacketEvents.getAPI().getServerManager().getVersion().toClientVersion(), getBlockStateId());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void setBlockState(WrappedBlockState blockState) {
 | 
				
			||||||
 | 
					        setBlockStateId(blockState.getGlobalId());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public int getObjectData() {
 | 
					    public int getObjectData() {
 | 
				
			||||||
        return blockStateId;
 | 
					        return blockStateId;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										42
									
								
								api/src/main/java/me/tofaa/entitylib/meta/other/TntMeta.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								api/src/main/java/me/tofaa/entitylib/meta/other/TntMeta.java
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,42 @@
 | 
				
			||||||
 | 
					package me.tofaa.entitylib.meta.other;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.github.retrooper.packetevents.PacketEvents;
 | 
				
			||||||
 | 
					import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
 | 
				
			||||||
 | 
					import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
 | 
				
			||||||
 | 
					import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
 | 
				
			||||||
 | 
					import me.tofaa.entitylib.meta.EntityMeta;
 | 
				
			||||||
 | 
					import me.tofaa.entitylib.meta.Metadata;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class TntMeta extends EntityMeta {
 | 
				
			||||||
 | 
					    public static final byte OFFSET = EntityMeta.MAX_OFFSET;
 | 
				
			||||||
 | 
					    public static final byte MAX_OFFSET = OFFSET + 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public TntMeta(int entityId, Metadata metadata) {
 | 
				
			||||||
 | 
					        super(entityId, metadata);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public int getFuseTime() {
 | 
				
			||||||
 | 
					        return super.metadata.getIndex(OFFSET, 80);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void setFuseTime(int value) {
 | 
				
			||||||
 | 
					        super.metadata.setIndex(OFFSET, EntityDataTypes.INT, value);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public int getBlockData() {
 | 
				
			||||||
 | 
					        return super.metadata.getIndex(offset(OFFSET, 1), StateTypes.TNT.createBlockState().getGlobalId());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void setBlockData(int blockData) {
 | 
				
			||||||
 | 
					        super.metadata.setIndex(offset(OFFSET, 1), EntityDataTypes.BLOCK_STATE, blockData);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public WrappedBlockState getBlockState() {
 | 
				
			||||||
 | 
					        return WrappedBlockState.getByGlobalId(PacketEvents.getAPI().getServerManager().getVersion().toClientVersion(), getBlockData());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void setBlockState(WrappedBlockState blockState) {
 | 
				
			||||||
 | 
					        setBlockData(blockState.getGlobalId());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										34
									
								
								api/src/main/java/me/tofaa/entitylib/utils/PacketUtil.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								api/src/main/java/me/tofaa/entitylib/utils/PacketUtil.java
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,34 @@
 | 
				
			||||||
 | 
					package me.tofaa.entitylib.utils;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.github.retrooper.packetevents.protocol.entity.data.EntityData;
 | 
				
			||||||
 | 
					import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
 | 
				
			||||||
 | 
					import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityMetadata;
 | 
				
			||||||
 | 
					import me.tofaa.entitylib.EntityLib;
 | 
				
			||||||
 | 
					import java.util.Locale;
 | 
				
			||||||
 | 
					import java.util.Optional;
 | 
				
			||||||
 | 
					import java.util.UUID;
 | 
				
			||||||
 | 
					import net.kyori.adventure.text.Component;
 | 
				
			||||||
 | 
					import net.kyori.adventure.translation.GlobalTranslator;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class PacketUtil {
 | 
				
			||||||
 | 
					    private PacketUtil() {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static void renderPacket(UUID user, WrapperPlayServerEntityMetadata metadata) {
 | 
				
			||||||
 | 
					        Locale locale = EntityLib.getApi().getUserLocaleProvider().locale(user);
 | 
				
			||||||
 | 
					        for (final EntityData<?> entityData : metadata.getEntityMetadata()) {
 | 
				
			||||||
 | 
					            if (entityData.getType() == EntityDataTypes.ADV_COMPONENT) {
 | 
				
			||||||
 | 
					                Component component = (Component) entityData.getValue();
 | 
				
			||||||
 | 
					                final Component rendered = GlobalTranslator.render(component, locale);
 | 
				
			||||||
 | 
					                ((EntityData<Component>) entityData).setValue(rendered);
 | 
				
			||||||
 | 
					            } else if (entityData.getType() == EntityDataTypes.OPTIONAL_ADV_COMPONENT) {
 | 
				
			||||||
 | 
					                final Optional<Component> optional = (Optional<Component>) entityData.getValue();
 | 
				
			||||||
 | 
					                if (optional.isPresent()) {
 | 
				
			||||||
 | 
					                    final Component component = optional.get();
 | 
				
			||||||
 | 
					                    final Component rendered = GlobalTranslator.render(component, locale);
 | 
				
			||||||
 | 
					                    ((EntityData<Optional<Component>>) entityData).setValue(Optional.of(rendered));
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -25,21 +25,57 @@ public class ViewerEngine {
 | 
				
			||||||
    private final Set<WrapperEntity> tracked;
 | 
					    private final Set<WrapperEntity> tracked;
 | 
				
			||||||
    private final ViewerEngineListener listener;
 | 
					    private final ViewerEngineListener listener;
 | 
				
			||||||
    private Executor executor;
 | 
					    private Executor executor;
 | 
				
			||||||
 | 
					    private boolean enabled = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Creates an instance of ViewerEngine
 | 
				
			||||||
 | 
					     * It is recommended to specify explicitly the Executor that should be used.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
    public ViewerEngine() {
 | 
					    public ViewerEngine() {
 | 
				
			||||||
 | 
					        this(Executors.newSingleThreadExecutor());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Creates an instance of ViewerEngine with a specific executor. Depending on your rules one thread might not be enough
 | 
				
			||||||
 | 
					     * @param executor The executor that is used to process entity tracking.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public ViewerEngine(Executor executor) {
 | 
				
			||||||
        this.globalRules = new CopyOnWriteArrayList<>();
 | 
					        this.globalRules = new CopyOnWriteArrayList<>();
 | 
				
			||||||
        this.tracked = Collections.newSetFromMap(new WeakHashMap<>());
 | 
					        this.tracked = Collections.newSetFromMap(new WeakHashMap<>());
 | 
				
			||||||
        this.executor = Executors.newSingleThreadExecutor();
 | 
					        this.executor = executor;
 | 
				
			||||||
        this.listener = new ViewerEngineListener(this);
 | 
					        this.listener = new ViewerEngineListener(this);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Enables this viewer engine.
 | 
				
			||||||
 | 
					     * Registers a viewer engine listener to handle tracking
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
    public void enable() {
 | 
					    public void enable() {
 | 
				
			||||||
 | 
					        if (enabled) {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        enabled = true;
 | 
				
			||||||
        EntityLib.getApi().getPacketEvents().getEventManager().registerListener(listener);
 | 
					        EntityLib.getApi().getPacketEvents().getEventManager().registerListener(listener);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Disables this viewer engine.
 | 
				
			||||||
 | 
					     * Unregisters the viewer engine listener that handles tracking.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
    public void disable() {
 | 
					    public void disable() {
 | 
				
			||||||
 | 
					        if (!enabled) {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        enabled = false;
 | 
				
			||||||
        EntityLib.getApi().getPacketEvents().getEventManager().unregisterListener(listener);
 | 
					        EntityLib.getApi().getPacketEvents().getEventManager().unregisterListener(listener);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Refreshes and updates every tracked by this viewer engine entities viewers to see if they follow the spawning rules.
 | 
				
			||||||
 | 
					     * If they do not they will no longer see the entity;
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
    public void refresh() {
 | 
					    public void refresh() {
 | 
				
			||||||
        getTracked0().forEach(entity -> {
 | 
					        getTracked0().forEach(entity -> {
 | 
				
			||||||
            for (UUID viewer : entity.getViewers()) {
 | 
					            for (UUID viewer : entity.getViewers()) {
 | 
				
			||||||
| 
						 | 
					@ -58,19 +94,40 @@ public class ViewerEngine {
 | 
				
			||||||
        this.executor = executor;
 | 
					        this.executor = executor;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Tells this ViewerEngine to begin tracking a specific {@link WrapperEntity}
 | 
				
			||||||
 | 
					     * @param entity the entity to begin tracking.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
    public void track(@NotNull WrapperEntity entity) {
 | 
					    public void track(@NotNull WrapperEntity entity) {
 | 
				
			||||||
        tracked.add(entity);
 | 
					        tracked.add(entity);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Tells this ViewerEngine to stop tracking a specific {@link WrapperEntity}
 | 
				
			||||||
 | 
					     * @param entity the entity to stop tracking.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public void untrack(@NotNull WrapperEntity entity) {
 | 
				
			||||||
 | 
					        tracked.remove(entity);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public void clearTracked() {
 | 
					    public void clearTracked() {
 | 
				
			||||||
        tracked.clear();
 | 
					        tracked.clear();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Checks if a viewer/user validates every viewer rule handled by this viewer engine or not.
 | 
				
			||||||
 | 
					     * @param user The user to check
 | 
				
			||||||
 | 
					     * @param entity The entity that is getting its own viewer rules checked as well as the global defined one with {@link ViewerEngine#addViewerRule(ViewerRule)}
 | 
				
			||||||
 | 
					     * @return true if the user passed and did not fail any rules, false otherwise
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
    public boolean canSpawnFor(User user, WrapperEntity entity) {
 | 
					    public boolean canSpawnFor(User user, WrapperEntity entity) {
 | 
				
			||||||
        if (entity.getViewerRules().stream().anyMatch(rule -> rule.shouldSee(user))) return true;
 | 
					        if (entity.getViewerRules().stream().anyMatch(rule -> rule.shouldSee(user))) return true;
 | 
				
			||||||
        return globalRules.stream().anyMatch(rule -> rule.shouldSee(user));
 | 
					        return globalRules.stream().anyMatch(rule -> rule.shouldSee(user));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Same as {@link ViewerEngine#canSpawnFor(User, WrapperEntity)} but with UUID instead of User
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
    public boolean canSpawnFor(UUID userId, WrapperEntity entity) {
 | 
					    public boolean canSpawnFor(UUID userId, WrapperEntity entity) {
 | 
				
			||||||
        User user = EntityLib.getApi().getPacketEvents().getProtocolManager().getUser(
 | 
					        User user = EntityLib.getApi().getPacketEvents().getProtocolManager().getUser(
 | 
				
			||||||
                EntityLib.getApi().getPacketEvents().getProtocolManager().getChannel(userId)
 | 
					                EntityLib.getApi().getPacketEvents().getProtocolManager().getChannel(userId)
 | 
				
			||||||
| 
						 | 
					@ -79,6 +136,9 @@ public class ViewerEngine {
 | 
				
			||||||
        return canSpawnFor(user, entity);
 | 
					        return canSpawnFor(user, entity);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @return An unmodifiable view of the entities that are being tracked.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
    public @UnmodifiableView Collection<WrapperEntity> getTracked() {
 | 
					    public @UnmodifiableView Collection<WrapperEntity> getTracked() {
 | 
				
			||||||
        return Collections.unmodifiableCollection(tracked);
 | 
					        return Collections.unmodifiableCollection(tracked);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,31 +5,44 @@ import com.github.retrooper.packetevents.protocol.player.User;
 | 
				
			||||||
import com.github.retrooper.packetevents.protocol.world.Location;
 | 
					import com.github.retrooper.packetevents.protocol.world.Location;
 | 
				
			||||||
import com.github.retrooper.packetevents.util.Vector3d;
 | 
					import com.github.retrooper.packetevents.util.Vector3d;
 | 
				
			||||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
 | 
					import com.github.retrooper.packetevents.wrapper.PacketWrapper;
 | 
				
			||||||
import com.github.retrooper.packetevents.wrapper.play.server.*;
 | 
					import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerBundle;
 | 
				
			||||||
 | 
					import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerDestroyEntities;
 | 
				
			||||||
 | 
					import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityHeadLook;
 | 
				
			||||||
 | 
					import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityMetadata;
 | 
				
			||||||
 | 
					import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityRotation;
 | 
				
			||||||
 | 
					import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityTeleport;
 | 
				
			||||||
 | 
					import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityVelocity;
 | 
				
			||||||
 | 
					import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerSetPassengers;
 | 
				
			||||||
 | 
					import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerSpawnEntity;
 | 
				
			||||||
 | 
					import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerSystemChatMessage;
 | 
				
			||||||
import me.tofaa.entitylib.EntityLib;
 | 
					import me.tofaa.entitylib.EntityLib;
 | 
				
			||||||
import me.tofaa.entitylib.container.EntityContainer;
 | 
					import me.tofaa.entitylib.container.EntityContainer;
 | 
				
			||||||
import me.tofaa.entitylib.meta.EntityMeta;
 | 
					import me.tofaa.entitylib.meta.EntityMeta;
 | 
				
			||||||
import me.tofaa.entitylib.meta.types.ObjectData;
 | 
					import me.tofaa.entitylib.meta.types.ObjectData;
 | 
				
			||||||
import me.tofaa.entitylib.tick.Tickable;
 | 
					import me.tofaa.entitylib.tick.Tickable;
 | 
				
			||||||
 | 
					import me.tofaa.entitylib.utils.PacketUtil;
 | 
				
			||||||
import me.tofaa.entitylib.ve.ViewerRule;
 | 
					import me.tofaa.entitylib.ve.ViewerRule;
 | 
				
			||||||
import me.tofaa.entitylib.wrapper.spawning.SpawnPacketProvider;
 | 
					import me.tofaa.entitylib.wrapper.spawning.SpawnPacketProvider;
 | 
				
			||||||
 | 
					import java.util.Collection;
 | 
				
			||||||
 | 
					import java.util.Collections;
 | 
				
			||||||
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					import java.util.Optional;
 | 
				
			||||||
 | 
					import java.util.Set;
 | 
				
			||||||
 | 
					import java.util.UUID;
 | 
				
			||||||
 | 
					import java.util.concurrent.ConcurrentHashMap;
 | 
				
			||||||
 | 
					import java.util.concurrent.CopyOnWriteArrayList;
 | 
				
			||||||
 | 
					import java.util.function.Consumer;
 | 
				
			||||||
import net.kyori.adventure.text.Component;
 | 
					import net.kyori.adventure.text.Component;
 | 
				
			||||||
import org.jetbrains.annotations.ApiStatus;
 | 
					import org.jetbrains.annotations.ApiStatus;
 | 
				
			||||||
import org.jetbrains.annotations.NotNull;
 | 
					import org.jetbrains.annotations.NotNull;
 | 
				
			||||||
import org.jetbrains.annotations.Nullable;
 | 
					import org.jetbrains.annotations.Nullable;
 | 
				
			||||||
import org.jetbrains.annotations.UnmodifiableView;
 | 
					import org.jetbrains.annotations.UnmodifiableView;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.*;
 | 
					 | 
				
			||||||
import java.util.concurrent.ConcurrentHashMap;
 | 
					 | 
				
			||||||
import java.util.concurrent.CopyOnWriteArrayList;
 | 
					 | 
				
			||||||
import java.util.function.Consumer;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
public class WrapperEntity implements Tickable {
 | 
					public class WrapperEntity implements Tickable {
 | 
				
			||||||
 | 
					 | 
				
			||||||
    private final UUID uuid;
 | 
					    private final UUID uuid;
 | 
				
			||||||
    private final int entityId;
 | 
					    private final int entityId;
 | 
				
			||||||
    private EntityType entityType;
 | 
					    private final EntityType entityType;
 | 
				
			||||||
    private EntityMeta entityMeta;
 | 
					    private final EntityMeta entityMeta;
 | 
				
			||||||
    private boolean ticking;
 | 
					    private boolean ticking;
 | 
				
			||||||
    protected Location location;
 | 
					    protected Location location;
 | 
				
			||||||
    private Location preRidingLocation;
 | 
					    private Location preRidingLocation;
 | 
				
			||||||
| 
						 | 
					@ -62,6 +75,7 @@ public class WrapperEntity implements Tickable {
 | 
				
			||||||
    public WrapperEntity(UUID uuid, EntityType entityType) {
 | 
					    public WrapperEntity(UUID uuid, EntityType entityType) {
 | 
				
			||||||
        this(EntityLib.getPlatform().getEntityIdProvider().provide(uuid, entityType), uuid, entityType);
 | 
					        this(EntityLib.getPlatform().getEntityIdProvider().provide(uuid, entityType), uuid, entityType);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public WrapperEntity(EntityType entityType) {
 | 
					    public WrapperEntity(EntityType entityType) {
 | 
				
			||||||
        this(EntityLib.getPlatform().getEntityUuidProvider().provide(entityType), entityType);
 | 
					        this(EntityLib.getPlatform().getEntityUuidProvider().provide(entityType), entityType);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -72,25 +86,20 @@ public class WrapperEntity implements Tickable {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public boolean spawn(Location location, EntityContainer parent) {
 | 
					    public boolean spawn(Location location, EntityContainer parent) {
 | 
				
			||||||
        if (spawned) return false;
 | 
					        if (spawned) return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.location = location;
 | 
					        this.location = location;
 | 
				
			||||||
        this.spawned = true;
 | 
					        this.spawned = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        sendPacketsToViewers(
 | 
					        sendPacketsToViewers(
 | 
				
			||||||
                new WrapperPlayServerSpawnEntity(
 | 
					                createSpawnPacket(),
 | 
				
			||||||
                        entityId,
 | 
					 | 
				
			||||||
                        Optional.of(this.uuid),
 | 
					 | 
				
			||||||
                        entityType,
 | 
					 | 
				
			||||||
                        location.getPosition(),
 | 
					 | 
				
			||||||
                        location.getPitch(),
 | 
					 | 
				
			||||||
                        location.getYaw(),
 | 
					 | 
				
			||||||
                        location.getYaw(),
 | 
					 | 
				
			||||||
                        getObjectData(),
 | 
					 | 
				
			||||||
                        createVeloPacket()
 | 
					 | 
				
			||||||
                ),
 | 
					 | 
				
			||||||
                entityMeta.createPacket()
 | 
					                entityMeta.createPacket()
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (this instanceof WrapperLivingEntity) {
 | 
					        if (this instanceof WrapperLivingEntity) {
 | 
				
			||||||
            sendPacketsToViewers(((WrapperLivingEntity)this).getAttributes().createPacket());
 | 
					            WrapperLivingEntity wrapperLivingEntity = (WrapperLivingEntity) this;
 | 
				
			||||||
 | 
					            wrapperLivingEntity.createSpawnPackets().forEach(this::sendPacketsToViewers);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.parent = parent;
 | 
					        this.parent = parent;
 | 
				
			||||||
        parent.addEntity(this);
 | 
					        parent.addEntity(this);
 | 
				
			||||||
        return true;
 | 
					        return true;
 | 
				
			||||||
| 
						 | 
					@ -101,7 +110,7 @@ public class WrapperEntity implements Tickable {
 | 
				
			||||||
        return SpawnPacketProvider.GENERAL.provide(this);
 | 
					        return SpawnPacketProvider.GENERAL.provide(this);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public boolean spawn(Location location) {
 | 
					    public boolean spawn(@NotNull Location location) {
 | 
				
			||||||
        return spawn(location, EntityLib.getApi().getDefaultContainer());
 | 
					        return spawn(location, EntityLib.getApi().getDefaultContainer());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -110,6 +119,7 @@ public class WrapperEntity implements Tickable {
 | 
				
			||||||
        if (entityMeta instanceof ObjectData) {
 | 
					        if (entityMeta instanceof ObjectData) {
 | 
				
			||||||
            return ((ObjectData) entityMeta).getObjectData();
 | 
					            return ((ObjectData) entityMeta).getObjectData();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return 0;
 | 
					        return 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -117,6 +127,7 @@ public class WrapperEntity implements Tickable {
 | 
				
			||||||
    public Optional<Vector3d> createVeloPacket() {
 | 
					    public Optional<Vector3d> createVeloPacket() {
 | 
				
			||||||
        Optional<Vector3d> velocity;
 | 
					        Optional<Vector3d> velocity;
 | 
				
			||||||
        double veloX = 0, veloY = 0, veloZ = 0;
 | 
					        double veloX = 0, veloY = 0, veloZ = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (entityMeta instanceof ObjectData) {
 | 
					        if (entityMeta instanceof ObjectData) {
 | 
				
			||||||
            ObjectData od = (ObjectData) entityMeta;
 | 
					            ObjectData od = (ObjectData) entityMeta;
 | 
				
			||||||
            if (od.requiresVelocityPacketAtSpawn()) {
 | 
					            if (od.requiresVelocityPacketAtSpawn()) {
 | 
				
			||||||
| 
						 | 
					@ -126,11 +137,13 @@ public class WrapperEntity implements Tickable {
 | 
				
			||||||
                veloZ = veloPacket.getVelocity().getZ();
 | 
					                veloZ = veloPacket.getVelocity().getZ();
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (veloX == 0 && veloY == 0 && veloZ == 0) {
 | 
					        if (veloX == 0 && veloY == 0 && veloZ == 0) {
 | 
				
			||||||
            velocity = Optional.of(Vector3d.zero());
 | 
					            velocity = Optional.of(Vector3d.zero());
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            velocity = Optional.of(new Vector3d(veloX, veloY, veloZ));
 | 
					            velocity = Optional.of(new Vector3d(veloX, veloY, veloZ));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return velocity;
 | 
					        return velocity;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -141,37 +154,37 @@ public class WrapperEntity implements Tickable {
 | 
				
			||||||
    public void remove() {
 | 
					    public void remove() {
 | 
				
			||||||
        if (parent != null) {
 | 
					        if (parent != null) {
 | 
				
			||||||
            parent.removeEntity(this, true);
 | 
					            parent.removeEntity(this, true);
 | 
				
			||||||
        }
 | 
					        } else {
 | 
				
			||||||
        else {
 | 
					 | 
				
			||||||
            despawn();
 | 
					            despawn();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public void despawn() {
 | 
					    public void despawn() {
 | 
				
			||||||
        if (!spawned) return;
 | 
					        if (!spawned) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        spawned = false;
 | 
					        spawned = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (this instanceof WrapperPlayer) {
 | 
					        if (this instanceof WrapperPlayer) {
 | 
				
			||||||
            WrapperPlayer p = (WrapperPlayer) this;
 | 
					            WrapperPlayer p = (WrapperPlayer) this;
 | 
				
			||||||
            sendPacketsToViewers(p.tabListRemovePacket());
 | 
					            sendPacketsToViewers(p.tabListRemovePacket());
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        sendPacketToViewers(new WrapperPlayServerDestroyEntities(entityId));
 | 
					        sendPacketToViewers(new WrapperPlayServerDestroyEntities(entityId));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public void teleport(@NotNull Location location, boolean onGround) {
 | 
					    public void teleport(@NotNull Location location, boolean onGround) {
 | 
				
			||||||
        if (!spawned) {
 | 
					        if (!spawned) return;
 | 
				
			||||||
            return;
 | 
					
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        this.location = location;
 | 
					        this.location = location;
 | 
				
			||||||
        this.onGround = onGround;
 | 
					        this.onGround = onGround;
 | 
				
			||||||
        sendPacketToViewers(
 | 
					
 | 
				
			||||||
                new WrapperPlayServerEntityTeleport(
 | 
					        sendPacketToViewers(new WrapperPlayServerEntityTeleport(
 | 
				
			||||||
                entityId,
 | 
					                entityId,
 | 
				
			||||||
                location.getPosition(),
 | 
					                location.getPosition(),
 | 
				
			||||||
                location.getYaw(),
 | 
					                location.getYaw(),
 | 
				
			||||||
                location.getPitch(),
 | 
					                location.getPitch(),
 | 
				
			||||||
                onGround
 | 
					                onGround
 | 
				
			||||||
                )
 | 
					        ));
 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public void teleport(@NotNull Location location) {
 | 
					    public void teleport(@NotNull Location location) {
 | 
				
			||||||
| 
						 | 
					@ -180,30 +193,38 @@ public class WrapperEntity implements Tickable {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Adds a viewer to the viewers set. The viewer will receive all packets and be informed of this addition
 | 
					     * Adds a viewer to the viewers set. The viewer will receive all packets and be informed of this addition
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
     * @param uuid the uuid of the user to add
 | 
					     * @param uuid the uuid of the user to add
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public void addViewer(UUID uuid) {
 | 
					    public void addViewer(@NotNull UUID uuid) {
 | 
				
			||||||
        if (!viewers.add(uuid)) {
 | 
					        if (!viewers.add(uuid)) {
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (location == null) {
 | 
					        if (location == null) {
 | 
				
			||||||
            if (EntityLib.getApi().getSettings().isDebugMode()) {
 | 
					            if (EntityLib.getApi().getSettings().isDebugMode()) {
 | 
				
			||||||
                EntityLib.getPlatform().getLogger().warning("Location is null for entity " + entityId + ". Cannot spawn.");
 | 
					                EntityLib.getPlatform().getLogger().warning("Location is null for entity " + entityId + ". Cannot spawn.");
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (spawned) {
 | 
					        if (spawned) {
 | 
				
			||||||
            if (this instanceof WrapperPlayer) {
 | 
					            if (this instanceof WrapperPlayer) {
 | 
				
			||||||
                WrapperPlayer p = (WrapperPlayer) this;
 | 
					                WrapperPlayer p = (WrapperPlayer) this;
 | 
				
			||||||
                sendPacket(uuid, p.tabListPacket());
 | 
					                sendPacket(uuid, p.tabListPacket());
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            sendPacket(uuid, createSpawnPacket());
 | 
					            sendPacket(uuid, createSpawnPacket());
 | 
				
			||||||
            sendPacket(uuid, entityMeta.createPacket());
 | 
					            sendPacket(uuid, entityMeta.createPacket());
 | 
				
			||||||
            sendPacket(uuid, createPassengerPacket());
 | 
					            sendPacket(uuid, createPassengerPacket());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (this instanceof WrapperLivingEntity) {
 | 
					            if (this instanceof WrapperLivingEntity) {
 | 
				
			||||||
                sendPacket(uuid, ((WrapperLivingEntity)this).getAttributes().createPacket());
 | 
					                WrapperLivingEntity wrapperLivingEntity = (WrapperLivingEntity) this;
 | 
				
			||||||
 | 
					                wrapperLivingEntity.createSpawnPackets().forEach(packetWrapper -> sendPacket(uuid, packetWrapper));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (EntityLib.getApi().getSettings().isDebugMode()) {
 | 
					        if (EntityLib.getApi().getSettings().isDebugMode()) {
 | 
				
			||||||
            EntityLib.getPlatform().getLogger().info("Added viewer " + uuid + " to entity " + entityId);
 | 
					            EntityLib.getPlatform().getLogger().info("Added viewer " + uuid + " to entity " + entityId);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					@ -221,7 +242,7 @@ public class WrapperEntity implements Tickable {
 | 
				
			||||||
        sendPacketToViewers(new WrapperPlayServerSystemChatMessage(true, message));
 | 
					        sendPacketToViewers(new WrapperPlayServerSystemChatMessage(true, message));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    protected WrapperPlayServerSpawnEntity createSpawnPacket() {
 | 
					    protected PacketWrapper<?> createSpawnPacket() {
 | 
				
			||||||
        return new WrapperPlayServerSpawnEntity(
 | 
					        return new WrapperPlayServerSpawnEntity(
 | 
				
			||||||
                entityId,
 | 
					                entityId,
 | 
				
			||||||
                Optional.of(this.uuid),
 | 
					                Optional.of(this.uuid),
 | 
				
			||||||
| 
						 | 
					@ -235,62 +256,70 @@ public class WrapperEntity implements Tickable {
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public void addViewer(User user) {
 | 
					    public void addViewer(@NotNull User user) {
 | 
				
			||||||
        addViewer(user.getUUID());
 | 
					        addViewer(user.getUUID());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Adds a viewer silently into the viewers set. The viewer will not receive any packets or be informed of this addition
 | 
					     * Adds a viewer silently into the viewers set. The viewer will not receive any packets or be informed of this addition
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
     * @param uuid the uuid of the user to add
 | 
					     * @param uuid the uuid of the user to add
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public void addViewerSilently(UUID uuid) {
 | 
					    public void addViewerSilently(@NotNull UUID uuid) {
 | 
				
			||||||
        viewers.add(uuid);
 | 
					        viewers.add(uuid);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Adds a viewer silently into the viewers set. The viewer will not receive any packets or be informed of this addition
 | 
					     * Adds a viewer silently into the viewers set. The viewer will not receive any packets or be informed of this addition
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
     * @param user the user to add
 | 
					     * @param user the user to add
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public void addViewerSilently(User user) {
 | 
					    public void addViewerSilently(@NotNull User user) {
 | 
				
			||||||
        addViewerSilently(user.getUUID());
 | 
					        addViewerSilently(user.getUUID());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Removes a viewer from the viewers set of this entity. The viewer will be informed of this removal and will no longer receive any packets
 | 
					     * Removes a viewer from the viewers set of this entity. The viewer will be informed of this removal and will no longer receive any packets
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
     * @param uuid the uuid of the user to remove
 | 
					     * @param uuid the uuid of the user to remove
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public void removeViewer(UUID uuid) {
 | 
					    public void removeViewer(@NotNull UUID uuid) {
 | 
				
			||||||
        if (!viewers.remove(uuid)) {
 | 
					        if (!viewers.remove(uuid)) {
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (this instanceof WrapperPlayer) {
 | 
					        if (this instanceof WrapperPlayer) {
 | 
				
			||||||
            WrapperPlayer p = (WrapperPlayer) this;
 | 
					            WrapperPlayer p = (WrapperPlayer) this;
 | 
				
			||||||
            sendPacket(uuid, p.tabListRemovePacket());
 | 
					            sendPacket(uuid, p.tabListRemovePacket());
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        sendPacket(uuid, new WrapperPlayServerDestroyEntities(entityId));
 | 
					        sendPacket(uuid, new WrapperPlayServerDestroyEntities(entityId));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Removes a viewer from the viewers set of this entity. The viewer will be informed of this removal and will no longer receive any packets
 | 
					     * Removes a viewer from the viewers set of this entity. The viewer will be informed of this removal and will no longer receive any packets
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
     * @param user the user to remove
 | 
					     * @param user the user to remove
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public void removeViewer(User user) {
 | 
					    public void removeViewer(@NotNull User user) {
 | 
				
			||||||
        removeViewer(user.getUUID());
 | 
					        removeViewer(user.getUUID());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * removes a viewer silently into the viewers set. The viewer will not receive any packets or be informed of this removal
 | 
					     * removes a viewer silently into the viewers set. The viewer will not receive any packets or be informed of this removal
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
     * @param uuid of the user to remove
 | 
					     * @param uuid of the user to remove
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public void removeViewerSilently(UUID uuid) {
 | 
					    public void removeViewerSilently(@NotNull UUID uuid) {
 | 
				
			||||||
        viewers.remove(uuid);
 | 
					        viewers.remove(uuid);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * removes a viewer silently into the viewers set. The viewer will not receive any packets or be informed of this removal
 | 
					     * removes a viewer silently into the viewers set. The viewer will not receive any packets or be informed of this removal
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
     * @param user the user to remove
 | 
					     * @param user the user to remove
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public void removeViewerSilently(User user) {
 | 
					    public void removeViewerSilently(@NotNull User user) {
 | 
				
			||||||
        removeViewerSilently(user.getUUID());
 | 
					        removeViewerSilently(user.getUUID());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -298,11 +327,11 @@ public class WrapperEntity implements Tickable {
 | 
				
			||||||
        return onGround;
 | 
					        return onGround;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public Vector3d getVelocity() {
 | 
					    public @NotNull Vector3d getVelocity() {
 | 
				
			||||||
        return velocity;
 | 
					        return velocity;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public void setVelocity(Vector3d velocity) {
 | 
					    public void setVelocity(@NotNull Vector3d velocity) {
 | 
				
			||||||
        this.velocity = velocity;
 | 
					        this.velocity = velocity;
 | 
				
			||||||
        sendPacketToViewers(getVelocityPacket());
 | 
					        sendPacketToViewers(getVelocityPacket());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -331,7 +360,7 @@ public class WrapperEntity implements Tickable {
 | 
				
			||||||
        return entityId;
 | 
					        return entityId;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public EntityMeta getEntityMeta() {
 | 
					    public @NotNull EntityMeta getEntityMeta() {
 | 
				
			||||||
        return entityMeta;
 | 
					        return entityMeta;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -339,12 +368,12 @@ public class WrapperEntity implements Tickable {
 | 
				
			||||||
        return metaClass.cast(entityMeta);
 | 
					        return metaClass.cast(entityMeta);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public <T extends EntityMeta> void consumeEntityMeta(@NotNull Class<T> metaClass, Consumer<T> consumer) {
 | 
					    public <T extends EntityMeta> void consumeEntityMeta(@NotNull Class<T> metaClass, @NotNull Consumer<T> consumer) {
 | 
				
			||||||
        T meta = getEntityMeta(metaClass);
 | 
					        T meta = getEntityMeta(metaClass);
 | 
				
			||||||
        consumer.accept(meta);
 | 
					        consumer.accept(meta);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public void consumeMeta(Consumer<EntityMeta> consumer) {
 | 
					    public void consumeMeta(@NotNull Consumer<EntityMeta> consumer) {
 | 
				
			||||||
        consumer.accept(entityMeta);
 | 
					        consumer.accept(entityMeta);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -358,13 +387,14 @@ public class WrapperEntity implements Tickable {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Returns an unmodifiable set of the passengers of the entity.
 | 
					     * Returns an unmodifiable set of the passengers of the entity.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
     * @return the passengers of the entity
 | 
					     * @return the passengers of the entity
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public Set<Integer> getPassengers() {
 | 
					    public @NotNull Set<Integer> getPassengers() {
 | 
				
			||||||
        return Collections.unmodifiableSet(passengers);
 | 
					        return Collections.unmodifiableSet(passengers);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public WrapperEntity getRiding() {
 | 
					    public @Nullable WrapperEntity getRiding() {
 | 
				
			||||||
        return EntityLib.getApi().getEntity(riding);
 | 
					        return EntityLib.getApi().getEntity(riding);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -433,20 +463,22 @@ public class WrapperEntity implements Tickable {
 | 
				
			||||||
                new WrapperPlayServerEntityRotation(entityId, yaw, pitch, onGround),
 | 
					                new WrapperPlayServerEntityRotation(entityId, yaw, pitch, onGround),
 | 
				
			||||||
                new WrapperPlayServerEntityHeadLook(entityId, yaw)
 | 
					                new WrapperPlayServerEntityHeadLook(entityId, yaw)
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.location.setYaw(yaw);
 | 
					        this.location.setYaw(yaw);
 | 
				
			||||||
        this.location.setPitch(pitch);
 | 
					        this.location.setPitch(pitch);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public void rotateHead(Location location) {
 | 
					    public void rotateHead(@NotNull Location location) {
 | 
				
			||||||
        rotateHead(location.getYaw(), location.getPitch());
 | 
					        rotateHead(location.getYaw(), location.getPitch());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public void rotateHead(WrapperEntity entity) {
 | 
					    public void rotateHead(@NotNull WrapperEntity entity) {
 | 
				
			||||||
        rotateHead(entity.getLocation());
 | 
					        rotateHead(entity.getLocation());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public void refresh() {
 | 
					    public void refresh() {
 | 
				
			||||||
        if (!spawned) return;
 | 
					        if (!spawned) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        sendPacketsToViewers(entityMeta.createPacket(), createPassengerPacket());
 | 
					        sendPacketsToViewers(entityMeta.createPacket(), createPassengerPacket());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -457,13 +489,12 @@ public class WrapperEntity implements Tickable {
 | 
				
			||||||
                sendPacket(uuid, packet);
 | 
					                sendPacket(uuid, packet);
 | 
				
			||||||
                sendPacket(uuid, new WrapperPlayServerBundle());
 | 
					                sendPacket(uuid, new WrapperPlayServerBundle());
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
        }
 | 
					        } else {
 | 
				
			||||||
        else {
 | 
					 | 
				
			||||||
            viewers.forEach(uuid -> sendPacket(uuid, packet));
 | 
					            viewers.forEach(uuid -> sendPacket(uuid, packet));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public void sendPacketsToViewers(PacketWrapper<?>... wrappers) {
 | 
					    public void sendPacketsToViewers(PacketWrapper<?> @NotNull ... wrappers) {
 | 
				
			||||||
        for (PacketWrapper<?> wrapper : wrappers) {
 | 
					        for (PacketWrapper<?> wrapper : wrappers) {
 | 
				
			||||||
            sendPacketToViewers(wrapper);
 | 
					            sendPacketToViewers(wrapper);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					@ -483,13 +514,21 @@ public class WrapperEntity implements Tickable {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private static void sendPacket(UUID user, PacketWrapper<?> wrapper) {
 | 
					    private static void sendPacket(UUID user, PacketWrapper<?> wrapper) {
 | 
				
			||||||
        if (wrapper == null) return;
 | 
					        if (wrapper == null) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Object channel = EntityLib.getApi().getPacketEvents().getProtocolManager().getChannel(user);
 | 
					        Object channel = EntityLib.getApi().getPacketEvents().getProtocolManager().getChannel(user);
 | 
				
			||||||
        if (channel == null) {
 | 
					        if (channel == null) {
 | 
				
			||||||
            if (EntityLib.getApi().getSettings().isDebugMode()) {
 | 
					            if (EntityLib.getApi().getSettings().isDebugMode()) {
 | 
				
			||||||
                EntityLib.getPlatform().getLogger().warning("Failed to send packet to " + user + " because the channel was null. They may be disconnected/not online.");
 | 
					                EntityLib.getPlatform().getLogger().warning("Failed to send packet to " + user + " because the channel was null. They may be disconnected/not online.");
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Special handling for entity metadata packets to support `GlobalTranslator` functionality and component rendering
 | 
				
			||||||
 | 
					        if (wrapper instanceof WrapperPlayServerEntityMetadata) {
 | 
				
			||||||
 | 
					            PacketUtil.renderPacket(user, (WrapperPlayServerEntityMetadata) wrapper);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        EntityLib.getApi().getPacketEvents().getProtocolManager().sendPacket(channel, wrapper);
 | 
					        EntityLib.getApi().getPacketEvents().getProtocolManager().sendPacket(channel, wrapper);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -504,12 +543,14 @@ public class WrapperEntity implements Tickable {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Adds a passenger to the entity. The passenger will be visible to all viewers of the entity.
 | 
					     * Adds a passenger to the entity. The passenger will be visible to all viewers of the entity.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
     * @param passenger the entity id of the passenger
 | 
					     * @param passenger the entity id of the passenger
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public void addPassenger(int passenger) {
 | 
					    public void addPassenger(int passenger) {
 | 
				
			||||||
        if (passengers.contains(passenger)) {
 | 
					        if (passengers.contains(passenger)) {
 | 
				
			||||||
            throw new IllegalArgumentException("Passenger already exists");
 | 
					            throw new IllegalArgumentException("Passenger already exists");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        passengers.add(passenger);
 | 
					        passengers.add(passenger);
 | 
				
			||||||
        sendPacketToViewers(createPassengerPacket());
 | 
					        sendPacketToViewers(createPassengerPacket());
 | 
				
			||||||
        WrapperEntity e = EntityLib.getApi().getEntity(passenger);
 | 
					        WrapperEntity e = EntityLib.getApi().getEntity(passenger);
 | 
				
			||||||
| 
						 | 
					@ -533,9 +574,10 @@ public class WrapperEntity implements Tickable {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Adds multiple passengers to the entity. The passengers will be visible to all viewers of the entity.
 | 
					     * Adds multiple passengers to the entity. The passengers will be visible to all viewers of the entity.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
     * @param passengers the entity ids of the passengers
 | 
					     * @param passengers the entity ids of the passengers
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public void addPassengers(int... passengers) {
 | 
					    public void addPassengers(int @NotNull ... passengers) {
 | 
				
			||||||
        for (int passenger : passengers) {
 | 
					        for (int passenger : passengers) {
 | 
				
			||||||
            addPassenger(passenger);
 | 
					            addPassenger(passenger);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					@ -543,17 +585,19 @@ public class WrapperEntity implements Tickable {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Adds a passenger to the entity. The passenger will be visible to all viewers of the entity.
 | 
					     * Adds a passenger to the entity. The passenger will be visible to all viewers of the entity.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
     * @param passenger the wrapper entity passenger
 | 
					     * @param passenger the wrapper entity passenger
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public void addPassenger(WrapperEntity passenger) {
 | 
					    public void addPassenger(@NotNull WrapperEntity passenger) {
 | 
				
			||||||
        addPassenger(passenger.getEntityId());
 | 
					        addPassenger(passenger.getEntityId());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Adds multiple passengers to the entity. The passengers will be visible to all viewers of the entity.
 | 
					     * Adds multiple passengers to the entity. The passengers will be visible to all viewers of the entity.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
     * @param passengers the wrapper entity passengers
 | 
					     * @param passengers the wrapper entity passengers
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public void addPassengers(WrapperEntity... passengers) {
 | 
					    public void addPassengers(WrapperEntity @NotNull ... passengers) {
 | 
				
			||||||
        for (WrapperEntity passenger : passengers) {
 | 
					        for (WrapperEntity passenger : passengers) {
 | 
				
			||||||
            addPassenger(passenger);
 | 
					            addPassenger(passenger);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					@ -561,12 +605,14 @@ public class WrapperEntity implements Tickable {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Removes a passenger from the entity. The passenger will be removed from the view of all viewers of the entity.
 | 
					     * Removes a passenger from the entity. The passenger will be removed from the view of all viewers of the entity.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
     * @param passenger the entity id of the passenger
 | 
					     * @param passenger the entity id of the passenger
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public void removePassenger(int passenger) {
 | 
					    public void removePassenger(int passenger) {
 | 
				
			||||||
        if (!passengers.contains(passenger)) {
 | 
					        if (!passengers.contains(passenger)) {
 | 
				
			||||||
            throw new IllegalArgumentException("Passenger does not exist");
 | 
					            throw new IllegalArgumentException("Passenger does not exist");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        passengers.remove(passenger);
 | 
					        passengers.remove(passenger);
 | 
				
			||||||
        sendPacketToViewers(createPassengerPacket());
 | 
					        sendPacketToViewers(createPassengerPacket());
 | 
				
			||||||
        WrapperEntity e = EntityLib.getApi().getEntity(passenger);
 | 
					        WrapperEntity e = EntityLib.getApi().getEntity(passenger);
 | 
				
			||||||
| 
						 | 
					@ -588,15 +634,16 @@ public class WrapperEntity implements Tickable {
 | 
				
			||||||
     * @param passenger the passenger wrapper entity
 | 
					     * @param passenger the passenger wrapper entity
 | 
				
			||||||
     * @return true if the entity has the passenger, false otherwise
 | 
					     * @return true if the entity has the passenger, false otherwise
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public boolean hasPassenger(WrapperEntity passenger) {
 | 
					    public boolean hasPassenger(@NotNull WrapperEntity passenger) {
 | 
				
			||||||
        return hasPassenger(passenger.getEntityId());
 | 
					        return hasPassenger(passenger.getEntityId());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Removes multiple passengers from the entity. The passengers will be removed from the view of all viewers of the entity.
 | 
					     * Removes multiple passengers from the entity. The passengers will be removed from the view of all viewers of the entity.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
     * @param passengers the entity ids of the passengers
 | 
					     * @param passengers the entity ids of the passengers
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public void removePassengers(int... passengers) {
 | 
					    public void removePassengers(int @NotNull ... passengers) {
 | 
				
			||||||
        for (int passenger : passengers) {
 | 
					        for (int passenger : passengers) {
 | 
				
			||||||
            removePassenger(passenger);
 | 
					            removePassenger(passenger);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					@ -604,17 +651,19 @@ public class WrapperEntity implements Tickable {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Removes a passenger from the entity. The passenger will be removed from the view of all viewers of the entity.
 | 
					     * Removes a passenger from the entity. The passenger will be removed from the view of all viewers of the entity.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
     * @param passenger the wrapper entity passenger
 | 
					     * @param passenger the wrapper entity passenger
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public void removePassenger(WrapperEntity passenger) {
 | 
					    public void removePassenger(@NotNull WrapperEntity passenger) {
 | 
				
			||||||
        removePassenger(passenger.getEntityId());
 | 
					        removePassenger(passenger.getEntityId());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Removes multiple passengers from the entity. The passengers will be removed from the view of all viewers of the entity.
 | 
					     * Removes multiple passengers from the entity. The passengers will be removed from the view of all viewers of the entity.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
     * @param passengers the wrapper entity passengers
 | 
					     * @param passengers the wrapper entity passengers
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public void removePassengers(WrapperEntity... passengers) {
 | 
					    public void removePassengers(WrapperEntity @NotNull ... passengers) {
 | 
				
			||||||
        for (WrapperEntity passenger : passengers) {
 | 
					        for (WrapperEntity passenger : passengers) {
 | 
				
			||||||
            removePassenger(passenger);
 | 
					            removePassenger(passenger);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					@ -631,11 +680,11 @@ public class WrapperEntity implements Tickable {
 | 
				
			||||||
        return Collections.unmodifiableSet(viewers);
 | 
					        return Collections.unmodifiableSet(viewers);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public boolean hasViewer(UUID uuid) {
 | 
					    public boolean hasViewer(@NotNull UUID uuid) {
 | 
				
			||||||
        return viewers.contains(uuid);
 | 
					        return viewers.contains(uuid);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public boolean hasViewer(User user) {
 | 
					    public boolean hasViewer(@NotNull User user) {
 | 
				
			||||||
        return hasViewer(user.getUUID());
 | 
					        return hasViewer(user.getUUID());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,229 @@
 | 
				
			||||||
 | 
					package me.tofaa.entitylib.wrapper;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
 | 
				
			||||||
 | 
					import com.github.retrooper.packetevents.protocol.potion.PotionType;
 | 
				
			||||||
 | 
					import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityEffect;
 | 
				
			||||||
 | 
					import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerRemoveEntityEffect;
 | 
				
			||||||
 | 
					import org.jetbrains.annotations.NotNull;
 | 
				
			||||||
 | 
					import org.jetbrains.annotations.Nullable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.*;
 | 
				
			||||||
 | 
					import java.util.concurrent.ConcurrentHashMap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class WrapperEntityPotionEffect {
 | 
				
			||||||
 | 
					    private final WrapperLivingEntity entity;
 | 
				
			||||||
 | 
					    private final Map<PotionType, WrapperPotionEffect> effects = new ConcurrentHashMap<>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private boolean notifyChanges = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public WrapperEntityPotionEffect(WrapperLivingEntity entity) {
 | 
				
			||||||
 | 
					        this.entity = entity;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @param type       The type of the potion effect {@link com.github.retrooper.packetevents.protocol.potion.PotionTypes}
 | 
				
			||||||
 | 
					     * @param amplifier  The amplifier of the potion effect. The notchian client displays the number as (amplifier + 1)
 | 
				
			||||||
 | 
					     * @param duration   The duration of the potion effect in ticks, if set to -1 the client will display the effect as infinite
 | 
				
			||||||
 | 
					     * @param ambient    A
 | 
				
			||||||
 | 
					     * @param visible    A
 | 
				
			||||||
 | 
					     * @param showIcons  A
 | 
				
			||||||
 | 
					     * @param factorData The factor data of the potion effect, if hasFactorData is false this will be ignored
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public void addPotionEffect(
 | 
				
			||||||
 | 
					            PotionType type,
 | 
				
			||||||
 | 
					            int amplifier,
 | 
				
			||||||
 | 
					            int duration,
 | 
				
			||||||
 | 
					            boolean ambient,
 | 
				
			||||||
 | 
					            boolean visible,
 | 
				
			||||||
 | 
					            boolean showIcons,
 | 
				
			||||||
 | 
					            @Nullable NBTCompound factorData
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					        WrapperPotionEffect effect = new WrapperPotionEffect(type, amplifier, duration, ambient, visible, showIcons, factorData);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.effects.put(type, effect);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.entity.sendPacketToViewers(createEffectPacket(effect));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @param type       The type of the potion effect {@link com.github.retrooper.packetevents.protocol.potion.PotionTypes}
 | 
				
			||||||
 | 
					     * @param amplifier  The amplifier of the potion effect. The notchian client displays the number as (amplifier + 1)
 | 
				
			||||||
 | 
					     * @param duration   The duration of the potion effect in ticks, if set to -1 the client will display the effect as infinite
 | 
				
			||||||
 | 
					     * @param flags      The bit flags of the potion effect see: <a href="https://minecraft.wiki/w/Java_Edition_protocol#Entity_Effect">https://minecraft.wiki/w/Java_Edition_protocol#Entity_Effect</a>
 | 
				
			||||||
 | 
					     * @param factorData The factor data of the potion effect, if hasFactorData is false this will be ignored
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public void addPotionEffect(
 | 
				
			||||||
 | 
					            PotionType type,
 | 
				
			||||||
 | 
					            int amplifier,
 | 
				
			||||||
 | 
					            int duration,
 | 
				
			||||||
 | 
					            byte flags,
 | 
				
			||||||
 | 
					            @Nullable NBTCompound factorData
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					        BitSet flagsBitSet = BitSet.valueOf(new byte[]{flags});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        boolean ambient = flagsBitSet.get(0);
 | 
				
			||||||
 | 
					        boolean visible = flagsBitSet.get(1);
 | 
				
			||||||
 | 
					        boolean icons = flagsBitSet.get(2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        addPotionEffect(type, amplifier, duration, ambient, visible, icons, factorData);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @param type          The type of the potion effect {@link com.github.retrooper.packetevents.protocol.potion.PotionTypes}
 | 
				
			||||||
 | 
					     * @param amplifier     The amplifier of the potion effect. The notchian client displays the number as (amplifier + 1)
 | 
				
			||||||
 | 
					     * @param duration      The duration of the potion effect in ticks, if set to -1 the client will display the effect as infinite
 | 
				
			||||||
 | 
					     * @param flags         The bit flags of the potion effect see: <a href="https://minecraft.wiki/w/Java_Edition_protocol#Entity_Effect">https://minecraft.wiki/w/Java_Edition_protocol#Entity_Effect</a>
 | 
				
			||||||
 | 
					     * @param hasFactorData Whether the potion effect has factor data
 | 
				
			||||||
 | 
					     * @param factorData    The factor data of the potion effect, if hasFactorData is false this will be ignored
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public void addPotionEffect(
 | 
				
			||||||
 | 
					            PotionType type,
 | 
				
			||||||
 | 
					            int amplifier,
 | 
				
			||||||
 | 
					            int duration,
 | 
				
			||||||
 | 
					            byte flags,
 | 
				
			||||||
 | 
					            boolean hasFactorData,
 | 
				
			||||||
 | 
					            @Nullable NBTCompound factorData
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					        addPotionEffect(type, amplifier, duration, flags, hasFactorData ? factorData : null);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Adds a potion effect to the entity.
 | 
				
			||||||
 | 
					     * EntityLib will not keep track of the potions you give or what you do with them,
 | 
				
			||||||
 | 
					     * this simply sends the packet to the viewers of the entity.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param type      The type of the potion effect {@link com.github.retrooper.packetevents.protocol.potion.PotionTypes}
 | 
				
			||||||
 | 
					     * @param amplifier The amplifier of the potion effect. The notchian client displays the number as (amplifier + 1)
 | 
				
			||||||
 | 
					     * @param duration  The duration of the potion effect in ticks, if set to -1 the client will display the effect as infinite
 | 
				
			||||||
 | 
					     * @param flags     The bit flags of the potion effect see: <a href="https://minecraft.wiki/w/Java_Edition_protocol#Entity_Effect">https://minecraft.wiki/w/Java_Edition_protocol#Entity_Effect</a>
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public void addPotionEffect(
 | 
				
			||||||
 | 
					            PotionType type,
 | 
				
			||||||
 | 
					            int amplifier,
 | 
				
			||||||
 | 
					            int duration,
 | 
				
			||||||
 | 
					            byte flags
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					        addPotionEffect(type, amplifier, duration, flags, false, null);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void removePotionEffect(@NotNull PotionType potionType) {
 | 
				
			||||||
 | 
					        if (this.effects.remove(potionType) != null) {
 | 
				
			||||||
 | 
					            this.entity.sendPacketsToViewers(createRemoveEffectPacket(potionType));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void clearPotionEffects() {
 | 
				
			||||||
 | 
					        new ArrayList<>(this.effects.keySet()).forEach(this::removePotionEffect);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public @NotNull List<WrapperPlayServerEntityEffect> createEffectPackets() {
 | 
				
			||||||
 | 
					        List<WrapperPlayServerEntityEffect> packets = new ArrayList<>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.effects.forEach((potionType, effect) -> packets.add(createEffectPacket(effect)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return packets;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public @NotNull WrapperPlayServerEntityEffect createEffectPacket(@NotNull WrapperPotionEffect effect) {
 | 
				
			||||||
 | 
					        PotionType potionType = effect.getPotionType();
 | 
				
			||||||
 | 
					        int amplifier = effect.getAmplifier();
 | 
				
			||||||
 | 
					        int duration = effect.getDuration();
 | 
				
			||||||
 | 
					        boolean ambient = effect.isAmbient();
 | 
				
			||||||
 | 
					        boolean visible = effect.isVisible();
 | 
				
			||||||
 | 
					        boolean icons = effect.hasIcons();
 | 
				
			||||||
 | 
					        NBTCompound factorData = effect.getFactorData();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        int flags = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        flags |= ambient ? 1 : 0;       // Bit 0 para ambient
 | 
				
			||||||
 | 
					        flags |= visible ? (1 << 1) : 0;  // Bit 1 para visible
 | 
				
			||||||
 | 
					        flags |= icons ? (1 << 2) : 0;    // Bit 2 para icons
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        WrapperPlayServerEntityEffect wrapperPlayServerEntityEffect = new WrapperPlayServerEntityEffect(
 | 
				
			||||||
 | 
					                0,
 | 
				
			||||||
 | 
					                null,
 | 
				
			||||||
 | 
					                0,
 | 
				
			||||||
 | 
					                0,
 | 
				
			||||||
 | 
					                (byte) flags
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        wrapperPlayServerEntityEffect.setEntityId(this.entity.getEntityId());
 | 
				
			||||||
 | 
					        wrapperPlayServerEntityEffect.setPotionType(potionType);
 | 
				
			||||||
 | 
					        wrapperPlayServerEntityEffect.setEffectAmplifier(amplifier);
 | 
				
			||||||
 | 
					        wrapperPlayServerEntityEffect.setEffectDurationTicks(duration);
 | 
				
			||||||
 | 
					        wrapperPlayServerEntityEffect.setFactorData(factorData);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return wrapperPlayServerEntityEffect;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public @NotNull WrapperPlayServerRemoveEntityEffect createRemoveEffectPacket(@NotNull PotionType potionType) {
 | 
				
			||||||
 | 
					        return new WrapperPlayServerRemoveEntityEffect(this.entity.getEntityId(), potionType);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void refresh() {
 | 
				
			||||||
 | 
					        if (notifyChanges) {
 | 
				
			||||||
 | 
					            new ArrayList<>(this.effects.values()).forEach(effect -> {
 | 
				
			||||||
 | 
					                WrapperPlayServerEntityEffect wrapperPlayServerEntityEffect = createEffectPacket(effect);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                this.entity.sendPacketToViewers(wrapperPlayServerEntityEffect);
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public boolean isNotifyingChanges() {
 | 
				
			||||||
 | 
					        return notifyChanges;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void setNotifyChanges(boolean notifyChanges) {
 | 
				
			||||||
 | 
					        this.notifyChanges = notifyChanges;
 | 
				
			||||||
 | 
					        refresh();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static class WrapperPotionEffect {
 | 
				
			||||||
 | 
					        private final PotionType potionType;
 | 
				
			||||||
 | 
					        private final int amplifier;
 | 
				
			||||||
 | 
					        private final int duration;
 | 
				
			||||||
 | 
					        private final boolean ambient;
 | 
				
			||||||
 | 
					        private final boolean visible;
 | 
				
			||||||
 | 
					        private final boolean icons;
 | 
				
			||||||
 | 
					        private final @Nullable NBTCompound factorData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private WrapperPotionEffect(PotionType potionType, int amplifier, int duration, boolean ambient, boolean visible, boolean icons, @Nullable NBTCompound factorData) {
 | 
				
			||||||
 | 
					            this.potionType = potionType;
 | 
				
			||||||
 | 
					            this.amplifier = amplifier;
 | 
				
			||||||
 | 
					            this.duration = duration;
 | 
				
			||||||
 | 
					            this.ambient = ambient;
 | 
				
			||||||
 | 
					            this.visible = visible;
 | 
				
			||||||
 | 
					            this.icons = icons;
 | 
				
			||||||
 | 
					            this.factorData = factorData;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public PotionType getPotionType() {
 | 
				
			||||||
 | 
					            return potionType;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public int getAmplifier() {
 | 
				
			||||||
 | 
					            return amplifier;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public int getDuration() {
 | 
				
			||||||
 | 
					            return duration;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public boolean isAmbient() {
 | 
				
			||||||
 | 
					            return ambient;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public boolean isVisible() {
 | 
				
			||||||
 | 
					            return visible;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public boolean hasIcons() {
 | 
				
			||||||
 | 
					            return icons;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public @Nullable NBTCompound getFactorData() {
 | 
				
			||||||
 | 
					            return factorData;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,25 +1,37 @@
 | 
				
			||||||
package me.tofaa.entitylib.wrapper;
 | 
					package me.tofaa.entitylib.wrapper;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.github.retrooper.packetevents.manager.server.ServerVersion;
 | 
				
			||||||
import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
 | 
					import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
 | 
				
			||||||
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
 | 
					import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
 | 
				
			||||||
import com.github.retrooper.packetevents.protocol.potion.PotionType;
 | 
					import com.github.retrooper.packetevents.protocol.potion.PotionType;
 | 
				
			||||||
 | 
					import com.github.retrooper.packetevents.protocol.world.Location;
 | 
				
			||||||
 | 
					import com.github.retrooper.packetevents.wrapper.PacketWrapper;
 | 
				
			||||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityAnimation;
 | 
					import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityAnimation;
 | 
				
			||||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityEffect;
 | 
					import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityEffect;
 | 
				
			||||||
 | 
					import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityEquipment;
 | 
				
			||||||
 | 
					import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerHurtAnimation;
 | 
				
			||||||
import me.tofaa.entitylib.EntityLib;
 | 
					import me.tofaa.entitylib.EntityLib;
 | 
				
			||||||
 | 
					import me.tofaa.entitylib.container.EntityContainer;
 | 
				
			||||||
import me.tofaa.entitylib.meta.EntityMeta;
 | 
					import me.tofaa.entitylib.meta.EntityMeta;
 | 
				
			||||||
 | 
					import me.tofaa.entitylib.utils.VersionUtil;
 | 
				
			||||||
 | 
					import org.jetbrains.annotations.NotNull;
 | 
				
			||||||
import org.jetbrains.annotations.Nullable;
 | 
					import org.jetbrains.annotations.Nullable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.ArrayList;
 | 
				
			||||||
 | 
					import java.util.List;
 | 
				
			||||||
import java.util.UUID;
 | 
					import java.util.UUID;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class WrapperLivingEntity extends WrapperEntity {
 | 
					public class WrapperLivingEntity extends WrapperEntity {
 | 
				
			||||||
 | 
					 | 
				
			||||||
    private final WrapperEntityEquipment equipment;
 | 
					    private final WrapperEntityEquipment equipment;
 | 
				
			||||||
    private final WrapperEntityAttributes attributes;
 | 
					    private final WrapperEntityAttributes attributes;
 | 
				
			||||||
 | 
					    private final WrapperEntityPotionEffect potionEffect;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public WrapperLivingEntity(int entityId, UUID uuid, EntityType entityType, EntityMeta entityMeta) {
 | 
					    public WrapperLivingEntity(int entityId, UUID uuid, EntityType entityType, EntityMeta entityMeta) {
 | 
				
			||||||
        super(entityId, uuid, entityType, entityMeta);
 | 
					        super(entityId, uuid, entityType, entityMeta);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.equipment = new WrapperEntityEquipment(this);
 | 
					        this.equipment = new WrapperEntityEquipment(this);
 | 
				
			||||||
        this.attributes = new WrapperEntityAttributes(this);
 | 
					        this.attributes = new WrapperEntityAttributes(this);
 | 
				
			||||||
 | 
					        this.potionEffect = new WrapperEntityPotionEffect(this);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public WrapperLivingEntity(int entityId, UUID uuid, EntityType entityType) {
 | 
					    public WrapperLivingEntity(int entityId, UUID uuid, EntityType entityType) {
 | 
				
			||||||
| 
						 | 
					@ -33,6 +45,7 @@ public class WrapperLivingEntity extends WrapperEntity{
 | 
				
			||||||
    public WrapperLivingEntity(UUID uuid, EntityType entityType) {
 | 
					    public WrapperLivingEntity(UUID uuid, EntityType entityType) {
 | 
				
			||||||
        this(EntityLib.getPlatform().getEntityIdProvider().provide(uuid, entityType), uuid, entityType);
 | 
					        this(EntityLib.getPlatform().getEntityIdProvider().provide(uuid, entityType), uuid, entityType);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public WrapperLivingEntity(EntityType entityType) {
 | 
					    public WrapperLivingEntity(EntityType entityType) {
 | 
				
			||||||
        this(EntityLib.getPlatform().getEntityUuidProvider().provide(entityType), entityType);
 | 
					        this(EntityLib.getPlatform().getEntityUuidProvider().provide(entityType), entityType);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -40,24 +53,44 @@ public class WrapperLivingEntity extends WrapperEntity{
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void refresh() {
 | 
					    public void refresh() {
 | 
				
			||||||
        super.refresh();
 | 
					        super.refresh();
 | 
				
			||||||
        equipment.refresh();
 | 
					
 | 
				
			||||||
        attributes.refresh();
 | 
					        this.equipment.refresh();
 | 
				
			||||||
 | 
					        this.potionEffect.refresh();
 | 
				
			||||||
 | 
					        this.attributes.refresh();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public WrapperEntityAttributes getAttributes() {
 | 
					    public WrapperEntityAttributes getAttributes() {
 | 
				
			||||||
        return attributes;
 | 
					        return this.attributes;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public WrapperEntityEquipment getEquipment() {
 | 
				
			||||||
 | 
					        return this.equipment;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public WrapperEntityPotionEffect getPotionEffect() {
 | 
				
			||||||
 | 
					        return this.potionEffect;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public @NotNull List<PacketWrapper<?>> createSpawnPackets() {
 | 
				
			||||||
 | 
					        List<PacketWrapper<?>> packets = new ArrayList<>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        packets.add(getAttributes().createPacket());
 | 
				
			||||||
 | 
					        packets.add(getEquipment().createPacket());
 | 
				
			||||||
 | 
					        packets.addAll(getPotionEffect().createEffectPackets());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return packets;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Adds a potion effect to the entity.
 | 
					     * Adds a potion effect to the entity.
 | 
				
			||||||
     * EntityLib will not keep track of the potions you give or what you do with them,
 | 
					     * EntityLib will not keep track of the potions you give or what you do with them,
 | 
				
			||||||
     * this simply sends the packet to the viewers of the entity.
 | 
					     * this simply sends the packet to the viewers of the entity.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
     * @param type          The type of the potion effect {@link com.github.retrooper.packetevents.protocol.potion.PotionTypes}
 | 
					     * @param type          The type of the potion effect {@link com.github.retrooper.packetevents.protocol.potion.PotionTypes}
 | 
				
			||||||
     * @param amplifier     The amplifier of the potion effect. The notchian client displays the number as (amplifier + 1)
 | 
					     * @param amplifier     The amplifier of the potion effect. The notchian client displays the number as (amplifier + 1)
 | 
				
			||||||
     * @param duration      The duration of the potion effect in ticks, if set to -1 the client will display the effect as infinite
 | 
					     * @param duration      The duration of the potion effect in ticks, if set to -1 the client will display the effect as infinite
 | 
				
			||||||
     * @param flags The bit flags of the potion effect see: https://wiki.vg/Protocol#Entity_Effect
 | 
					     * @param flags         The bit flags of the potion effect see:
 | 
				
			||||||
 | 
					     *                      <a href="https://minecraft.wiki/w/Java_Edition_protocol#Entity_Effect">https://minecraft.wiki/w/Java_Edition_protocol#Entity_Effect</a>
 | 
				
			||||||
     * @param hasFactorData Whether the potion effect has factor data
 | 
					     * @param hasFactorData Whether the potion effect has factor data
 | 
				
			||||||
     * @param factorData    The factor data of the potion effect, if hasFactorData is false this will be ignored
 | 
					     * @param factorData    The factor data of the potion effect, if hasFactorData is false this will be ignored
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
| 
						 | 
					@ -69,25 +102,19 @@ public class WrapperLivingEntity extends WrapperEntity{
 | 
				
			||||||
            boolean hasFactorData,
 | 
					            boolean hasFactorData,
 | 
				
			||||||
            @Nullable NBTCompound factorData
 | 
					            @Nullable NBTCompound factorData
 | 
				
			||||||
    ) {
 | 
					    ) {
 | 
				
			||||||
        sendPacketToViewers(
 | 
					        this.potionEffect.addPotionEffect(type, amplifier, duration, flags, hasFactorData, factorData);
 | 
				
			||||||
                new WrapperPlayServerEntityEffect(
 | 
					 | 
				
			||||||
                        getEntityId(),
 | 
					 | 
				
			||||||
                        type,
 | 
					 | 
				
			||||||
                        amplifier,
 | 
					 | 
				
			||||||
                        duration,
 | 
					 | 
				
			||||||
                        flags
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Adds a potion effect to the entity.
 | 
					     * Adds a potion effect to the entity.
 | 
				
			||||||
     * EntityLib will not keep track of the potions you give or what you do with them,
 | 
					     * EntityLib will not keep track of the potions you give or what you do with them,
 | 
				
			||||||
     * this simply sends the packet to the viewers of the entity.
 | 
					     * this simply sends the packet to the viewers of the entity.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
     * @param type      The type of the potion effect {@link com.github.retrooper.packetevents.protocol.potion.PotionTypes}
 | 
					     * @param type      The type of the potion effect {@link com.github.retrooper.packetevents.protocol.potion.PotionTypes}
 | 
				
			||||||
     * @param amplifier The amplifier of the potion effect. The notchian client displays the number as (amplifier + 1)
 | 
					     * @param amplifier The amplifier of the potion effect. The notchian client displays the number as (amplifier + 1)
 | 
				
			||||||
     * @param duration  The duration of the potion effect in ticks, if set to -1 the client will display the effect as infinite
 | 
					     * @param duration  The duration of the potion effect in ticks, if set to -1 the client will display the effect as infinite
 | 
				
			||||||
     * @param flags The bit flags of the potion effect see: https://wiki.vg/Protocol#Entity_Effect
 | 
					     * @param flags     The bit flags of the potion effect see:
 | 
				
			||||||
 | 
					     *                  <a href="https://minecraft.wiki/w/Java_Edition_protocol#Entity_Effect">https://minecraft.wiki/w/Java_Edition_protocol#Entity_Effect</a>
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public void addPotionEffect(
 | 
					    public void addPotionEffect(
 | 
				
			||||||
            PotionType type,
 | 
					            PotionType type,
 | 
				
			||||||
| 
						 | 
					@ -110,7 +137,30 @@ public class WrapperLivingEntity extends WrapperEntity{
 | 
				
			||||||
        sendAnimation(WrapperPlayServerEntityAnimation.EntityAnimationType.WAKE_UP);
 | 
					        sendAnimation(WrapperPlayServerEntityAnimation.EntityAnimationType.WAKE_UP);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Plays the hurt animation of the entity.
 | 
				
			||||||
 | 
					     * This method is deprecated and should use {@link #playHurtAnimation(int)} instead.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    @Deprecated
 | 
				
			||||||
    public void playHurtAnimation() {
 | 
					    public void playHurtAnimation() {
 | 
				
			||||||
 | 
					        playHurtAnimation(0);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Plays the hurt animation of the entity.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param yaw The yaw of the entity when the hurt animation is played.
 | 
				
			||||||
 | 
					     *            For any entity other than a player it's safe to simply put 0, as it's not used.
 | 
				
			||||||
 | 
					     *            The yaw is only used on 1.19.4+.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public void playHurtAnimation(int yaw) {
 | 
				
			||||||
 | 
					        // 1.19.4+ uses a different packet for hurt animation than previous versions
 | 
				
			||||||
 | 
					        if (VersionUtil.isNewerThan(ServerVersion.V_1_19_4)) {
 | 
				
			||||||
 | 
					            sendPacketToViewers(
 | 
				
			||||||
 | 
					                    new WrapperPlayServerHurtAnimation(getEntityId(), yaw)
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        sendAnimation(WrapperPlayServerEntityAnimation.EntityAnimationType.HURT);
 | 
					        sendAnimation(WrapperPlayServerEntityAnimation.EntityAnimationType.HURT);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -127,8 +177,4 @@ public class WrapperLivingEntity extends WrapperEntity{
 | 
				
			||||||
                new WrapperPlayServerEntityAnimation(getEntityId(), type)
 | 
					                new WrapperPlayServerEntityAnimation(getEntityId(), type)
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    public WrapperEntityEquipment getEquipment() {
 | 
					 | 
				
			||||||
        return equipment;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,16 +1,24 @@
 | 
				
			||||||
package me.tofaa.entitylib.wrapper;
 | 
					package me.tofaa.entitylib.wrapper;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.github.retrooper.packetevents.manager.server.ServerVersion;
 | 
				
			||||||
import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
 | 
					import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
 | 
				
			||||||
import com.github.retrooper.packetevents.protocol.player.*;
 | 
					import com.github.retrooper.packetevents.protocol.player.GameMode;
 | 
				
			||||||
import com.github.retrooper.packetevents.protocol.world.Location;
 | 
					import com.github.retrooper.packetevents.protocol.player.TextureProperty;
 | 
				
			||||||
import com.github.retrooper.packetevents.util.Vector3d;
 | 
					import com.github.retrooper.packetevents.protocol.player.UserProfile;
 | 
				
			||||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
 | 
					import com.github.retrooper.packetevents.wrapper.PacketWrapper;
 | 
				
			||||||
import com.github.retrooper.packetevents.wrapper.play.server.*;
 | 
					import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerDestroyEntities;
 | 
				
			||||||
 | 
					import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityHeadLook;
 | 
				
			||||||
 | 
					import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityRotation;
 | 
				
			||||||
 | 
					import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerPlayerInfoRemove;
 | 
				
			||||||
 | 
					import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerPlayerInfoUpdate;
 | 
				
			||||||
 | 
					import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerSpawnPlayer;
 | 
				
			||||||
import me.tofaa.entitylib.EntityLib;
 | 
					import me.tofaa.entitylib.EntityLib;
 | 
				
			||||||
import me.tofaa.entitylib.meta.EntityMeta;
 | 
					import me.tofaa.entitylib.meta.EntityMeta;
 | 
				
			||||||
 | 
					import java.util.EnumSet;
 | 
				
			||||||
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					import java.util.UUID;
 | 
				
			||||||
import net.kyori.adventure.text.Component;
 | 
					import net.kyori.adventure.text.Component;
 | 
				
			||||||
 | 
					import org.jetbrains.annotations.NotNull;
 | 
				
			||||||
import java.util.*;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class WrapperPlayer extends WrapperLivingEntity {
 | 
					public class WrapperPlayer extends WrapperLivingEntity {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -25,6 +33,27 @@ public class WrapperPlayer extends WrapperLivingEntity {
 | 
				
			||||||
        this.profile = profile;
 | 
					        this.profile = profile;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    protected PacketWrapper<?> createSpawnPacket() {
 | 
				
			||||||
 | 
					        if (EntityLib.getApi().getPacketEvents().getServerManager().getVersion().isOlderThanOrEquals(ServerVersion.V_1_20_1)) {
 | 
				
			||||||
 | 
					            return new WrapperPlayServerSpawnPlayer(
 | 
				
			||||||
 | 
					                    getEntityId(),
 | 
				
			||||||
 | 
					                    profile.getUUID(),
 | 
				
			||||||
 | 
					                    getLocation(),
 | 
				
			||||||
 | 
					                    getEntityMeta().entityData()
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return super.createSpawnPacket();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public @NotNull List<PacketWrapper<?>> createSpawnPackets() {
 | 
				
			||||||
 | 
					        final List<PacketWrapper<?>> packets = super.createSpawnPackets();
 | 
				
			||||||
 | 
					        packets.add(new WrapperPlayServerEntityRotation(getEntityId(), getYaw(), getPitch(), isOnGround()));
 | 
				
			||||||
 | 
					        packets.add(new WrapperPlayServerEntityHeadLook(getEntityId(), getYaw()));
 | 
				
			||||||
 | 
					        return packets;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public WrapperPlayServerPlayerInfoUpdate tabListPacket() {
 | 
					    public WrapperPlayServerPlayerInfoUpdate tabListPacket() {
 | 
				
			||||||
        EnumSet<WrapperPlayServerPlayerInfoUpdate.Action> actions = EnumSet.of(
 | 
					        EnumSet<WrapperPlayServerPlayerInfoUpdate.Action> actions = EnumSet.of(
 | 
				
			||||||
                WrapperPlayServerPlayerInfoUpdate.Action.ADD_PLAYER,
 | 
					                WrapperPlayServerPlayerInfoUpdate.Action.ADD_PLAYER,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -41,6 +41,7 @@ abstract class ELVersionTask : DefaultTask() {
 | 
				
			||||||
             */
 | 
					             */
 | 
				
			||||||
            package $packageName;
 | 
					            package $packageName;
 | 
				
			||||||
           
 | 
					           
 | 
				
			||||||
 | 
					            import java.text.DateFormat;
 | 
				
			||||||
            import com.github.retrooper.packetevents.util.PEVersion;
 | 
					            import com.github.retrooper.packetevents.util.PEVersion;
 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
            public final class ELVersions {
 | 
					            public final class ELVersions {
 | 
				
			||||||
| 
						 | 
					@ -52,6 +53,29 @@ abstract class ELVersionTask : DefaultTask() {
 | 
				
			||||||
                private ELVersions() {
 | 
					                private ELVersions() {
 | 
				
			||||||
                    throw new IllegalStateException();
 | 
					                    throw new IllegalStateException();
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					                public static class Version {
 | 
				
			||||||
 | 
					                    
 | 
				
			||||||
 | 
					                    private final long timestamp;
 | 
				
			||||||
 | 
					                    
 | 
				
			||||||
 | 
					                    public Version(long timestamp) {
 | 
				
			||||||
 | 
					                        this.timestamp = timestamp;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    
 | 
				
			||||||
 | 
					                    public long getTimestamp() {
 | 
				
			||||||
 | 
					                        return timestamp;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    
 | 
				
			||||||
 | 
					                    public String getTimestampFormatted() {
 | 
				
			||||||
 | 
					                        return  DateFormat.getDateTimeInstance().format(new java.util.Date(timestamp));
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					                    public boolean isOlderThan(Version version) {
 | 
				
			||||||
 | 
					                        return this.timestamp < version.timestamp;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        """.trimIndent())
 | 
					        """.trimIndent())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,17 +4,19 @@ import com.github.retrooper.packetevents.PacketEventsAPI;
 | 
				
			||||||
import me.tofaa.entitylib.APIConfig;
 | 
					import me.tofaa.entitylib.APIConfig;
 | 
				
			||||||
import me.tofaa.entitylib.EntityLibAPI;
 | 
					import me.tofaa.entitylib.EntityLibAPI;
 | 
				
			||||||
import me.tofaa.entitylib.Platform;
 | 
					import me.tofaa.entitylib.Platform;
 | 
				
			||||||
 | 
					import me.tofaa.entitylib.UserLocaleProvider;
 | 
				
			||||||
import me.tofaa.entitylib.container.EntityContainer;
 | 
					import me.tofaa.entitylib.container.EntityContainer;
 | 
				
			||||||
import me.tofaa.entitylib.tick.TickContainer;
 | 
					import me.tofaa.entitylib.tick.TickContainer;
 | 
				
			||||||
import me.tofaa.entitylib.wrapper.WrapperEntity;
 | 
					import me.tofaa.entitylib.wrapper.WrapperEntity;
 | 
				
			||||||
import org.jetbrains.annotations.NotNull;
 | 
					import org.jetbrains.annotations.NotNull;
 | 
				
			||||||
import org.jetbrains.annotations.Nullable;
 | 
					import org.jetbrains.annotations.Nullable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.*;
 | 
					import java.util.Collection;
 | 
				
			||||||
 | 
					import java.util.Collections;
 | 
				
			||||||
 | 
					import java.util.HashSet;
 | 
				
			||||||
 | 
					import java.util.UUID;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public abstract class AbstractEntityLibAPI<P, T> implements EntityLibAPI<T> {
 | 
					public abstract class AbstractEntityLibAPI<P, T> implements EntityLibAPI<T> {
 | 
				
			||||||
 | 
					 | 
				
			||||||
    protected final Platform<P> platform;
 | 
					    protected final Platform<P> platform;
 | 
				
			||||||
    protected final PacketEventsAPI<?> packetEvents;
 | 
					    protected final PacketEventsAPI<?> packetEvents;
 | 
				
			||||||
    protected final APIConfig settings;
 | 
					    protected final APIConfig settings;
 | 
				
			||||||
| 
						 | 
					@ -36,7 +38,6 @@ public abstract class AbstractEntityLibAPI<P, T> implements EntityLibAPI<T> {
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public @Nullable WrapperEntity getEntity(@NotNull UUID uuid) {
 | 
					    public @Nullable WrapperEntity getEntity(@NotNull UUID uuid) {
 | 
				
			||||||
        return defaultEntityContainer.getEntity(uuid);
 | 
					        return defaultEntityContainer.getEntity(uuid);
 | 
				
			||||||
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
| 
						 | 
					@ -49,9 +50,8 @@ public abstract class AbstractEntityLibAPI<P, T> implements EntityLibAPI<T> {
 | 
				
			||||||
        return defaultEntityContainer;
 | 
					        return defaultEntityContainer;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @NotNull
 | 
					 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public APIConfig getSettings() {
 | 
					    public @NotNull APIConfig getSettings() {
 | 
				
			||||||
        return settings;
 | 
					        return settings;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -60,9 +60,13 @@ public abstract class AbstractEntityLibAPI<P, T> implements EntityLibAPI<T> {
 | 
				
			||||||
        return packetEvents;
 | 
					        return packetEvents;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @NotNull
 | 
					 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public Collection<TickContainer<?, T>> getTickContainers() {
 | 
					    public @NotNull Collection<TickContainer<?, T>> getTickContainers() {
 | 
				
			||||||
        return tickContainers;
 | 
					        return tickContainers;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public @NotNull UserLocaleProvider getUserLocaleProvider() {
 | 
				
			||||||
 | 
					        return platform.getUserLocaleProvider();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,8 +1,8 @@
 | 
				
			||||||
[versions]
 | 
					[versions]
 | 
				
			||||||
adventure = "4.16.0"
 | 
					adventure = "4.22.0"
 | 
				
			||||||
jetbrains-annotations = "24.0.0"
 | 
					jetbrains-annotations = "26.0.2"
 | 
				
			||||||
gson = "2.11.0"
 | 
					gson = "2.13.1"
 | 
				
			||||||
packetevents = "2.7.0"
 | 
					packetevents = "2.9.1"
 | 
				
			||||||
paper = "1.21-R0.1-SNAPSHOT"
 | 
					paper = "1.21-R0.1-SNAPSHOT"
 | 
				
			||||||
velocity = "3.3.0-SNAPSHOT"
 | 
					velocity = "3.3.0-SNAPSHOT"
 | 
				
			||||||
run-paper = "2.3.0"
 | 
					run-paper = "2.3.0"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,15 +1,21 @@
 | 
				
			||||||
package me.tofaa.entitylib.spigot;
 | 
					package me.tofaa.entitylib.spigot;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.github.retrooper.packetevents.PacketEventsAPI;
 | 
				
			||||||
 | 
					import io.github.retrooper.packetevents.bstats.bukkit.Metrics;
 | 
				
			||||||
 | 
					import io.github.retrooper.packetevents.bstats.charts.SimplePie;
 | 
				
			||||||
import me.tofaa.entitylib.APIConfig;
 | 
					import me.tofaa.entitylib.APIConfig;
 | 
				
			||||||
 | 
					import me.tofaa.entitylib.EntityLib;
 | 
				
			||||||
 | 
					import me.tofaa.entitylib.UserLocaleProvider;
 | 
				
			||||||
import me.tofaa.entitylib.common.AbstractPlatform;
 | 
					import me.tofaa.entitylib.common.AbstractPlatform;
 | 
				
			||||||
 | 
					import java.util.logging.Logger;
 | 
				
			||||||
 | 
					import org.bukkit.plugin.Plugin;
 | 
				
			||||||
import org.bukkit.plugin.java.JavaPlugin;
 | 
					import org.bukkit.plugin.java.JavaPlugin;
 | 
				
			||||||
import org.jetbrains.annotations.NotNull;
 | 
					import org.jetbrains.annotations.NotNull;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.logging.Logger;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
public class SpigotEntityLibPlatform extends AbstractPlatform<JavaPlugin> {
 | 
					public class SpigotEntityLibPlatform extends AbstractPlatform<JavaPlugin> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private SpigotEntityLibAPI api;
 | 
					    private SpigotEntityLibAPI api;
 | 
				
			||||||
 | 
					    private UserLocaleProvider userLocaleProvider = new SpigotPlayerLocaleProvider();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public SpigotEntityLibPlatform(@NotNull JavaPlugin plugin) {
 | 
					    public SpigotEntityLibPlatform(@NotNull JavaPlugin plugin) {
 | 
				
			||||||
        super(plugin);
 | 
					        super(plugin);
 | 
				
			||||||
| 
						 | 
					@ -23,6 +29,10 @@ public class SpigotEntityLibPlatform extends AbstractPlatform<JavaPlugin> {
 | 
				
			||||||
        this.setEntityIdProvider(new SpigotEntityIdProvider(this));
 | 
					        this.setEntityIdProvider(new SpigotEntityIdProvider(this));
 | 
				
			||||||
        this.api.onLoad();
 | 
					        this.api.onLoad();
 | 
				
			||||||
        this.api.onEnable();
 | 
					        this.api.onEnable();
 | 
				
			||||||
 | 
					        if (settings.shouldUseBstats()) {
 | 
				
			||||||
 | 
					            PacketEventsAPI<Plugin> pe = (PacketEventsAPI<Plugin>) api.getPacketEvents();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
| 
						 | 
					@ -34,4 +44,14 @@ public class SpigotEntityLibPlatform extends AbstractPlatform<JavaPlugin> {
 | 
				
			||||||
    public String getName() {
 | 
					    public String getName() {
 | 
				
			||||||
        return "Spigot";
 | 
					        return "Spigot";
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public @NotNull UserLocaleProvider getUserLocaleProvider() {
 | 
				
			||||||
 | 
					        return userLocaleProvider;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void setUserLocaleProvider(@NotNull final UserLocaleProvider provider) {
 | 
				
			||||||
 | 
					        this.userLocaleProvider = provider;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,73 @@
 | 
				
			||||||
 | 
					package me.tofaa.entitylib.spigot;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import me.tofaa.entitylib.UserLocaleProvider;
 | 
				
			||||||
 | 
					import java.lang.invoke.MethodHandle;
 | 
				
			||||||
 | 
					import java.lang.invoke.MethodHandles;
 | 
				
			||||||
 | 
					import java.lang.invoke.MethodType;
 | 
				
			||||||
 | 
					import java.util.Locale;
 | 
				
			||||||
 | 
					import java.util.UUID;
 | 
				
			||||||
 | 
					import java.util.function.Function;
 | 
				
			||||||
 | 
					import net.kyori.adventure.translation.Translator;
 | 
				
			||||||
 | 
					import org.bukkit.Bukkit;
 | 
				
			||||||
 | 
					import org.bukkit.entity.Player;
 | 
				
			||||||
 | 
					import org.jetbrains.annotations.NotNull;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * This implementation is based on code from the scoreboard-library project:
 | 
				
			||||||
 | 
					 * <a href="https://github.com/MegavexNetwork/scoreboard-library/blob/bc8e3c2d2ecf9973ec0d6bb8ae4af94ed008b360/commons/src/main/java/net/megavex/scoreboardlibrary/implementation/commons/LocaleProvider.java">LocaleProvider</a>
 | 
				
			||||||
 | 
					 * Modified and adapted for use in EntityLib.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class SpigotPlayerLocaleProvider implements UserLocaleProvider {
 | 
				
			||||||
 | 
					    private static final Locale DEFAULT_LOCALE = Locale.US;
 | 
				
			||||||
 | 
					    private static final Function<Player, Locale> provider = get();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public Locale locale(final UUID user) {
 | 
				
			||||||
 | 
					        final Player player = Bukkit.getPlayer(user);
 | 
				
			||||||
 | 
					        return player == null ? DEFAULT_LOCALE : provider.apply(player);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static @NotNull Function<Player, Locale> get() {
 | 
				
			||||||
 | 
					        MethodHandles.Lookup lookup = MethodHandles.publicLookup();
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            MethodHandle adventureMethod = lookup.findVirtual(Player.class, "locale", MethodType.methodType(Locale.class));
 | 
				
			||||||
 | 
					            return player -> {
 | 
				
			||||||
 | 
					                try {
 | 
				
			||||||
 | 
					                    return (Locale) adventureMethod.invokeExact(player);
 | 
				
			||||||
 | 
					                } catch (Throwable e) {
 | 
				
			||||||
 | 
					                    throw new RuntimeException(e);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					        } catch (IllegalAccessException | NoSuchMethodException ignored) {
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        MethodType methodType = MethodType.methodType(String.class);
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            MethodHandle legacySpigotMethod = lookup.findVirtual(Player.Spigot.class, "getLocale", methodType);
 | 
				
			||||||
 | 
					            return player -> {
 | 
				
			||||||
 | 
					                try {
 | 
				
			||||||
 | 
					                    Locale locale = Translator.parseLocale((String) legacySpigotMethod.invokeExact(player.spigot()));
 | 
				
			||||||
 | 
					                    return locale == null ? DEFAULT_LOCALE : locale;
 | 
				
			||||||
 | 
					                } catch (Throwable e) {
 | 
				
			||||||
 | 
					                    throw new RuntimeException(e);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					        } catch (IllegalAccessException | NoSuchMethodException ignored) {
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            MethodHandle legacyMethod = lookup.findVirtual(Player.class, "getLocale", methodType);
 | 
				
			||||||
 | 
					            return player -> {
 | 
				
			||||||
 | 
					                try {
 | 
				
			||||||
 | 
					                    Locale locale = Translator.parseLocale((String) legacyMethod.invokeExact(player));
 | 
				
			||||||
 | 
					                    return locale == null ? DEFAULT_LOCALE : locale;
 | 
				
			||||||
 | 
					                } catch (Throwable e) {
 | 
				
			||||||
 | 
					                    throw new RuntimeException(e);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					        } catch (IllegalAccessException | NoSuchMethodException ignored) {
 | 
				
			||||||
 | 
					            throw new RuntimeException("No way to get players locale found");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -2,15 +2,18 @@ package me.tofaa.entitylib.standalone;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import me.tofaa.entitylib.APIConfig;
 | 
					import me.tofaa.entitylib.APIConfig;
 | 
				
			||||||
import me.tofaa.entitylib.EntityLibAPI;
 | 
					import me.tofaa.entitylib.EntityLibAPI;
 | 
				
			||||||
 | 
					import me.tofaa.entitylib.UserLocaleProvider;
 | 
				
			||||||
import me.tofaa.entitylib.common.AbstractPlatform;
 | 
					import me.tofaa.entitylib.common.AbstractPlatform;
 | 
				
			||||||
 | 
					import java.util.Locale;
 | 
				
			||||||
import org.jetbrains.annotations.NotNull;
 | 
					import org.jetbrains.annotations.NotNull;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class StandaloneEntityLibPlatform extends AbstractPlatform<Object> {
 | 
					public class StandaloneEntityLibPlatform extends AbstractPlatform<Object> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private StandaloneEntityLibApi api;
 | 
					    private StandaloneEntityLibApi api;
 | 
				
			||||||
 | 
					    private UserLocaleProvider userLocaleProvider = (user) -> Locale.US;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private StandaloneEntityLibPlatform() {
 | 
					    public StandaloneEntityLibPlatform() {
 | 
				
			||||||
        super(null);
 | 
					        super(null);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -34,4 +37,14 @@ public class StandaloneEntityLibPlatform extends AbstractPlatform<Object> {
 | 
				
			||||||
    public String getName() {
 | 
					    public String getName() {
 | 
				
			||||||
        return "Standalone";
 | 
					        return "Standalone";
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public @NotNull UserLocaleProvider getUserLocaleProvider() {
 | 
				
			||||||
 | 
					        return userLocaleProvider;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void setUserLocaleProvider(@NotNull final UserLocaleProvider provider) {
 | 
				
			||||||
 | 
					        this.userLocaleProvider = provider;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,6 +9,7 @@ import com.velocitypowered.api.proxy.ProxyServer;
 | 
				
			||||||
import io.github.retrooper.packetevents.velocity.factory.VelocityPacketEventsBuilder;
 | 
					import io.github.retrooper.packetevents.velocity.factory.VelocityPacketEventsBuilder;
 | 
				
			||||||
import me.tofaa.entitylib.APIConfig;
 | 
					import me.tofaa.entitylib.APIConfig;
 | 
				
			||||||
import me.tofaa.entitylib.EntityLibAPI;
 | 
					import me.tofaa.entitylib.EntityLibAPI;
 | 
				
			||||||
 | 
					import me.tofaa.entitylib.UserLocaleProvider;
 | 
				
			||||||
import me.tofaa.entitylib.common.AbstractPlatform;
 | 
					import me.tofaa.entitylib.common.AbstractPlatform;
 | 
				
			||||||
import org.jetbrains.annotations.NotNull;
 | 
					import org.jetbrains.annotations.NotNull;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -16,6 +17,7 @@ import java.util.logging.Logger;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class VelocityEntityLibPlatform extends AbstractPlatform<ProxyServer> {
 | 
					public class VelocityEntityLibPlatform extends AbstractPlatform<ProxyServer> {
 | 
				
			||||||
    private VelocityEntityLibAPI api;
 | 
					    private VelocityEntityLibAPI api;
 | 
				
			||||||
 | 
					    private UserLocaleProvider userLocaleProvider;
 | 
				
			||||||
    private Object plugin;
 | 
					    private Object plugin;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public VelocityEntityLibPlatform(Object plugin, ProxyServer handle) {
 | 
					    public VelocityEntityLibPlatform(Object plugin, ProxyServer handle) {
 | 
				
			||||||
| 
						 | 
					@ -54,4 +56,14 @@ public class VelocityEntityLibPlatform extends AbstractPlatform<ProxyServer> {
 | 
				
			||||||
    public String getName() {
 | 
					    public String getName() {
 | 
				
			||||||
        return "Velocity";
 | 
					        return "Velocity";
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public @NotNull UserLocaleProvider getUserLocaleProvider() {
 | 
				
			||||||
 | 
					        return userLocaleProvider;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void setUserLocaleProvider(final UserLocaleProvider userLocaleProvider) {
 | 
				
			||||||
 | 
					        this.userLocaleProvider = userLocaleProvider;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,20 @@
 | 
				
			||||||
 | 
					package me.tofaa.entitylib.velocity;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.velocitypowered.api.proxy.Player;
 | 
				
			||||||
 | 
					import com.velocitypowered.api.proxy.ProxyServer;
 | 
				
			||||||
 | 
					import me.tofaa.entitylib.UserLocaleProvider;
 | 
				
			||||||
 | 
					import java.util.Locale;
 | 
				
			||||||
 | 
					import java.util.UUID;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class VelocityPlayerLocaleProvider implements UserLocaleProvider {
 | 
				
			||||||
 | 
					    private final ProxyServer proxyServer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public VelocityPlayerLocaleProvider(final ProxyServer proxyServer) {
 | 
				
			||||||
 | 
					        this.proxyServer = proxyServer;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public Locale locale(final UUID user) {
 | 
				
			||||||
 | 
					        return proxyServer.getPlayer(user).map(Player::getEffectiveLocale).orElse(Locale.US);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -34,7 +34,7 @@ include(":platforms:spigot")
 | 
				
			||||||
include(":platforms:velocity")
 | 
					include(":platforms:velocity")
 | 
				
			||||||
include(":platforms:standalone")
 | 
					include(":platforms:standalone")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if (!System.getenv("JITPACK").toBoolean()) {
 | 
					if (System.getenv("PRIVATE").toBoolean()) {
 | 
				
			||||||
    include("discord-bot")
 | 
					    include("discord-bot")
 | 
				
			||||||
    include(":code-gen")
 | 
					    include(":code-gen")
 | 
				
			||||||
    include(":test-plugin")
 | 
					    include(":test-plugin")
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,11 +9,13 @@ import org.bukkit.command.CommandMap;
 | 
				
			||||||
import org.bukkit.plugin.java.JavaPlugin;
 | 
					import org.bukkit.plugin.java.JavaPlugin;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.lang.reflect.InvocationTargetException;
 | 
					import java.lang.reflect.InvocationTargetException;
 | 
				
			||||||
 | 
					import java.text.DateFormat;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class TestEntityLibPlugin extends JavaPlugin {
 | 
					public class TestEntityLibPlugin extends JavaPlugin {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void onEnable() {
 | 
					    public void onEnable() {
 | 
				
			||||||
 | 
					        DateFormat.getDateTimeInstance().format(new java.util.Date(timestamp));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        SpigotEntityLibPlatform platform = new SpigotEntityLibPlatform(this);
 | 
					        SpigotEntityLibPlatform platform = new SpigotEntityLibPlatform(this);
 | 
				
			||||||
        APIConfig settings = new APIConfig(PacketEvents.getAPI())
 | 
					        APIConfig settings = new APIConfig(PacketEvents.getAPI())
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue