From 6ecc6bf136f6fc99b9f76e195518ace89029bc1b Mon Sep 17 00:00:00 2001 From: Edelweiss Date: Sun, 18 Feb 2024 16:24:22 -0600 Subject: [PATCH] Migrate Offline-Player-Cache & Integrate into main mod --- build.gradle | 12 +- gradle.properties | 4 +- ...lient.kt => PlayerEXDirectorsCutClient.kt} | 0 ...ixins.json => playerex.client.mixins.json} | 0 .../playerex/mixin/LevelPropertiesMixin.java | 44 ++++ .../playerex/mixin/PlayerManagerMixin.java | 51 +++++ .../UnmodifiableLevelPropertiesMixin.java | 23 ++ .../edelweiss/playerex/PlayerEXComponents.kt | 34 +++ .../playerex/PlayerEXDCEntityComponents.kt | 16 -- .../playerex/PlayerEXDirectorsCut.kt | 38 ++++ ...t => PlayerEXDirectorsCutDataGenerator.kt} | 1 + .../playerex/Playerexdirectorscut.kt | 18 -- .../com/edelweiss/playerex/api/PlayerEXAPI.kt | 17 ++ .../edelweiss/playerex/api/PlayerEXDCApi.kt | 8 - .../playerex/cache/CachedPlayerValue.kt | 21 ++ .../playerex/cache/PlayerCacheKeys.kt | 7 + .../edelweiss/playerex/cache/PlayerEXCache.kt | 40 ++++ .../playerex/cache/PlayerEXCacheData.kt | 5 + .../playerex/cache/PlayerEXCacheInternal.kt | 204 ++++++++++++++++++ .../playerex/cache/PlayerEXCacheProvider.kt | 28 +++ .../commands/PlayerEXCacheCommands.kt | 171 +++++++++++++++ .../playerex/commands/PlayerEXCommands.kt | 18 ++ .../components/LivingEntityComponent.kt | 18 +- .../components/PlayerEntityComponent.kt | 18 ++ .../playerex/constants/EntityAttributes.kt | 29 +++ .../constants/PlayerEXDCAttributes.kt | 10 - .../playerex/constants/StackingBehaviors.kt | 6 + .../listeners/ServerEventListeners.kt | 16 ++ .../edelweiss/playerex/values/LevelValue.kt | 40 ++++ .../icon.png | Bin src/main/resources/fabric.mod.json | 11 +- .../playerex-directors-cut.mixins.json | 10 - src/main/resources/playerex.mixins.json | 13 ++ 33 files changed, 853 insertions(+), 78 deletions(-) rename src/client/kotlin/com/edelweiss/playerex/{PlayerexdirectorscutClient.kt => PlayerEXDirectorsCutClient.kt} (100%) rename src/client/resources/{playerex-directors-cut.client.mixins.json => playerex.client.mixins.json} (100%) create mode 100644 src/main/java/com/edelweiss/playerex/mixin/LevelPropertiesMixin.java create mode 100644 src/main/java/com/edelweiss/playerex/mixin/PlayerManagerMixin.java create mode 100644 src/main/java/com/edelweiss/playerex/mixin/UnmodifiableLevelPropertiesMixin.java create mode 100644 src/main/kotlin/com/edelweiss/playerex/PlayerEXComponents.kt delete mode 100644 src/main/kotlin/com/edelweiss/playerex/PlayerEXDCEntityComponents.kt create mode 100644 src/main/kotlin/com/edelweiss/playerex/PlayerEXDirectorsCut.kt rename src/main/kotlin/com/edelweiss/playerex/{PlayerexdirectorscutDataGenerator.kt => PlayerEXDirectorsCutDataGenerator.kt} (99%) delete mode 100644 src/main/kotlin/com/edelweiss/playerex/Playerexdirectorscut.kt create mode 100644 src/main/kotlin/com/edelweiss/playerex/api/PlayerEXAPI.kt delete mode 100644 src/main/kotlin/com/edelweiss/playerex/api/PlayerEXDCApi.kt create mode 100644 src/main/kotlin/com/edelweiss/playerex/cache/CachedPlayerValue.kt create mode 100644 src/main/kotlin/com/edelweiss/playerex/cache/PlayerCacheKeys.kt create mode 100644 src/main/kotlin/com/edelweiss/playerex/cache/PlayerEXCache.kt create mode 100644 src/main/kotlin/com/edelweiss/playerex/cache/PlayerEXCacheData.kt create mode 100644 src/main/kotlin/com/edelweiss/playerex/cache/PlayerEXCacheInternal.kt create mode 100644 src/main/kotlin/com/edelweiss/playerex/cache/PlayerEXCacheProvider.kt create mode 100644 src/main/kotlin/com/edelweiss/playerex/commands/PlayerEXCacheCommands.kt create mode 100644 src/main/kotlin/com/edelweiss/playerex/commands/PlayerEXCommands.kt create mode 100644 src/main/kotlin/com/edelweiss/playerex/components/PlayerEntityComponent.kt create mode 100644 src/main/kotlin/com/edelweiss/playerex/constants/EntityAttributes.kt delete mode 100644 src/main/kotlin/com/edelweiss/playerex/constants/PlayerEXDCAttributes.kt create mode 100644 src/main/kotlin/com/edelweiss/playerex/constants/StackingBehaviors.kt create mode 100644 src/main/kotlin/com/edelweiss/playerex/listeners/ServerEventListeners.kt create mode 100644 src/main/kotlin/com/edelweiss/playerex/values/LevelValue.kt rename src/main/resources/assets/{playerex-directors-cut => playerex}/icon.png (100%) delete mode 100644 src/main/resources/playerex-directors-cut.mixins.json create mode 100644 src/main/resources/playerex.mixins.json diff --git a/build.gradle b/build.gradle index 2f362096..01101698 100644 --- a/build.gradle +++ b/build.gradle @@ -16,6 +16,10 @@ repositories { name = "Ladysnake Mods" url = 'https://maven.ladysnake.org/releases' } + maven { + name = "Modrinth" + url = "https://api.modrinth.com/maven" + } } loom { @@ -44,13 +48,19 @@ dependencies { modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" modImplementation "net.fabricmc:fabric-language-kotlin:${project.fabric_kotlin_version}" - // Replace modImplementation with modApi if you expose components in your own API * + // Cardinal Components modImplementation "dev.onyxstudios.cardinal-components-api:cardinal-components-base:${project.cardinal_components_version}" include "dev.onyxstudios.cardinal-components-api:cardinal-components-base:${project.cardinal_components_version}" modImplementation "dev.onyxstudios.cardinal-components-api:cardinal-components-entity:${project.cardinal_components_version}" include "dev.onyxstudios.cardinal-components-api:cardinal-components-entity:${project.cardinal_components_version}" modImplementation "dev.onyxstudios.cardinal-components-api:cardinal-components-chunk:${project.cardinal_components_version}" include "dev.onyxstudios.cardinal-components-api:cardinal-components-chunk:${project.cardinal_components_version}" + modImplementation "dev.onyxstudios.cardinal-components-api:cardinal-components-level:${project.cardinal_components_version}" + include "dev.onyxstudios.cardinal-components-api:cardinal-components-level:${project.cardinal_components_version}" + + modImplementation "maven.modrinth:projectile-damage-attribute:${project.projectile_damage_attribute_version}-fabric" + + modImplementation include("maven.modrinth:AdditionalEntityAttributes:${project.additional_entity_attributes_version}") } processResources { diff --git a/gradle.properties b/gradle.properties index a799e1ed..dc02876b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -14,4 +14,6 @@ archives_base_name=playerex-directors-cut # Dependencies fabric_version=0.92.0+1.20.1 -cardinal_components_version=5.2.2 \ No newline at end of file +cardinal_components_version=5.2.2 +additional_entity_attributes_version=1.7.0+1.20.0 +projectile_damage_attribute_version=3.2.2+1.20.1 \ No newline at end of file diff --git a/src/client/kotlin/com/edelweiss/playerex/PlayerexdirectorscutClient.kt b/src/client/kotlin/com/edelweiss/playerex/PlayerEXDirectorsCutClient.kt similarity index 100% rename from src/client/kotlin/com/edelweiss/playerex/PlayerexdirectorscutClient.kt rename to src/client/kotlin/com/edelweiss/playerex/PlayerEXDirectorsCutClient.kt diff --git a/src/client/resources/playerex-directors-cut.client.mixins.json b/src/client/resources/playerex.client.mixins.json similarity index 100% rename from src/client/resources/playerex-directors-cut.client.mixins.json rename to src/client/resources/playerex.client.mixins.json diff --git a/src/main/java/com/edelweiss/playerex/mixin/LevelPropertiesMixin.java b/src/main/java/com/edelweiss/playerex/mixin/LevelPropertiesMixin.java new file mode 100644 index 00000000..f624b9da --- /dev/null +++ b/src/main/java/com/edelweiss/playerex/mixin/LevelPropertiesMixin.java @@ -0,0 +1,44 @@ +package com.edelweiss.playerex.mixin; + +import com.edelweiss.playerex.cache.PlayerEXCacheData; +import com.edelweiss.playerex.cache.PlayerEXCacheInternal; +import com.mojang.datafixers.DataFixer; +import com.mojang.serialization.Dynamic; +import com.mojang.serialization.Lifecycle; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.nbt.NbtElement; +import net.minecraft.nbt.NbtList; +import net.minecraft.registry.DynamicRegistryManager; +import net.minecraft.world.gen.GeneratorOptions; +import net.minecraft.world.level.LevelInfo; +import net.minecraft.world.level.LevelProperties; +import net.minecraft.world.level.storage.SaveVersionInfo; +import org.jetbrains.annotations.NotNull; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(LevelProperties.class) +abstract class LevelPropertiesMixin implements PlayerEXCacheData { + @Unique + private final PlayerEXCacheInternal playerEXCache = new PlayerEXCacheInternal(); + + @Inject(method = "updateProperties", at = @At("HEAD")) + private void playerex_updateProperties(DynamicRegistryManager registryManager, NbtCompound levelNbt, NbtCompound playerNbt, CallbackInfo ci) { + levelNbt.put("PlayerEXCache", playerEXCache.writeToNbt()); + } + + @Inject(method = "readProperties", at = @At("RETURN")) + private static void playerex_readProperties(Dynamic dynamic, DataFixer dataFixer, int dataVersion, NbtCompound playerData, LevelInfo levelInfo, SaveVersionInfo saveVersionInfo, LevelProperties.SpecialProperty specialProperty, GeneratorOptions generatorOptions, Lifecycle lifecycle, CallbackInfoReturnable cir) { + LevelProperties levelProperties = cir.getReturnValue(); + dynamic.get("PlayerEXCache").result().map(Dynamic::getValue).ifPresent(nbtElement -> ((PlayerEXCacheData) levelProperties).playerEXCache().readFromNbt((NbtList) nbtElement)); + } + + @Override + public PlayerEXCacheInternal playerEXCache() { + return this.playerEXCache; + } +} diff --git a/src/main/java/com/edelweiss/playerex/mixin/PlayerManagerMixin.java b/src/main/java/com/edelweiss/playerex/mixin/PlayerManagerMixin.java new file mode 100644 index 00000000..07df77bc --- /dev/null +++ b/src/main/java/com/edelweiss/playerex/mixin/PlayerManagerMixin.java @@ -0,0 +1,51 @@ +package com.edelweiss.playerex.mixin; + +import com.edelweiss.playerex.cache.PlayerEXCacheInternal; +import net.minecraft.network.ClientConnection; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.PlayerManager; +import net.minecraft.server.network.ServerPlayerEntity; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.List; + +@Mixin(PlayerManager.class) +abstract class PlayerManagerMixin { + + @Final + @Shadow + private MinecraftServer server; + + @Final + @Shadow + private List players; + + @Inject(method = "onPlayerConnect", at = @At("TAIL")) + private void playerex_onPlayerConnect(ClientConnection connection, ServerPlayerEntity player, CallbackInfo ci) { + PlayerEXCacheInternal.Companion.ifCachePresent(this.server, null, playerCache -> { + playerCache.uncache(player); + return null; + }); + } + + @Inject(method = "remove", at = @At("HEAD")) + private void playerex_remove(ServerPlayerEntity player, CallbackInfo ci) { + PlayerEXCacheInternal.Companion.ifCachePresent(this.server, null, playerCache -> { + playerCache.cache(player); + return null; + }); + } + + @Inject(method = "disconnectAllPlayers", at = @At("HEAD")) + private void playerex_disconnectAllPlayers(CallbackInfo ci) { + PlayerEXCacheInternal.Companion.ifCachePresent(this.server, null, playerCache -> { + for (ServerPlayerEntity player : this.players) { playerCache.cache(player); } + return null; + }); + } +} \ No newline at end of file diff --git a/src/main/java/com/edelweiss/playerex/mixin/UnmodifiableLevelPropertiesMixin.java b/src/main/java/com/edelweiss/playerex/mixin/UnmodifiableLevelPropertiesMixin.java new file mode 100644 index 00000000..9863fb0c --- /dev/null +++ b/src/main/java/com/edelweiss/playerex/mixin/UnmodifiableLevelPropertiesMixin.java @@ -0,0 +1,23 @@ +package com.edelweiss.playerex.mixin; + +import com.edelweiss.playerex.cache.PlayerEXCacheData; +import com.edelweiss.playerex.cache.PlayerEXCacheInternal; +import net.minecraft.world.level.ServerWorldProperties; +import net.minecraft.world.level.UnmodifiableLevelProperties; +import org.jetbrains.annotations.NotNull; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(UnmodifiableLevelProperties.class) +abstract class UnmodifiableLevelPropertiesMixin implements PlayerEXCacheData { + @Final + @Shadow + private ServerWorldProperties worldProperties; + + @NotNull + @Override + public PlayerEXCacheInternal playerEXCache() { + return ((PlayerEXCacheData) this.worldProperties).playerEXCache(); + } +} diff --git a/src/main/kotlin/com/edelweiss/playerex/PlayerEXComponents.kt b/src/main/kotlin/com/edelweiss/playerex/PlayerEXComponents.kt new file mode 100644 index 00000000..a36f5f7b --- /dev/null +++ b/src/main/kotlin/com/edelweiss/playerex/PlayerEXComponents.kt @@ -0,0 +1,34 @@ +package com.edelweiss.playerex + +import com.edelweiss.playerex.api.PlayerEXAPI +import com.edelweiss.playerex.components.LivingEntityComponent +import com.edelweiss.playerex.components.PlayerEntityComponent +import dev.onyxstudios.cca.api.v3.component.ComponentKey +import dev.onyxstudios.cca.api.v3.component.ComponentRegistry +import dev.onyxstudios.cca.api.v3.entity.EntityComponentFactoryRegistry +import dev.onyxstudios.cca.api.v3.entity.EntityComponentInitializer +import dev.onyxstudios.cca.api.v3.level.LevelComponentFactoryRegistry +import dev.onyxstudios.cca.api.v3.level.LevelComponentInitializer +import dev.onyxstudios.cca.api.v3.world.WorldComponentFactoryRegistry +import dev.onyxstudios.cca.api.v3.world.WorldComponentInitializer +import net.minecraft.entity.LivingEntity + +class PlayerEXComponents : EntityComponentInitializer, LevelComponentInitializer, WorldComponentInitializer { + companion object { + val livingEntities: ComponentKey = ComponentRegistry.getOrCreate(PlayerEXAPI.id("living_entities"), LivingEntityComponent::class.java) + val playerEntities: ComponentKey = ComponentRegistry.getOrCreate(PlayerEXAPI.id("player_entities"), PlayerEntityComponent::class.java) + } + + override fun registerEntityComponentFactories(registry: EntityComponentFactoryRegistry) { + registry.registerFor(LivingEntity::class.java, livingEntities) { entity -> LivingEntityComponent(entity) } + registry.registerForPlayers(playerEntities) { player -> PlayerEntityComponent(player) } + } + + override fun registerLevelComponentFactories(registry: LevelComponentFactoryRegistry) { + + } + + override fun registerWorldComponentFactories(registry: WorldComponentFactoryRegistry) { + + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/edelweiss/playerex/PlayerEXDCEntityComponents.kt b/src/main/kotlin/com/edelweiss/playerex/PlayerEXDCEntityComponents.kt deleted file mode 100644 index ca3087d7..00000000 --- a/src/main/kotlin/com/edelweiss/playerex/PlayerEXDCEntityComponents.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.edelweiss.playerex - -import com.edelweiss.playerex.api.PlayerEXDCApi -import com.edelweiss.playerex.components.LivingEntityComponent -import dev.onyxstudios.cca.api.v3.component.ComponentKey -import dev.onyxstudios.cca.api.v3.component.ComponentRegistry -import dev.onyxstudios.cca.api.v3.entity.EntityComponentFactoryRegistry -import dev.onyxstudios.cca.api.v3.entity.EntityComponentInitializer -import net.minecraft.entity.LivingEntity - -class PlayerEXDCEntityComponents : EntityComponentInitializer { - val livingEntities: ComponentKey = ComponentRegistry.getOrCreate(PlayerEXDCApi.createID("living_entities"), LivingEntityComponent::class.java) - override fun registerEntityComponentFactories(registry: EntityComponentFactoryRegistry) { - registry.registerFor(LivingEntity::class.java, livingEntities) { LivingEntityComponent() } - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/edelweiss/playerex/PlayerEXDirectorsCut.kt b/src/main/kotlin/com/edelweiss/playerex/PlayerEXDirectorsCut.kt new file mode 100644 index 00000000..11e88682 --- /dev/null +++ b/src/main/kotlin/com/edelweiss/playerex/PlayerEXDirectorsCut.kt @@ -0,0 +1,38 @@ +package com.edelweiss.playerex + +import com.edelweiss.playerex.commands.PlayerEXCacheCommands +import com.edelweiss.playerex.commands.PlayerEXCommands +import net.fabricmc.api.ModInitializer +import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback +import org.slf4j.LoggerFactory + +object PlayerEXDirectorsCut : ModInitializer { + const val MODID: String = "playerex" + + val logger = LoggerFactory.getLogger(MODID) + + private fun registerCommands() = CommandRegistrationCallback.EVENT.register { dispatcher, _, _ -> + val head = PlayerEXCommands.registerHead(dispatcher) + PlayerEXCacheCommands.register(head) + } + + override fun onInitialize() { +// ServerLifecycleEvents.SERVER_STARTING.register(ServerEventListeners::serverStarting) +// ServerPlayerEvents.COPY_FROM.register(ServerEventListeners::reset) + +// // Register LivingEntity events +// LivingEntityEvents.ON_HEAL.register(EventFactory::healed); +// LivingEntityEvents.EVERY_SECOND.register(EventFactory::healthRegeneration); +// LivingEntityEvents.ON_DAMAGE.register(EventFactory::onDamage); +// LivingEntityEvents.SHOULD_DAMAGE.register(EventFactory::shouldDamage); +// +// // Register PlayerEntity events +// PlayerEntityEvents.ON_CRIT.register(EventFactory::onCritAttack); +// PlayerEntityEvents.SHOULD_CRIT.register(EventFactory::attackIsCrit); +// +// // Register attribute modification events +// EntityAttributeModifiedEvents.CLAMPED.register(EventFactory::clamped); + + this.registerCommands() + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/edelweiss/playerex/PlayerexdirectorscutDataGenerator.kt b/src/main/kotlin/com/edelweiss/playerex/PlayerEXDirectorsCutDataGenerator.kt similarity index 99% rename from src/main/kotlin/com/edelweiss/playerex/PlayerexdirectorscutDataGenerator.kt rename to src/main/kotlin/com/edelweiss/playerex/PlayerEXDirectorsCutDataGenerator.kt index ef7ace70..29bc0e10 100644 --- a/src/main/kotlin/com/edelweiss/playerex/PlayerexdirectorscutDataGenerator.kt +++ b/src/main/kotlin/com/edelweiss/playerex/PlayerEXDirectorsCutDataGenerator.kt @@ -5,5 +5,6 @@ import net.fabricmc.fabric.api.datagen.v1.FabricDataGenerator object PlayerEXDirectorsCutDataGenerator : DataGeneratorEntrypoint { override fun onInitializeDataGenerator(fabricDataGenerator: FabricDataGenerator) { + } } \ No newline at end of file diff --git a/src/main/kotlin/com/edelweiss/playerex/Playerexdirectorscut.kt b/src/main/kotlin/com/edelweiss/playerex/Playerexdirectorscut.kt deleted file mode 100644 index 38669be9..00000000 --- a/src/main/kotlin/com/edelweiss/playerex/Playerexdirectorscut.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.edelweiss.playerex - -import net.fabricmc.api.ModInitializer -import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents -import net.fabricmc.fabric.api.networking.v1.ServerLoginNetworking -import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking -import net.minecraft.world.WorldEvents -import org.slf4j.LoggerFactory - -object PlayerEXDirectorsCut : ModInitializer { - const val MODID: String = "playerex-directors-cut" - - private val logger = LoggerFactory.getLogger(MODID) - - override fun onInitialize() { - - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/edelweiss/playerex/api/PlayerEXAPI.kt b/src/main/kotlin/com/edelweiss/playerex/api/PlayerEXAPI.kt new file mode 100644 index 00000000..d1edf52e --- /dev/null +++ b/src/main/kotlin/com/edelweiss/playerex/api/PlayerEXAPI.kt @@ -0,0 +1,17 @@ +package com.edelweiss.playerex.api + +import com.edelweiss.playerex.PlayerEXDirectorsCut +import com.edelweiss.playerex.cache.PlayerEXCache +import com.edelweiss.playerex.values.LevelValue +import net.minecraft.util.Identifier + +/** Singleton used for main API access for PlayerEX. */ +object PlayerEXAPI { + val LEVEL_VALUE = PlayerEXCache.register(LevelValue()) + + + /** + * Creates and returns an `Identifier` based on the PlayerEX mod id. + * */ + fun id(str: String) = Identifier(PlayerEXDirectorsCut.MODID, str) +} diff --git a/src/main/kotlin/com/edelweiss/playerex/api/PlayerEXDCApi.kt b/src/main/kotlin/com/edelweiss/playerex/api/PlayerEXDCApi.kt deleted file mode 100644 index 22d962da..00000000 --- a/src/main/kotlin/com/edelweiss/playerex/api/PlayerEXDCApi.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.edelweiss.playerex.api - -import com.edelweiss.playerex.PlayerEXDirectorsCut -import net.minecraft.util.Identifier - -object PlayerEXDCApi { - fun createID(str: String) = Identifier(PlayerEXDirectorsCut.MODID, str) -} diff --git a/src/main/kotlin/com/edelweiss/playerex/cache/CachedPlayerValue.kt b/src/main/kotlin/com/edelweiss/playerex/cache/CachedPlayerValue.kt new file mode 100644 index 00000000..5d2abc2e --- /dev/null +++ b/src/main/kotlin/com/edelweiss/playerex/cache/CachedPlayerValue.kt @@ -0,0 +1,21 @@ +package com.edelweiss.playerex.cache + +import net.minecraft.nbt.NbtCompound +import net.minecraft.server.network.ServerPlayerEntity +import net.minecraft.util.Identifier + +interface CachedPlayerValue { + /** + * Used to get the cached value from the player. + * */ + fun get(player: ServerPlayerEntity): V + + /** Reads a value from a nbt. */ + fun readFromNbt(tag: NbtCompound): V + + /** Writes a value to a nbt. */ + fun writeToNbt(tag: NbtCompound, value: Any?): Boolean + + /** The key of the value. This would be used in the form `modid:`. */ + fun id(): Identifier +} \ No newline at end of file diff --git a/src/main/kotlin/com/edelweiss/playerex/cache/PlayerCacheKeys.kt b/src/main/kotlin/com/edelweiss/playerex/cache/PlayerCacheKeys.kt new file mode 100644 index 00000000..20345e14 --- /dev/null +++ b/src/main/kotlin/com/edelweiss/playerex/cache/PlayerCacheKeys.kt @@ -0,0 +1,7 @@ +package com.edelweiss.playerex.cache + +enum class PlayerCacheKeys(val key: String) { + UUID("uuid"), + Name("name"), + Keys("keys"), +} \ No newline at end of file diff --git a/src/main/kotlin/com/edelweiss/playerex/cache/PlayerEXCache.kt b/src/main/kotlin/com/edelweiss/playerex/cache/PlayerEXCache.kt new file mode 100644 index 00000000..f249b8af --- /dev/null +++ b/src/main/kotlin/com/edelweiss/playerex/cache/PlayerEXCache.kt @@ -0,0 +1,40 @@ +package com.edelweiss.playerex.cache + +import com.edelweiss.playerex.PlayerEXDirectorsCut +import net.minecraft.server.MinecraftServer +import java.util.UUID + +interface PlayerEXCache { + companion object { + /** Registers the provided cached value to the server. */ + fun register(key: CachedPlayerValue): CachedPlayerValue { + PlayerEXDirectorsCut.logger.debug("Cached Value has been registered: <{} :: #id: {}>", key, key.id()) + return PlayerEXCacheInternal.register(key) + } + + /** Get access to the cache object. Should only be used on the server. */ + fun getCache(server: MinecraftServer, fallback: T, function: (PlayerEXCache) -> T): T { + val provider = PlayerEXCacheProvider(server) + if (provider.isEmpty()) return fallback + return function(provider) + } + } + + /** Fetches the last cached value if offline, otherwise will fetch the current value from the player. */ + fun get(uuid: UUID, key: CachedPlayerValue) {} + + /** Fetches the last cached value if offline, otherwise will fetch the current value from the player. */ + fun get(playerName: String, key: CachedPlayerValue) {} + + /** Returns all offline & online player UUIDs. */ + fun playerIDs(): Set + + /** Returns all offline & online player names. */ + fun playerNames(): Set + + /** Checks if the player with the UUID is in the cache or not. */ + fun isPlayerCached(uuid: UUID): Boolean + + /** Checks if the player with the name is in the cache or not. */ + fun isPlayerCached(playerName: String) +} \ No newline at end of file diff --git a/src/main/kotlin/com/edelweiss/playerex/cache/PlayerEXCacheData.kt b/src/main/kotlin/com/edelweiss/playerex/cache/PlayerEXCacheData.kt new file mode 100644 index 00000000..a49068c9 --- /dev/null +++ b/src/main/kotlin/com/edelweiss/playerex/cache/PlayerEXCacheData.kt @@ -0,0 +1,5 @@ +package com.edelweiss.playerex.cache + +interface PlayerEXCacheData { + fun playerEXCache(): PlayerEXCacheInternal +} \ No newline at end of file diff --git a/src/main/kotlin/com/edelweiss/playerex/cache/PlayerEXCacheInternal.kt b/src/main/kotlin/com/edelweiss/playerex/cache/PlayerEXCacheInternal.kt new file mode 100644 index 00000000..ab493bfc --- /dev/null +++ b/src/main/kotlin/com/edelweiss/playerex/cache/PlayerEXCacheInternal.kt @@ -0,0 +1,204 @@ +package com.edelweiss.playerex.cache + +import com.google.common.collect.BiMap +import com.google.common.collect.HashBiMap +import net.minecraft.nbt.NbtCompound +import net.minecraft.nbt.NbtList +import net.minecraft.server.MinecraftServer +import net.minecraft.server.network.ServerPlayerEntity +import net.minecraft.util.Identifier +import java.util.UUID + +class PlayerEXCacheInternal( + private val cache: MutableMap, *>> = mutableMapOf(), + val playerNameToUUID: BiMap = HashBiMap.create() +) { + companion object { + private val cacheKeys = mutableMapOf>() + + @Suppress("UNCHECKED_CAST") + fun register(key: CachedPlayerValue): CachedPlayerValue { + return cacheKeys.computeIfAbsent(key.id()) { key } as CachedPlayerValue + } + + fun keys(): Set = cacheKeys.keys + + fun getKey(id: Identifier): CachedPlayerValue<*>? = cacheKeys[id] + + /** In the case if a cache exists, it will return a function that provides the internal cache for use. */ + fun ifCachePresent(server: MinecraftServer, fallback: T, function: (PlayerEXCacheInternal) -> T): T { + val worldProperties = server.overworld.levelProperties + val cache = (worldProperties as PlayerEXCacheData?)?.playerEXCache() + return if (cache != null) function(cache) else fallback + } + } + + private fun isValidPlayerData(player: ServerPlayerEntity, function: (UUID, String) -> Unit): Boolean { + val profile = player.gameProfile ?: return false + if (profile.id == null || profile.name == null) return false + function(profile.id, profile.name) + return true + } + + @Suppress("UNCHECKED_CAST") + private fun getFromCache(uuid: UUID, key: CachedPlayerValue): V? = this.cache[uuid]?.get(key) as V? + + /** Gets a cached value from a players `UUID` and a cached value key.*/ + internal fun get(server: MinecraftServer, uuid: UUID, key: CachedPlayerValue): V? { + val player = server.playerManager.getPlayer(uuid) + return if (player == null) this.getFromCache(uuid, key) else key.get(player) + } + + /** Gets a cached value from a players name and a cached value key. */ + internal fun get(server: MinecraftServer, playerName: String, key: CachedPlayerValue): V? { + if (playerName.isEmpty()) return null + val player = server.playerManager.getPlayer(playerName) + if (player == null) { + val uuid = this.playerNameToUUID[playerName]?: return null + return this.getFromCache(uuid, key) + } + return key.get(player) + } + + /** Collect all the player ids from the server into a `Set`. */ + fun playerIDs(server: MinecraftServer): Collection { + val set = HashSet(this.playerNameToUUID.values) + for (player in server.playerManager.playerList) { + val uuid = player?.gameProfile?.id ?: continue + set.add(uuid) + } + return set + } + + /** Collects all the player names from the server into a `Set`. */ + fun playerNames(server: MinecraftServer): Collection { + val set = HashSet(this.playerNameToUUID.keys) + for (player in server.playerManager.playerList) { + val playerName = player?.gameProfile?.name + if (!playerName.isNullOrEmpty()) set.add(playerName) + } + return set + } + + fun writeToNbt(): NbtList { + val list = NbtList() + val uuidToPlayerNames = this.playerNameToUUID.inverse() + + for (uuid in this.cache.keys) { + val data = this.cache[uuid] ?: continue + + val entry = NbtCompound() + val keys = NbtCompound() + + entry.putUuid(PlayerCacheKeys.UUID.key, uuid) + entry.putString(PlayerCacheKeys.Name.key, uuidToPlayerNames.getOrDefault(uuid, "")) + + for (key in data.keys) { + val innerEntry = NbtCompound() + key.writeToNbt(innerEntry, data[key]) + keys.put(key.id().toString(), innerEntry) + } + + entry.put(PlayerCacheKeys.Keys.key, keys) + list.add(entry) + } + + return list + } + + fun readFromNbt(list: NbtList) { + if (list.isEmpty()) return + + this.cache.clear() + this.playerNameToUUID.clear() + + for (index in list.indices) { + val entry = list.getCompound(index) + val keysCompound = entry.getCompound(PlayerCacheKeys.Keys.key) + val uuid = entry.getUuid(PlayerCacheKeys.UUID.key) + val name = entry.getString(PlayerCacheKeys.Name.key) + + if (name.isEmpty()) continue + + val data = mutableMapOf, Any>() + + for (id in keysCompound.keys) { + val key = cacheKeys[Identifier(id)] + val value = key?.readFromNbt(keysCompound.getCompound(id)) ?: continue + data[key] = value + } + + this.cache[uuid] = data + this.playerNameToUUID[name] = uuid + } + } + + fun isPlayerCached(uuid: UUID) = this.cache.containsKey(uuid) + + fun isPlayerCached(name: String) = this.playerNameToUUID.containsKey(name) + + fun cache(player: ServerPlayerEntity): Boolean = this.isValidPlayerData(player) { uuid, playerName -> + val value = mutableMapOf, Any?>() + cacheKeys.values.forEach { key -> value[key] = key.get(player) } + this.cache[uuid] = value + this.playerNameToUUID[playerName] = uuid + } + + /** Un-caches the player based on the provided `ServerPlayerEntity`. */ + fun uncache(player: ServerPlayerEntity) = this.isValidPlayerData(player) { uuid, _ -> + this.cache.remove(uuid) + this.playerNameToUUID.inverse().remove(uuid) + } + + /** + * Attempts to un-cache the player using a `UUID` and a given key. + * + * This could fail if the UUID is not in the cache, or the key removed is not present in the cache. + */ + fun uncache(uuid: UUID, key: CachedPlayerValue<*>): Boolean { + if (cacheKeys.containsKey(key.id())) return false + + val value = this.cache[uuid] ?: return false + + if (value.remove(key) != null) { + if (value.isEmpty()) { + this.cache.remove(uuid) + this.playerNameToUUID.inverse().remove(uuid) + } + return true + } + return false + } + + /** + * Attempts to un-cache the player using their name and a given key. + * + * This could fail if the player name is not in the cache, or the key removed is not present in the cache. + */ + fun uncache(playerName: String, key: CachedPlayerValue<*>): Boolean { + if (playerName.isEmpty()) return false + return this.uncache(this.playerNameToUUID[playerName] ?: return false, key) + } + + + /** + * Attempts to un-cache the player using a `UUID`. + * + * This could fail if the UUID is not in the cache. + */ + fun uncache(uuid: UUID): Boolean { + this.cache.remove(uuid) + return this.playerNameToUUID.inverse().remove(uuid) != null + } + + /** + * Attempts to un-cache the player using their name. + * + * This could fail if the UUID is not in the cache. + */ + fun uncache(playerName: String): Boolean { + if (playerName.isEmpty()) return false + val uuid = this.playerNameToUUID[playerName] ?: return false + return this.uncache(uuid) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/edelweiss/playerex/cache/PlayerEXCacheProvider.kt b/src/main/kotlin/com/edelweiss/playerex/cache/PlayerEXCacheProvider.kt new file mode 100644 index 00000000..e6b3d761 --- /dev/null +++ b/src/main/kotlin/com/edelweiss/playerex/cache/PlayerEXCacheProvider.kt @@ -0,0 +1,28 @@ +package com.edelweiss.playerex.cache + +import net.minecraft.server.MinecraftServer +import java.util.* + +class PlayerEXCacheProvider( + private val server: MinecraftServer, + private val internal: PlayerEXCacheInternal? = PlayerEXCacheInternal.ifCachePresent(server, null) { cache -> cache } +) : PlayerEXCache { + /** Checks if the cache is "empty", as in being `null`. */ + fun isEmpty(): Boolean = this.internal == null + + override fun playerIDs(): Set { + TODO("Not yet implemented") + } + + override fun playerNames(): Set { + TODO("Not yet implemented") + } + + override fun isPlayerCached(uuid: UUID): Boolean { + TODO("Not yet implemented") + } + + override fun isPlayerCached(playerName: String) { + TODO("Not yet implemented") + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/edelweiss/playerex/commands/PlayerEXCacheCommands.kt b/src/main/kotlin/com/edelweiss/playerex/commands/PlayerEXCacheCommands.kt new file mode 100644 index 00000000..f31b46f7 --- /dev/null +++ b/src/main/kotlin/com/edelweiss/playerex/commands/PlayerEXCacheCommands.kt @@ -0,0 +1,171 @@ +package com.edelweiss.playerex.commands + +import com.edelweiss.playerex.cache.PlayerEXCacheInternal +import com.mojang.brigadier.arguments.StringArgumentType +import com.mojang.brigadier.context.CommandContext +import com.mojang.brigadier.suggestion.SuggestionProvider +import com.mojang.brigadier.tree.ArgumentCommandNode +import com.mojang.brigadier.tree.LiteralCommandNode +import com.mojang.datafixers.util.Either +import net.minecraft.command.CommandSource +import net.minecraft.command.argument.IdentifierArgumentType +import net.minecraft.command.argument.UuidArgumentType +import net.minecraft.server.command.CommandManager +import net.minecraft.server.command.ServerCommandSource +import net.minecraft.text.MutableText +import net.minecraft.text.Text +import net.minecraft.util.Formatting +import net.minecraft.util.Identifier +import java.util.UUID +import kotlin.math.abs + +object PlayerEXCacheCommands { + private val suggestionKeys = SuggestionProvider { _, builder -> + CommandSource.suggestIdentifiers(PlayerEXCacheInternal.keys(), builder) + } + private val suggestionNames = SuggestionProvider { ctx, builder -> + PlayerEXCacheInternal.ifCachePresent(ctx.source.server, builder.buildFuture()) { cache -> + cache.playerNames(ctx.source.server).forEach(builder::suggest) + return@ifCachePresent builder.buildFuture() + } + } + private val suggestionUUIDs = SuggestionProvider { ctx, builder -> + PlayerEXCacheInternal.ifCachePresent(ctx.source.server, builder.buildFuture()) { cache -> + cache.playerIDs(ctx.source.server).forEach { id -> builder.suggest(id.toString()) } + return@ifCachePresent builder.buildFuture() + } + } + + private fun nullKeyMessage(id: T): () -> MutableText = { Text.literal("$id -> ").formatted(Formatting.RED) } + + private fun playerIDMessage(cache: PlayerEXCacheInternal, id: Either?, function: () -> MutableText): () -> MutableText = { + var formattedID = "" + id?.ifLeft { name -> + formattedID = "UUID: ${cache.playerNameToUUID[name]}\n" + "Name: $id" + }?.ifRight { + uuid -> formattedID = "UUID: $id\n" + "Name: ${cache.playerNameToUUID.inverse()[uuid]}" + } + Text.literal("$formattedID\n").formatted(Formatting.GREEN) + .append(function()) + } + + private fun getKey(input: (CommandContext) -> T): ArgumentCommandNode { + return CommandManager.argument("key", IdentifierArgumentType.identifier()).suggests(suggestionKeys).executes { ctx -> + val id = input(ctx) + val identifier = IdentifierArgumentType.getIdentifier(ctx, "key") + val value = PlayerEXCacheInternal.getKey(identifier) + + if (value == null) { + ctx.source.sendFeedback(nullKeyMessage(id), false) + return@executes -1 + } + + val server = ctx.source.server + + return@executes PlayerEXCacheInternal.ifCachePresent(server, -1) { cache -> + val uuidOrString: Either? = if (id is String) Either.left(id) else { if (id is UUID) Either.right(id) else null } + var fetchedValue: Any? = null + + ctx.source.sendFeedback( + playerIDMessage(cache, uuidOrString) { Text.literal("[$identifier] is ($value)").formatted(Formatting.WHITE) }, + false + ) + + uuidOrString?.ifLeft { fetchedValue = cache.get(server, id as String, value) } + uuidOrString?.ifRight { fetchedValue = cache.get(server, id as UUID, value) } + + if (fetchedValue is Number) return@ifCachePresent abs(fetchedValue as Int) % 16 + + return@ifCachePresent 1 + } + }.build() + } + + private fun removeKey(input: (CommandContext) -> T): ArgumentCommandNode { + return CommandManager.argument("key", IdentifierArgumentType.identifier()).suggests(suggestionKeys).executes { ctx -> + val id = input(ctx) + val identifier = IdentifierArgumentType.getIdentifier(ctx, "key") + val value = PlayerEXCacheInternal.getKey(identifier) + + if (value == null) { + ctx.source.sendFeedback(nullKeyMessage(id), false) + return@executes -1 + } + + val server = ctx.source.server + + return@executes PlayerEXCacheInternal.ifCachePresent(server, -1) { cache -> + if (id is String) cache.uncache(id as String) + else if (id is UUID) cache.uncache(id as UUID) + + ctx.source.sendFeedback({Text.literal("-$id -$identifier").formatted(Formatting.GRAY)}, false) + + return@ifCachePresent 1 + } + }.build() + } + + private fun get(root: LiteralCommandNode) { + val getNode = CommandManager.literal("get").build() + val nameNode = CommandManager.literal("name").build() + val uuidNode = CommandManager.literal("uuid").build() + + val nameArgNode = CommandManager.argument("name", StringArgumentType.string()).suggests(suggestionNames).build() + val key1 = getKey { ctx -> StringArgumentType.getString(ctx, "name") } + val uuid = CommandManager.argument("uuid", UuidArgumentType.uuid()).suggests(suggestionUUIDs).build() + val key2 = getKey { ctx -> UuidArgumentType.getUuid(ctx, "uuid") } + + root.addChild(getNode) + getNode.addChild(nameNode) + getNode.addChild(uuidNode) + + nameNode.addChild(nameArgNode) + uuidNode.addChild(uuid) + nameArgNode.addChild(key1) + uuid.addChild(key2) + } + + private fun remove(root: LiteralCommandNode) { + val removeNode = CommandManager.literal("remove").build() + val nameNode = CommandManager.literal("name").build() + val uuidNode = CommandManager.literal("uuid").build() + + val nameArgNode = CommandManager.argument("name", StringArgumentType.string()).suggests(suggestionNames).executes {ctx -> + val server = ctx.source.server + return@executes PlayerEXCacheInternal.ifCachePresent(server, -1) { cache -> + val playerString = StringArgumentType.getString(ctx, "name") + cache.uncache(playerString) + ctx.source.sendFeedback({Text.literal("-$playerString -*").formatted(Formatting.GRAY)}, false) + return@ifCachePresent 1 + } + }.build() + + val key1 = removeKey { ctx -> StringArgumentType.getString(ctx, "name") } + val uuid = CommandManager.argument("uuid", UuidArgumentType.uuid()).suggests(suggestionUUIDs).executes { ctx -> + val server = ctx.source.server + return@executes PlayerEXCacheInternal.ifCachePresent(server, -1) { cache -> + val playerUUID = UuidArgumentType.getUuid(ctx, "uuid") + cache.uncache(playerUUID) + ctx.source.sendFeedback({Text.literal("-$playerUUID -*").formatted(Formatting.GRAY)}, false) + return@ifCachePresent 1 + } + }.build() + + val key2 = removeKey { ctx -> UuidArgumentType.getUuid(ctx, "uuid") } + + root.addChild(removeNode) + removeNode.addChild(nameNode) + removeNode.addChild(uuidNode) + nameNode.addChild(nameArgNode) + uuidNode.addChild(uuid) + nameArgNode.addChild(key1) + uuid.addChild(key2) + } + + fun register(head: LiteralCommandNode) { + val root = CommandManager.literal("cache").requires { source -> source.hasPermissionLevel(2) }.build() + head.addChild(root) + get(root) + remove(root) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/edelweiss/playerex/commands/PlayerEXCommands.kt b/src/main/kotlin/com/edelweiss/playerex/commands/PlayerEXCommands.kt new file mode 100644 index 00000000..96261d9e --- /dev/null +++ b/src/main/kotlin/com/edelweiss/playerex/commands/PlayerEXCommands.kt @@ -0,0 +1,18 @@ +package com.edelweiss.playerex.commands + +import com.mojang.brigadier.CommandDispatcher +import com.mojang.brigadier.tree.LiteralCommandNode +import net.minecraft.server.command.CommandManager +import net.minecraft.server.command.ServerCommandSource + +object PlayerEXCommands { + fun registerHead(dispatcher: CommandDispatcher): LiteralCommandNode { + val head = CommandManager.literal("playerex").requires { source -> source.hasPermissionLevel(2) }.build() + + // add playerex commands + + dispatcher.root.addChild(head) + + return head + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/edelweiss/playerex/components/LivingEntityComponent.kt b/src/main/kotlin/com/edelweiss/playerex/components/LivingEntityComponent.kt index fdd32a63..4fa8dbf0 100644 --- a/src/main/kotlin/com/edelweiss/playerex/components/LivingEntityComponent.kt +++ b/src/main/kotlin/com/edelweiss/playerex/components/LivingEntityComponent.kt @@ -1,26 +1,26 @@ package com.edelweiss.playerex.components -import com.edelweiss.playerex.constants.PlayerEXDCAttributes -import dev.onyxstudios.cca.api.v3.component.Component -import dev.onyxstudios.cca.api.v3.entity.PlayerComponent +import com.edelweiss.playerex.constants.EntityAttributes +import dev.onyxstudios.cca.api.v3.component.sync.AutoSyncedComponent +import net.minecraft.entity.LivingEntity import net.minecraft.nbt.NbtCompound -class LivingEntityComponent() : PlayerComponent, Component { +class LivingEntityComponent(private val entity: LivingEntity) : AutoSyncedComponent { companion object {} - private val attributes = mutableMapOf() + private val attributes = mutableMapOf() - fun setAttribute(attribute: PlayerEXDCAttributes, value: Int) { + fun setAttribute(attribute: EntityAttributes, value: Double) { this.attributes[attribute] = value } - fun getAttribute(attribute: PlayerEXDCAttributes): Int? = this.attributes[attribute] + fun getAttribute(attribute: EntityAttributes): Double? = this.attributes[attribute] override fun readFromNbt(tag: NbtCompound) { - PlayerEXDCAttributes.entries.forEach { attribute -> attributes[attribute] = tag.getInt(attribute.tag) } + EntityAttributes.entries.forEach { attribute -> attributes[attribute] = tag.getDouble(attribute.id.path) } } override fun writeToNbt(tag: NbtCompound) { - attributes.forEach { (key, value) -> tag.putInt(key.tag, value) } + attributes.forEach { (key, value) -> tag.putDouble(key.id.path, value) } } } \ No newline at end of file diff --git a/src/main/kotlin/com/edelweiss/playerex/components/PlayerEntityComponent.kt b/src/main/kotlin/com/edelweiss/playerex/components/PlayerEntityComponent.kt new file mode 100644 index 00000000..a68e79b1 --- /dev/null +++ b/src/main/kotlin/com/edelweiss/playerex/components/PlayerEntityComponent.kt @@ -0,0 +1,18 @@ +package com.edelweiss.playerex.components + +import dev.onyxstudios.cca.api.v3.component.sync.AutoSyncedComponent +import dev.onyxstudios.cca.api.v3.entity.PlayerComponent +import net.minecraft.entity.player.PlayerEntity +import net.minecraft.nbt.NbtCompound + +class PlayerEntityComponent(private val provider: PlayerEntity) : PlayerComponent, AutoSyncedComponent { + companion object {} + + override fun readFromNbt(tag: NbtCompound) { + + } + + override fun writeToNbt(tag: NbtCompound) { + + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/edelweiss/playerex/constants/EntityAttributes.kt b/src/main/kotlin/com/edelweiss/playerex/constants/EntityAttributes.kt new file mode 100644 index 00000000..7c465c54 --- /dev/null +++ b/src/main/kotlin/com/edelweiss/playerex/constants/EntityAttributes.kt @@ -0,0 +1,29 @@ +package com.edelweiss.playerex.constants + +import com.edelweiss.playerex.api.PlayerEXAPI +import net.minecraft.util.Identifier + +enum class EntityAttributes(val id: Identifier) { + Luck(PlayerEXAPI.id("luck")), + Level(PlayerEXAPI.id("level")), + Focus(PlayerEXAPI.id("focus")), + Evasion(PlayerEXAPI.id("evasion")), + Lifesteal(PlayerEXAPI.id("lifesteal")), + Strength(PlayerEXAPI.id("strength")), + Dexterity(PlayerEXAPI.id("dexterity")), + Intelligence(PlayerEXAPI.id("intelligence")), + Constitution(PlayerEXAPI.id("constitution")), + BreakingSpeed(PlayerEXAPI.id("breaking_speed")), + HealthRegeneration(PlayerEXAPI.id("health_regeneration")), + HealAmplification(PlayerEXAPI.id("heal_amplification")), + MeleeCritDamage(PlayerEXAPI.id("melee_crit_damage")), + MeleeCritChance(PlayerEXAPI.id("melee_crit_chance")), + RangedCritDamage(PlayerEXAPI.id("ranged_crit_damage")), + RangedCritChance(PlayerEXAPI.id("ranged_crit_chance")), + RangedBonusDamage(PlayerEXAPI.id("ranged_damage")), + FireResistance(PlayerEXAPI.id("fire_resistance")), + FreezeResistance(PlayerEXAPI.id("freeze_resistance")), + LightningResistance(PlayerEXAPI.id("lightning_resistance")), + PoisonResistance(PlayerEXAPI.id("poison_resistance")), + WitherResistance(PlayerEXAPI.id("wither_resistance")), +} \ No newline at end of file diff --git a/src/main/kotlin/com/edelweiss/playerex/constants/PlayerEXDCAttributes.kt b/src/main/kotlin/com/edelweiss/playerex/constants/PlayerEXDCAttributes.kt deleted file mode 100644 index c588651d..00000000 --- a/src/main/kotlin/com/edelweiss/playerex/constants/PlayerEXDCAttributes.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.edelweiss.playerex.constants - -enum class PlayerEXDCAttributes(val tag: String) { - Constitution("constitution"), - Strength("strength"), - Dexterity("dexterity"), - Intelligence("intelligence"), - Focus("focus"), - Luck("luck") -} \ No newline at end of file diff --git a/src/main/kotlin/com/edelweiss/playerex/constants/StackingBehaviors.kt b/src/main/kotlin/com/edelweiss/playerex/constants/StackingBehaviors.kt new file mode 100644 index 00000000..b48c915e --- /dev/null +++ b/src/main/kotlin/com/edelweiss/playerex/constants/StackingBehaviors.kt @@ -0,0 +1,6 @@ +package com.edelweiss.playerex.constants + +enum class StackingBehaviors { + Flat, + Diminishing +} \ No newline at end of file diff --git a/src/main/kotlin/com/edelweiss/playerex/listeners/ServerEventListeners.kt b/src/main/kotlin/com/edelweiss/playerex/listeners/ServerEventListeners.kt new file mode 100644 index 00000000..f48799b7 --- /dev/null +++ b/src/main/kotlin/com/edelweiss/playerex/listeners/ServerEventListeners.kt @@ -0,0 +1,16 @@ +package com.edelweiss.playerex.listeners + +import com.edelweiss.playerex.PlayerEXComponents +import net.minecraft.server.MinecraftServer +import net.minecraft.server.network.ServerPlayerEntity + +object ServerEventListeners { + fun serverStarting(server: MinecraftServer) { + + } + + /** Before a player respawns, copy old data to another player. */ + fun reset(oldPlayer: ServerPlayerEntity, newPlayer: ServerPlayerEntity, alive: Boolean) { + PlayerEXComponents.playerEntities.get(newPlayer) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/edelweiss/playerex/values/LevelValue.kt b/src/main/kotlin/com/edelweiss/playerex/values/LevelValue.kt new file mode 100644 index 00000000..ac757632 --- /dev/null +++ b/src/main/kotlin/com/edelweiss/playerex/values/LevelValue.kt @@ -0,0 +1,40 @@ +package com.edelweiss.playerex.values + +import com.edelweiss.playerex.api.PlayerEXAPI +import com.edelweiss.playerex.cache.CachedPlayerValue +import net.minecraft.nbt.NbtCompound +import net.minecraft.server.network.ServerPlayerEntity +import net.minecraft.util.Identifier + +/** Represents a cacheable PlayerEX level. */ +class LevelValue(private val id: Identifier = PlayerEXAPI.id("level")) : CachedPlayerValue { + override fun get(player: ServerPlayerEntity): Int { + return 0 // todo: requires data attributes + } + + override fun readFromNbt(tag: NbtCompound): Int { + return tag.getInt("level") + } + + override fun writeToNbt(tag: NbtCompound, value: Any?): Boolean { + if (value is Int) { + tag.putInt("level", value) + return true + } + else return false + } + + override fun id(): Identifier = this.id + + // todo: unsure if this is needed, but will leave this here (for now) ~ Jecka + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other === null) return false + if (other !is LevelValue) return false + return this.id == other.id + } + + override fun hashCode(): Int = this.id.hashCode() + + override fun toString(): String = this.id.toString() +} \ No newline at end of file diff --git a/src/main/resources/assets/playerex-directors-cut/icon.png b/src/main/resources/assets/playerex/icon.png similarity index 100% rename from src/main/resources/assets/playerex-directors-cut/icon.png rename to src/main/resources/assets/playerex/icon.png diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 846cf478..ef1e6740 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -15,7 +15,7 @@ "sources": "https://github.com/FabricMC/fabric-example-mod" }, "license": "CC0-1.0", - "icon": "assets/playerex-directors-cut/icon.png", + "icon": "assets/playerex/icon.png", "environment": "*", "entrypoints": { "main": [ @@ -37,13 +37,13 @@ } ], "cardinal-components": [ - "com.edelweiss.playerex.PlayerEXDCEntityComponents" + "com.edelweiss.playerex.PlayerEXComponents" ] }, "mixins": [ - "playerex-directors-cut.mixins.json", + "playerex.mixins.json", { - "config": "playerex-directors-cut.client.mixins.json", + "config": "playerex.client.mixins.json", "environment": "client" } ], @@ -56,7 +56,8 @@ }, "custom": { "cardinal-components": [ - "playerex-directors-cut:living_entities" + "playerex:living_entities", + "playerex:player_entities" ] } } \ No newline at end of file diff --git a/src/main/resources/playerex-directors-cut.mixins.json b/src/main/resources/playerex-directors-cut.mixins.json deleted file mode 100644 index d9b5cd3b..00000000 --- a/src/main/resources/playerex-directors-cut.mixins.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "required": true, - "package": "com.edelweiss.playerex.mixin", - "compatibilityLevel": "JAVA_17", - "mixins": [ - ], - "injectors": { - "defaultRequire": 1 - } -} \ No newline at end of file diff --git a/src/main/resources/playerex.mixins.json b/src/main/resources/playerex.mixins.json new file mode 100644 index 00000000..6248f963 --- /dev/null +++ b/src/main/resources/playerex.mixins.json @@ -0,0 +1,13 @@ +{ + "required": true, + "package": "com.edelweiss.playerex.mixin", + "compatibilityLevel": "JAVA_17", + "mixins": [ + "LevelPropertiesMixin", + "PlayerManagerMixin", + "UnmodifiableLevelPropertiesMixin" + ], + "injectors": { + "defaultRequire": 1 + } +} \ No newline at end of file