diff --git a/common/src/main/kotlin/com/rafacasari/mod/cobbledex/Cobbledex.kt b/common/src/main/kotlin/com/rafacasari/mod/cobbledex/Cobbledex.kt index 090982f..46dd590 100644 --- a/common/src/main/kotlin/com/rafacasari/mod/cobbledex/Cobbledex.kt +++ b/common/src/main/kotlin/com/rafacasari/mod/cobbledex/Cobbledex.kt @@ -9,6 +9,8 @@ import com.cobblemon.mod.common.api.text.onHover import com.cobblemon.mod.common.platform.events.PlatformEvents import com.cobblemon.mod.common.platform.events.ServerPlayerEvent import com.cobblemon.mod.common.pokemon.FormData +import com.cobblemon.mod.common.util.server +import com.rafacasari.mod.cobbledex.api.CobbledexCoopDiscovery import com.rafacasari.mod.cobbledex.api.CobbledexDiscovery import com.rafacasari.mod.cobbledex.api.classes.DiscoveryRegister import com.rafacasari.mod.cobbledex.client.gui.CobbledexCollectionGUI @@ -23,10 +25,13 @@ import com.rafacasari.mod.cobbledex.network.client.packets.ReceiveCollectionData import com.rafacasari.mod.cobbledex.utils.MiscUtils.cobbledexTextTranslation import com.rafacasari.mod.cobbledex.utils.MiscUtils.logInfo import net.minecraft.server.network.ServerPlayerEntity +import net.minecraft.text.Text import net.minecraft.util.Formatting +import net.minecraft.util.WorldSavePath import java.io.File import java.io.FileReader import java.io.FileWriter +import java.nio.file.Paths object Cobbledex { private lateinit var config: CobbledexConfig @@ -48,10 +53,12 @@ object Cobbledex { implementation.registerItems() loadConfig() - PlatformEvents.SERVER_STARTED.subscribe { _ -> + PlatformEvents.SERVER_STARTED.subscribe { serverEvent -> logInfo("Server initialized...") PlayerDataExtensionRegistry.register(CobbledexDiscovery.NAME_KEY, CobbledexDiscovery::class.java) + val serverPath = serverEvent.server.getSavePath(WorldSavePath.ROOT).toAbsolutePath() + CobbledexCoopDiscovery.load(Paths.get(serverPath.toString(), "cobbledex-coop.json").toString()) if (!eventsCreated) { CobblemonEvents.STARTER_CHOSEN.subscribe(Priority.LOW) { @@ -74,6 +81,18 @@ object Cobbledex { registerPlayerDiscovery(player, it.pokemon.form, it.pokemon.shiny, DiscoveryRegister.RegisterType.CAUGHT) } + CobblemonEvents.TRADE_COMPLETED.subscribe(Priority.LOW) { + serverEvent.server.playerManager.getPlayer(it.tradeParticipant1.uuid)?.let { player -> + val pokemon = it.tradeParticipant2Pokemon + registerPlayerDiscovery(player, pokemon.form, pokemon.shiny, DiscoveryRegister.RegisterType.CAUGHT) + } + + serverEvent.server.playerManager.getPlayer(it.tradeParticipant2.uuid)?.let { player -> + val pokemon = it.tradeParticipant1Pokemon + registerPlayerDiscovery(player, pokemon.form, pokemon.shiny, DiscoveryRegister.RegisterType.CAUGHT) + } + } + // This should prevent events from being added more than once eventsCreated = true } @@ -89,10 +108,18 @@ object Cobbledex { } PlatformEvents.SERVER_PLAYER_LOGIN.subscribe { login: ServerPlayerEvent.Login -> + if (config.CoopMode) { + val discoveryData = CobbledexCoopDiscovery.getDiscovery() + if (discoveryData != null) { + ReceiveCollectionDataPacket(discoveryData.registers).sendToPlayer(login.player) + } + } + else { + val cobbledexData = CobbledexDiscovery.getPlayerData(login.player) + val registers = cobbledexData.registers + ReceiveCollectionDataPacket(registers).sendToPlayer(login.player) + } - val cobbledexData = CobbledexDiscovery.getPlayerData(login.player) - val registers = cobbledexData.registers - ReceiveCollectionDataPacket(registers).sendToPlayer(login.player) getConfig().syncPlayer(login.player) } } @@ -110,9 +137,28 @@ object Cobbledex { if (formData == null) return ActionResult.PASS - if(CobbledexDiscovery.addOrUpdatePlayer(player, formData, isShiny, type) { newEntry -> + val isANewDiscovery = CobbledexDiscovery.addOrUpdatePlayer(player, formData, isShiny, type) { newEntry -> AddToCollectionPacket(formData, newEntry).sendToPlayer(player) - }) { + } + + val isANewCoopDiscovery = CobbledexCoopDiscovery.addOrUpdateCoop(formData, isShiny, type) { newEntry -> + if (config.CoopMode) + AddToCollectionPacket(formData, newEntry).sendToAllPlayers() + } + + if(isANewCoopDiscovery && config.CoopMode) { + val translation = cobbledexTextTranslation("new_pokemon_discovered_coop", Text.literal(player.gameProfile.name).bold(), formData.species.translatedName.bold().formatted(Formatting.GREEN).onClick { + OpenCobbledexPacket(formData).sendToPlayer(it) + }.onHover(cobbledexTextTranslation("click_to_open_cobbledex"))) + + server()?.let { server -> + server.playerManager.playerList.forEach { serverPlayer -> + serverPlayer.sendMessage(translation) + } + } + } + + if(isANewDiscovery && !config.CoopMode) { val translation = cobbledexTextTranslation("new_pokemon_discovered", formData.species.translatedName.bold().formatted(Formatting.GREEN).onClick { OpenCobbledexPacket(formData).sendToPlayer(it) }.onHover(cobbledexTextTranslation("click_to_open_cobbledex"))) diff --git a/common/src/main/kotlin/com/rafacasari/mod/cobbledex/CobbledexConfig.kt b/common/src/main/kotlin/com/rafacasari/mod/cobbledex/CobbledexConfig.kt index 8724afe..7a40944 100644 --- a/common/src/main/kotlin/com/rafacasari/mod/cobbledex/CobbledexConfig.kt +++ b/common/src/main/kotlin/com/rafacasari/mod/cobbledex/CobbledexConfig.kt @@ -9,6 +9,7 @@ import net.minecraft.server.network.ServerPlayerEntity class CobbledexConfig : IEncodable { + var CoopMode = false var GiveCobbledexItemOnStarterChosen = true var HowToFind_IsEnabled = true @@ -36,6 +37,8 @@ class CobbledexConfig : IEncodable { fun decode(reader: PacketByteBuf) : CobbledexConfig { val config = CobbledexConfig() + config.CoopMode = reader.readBoolean() + config.HowToFind_IsEnabled = reader.readBoolean() config.HowToFind_NeedSeen = reader.readBoolean() config.HowToFind_NeedCatch = reader.readBoolean() @@ -67,6 +70,8 @@ class CobbledexConfig : IEncodable { } override fun encode(buffer: PacketByteBuf) { + buffer.writeBoolean(CoopMode) + buffer.writeBoolean(HowToFind_IsEnabled) buffer.writeBoolean(HowToFind_NeedSeen) buffer.writeBoolean(HowToFind_NeedCatch) diff --git a/common/src/main/kotlin/com/rafacasari/mod/cobbledex/api/CobbledexCoopDiscovery.kt b/common/src/main/kotlin/com/rafacasari/mod/cobbledex/api/CobbledexCoopDiscovery.kt new file mode 100644 index 0000000..b8bc17b --- /dev/null +++ b/common/src/main/kotlin/com/rafacasari/mod/cobbledex/api/CobbledexCoopDiscovery.kt @@ -0,0 +1,163 @@ +package com.rafacasari.mod.cobbledex.api + +import com.cobblemon.mod.common.pokemon.FormData +import com.google.gson.GsonBuilder +import com.rafacasari.mod.cobbledex.api.classes.DiscoveryRegister +import com.rafacasari.mod.cobbledex.utils.MiscUtils.logDebug +import com.rafacasari.mod.cobbledex.utils.MiscUtils.logError +import com.rafacasari.mod.cobbledex.utils.MiscUtils.logInfo +import com.rafacasari.mod.cobbledex.utils.MiscUtils.logWarn +import java.io.File +import java.io.FileReader +import java.io.FileWriter + +class CobbledexCoopDiscovery(val registers: MutableMap> = mutableMapOf()) { + companion object { + private val GSON = GsonBuilder() + .disableHtmlEscaping() + .setPrettyPrinting() + .create() + + private var isInitialized: Boolean =false + private lateinit var discovery: CobbledexCoopDiscovery + + private lateinit var filePath: String + fun getDiscovery() : CobbledexCoopDiscovery? + { + if (!isInitialized) + logWarn("Called getDiscovery before initialization") + + return if (this::discovery.isInitialized) discovery else null + } + + fun load(path: String) { + if (isInitialized) { + logWarn("CobbledexCoopDiscovery.load was called twice!") + return + } + + isInitialized = true + filePath = path + + logInfo("Loading CobbledexCoopDiscovery at \"${filePath}\"...") + val configFile = File(path) + configFile.parentFile.mkdirs() + + if (configFile.exists()) { + try { + val fileReader = FileReader(configFile) + discovery = GSON.fromJson(fileReader, CobbledexCoopDiscovery::class.java) + fileReader.close() + } catch (error: Exception) { + logError("COOP Cobbledex Discovery failed to load, using default file instead!") + discovery = CobbledexCoopDiscovery() + error.printStackTrace() + } + } else { + discovery = CobbledexCoopDiscovery() + } + + this.save() + } + + fun save() { + if (!isInitialized) + { + logWarn("Tried to save CobbledexCoopDiscovery without loading it first") + return + } + + if (!this::filePath.isInitialized) + { + logWarn("Tried to save CobbledexCoopDiscovery without filePath being initialized") + return + } + + val discoveryRegister = getDiscovery() + if (discoveryRegister == null) { + logWarn("Tried to save CobbledexCoopDiscovery but discover variable was null (or not initialized)") + return + } + + logDebug("Saving ${discoveryRegister.registers.size} entries to $filePath") + try { + val fileWriter = FileWriter(File(filePath)) + GSON.toJson(discoveryRegister, fileWriter) + fileWriter.flush() + fileWriter.close() + } catch (exception: Exception) { + logError("Failed to save the CobbledexCoopDiscovery! Stack trace:") + exception.printStackTrace() + } + } + + fun addOrUpdateWithoutSaving(speciesShowdownId: String, formOnlyShowdownId: String, isShiny: Boolean, status: DiscoveryRegister.RegisterType, update: ((DiscoveryRegister) -> Unit)? = null): Boolean { + val data = getDiscovery() + + var returnValue = false + if (data != null) returnValue = data.addOrUpdate(speciesShowdownId, formOnlyShowdownId, isShiny, status, update) + + return returnValue + } + + fun addOrUpdateCoop(speciesShowdownId: String, formOnlyShowdownId: String, isShiny: Boolean, status: DiscoveryRegister.RegisterType, update: ((DiscoveryRegister) -> Unit)? = null): Boolean { + val returnValue = addOrUpdateWithoutSaving(speciesShowdownId, formOnlyShowdownId, isShiny, status, update) + + // Save :D + save() + return returnValue + } + + fun addOrUpdateCoopWithoutSaving(form: FormData, isShiny: Boolean, status: DiscoveryRegister.RegisterType, update: ((DiscoveryRegister) -> Unit)? = null): Boolean { + return addOrUpdateWithoutSaving(form.species.showdownId(), form.formOnlyShowdownId(), isShiny, status, update) + } + + fun addOrUpdateCoop(form: FormData, isShiny: Boolean, status: DiscoveryRegister.RegisterType, update: ((DiscoveryRegister) -> Unit)? = null): Boolean { + return addOrUpdateCoop(form.species.showdownId(), form.formOnlyShowdownId(), isShiny, status, update) + } + } + + private fun getRegister(showdownId: String): MutableMap? { + return registers[showdownId] + } + + // addOrUpdate(showdownId, onlyFormShowdownId) + // Returns if it is a new entry (meaning that should display a message in chat) + // + fun addOrUpdate(species: String, form: String, isShiny: Boolean, status: DiscoveryRegister.RegisterType, update: ((DiscoveryRegister) -> Unit)?): Boolean { + val currentRegister = getRegister(species) + + val discoverTimestamp = System.currentTimeMillis() + val caughtTimestamp = if(status == DiscoveryRegister.RegisterType.CAUGHT) discoverTimestamp else null + + if (currentRegister != null) { + val formRegister = currentRegister[form] + if (formRegister != null) { + // Update only if needed + if (!formRegister.isShiny && isShiny) + formRegister.isShiny = true + + // Update only if needed + if (formRegister.status == DiscoveryRegister.RegisterType.SEEN && status == DiscoveryRegister.RegisterType.CAUGHT) { + formRegister.status = DiscoveryRegister.RegisterType.CAUGHT + formRegister.caughtTimestamp = caughtTimestamp + } + + update?.invoke(formRegister) + return false + } else { + // New form + val newRegister = DiscoveryRegister(isShiny, status, discoverTimestamp, caughtTimestamp) + currentRegister[form] = newRegister + update?.invoke(newRegister) + return true + } + } else { + // New pokemon + val newRegister = DiscoveryRegister(isShiny, status, discoverTimestamp, caughtTimestamp) + registers[species] = mutableMapOf(form to newRegister) + update?.invoke(newRegister) + return true + } + } +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/rafacasari/mod/cobbledex/api/CobbledexDiscovery.kt b/common/src/main/kotlin/com/rafacasari/mod/cobbledex/api/CobbledexDiscovery.kt index a1166ba..16e972f 100644 --- a/common/src/main/kotlin/com/rafacasari/mod/cobbledex/api/CobbledexDiscovery.kt +++ b/common/src/main/kotlin/com/rafacasari/mod/cobbledex/api/CobbledexDiscovery.kt @@ -62,7 +62,7 @@ class CobbledexDiscovery(val registers: MutableMap Unit)?): Boolean { + fun addOrUpdate(species: String, form: String, isShiny: Boolean, status: DiscoveryRegister.RegisterType, update: ((DiscoveryRegister) -> Unit)? = null): Boolean { val currentRegister = getRegister(species) val discoverTimestamp = System.currentTimeMillis() diff --git a/common/src/main/kotlin/com/rafacasari/mod/cobbledex/client/gui/CobbledexCollectionGUI.kt b/common/src/main/kotlin/com/rafacasari/mod/cobbledex/client/gui/CobbledexCollectionGUI.kt index 07022c3..f77730d 100644 --- a/common/src/main/kotlin/com/rafacasari/mod/cobbledex/client/gui/CobbledexCollectionGUI.kt +++ b/common/src/main/kotlin/com/rafacasari/mod/cobbledex/client/gui/CobbledexCollectionGUI.kt @@ -119,9 +119,10 @@ class CobbledexCollectionGUI : Screen(cobbledexTextTranslation("cobbledex")) { } searchWidget.text = lastSearch - this.addDrawableChild(searchWidget) + setInitialFocus(searchWidget) + addDrawableChild(ImageButton(DOUBLE_LEFT_ARROW, 14, 11, x + 170, y + 175) { currentPage = 1 }) @@ -331,10 +332,10 @@ class CobbledexCollectionGUI : Screen(cobbledexTextTranslation("cobbledex")) { blitk( matrixStack = matrices, texture = CAUGHT_ICON, - x = (entryX + ENTRY_SIZE - (11 * SCALE) - 1F) / SCALE, - y = (entryY + 1F) / SCALE, - width = 11, - height = 11, + x = (entryX + ENTRY_SIZE - (11 * SCALE) - 1f) / SCALE, + y = (entryY + 0.5F) / SCALE, + width = 12, + height = 12, scale = SCALE, alpha = 0.75f ) @@ -343,11 +344,11 @@ class CobbledexCollectionGUI : Screen(cobbledexTextTranslation("cobbledex")) { blitk( matrixStack = matrices, texture = SHINY_ICON, - x = (entryX + ENTRY_SIZE - (11 * SCALE) - 1F) / SCALE, - y = (entryY + ENTRY_SIZE - (11 * SCALE) - 1) / SCALE, - width = 11, - height = 11, - scale = SCALE + x = (entryX + ENTRY_SIZE - (14 * SCALE) - 0.5F) / SCALE, + y = (entryY + ENTRY_SIZE - (14 * SCALE) - 0.5F) / SCALE, + width = 14, + height = 14, + scale = SCALE, alpha = 0.75f ) } diff --git a/common/src/main/kotlin/com/rafacasari/mod/cobbledex/client/gui/menus/BattleMenu.kt b/common/src/main/kotlin/com/rafacasari/mod/cobbledex/client/gui/menus/BattleMenu.kt index b3dea06..304bf85 100644 --- a/common/src/main/kotlin/com/rafacasari/mod/cobbledex/client/gui/menus/BattleMenu.kt +++ b/common/src/main/kotlin/com/rafacasari/mod/cobbledex/client/gui/menus/BattleMenu.kt @@ -5,34 +5,38 @@ import com.cobblemon.mod.common.api.text.bold import com.cobblemon.mod.common.api.text.text import com.cobblemon.mod.common.api.types.ElementalTypes import com.cobblemon.mod.common.pokemon.FormData -import com.rafacasari.mod.cobbledex.CobbledexConstants.Client.discoveredList -import com.rafacasari.mod.cobbledex.api.classes.DiscoveryRegister import com.rafacasari.mod.cobbledex.client.widget.LongTextDisplay -import com.rafacasari.mod.cobbledex.network.client.handlers.SyncServerSettingsHandler +import com.rafacasari.mod.cobbledex.utils.MiscUtils.cobbledexTextTranslation +import com.rafacasari.mod.cobbledex.utils.MiscUtils.format import com.rafacasari.mod.cobbledex.utils.TypeChartUtils import com.rafacasari.mod.cobbledex.utils.MiscUtils.withRGBColor -import net.minecraft.text.Text object BattleMenu { fun drawText(longTextDisplay: LongTextDisplay?, pokemon: FormData?) { if (pokemon == null || longTextDisplay == null) return - val config = SyncServerSettingsHandler.config - val registerType = discoveredList[pokemon.species.showdownId()]?.get(pokemon.formOnlyShowdownId())?.status - val hasCaught = registerType == DiscoveryRegister.RegisterType.CAUGHT - val hasSeen = hasCaught || registerType == DiscoveryRegister.RegisterType.SEEN - - +// val config = SyncServerSettingsHandler.config +// val registerType = discoveredList[pokemon.species.showdownId()]?.get(pokemon.formOnlyShowdownId())?.status +// val hasCaught = registerType == DiscoveryRegister.RegisterType.CAUGHT +// val hasSeen = hasCaught || registerType == DiscoveryRegister.RegisterType.SEEN val elementalMultipliers = ElementalTypes.all() .groupBy { TypeChartUtils.getModifier(it, pokemon.primaryType, pokemon.secondaryType) } .toSortedMap(Comparator.reverseOrder()) + if (elementalMultipliers.isNotEmpty()) { + longTextDisplay.addText(cobbledexTextTranslation("battle.title").bold()) + } + elementalMultipliers.filter { it.key != 1f }.forEach { elementalKey -> - val translation = Text.translatable("cobbledex.texts.battle.damage_from", elementalKey.key) + + val key = "battle.damage_from.multiplier_${elementalKey.key.format().replace(".", "_")}" + + val translation = cobbledexTextTranslation(key, "%.2f". format(elementalKey.key)) longTextDisplay.addText(translation) + val typesText = elementalKey.value.fold("".text()) { acc, element -> if (elementalKey.value.first() != element) acc.add(" ".text()) diff --git a/common/src/main/kotlin/com/rafacasari/mod/cobbledex/commands/server/CobbledexCommand.kt b/common/src/main/kotlin/com/rafacasari/mod/cobbledex/commands/server/CobbledexCommand.kt index 78634b5..d8449d3 100644 --- a/common/src/main/kotlin/com/rafacasari/mod/cobbledex/commands/server/CobbledexCommand.kt +++ b/common/src/main/kotlin/com/rafacasari/mod/cobbledex/commands/server/CobbledexCommand.kt @@ -4,9 +4,12 @@ import com.cobblemon.mod.common.api.permission.CobblemonPermission import com.cobblemon.mod.common.api.permission.PermissionLevel import com.cobblemon.mod.common.api.pokemon.PokemonSpecies import com.cobblemon.mod.common.api.text.bold +import com.cobblemon.mod.common.api.text.green import com.cobblemon.mod.common.api.text.red import com.cobblemon.mod.common.api.text.text import com.cobblemon.mod.common.command.argument.PokemonPropertiesArgumentType +import com.cobblemon.mod.common.util.party +import com.cobblemon.mod.common.util.pc import com.cobblemon.mod.common.util.permission import com.mojang.brigadier.Command import com.mojang.brigadier.CommandDispatcher @@ -15,17 +18,25 @@ import com.mojang.brigadier.context.CommandContext import com.mojang.brigadier.exceptions.SimpleCommandExceptionType import com.rafacasari.mod.cobbledex.Cobbledex import com.rafacasari.mod.cobbledex.CobbledexConfig +import com.rafacasari.mod.cobbledex.api.CobbledexCoopDiscovery +import com.rafacasari.mod.cobbledex.api.CobbledexDiscovery +import com.rafacasari.mod.cobbledex.api.classes.DiscoveryRegister import com.rafacasari.mod.cobbledex.commands.arguments.SettingArgumentSuggestion import com.rafacasari.mod.cobbledex.network.client.packets.OpenCobbledexPacket +import com.rafacasari.mod.cobbledex.network.client.packets.OpenDiscoveryPacket +import com.rafacasari.mod.cobbledex.network.client.packets.ReceiveCollectionDataPacket import com.rafacasari.mod.cobbledex.utils.MiscUtils.cobbledexTextTranslation import com.rafacasari.mod.cobbledex.utils.MiscUtils.logError +import net.minecraft.command.argument.EntityArgumentType import net.minecraft.server.command.CommandManager import net.minecraft.server.command.ServerCommandSource +import net.minecraft.text.Text import kotlin.reflect.* import kotlin.reflect.full.memberProperties object CobbledexCommand : IServerCommandInterface { + private val AUTO_PERMISSION = CobblemonPermission("commands.cobbledex.auto", PermissionLevel.ALL_COMMANDS) private val CONFIG_COBBLEDEX_PERMISSION = CobblemonPermission("commands.cobbledex.config", PermissionLevel.ALL_COMMANDS) private val OPEN_COBBLEDEX_PERMISSION = CobblemonPermission("commands.cobbledex.show", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS) private val OPEN_COLLECTION_PERMISSION = CobblemonPermission("commands.cobbledex.collection", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS) @@ -38,10 +49,10 @@ object CobbledexCommand : IServerCommandInterface { val propertyValue = dispatcher.createArgument("value", StringArgumentType.word()).suggests(SettingArgumentSuggestion()) + val playersArgument = CommandManager.argument("players", EntityArgumentType.players()) + val command = createLiteralArgument("cobbledex") - .then(CommandManager.literal("collection").permission(OPEN_COLLECTION_PERMISSION).executes { ctx -> - openCollection(ctx) - }) + // Add config options here .then( CommandManager.literal("config").permission(CONFIG_COBBLEDEX_PERMISSION) @@ -50,8 +61,12 @@ object CobbledexCommand : IServerCommandInterface { applySetting(ctx) })) ) + // Show Collection + .then(CommandManager.literal("collection").permission(OPEN_COLLECTION_PERMISSION).executes { ctx -> + openCollection(ctx) + }) - // + // Show Cobbledex .then( CommandManager.literal("show").permission(OPEN_COBBLEDEX_PERMISSION) .then(pokemonProperty.executes { ctx -> @@ -59,31 +74,79 @@ object CobbledexCommand : IServerCommandInterface { }) ) + // Auto get commands + .then( + CommandManager.literal("auto") + .permission(AUTO_PERMISSION) + .then(playersArgument.executes { ctx -> + executeAuto(ctx) + }) + ) + dispatcher.register(command) } catch (e: Exception) { logError("Error while registering cobbledex command!") e.printStackTrace() } } + + private fun executeAuto(ctx: CommandContext): Int { + val players = EntityArgumentType.getPlayers(ctx, "players") + players.forEach { player -> + try { + val discovery = CobbledexDiscovery.getPlayerData(player) + + discovery.registers.forEach { entry -> + entry.value.forEach { formEntry -> + CobbledexCoopDiscovery.addOrUpdateWithoutSaving(entry.key, formEntry.key, formEntry.value.isShiny, formEntry.value.status) + } + } + + val pc = player.pc() + pc.forEach { pokemon -> + discovery.addOrUpdate(pokemon.species.showdownId(), pokemon.form.formOnlyShowdownId(), pokemon.shiny, DiscoveryRegister.RegisterType.CAUGHT) + CobbledexCoopDiscovery.addOrUpdateCoopWithoutSaving(pokemon.form, pokemon.shiny, DiscoveryRegister.RegisterType.CAUGHT) + } + + val party = player.party() + party.forEach { pokemon -> + discovery.addOrUpdate(pokemon.species.showdownId(), pokemon.form.formOnlyShowdownId(), pokemon.shiny, DiscoveryRegister.RegisterType.CAUGHT) + CobbledexCoopDiscovery.addOrUpdateCoopWithoutSaving(pokemon.form, pokemon.shiny, DiscoveryRegister.RegisterType.CAUGHT) + } + + if (Cobbledex.getConfig().CoopMode) + CobbledexCoopDiscovery.getDiscovery()?.registers?.let { + ReceiveCollectionDataPacket(it).sendToPlayer(player) + } + else + ReceiveCollectionDataPacket(discovery.registers).sendToPlayer(player) + } catch (_: Exception) { + // Suppress any error + } + + } + + CobbledexCoopDiscovery.save() + ctx.source.sendMessage(Text.literal("Successfully updated player(s)").bold().green()) + return Command.SINGLE_SUCCESS + } + private val UNKNOWN_PROPERTY_EXCEPTION = SimpleCommandExceptionType("Unknown property!".text().red()) private val WRONG_VALUE_EXCEPTION = SimpleCommandExceptionType("Unknown property!".text().red()) private fun getSetting(ctx: CommandContext): Int { - val option = StringArgumentType.getString(ctx, "option") val property = CobbledexConfig::class.memberProperties.find { it.name.lowercase() == option.lowercase() } ?: throw UNKNOWN_PROPERTY_EXCEPTION.create() val getValue = property.get(Cobbledex.getConfig()).toString() ctx.source.sendMessage(cobbledexTextTranslation("commands.current_setting", option.text().bold(), getValue.text().bold())) - return Command.SINGLE_SUCCESS } private fun applySetting(ctx: CommandContext): Int { - val option = StringArgumentType.getString(ctx, "option") val value = StringArgumentType.getString(ctx, "value").lowercase() @@ -98,17 +161,27 @@ object CobbledexCommand : IServerCommandInterface { ctx.source.sendMessage(cobbledexTextTranslation("commands.successfully_applied", option.text().bold(), getValue.text().bold())) Cobbledex.saveConfig() + if (property.name == CobbledexConfig::CoopMode.name) { + ctx.source.server.playerManager.playerList.forEach { player -> + if (config.CoopMode) + CobbledexCoopDiscovery.getDiscovery()?.registers?.let { + ReceiveCollectionDataPacket(it).sendToPlayer(player) + } + else { + val discovery = CobbledexDiscovery.getPlayerData(player) + ReceiveCollectionDataPacket(discovery.registers).sendToPlayer(player) + } + } + } + config.syncEveryone() } - - - return Command.SINGLE_SUCCESS } private fun openCollection(ctx: CommandContext): Int { ctx.source.player?.let { player -> - // TODO: Create Show Collection packet + OpenDiscoveryPacket().sendToPlayer(player) } return Command.SINGLE_SUCCESS @@ -128,7 +201,6 @@ object CobbledexCommand : IServerCommandInterface { OpenCobbledexPacket(species.getForm(properties.aspects)).sendToPlayer(player) } - return Command.SINGLE_SUCCESS } } \ No newline at end of file diff --git a/common/src/main/kotlin/com/rafacasari/mod/cobbledex/network/CobbledexNetwork.kt b/common/src/main/kotlin/com/rafacasari/mod/cobbledex/network/CobbledexNetwork.kt index a623bd2..2896a9f 100644 --- a/common/src/main/kotlin/com/rafacasari/mod/cobbledex/network/CobbledexNetwork.kt +++ b/common/src/main/kotlin/com/rafacasari/mod/cobbledex/network/CobbledexNetwork.kt @@ -23,6 +23,7 @@ object CobbledexNetwork { createClientBound(OpenCobbledexPacket.ID, OpenCobbledexPacket::decode, OpenCobbledexHandler) createClientBound(ReceiveCollectionDataPacket.ID, ReceiveCollectionDataPacket::decode, ReceiveCollectionDataHandler) createClientBound(SyncServerSettingsPacket.ID, SyncServerSettingsPacket::decode, SyncServerSettingsHandler) + createClientBound(OpenDiscoveryPacket.ID, OpenDiscoveryPacket::decode, OpenDiscoveryHandler) } fun registerServerBound() { diff --git a/common/src/main/kotlin/com/rafacasari/mod/cobbledex/network/client/handlers/OpenDiscoveryHandler.kt b/common/src/main/kotlin/com/rafacasari/mod/cobbledex/network/client/handlers/OpenDiscoveryHandler.kt new file mode 100644 index 0000000..be8c74c --- /dev/null +++ b/common/src/main/kotlin/com/rafacasari/mod/cobbledex/network/client/handlers/OpenDiscoveryHandler.kt @@ -0,0 +1,12 @@ +package com.rafacasari.mod.cobbledex.network.client.handlers + +import com.rafacasari.mod.cobbledex.client.gui.CobbledexCollectionGUI +import com.rafacasari.mod.cobbledex.network.client.IClientNetworkPacketHandler +import com.rafacasari.mod.cobbledex.network.client.packets.OpenDiscoveryPacket +import net.minecraft.client.MinecraftClient + +object OpenDiscoveryHandler : IClientNetworkPacketHandler { + override fun handle(packet: OpenDiscoveryPacket, client: MinecraftClient) { + CobbledexCollectionGUI.show() + } +} \ No newline at end of file diff --git a/common/src/main/kotlin/com/rafacasari/mod/cobbledex/network/client/packets/OpenDiscoveryPacket.kt b/common/src/main/kotlin/com/rafacasari/mod/cobbledex/network/client/packets/OpenDiscoveryPacket.kt new file mode 100644 index 0000000..02a161a --- /dev/null +++ b/common/src/main/kotlin/com/rafacasari/mod/cobbledex/network/client/packets/OpenDiscoveryPacket.kt @@ -0,0 +1,20 @@ +package com.rafacasari.mod.cobbledex.network.client.packets + +import com.rafacasari.mod.cobbledex.network.INetworkPacket +import net.minecraft.network.PacketByteBuf +import net.minecraft.util.Identifier + +class OpenDiscoveryPacket internal constructor(): INetworkPacket { + + override val id = ID + override fun encode(buffer: PacketByteBuf) { + + } + + companion object{ + val ID = Identifier("cobbledex", "force_open_discovery") + fun decode(reader: PacketByteBuf) : OpenDiscoveryPacket { + return OpenDiscoveryPacket() + } + } +} \ No newline at end of file diff --git a/common/src/main/resources/assets/cobbledex/lang/en_us.json b/common/src/main/resources/assets/cobbledex/lang/en_us.json index 5f89859..bbcdcbc 100644 --- a/common/src/main/resources/assets/cobbledex/lang/en_us.json +++ b/common/src/main/resources/assets/cobbledex/lang/en_us.json @@ -37,8 +37,16 @@ "cobbledex.texts.need.view_drops": "view drops", "cobbledex.texts.not_a_pokemon": "That's not a Pokémon!", + "cobbledex.texts.battle.title": "Damage Multipliers", + "cobbledex.texts.battle.damage_from.multiplier_4": "%sx | §lSuper Weak§r against:", + "cobbledex.texts.battle.damage_from.multiplier_2": "%sx | §lWeak§r against:", + "cobbledex.texts.battle.damage_from.multiplier_0_5": "%sx | §lResistant§r against:", + "cobbledex.texts.battle.damage_from.multiplier_0_25": "%sx | §lSuper Resistant§r against:", + "cobbledex.texts.battle.damage_from.multiplier_0": "%sx | §lImmune§r against:", + "cobbledex.texts.tooltip.hold_shift_timestamp": "Hold for timestamps", "cobbledex.texts.new_pokemon_discovered": "You've discovered a new Pokémon: %s", + "cobbledex.texts.new_pokemon_discovered_coop": "%s discovered a new Pokémon: %s", "cobbledex.texts.click_to_open_cobbledex": "Click to open in Cobbledex", "cobbledex.texts.tooltip_description.discovered": "Discovered: %s/%s (%s)", "cobbledex.texts.tooltip_description.total_forms_discovered": "Forms discovered: %s", @@ -93,6 +101,25 @@ "cobblemon.evolution/rowlet_dartrix_hisui_bias": "Hisui", "cobblemon.evolution/cyndaquil_quilava_hisui_bias": "Hisui", "cobblemon.evolution/oshawott_dewott_hisui_bias": "Hisui", + "cobblemon.evolution/sliggoo_hisuian": "Hisui", + + "structure.cobblemon.ruins/crumbling_arch_ruins": "Crumbling Arch Ruins", + "structure.cobblemon.ruins/decaying_crypt_ruins": "Decaying Crypt Ruins", + "structure.cobblemon.ruins/deserted_gimmi_tower": "Deserted Gimmi Tower", + "structure.cobblemon.ruins/deserted_house_ruins": "Deserted House Ruins", + "structure.cobblemon.ruins/deserted_tower_ruins": "Deserted Tower Ruins", + "structure.cobblemon.ruins/deserted_town_center_ruins": "Deserted Town Center Ruins", + "structure.cobblemon.ruins/fallen_statue_ruins": "Fallen Statue Ruins", + "structure.cobblemon.ruins/frozen_gimmi_tower": "Frozen Gimmi Tower", + "structure.cobblemon.ruins/hidden_bunker_ruins": "Hidden Bunker Ruins", + "structure.cobblemon.ruins/lush_gimmi_tower": "Lush Gimmi Tower", + "structure.cobblemon.ruins/mossy_oubliette_ruins": "Mossy Oubliette Ruins", + "structure.cobblemon.ruins/rooted_arch_ruins": "Rooted Arch Ruins", + "structure.cobblemon.ruins/rooted_gimmi_tower": "Rooted Gimmi Tower", + "structure.cobblemon.ruins/sunscorched_gimmi_tower": "Sunscorched Gimmi Tower", + "structure.cobblemon.ruins/temperate_gimmi_tower": "Temperate Gimmi Tower", + "structure.cobblemon.ruins/toppled_pillars_ruins": "Toppled Pillars Ruins", + "structure.cobblemon.ruins/unstable_cave_ruins": "Unstable Cave Ruins", "the_bumblezone.the_bumblezone": "Bumblezone", @@ -114,6 +141,12 @@ "structure.minecraft.ruinedportal": "Ruined Portal", "structure.minecraft.pillager_outpost": "Pillar Outpost", "structure.minecraft.swamp_hut": "Swamp Hut", + "structure.minecraft.desert_pyramid": "Desert Pyramid", + "structure.minecraft.desert_well": "Desert Well", + "structure.minecraft.jungle_pyramid": "Jungle Pyramid", + "structure.minecraft.ancient_city": "Ancient City", + "structure.minecraft.nether_fossil": "Nether Fossil", + "structure.minecraft.trail_ruins": "Trail Ruins", "minecraft.is_void": "The Void", "minecraft.is_end": "The End", diff --git a/common/src/main/resources/assets/cobbledex/lang/es_es.json b/common/src/main/resources/assets/cobbledex/lang/es_es.json index 0a35c70..3ea0f3f 100644 --- a/common/src/main/resources/assets/cobbledex/lang/es_es.json +++ b/common/src/main/resources/assets/cobbledex/lang/es_es.json @@ -1,5 +1,4 @@ { - "cobbledex.errors.NotAPokemon": "¡Eso no es un Pokémon!", "item.cobbledex.cobbledex_item": "Cobbledex", "cobbledex.texts.cobbledex": "Cobbledex", "cobbledex.texts.weakness": "Es débil contra", @@ -8,9 +7,113 @@ "cobbledex.texts.biomes": "Dónde encontrar:", "cobbledex.texts.drops": "Objetos que lleva:", "cobbledex.texts.pokedex_number": "N.º Pokedex", - "cobbledex.texts.evolutions": "Evoluciones", + "cobbledex.texts.evolutions": "Evolución", + "cobbledex.texts.preevolutions": "Pre-evolución", + "cobbledex.texts.forms": "Formas", "cobbledex.texts.weight": "Peso", "cobbledex.texts.height": "Altura", + "cobbledex.texts.select": "Seleccionar", + "cobbledex.texts.battle.damage_from": "%sx damage from:", + "cobbledex.texts.tab.info": "Info", + "cobbledex.texts.tab.battle": "Battle", + "cobbledex.texts.tab.evolve": "Evolve", + "cobbledex.texts.search": "Buscar", + "cobbledex.texts.commands.current_setting": "%s is currently set to %s", + "cobbledex.texts.commands.successfully_applied": "§a✔ Aplicado:§r %s set to %s", + "cobbledex.texts.discovery_status": "Estado: %s", + "cobbledex.texts.discovery_status.discovered": "Visto", + "cobbledex.texts.discovery_status.caught": "Atrapado", + "cobbledex.texts.shiny": "Shiny!", + "cobbledex.texts.discovered_on": "Visto: %s", + "cobbledex.texts.caught_on": "Atrapado: %s", + "cobbledex.texts.info.height_value": "%sm", + "cobbledex.texts.info.weight_value": "%skg", + "cobbledex.texts.no_drops_found": "No se encontraron objetos", + "cobbledex.texts.blocked_by_server": "Esta función está deshabilitada en este servidor", + "cobbledex.texts.need_seen": "Debes §lver§r a este Pokémon para poder ver su %s!", + "cobbledex.texts.need_catch": "Debes §latrapar§r a este Pokémon para poder ver su %s!", + "cobbledex.texts.need.view_evolutions": "evolución", + "cobbledex.texts.need.view_spawns": "spawn", + "cobbledex.texts.need.view_drops": "objeto", + "cobbledex.texts.not_a_pokemon": "¡Eso no es un Pokémon!", + + "cobbledex.texts.tooltip.hold_shift_timestamp": "Presiona para ver marcas de tiempo", + "cobbledex.texts.new_pokemon_discovered": "%s ha sido registrado en la Cobbledex", + "cobbledex.texts.click_to_open_cobbledex": "Pulsa para abrir en la Cobbledex", + "cobbledex.texts.tooltip_description.discovered": "Vistos: %s/%s (%s)", + "cobbledex.texts.tooltip_description.total_forms_discovered": "Formas vistas: %s", + "cobbledex.texts.tooltip_description.caught": "Atrapados: %s/%s (%s)", + "cobbledex.texts.tooltip_description.total_forms_caught": "Formas atrapadas: %s", + "cobbledex.texts.tooltip_description.press_shift": "Presiona para ver las instrucciones", + "cobbledex.texts.tooltip_description.instructions1": "§a§lClick-Derecho§r en un Pokémon para marcarlo como visto", + "cobbledex.texts.tooltip_description.instructions2": "§a§lClick-Derecho§r en un Pokémon para abrir la §lInformación§r", + "cobbledex.texts.tooltip_description.instructions3": "§a§lClick-Derecho§r en el aire para abrir el §lúltimo Pokémon visto§r", + "cobbledex.texts.tooltip_description.instructions4": "§a§lShift + Click-Derecho§r para abrir la §lColección§r", + "cobbledex.texts.drops.item": "%s | %s%% | %sx", + "cobbledex.texts.weather.clear": "Despejado", + "cobbledex.texts.weather.raining": "Lloviendo", + "cobbledex.texts.weather.thundering": "Tormenta eléctrica", + "cobbledex.texts.weather.raining_and_thundering": "Lloviendo y con tormenta eléctrica", + "cobbledex.texts.no_evolution_found": "No se ha encontrado ninguna evolución para %s.", + + "cobbledex.evolution.use_item": "Usando %s", + "cobbledex.evolution.trade_any": "Usando %s o intercambiando con otro entrenador", + "cobbledex.evolution.trade_specific": "Intercambiando por un %s o usa un %s", + "cobbledex.evolution.damage_taken": "Necesita %s de daño recibido", + "cobbledex.evolution.level": "Evoluciona al nivel: %s", + "cobbledex.evolution.friendship": "Amistad: %s", + "cobbledex.evolution.held_item": "Necesita tener el objeto equipado: %s", + "cobbledex.evolution.any_requirement": "Necesita alguno de estos requisitos:", + "cobbledex.evolution.attack_defence_ratio.attack_higher": "Necesita más ataque que defensa", + "cobbledex.evolution.attack_defence_ratio.defence_higher": "Necesita más defensa que ataque", + "cobbledex.evolution.attack_defence_ratio.equal": "Necesita valores iguales de ataque y defensa", + "cobbledex.evolution.battle_critical_hits": "Necesita %s golpes críticos en batalla", + "cobbledex.evolution.blocks_traveled": "Necesita recorrer %s bloques", + "cobbledex.evolution.defeat": "Necesita ser derrotado %s veces", + "cobbledex.evolution.move_set": "Subiendo un nivel y necesita movimiento %s", + "cobbledex.evolution.move_type": "Subiendo un nivel y necesita conocer un movimiento de tipo %s", + "cobbledex.evolution.party_member": "Necesita un %s en tu equipo", + "cobbledex.evolution.player_has_advancement": "El entrenador necesita avance %s", + "cobbledex.evolution.property_range": "Necesita %s entre %s", + "cobbledex.evolution.recoil": "Necesita %s de retroceso", + "cobbledex.evolution.stat_equal": "Las estadísticas %s y %s necesitan ser iguales", + "cobbledex.evolution.stat_compare": "La estadística %s debe ser mayor que %s", + "cobbledex.evolution.time_range": "Necesita hora del día: %s", + "cobbledex.evolution.use_move": "Necesita usar el movimiento %s %s veces", + "cobbledex.evolution.weather": "Necesita clima: %s", + "cobbledex.evolution.biome.condition": "Necesita estar en el bioma: %s", + "cobbledex.evolution.biome.anti_condition": "Bioma en lista negra: %s", + "cobbledex.evolution.world": "Necesita Mundo: %s", + "cobbledex.evolution.moon_phase": "Necesita fase lunar: %s", + "cobbledex.evolution.structure.condition": "Necesita estructura: %s", + "cobbledex.evolution.structure.anti_condition": "Estructura en lista negra: %s", + + "cobblemon.evolution/alolan": "Alola", + "cobblemon.evolution/hisui": "Hisui", + "cobblemon.evolution/rowlet_dartrix_hisui_bias": "Hisui", + "cobblemon.evolution/cyndaquil_quilava_hisui_bias": "Hisui", + "cobblemon.evolution/oshawott_dewott_hisui_bias": "Hisui", + "cobblemon.evolution/sliggoo_hisuian": "Hisui", + + "structure.cobblemon.ruins/crumbling_arch_ruins": "Crumbling Arch Ruins", + "structure.cobblemon.ruins/decaying_crypt_ruins": "Decaying Crypt Ruins", + "structure.cobblemon.ruins/deserted_gimmi_tower": "Deserted Gimmi Tower", + "structure.cobblemon.ruins/deserted_house_ruins": "Deserted House Ruins", + "structure.cobblemon.ruins/deserted_tower_ruins": "Deserted Tower Ruins", + "structure.cobblemon.ruins/deserted_town_center_ruins": "Deserted Town Center Ruins", + "structure.cobblemon.ruins/fallen_statue_ruins": "Fallen Statue Ruins", + "structure.cobblemon.ruins/frozen_gimmi_tower": "Frozen Gimmi Tower", + "structure.cobblemon.ruins/hidden_bunker_ruins": "Hidden Bunker Ruins", + "structure.cobblemon.ruins/lush_gimmi_tower": "Lush Gimmi Tower", + "structure.cobblemon.ruins/mossy_oubliette_ruins": "Mossy Oubliette Ruins", + "structure.cobblemon.ruins/rooted_arch_ruins": "Rooted Arch Ruins", + "structure.cobblemon.ruins/rooted_gimmi_tower": "Rooted Gimmi Tower", + "structure.cobblemon.ruins/sunscorched_gimmi_tower": "Sunscorched Gimmi Tower", + "structure.cobblemon.ruins/temperate_gimmi_tower": "Temperate Gimmi Tower", + "structure.cobblemon.ruins/toppled_pillars_ruins": "Toppled Pillars Ruins", + "structure.cobblemon.ruins/unstable_cave_ruins": "Unstable Cave Ruins", + + "the_bumblezone.the_bumblezone": "Bumblezone", "structure.minecraft.endcity": "End City", "structure.minecraft.fortress": "Nether Fortress", @@ -30,6 +133,12 @@ "structure.minecraft.ruinedportal": "Ruined Portal", "structure.minecraft.pillager_outpost": "Pillar Outpost", "structure.minecraft.swamp_hut": "Swamp Hut", + "structure.minecraft.desert_pyramid": "Desert Pyramid", + "structure.minecraft.desert_well": "Desert Well", + "structure.minecraft.jungle_pyramid": "Jungle Pyramid", + "structure.minecraft.ancient_city": "Ancient City", + "structure.minecraft.nether_fossil": "Nether Fossil", + "structure.minecraft.trail_ruins": "Trail Ruins", "minecraft.is_void": "The Void", "minecraft.is_end": "The End", @@ -102,4 +211,5 @@ "cobblemon.nether/is_toxic": "Toxic", "cobblemon.nether/is_warped": "Warped", "cobblemon.nether/is_wasteland": "Wasteland" + } \ No newline at end of file diff --git a/common/src/main/resources/assets/cobbledex/textures/gui/collection/pokeball.png b/common/src/main/resources/assets/cobbledex/textures/gui/collection/pokeball.png index 7cbc92f..0db63b8 100644 Binary files a/common/src/main/resources/assets/cobbledex/textures/gui/collection/pokeball.png and b/common/src/main/resources/assets/cobbledex/textures/gui/collection/pokeball.png differ diff --git a/common/src/main/resources/assets/cobbledex/textures/gui/collection/shiny_icon.png b/common/src/main/resources/assets/cobbledex/textures/gui/collection/shiny_icon.png index d1f4bad..0670b9a 100644 Binary files a/common/src/main/resources/assets/cobbledex/textures/gui/collection/shiny_icon.png and b/common/src/main/resources/assets/cobbledex/textures/gui/collection/shiny_icon.png differ diff --git a/gradle.properties b/gradle.properties index 6d85040..6f50f1e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,7 +8,7 @@ mod_id=cobbledex generated_file_name_addon=-1.20.1 archives_base_name=cobbledex-1.20.1 -mod_version=1.0.31 +mod_version=1.0.32 mod_description=A mod to track your progress on Cobblemon. Fabric and Forge compatible. mod_icon=assets/cobbledex/icon.png repository=https://github.com/rafacasari/cobbledex