mirror of
https://gitlab.com/cable-mc/cobblemon.git
synced 2026-10-25 00:26:26 -04:00
Compare commits
114
Commits
form-registry
...
v1.2.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
16007d3c1b | ||
|
|
ccee0065c2 | ||
|
|
30137a9308 | ||
|
|
c853644c16 | ||
|
|
794d1b391d | ||
|
|
3ac2687f1e | ||
|
|
511fd00652 | ||
|
|
405d3fd774 | ||
|
|
7a26d613fd | ||
|
|
0a02edf6f3 | ||
|
|
e8c7b31144 | ||
|
|
d6f6742658 | ||
|
|
c76dfe9e96 | ||
|
|
3ba88265eb | ||
|
|
dcc8975757 | ||
|
|
e824234057 | ||
|
|
0cc8bd6e0f | ||
|
|
1e45ff34f0 | ||
|
|
2532511d53 | ||
|
|
14f7c5ecc3 | ||
|
|
1ec6af6d34 | ||
|
|
e472ee5fbd | ||
|
|
7b4f43fd12 | ||
|
|
8a49b88c7a | ||
|
|
2138022f6d | ||
|
|
fd3bc667a9 | ||
|
|
4db5e54d88 | ||
|
|
62748437de | ||
|
|
163b2df7f6 | ||
|
|
386bad2c1c | ||
|
|
d304028389 | ||
|
|
964894f376 | ||
|
|
ec8dfd746d | ||
|
|
732547213a | ||
|
|
df888a7f36 | ||
|
|
bd01b9d682 | ||
|
|
ab390703da | ||
|
|
28cd8f0265 | ||
|
|
ca47636ffe | ||
|
|
a852b8e535 | ||
|
|
fa6f52d305 | ||
|
|
3e8d8daa9b | ||
|
|
8196a686df | ||
|
|
da157a1b28 | ||
|
|
167191a135 | ||
|
|
e6f881df6e | ||
|
|
53f82b1971 | ||
|
|
9f775f2c92 | ||
|
|
07f89dc691 | ||
|
|
0c70a5cbac | ||
|
|
3ceda765c9 | ||
|
|
e3360e2d18 | ||
|
|
b4e2ecc8f1 | ||
|
|
bdd6ea48a0 | ||
|
|
84244c0376 | ||
|
|
6fec1417b1 | ||
|
|
142c47de1c | ||
|
|
e796883660 | ||
|
|
c6779385a7 | ||
|
|
1a0ea5db72 | ||
|
|
342a1ceb6d | ||
|
|
0e7d3438a5 | ||
|
|
cadcdab39b | ||
|
|
0bc7614809 | ||
|
|
ecbde40aa6 | ||
|
|
672ed74309 | ||
|
|
469e9e9065 | ||
|
|
2dba103c14 | ||
|
|
be7c0220d4 | ||
|
|
14f9640556 | ||
|
|
3b2940ac59 | ||
|
|
036d9c5e6b | ||
|
|
76cdecbb94 | ||
|
|
1d6317b5d6 | ||
|
|
26f963f9b9 | ||
|
|
9ee90508ed | ||
|
|
9b6da631ee | ||
|
|
c26edc55f5 | ||
|
|
f1c306051c | ||
|
|
dacb16044d | ||
|
|
68478f84d8 | ||
|
|
6272bfe2d6 | ||
|
|
e561bfd148 | ||
|
|
2f9cc2b41c | ||
|
|
8d39e2536b | ||
|
|
17fa80e752 | ||
|
|
4d2641308a | ||
|
|
27e02963eb | ||
|
|
d71c03e48a | ||
|
|
43b69ba860 | ||
|
|
64bfb72c53 | ||
|
|
6810232183 | ||
|
|
6e25c2591e | ||
|
|
0be43ec28c | ||
|
|
78f0f572b2 | ||
|
|
6d99c7e643 | ||
|
|
c6f4fc8992 | ||
|
|
320c471b4e | ||
|
|
0ea8d8932e | ||
|
|
7325f4b6ac | ||
|
|
4fd035aa16 | ||
|
|
5f1038d7a4 | ||
|
|
6449cb7295 | ||
|
|
1fa0e81b8e | ||
|
|
b243a0a098 | ||
|
|
139253454c | ||
|
|
7224ac123f | ||
|
|
c53018942b | ||
|
|
45eaf6fb3b | ||
|
|
8e4141ccc1 | ||
|
|
41c6accc16 | ||
|
|
2302d6e59f | ||
|
|
5848e7b21c | ||
|
|
2a2c0da200 |
+2
-1
@@ -31,4 +31,5 @@ forge*changelog.txt
|
||||
common/src/main/resources/assets/cobblemon/showdown
|
||||
|
||||
# Generated files
|
||||
*/generated/resources/*
|
||||
*/generated/resources/*
|
||||
/fabric/src/generated/resources/cobblemon-common.accesswidener
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ stages:
|
||||
build-job:
|
||||
stage: build
|
||||
script:
|
||||
- export GRADLE_OPTS="-Xmx3G -Xms3G"
|
||||
- export GRADLE_OPTS="-Xmx4G -Xms4G"
|
||||
- chmod +x ./gradlew
|
||||
- ./gradlew build
|
||||
cache:
|
||||
|
||||
+46
-12
@@ -1,30 +1,63 @@
|
||||
# Changelog
|
||||
|
||||
## 1.1.2
|
||||
## [1.2.0 - The Customization Update (January 1st, 2023)](#1-2-0)
|
||||
### Additions
|
||||
- Reworked customisation of models, textures, and animations to make fakemon very easy to create.
|
||||
- Added 'nature' and 'pokeball' options to commands such as /spawnpokemon and /givepokemon.
|
||||
- Added support for datapack spawn files and spawn file presets.
|
||||
- Added models for Natu and Xatu, Murkrow and Honchkrow, Wailmer and Wailord.
|
||||
- Added new PC interface and it is beautiful.
|
||||
- Reworked the battle system so that battles load faster, cause fewer bugs, and can run on shared server hosts. This is a very big change that also reduced the size of the mod by 50mb!
|
||||
- Added full resource pack / data pack customization of models, textures, animations, spawning, and spawn file presets to make custom Pokémon species and variations very easy to create. You can find the guide for creating custom Pokémon on [our website](https://cobblemon.com/guides/custompokemon.html)!
|
||||
- Added water surface spawning for Pokémon like Lapras.
|
||||
- Added emissive texture support to Pokémon render layers.
|
||||
- Added compatibility for Mod Menu ([CurseForge](https://www.curseforge.com/minecraft/mc-mods/modmenu), [Modrinth](https://modrinth.com/mod/modmenu)).
|
||||
- Added blank ambient Pokémon cries so cries can be added via resource packs.
|
||||
- Added new sounds for GUIs and item uses.
|
||||
- Added `nature` and `pokeball` options to commands such as `/spawnpokemon` and `/givepokemon`.
|
||||
|
||||
### Changes
|
||||
- Reinforced party and PC saving to make data corruption from crashes less bad.
|
||||
- Added a config option for whether the starter config will be exported, making it more maintainable as we add starter Pokémon.
|
||||
- Battles now start with the options menu open for convenience.
|
||||
- Doubled the default charge rate of healers. You'd need to reset your config under `./config/cobblemon/main.json` to see this change!
|
||||
- Changed the default Apricorn seed chance config value from 6% to 10%.
|
||||
- The mod now correctly reports our dependency on Architectury API so people don't get super confused when things don't work.
|
||||
- Pokémon now look at their opponents during battle.
|
||||
- Updated Sableye's animations to be super freaky.
|
||||
- Changed the healer advancements to make the healing machine's mechanics more obvious.
|
||||
|
||||
### Fixes
|
||||
- Fixed an incompatibility with [Porting Lib](https://github.com/Fabricators-of-Create/Porting-Lib) used by Fabric ports of mods such as Create or Twilight Forest.
|
||||
- Fixed HP and max HP values in the battle GUI not being correct.
|
||||
- Fixed some animations on snake-type Pokémon being mega slow.
|
||||
- Fixed some animations on snake-type Pokémon being super slow.
|
||||
- Fixed a typo in the English name for Calcium. Calcuim.
|
||||
- Fixed Pokémon gradually becoming rarer around you if you move long distances.
|
||||
- Fixed a shoulder mount crash on Fabric.
|
||||
- Fixed a rare issue where chunks would take a really long time to generate.
|
||||
- Fixed a singleplayer bug where battles wouldn't work after leaving then rejoining a world.
|
||||
- Fixed stat calculations for everything except HP. HP was fine though :).
|
||||
- Fixed a randomized Pokémon spawning in mountains that corrupted the data of whatever party or PC it got into. Yikes.
|
||||
- Fixed a rare crash involving literally random number generation. A random crash involving random numbers.
|
||||
- Fixed all regular Mewtwo having the stats and types of Mega Mewtwo X - same deal with many other Pokémon.
|
||||
- Fixed the framing of many Pokémon in GUIs.
|
||||
- Fixed texture glitches with Rattata and Nidoqueen (again!).
|
||||
- Fixed dropped item forms of all Pokéballs and the Healing Machine, and slightly adjusted all other display settings
|
||||
- Fixed issues with forms not showing the correct evolution in the evolution menu.
|
||||
- Fixed some alternate forms not having the alternate stats and types.
|
||||
- Fixed moves that only work in double battles not being selectable at all (such as Helping Hand and Aromatic Mist).
|
||||
- Fixed abilities not remaining legal in some forms.
|
||||
- Fixed Poké Ball capture effects not triggering after a successful capture, such as the Heal Ball's healing effect.
|
||||
- Fixed multiple-hit moves sending gibberish into the battle chat.
|
||||
- Fixed Pyukumuku not being appropriately scaled.
|
||||
- Fixed shiny and other variations of Pokémon not showing in the battle GUI.
|
||||
- Fixed Eevee being poorly positioned and un-animated on shoulders.
|
||||
- Fixed a Pokémon's hitbox not updating when it evolves while sent out.
|
||||
- Fixed a Pokémon's PP going from zero to above the maximum when entering another battle.
|
||||
|
||||
## 1.1.1 (November 27th, 2022)
|
||||
|
||||
## [1.1.1 (November 27th, 2022)](#1-1-1)
|
||||
### Fixes
|
||||
- Fixed a critical issue with servers where Pokémon data didn't properly synchronize and so you couldn't see any.
|
||||
|
||||
## 1.1.0 - The Swim and Sleep Update (November 27th, 2022)
|
||||
## [1.1.0 - The Swim and Sleep Update (November 27th, 2022)](#1-1-0)
|
||||
#### "Ideally not at the same time."
|
||||
|
||||
|
||||
### Additions
|
||||
- Added a new GUI for viewing party information, rearranging moves, and evolving Pokémon. It looks too good.
|
||||
- Starter Pokémon will sleep on top of you if sent out when you get on a bed.
|
||||
@@ -78,6 +111,7 @@
|
||||
- Statuses like sleep and frozen no longer last forever if it was carried over from a previous battle.
|
||||
|
||||
### Localization
|
||||
- Added species, ability, and move translations for ko_ko, jp_jp, fr_fr, es_es, it_it, and zh_cn.
|
||||
## 1.0.0 (2022-11-12)
|
||||
- Added species, ability, and move translations for `ko_ko`, `jp_jp`, `fr_fr`, `es_es`, `it_it`, and `zh_cn`.
|
||||
|
||||
## [1.0.0 (November 12th, 2022)](#1-0-0)
|
||||
- Initial release.
|
||||
@@ -19,6 +19,7 @@ tasks {
|
||||
archiveClassifier.set("dev-shadow")
|
||||
archiveBaseName.set("Cobblemon-${project.name}")
|
||||
configurations = listOf(bundle)
|
||||
mergeServiceFiles()
|
||||
}
|
||||
|
||||
remapJar {
|
||||
|
||||
@@ -21,8 +21,7 @@ dependencies {
|
||||
modApi(libs.mclib)
|
||||
|
||||
// For Showdown
|
||||
modCompileOnly(libs.javet) // Linux or Windows
|
||||
modCompileOnly(libs.javetMac) // Mac OS (x86_64 Only)
|
||||
modCompileOnly(libs.graal)
|
||||
|
||||
//shadowCommon group: 'commons-io', name: 'commons-io', version: '2.6'
|
||||
|
||||
@@ -33,11 +32,6 @@ dependencies {
|
||||
testImplementation(libs.mockk)
|
||||
|
||||
compileOnly("net.luckperms:api:${rootProject.property("luckperms_version")}")
|
||||
|
||||
// For Showdown
|
||||
// modCompileOnly 'com.caoccao.javet:javet:1.0.6' // Linux or Windows
|
||||
// modCompileOnly 'com.caoccao.javet:javet-macos:1.0.6' // Mac OS (x86_64 Only)
|
||||
// modCompileOnly group: 'commons-io', name: 'commons-io', version: '2.6'
|
||||
}
|
||||
|
||||
publishing {
|
||||
|
||||
@@ -48,7 +48,6 @@ import com.cobblemon.mod.common.api.reactive.Observable.Companion.map
|
||||
import com.cobblemon.mod.common.api.reactive.Observable.Companion.takeFirst
|
||||
import com.cobblemon.mod.common.api.scheduling.ScheduledTaskTracker
|
||||
import com.cobblemon.mod.common.api.spawning.BestSpawner
|
||||
import com.cobblemon.mod.common.api.spawning.CobblemonSpawnPools
|
||||
import com.cobblemon.mod.common.api.spawning.CobblemonSpawningProspector
|
||||
import com.cobblemon.mod.common.api.spawning.context.AreaContextResolver
|
||||
import com.cobblemon.mod.common.api.spawning.prospecting.SpawningProspector
|
||||
@@ -68,7 +67,6 @@ import com.cobblemon.mod.common.battles.BattleSide
|
||||
import com.cobblemon.mod.common.battles.ShowdownThread
|
||||
import com.cobblemon.mod.common.battles.actor.PokemonBattleActor
|
||||
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||
import com.cobblemon.mod.common.battles.runner.ShowdownConnection
|
||||
import com.cobblemon.mod.common.config.CobblemonConfig
|
||||
import com.cobblemon.mod.common.config.constraint.IntConstraint
|
||||
import com.cobblemon.mod.common.config.starter.StarterConfig
|
||||
@@ -128,7 +126,6 @@ object Cobblemon {
|
||||
val LOGGER = LogManager.getLogger()
|
||||
|
||||
lateinit var implementation: CobblemonImplementation
|
||||
lateinit var showdown: ShowdownConnection
|
||||
var captureCalculator: CaptureCalculator = CobblemonGen348CaptureCalculator
|
||||
var experienceCalculator: ExperienceCalculator = StandardExperienceCalculator
|
||||
var evYieldCalculator: EvCalculator = Generation8EvCalculator
|
||||
@@ -261,7 +258,6 @@ object Cobblemon {
|
||||
SERVER_STOPPED.subscribe {
|
||||
storage.unregisterAll()
|
||||
playerData.saveAll()
|
||||
showdown.close()
|
||||
}
|
||||
SERVER_STARTED.subscribe {
|
||||
bestSpawner.onServerStarted()
|
||||
@@ -351,19 +347,23 @@ object Cobblemon {
|
||||
}
|
||||
|
||||
fun loadStarterConfig(): StarterConfig {
|
||||
val file = File("config/cobblemon/starters.json")
|
||||
file.parentFile.mkdirs()
|
||||
if (!file.exists()) {
|
||||
val config = StarterConfig()
|
||||
val pw = PrintWriter(file)
|
||||
StarterConfig.GSON.toJson(config, pw)
|
||||
pw.close()
|
||||
if (config.exportStarterConfig) {
|
||||
val file = File("config/cobblemon/starters.json")
|
||||
file.parentFile.mkdirs()
|
||||
if (!file.exists()) {
|
||||
val config = StarterConfig()
|
||||
val pw = PrintWriter(file)
|
||||
StarterConfig.GSON.toJson(config, pw)
|
||||
pw.close()
|
||||
return config
|
||||
}
|
||||
val reader = FileReader(file)
|
||||
val config = StarterConfig.GSON.fromJson(reader, StarterConfig::class.java)
|
||||
reader.close()
|
||||
return config
|
||||
} else {
|
||||
return StarterConfig()
|
||||
}
|
||||
val reader = FileReader(file)
|
||||
val config = StarterConfig.GSON.fromJson(reader, StarterConfig::class.java)
|
||||
reader.close()
|
||||
return config
|
||||
}
|
||||
|
||||
fun saveConfig() {
|
||||
|
||||
@@ -52,6 +52,7 @@ import com.cobblemon.mod.common.net.messages.client.pokemon.update.evolution.Add
|
||||
import com.cobblemon.mod.common.net.messages.client.pokemon.update.evolution.ClearEvolutionsPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pokemon.update.evolution.RemoveEvolutionPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.settings.ServerSettingsPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.sound.UnvalidatedPlaySoundS2CPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.starter.OpenStarterUIPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.starter.SetClientPlayerDataPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.RemoveClientPokemonPacket
|
||||
@@ -207,6 +208,9 @@ object CobblemonNetwork {
|
||||
buildClientMessage<SpeciesRegistrySyncPacket>()
|
||||
buildClientMessage<PropertiesCompletionRegistrySyncPacket>()
|
||||
|
||||
// Hax
|
||||
buildClientMessage<UnvalidatedPlaySoundS2CPacket>()
|
||||
|
||||
/**
|
||||
* Server Packets
|
||||
*/
|
||||
|
||||
@@ -16,6 +16,14 @@ import net.minecraft.util.registry.Registry
|
||||
object CobblemonSounds : CompletableRegistry<SoundEvent>(Registry.SOUND_EVENT_KEY) {
|
||||
private fun queue(name: String) = queue(name) { SoundEvent(cobblemonResource(name)) }
|
||||
|
||||
val GUI_CLICK = queue("gui.click")
|
||||
|
||||
val PC_ON = queue("pc.on")
|
||||
val PC_OFF = queue("pc.off")
|
||||
val PC_GRAB = queue("pc.grab")
|
||||
val PC_DROP = queue("pc.drop")
|
||||
val PC_RELEASE = queue("pc.release")
|
||||
|
||||
val POKE_BALL_CAPTURE_STARTED = queue("poke_ball.capture_started")
|
||||
val POKE_BALL_CAPTURE_SUCCEEDED = queue("poke_ball.capture_succeeded")
|
||||
val POKE_BALL_SHAKE = queue("poke_ball.shake")
|
||||
@@ -23,5 +31,6 @@ object CobblemonSounds : CompletableRegistry<SoundEvent>(Registry.SOUND_EVENT_KE
|
||||
val POKE_BALL_HIT = queue("poke_ball.hit")
|
||||
val POKE_BALL_SEND_OUT = queue("poke_ball.send_out")
|
||||
val POKE_BALL_RECALL = queue("poke_ball.recall")
|
||||
|
||||
val ITEM_USE = queue("item.use")
|
||||
}
|
||||
@@ -22,7 +22,6 @@ import com.google.gson.JsonDeserializer
|
||||
import com.google.gson.JsonElement
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import java.lang.reflect.Type
|
||||
import kotlin.io.path.Path
|
||||
import net.minecraft.resource.ResourceType
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.text.MutableText
|
||||
@@ -83,6 +82,6 @@ object Abilities : JsonDataRegistry<AbilityTemplate> {
|
||||
fun all() = allAbilities.toList()
|
||||
fun first() = allAbilities.first()
|
||||
fun get(name: String) = abilityMap[name.lowercase()]
|
||||
fun getOrException(name: String) = get(name)!!
|
||||
fun getOrException(name: String) = get(name) ?: throw IllegalArgumentException("Unable to find ability of name: $name")
|
||||
fun count() = allAbilities.size
|
||||
}
|
||||
@@ -21,27 +21,35 @@ import net.minecraft.text.MutableText
|
||||
* @author Qu
|
||||
* @since January 9th, 2022
|
||||
*/
|
||||
open class Ability internal constructor(var template: AbilityTemplate) {
|
||||
open class Ability internal constructor(var template: AbilityTemplate, var forced: Boolean) {
|
||||
|
||||
val name: String
|
||||
get() = template.name
|
||||
|
||||
val displayName: MutableText
|
||||
val displayName: String
|
||||
get() = template.displayName
|
||||
|
||||
val description: MutableText
|
||||
val description: String
|
||||
get() = template.description
|
||||
|
||||
open fun saveToNBT(nbt: NbtCompound): NbtCompound {
|
||||
nbt.putString(DataKeys.POKEMON_ABILITY_NAME, name)
|
||||
nbt.putBoolean(DataKeys.POKEMON_ABILITY_FORCED, forced)
|
||||
return nbt
|
||||
}
|
||||
|
||||
open fun saveToJSON(json: JsonObject): JsonObject {
|
||||
json.addProperty(DataKeys.POKEMON_ABILITY_NAME, name)
|
||||
json.addProperty(DataKeys.POKEMON_ABILITY_FORCED, forced)
|
||||
return json
|
||||
}
|
||||
|
||||
open fun loadFromNBT(nbt: NbtCompound) = this
|
||||
open fun loadFromJSON(json: JsonObject) = this
|
||||
open fun loadFromNBT(nbt: NbtCompound): Ability {
|
||||
forced = nbt.getBoolean(DataKeys.POKEMON_ABILITY_FORCED)
|
||||
return this
|
||||
}
|
||||
open fun loadFromJSON(json: JsonObject): Ability {
|
||||
forced = json.get(DataKeys.POKEMON_ABILITY_FORCED)?.asBoolean ?: false
|
||||
return this
|
||||
}
|
||||
}
|
||||
@@ -8,10 +8,8 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.abilities
|
||||
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import com.google.gson.JsonObject
|
||||
import net.minecraft.nbt.NbtCompound
|
||||
import net.minecraft.text.MutableText
|
||||
|
||||
/**
|
||||
* This represents the base of an Ability.
|
||||
@@ -21,14 +19,14 @@ import net.minecraft.text.MutableText
|
||||
*/
|
||||
class AbilityTemplate(
|
||||
val name: String = "",
|
||||
var builder: (AbilityTemplate) -> Ability = { Ability(it) },
|
||||
val displayName: MutableText = lang("ability.$name"),
|
||||
val description: MutableText = lang("ability.$name.desc")
|
||||
var builder: (AbilityTemplate, forced: Boolean) -> Ability = { template, forced -> Ability(template, forced) },
|
||||
val displayName: String = "cobblemon.ability.$name",
|
||||
val description: String = "cobblemon.ability.$name.desc"
|
||||
) {
|
||||
/**
|
||||
* Returns the Ability or if applicable the extension connected to this template
|
||||
*/
|
||||
fun create() = builder(this)
|
||||
fun create(forced: Boolean = false) = builder(this, forced)
|
||||
|
||||
|
||||
/**
|
||||
@@ -36,12 +34,12 @@ class AbilityTemplate(
|
||||
*
|
||||
* Ability extensions need to write and read their needed data from here.
|
||||
*/
|
||||
fun create(nbt: NbtCompound) = builder(this).loadFromNBT(nbt)
|
||||
fun create(nbt: NbtCompound) = create().loadFromNBT(nbt)
|
||||
|
||||
/**
|
||||
* Returns the Ability and loads the given JSON object into it.
|
||||
*
|
||||
* Ability extensions need to write and read their needed data from here.
|
||||
*/
|
||||
fun create(json: JsonObject) = builder(this).loadFromJSON(json)
|
||||
fun create(json: JsonObject) = create().loadFromJSON(json)
|
||||
}
|
||||
@@ -10,7 +10,6 @@ package com.cobblemon.mod.common.api.battles.model
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.Cobblemon.LOGGER
|
||||
import com.cobblemon.mod.common.Cobblemon.showdown
|
||||
import com.cobblemon.mod.common.CobblemonNetwork
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.ActorType
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
|
||||
@@ -26,13 +25,11 @@ import com.cobblemon.mod.common.battles.BattleSide
|
||||
import com.cobblemon.mod.common.battles.dispatch.BattleDispatch
|
||||
import com.cobblemon.mod.common.battles.dispatch.DispatchResult
|
||||
import com.cobblemon.mod.common.battles.dispatch.GO
|
||||
import com.cobblemon.mod.common.battles.runner.GraalShowdown
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleEndPacket
|
||||
import com.cobblemon.mod.common.pokemon.feature.BattleCriticalHitsFeature
|
||||
import com.cobblemon.mod.common.util.DataKeys
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
import com.cobblemon.mod.common.util.getPlayer
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonObject
|
||||
import java.util.UUID
|
||||
import java.util.concurrent.ConcurrentLinkedQueue
|
||||
import net.minecraft.text.Text
|
||||
@@ -50,6 +47,7 @@ open class PokemonBattle(
|
||||
) {
|
||||
/** Whether or not logging will be silenced for this battle. */
|
||||
var mute = true
|
||||
|
||||
init {
|
||||
side1.battle = this
|
||||
side2.battle = this
|
||||
@@ -148,17 +146,8 @@ open class PokemonBattle(
|
||||
}
|
||||
|
||||
fun writeShowdownAction(vararg messages: String) {
|
||||
val jsonArray = JsonArray()
|
||||
for (message in messages) {
|
||||
jsonArray.add(message)
|
||||
}
|
||||
val request = JsonObject()
|
||||
request.addProperty(DataKeys.REQUEST_TYPE, DataKeys.REQUEST_BATTLE_SEND_MESSAGE)
|
||||
request.addProperty(DataKeys.REQUEST_BATTLE_ID, battleId.toString())
|
||||
request.add(DataKeys.REQUEST_MESSAGES, jsonArray)
|
||||
val json = BattleRegistry.gson.toJson(request)
|
||||
log(json)
|
||||
showdown.write(json)
|
||||
log(messages.joinToString("\n"))
|
||||
GraalShowdown.sendToShowdown(battleId, messages.toList().toTypedArray())
|
||||
}
|
||||
|
||||
fun turn(newTurnNumber: Int) {
|
||||
|
||||
@@ -9,8 +9,11 @@
|
||||
package com.cobblemon.mod.common.api.net
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonNetwork
|
||||
import com.cobblemon.mod.common.util.getServer
|
||||
import net.minecraft.network.PacketByteBuf
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.util.registry.RegistryKey
|
||||
import net.minecraft.world.World
|
||||
|
||||
/*
|
||||
* Simple packet interface to make a more traditional layout for netcode
|
||||
@@ -30,4 +33,17 @@ interface NetworkPacket {
|
||||
}
|
||||
fun sendToAllPlayers() = CobblemonNetwork.sendToAllPlayers(this)
|
||||
fun sendToServer() = CobblemonNetwork.sendToServer(this)
|
||||
// A copy from PlayerManager#sendToAround to work with our packets
|
||||
fun sendToPlayersAround(x: Double, y: Double, z: Double, distance: Double, worldKey: RegistryKey<World>, exclusionCondition: (ServerPlayerEntity) -> Boolean = { false }) {
|
||||
val server = getServer() ?: return
|
||||
server.playerManager.playerList.filter { player ->
|
||||
if (exclusionCondition.invoke(player))
|
||||
return@filter false
|
||||
val xDiff = x - player.x
|
||||
val yDiff = y - player.y
|
||||
val zDiff = z - player.z
|
||||
return@filter (xDiff * xDiff + yDiff * yDiff + zDiff) < distance * distance
|
||||
}
|
||||
.forEach { player -> CobblemonNetwork.sendToPlayer(player, this) }
|
||||
}
|
||||
}
|
||||
@@ -26,127 +26,127 @@ object Natures {
|
||||
private val allNatures = mutableListOf<Nature>()
|
||||
|
||||
val HARDY = registerNature(
|
||||
Nature(cobblemonResource("hardy"), lang("nature.hardy"),
|
||||
Nature(cobblemonResource("hardy"), "cobblemon.nature.hardy",
|
||||
null, null, null, null)
|
||||
)
|
||||
|
||||
val LONELY = registerNature(
|
||||
Nature(cobblemonResource("lonely"), lang("nature.lonely"),
|
||||
Nature(cobblemonResource("lonely"), "cobblemon.nature.lonely",
|
||||
Stats.ATTACK, Stats.DEFENCE, Flavor.SPICY, Flavor.SOUR)
|
||||
)
|
||||
|
||||
val BRAVE = registerNature(
|
||||
Nature(cobblemonResource("brave"), lang("nature.brave"),
|
||||
Nature(cobblemonResource("brave"), "cobblemon.nature.brave",
|
||||
Stats.ATTACK, Stats.SPEED, Flavor.SPICY, Flavor.SWEET)
|
||||
)
|
||||
|
||||
val ADAMANT = registerNature(
|
||||
Nature(cobblemonResource("adamant"), lang("nature.adamant"),
|
||||
Nature(cobblemonResource("adamant"), "cobblemon.nature.adamant",
|
||||
Stats.ATTACK, Stats.SPECIAL_ATTACK, Flavor.SPICY, Flavor.DRY)
|
||||
)
|
||||
|
||||
val NAUGHTY = registerNature(
|
||||
Nature(cobblemonResource("naughty"), lang("nature.naughty"),
|
||||
Nature(cobblemonResource("naughty"), "cobblemon.nature.naughty",
|
||||
Stats.ATTACK, Stats.SPECIAL_DEFENCE, Flavor.SPICY, Flavor.BITTER)
|
||||
)
|
||||
|
||||
val BOLD = registerNature(
|
||||
Nature(cobblemonResource("bold"), lang("nature.bold"),
|
||||
Nature(cobblemonResource("bold"), "cobblemon.nature.bold",
|
||||
Stats.DEFENCE, Stats.ATTACK, Flavor.SOUR, Flavor.SPICY)
|
||||
)
|
||||
|
||||
val DOCILE = registerNature(
|
||||
Nature(cobblemonResource("docile"), lang("nature.docile"),
|
||||
Nature(cobblemonResource("docile"), "cobblemon.nature.docile",
|
||||
null, null, null, null)
|
||||
)
|
||||
|
||||
val RELAXED = registerNature(
|
||||
Nature(cobblemonResource("relaxed"), lang("nature.relaxed"),
|
||||
Nature(cobblemonResource("relaxed"), "cobblemon.nature.relaxed",
|
||||
Stats.DEFENCE, Stats.SPEED, Flavor.SOUR, Flavor.SWEET)
|
||||
)
|
||||
|
||||
val IMPISH = registerNature(
|
||||
Nature(cobblemonResource("impish"), lang("nature.impish"),
|
||||
Nature(cobblemonResource("impish"), "cobblemon.nature.impish",
|
||||
Stats.DEFENCE, Stats.SPECIAL_ATTACK, Flavor.SOUR, Flavor.DRY)
|
||||
)
|
||||
|
||||
val LAX = registerNature(
|
||||
Nature(cobblemonResource("lax"), lang("nature.lax"),
|
||||
Nature(cobblemonResource("lax"), "cobblemon.nature.lax",
|
||||
Stats.DEFENCE, Stats.SPECIAL_DEFENCE, Flavor.SOUR, Flavor.BITTER)
|
||||
)
|
||||
|
||||
val TIMID = registerNature(
|
||||
Nature(cobblemonResource("timid"), lang("nature.timid"),
|
||||
Nature(cobblemonResource("timid"), "cobblemon.nature.timid",
|
||||
Stats.SPEED, Stats.ATTACK, Flavor.SWEET, Flavor.SPICY)
|
||||
)
|
||||
|
||||
val HASTY = registerNature(
|
||||
Nature(cobblemonResource("hasty"), lang("nature.hasty"),
|
||||
Nature(cobblemonResource("hasty"), "cobblemon.nature.hasty",
|
||||
Stats.SPEED, Stats.DEFENCE, Flavor.SWEET, Flavor.SOUR)
|
||||
)
|
||||
|
||||
val SERIOUS = registerNature(
|
||||
Nature(cobblemonResource("serious"), lang("nature.serious"),
|
||||
Nature(cobblemonResource("serious"), "cobblemon.nature.serious",
|
||||
null, null, null, null)
|
||||
)
|
||||
|
||||
val JOLLY = registerNature(
|
||||
Nature(cobblemonResource("jolly"), lang("nature.jolly"),
|
||||
Nature(cobblemonResource("jolly"), "cobblemon.nature.jolly",
|
||||
Stats.SPEED, Stats.SPECIAL_ATTACK, Flavor.SWEET, Flavor.DRY)
|
||||
)
|
||||
|
||||
val NAIVE = registerNature(
|
||||
Nature(cobblemonResource("naive"), lang("nature.naive"),
|
||||
Nature(cobblemonResource("naive"), "cobblemon.nature.naive",
|
||||
Stats.SPEED, Stats.SPECIAL_DEFENCE, Flavor.SWEET, Flavor.BITTER)
|
||||
)
|
||||
|
||||
val MODEST = registerNature(
|
||||
Nature(cobblemonResource("modest"), lang("nature.modest"),
|
||||
Nature(cobblemonResource("modest"), "cobblemon.nature.modest",
|
||||
Stats.SPECIAL_ATTACK, Stats.ATTACK, null, null)
|
||||
)
|
||||
|
||||
val MILD = registerNature(
|
||||
Nature(cobblemonResource("mild"), lang("nature.mild"),
|
||||
Nature(cobblemonResource("mild"), "cobblemon.nature.mild",
|
||||
Stats.SPECIAL_ATTACK, Stats.DEFENCE, Flavor.DRY, Flavor.SOUR)
|
||||
)
|
||||
|
||||
val QUIET = registerNature(
|
||||
Nature(cobblemonResource("quiet"), lang("nature.quiet"),
|
||||
Nature(cobblemonResource("quiet"), "cobblemon.nature.quiet",
|
||||
Stats.SPECIAL_ATTACK, Stats.SPEED, Flavor.DRY, Flavor.SWEET)
|
||||
)
|
||||
|
||||
val BASHFUL = registerNature(
|
||||
Nature(cobblemonResource("bashful"), lang("nature.bashful"),
|
||||
Nature(cobblemonResource("bashful"), "cobblemon.nature.bashful",
|
||||
null, null, null, null)
|
||||
)
|
||||
|
||||
val RASH = registerNature(
|
||||
Nature(cobblemonResource("rash"), lang("nature.rash"),
|
||||
Nature(cobblemonResource("rash"), "cobblemon.nature.rash",
|
||||
Stats.SPECIAL_ATTACK, Stats.SPECIAL_DEFENCE, Flavor.DRY, Flavor.BITTER)
|
||||
)
|
||||
|
||||
val CALM = registerNature(
|
||||
Nature(cobblemonResource("calm"), lang("nature.calm"),
|
||||
Nature(cobblemonResource("calm"), "cobblemon.nature.calm",
|
||||
Stats.SPECIAL_DEFENCE, Stats.ATTACK, Flavor.BITTER, Flavor.SPICY)
|
||||
)
|
||||
|
||||
val GENTLE = registerNature(
|
||||
Nature(cobblemonResource("gentle"), lang("nature.gentle"),
|
||||
Nature(cobblemonResource("gentle"), "cobblemon.nature.gentle",
|
||||
Stats.SPECIAL_DEFENCE, Stats.DEFENCE, Flavor.BITTER, Flavor.SOUR)
|
||||
)
|
||||
|
||||
val SASSY = registerNature(
|
||||
Nature(cobblemonResource("sassy"), lang("nature.sassy"),
|
||||
Nature(cobblemonResource("sassy"), "cobblemon.nature.sassy",
|
||||
Stats.SPECIAL_DEFENCE, Stats.SPEED, Flavor.BITTER, Flavor.SWEET)
|
||||
)
|
||||
|
||||
val CAREFUL = registerNature(
|
||||
Nature(cobblemonResource("careful"), lang("nature.careful"),
|
||||
Nature(cobblemonResource("careful"), "cobblemon.nature.careful",
|
||||
Stats.SPECIAL_DEFENCE, Stats.SPECIAL_ATTACK, Flavor.BITTER, Flavor.DRY)
|
||||
)
|
||||
|
||||
val QUIRKY = registerNature(
|
||||
Nature(cobblemonResource("quirky"), lang("nature.quirky"),
|
||||
Nature(cobblemonResource("quirky"), "cobblemon.nature.quirky",
|
||||
null, null, null, null)
|
||||
)
|
||||
|
||||
|
||||
@@ -311,7 +311,14 @@ open class PokemonProperties {
|
||||
}
|
||||
|
||||
fun create(): Pokemon {
|
||||
return Pokemon().also { apply(it) }.also { if (it.moveSet.none { it != null }) it.initializeMoveset() }
|
||||
val pokemon = Pokemon()
|
||||
apply(pokemon)
|
||||
// Force the setter to initialize it
|
||||
pokemon.species = pokemon.species
|
||||
if (pokemon.moveSet.none { it != null }) {
|
||||
pokemon.initializeMoveset()
|
||||
}
|
||||
return pokemon
|
||||
}
|
||||
|
||||
fun createEntity(world: World): PokemonEntity {
|
||||
@@ -366,6 +373,7 @@ open class PokemonProperties {
|
||||
val custom = JsonArray()
|
||||
customProperties.map { it.asString() }.forEach { custom.add(it) }
|
||||
json.add(DataKeys.POKEMON_PROPERTIES_CUSTOM, custom)
|
||||
|
||||
return json
|
||||
}
|
||||
|
||||
|
||||
@@ -8,8 +8,6 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.pokemon
|
||||
|
||||
import com.caoccao.javet.interop.V8Host
|
||||
import com.caoccao.javet.interop.V8Runtime
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.abilities.AbilityPool
|
||||
import com.cobblemon.mod.common.api.abilities.AbilityTemplate
|
||||
@@ -32,10 +30,11 @@ import com.cobblemon.mod.common.api.pokemon.experience.ExperienceGroupAdapter
|
||||
import com.cobblemon.mod.common.api.pokemon.moves.Learnset
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stat
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.api.spawning.condition.TimeRange
|
||||
import com.cobblemon.mod.common.api.spawning.TimeRange
|
||||
import com.cobblemon.mod.common.api.types.ElementalType
|
||||
import com.cobblemon.mod.common.api.types.ElementalTypes
|
||||
import com.cobblemon.mod.common.api.types.adapters.ElementalTypeAdapter
|
||||
import com.cobblemon.mod.common.battles.runner.GraalShowdown
|
||||
import com.cobblemon.mod.common.net.messages.client.data.SpeciesRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.pokemon.FormData
|
||||
import com.cobblemon.mod.common.pokemon.Species
|
||||
@@ -51,11 +50,11 @@ import com.cobblemon.mod.common.util.adapters.DropEntryAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.EggGroupAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.IntRangeAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.IntRangesAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.ItemLikeConditionAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.LazySetAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.LearnsetAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.NbtCompoundAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.TimeRangeAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.pokemonPropertiesShortAdapter
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.google.common.collect.HashBasedTable
|
||||
@@ -64,7 +63,6 @@ import com.google.gson.GsonBuilder
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import java.io.File
|
||||
import java.nio.file.Files
|
||||
import kotlin.io.path.Path
|
||||
import kotlin.reflect.KProperty
|
||||
import net.minecraft.block.Block
|
||||
import net.minecraft.entity.EntityDimensions
|
||||
@@ -99,7 +97,7 @@ object PokemonSpecies : JsonDataRegistry<Species> {
|
||||
.registerTypeAdapter(IntRange::class.java, IntRangeAdapter)
|
||||
.registerTypeAdapter(PokemonProperties::class.java, pokemonPropertiesShortAdapter)
|
||||
.registerTypeAdapter(Identifier::class.java, IdentifierAdapter)
|
||||
.registerTypeAdapter(TimeRange::class.java, TimeRangeAdapter)
|
||||
.registerTypeAdapter(TimeRange::class.java, IntRangesAdapter(TimeRange.timeRanges) { TimeRange(*it) })
|
||||
.registerTypeAdapter(ItemDropMethod::class.java, ItemDropMethod.adapter)
|
||||
.registerTypeAdapter(SleepDepth::class.java, SleepDepth.adapter)
|
||||
.registerTypeAdapter(DropEntry::class.java, DropEntryAdapter)
|
||||
@@ -218,45 +216,40 @@ object PokemonSpecies : JsonDataRegistry<Species> {
|
||||
this.speciesByDex.remove(species.resourceIdentifier.namespace, species.nationalPokedexNumber)
|
||||
}
|
||||
}
|
||||
V8Host.getNodeInstance().createV8Runtime<V8Runtime>().use { runtime ->
|
||||
// Showdown loads mods by reading existing files as such we cannot dynamically add to the Pokédex, instead, we will overwrite the existing file and force a mod reload.
|
||||
val pokedexFile = File("node_modules/pokemon-showdown/.data-dist/mods/Cobblemon/pokedex.js")
|
||||
Files.createDirectories(pokedexFile.toPath().parent)
|
||||
pokedexFile.bufferedWriter().use { writer ->
|
||||
writer.write(
|
||||
"""
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", {value: true});
|
||||
const Pokedex = {
|
||||
$pokedexDataHolder
|
||||
};
|
||||
exports.Pokedex = Pokedex;
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
val formatsDataFile = File("node_modules/pokemon-showdown/.data-dist/mods/Cobblemon/formats-data.js")
|
||||
formatsDataFile.bufferedWriter().use { writer ->
|
||||
writer.write(
|
||||
"""
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", {value: true});
|
||||
const FormatsData = {
|
||||
$formatsDataHolder
|
||||
};
|
||||
exports.FormatsData = FormatsData;
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
val executor = runtime.getExecutor(
|
||||
|
||||
|
||||
// Showdown loads mods by reading existing files as such we cannot dynamically add to the Pokédex, instead, we will overwrite the existing file and force a mod reload.
|
||||
val pokedexFile = File("showdown/node_modules/pokemon-showdown/.data-dist/mods/cobblemon/pokedex.js")
|
||||
Files.createDirectories(pokedexFile.toPath().parent)
|
||||
pokedexFile.bufferedWriter().use { writer ->
|
||||
writer.write(
|
||||
"""
|
||||
const PokemonShowdown = require('pokemon-showdown');
|
||||
PokemonShowdown.Dex.modsLoaded = false;
|
||||
PokemonShowdown.Dex.includeMods();
|
||||
""".trimIndent()
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", {value: true});
|
||||
const Pokedex = {
|
||||
$pokedexDataHolder
|
||||
};
|
||||
exports.Pokedex = Pokedex;
|
||||
""".trimIndent()
|
||||
)
|
||||
executor.resourceName = "./node_modules"
|
||||
executor.executeVoid()
|
||||
}
|
||||
val formatsDataFile = File("showdown/node_modules/pokemon-showdown/.data-dist/mods/cobblemon/formats-data.js")
|
||||
formatsDataFile.bufferedWriter().use { writer ->
|
||||
writer.write(
|
||||
"""
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", {value: true});
|
||||
const FormatsData = {
|
||||
$formatsDataHolder
|
||||
};
|
||||
exports.FormatsData = FormatsData;
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
GraalShowdown.context.eval("js", """
|
||||
PokemonShowdown.Dex.modsLoaded = false;
|
||||
PokemonShowdown.Dex.includeMods();
|
||||
""".trimIndent())
|
||||
Cobblemon.LOGGER.info("Finished creating showdown data for species")
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -122,7 +122,7 @@ class FlagSpeciesFeatureProvider : SpeciesFeatureProvider<FlagSpeciesFeature>, C
|
||||
}
|
||||
|
||||
override fun provide(properties: PokemonProperties): Set<String> {
|
||||
return if (isAspect && properties.customProperties.filterIsInstance<FlagSpeciesFeature>().find { it.name == keys.first() }?.enabled == true) {
|
||||
return if (isAspect && properties.customProperties.filterIsInstance<FlagSpeciesFeature>().find { it.name == keys.first() }?.enabled == true) {
|
||||
setOf(keys.first())
|
||||
} else {
|
||||
emptySet()
|
||||
|
||||
+10
-11
@@ -37,6 +37,12 @@ object CobblemonPokemonLabels {
|
||||
*/
|
||||
const val PSEUDO_LEGENDARY = "pseudo_legendary"
|
||||
|
||||
/**
|
||||
* Represents a baby Pokémon, this is not just a first stage Pokémon species, it is also unable to breed.
|
||||
* For more information see this [Bulbapedia](https://bulbapedia.bulbagarden.net/wiki/Baby_Pok%C3%A9mon) page.
|
||||
*/
|
||||
const val BABY = "baby"
|
||||
|
||||
/**
|
||||
* Represents a Pokémon that has multiple forms depending on the region they're from.
|
||||
* In Cobblemon/Minecraft terms there are no regions, but we follow the official concept.
|
||||
@@ -93,12 +99,6 @@ object CobblemonPokemonLabels {
|
||||
*/
|
||||
const val REGIONAL_OF_PALDEA = "paldea_regional"
|
||||
|
||||
/**
|
||||
* Represents a Pokémon "baby", this is not just a first stage Pokémon species, it is also unable to breed.
|
||||
* For more information see this [Bulbapedia](https://bulbapedia.bulbagarden.net/wiki/Baby_Pok%C3%A9mon) page.
|
||||
*/
|
||||
const val BABY = "baby"
|
||||
|
||||
/**
|
||||
* Represents a mega evolution.
|
||||
* For more information see the [Bulbapedia](https://bulbapedia.bulbagarden.net/wiki/Mega_Evolution) page.
|
||||
@@ -158,13 +158,12 @@ object CobblemonPokemonLabels {
|
||||
const val GENERATION_8 = "gen8"
|
||||
|
||||
/**
|
||||
* Official Pokémon changed by a datapack, there is no guarantee authors will adhere to this principle
|
||||
* Official Pokémon changed by a data pack, there is no guarantee authors will adhere to this principle
|
||||
*/
|
||||
const val CUSTOMIZED_OFFICIAL = "customized_official"
|
||||
|
||||
/**
|
||||
* Unofficial Pokémon created by a datapack, there is no guarantee authors will adhere to this principle
|
||||
* Unofficial Pokémon created by a data pack, there is no guarantee authors will adhere to this principle
|
||||
*/
|
||||
const val FAKEMON = "fakemon"
|
||||
|
||||
}
|
||||
const val CUSTOM = "custom"
|
||||
}
|
||||
|
||||
@@ -15,17 +15,20 @@ import com.cobblemon.mod.common.api.spawning.condition.BasicSpawningCondition
|
||||
import com.cobblemon.mod.common.api.spawning.condition.GroundedSpawningCondition
|
||||
import com.cobblemon.mod.common.api.spawning.condition.SpawningCondition
|
||||
import com.cobblemon.mod.common.api.spawning.condition.SubmergedSpawningCondition
|
||||
import com.cobblemon.mod.common.api.spawning.condition.SurfaceSpawningCondition
|
||||
import com.cobblemon.mod.common.api.spawning.context.AreaContextResolver
|
||||
import com.cobblemon.mod.common.api.spawning.context.GroundedSpawningContext
|
||||
import com.cobblemon.mod.common.api.spawning.context.LavafloorSpawningContext
|
||||
import com.cobblemon.mod.common.api.spawning.context.SeafloorSpawningContext
|
||||
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
|
||||
import com.cobblemon.mod.common.api.spawning.context.SubmergedSpawningContext
|
||||
import com.cobblemon.mod.common.api.spawning.context.SurfaceSpawningContext
|
||||
import com.cobblemon.mod.common.api.spawning.context.calculators.GroundedSpawningContextCalculator
|
||||
import com.cobblemon.mod.common.api.spawning.context.calculators.LavafloorSpawningContextCalculator
|
||||
import com.cobblemon.mod.common.api.spawning.context.calculators.SeafloorSpawningContextCalculator
|
||||
import com.cobblemon.mod.common.api.spawning.context.calculators.SpawningContextCalculator
|
||||
import com.cobblemon.mod.common.api.spawning.context.calculators.SubmergedSpawningContextCalculator
|
||||
import com.cobblemon.mod.common.api.spawning.context.calculators.SurfaceSpawningContextCalculator
|
||||
import com.cobblemon.mod.common.api.spawning.detail.PokemonSpawnDetail
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnAction
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
|
||||
@@ -33,7 +36,6 @@ import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.preset.BasicSpawnDetailPreset
|
||||
import com.cobblemon.mod.common.api.spawning.preset.BestSpawnerConfig
|
||||
import com.cobblemon.mod.common.api.spawning.preset.PokemonSpawnDetailPreset
|
||||
import com.cobblemon.mod.common.api.spawning.preset.SpawnDetailPreset
|
||||
import com.cobblemon.mod.common.api.spawning.prospecting.SpawningProspector
|
||||
import com.cobblemon.mod.common.api.spawning.selection.SpawningSelector
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.AreaSpawner
|
||||
@@ -44,7 +46,6 @@ import com.cobblemon.mod.common.api.spawning.spawner.Spawner
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.TickingSpawner
|
||||
import com.cobblemon.mod.common.entity.pokemon.CobblemonAgingDespawner
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
/**
|
||||
* A grouping of all the overarching behaviours of the Best Spawner system. This is a convenient accessor to
|
||||
@@ -89,17 +90,20 @@ object BestSpawner {
|
||||
SpawningCondition.register(AreaSpawningCondition.NAME, AreaSpawningCondition::class.java)
|
||||
SpawningCondition.register(SubmergedSpawningCondition.NAME, SubmergedSpawningCondition::class.java)
|
||||
SpawningCondition.register(GroundedSpawningCondition.NAME, GroundedSpawningCondition::class.java)
|
||||
SpawningCondition.register(SurfaceSpawningCondition.NAME, SurfaceSpawningCondition::class.java)
|
||||
|
||||
LOGGER.info("Loaded ${SpawningCondition.conditionTypes.size} spawning condition types.")
|
||||
SpawningContextCalculator.register(GroundedSpawningContextCalculator)
|
||||
SpawningContextCalculator.register(SeafloorSpawningContextCalculator)
|
||||
SpawningContextCalculator.register(LavafloorSpawningContextCalculator)
|
||||
SpawningContextCalculator.register(SubmergedSpawningContextCalculator)
|
||||
SpawningContextCalculator.register(SurfaceSpawningContextCalculator)
|
||||
|
||||
SpawningContext.register(name = "grounded", clazz = GroundedSpawningContext::class.java, defaultCondition = GroundedSpawningCondition.NAME)
|
||||
SpawningContext.register(name = "seafloor", clazz = SeafloorSpawningContext::class.java, defaultCondition = GroundedSpawningCondition.NAME)
|
||||
SpawningContext.register(name = "lavafloor", clazz = LavafloorSpawningContext::class.java, defaultCondition = GroundedSpawningCondition.NAME)
|
||||
SpawningContext.register(name = "submerged", clazz = SubmergedSpawningContext::class.java, defaultCondition = SubmergedSpawningCondition.NAME)
|
||||
SpawningContext.register(name = "surface", clazz = SurfaceSpawningContext::class.java, defaultCondition = SurfaceSpawningCondition.NAME)
|
||||
|
||||
LOGGER.info("Loaded ${SpawningContext.contexts.size} spawning context types.")
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.spawning
|
||||
|
||||
/**
|
||||
* A simple utility for combining multiple integer ranges.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since December 16th, 2022
|
||||
*/
|
||||
open class IntRanges() {
|
||||
constructor(vararg ranges: IntRange) : this() {
|
||||
this.ranges = ranges.toMutableList()
|
||||
}
|
||||
|
||||
var ranges = mutableListOf<IntRange>()
|
||||
|
||||
operator fun contains(value: Int) = ranges.any { value in it }
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.spawning
|
||||
|
||||
import com.cobblemon.mod.common.api.spawning.MoonPhaseRange.Companion.moonPhaseRanges
|
||||
import com.cobblemon.mod.common.api.spawning.condition.SpawningCondition
|
||||
|
||||
/**
|
||||
* A range of moon phases for a world mainly to be used in [SpawningCondition]s. A moon phase range
|
||||
* is defined as any number of phase integer ranges (0-7).
|
||||
*
|
||||
* There are a series of in-built moon phase ranges that you can replace if they don't suit
|
||||
* your definitions.
|
||||
*
|
||||
* If you want a moon phase range to be referenced by name in [SpawningCondition]s, you need
|
||||
* to register it, by name, in [moonPhaseRanges].
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since December 16th, 2022
|
||||
*/
|
||||
class MoonPhaseRange : IntRanges {
|
||||
companion object {
|
||||
val moonPhaseRanges = mutableMapOf(
|
||||
"crescent" to MoonPhaseRange(3..3, 5..5),
|
||||
"gibbous" to MoonPhaseRange(1..1, 7..7),
|
||||
"full" to MoonPhaseRange(0..0),
|
||||
"new" to MoonPhaseRange(4..4),
|
||||
"quarter" to MoonPhaseRange(2..2, 6..6),
|
||||
"waxing" to MoonPhaseRange(5..5, 7..7),
|
||||
"waning" to MoonPhaseRange(1..1, 3..3)
|
||||
)
|
||||
}
|
||||
|
||||
constructor() : super()
|
||||
constructor(vararg ranges: IntRange) : super(*ranges)
|
||||
}
|
||||
@@ -10,28 +10,28 @@ package com.cobblemon.mod.common.api.spawning
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.conditional.RegistryLikeCondition
|
||||
import com.cobblemon.mod.common.api.data.DataRegistry
|
||||
import com.cobblemon.mod.common.api.data.JsonDataRegistry
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.api.spawning.condition.SpawningCondition
|
||||
import com.cobblemon.mod.common.api.spawning.condition.TimeRange
|
||||
import com.cobblemon.mod.common.api.spawning.context.RegisteredSpawningContext
|
||||
import com.cobblemon.mod.common.api.spawning.preset.SpawnDetailPreset
|
||||
import com.cobblemon.mod.common.util.adapters.BiomeLikeConditionAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.BlockLikeConditionAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.FluidLikeConditionAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.IntRangesAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.RegisteredSpawningContextAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.SpawnBucketAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.SpawnDetailPresetAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.SpawningConditionAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.TimeRangeAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.pokemonPropertiesShortAdapter
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import net.minecraft.block.Block
|
||||
import net.minecraft.fluid.Fluid
|
||||
import net.minecraft.resource.ResourceType
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.util.Identifier
|
||||
@@ -54,10 +54,12 @@ object SpawnDetailPresets : JsonDataRegistry<SpawnDetailPreset> {
|
||||
.registerTypeAdapter(RegisteredSpawningContext::class.java, RegisteredSpawningContextAdapter)
|
||||
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Biome::class.java).type, BiomeLikeConditionAdapter)
|
||||
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Block::class.java).type, BlockLikeConditionAdapter)
|
||||
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Fluid::class.java).type, FluidLikeConditionAdapter)
|
||||
.registerTypeAdapter(SpawnDetailPreset::class.java, SpawnDetailPresetAdapter)
|
||||
.registerTypeAdapter(Identifier::class.java, IdentifierAdapter)
|
||||
.registerTypeAdapter(SpawningCondition::class.java, SpawningConditionAdapter)
|
||||
.registerTypeAdapter(TimeRange::class.java, TimeRangeAdapter)
|
||||
.registerTypeAdapter(TimeRange::class.java, IntRangesAdapter(TimeRange.timeRanges) { TimeRange(*it) })
|
||||
.registerTypeAdapter(MoonPhaseRange::class.java, IntRangesAdapter(MoonPhaseRange.moonPhaseRanges) { MoonPhaseRange(*it) })
|
||||
.registerTypeAdapter(PokemonProperties::class.java, pokemonPropertiesShortAdapter)
|
||||
.create()
|
||||
|
||||
|
||||
@@ -8,46 +8,30 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.spawning
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.Cobblemon.LOGGER
|
||||
import com.cobblemon.mod.common.Cobblemon.config
|
||||
import com.cobblemon.mod.common.api.conditional.RegistryLikeCondition
|
||||
import com.cobblemon.mod.common.api.drop.DropEntry
|
||||
import com.cobblemon.mod.common.api.drop.ItemDropMethod
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
|
||||
import com.cobblemon.mod.common.api.spawning.condition.SpawningCondition
|
||||
import com.cobblemon.mod.common.api.spawning.condition.TimeRange
|
||||
import com.cobblemon.mod.common.api.spawning.context.RegisteredSpawningContext
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnPool
|
||||
import com.cobblemon.mod.common.util.AssetLoading
|
||||
import com.cobblemon.mod.common.util.AssetLoading.toPath
|
||||
import com.cobblemon.mod.common.util.adapters.BiomeLikeConditionAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.BlockLikeConditionAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.DropEntryAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.FluidLikeConditionAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.IntRangeAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.IntRangesAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.NbtCompoundAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.RegisteredSpawningContextAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.SpawnBucketAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.SpawnDetailAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.SpawningConditionAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.TimeRangeAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.pokemonPropertiesShortAdapter
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.fromJson
|
||||
import com.cobblemon.mod.common.util.isHigherVersion
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.io.FileReader
|
||||
import java.io.InputStream
|
||||
import java.io.InputStreamReader
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.pathString
|
||||
import net.minecraft.block.Block
|
||||
import net.minecraft.fluid.Fluid
|
||||
import net.minecraft.nbt.NbtCompound
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.world.biome.Biome
|
||||
@@ -66,12 +50,14 @@ object SpawnLoader {
|
||||
.setLenient()
|
||||
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Biome::class.java).type, BiomeLikeConditionAdapter)
|
||||
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Block::class.java).type, BlockLikeConditionAdapter)
|
||||
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Fluid::class.java).type, FluidLikeConditionAdapter)
|
||||
.registerTypeAdapter(RegisteredSpawningContext::class.java, RegisteredSpawningContextAdapter)
|
||||
.registerTypeAdapter(Identifier::class.java, IdentifierAdapter)
|
||||
.registerTypeAdapter(SpawnDetail::class.java, SpawnDetailAdapter)
|
||||
.registerTypeAdapter(DropEntry::class.java, DropEntryAdapter)
|
||||
.registerTypeAdapter(SpawningCondition::class.java, SpawningConditionAdapter)
|
||||
.registerTypeAdapter(TimeRange::class.java, TimeRangeAdapter)
|
||||
.registerTypeAdapter(TimeRange::class.java, IntRangesAdapter(TimeRange.timeRanges) { TimeRange(*it) })
|
||||
.registerTypeAdapter(MoonPhaseRange::class.java, IntRangesAdapter(MoonPhaseRange.moonPhaseRanges) { MoonPhaseRange(*it) })
|
||||
.registerTypeAdapter(ItemDropMethod::class.java, ItemDropMethod.adapter)
|
||||
.registerTypeAdapter(PokemonProperties::class.java, pokemonPropertiesShortAdapter)
|
||||
.registerTypeAdapter(SpawnBucket::class.java, SpawnBucketAdapter)
|
||||
@@ -80,146 +66,4 @@ object SpawnLoader {
|
||||
.create()
|
||||
|
||||
var deserializingConditionClass: Class<out SpawningCondition<*>>? = null
|
||||
|
||||
// fun load(folder: String): SpawnPool {
|
||||
// val pool = SpawnPool()
|
||||
//
|
||||
// val external = getExternalSets(folder)
|
||||
// val internal = loadInternalFolder(folder)
|
||||
//
|
||||
// external.forEach { set ->
|
||||
// val matchingInternal = internal.find { it.id == set.id }
|
||||
// if (set.preventOverwrite) {
|
||||
// if (matchingInternal != null) {
|
||||
// internal.remove(matchingInternal)
|
||||
// }
|
||||
// if (set.isEnabled()) {
|
||||
// pool.details.addAll(set.filter { it.isModDependencySatisfied() })
|
||||
// }
|
||||
// } else {
|
||||
// if (matchingInternal != null && matchingInternal.version.isHigherVersion(set.version)) {
|
||||
// if (matchingInternal.isEnabled()) {
|
||||
// pool.details.addAll(matchingInternal.filter { it.isModDependencySatisfied() })
|
||||
// }
|
||||
// internal.remove(matchingInternal)
|
||||
// exportSet(folder, matchingInternal)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// internal.forEach { set ->
|
||||
// if (set.isEnabled()) {
|
||||
// pool.details.addAll(set.filter { it.isModDependencySatisfied() })
|
||||
// }
|
||||
// if (config.exportSpawnsToConfig) {
|
||||
// exportSet(folder, set)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// pool.precalculate()
|
||||
//
|
||||
// return pool
|
||||
// }
|
||||
//
|
||||
// fun exportSet(folder: String, set: SpawnSet) {
|
||||
// val file = File("./config/cobblemon/spawning/spawns/$folder/${set.id.lowercase()}.set.json")
|
||||
// file.parentFile.mkdirs()
|
||||
// file.createNewFile()
|
||||
//
|
||||
// val internalStream = Cobblemon::class.java.getResourceAsStream(set.path.toAbsolutePath().toString())!!
|
||||
// val bytes = internalStream.readAllBytes()
|
||||
// internalStream.close()
|
||||
//
|
||||
// val externalStream = FileOutputStream(file)
|
||||
// externalStream.write(bytes)
|
||||
// externalStream.close()
|
||||
// }
|
||||
//
|
||||
// fun getExternalSets(folder: String): MutableList<SpawnSet> {
|
||||
// val sets = mutableListOf<SpawnSet>()
|
||||
// val files = mutableListOf<File>()
|
||||
// AssetLoading.searchFor(
|
||||
// dir = "config/cobblemon/spawning/spawns/$folder",
|
||||
// suffix = ".json",
|
||||
// list = files
|
||||
// )
|
||||
// val paths = files.map { it.toPath() }
|
||||
//
|
||||
// sets.addAll(
|
||||
// paths.mapNotNull {
|
||||
// try {
|
||||
// val file = it.toFile()
|
||||
// val reader = FileReader(file)
|
||||
// val set = gson.fromJson<SpawnSet>(reader)
|
||||
// reader.close()
|
||||
// return@mapNotNull set
|
||||
// } catch (exception : Exception) {
|
||||
// LOGGER.error("Unable to load spawn set from ${it.pathString}")
|
||||
// exception.printStackTrace()
|
||||
// null
|
||||
// }
|
||||
// }
|
||||
// )
|
||||
//
|
||||
// return sets
|
||||
// }
|
||||
//
|
||||
// fun loadSetFromPath(path: Path): SpawnSet {
|
||||
// val pathString = if (path.toString().startsWith("/")) path.toString() else "/$path"
|
||||
// val inputStream = Cobblemon.javaClass.getResourceAsStream(pathString)
|
||||
// ?: throw IllegalArgumentException("Unable to open resource stream for: $pathString")
|
||||
// val reader = InputStreamReader(inputStream)
|
||||
// val set = gson.fromJson<SpawnSet>(reader)
|
||||
// reader.close()
|
||||
// return set
|
||||
// }
|
||||
//
|
||||
// fun loadInternalFolder(folder: String): MutableList<SpawnSet> {
|
||||
// val internalFolder = cobblemonResource("spawning/spawns/$folder")
|
||||
// val path = internalFolder.toPath() ?: throw IllegalArgumentException("There is no valid, internal path for $internalFolder")
|
||||
// val internalPaths = AssetLoading.fileSearch(path, { it.toString().endsWith(".json") }, recursive = true)
|
||||
// val sets = mutableListOf<SpawnSet>()
|
||||
// sets.addAll(internalPaths.flatMap { filePath -> loadInternalFile(filePath) })
|
||||
// return sets
|
||||
// }
|
||||
//
|
||||
// fun loadInternalFile(path: Path): MutableList<SpawnSet> {
|
||||
// if (path.toString().endsWith(".packed.json")) {
|
||||
// return loadPackedSets(path).onEach { it.path = path }
|
||||
// } else if (path.toString().endsWith(".json")) {
|
||||
// return mutableListOf(loadSetFromPath(path)).onEach { it.path = path }
|
||||
// }
|
||||
//
|
||||
// return mutableListOf()
|
||||
// }
|
||||
//
|
||||
// fun loadPackedSets(path: Path): MutableList<SpawnSet> {
|
||||
// val fileStream = Cobblemon::class.java.getResourceAsStream(path.toAbsolutePath().toString())
|
||||
// ?: throw IllegalArgumentException("Unable to create input stream for $path")
|
||||
//
|
||||
// return try {
|
||||
// loadPackedSetsFromStream(fileStream)
|
||||
// } catch (e: Exception) {
|
||||
// LOGGER.error(e.message)
|
||||
// return mutableListOf()
|
||||
// } finally {
|
||||
// fileStream.close()
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//
|
||||
// fun loadPackedSetsFromStream(inputStream: InputStream): MutableList<SpawnSet> {
|
||||
// val sets = mutableListOf<SpawnSet>()
|
||||
// val stream = InputStreamReader(inputStream)
|
||||
// val jsonArray = gson.fromJson(stream, JsonArray::class.java)
|
||||
// stream.close()
|
||||
// jsonArray.forEach { jsonElement ->
|
||||
// try {
|
||||
// sets.add(gson.fromJson<SpawnSet>(jsonElement))
|
||||
// } catch (exception: Exception) {
|
||||
// exception.printStackTrace()
|
||||
// }
|
||||
// }
|
||||
// return sets
|
||||
// }
|
||||
}
|
||||
|
||||
+10
-13
@@ -6,10 +6,12 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.spawning.condition
|
||||
package com.cobblemon.mod.common.api.spawning
|
||||
|
||||
import com.cobblemon.mod.common.api.spawning.condition.SpawningCondition
|
||||
|
||||
/**
|
||||
* A range of time ticks for a world to be used in [SpawningCondition]s. A time range
|
||||
* A range of time ticks for a world mainly to be used in [SpawningCondition]s. A time range
|
||||
* is defined as any number of tick ranges. For example, you can define a time range
|
||||
* as being between 0 and 12000 ticks or 13000 and 14000 ticks just for a single time
|
||||
* range. This is to deal with the limitation that Minecraft days go from 0 ticks to
|
||||
@@ -19,14 +21,14 @@ package com.cobblemon.mod.common.api.spawning.condition
|
||||
* your definitions.
|
||||
*
|
||||
* If you want a time range to be referenced by name in [SpawningCondition]s, you need
|
||||
* to register it, by name, in [ranges].
|
||||
* to register it, by name, in [timeRanges].
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since January 26th, 2022
|
||||
*/
|
||||
class TimeRange() {
|
||||
class TimeRange : IntRanges {
|
||||
companion object {
|
||||
val ranges = mutableMapOf(
|
||||
val timeRanges = mutableMapOf(
|
||||
"any" to TimeRange(0..23999),
|
||||
"day" to TimeRange(23460..23999, 0..12541),
|
||||
"night" to TimeRange(12542..23459),
|
||||
@@ -40,11 +42,6 @@ class TimeRange() {
|
||||
)
|
||||
}
|
||||
|
||||
constructor(vararg ranges: IntRange) : this() {
|
||||
this.ranges = ranges.toMutableList()
|
||||
}
|
||||
|
||||
var ranges = mutableListOf<IntRange>()
|
||||
|
||||
operator fun contains(timeTicks: Int) = ranges.any { timeTicks in it }
|
||||
}
|
||||
constructor() : super()
|
||||
constructor(vararg ranges: IntRange) : super(*ranges)
|
||||
}
|
||||
+4
-2
@@ -9,6 +9,8 @@
|
||||
package com.cobblemon.mod.common.api.spawning.condition
|
||||
|
||||
import com.cobblemon.mod.common.api.conditional.RegistryLikeCondition
|
||||
import com.cobblemon.mod.common.api.spawning.MoonPhaseRange
|
||||
import com.cobblemon.mod.common.api.spawning.TimeRange
|
||||
import com.cobblemon.mod.common.api.spawning.condition.ListCheckMode.ALL
|
||||
import com.cobblemon.mod.common.api.spawning.condition.ListCheckMode.ANY
|
||||
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
|
||||
@@ -37,7 +39,7 @@ abstract class SpawningCondition<T : SpawningContext> {
|
||||
|
||||
var dimensions: MutableList<Identifier>? = null
|
||||
var biomes: MutableSet<RegistryLikeCondition<Biome>>? = null
|
||||
var moonPhase: Int? = null
|
||||
var moonPhase: MoonPhaseRange? = null
|
||||
var canSeeSky: Boolean? = null
|
||||
var minX: Float? = null
|
||||
var minY: Float? = null
|
||||
@@ -76,7 +78,7 @@ abstract class SpawningCondition<T : SpawningContext> {
|
||||
return false
|
||||
} else if (dimensions != null && dimensions!!.isNotEmpty() && ctx.world.dimension.effects !in dimensions!!) {
|
||||
return false
|
||||
} else if (moonPhase != null && moonPhase != ctx.moonPhase) {
|
||||
} else if (moonPhase != null && ctx.moonPhase in moonPhase!!) {
|
||||
return false
|
||||
} else if (biomes != null && biomes!!.isNotEmpty() && biomes!!.none { condition -> condition.fits(ctx.biome, ctx.biomeRegistry) }) {
|
||||
return false
|
||||
|
||||
+6
-5
@@ -8,10 +8,11 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.spawning.condition
|
||||
|
||||
import com.cobblemon.mod.common.api.conditional.RegistryLikeCondition
|
||||
import com.cobblemon.mod.common.api.spawning.context.SubmergedSpawningContext
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
|
||||
import com.cobblemon.mod.common.util.Merger
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.fluid.Fluid
|
||||
|
||||
/**
|
||||
* Base type for a spawning condition that applies to some kind of [SubmergedSpawningContext]. This
|
||||
@@ -24,7 +25,7 @@ abstract class SubmergedTypeSpawningCondition<T : SubmergedSpawningContext> : Ar
|
||||
var minDepth: Int? = null
|
||||
var maxDepth: Int? = null
|
||||
var fluidIsSource: Boolean? = null
|
||||
var fluidBlock: Identifier? = null
|
||||
var fluid: RegistryLikeCondition<Fluid>? = null
|
||||
|
||||
override fun fits(ctx: T, detail: SpawnDetail): Boolean {
|
||||
return if (!super.fits(ctx, detail)) {
|
||||
@@ -33,9 +34,9 @@ abstract class SubmergedTypeSpawningCondition<T : SubmergedSpawningContext> : Ar
|
||||
false
|
||||
} else if (maxDepth != null && ctx.depth > maxDepth!!) {
|
||||
false
|
||||
} else if (fluidIsSource != null && ctx.fluidState.isStill != fluidIsSource!!) {
|
||||
} else if (fluidIsSource != null && ctx.fluid.isStill != fluidIsSource!!) {
|
||||
false
|
||||
} else !(fluidBlock != null && ctx.blockRegistry.getKey(ctx.fluidBlock).get().value != fluidBlock!!)
|
||||
} else !(ctx.fluid.isEmpty || (fluid != null && !fluid!!.fits(ctx.fluid.fluid, ctx.fluidRegistry)))
|
||||
}
|
||||
|
||||
override fun copyFrom(other: SpawningCondition<*>, merger: Merger) {
|
||||
@@ -44,7 +45,7 @@ abstract class SubmergedTypeSpawningCondition<T : SubmergedSpawningContext> : Ar
|
||||
minDepth = merger.mergeSingle(minDepth, other.minDepth)
|
||||
maxDepth = merger.mergeSingle(minDepth, other.minDepth)
|
||||
fluidIsSource = merger.mergeSingle(fluidIsSource, other.fluidIsSource)
|
||||
fluidBlock = merger.mergeSingle(fluidBlock, other.fluidBlock)
|
||||
fluid = merger.mergeSingle(fluid, other.fluid)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.spawning.condition
|
||||
|
||||
import com.cobblemon.mod.common.api.conditional.RegistryLikeCondition
|
||||
import com.cobblemon.mod.common.api.spawning.context.SurfaceSpawningContext
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
|
||||
import com.cobblemon.mod.common.util.Merger
|
||||
import net.minecraft.fluid.Fluid
|
||||
|
||||
/**
|
||||
* Base type for a spawning condition that applies to some kind of [SurfaceSpawningContext]. This
|
||||
* can be extended for subclasses of [SurfaceSpawningContext].
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since December 15th, 2022
|
||||
*/
|
||||
abstract class SurfaceTypeSpawningCondition<T : SurfaceSpawningContext> : AreaTypeSpawningCondition<T>() {
|
||||
var minDepth: Int? = null
|
||||
var maxDepth: Int? = null
|
||||
var fluid: RegistryLikeCondition<Fluid>? = null
|
||||
|
||||
override fun fits(ctx: T, detail: SpawnDetail): Boolean {
|
||||
return if (!super.fits(ctx, detail)) {
|
||||
false
|
||||
} else if (minDepth != null && ctx.depth < minDepth!!) {
|
||||
false
|
||||
} else if (maxDepth != null && ctx.depth > maxDepth!!) {
|
||||
false
|
||||
} else !(ctx.baseBlock.fluidState.isEmpty || (fluid != null && !fluid!!.fits(ctx.baseBlock.fluidState.fluid, ctx.fluidRegistry)))
|
||||
}
|
||||
|
||||
override fun copyFrom(other: SpawningCondition<*>, merger: Merger) {
|
||||
super.copyFrom(other, merger)
|
||||
if (other is SurfaceTypeSpawningCondition) {
|
||||
minDepth = merger.mergeSingle(minDepth, other.minDepth)
|
||||
maxDepth = merger.mergeSingle(minDepth, other.minDepth)
|
||||
fluid = merger.mergeSingle(fluid, other.fluid)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A spawning condition for a [SurfaceSpawningContext].
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since December 15th, 2022
|
||||
*/
|
||||
open class SurfaceSpawningCondition : SurfaceTypeSpawningCondition<SurfaceSpawningContext>() {
|
||||
override fun contextClass() = SurfaceSpawningContext::class.java
|
||||
companion object {
|
||||
const val NAME = "surface"
|
||||
}
|
||||
}
|
||||
+14
@@ -92,4 +92,18 @@ open class LavafloorSpawningContext(
|
||||
height: Int,
|
||||
nearbyBlocks: List<BlockState>,
|
||||
slice: WorldSlice
|
||||
) : FlooredSpawningContext(cause, world, position, light, canSeeSky, influences, width, height, nearbyBlocks, slice)
|
||||
|
||||
open class SurfaceSpawningContext(
|
||||
cause: SpawnCause,
|
||||
world: World,
|
||||
position: BlockPos,
|
||||
light: Int,
|
||||
canSeeSky: Boolean,
|
||||
influences: MutableList<SpawningInfluence>,
|
||||
width: Int,
|
||||
height: Int,
|
||||
val depth: Int,
|
||||
nearbyBlocks: List<BlockState>,
|
||||
slice: WorldSlice
|
||||
) : FlooredSpawningContext(cause, world, position, light, canSeeSky, influences, width, height, nearbyBlocks, slice)
|
||||
+2
@@ -15,6 +15,7 @@ import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.Spawner
|
||||
import net.minecraft.block.Block
|
||||
import net.minecraft.entity.Entity
|
||||
import net.minecraft.fluid.Fluid
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import net.minecraft.util.registry.Registry
|
||||
@@ -65,6 +66,7 @@ abstract class SpawningContext {
|
||||
|
||||
val biomeRegistry: Registry<Biome> by lazy { world.registryManager.get(Registry.BIOME_KEY) }
|
||||
val blockRegistry: Registry<Block> by lazy { world.registryManager.get(Registry.BLOCK_KEY) }
|
||||
val fluidRegistry: Registry<Fluid> by lazy { world.registryManager.get(Registry.FLUID_KEY)}
|
||||
|
||||
val biomeName: Identifier
|
||||
get() = this.biomeRegistry.getId(biome)!!
|
||||
|
||||
+1
-2
@@ -34,6 +34,5 @@ open class SubmergedSpawningContext(
|
||||
nearbyBlocks: List<BlockState>,
|
||||
slice: WorldSlice
|
||||
) : AreaSpawningContext(cause, world, position, light, canSeeSky, influences, width, height, nearbyBlocks, slice) {
|
||||
val fluidBlock = slice.getBlockState(position.x, position.y, position.z).block
|
||||
val fluidState = slice.getBlockState(position.x, position.y, position.z).fluidState
|
||||
val fluid = slice.getBlockState(position.x, position.y, position.z).fluidState
|
||||
}
|
||||
+32
-1
@@ -13,6 +13,7 @@ import com.cobblemon.mod.common.api.spawning.context.FlooredSpawningContext
|
||||
import com.cobblemon.mod.common.api.spawning.context.GroundedSpawningContext
|
||||
import com.cobblemon.mod.common.api.spawning.context.LavafloorSpawningContext
|
||||
import com.cobblemon.mod.common.api.spawning.context.SeafloorSpawningContext
|
||||
import com.cobblemon.mod.common.api.spawning.context.SurfaceSpawningContext
|
||||
import com.cobblemon.mod.common.api.spawning.context.calculators.SpawningContextCalculator.Companion.isAirCondition
|
||||
import com.cobblemon.mod.common.api.spawning.context.calculators.SpawningContextCalculator.Companion.isLavaCondition
|
||||
import com.cobblemon.mod.common.api.spawning.context.calculators.SpawningContextCalculator.Companion.isSolidCondition
|
||||
@@ -120,4 +121,34 @@ object LavafloorSpawningContextCalculator : FlooredSpawningContextCalculator<Lav
|
||||
nearbyBlocks = getNearbyBlocks(input)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The context calculator used for [SurfaceSpawningContext]s. Requires a fluid block below it and
|
||||
* air blocks in its surroundings.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since December 15th, 2022
|
||||
*/
|
||||
object SurfaceSpawningContextCalculator : FlooredSpawningContextCalculator<SurfaceSpawningContext> {
|
||||
override val baseCondition: (BlockState) -> Boolean = { !it.fluidState.isEmpty }
|
||||
override val surroundingCondition: (BlockState) -> Boolean = isAirCondition
|
||||
|
||||
override fun calculate(input: AreaSpawningInput): SurfaceSpawningContext {
|
||||
return SurfaceSpawningContext(
|
||||
cause = input.cause,
|
||||
world = input.world,
|
||||
position = input.position.toImmutable(),
|
||||
light = getLight(input),
|
||||
canSeeSky = getCanSeeSky(input),
|
||||
influences = input.spawner.copyInfluences(),
|
||||
width = getHorizontalSpace(input, surroundingCondition, config.maxHorizontalSpace, offsetY = 1),
|
||||
height = getHeight(input, surroundingCondition, config.maxVerticalSpace / 2, offsetY = 1),
|
||||
depth = getDepth(input, baseCondition, config.maxVerticalSpace / 2),
|
||||
slice = input.slice,
|
||||
nearbyBlocks = getNearbyBlocks(input)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -33,7 +33,8 @@ class BestSpawnerConfig {
|
||||
val replaceWithNewVersion = true
|
||||
val contextWeights = mutableMapOf(
|
||||
"grounded" to 1F,
|
||||
"submerged" to 0.7F
|
||||
"submerged" to 0.95F,
|
||||
"surface" to 0.05F
|
||||
)
|
||||
val buckets = mutableListOf(
|
||||
SpawnBucket("common", 94.4F),
|
||||
|
||||
+5
-5
@@ -13,15 +13,15 @@ import com.cobblemon.mod.common.api.spawning.SpawnCause
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnerManager
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnPool
|
||||
import com.cobblemon.mod.common.util.getPlayer
|
||||
import com.cobblemon.mod.common.util.nextBetween
|
||||
import java.util.UUID
|
||||
import kotlin.math.atan
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.sin
|
||||
import kotlin.random.Random
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.util.math.MathHelper.PI
|
||||
import net.minecraft.util.math.MathHelper.ceil
|
||||
import net.minecraft.util.math.MathHelper.nextBetween
|
||||
import net.minecraft.util.math.random.Random
|
||||
|
||||
/**
|
||||
* A spawner that works around a single player. It will do basic tracking of a player's speed
|
||||
@@ -39,12 +39,12 @@ class PlayerSpawner(player: ServerPlayerEntity, spawns: SpawnPool, manager: Spaw
|
||||
val sliceDiameter = config.worldSliceDiameter
|
||||
val sliceHeight = config.worldSliceHeight
|
||||
|
||||
val rand = Random.create()
|
||||
val rand = Random.Default
|
||||
|
||||
val center = player.pos
|
||||
|
||||
val r = nextBetween(rand, config.minimumSliceDistanceFromPlayer, config.maximumSliceDistanceFromPlayer)
|
||||
val thetatemp = atan(player.velocity.z / player.velocity.x) + nextBetween(rand, -PI/2, PI/2 )
|
||||
val r = rand.nextBetween(config.minimumSliceDistanceFromPlayer, config.maximumSliceDistanceFromPlayer)
|
||||
val thetatemp = atan(player.velocity.z / player.velocity.x) + rand.nextBetween(-PI/2, PI/2 )
|
||||
val theta = if (player.velocity.horizontalLength() < 0.1) {
|
||||
rand.nextDouble() * 2 * PI
|
||||
} else if (player.velocity.x < 0) {
|
||||
|
||||
+10
-6
@@ -44,11 +44,15 @@ open class JSONStoreAdapter(
|
||||
}
|
||||
|
||||
override fun <E, T : PokemonStore<E>> load(file: File, storeClass: Class<out T>, uuid: UUID): T? {
|
||||
val br = BufferedReader(FileReader(file))
|
||||
val json = gson.fromJson<JsonObject>(br)
|
||||
br.close()
|
||||
val store = storeClass.getConstructor(UUID::class.java).newInstance(uuid)
|
||||
store.loadFromJSON(json)
|
||||
return store
|
||||
return try {
|
||||
val br = BufferedReader(FileReader(file))
|
||||
val json = gson.fromJson<JsonObject>(br)
|
||||
br.close()
|
||||
val store = storeClass.getConstructor(UUID::class.java).newInstance(uuid)
|
||||
store.loadFromJSON(json)
|
||||
store
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -38,9 +38,9 @@ open class NBTStoreAdapter(
|
||||
val nbt = NbtIo.readCompressed(file)
|
||||
store.loadFromNBT(nbt)
|
||||
store
|
||||
} catch (eof: EOFException) {
|
||||
LOGGER.error("Pokémon save file for ${storeClass.simpleName} ($uuid) was corrupted. A fresh file will be created.")
|
||||
store
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
@@ -8,6 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.storage.adapter.flatifle
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon.LOGGER
|
||||
import com.cobblemon.mod.common.api.storage.PokemonStore
|
||||
import com.cobblemon.mod.common.api.storage.StorePosition
|
||||
import com.cobblemon.mod.common.api.storage.adapter.CobblemonAdapterParent
|
||||
@@ -67,6 +68,7 @@ abstract class OneToOneFileStoreAdapter<S>(
|
||||
try {
|
||||
val tempLoaded = load(tempFile, storeClass, uuid)
|
||||
if (tempLoaded != null) {
|
||||
save(file, serialize(tempLoaded))
|
||||
return tempLoaded
|
||||
}
|
||||
} finally {
|
||||
@@ -76,6 +78,10 @@ abstract class OneToOneFileStoreAdapter<S>(
|
||||
|
||||
return if (file.exists()) {
|
||||
load(file, storeClass, uuid)
|
||||
?: let {
|
||||
LOGGER.error("Pokémon save file for ${storeClass.simpleName} ($uuid) was corrupted. A fresh file will be created.")
|
||||
storeClass.getConstructor(UUID::class.java).newInstance(uuid)
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ import net.minecraft.network.PacketByteBuf
|
||||
* @since March 9th, 2022
|
||||
*/
|
||||
data class BattleFormat(
|
||||
val mod: String = "Cobblemon",
|
||||
val mod: String = "cobblemon",
|
||||
val battleType: BattleType = BattleTypes.SINGLES,
|
||||
val ruleSet: Set<String> = setOf()
|
||||
) {
|
||||
|
||||
@@ -8,15 +8,12 @@
|
||||
|
||||
package com.cobblemon.mod.common.battles
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon.showdown
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||
import com.cobblemon.mod.common.api.pokemon.status.Statuses
|
||||
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||
import com.cobblemon.mod.common.util.DataKeys
|
||||
import com.cobblemon.mod.common.battles.runner.GraalShowdown
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonObject
|
||||
import java.time.Instant
|
||||
import java.util.Optional
|
||||
import java.util.UUID
|
||||
@@ -113,10 +110,6 @@ object BattleRegistry {
|
||||
return team.joinToString("]")
|
||||
}
|
||||
|
||||
/**
|
||||
* Temporary starting method for a battle.
|
||||
* TODO: Replace with a builder for battle definition and then a starting method that takes the built result?
|
||||
*/
|
||||
fun startBattle(
|
||||
battleFormat: BattleFormat,
|
||||
side1: BattleSide,
|
||||
@@ -126,8 +119,8 @@ object BattleRegistry {
|
||||
battleMap[battle.battleId] = battle
|
||||
|
||||
// Build request message
|
||||
val jsonArray = JsonArray()
|
||||
jsonArray.add(">start { \"format\": ${battleFormat.toFormatJSON()} }")
|
||||
val messages = mutableListOf<String>()
|
||||
messages.add(">start { \"format\": ${battleFormat.toFormatJSON()} }")
|
||||
|
||||
/*
|
||||
* Showdown IDs are like p1, p2, p3, etc. Showdown uses these keys to identify who is doing what to whom.
|
||||
@@ -167,21 +160,16 @@ object BattleRegistry {
|
||||
|
||||
// -> Add the players and team
|
||||
for (actor in battle.actors.sortedBy { it.showdownId }) {
|
||||
jsonArray.add(""">player ${actor.showdownId} {"name":"${actor.uuid}","team":"${actor.pokemonList.packTeam()}"}""")
|
||||
messages.add(""">player ${actor.showdownId} {"name":"${actor.uuid}","team":"${actor.pokemonList.packTeam()}"}""")
|
||||
}
|
||||
|
||||
// -> Set team size
|
||||
for (actor in battle.actors.sortedBy { it.showdownId }) {
|
||||
jsonArray.add(">${actor.showdownId} team ${actor.pokemonList.count()}")
|
||||
messages.add(">${actor.showdownId} team ${actor.pokemonList.count()}")
|
||||
}
|
||||
|
||||
// Compiles the request and sends it off
|
||||
val request = JsonObject()
|
||||
request.addProperty(DataKeys.REQUEST_TYPE, DataKeys.REQUEST_BATTLE_START)
|
||||
request.addProperty(DataKeys.REQUEST_BATTLE_ID, battle.battleId.toString())
|
||||
request.add(DataKeys.REQUEST_MESSAGES, jsonArray)
|
||||
showdown.write(gson.toJson(request))
|
||||
|
||||
GraalShowdown.startBattle(battle, messages.toTypedArray())
|
||||
return battle
|
||||
}
|
||||
|
||||
|
||||
@@ -99,7 +99,7 @@ data class MoveActionResponse(var moveName: String, var targetPnx: String? = nul
|
||||
// No PP or disabled or something
|
||||
return false
|
||||
}
|
||||
val availableTargets = move.target.targetList(activeBattlePokemon) ?: return true
|
||||
val availableTargets = move.target.targetList(activeBattlePokemon)?.takeIf { it.isNotEmpty() } ?: return true
|
||||
|
||||
val pnx = targetPnx ?: return false // If the targets list is non-null then they need to have specified a target
|
||||
val (_, targetPokemon) = activeBattlePokemon.actor.battle.getActorAndActiveSlotFromPNX(pnx)
|
||||
|
||||
@@ -28,7 +28,6 @@ import com.cobblemon.mod.common.battles.dispatch.GO
|
||||
import com.cobblemon.mod.common.battles.dispatch.UntilDispatch
|
||||
import com.cobblemon.mod.common.battles.dispatch.WaitDispatch
|
||||
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||
import com.cobblemon.mod.common.battles.runner.ShowdownConnection
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleFaintPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleHealthChangePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleInitializePacket
|
||||
@@ -96,6 +95,7 @@ object ShowdownInterpreter {
|
||||
updateInstructions["|-status|"] = this::handleStatusInstruction
|
||||
updateInstructions["|-end|"] = this::handleEndInstruction
|
||||
updateInstructions["|-miss|"] = this::handleMissInstruction
|
||||
updateInstructions["|-hitcount|"] = this::handleHitCountInstruction
|
||||
|
||||
sideUpdateInstructions["|request|"] = this::handleRequestInstruction
|
||||
splitUpdateInstructions["|switch|"] = this::handleSwitchInstruction
|
||||
@@ -149,18 +149,15 @@ object ShowdownInterpreter {
|
||||
else -> "HUH!?"
|
||||
}
|
||||
|
||||
fun interpretMessage(message: String) {
|
||||
fun interpretMessage(battleId: UUID, message: String) {
|
||||
// Check key map and use function if matching
|
||||
val battleId = message.split(ShowdownConnection.LINE_START)[0]
|
||||
val rawMessage = message.replace(battleId + ShowdownConnection.LINE_START, "")
|
||||
|
||||
if (rawMessage.startsWith("{\"winner\":\"")) {
|
||||
if (message.startsWith("{\"winner\":\"")) {
|
||||
// The post-win message is something we don't care about just yet. It's basically a summary of what happened in the battle.
|
||||
// Check /docs/example-post-win-message.json for its format.
|
||||
return
|
||||
}
|
||||
|
||||
val battle = BattleRegistry.getBattle(UUID.fromString(battleId))
|
||||
val battle = BattleRegistry.getBattle(battleId)
|
||||
|
||||
if (battle == null) {
|
||||
LOGGER.info("No battle could be found with the id: $battleId")
|
||||
@@ -169,7 +166,7 @@ object ShowdownInterpreter {
|
||||
|
||||
runOnServer {
|
||||
battle.showdownMessages.add(message)
|
||||
interpret(battle, rawMessage)
|
||||
interpret(battle, message)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -904,4 +901,14 @@ object ShowdownInterpreter {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// |-hitcount|POKEMON|NUM
|
||||
fun handleHitCountInstruction(battle: PokemonBattle, message: String, remainingLines: MutableList<String>) {
|
||||
battle.dispatchGo {
|
||||
val hitCount = message.substringAfterLast("|").toIntOrNull() ?: -1
|
||||
val lang = if (hitCount == 1) battleLang("hit_count_singular") else battleLang("hit_count", hitCount)
|
||||
battle.broadcastChatMessage(lang)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -11,19 +11,17 @@ package com.cobblemon.mod.common.battles
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.Cobblemon.LOGGER
|
||||
import com.cobblemon.mod.common.Cobblemon.config
|
||||
import com.cobblemon.mod.common.Cobblemon.showdown
|
||||
import com.cobblemon.mod.common.battles.runner.JavetShowdownConnection
|
||||
import com.cobblemon.mod.common.battles.runner.GraalShowdown
|
||||
import com.cobblemon.mod.common.util.FileUtils
|
||||
import com.cobblemon.mod.common.util.extractTo
|
||||
import com.cobblemon.mod.common.util.fromJson
|
||||
import com.google.gson.GsonBuilder
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
import java.io.IOException
|
||||
import java.io.InputStreamReader
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import net.minecraft.client.MinecraftClient
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
class ShowdownThread : Thread("Cobblemon Showdown") {
|
||||
|
||||
var showdownStarted = CompletableFuture<Unit>()
|
||||
@@ -32,7 +30,8 @@ class ShowdownThread : Thread("Cobblemon Showdown") {
|
||||
.create()
|
||||
|
||||
override fun run() {
|
||||
var showdownDir = File(".")
|
||||
var showdownDir = File("showdown")
|
||||
showdownDir.mkdir()
|
||||
|
||||
val showdownMetadata = loadShowdownMetadata()
|
||||
|
||||
@@ -63,73 +62,13 @@ class ShowdownThread : Thread("Cobblemon Showdown") {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Initialize showdown connection
|
||||
showdown = JavetShowdownConnection()
|
||||
(showdown as JavetShowdownConnection).initializeServer()
|
||||
GraalShowdown.createContext()
|
||||
GraalShowdown.boot()
|
||||
|
||||
// Sleep for two seconds before attempting connection
|
||||
sleep(2000)
|
||||
|
||||
val maxTries = 15
|
||||
var tries = 0
|
||||
|
||||
// If connection fails, wait another two seconds
|
||||
while (!attemptConnection() && tries < maxTries) {
|
||||
tries++
|
||||
sleep(3000)
|
||||
}
|
||||
|
||||
// Max attempts
|
||||
if (tries == maxTries) {
|
||||
LOGGER.error("Failed to connect to showdown after 5 tries.")
|
||||
MinecraftClient.getInstance().close()
|
||||
}
|
||||
|
||||
LOGGER.info("Showdown has been connected!")
|
||||
LOGGER.info("Showdown has been started!")
|
||||
showdownStarted.complete(Unit)
|
||||
|
||||
// Reset tries as this will be used by reconnection attempts
|
||||
tries = 0
|
||||
|
||||
// While showdown is not closed, continue to check connection and read messages
|
||||
while (!showdown.isClosed()) {
|
||||
|
||||
// Attempt reconnection if not connected
|
||||
if (!showdown.isConnected()) {
|
||||
while (!attemptConnection() && tries < maxTries) {
|
||||
tries++
|
||||
sleep(3000)
|
||||
}
|
||||
|
||||
// Max attempts
|
||||
if (tries == maxTries) {
|
||||
LOGGER.error("Failed to connect to showdown after 5 tries.")
|
||||
MinecraftClient.getInstance().close()
|
||||
}
|
||||
|
||||
tries = 0
|
||||
LOGGER.info("Showdown has been reconnected!")
|
||||
}
|
||||
|
||||
// Reads messages and don't destroy the connection if there is an error
|
||||
try {
|
||||
showdown.read(ShowdownInterpreter::interpretMessage)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
// Read messages every half a second
|
||||
sleep(500)
|
||||
}
|
||||
}
|
||||
|
||||
private fun attemptConnection() : Boolean {
|
||||
try {
|
||||
showdown.open()
|
||||
return true
|
||||
} catch (exception: IOException) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadShowdownMetadata() : ShowdownMetadata? {
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.runner
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import java.util.logging.Handler
|
||||
import java.util.logging.Level
|
||||
import java.util.logging.LogRecord
|
||||
|
||||
object GraalLogger : Handler() {
|
||||
override fun publish(record: LogRecord?) {
|
||||
if(record == null) {
|
||||
return
|
||||
}
|
||||
|
||||
when (record.level) {
|
||||
Level.INFO -> Cobblemon.LOGGER.info(record.message)
|
||||
Level.WARNING -> Cobblemon.LOGGER.warn(record.message)
|
||||
Level.SEVERE -> Cobblemon.LOGGER.error(record.message)
|
||||
else -> Cobblemon.LOGGER.debug(record.message)
|
||||
}
|
||||
}
|
||||
|
||||
override fun flush() {}
|
||||
|
||||
override fun close() {}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.runner
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.battles.ShowdownInterpreter
|
||||
import java.io.File
|
||||
import java.util.UUID
|
||||
import org.graalvm.polyglot.Context
|
||||
import org.graalvm.polyglot.HostAccess
|
||||
import org.graalvm.polyglot.PolyglotAccess
|
||||
import org.graalvm.polyglot.Value
|
||||
|
||||
object GraalShowdown {
|
||||
@Transient
|
||||
lateinit var context: Context
|
||||
@Transient
|
||||
lateinit var sendBattleMessageFunction: Value
|
||||
fun createContext() {
|
||||
val access = HostAccess.newBuilder(HostAccess.ALL).build()
|
||||
context = Context.newBuilder("js")
|
||||
.allowIO(true)
|
||||
.allowExperimentalOptions(true)
|
||||
.allowPolyglotAccess(PolyglotAccess.ALL)
|
||||
.allowHostAccess(access)
|
||||
.allowAllAccess(true)
|
||||
.allowCreateThread(true)
|
||||
.logHandler(GraalLogger)
|
||||
.option("engine.WarnInterpreterOnly", "false")
|
||||
.option("js.commonjs-require", "true")
|
||||
.option("js.commonjs-require-cwd", "showdown")
|
||||
.option(
|
||||
"js.commonjs-core-modules-replacements",
|
||||
"buffer:buffer/,crypto:crypto-browserify,path:path-browserify"
|
||||
)
|
||||
.allowHostClassLoading(true)
|
||||
.allowNativeAccess(true)
|
||||
.allowCreateProcess(true)
|
||||
.build()
|
||||
|
||||
context.eval("js", """
|
||||
globalThis.process = {
|
||||
cwd: function() {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun boot() {
|
||||
context.eval("js", File("showdown/index.js").readText())
|
||||
sendBattleMessageFunction = context.getBindings("js").getMember("sendBattleMessage")
|
||||
}
|
||||
|
||||
fun startBattle(battle: PokemonBattle, messages: Array<String>) {
|
||||
val startBattleFunction = context.getBindings("js").getMember("startBattle")
|
||||
startBattleFunction.execute(GraalShowdown, battle.battleId.toString(), messages)
|
||||
}
|
||||
|
||||
fun sendFromShowdown(battleId: String, message: String) {
|
||||
ShowdownInterpreter.interpretMessage(UUID.fromString(battleId), message)
|
||||
}
|
||||
|
||||
fun sendToShowdown(battleId: UUID, messages: Array<String>) {
|
||||
sendBattleMessageFunction.execute(battleId.toString(), messages)
|
||||
}
|
||||
}
|
||||
-72
@@ -1,72 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.runner
|
||||
|
||||
import java.io.BufferedReader
|
||||
import java.io.IOException
|
||||
import java.io.InputStreamReader
|
||||
import java.io.OutputStreamWriter
|
||||
import java.net.InetAddress
|
||||
import java.net.Socket
|
||||
import java.nio.charset.Charset
|
||||
class JavetShowdownConnection : ShowdownConnection {
|
||||
|
||||
private lateinit var socket: Socket
|
||||
private lateinit var writer: OutputStreamWriter
|
||||
private lateinit var reader: BufferedReader
|
||||
private var data = ""
|
||||
private var closed = false
|
||||
private val serverThread = Thread({ ShowdownServer.start() }, "Cobblemon Showdown Server")
|
||||
|
||||
fun initializeServer() {
|
||||
serverThread.start()
|
||||
}
|
||||
|
||||
override fun open() {
|
||||
socket = Socket(InetAddress.getLocalHost(), ShowdownServer.port, InetAddress.getLocalHost(), 0)
|
||||
socket.keepAlive = true
|
||||
writer = socket.getOutputStream().writer(charset = Charset.forName("ascii"))
|
||||
reader = BufferedReader(InputStreamReader(socket.getInputStream()))
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
socket.close()
|
||||
closed = true
|
||||
}
|
||||
|
||||
override fun write(input: String) {
|
||||
writer.write(input + ShowdownConnection.LINE_END)
|
||||
writer.flush()
|
||||
}
|
||||
|
||||
override fun read(messageHandler: (String) -> Unit) {
|
||||
try {
|
||||
while (reader.ready()) {
|
||||
val char = reader.read()
|
||||
if (char > -1) {
|
||||
data += char.toChar()
|
||||
if (data.endsWith(ShowdownConnection.LINE_END)) {
|
||||
messageHandler(data.replace(ShowdownConnection.LINE_END, ""))
|
||||
data = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (exception: IOException) {
|
||||
exception.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
override fun isClosed() : Boolean {
|
||||
return closed
|
||||
}
|
||||
|
||||
override fun isConnected(): Boolean {
|
||||
return socket.isConnected
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.runner
|
||||
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
|
||||
/**
|
||||
* Modified from https://lankydan.dev/running-a-kotlin-class-as-a-subprocess
|
||||
*
|
||||
* Spawns a process and returns it
|
||||
*/
|
||||
@Throws(IOException::class, InterruptedException::class)
|
||||
fun exec(clazz: Class<*>, args: List<String> = emptyList(), jvmArgs: List<String> = emptyList()): Process {
|
||||
val javaHome = System.getProperty("java.home")
|
||||
val javaBin = javaHome + File.separator + "bin" + File.separator + "java"
|
||||
val classpath = System.getProperty("java.class.path")
|
||||
val className = clazz.name
|
||||
|
||||
val command = ArrayList<String>()
|
||||
command.add(javaBin)
|
||||
command.addAll(jvmArgs)
|
||||
command.add("-cp")
|
||||
command.add(classpath)
|
||||
command.add(className)
|
||||
command.addAll(args)
|
||||
|
||||
val builder = ProcessBuilder(command)
|
||||
return builder.inheritIO().start()
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.runner
|
||||
|
||||
interface ShowdownConnection {
|
||||
fun open()
|
||||
fun close()
|
||||
fun write(input: String)
|
||||
fun read(messageHandler: (String) -> Unit)
|
||||
fun isClosed(): Boolean
|
||||
fun isConnected(): Boolean
|
||||
|
||||
companion object {
|
||||
const val LINE_END = "{EOT}"
|
||||
const val LINE_START = "{SOT}"
|
||||
}
|
||||
}
|
||||
@@ -1,180 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.runner
|
||||
|
||||
import com.caoccao.javet.interop.V8Host
|
||||
import com.caoccao.javet.interop.V8Runtime
|
||||
import java.net.DatagramSocket
|
||||
import java.net.ServerSocket
|
||||
|
||||
object ShowdownServer {
|
||||
var minPort = 25650
|
||||
var maxPort = 25700
|
||||
var port = 0
|
||||
fun findOpenPort(): Int? {
|
||||
for (port in minPort..maxPort) {
|
||||
if (isOpenPort(port)) {
|
||||
return port
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun isOpenPort(port: Int): Boolean {
|
||||
var ss: ServerSocket? = null
|
||||
var ds: DatagramSocket? = null
|
||||
try {
|
||||
ss = ServerSocket(port)
|
||||
ss.reuseAddress = true
|
||||
ds = DatagramSocket(port)
|
||||
ds.reuseAddress = true
|
||||
return true
|
||||
} catch (_: Exception) {
|
||||
} finally {
|
||||
try { ss?.close() } catch (_: Exception) {}
|
||||
try { ds?.close() } catch (_: Exception) {}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun start() {
|
||||
val port = findOpenPort() ?: throw IllegalStateException("No port open in range $minPort-$maxPort for Showdown to start on!")
|
||||
this.port = port
|
||||
val runtime = V8Host.getNodeInstance().createV8Runtime<V8Runtime>()
|
||||
runtime.use {
|
||||
val executor = it.getExecutor(
|
||||
"""
|
||||
const PokemonShowdown = require('pokemon-showdown');
|
||||
var Net = require('net')
|
||||
|
||||
const port = $port;
|
||||
const battleMap = new Map();
|
||||
|
||||
// Use net.createServer() in your code. This is just for illustration purpose.
|
||||
// Create a new TCP server.
|
||||
const server = Net.createServer();
|
||||
// The server listens to a socket for a client to make a connection request.
|
||||
// Think of a socket as an end point.
|
||||
server.listen(port, function () {
|
||||
console.log('Server listening for connection requests on socket localhost: ' + port);
|
||||
});
|
||||
|
||||
// When a client requests a connection with the server, the server creates a new
|
||||
// socket dedicated to that client.
|
||||
server.on('connection', function (socket) {
|
||||
console.log('A new connection has been established.');
|
||||
|
||||
// The server can also receive data from the client by reading from its socket.
|
||||
// The end of the message is the tag {EOT}
|
||||
let messageBuffer = new MessageBuffer("{EOT}")
|
||||
socket.on('data', function (chunk) {
|
||||
messageBuffer.push(chunk);
|
||||
|
||||
// When is a message is fully formed from chunking, we handle the data
|
||||
while (!messageBuffer.isFinished()) {
|
||||
const message = messageBuffer.handleData()
|
||||
try {
|
||||
// Parses the request and goes over message types
|
||||
const request = JSON.parse(message);
|
||||
switch(request.RequestType) {
|
||||
case 'StartBattle': {
|
||||
const battleStream = new PokemonShowdown.BattleStream();
|
||||
battleMap.set(request.RequestBattleId, battleStream);
|
||||
|
||||
// Join messages with new line
|
||||
for(const element of request.RequestMessages) {
|
||||
battleStream.write(element);
|
||||
}
|
||||
|
||||
// Any battle output then gets written to the socket
|
||||
// TODO: Send the battle id with this
|
||||
// TODO: Add a way to cancel battle earlier and close stream
|
||||
(async () => {
|
||||
for await (const output of battleStream) {
|
||||
socket.write(request.RequestBattleId + "{SOT}" + output + "{EOT}")
|
||||
}
|
||||
})();
|
||||
break;
|
||||
}
|
||||
case 'SendMessage': {
|
||||
const battleStream = battleMap.get(request.RequestBattleId)
|
||||
for(const element of request.RequestMessages) {
|
||||
battleStream.write(element);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// When the client requests to end the TCP connection with the server, the server
|
||||
// ends the connection.
|
||||
socket.on('end', function () {
|
||||
console.log('Closing connection with the client');
|
||||
server.close();
|
||||
});
|
||||
|
||||
// Don't forget to catch error, for your own sake.
|
||||
socket.on('error', function (err) {
|
||||
console.log(`Error: ` + err);
|
||||
});
|
||||
});
|
||||
|
||||
class MessageBuffer {
|
||||
constructor(delimiter) {
|
||||
this.delimiter = delimiter
|
||||
this.buffer = ""
|
||||
}
|
||||
|
||||
isFinished() {
|
||||
if (
|
||||
this.buffer.length === 0 ||
|
||||
this.buffer.indexOf(this.delimiter) === -1
|
||||
) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
push(data) {
|
||||
this.buffer += data
|
||||
}
|
||||
|
||||
getMessage() {
|
||||
const delimiterIndex = this.buffer.indexOf(this.delimiter)
|
||||
if (delimiterIndex !== -1) {
|
||||
const message = this.buffer.slice(0, delimiterIndex)
|
||||
this.buffer = this.buffer.replace(message + this.delimiter, "")
|
||||
return message
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
handleData() {
|
||||
/**
|
||||
* Try to accumulate the buffer with messages
|
||||
*
|
||||
* If the server isn't sending delimiters for some reason
|
||||
* then nothing will ever come back for these requests
|
||||
*/
|
||||
const message = this.getMessage()
|
||||
return message
|
||||
}
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
executor.resourceName = "./node_modules"
|
||||
executor.executeVoid()
|
||||
}
|
||||
}
|
||||
}
|
||||
-67
@@ -1,67 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.runner
|
||||
|
||||
import java.io.BufferedReader
|
||||
import java.io.IOException
|
||||
import java.io.InputStreamReader
|
||||
import java.io.OutputStreamWriter
|
||||
import java.net.InetAddress
|
||||
import java.net.Socket
|
||||
import java.nio.charset.Charset
|
||||
class StandardShowdownConnection(host: InetAddress, port: Int): ShowdownConnection {
|
||||
|
||||
private lateinit var socket: Socket
|
||||
private lateinit var writer: OutputStreamWriter
|
||||
private lateinit var reader: BufferedReader
|
||||
private var data = ""
|
||||
private var closed: Boolean = false
|
||||
|
||||
override fun open() {
|
||||
socket = Socket(InetAddress.getLocalHost(), 25567, InetAddress.getLocalHost(), 25566)
|
||||
socket.keepAlive = true
|
||||
writer = socket.getOutputStream().writer(charset = Charset.forName("ascii"))
|
||||
reader = BufferedReader(InputStreamReader(socket.getInputStream()))
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
socket.close()
|
||||
closed = true
|
||||
}
|
||||
|
||||
override fun write(input: String) {
|
||||
writer.write(input + ShowdownConnection.LINE_END)
|
||||
writer.flush()
|
||||
}
|
||||
|
||||
override fun read(messageHandler: (String) -> Unit) {
|
||||
try {
|
||||
while (reader.ready()) {
|
||||
val char = reader.read()
|
||||
if (char > -1) {
|
||||
data += char.toChar()
|
||||
if (data.endsWith(ShowdownConnection.LINE_END)) {
|
||||
messageHandler(data.replace(ShowdownConnection.LINE_END, ""))
|
||||
data = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (exception: IOException) {
|
||||
exception.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
override fun isClosed(): Boolean {
|
||||
return closed
|
||||
}
|
||||
|
||||
override fun isConnected(): Boolean {
|
||||
return socket.isConnected
|
||||
}
|
||||
}
|
||||
@@ -151,7 +151,7 @@ object CobblemonClient {
|
||||
|
||||
fun reloadCodedAssets(resourceManager: ResourceManager) {
|
||||
LOGGER.info("Reloading assets")
|
||||
BedrockAnimationRepository.clear()
|
||||
BedrockAnimationRepository.loadAnimations(resourceManager)
|
||||
PokemonModelRepository.reload(resourceManager)
|
||||
LOGGER.info("Loaded assets")
|
||||
// PokeBallModelRepository.reload(resourceManager)
|
||||
|
||||
@@ -22,6 +22,7 @@ class ClientBattlePokemon(
|
||||
val uuid: UUID,
|
||||
var displayName: MutableText,
|
||||
var properties: PokemonProperties,
|
||||
var aspects: Set<String>,
|
||||
var hpRatio: Float,
|
||||
var status: PersistentStatus?,
|
||||
var statChanges: MutableMap<Stat, Int>
|
||||
|
||||
+24
-10
@@ -6,39 +6,53 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.gui.summary
|
||||
package com.cobblemon.mod.common.client.gui
|
||||
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.client.gui.widget.ButtonWidget
|
||||
import net.minecraft.client.sound.SoundManager
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
import net.minecraft.text.Text
|
||||
|
||||
class ExitButton(
|
||||
pX: Int, pY: Int,
|
||||
onPress: PressAction
|
||||
): ButtonWidget(pX, pY, (WIDTH * SCALE).toInt(), (HEIGHT * SCALE).toInt(), Text.literal(""), onPress) {
|
||||
): ButtonWidget(pX, pY, WIDTH.toInt(), HEIGHT.toInt(), Text.literal("Exit"), onPress) {
|
||||
|
||||
companion object {
|
||||
private const val WIDTH = 52F
|
||||
private const val HEIGHT = 26F
|
||||
private const val WIDTH = 26F
|
||||
private const val HEIGHT = 13F
|
||||
private const val SCALE = 0.5F
|
||||
private val exitButtonResource = cobblemonResource("ui/summary/summary_back_button.png")
|
||||
private val buttonResource = cobblemonResource("ui/common/back_button.png")
|
||||
private val iconResource = cobblemonResource("ui/common/back_button_icon.png")
|
||||
}
|
||||
|
||||
override fun renderButton(pMatrixStack: MatrixStack, pMouseX: Int, pMouseY: Int, pPartialTicks: Float) {
|
||||
blitk(
|
||||
matrixStack = pMatrixStack,
|
||||
texture = exitButtonResource,
|
||||
x = x * 2,
|
||||
y = y * 2,
|
||||
texture = buttonResource,
|
||||
x = x,
|
||||
y = y,
|
||||
width = WIDTH,
|
||||
height = HEIGHT,
|
||||
vOffset = if (isHovered(pMouseX.toDouble(), pMouseY.toDouble())) HEIGHT else 0,
|
||||
textureHeight = HEIGHT * 2,
|
||||
textureHeight = HEIGHT * 2
|
||||
)
|
||||
|
||||
blitk(
|
||||
matrixStack = pMatrixStack,
|
||||
texture = iconResource,
|
||||
x = (x + 7) / SCALE,
|
||||
y = (y + 4) / SCALE,
|
||||
width = 21,
|
||||
height = 11,
|
||||
scale = SCALE
|
||||
)
|
||||
}
|
||||
|
||||
fun isHovered(mouseX: Double, mouseY: Double) = mouseX.toFloat() in (x.toFloat()..(x.toFloat() + (WIDTH * SCALE))) && mouseY.toFloat() in (y.toFloat()..(y.toFloat() + (HEIGHT * SCALE)))
|
||||
override fun playDownSound(soundManager: SoundManager) {
|
||||
}
|
||||
|
||||
fun isHovered(mouseX: Double, mouseY: Double) = mouseX.toFloat() in (x.toFloat()..(x.toFloat() + WIDTH)) && mouseY.toFloat() in (y.toFloat()..(y.toFloat() + HEIGHT))
|
||||
}
|
||||
@@ -163,7 +163,7 @@ class BattleOverlay : InGameHud(MinecraftClient.getInstance(), MinecraftClient.g
|
||||
reversed = !left,
|
||||
species = battlePokemon.species,
|
||||
level = battlePokemon.level,
|
||||
aspects = battlePokemon.properties.aspects,
|
||||
aspects = battlePokemon.aspects,
|
||||
displayName = battlePokemon.displayName,
|
||||
gender = battlePokemon.gender,
|
||||
status = battlePokemon.status,
|
||||
|
||||
+7
@@ -8,6 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.client.gui.battle.subscreen
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.ActorType
|
||||
import com.cobblemon.mod.common.client.CobblemonClient
|
||||
import com.cobblemon.mod.common.client.battle.SingleActionRequest
|
||||
@@ -17,6 +18,8 @@ import com.cobblemon.mod.common.util.battleLang
|
||||
import net.minecraft.client.MinecraftClient
|
||||
import net.minecraft.client.gui.Selectable
|
||||
import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder
|
||||
import net.minecraft.client.sound.PositionedSoundInstance
|
||||
import net.minecraft.client.sound.SoundManager
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
import net.minecraft.text.MutableText
|
||||
import net.minecraft.util.Identifier
|
||||
@@ -94,5 +97,9 @@ class BattleGeneralActionSelection(
|
||||
override fun appendNarrations(builder: NarrationMessageBuilder) {
|
||||
}
|
||||
|
||||
override fun playDownSound(soundManager: SoundManager) {
|
||||
soundManager.play(PositionedSoundInstance.master(CobblemonSounds.GUI_CLICK.get(), 1.0F))
|
||||
}
|
||||
|
||||
override fun getType() = Selectable.SelectionType.NONE
|
||||
}
|
||||
+8
-1
@@ -8,6 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.client.gui.battle.subscreen
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.api.moves.Moves
|
||||
import com.cobblemon.mod.common.api.text.bold
|
||||
@@ -26,6 +27,8 @@ import com.cobblemon.mod.common.util.battleLang
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.math.toRGB
|
||||
import net.minecraft.client.MinecraftClient
|
||||
import net.minecraft.client.sound.PositionedSoundInstance
|
||||
import net.minecraft.client.sound.SoundManager
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.util.math.MathHelper.floor
|
||||
@@ -156,7 +159,7 @@ class BattleMoveSelection(
|
||||
}
|
||||
moveSelection.playDownSound(MinecraftClient.getInstance().soundManager)
|
||||
val targets = move.target.targetList(moveSelection.request.activePokemon)
|
||||
if (targets == null) {
|
||||
if (targets.isNullOrEmpty()) {
|
||||
moveSelection.battleGUI.selectAction(moveSelection.request, MoveActionResponse(move.id, null))
|
||||
} else if (targets.size == 1) {
|
||||
moveSelection.battleGUI.selectAction(moveSelection.request, MoveActionResponse(move.id, targets[0].getPNX()))
|
||||
@@ -185,4 +188,8 @@ class BattleMoveSelection(
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun playDownSound(soundManager: SoundManager) {
|
||||
soundManager.play(PositionedSoundInstance.master(CobblemonSounds.GUI_CLICK.get(), 1.0F))
|
||||
}
|
||||
}
|
||||
+7
@@ -8,6 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.client.gui.battle.subscreen
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.battles.ShowdownPokemon
|
||||
import com.cobblemon.mod.common.battles.SwitchActionResponse
|
||||
import com.cobblemon.mod.common.client.CobblemonClient
|
||||
@@ -19,6 +20,8 @@ import com.cobblemon.mod.common.util.battleLang
|
||||
import net.minecraft.client.MinecraftClient
|
||||
import net.minecraft.client.gui.Selectable
|
||||
import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder
|
||||
import net.minecraft.client.sound.PositionedSoundInstance
|
||||
import net.minecraft.client.sound.SoundManager
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
import net.minecraft.util.math.MathHelper.ceil
|
||||
class BattleSwitchPokemonSelection(
|
||||
@@ -120,5 +123,9 @@ class BattleSwitchPokemonSelection(
|
||||
override fun appendNarrations(builder: NarrationMessageBuilder) {
|
||||
}
|
||||
|
||||
override fun playDownSound(soundManager: SoundManager) {
|
||||
soundManager.play(PositionedSoundInstance.master(CobblemonSounds.GUI_CLICK.get(), 1.0F))
|
||||
}
|
||||
|
||||
override fun getType() = Selectable.SelectionType.HOVERED
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.gui.pc
|
||||
|
||||
import com.cobblemon.mod.common.api.storage.pc.PCPosition
|
||||
import com.cobblemon.mod.common.client.storage.ClientPC
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
|
||||
class BoxStorageSlot(
|
||||
x: Int, y: Int,
|
||||
private val parent: StorageWidget,
|
||||
private val pc: ClientPC,
|
||||
val position: PCPosition,
|
||||
onPress: PressAction
|
||||
) : StorageSlot(x, y, parent, onPress) {
|
||||
|
||||
override fun getPokemon(): Pokemon? {
|
||||
return pc.get(position)
|
||||
}
|
||||
|
||||
override fun shouldRender(): Boolean {
|
||||
val grabbedSlot = parent.grabbedSlot
|
||||
return if (grabbedSlot == null) {
|
||||
true
|
||||
} else {
|
||||
grabbedSlot.getPokemon() != getPokemon()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.gui.pc
|
||||
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.client.gui.widget.TexturedButtonWidget
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
class ExitButton(
|
||||
pX: Int, pY: Int,
|
||||
val pWidth: Int, val pHeight: Int,
|
||||
pXTexStart: Int, pYTexStart: Int, pYDiffText: Int,
|
||||
onPress: PressAction
|
||||
): TexturedButtonWidget(pX, pY, pWidth, pHeight, pXTexStart, pYTexStart, pYDiffText, exitButtonResource, onPress) {
|
||||
|
||||
companion object {
|
||||
private val exitButtonResource = cobblemonResource("ui/pc/pc_exit.png")
|
||||
}
|
||||
|
||||
override fun renderButton(pMatrixStack: MatrixStack, pMouseX: Int, pMouseY: Int, pPartialTicks: Float) {
|
||||
hovered = pMouseX >= x && pMouseY >= y && pMouseX < x + width && pMouseY < y + height
|
||||
if (isHovered) {
|
||||
blitk(
|
||||
matrixStack = pMatrixStack,
|
||||
x = x + 0.1, y = y - 1F,
|
||||
texture = exitButtonResource,
|
||||
width = pWidth, height = pHeight
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.gui.pc
|
||||
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
|
||||
class GrabbedStorageSlot(
|
||||
x: Int, y: Int,
|
||||
parent: StorageWidget,
|
||||
private val pokemon: Pokemon
|
||||
) : StorageSlot(x, y, parent, {}) {
|
||||
|
||||
override fun render(matrices: MatrixStack, mouseX: Int, mouseY: Int, delta: Float) {
|
||||
renderSlot(matrices, mouseX - (width / 2), mouseY - (height / 2))
|
||||
}
|
||||
|
||||
override fun getPokemon(): Pokemon? {
|
||||
return pokemon
|
||||
}
|
||||
|
||||
override fun isSelected(): Boolean {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -8,33 +8,47 @@
|
||||
|
||||
package com.cobblemon.mod.common.client.gui.pc
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.client.gui.widget.TexturedButtonWidget
|
||||
import net.minecraft.client.gui.widget.ButtonWidget
|
||||
import net.minecraft.client.sound.PositionedSoundInstance
|
||||
import net.minecraft.client.sound.SoundManager
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
import net.minecraft.text.Text
|
||||
|
||||
class NavigationButton(
|
||||
pX: Int, pY: Int,
|
||||
val pWidth: Int, val pHeight: Int,
|
||||
pXTexStart: Int, pYTexStart: Int, pYDiffText: Int,
|
||||
private val forward: Boolean,
|
||||
onPress: PressAction,
|
||||
): TexturedButtonWidget(pX, pY, pWidth, pHeight, pXTexStart, pYTexStart, pYDiffText, forwardButtonResource, onPress) {
|
||||
onPress: PressAction
|
||||
): ButtonWidget(pX, pY, (WIDTH * SCALE).toInt(), (HEIGHT * SCALE).toInt(), Text.literal("Navigation"), onPress) {
|
||||
|
||||
companion object {
|
||||
private val forwardButtonResource = cobblemonResource("ui/pc/pc_box_right.png")
|
||||
private val backwardsButtonResource = cobblemonResource("ui/pc/pc_box_left.png")
|
||||
private const val WIDTH = 8F
|
||||
private const val HEIGHT = 10F
|
||||
private const val SCALE = 0.5F
|
||||
private val forwardButtonResource = cobblemonResource("ui/pc/pc_arrow_next.png")
|
||||
private val backwardsButtonResource = cobblemonResource("ui/pc/pc_arrow_previous.png")
|
||||
}
|
||||
|
||||
override fun renderButton(pMatrixStack: MatrixStack, pMouseX: Int, pMouseY: Int, pPartialTicks: Float) {
|
||||
hovered = pMouseX >= x && pMouseY >= y && pMouseX < x + width && pMouseY < y + height
|
||||
if (isHovered) {
|
||||
blitk(
|
||||
matrixStack = pMatrixStack,
|
||||
x = x + 0.25, y = y - 0.5F,
|
||||
texture = if (forward) forwardButtonResource else backwardsButtonResource,
|
||||
width = pWidth, height = pHeight
|
||||
)
|
||||
}
|
||||
val hovered = (isHovered(pMouseX.toDouble(), pMouseY.toDouble()))
|
||||
blitk(
|
||||
matrixStack = pMatrixStack,
|
||||
x = x / SCALE,
|
||||
y = y / SCALE,
|
||||
texture = if (forward) forwardButtonResource else backwardsButtonResource,
|
||||
width = WIDTH,
|
||||
height = HEIGHT,
|
||||
vOffset = if (hovered) HEIGHT else 0,
|
||||
textureHeight = HEIGHT * 2,
|
||||
scale = SCALE
|
||||
)
|
||||
}
|
||||
|
||||
override fun playDownSound(soundManager: SoundManager) {
|
||||
soundManager.play(PositionedSoundInstance.master(CobblemonSounds.GUI_CLICK.get(), 1.0F))
|
||||
}
|
||||
|
||||
fun isHovered(mouseX: Double, mouseY: Double) = mouseX.toFloat() in (x.toFloat()..(x.toFloat() + (WIDTH * SCALE))) && mouseY.toFloat() in (y.toFloat()..(y.toFloat() + (HEIGHT * SCALE)))
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.gui.pc
|
||||
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.api.storage.pc.PCPosition
|
||||
import com.cobblemon.mod.common.client.gui.drawProfilePokemon
|
||||
import com.cobblemon.mod.common.client.storage.ClientPC
|
||||
import com.cobblemon.mod.common.util.scaleIt
|
||||
import com.mojang.blaze3d.systems.RenderSystem
|
||||
import net.minecraft.client.MinecraftClient
|
||||
import net.minecraft.client.gui.widget.ButtonWidget
|
||||
import net.minecraft.client.sound.SoundManager
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.util.math.Quaternion
|
||||
import net.minecraft.util.math.Vec3f
|
||||
class PCBoxMemberWidget(
|
||||
x: Int, y: Int,
|
||||
private val parent: PCWidget,
|
||||
private val pcGui: PCGui,
|
||||
private val pc: ClientPC,
|
||||
val position: PCPosition,
|
||||
onPress: PressAction
|
||||
) : ButtonWidget(x - PC_BOX_DIMENSION, y, PC_BOX_DIMENSION, PC_BOX_DIMENSION, Text.literal("PCBoxMember"), onPress) {
|
||||
|
||||
companion object {
|
||||
// Box slot
|
||||
private const val PC_BOX_DIMENSION = 32
|
||||
|
||||
// Portrait
|
||||
private const val PORTRAIT_DIMENSIONS = 27
|
||||
}
|
||||
|
||||
var playingDownSound = false
|
||||
|
||||
override fun playDownSound(soundManager: SoundManager) {
|
||||
}
|
||||
|
||||
override fun render(matrices: MatrixStack, mouseX: Int, mouseY: Int, delta: Float) {
|
||||
val pokemon = pc.get(position) ?: return
|
||||
matrices.push()
|
||||
val minecraft = MinecraftClient.getInstance()
|
||||
RenderSystem.enableScissor(
|
||||
this.scaleIt(this.x + 3),
|
||||
minecraft.window.height - this.scaleIt(this.y + PORTRAIT_DIMENSIONS + 2),
|
||||
this.scaleIt(PORTRAIT_DIMENSIONS),
|
||||
this.scaleIt(PORTRAIT_DIMENSIONS)
|
||||
)
|
||||
matrices.translate(this.x + (PORTRAIT_DIMENSIONS / 2.0) + 4, this.y + 4.0, 0.0)
|
||||
matrices.scale(2.5F, 2.5F, 1F)
|
||||
|
||||
drawProfilePokemon(
|
||||
renderablePokemon = pokemon.asRenderablePokemon(),
|
||||
matrixStack = matrices,
|
||||
rotation = Quaternion.fromEulerXyzDegrees(Vec3f(13F, 35F, 0F)),
|
||||
state = null,
|
||||
scale = 6F
|
||||
)
|
||||
RenderSystem.disableScissor()
|
||||
matrices.pop()
|
||||
|
||||
if (position == parent.selectedPosition) {
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = PCWidget.selectedResource,
|
||||
x = x,
|
||||
y = y,
|
||||
height = PC_BOX_DIMENSION,
|
||||
width = PC_BOX_DIMENSION
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,410 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.gui.pc
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.api.text.bold
|
||||
import com.cobblemon.mod.common.api.text.text
|
||||
import com.cobblemon.mod.common.client.CobblemonResources
|
||||
import com.cobblemon.mod.common.client.gui.ExitButton
|
||||
import com.cobblemon.mod.common.client.gui.TypeIcon
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.ModelWidget
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.client.storage.ClientPC
|
||||
import com.cobblemon.mod.common.client.storage.ClientParty
|
||||
import com.cobblemon.mod.common.pokemon.Gender
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.asTranslated
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import net.minecraft.client.MinecraftClient
|
||||
import net.minecraft.client.gui.screen.Screen
|
||||
import net.minecraft.client.sound.PositionedSoundInstance
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
import net.minecraft.sound.SoundEvent
|
||||
import net.minecraft.text.Text
|
||||
|
||||
class PCGUI(
|
||||
private val pc: ClientPC,
|
||||
private val party: ClientParty
|
||||
) : Screen(Text.translatable("cobblemon.ui.pc.title")) {
|
||||
|
||||
companion object {
|
||||
const val BASE_WIDTH = 349
|
||||
const val BASE_HEIGHT = 205
|
||||
const val TYPE_SPACER_WIDTH = 128
|
||||
const val TYPE_SPACER_HEIGHT = 12
|
||||
const val PC_SPACER_WIDTH = 342
|
||||
const val PC_SPACER_HEIGHT = 14
|
||||
const val PORTRAIT_SIZE = 66
|
||||
const val SCALE = 0.5F
|
||||
|
||||
private val baseResource = cobblemonResource("ui/pc/pc_base.png")
|
||||
private val portraitBackgroundResource = cobblemonResource("ui/pc/portrait_background.png")
|
||||
private val topSpacerResource = cobblemonResource("ui/pc/pc_spacer_top.png")
|
||||
private val bottomSpacerResource = cobblemonResource("ui/pc/pc_spacer_bottom.png")
|
||||
private val rightSpacerResource = cobblemonResource("ui/pc/pc_spacer_right.png")
|
||||
private val typeSpacerResource = cobblemonResource("ui/pc/type_spacer.png")
|
||||
private val typeSpacerSingleResource = cobblemonResource("ui/pc/type_spacer_single.png")
|
||||
private val typeSpacerDoubleResource = cobblemonResource("ui/pc/type_spacer_double.png")
|
||||
}
|
||||
|
||||
private lateinit var storageWidget: StorageWidget
|
||||
private var modelWidget: ModelWidget? = null
|
||||
internal var previewPokemon: Pokemon? = null
|
||||
|
||||
var ticksElapsed = 0
|
||||
var selectPointerOffsetY = 0
|
||||
var selectPointerOffsetIncrement = false
|
||||
|
||||
override fun init() {
|
||||
val x = (width - BASE_WIDTH) / 2
|
||||
val y = (height - BASE_HEIGHT) / 2
|
||||
|
||||
// Add Exit Button
|
||||
this.addDrawableChild(
|
||||
ExitButton(pX = x + 320, pY = y + 186) {
|
||||
playSound(CobblemonSounds.PC_OFF.get())
|
||||
MinecraftClient.getInstance().setScreen(null)
|
||||
}
|
||||
)
|
||||
|
||||
// Add Forward Button
|
||||
this.addDrawableChild(
|
||||
NavigationButton(
|
||||
pX = x + 221,
|
||||
pY = y + 17,
|
||||
forward = true
|
||||
) { storageWidget.box += 1 }
|
||||
)
|
||||
|
||||
// Add Backwards Button
|
||||
this.addDrawableChild(
|
||||
NavigationButton(
|
||||
pX = x + 119,
|
||||
pY = y + 17,
|
||||
forward = false
|
||||
) { storageWidget.box -= 1 }
|
||||
)
|
||||
|
||||
// Add Storage
|
||||
this.storageWidget = StorageWidget(
|
||||
pX = x + 85,
|
||||
pY = y + 27,
|
||||
pcGui = this,
|
||||
pc = pc,
|
||||
party = party
|
||||
)
|
||||
|
||||
this.setPreviewPokemon(null)
|
||||
this.addDrawableChild(storageWidget)
|
||||
super.init()
|
||||
}
|
||||
|
||||
override fun render(matrices: MatrixStack, mouseX: Int, mouseY: Int, delta: Float) {
|
||||
renderBackground(matrices)
|
||||
|
||||
val x = (width - BASE_WIDTH) / 2
|
||||
val y = (height - BASE_HEIGHT) / 2
|
||||
|
||||
// Render Portrait Background
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = portraitBackgroundResource,
|
||||
x = x + 6,
|
||||
y = y + 27,
|
||||
width = PORTRAIT_SIZE,
|
||||
height = PORTRAIT_SIZE
|
||||
)
|
||||
|
||||
// Render Model Portrait
|
||||
modelWidget?.render(matrices, mouseX, mouseY, delta)
|
||||
|
||||
// Render Base Resource
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = baseResource,
|
||||
x = x, y = y,
|
||||
width = BASE_WIDTH,
|
||||
height = BASE_HEIGHT
|
||||
)
|
||||
|
||||
// Render Info Labels
|
||||
drawScaledText(
|
||||
matrixStack = matrices,
|
||||
text = lang("ui.info.nature").bold(),
|
||||
x = x + 39,
|
||||
y = y + 129.5,
|
||||
centered = true,
|
||||
scale = SCALE
|
||||
)
|
||||
|
||||
drawScaledText(
|
||||
matrixStack = matrices,
|
||||
text = lang("ui.info.ability").bold(),
|
||||
x = x + 39,
|
||||
y = y + 146.5,
|
||||
centered = true,
|
||||
scale = SCALE
|
||||
)
|
||||
|
||||
drawScaledText(
|
||||
matrixStack = matrices,
|
||||
text = lang("ui.moves").bold(),
|
||||
x = x + 39,
|
||||
y = y + 163.5,
|
||||
centered = true,
|
||||
scale = SCALE
|
||||
)
|
||||
|
||||
// Render Pokemon Info
|
||||
val pokemon = previewPokemon
|
||||
if (pokemon != null) {
|
||||
// Status
|
||||
val status = pokemon.status?.status
|
||||
if (pokemon.isFainted() || status != null) {
|
||||
val statusName = if (pokemon.isFainted()) "fnt" else status?.showdownName
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = cobblemonResource("ui/battle/battle_status_$statusName.png"),
|
||||
x = x + 34,
|
||||
y = y + 1,
|
||||
height = 7,
|
||||
width = 39,
|
||||
uOffset = 35,
|
||||
textureWidth = 74
|
||||
)
|
||||
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = cobblemonResource("ui/summary/status_trim.png"),
|
||||
x = x + 34,
|
||||
y = y + 2,
|
||||
height = 6,
|
||||
width = 3
|
||||
)
|
||||
|
||||
drawScaledText(
|
||||
matrixStack = matrices,
|
||||
font = CobblemonResources.DEFAULT_LARGE,
|
||||
text = lang("ui.status.$statusName").bold(),
|
||||
x = x + 39,
|
||||
y = y
|
||||
)
|
||||
}
|
||||
|
||||
// Level
|
||||
drawScaledText(
|
||||
matrixStack = matrices,
|
||||
font = CobblemonResources.DEFAULT_LARGE,
|
||||
text = lang("ui.lv").bold(),
|
||||
x = x + 6,
|
||||
y = y + 1.5,
|
||||
shadow = true
|
||||
)
|
||||
|
||||
drawScaledText(
|
||||
matrixStack = matrices,
|
||||
font = CobblemonResources.DEFAULT_LARGE,
|
||||
text = pokemon.level.toString().text().bold(),
|
||||
x = x + 19,
|
||||
y = y + 1.5,
|
||||
shadow = true
|
||||
)
|
||||
|
||||
// Poké Ball
|
||||
val ballResource = cobblemonResource("textures/items/poke_balls/" + pokemon.caughtBall.name.path + ".png")
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = ballResource,
|
||||
x = (x + 3.5) / SCALE,
|
||||
y = (y + 12) / SCALE,
|
||||
width = 16,
|
||||
height = 16,
|
||||
scale = SCALE
|
||||
)
|
||||
|
||||
drawScaledText(
|
||||
matrixStack = matrices,
|
||||
font = CobblemonResources.DEFAULT_LARGE,
|
||||
text = pokemon.displayName.bold(),
|
||||
x = x + 12,
|
||||
y = y + 11.5,
|
||||
shadow = true
|
||||
)
|
||||
|
||||
if (pokemon.gender != Gender.GENDERLESS) {
|
||||
val isMale = pokemon.gender == Gender.MALE
|
||||
val textSymbol = if (isMale) "♂".text().bold() else "♀".text().bold()
|
||||
drawScaledText(
|
||||
matrixStack = matrices,
|
||||
font = CobblemonResources.DEFAULT_LARGE,
|
||||
text = textSymbol,
|
||||
x = x + 69, // 64 when tag icon is implemented
|
||||
y = y + 11.5,
|
||||
colour = if (isMale) 0x32CBFF else 0xFC5454,
|
||||
shadow = true
|
||||
)
|
||||
}
|
||||
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = if (pokemon.secondaryType != null) typeSpacerDoubleResource else typeSpacerSingleResource,
|
||||
x = (x + 7) / SCALE,
|
||||
y = (y + 118.5) / SCALE,
|
||||
width = TYPE_SPACER_WIDTH,
|
||||
height = TYPE_SPACER_HEIGHT,
|
||||
scale = SCALE
|
||||
)
|
||||
|
||||
TypeIcon(
|
||||
x = x + 39,
|
||||
y = y + 117,
|
||||
type = pokemon.primaryType,
|
||||
secondaryType = pokemon.secondaryType,
|
||||
doubleCenteredOffset = 5F,
|
||||
secondaryOffset = 10F,
|
||||
small = true,
|
||||
centeredX = true
|
||||
).render(matrices)
|
||||
|
||||
// Nature
|
||||
drawScaledText(
|
||||
matrixStack = matrices,
|
||||
text = pokemon.nature.displayName.asTranslated(),
|
||||
x = x + 39,
|
||||
y = y + 137,
|
||||
centered = true,
|
||||
shadow = true,
|
||||
scale = SCALE
|
||||
)
|
||||
|
||||
// Ability
|
||||
drawScaledText(
|
||||
matrixStack = matrices,
|
||||
text = pokemon.ability.displayName.asTranslated(),
|
||||
x = x + 39,
|
||||
y = y + 154,
|
||||
centered = true,
|
||||
shadow = true,
|
||||
scale = SCALE
|
||||
)
|
||||
|
||||
// Moves
|
||||
val moves = pokemon.moveSet.getMoves()
|
||||
for (i in moves.indices) {
|
||||
drawScaledText(
|
||||
matrixStack = matrices,
|
||||
text = moves[i].displayName,
|
||||
x = x + 39,
|
||||
y = y + 170.5 + (7 * i),
|
||||
centered = true,
|
||||
shadow = true,
|
||||
scale = SCALE
|
||||
)
|
||||
}
|
||||
|
||||
} else {
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = typeSpacerResource,
|
||||
x = (x + 7) / SCALE,
|
||||
y = (y + 118.5) / SCALE,
|
||||
width = TYPE_SPACER_WIDTH,
|
||||
height = TYPE_SPACER_HEIGHT,
|
||||
scale = SCALE
|
||||
)
|
||||
}
|
||||
|
||||
// Box Label
|
||||
drawScaledText(
|
||||
matrixStack = matrices,
|
||||
font = CobblemonResources.DEFAULT_LARGE,
|
||||
text = Text.translatable("cobblemon.ui.pc.box.title", (this.storageWidget.box + 1).toString()).bold(),
|
||||
x = x + 172,
|
||||
y = y + 15,
|
||||
centered = true
|
||||
)
|
||||
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = topSpacerResource,
|
||||
x = (x + 86.5) / SCALE,
|
||||
y = (y + 13) / SCALE,
|
||||
width = PC_SPACER_WIDTH,
|
||||
height = PC_SPACER_HEIGHT,
|
||||
scale = SCALE
|
||||
)
|
||||
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = bottomSpacerResource,
|
||||
x = (x + 86.5) / SCALE,
|
||||
y = (y + 189) / SCALE,
|
||||
width = PC_SPACER_WIDTH,
|
||||
height = PC_SPACER_HEIGHT,
|
||||
scale = SCALE
|
||||
)
|
||||
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = rightSpacerResource,
|
||||
x = (x + 275.5) / SCALE,
|
||||
y = (y + 184) / SCALE,
|
||||
width = 64,
|
||||
height = 24,
|
||||
scale = SCALE
|
||||
)
|
||||
|
||||
super.render(matrices, mouseX, mouseY, delta)
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this Screen should pause the Game in SinglePlayer
|
||||
*/
|
||||
override fun shouldPause(): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun tick() {
|
||||
ticksElapsed++
|
||||
|
||||
// Calculate select pointer offset
|
||||
var delayFactor = 3
|
||||
if (ticksElapsed % (2 * delayFactor) == 0) selectPointerOffsetIncrement = !selectPointerOffsetIncrement
|
||||
if (ticksElapsed % delayFactor == 0) selectPointerOffsetY += if (selectPointerOffsetIncrement) 1 else -1
|
||||
}
|
||||
|
||||
private fun playSound(soundEvent: SoundEvent) {
|
||||
MinecraftClient.getInstance().soundManager.play(PositionedSoundInstance.master(soundEvent, 1.0F))
|
||||
}
|
||||
|
||||
fun setPreviewPokemon(pokemon: Pokemon?) {
|
||||
if (pokemon != null) {
|
||||
previewPokemon = pokemon
|
||||
|
||||
val x = (width - BASE_WIDTH) / 2
|
||||
val y = (height - BASE_HEIGHT) / 2
|
||||
modelWidget = ModelWidget(
|
||||
pX = x + 6,
|
||||
pY = y + 27,
|
||||
pWidth = PORTRAIT_SIZE,
|
||||
pHeight = PORTRAIT_SIZE,
|
||||
pokemon = pokemon.asRenderablePokemon(),
|
||||
baseScale = 2F,
|
||||
rotationY = 325F,
|
||||
offsetY = -10.0
|
||||
)
|
||||
} else {
|
||||
previewPokemon = null;
|
||||
modelWidget = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,128 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.gui.pc
|
||||
|
||||
import com.cobblemon.mod.common.api.gui.ColourLibrary
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.client.CobblemonResources
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.client.storage.ClientPC
|
||||
import com.cobblemon.mod.common.client.storage.ClientParty
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.client.MinecraftClient
|
||||
import net.minecraft.client.gui.screen.Screen
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
import net.minecraft.text.Text
|
||||
class PCGui(
|
||||
private val pc: ClientPC,
|
||||
private val party: ClientParty
|
||||
) : Screen(Text.translatable("cobblemon.ui.pc.title")) {
|
||||
|
||||
companion object {
|
||||
// Size of Background
|
||||
private const val backgroundHeight = 200
|
||||
private const val backgroundWidth = 300
|
||||
// Textures
|
||||
private val background = cobblemonResource("ui/pc/pc_base.png")
|
||||
private val underlay = cobblemonResource("ui/pc/pc_underlay.png")
|
||||
}
|
||||
|
||||
private lateinit var pcWidget: PCWidget
|
||||
|
||||
override fun init() {
|
||||
val x = (width - backgroundWidth) / 2
|
||||
val y = (height - backgroundHeight) / 2
|
||||
|
||||
// Add Exit Button
|
||||
this.addDrawableChild(
|
||||
ExitButton(
|
||||
pX = x + 249, pY = y + 4,
|
||||
pWidth = 16, pHeight = 12,
|
||||
pXTexStart = 0, pYTexStart = 0, pYDiffText = 0
|
||||
) {
|
||||
MinecraftClient.getInstance().setScreen(null)
|
||||
})
|
||||
|
||||
// Add Forward Button
|
||||
this.addDrawableChild(
|
||||
NavigationButton(
|
||||
pX = x + 230, pY = y + 9,
|
||||
pWidth = 9, pHeight = 14,
|
||||
pXTexStart = 0, pYTexStart = 0, pYDiffText = 0,
|
||||
forward = true
|
||||
) {
|
||||
pcWidget.box += 1
|
||||
})
|
||||
|
||||
// Add Backwards Button
|
||||
this.addDrawableChild(
|
||||
NavigationButton(
|
||||
pX = x + 108, pY = y + 9,
|
||||
pWidth = 9, pHeight = 14,
|
||||
pXTexStart = 0, pYTexStart = 0, pYDiffText = 0,
|
||||
forward = false
|
||||
) {
|
||||
pcWidget.box -= 1
|
||||
})
|
||||
|
||||
// Add PC
|
||||
this.pcWidget = PCWidget(
|
||||
pX = x + 116, pY = y + 32,
|
||||
pWidth = 175, pHeight = 145,
|
||||
pcGui = this,
|
||||
pc = pc,
|
||||
party = party
|
||||
)
|
||||
this.addDrawableChild(pcWidget)
|
||||
super.init()
|
||||
}
|
||||
|
||||
override fun render(matrices: MatrixStack, mouseX: Int, mouseY: Int, delta: Float) {
|
||||
renderBackground(matrices)
|
||||
|
||||
val x = (width - backgroundWidth) / 2
|
||||
val y = (height - backgroundHeight) / 2
|
||||
|
||||
// Rendering PC Underlay
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = underlay,
|
||||
x = x + 7, y = y + 25,
|
||||
width = 65, height = 65
|
||||
)
|
||||
|
||||
// Rendering UI Background
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = background,
|
||||
x = x, y = y,
|
||||
width = backgroundWidth, height = backgroundHeight
|
||||
)
|
||||
|
||||
drawScaledText(
|
||||
matrixStack = matrices,
|
||||
font = CobblemonResources.DEFAULT_LARGE,
|
||||
text = Text.translatable("cobblemon.ui.box.title", (this.pcWidget.box + 1).toString()),
|
||||
x = (x + 173.5), y = (y + 8.75),
|
||||
colour = ColourLibrary.WHITE, shadow = false,
|
||||
centered = true,
|
||||
scale = 1.5f,
|
||||
)
|
||||
|
||||
super.render(matrices, mouseX, mouseY, delta)
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this Screen should pause the Game in SinglePlayer
|
||||
*/
|
||||
override fun shouldPause(): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
}
|
||||
-80
@@ -1,80 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.gui.pc
|
||||
|
||||
import com.cobblemon.mod.common.client.gui.drawProfilePokemon
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.SoundlessWidget
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonFloatingState
|
||||
import com.cobblemon.mod.common.client.storage.ClientPC
|
||||
import com.cobblemon.mod.common.client.storage.ClientParty
|
||||
import com.mojang.blaze3d.systems.RenderSystem
|
||||
import net.minecraft.client.MinecraftClient
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.util.math.Quaternion
|
||||
import net.minecraft.util.math.Vec3f
|
||||
|
||||
class PCPreviewSelectedWidget(
|
||||
pX: Int, pY: Int,
|
||||
pWidth: Int, pHeight: Int,
|
||||
val baseScale: Float = 2.7F,
|
||||
private val parent: PCWidget,
|
||||
private val pc: ClientPC,
|
||||
private val party: ClientParty,
|
||||
): SoundlessWidget(pX, pY, pWidth, pHeight, Text.literal("PC - PreviewSelectedWidget")) {
|
||||
|
||||
companion object {
|
||||
var render = true
|
||||
}
|
||||
|
||||
var state = PokemonFloatingState()
|
||||
private val minecraft = MinecraftClient.getInstance()
|
||||
private var rotVec = Vec3f(13F, 35F, 0F)
|
||||
|
||||
override fun render(pMatrixStack: MatrixStack, pMouseX: Int, pMouseY: Int, pPartialTicks: Float) {
|
||||
if (!render) {
|
||||
return
|
||||
}
|
||||
hovered = pMouseX >= x && pMouseY >= y && pMouseX < x + width && pMouseY < y + height
|
||||
renderPKM(pMatrixStack)
|
||||
}
|
||||
|
||||
private fun renderPKM(poseStack: MatrixStack) {
|
||||
val pokemon = parent.getSelectedPokemon() ?: return
|
||||
|
||||
poseStack.push()
|
||||
|
||||
RenderSystem.enableScissor(
|
||||
(x * minecraft.window.scaleFactor).toInt(),
|
||||
(minecraft.window.height - (y * minecraft.window.scaleFactor) - (height * minecraft.window.scaleFactor)).toInt(),
|
||||
(width * minecraft.window.scaleFactor).toInt(),
|
||||
(height * minecraft.window.scaleFactor).toInt()
|
||||
)
|
||||
|
||||
poseStack.translate(x + width * 0.5, y.toDouble(), 0.0)
|
||||
poseStack.scale(baseScale, baseScale, baseScale)
|
||||
poseStack.push()
|
||||
|
||||
drawProfilePokemon(
|
||||
renderablePokemon = pokemon.asRenderablePokemon(),
|
||||
matrixStack = poseStack,
|
||||
rotation = Quaternion.fromEulerXyzDegrees(rotVec),
|
||||
state = state
|
||||
)
|
||||
|
||||
poseStack.pop()
|
||||
RenderSystem.disableScissor()
|
||||
|
||||
poseStack.pop()
|
||||
}
|
||||
|
||||
override fun onClick(pMouseX: Double, pMouseY: Double) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.gui.pc
|
||||
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.client.storage.ClientPC
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.client.gui.widget.ButtonWidget
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
import net.minecraft.text.Text
|
||||
|
||||
class PCTrashWidget(
|
||||
x: Int, y: Int,
|
||||
private val parent: PCWidget,
|
||||
private val pc: ClientPC,
|
||||
onPress: PressAction
|
||||
) : ButtonWidget(x, y, WIDTH, HEIGHT, Text.literal("PCTrash"), onPress) {
|
||||
|
||||
companion object {
|
||||
private const val WIDTH = 13
|
||||
private const val HEIGHT = 14
|
||||
|
||||
val trashIcon = cobblemonResource("ui/pc/pc_trash.png")
|
||||
val trashIconHovered = cobblemonResource("ui/pc/pc_trash_hovered.png")
|
||||
}
|
||||
|
||||
override fun render(matrices: MatrixStack, mouseX: Int, mouseY: Int, delta: Float) {
|
||||
if (!parent.canDeleteSelected()) {
|
||||
return
|
||||
}
|
||||
|
||||
val isHovered = mouseX in x..(x + WIDTH) && mouseY in y..(y + HEIGHT)
|
||||
|
||||
val icon = if (isHovered) trashIconHovered else trashIcon
|
||||
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
x = x,
|
||||
y = y,
|
||||
width = WIDTH,
|
||||
height = HEIGHT,
|
||||
texture = icon
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,261 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.gui.pc
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonNetwork
|
||||
import com.cobblemon.mod.common.api.storage.StorePosition
|
||||
import com.cobblemon.mod.common.api.storage.party.PartyPosition
|
||||
import com.cobblemon.mod.common.api.storage.pc.PCPosition
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.SoundlessWidget
|
||||
import com.cobblemon.mod.common.client.settings.ServerSettings
|
||||
import com.cobblemon.mod.common.client.storage.ClientPC
|
||||
import com.cobblemon.mod.common.client.storage.ClientParty
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.SwapPCPartyPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.party.MovePartyPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.party.ReleasePartyPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.party.SwapPartyPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.pc.MovePCPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.pc.MovePCPokemonToPartyPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.pc.MovePartyPokemonToPCPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.pc.ReleasePCPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.pc.SwapPCPokemonPacket
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.client.MinecraftClient
|
||||
import net.minecraft.client.gui.widget.ButtonWidget
|
||||
import net.minecraft.client.sound.PositionedSoundInstance
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
import net.minecraft.sound.SoundEvents
|
||||
import net.minecraft.text.Text
|
||||
|
||||
class PCWidget(
|
||||
pX: Int, pY: Int,
|
||||
pWidth: Int, pHeight: Int,
|
||||
private val pcGui: PCGui,
|
||||
private val pc: ClientPC,
|
||||
private val party: ClientParty
|
||||
) : SoundlessWidget(pX, pY, pWidth, pHeight, Text.literal("PCWidget")) {
|
||||
|
||||
companion object {
|
||||
val selectedResource = cobblemonResource("ui/pc/pc_selected.png")
|
||||
}
|
||||
|
||||
var selectedPosition: StorePosition? = null
|
||||
|
||||
var box = 0
|
||||
set(value) {
|
||||
// If value is within min and max
|
||||
field = if (value > 0 && value < pc.boxes.size) {
|
||||
value
|
||||
}
|
||||
// If value is less than zero, wrap around to end.
|
||||
else if (value < 0) {
|
||||
pc.boxes.size - 1
|
||||
}
|
||||
// Else it's greater than max, wrap around to start.
|
||||
else {
|
||||
0
|
||||
}
|
||||
this.setupMemberWidgets()
|
||||
}
|
||||
|
||||
private val partyWidgets = arrayListOf<PartyMemberWidget>()
|
||||
private val pcWidgets = arrayListOf<PCBoxMemberWidget>()
|
||||
private val previewWidget: PCPreviewSelectedWidget
|
||||
private val trashWidget: PCTrashWidget
|
||||
|
||||
fun canDeleteSelected(): Boolean {
|
||||
return !(selectedPosition is PartyPosition && party.filterNotNull().size <= 1) && selectedPosition != null
|
||||
}
|
||||
|
||||
init {
|
||||
this.setupMemberWidgets()
|
||||
|
||||
this.previewWidget = PCPreviewSelectedWidget(
|
||||
pX = x - 105,
|
||||
pY = y,
|
||||
pWidth = 60,
|
||||
pHeight = 70,
|
||||
baseScale = 1.5f,
|
||||
parent = this,
|
||||
pc = pc,
|
||||
party = party
|
||||
).also {
|
||||
this.addWidget(it)
|
||||
}
|
||||
|
||||
this.trashWidget = PCTrashWidget(
|
||||
x = x - 22,
|
||||
y = y + 150,
|
||||
parent = this,
|
||||
pc = pc,
|
||||
onPress = {
|
||||
if (canDeleteSelected()) {
|
||||
val position = selectedPosition ?: return@PCTrashWidget
|
||||
val pokemon = getSelectedPokemon() ?: return@PCTrashWidget
|
||||
|
||||
val packet = when (position) {
|
||||
is PartyPosition -> ReleasePartyPokemonPacket(pokemon.uuid, position)
|
||||
is PCPosition -> ReleasePCPokemonPacket(pokemon.uuid, position)
|
||||
else -> return@PCTrashWidget
|
||||
}
|
||||
|
||||
CobblemonNetwork.sendToServer(packet)
|
||||
selectedPosition = null
|
||||
}
|
||||
}
|
||||
).also {
|
||||
addWidget(it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupMemberWidgets() {
|
||||
this.resetWidgets()
|
||||
var index = 0
|
||||
|
||||
// Box members
|
||||
for (row in 1..5) {
|
||||
for (col in 1..6) {
|
||||
PCBoxMemberWidget(
|
||||
x = x + (col-1) * 29,
|
||||
y = y + (row-1) * 29,
|
||||
parent = this,
|
||||
pcGui = pcGui,
|
||||
pc = pc,
|
||||
position = PCPosition(box, index),
|
||||
onPress = { this.onPokemonPressed(it) }
|
||||
).also { widget ->
|
||||
this.addWidget(widget)
|
||||
this.pcWidgets.add(widget)
|
||||
}
|
||||
index++
|
||||
}
|
||||
}
|
||||
|
||||
// Party slots
|
||||
for (partySlot in 0..5) {
|
||||
val texture = when(partySlot) {
|
||||
0 -> PartyMemberWidget.slotOneResource
|
||||
5 -> PartyMemberWidget.slotSixResource
|
||||
else -> PartyMemberWidget.slotTwoThroughFiveResource
|
||||
}
|
||||
|
||||
PartyMemberWidget(
|
||||
x = x + 185,
|
||||
y = (y - 19) + partySlot * 31,
|
||||
parent = this,
|
||||
pcGui = pcGui,
|
||||
pc = pc,
|
||||
party = party,
|
||||
position = PartyPosition(partySlot),
|
||||
texture = texture,
|
||||
onPress = { this.onPokemonPressed(it) }
|
||||
).also { widget ->
|
||||
this.addWidget(widget)
|
||||
this.partyWidgets.add(widget)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getSelectedPokemon(): Pokemon? {
|
||||
val selectedPosition = this.selectedPosition ?: return null
|
||||
return when (selectedPosition) {
|
||||
is PCPosition -> pc.get(selectedPosition)
|
||||
is PartyPosition -> party.get(selectedPosition)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
override fun render(matrices: MatrixStack, mouseX: Int, mouseY: Int, delta: Float) {
|
||||
this.previewWidget.render(matrices, mouseX, mouseY, delta)
|
||||
this.pcWidgets.forEach { widget -> widget.render(matrices, mouseX, mouseY, delta) }
|
||||
this.partyWidgets.forEach { widget -> widget.render(matrices, mouseX, mouseY, delta) }
|
||||
this.trashWidget.render(matrices, mouseX, mouseY, delta)
|
||||
}
|
||||
|
||||
private fun resetWidgets() {
|
||||
this.partyWidgets.forEach(this::removeWidget)
|
||||
this.partyWidgets.clear()
|
||||
|
||||
this.pcWidgets.forEach(this::removeWidget)
|
||||
this.pcWidgets.clear()
|
||||
}
|
||||
|
||||
fun clickSound() {
|
||||
MinecraftClient.getInstance().soundManager.play(PositionedSoundInstance.master(SoundEvents.UI_BUTTON_CLICK, 1.0f))
|
||||
}
|
||||
|
||||
private fun onPokemonPressed(button: ButtonWidget) {
|
||||
// Only use on member widgets
|
||||
val clickedPosition = when(button) {
|
||||
is PCBoxMemberWidget -> button.position
|
||||
is PartyMemberWidget -> button.position
|
||||
else -> return
|
||||
}
|
||||
|
||||
// Clicking on itself, so unselect position.
|
||||
if (this.selectedPosition != null && this.selectedPosition == clickedPosition) {
|
||||
this.selectedPosition = null
|
||||
clickSound()
|
||||
return
|
||||
}
|
||||
|
||||
// Check for selecting a Pokémon.
|
||||
val clickedPokemon = when(button) {
|
||||
is PCBoxMemberWidget -> pc.get(clickedPosition as PCPosition)
|
||||
is PartyMemberWidget -> party.get(clickedPosition as PartyPosition)
|
||||
else -> null
|
||||
}
|
||||
if (this.selectedPosition == null && clickedPokemon != null) {
|
||||
this.selectedPosition = clickedPosition
|
||||
clickSound()
|
||||
return
|
||||
}
|
||||
|
||||
// Handle movement within the PC.
|
||||
val selectedPokemon = when(this.selectedPosition) {
|
||||
is PCPosition -> pc.get(this.selectedPosition as PCPosition)
|
||||
is PartyPosition -> party.get(this.selectedPosition as PartyPosition)
|
||||
else -> null
|
||||
} ?: return
|
||||
|
||||
// PC -> PC
|
||||
if (this.selectedPosition is PCPosition && clickedPosition is PCPosition) {
|
||||
val packet = clickedPokemon?.let { SwapPCPokemonPacket(it.uuid, clickedPosition, selectedPokemon.uuid, this.selectedPosition as PCPosition) }
|
||||
?: MovePCPokemonPacket(selectedPokemon.uuid, selectedPosition as PCPosition, clickedPosition)
|
||||
packet.sendToServer()
|
||||
clickSound()
|
||||
this.selectedPosition = null
|
||||
}
|
||||
// PC -> Party
|
||||
else if (this.selectedPosition is PCPosition && clickedPosition is PartyPosition) {
|
||||
val packet = clickedPokemon?.let { SwapPCPartyPokemonPacket(clickedPokemon.uuid, clickedPosition, selectedPokemon.uuid, this.selectedPosition as PCPosition) }
|
||||
?: MovePCPokemonToPartyPacket(selectedPokemon.uuid, this.selectedPosition as PCPosition, clickedPosition)
|
||||
packet.sendToServer()
|
||||
this.selectedPosition = null
|
||||
}
|
||||
// Party -> PC
|
||||
else if (this.selectedPosition is PartyPosition && clickedPosition is PCPosition) {
|
||||
if (ServerSettings.preventCompletePartyDeposit && this.party.filterNotNull().size == 1 && clickedPokemon == null) {
|
||||
return
|
||||
}
|
||||
val packet = clickedPokemon?.let { SwapPCPartyPokemonPacket(selectedPokemon.uuid, this.selectedPosition as PartyPosition, clickedPokemon.uuid, clickedPosition) }
|
||||
?: MovePartyPokemonToPCPacket(selectedPokemon.uuid, this.selectedPosition as PartyPosition, clickedPosition)
|
||||
packet.sendToServer()
|
||||
this.selectedPosition = null
|
||||
}
|
||||
// Party -> Party
|
||||
else if (this.selectedPosition is PartyPosition && clickedPosition is PartyPosition) {
|
||||
val packet = clickedPokemon?.let { SwapPartyPokemonPacket(it.uuid, clickedPosition, selectedPokemon.uuid, this.selectedPosition as PartyPosition) }
|
||||
?: MovePartyPokemonPacket(selectedPokemon.uuid, selectedPosition as PartyPosition, clickedPosition)
|
||||
packet.sendToServer()
|
||||
this.selectedPosition = null
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.gui.pc
|
||||
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.api.storage.party.PartyPosition
|
||||
import com.cobblemon.mod.common.client.gui.drawProfilePokemon
|
||||
import com.cobblemon.mod.common.client.storage.ClientPC
|
||||
import com.cobblemon.mod.common.client.storage.ClientParty
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.scaleIt
|
||||
import com.mojang.blaze3d.systems.RenderSystem
|
||||
import net.minecraft.client.MinecraftClient
|
||||
import net.minecraft.client.gui.widget.ButtonWidget
|
||||
import net.minecraft.client.sound.SoundManager
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.math.Quaternion
|
||||
import net.minecraft.util.math.Vec3f
|
||||
|
||||
class PartyMemberWidget(
|
||||
x: Int, y: Int,
|
||||
private val parent: PCWidget,
|
||||
private val pcGui: PCGui,
|
||||
private val pc: ClientPC,
|
||||
private val party: ClientParty,
|
||||
val position: PartyPosition,
|
||||
private val texture: Identifier,
|
||||
onPress: PressAction
|
||||
) : ButtonWidget(x - PC_BOX_DIMENSION, y, PC_BOX_DIMENSION, PC_BOX_DIMENSION, Text.literal("PartyMember"), onPress) {
|
||||
|
||||
companion object {
|
||||
// Box slot
|
||||
private const val PC_BOX_DIMENSION = 32
|
||||
|
||||
// Portrait
|
||||
private const val PORTRAIT_DIMENSIONS = 29
|
||||
|
||||
// Slot Textures
|
||||
val slotOneResource = cobblemonResource("ui/pc/pc_party_1.png")
|
||||
val slotTwoThroughFiveResource = cobblemonResource("ui/pc/pc_party_2-5.png")
|
||||
val slotSixResource = cobblemonResource("ui/pc/pc_party_6.png")
|
||||
}
|
||||
|
||||
override fun playDownSound(soundManager: SoundManager) {
|
||||
}
|
||||
|
||||
override fun render(matrices: MatrixStack, mouseX: Int, mouseY: Int, delta: Float) {
|
||||
matrices.push()
|
||||
|
||||
val xOffset = if (texture == slotSixResource) -2f else 0f
|
||||
val slotWidth = if (texture == slotSixResource) 35 else 33
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
x = x + xOffset + -0.9f, y = y - 1F,
|
||||
texture = this.texture,
|
||||
width = slotWidth, height = 33
|
||||
)
|
||||
|
||||
val pokemon = party.get(position)
|
||||
if (pokemon != null) {
|
||||
val pokemonX = this.x - 3
|
||||
val pokemonY = this.y - 1
|
||||
|
||||
val minecraft = MinecraftClient.getInstance()
|
||||
RenderSystem.enableScissor(
|
||||
this.scaleIt(pokemonX + 3),
|
||||
minecraft.window.height - this.scaleIt(pokemonY + PORTRAIT_DIMENSIONS + 2),
|
||||
this.scaleIt(PORTRAIT_DIMENSIONS),
|
||||
this.scaleIt(PORTRAIT_DIMENSIONS)
|
||||
)
|
||||
matrices.push()
|
||||
matrices.translate(pokemonX + (PORTRAIT_DIMENSIONS / 2.0) + 4, pokemonY + 4.0, 0.0)
|
||||
matrices.scale(2.5F, 2.5F, 1F)
|
||||
drawProfilePokemon(
|
||||
renderablePokemon = pokemon.asRenderablePokemon(),
|
||||
matrixStack = matrices,
|
||||
rotation = Quaternion.fromEulerXyzDegrees(Vec3f(13F, 35F, 0F)),
|
||||
state = null,
|
||||
scale = 6F
|
||||
)
|
||||
RenderSystem.disableScissor()
|
||||
matrices.pop()
|
||||
|
||||
if (position == parent.selectedPosition) {
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = PCWidget.selectedResource,
|
||||
x = x,
|
||||
y = y + 1,
|
||||
height = PORTRAIT_DIMENSIONS,
|
||||
width = PORTRAIT_DIMENSIONS
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
matrices.pop()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.gui.pc
|
||||
|
||||
import com.cobblemon.mod.common.api.storage.party.PartyPosition
|
||||
import com.cobblemon.mod.common.client.storage.ClientParty
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
|
||||
class PartyStorageSlot(
|
||||
x: Int, y: Int,
|
||||
private val parent: StorageWidget,
|
||||
private val party: ClientParty,
|
||||
val position: PartyPosition,
|
||||
onPress: PressAction
|
||||
) : StorageSlot(x, y, parent, onPress) {
|
||||
|
||||
override fun getPokemon(): Pokemon? {
|
||||
return party.get(position)
|
||||
}
|
||||
|
||||
override fun shouldRender(): Boolean {
|
||||
val grabbedSlot = parent.grabbedSlot
|
||||
return if (grabbedSlot == null) {
|
||||
true
|
||||
} else {
|
||||
grabbedSlot.getPokemon() != getPokemon()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.gui.pc
|
||||
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.api.text.bold
|
||||
import com.cobblemon.mod.common.client.CobblemonResources
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import net.minecraft.client.gui.widget.ButtonWidget
|
||||
import net.minecraft.client.sound.SoundManager
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
import net.minecraft.text.Text
|
||||
|
||||
class ReleaseButton(
|
||||
x: Int, y: Int,
|
||||
private val parent: StorageWidget,
|
||||
onPress: PressAction
|
||||
) : ButtonWidget(x, y, WIDTH, HEIGHT, Text.literal("Release"), onPress) {
|
||||
|
||||
companion object {
|
||||
private const val WIDTH = 58
|
||||
private const val HEIGHT = 16
|
||||
|
||||
private val buttonResource = cobblemonResource("ui/pc/pc_release_button.png")
|
||||
}
|
||||
|
||||
override fun render(matrices: MatrixStack, mouseX: Int, mouseY: Int, delta: Float) {
|
||||
if (parent.canDeleteSelected() && !parent.displayConfirmRelease) {
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = buttonResource,
|
||||
x = x,
|
||||
y = y,
|
||||
width = WIDTH,
|
||||
height = HEIGHT,
|
||||
vOffset = if (isHovered(mouseX.toDouble(), mouseY.toDouble())) HEIGHT else 0,
|
||||
textureHeight = HEIGHT * 2
|
||||
)
|
||||
|
||||
drawScaledText(
|
||||
matrixStack = matrices,
|
||||
font = CobblemonResources.DEFAULT_LARGE,
|
||||
text = lang("ui.pc.release").bold(),
|
||||
x = x + (WIDTH / 2),
|
||||
y = y + 3.5,
|
||||
centered = true,
|
||||
shadow = true
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun playDownSound(pHandler: SoundManager) {
|
||||
}
|
||||
|
||||
fun isHovered(mouseX: Double, mouseY: Double) = mouseX.toFloat() in (x.toFloat()..(x.toFloat() + WIDTH)) && mouseY.toFloat() in (y.toFloat()..(y.toFloat() + HEIGHT))
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.gui.pc
|
||||
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.api.text.bold
|
||||
import com.cobblemon.mod.common.client.CobblemonResources
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import net.minecraft.client.gui.widget.ButtonWidget
|
||||
import net.minecraft.client.sound.SoundManager
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
import net.minecraft.text.Text
|
||||
|
||||
class ReleaseConfirmButton(
|
||||
x: Int, y: Int,
|
||||
private val parent: StorageWidget,
|
||||
private val subKey: String,
|
||||
onPress: PressAction
|
||||
) : ButtonWidget(x, y, WIDTH, HEIGHT, Text.literal("ReleaseConfirm"), onPress) {
|
||||
|
||||
companion object {
|
||||
private const val WIDTH = 30
|
||||
private const val HEIGHT = 13
|
||||
|
||||
private val buttonResource = cobblemonResource("ui/pc/pc_release_button_confirm.png")
|
||||
}
|
||||
|
||||
override fun render(matrices: MatrixStack, mouseX: Int, mouseY: Int, delta: Float) {
|
||||
if (parent.canDeleteSelected() && parent.displayConfirmRelease) {
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = buttonResource,
|
||||
x = x,
|
||||
y = y,
|
||||
width = WIDTH,
|
||||
height = HEIGHT,
|
||||
vOffset = if (isHovered(mouseX.toDouble(), mouseY.toDouble())) HEIGHT else 0,
|
||||
textureHeight = HEIGHT * 2
|
||||
)
|
||||
|
||||
drawScaledText(
|
||||
matrixStack = matrices,
|
||||
font = CobblemonResources.DEFAULT_LARGE,
|
||||
text = lang(subKey).bold(),
|
||||
x = x + (WIDTH / 2),
|
||||
y = y + 2,
|
||||
centered = true,
|
||||
shadow = true
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun playDownSound(soundManager: SoundManager) {
|
||||
}
|
||||
|
||||
fun isHovered(mouseX: Double, mouseY: Double) = mouseX.toFloat() in (x.toFloat()..(x.toFloat() + WIDTH)) && mouseY.toFloat() in (y.toFloat()..(y.toFloat() + HEIGHT))
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.gui.pc
|
||||
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.client.gui.drawProfilePokemon
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.pokemon.Gender
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import com.mojang.blaze3d.systems.RenderSystem
|
||||
import net.minecraft.client.MinecraftClient
|
||||
import net.minecraft.client.gui.widget.ButtonWidget
|
||||
import net.minecraft.client.sound.SoundManager
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.util.math.Quaternion
|
||||
import net.minecraft.util.math.Vec3f
|
||||
|
||||
open class StorageSlot(
|
||||
x: Int, y: Int,
|
||||
private val parent: StorageWidget,
|
||||
onPress: PressAction
|
||||
) : ButtonWidget(x, y, SIZE, SIZE, Text.literal("StorageSlot"), onPress) {
|
||||
|
||||
companion object {
|
||||
const val SIZE = 25
|
||||
|
||||
private val genderIconMale = cobblemonResource("ui/pc/gender_icon_male.png")
|
||||
private val genderIconFemale = cobblemonResource("ui/pc/gender_icon_female.png")
|
||||
private val selectPointerResource = cobblemonResource("ui/pc/pc_pointer.png")
|
||||
}
|
||||
|
||||
override fun playDownSound(soundManager: SoundManager) {
|
||||
}
|
||||
|
||||
override fun render(matrices: MatrixStack, mouseX: Int, mouseY: Int, delta: Float) {
|
||||
if (shouldRender()) {
|
||||
renderSlot(matrices, x, y)
|
||||
}
|
||||
}
|
||||
|
||||
fun renderSlot(matrices: MatrixStack, posX: Int, posY: Int) {
|
||||
val pokemon = getPokemon() ?: return
|
||||
|
||||
val minecraft = MinecraftClient.getInstance()
|
||||
RenderSystem.enableScissor(
|
||||
((posX - 2) * minecraft.window.scaleFactor).toInt(),
|
||||
(minecraft.window.height - (posY + SIZE + 2) * minecraft.window.scaleFactor).toInt(),
|
||||
((SIZE + 4) * minecraft.window.scaleFactor).toInt(),
|
||||
((SIZE + 4) * minecraft.window.scaleFactor).toInt()
|
||||
)
|
||||
|
||||
// Render Pokémon
|
||||
matrices.push()
|
||||
matrices.translate(posX + (SIZE / 2.0), posY + 3.0, 0.0)
|
||||
matrices.scale(2.5F, 2.5F, 1F)
|
||||
drawProfilePokemon(
|
||||
renderablePokemon = pokemon.asRenderablePokemon(),
|
||||
matrixStack = matrices,
|
||||
rotation = Quaternion.fromEulerXyzDegrees(Vec3f(13F, 35F, 0F)),
|
||||
state = null,
|
||||
scale = 4.5F
|
||||
)
|
||||
matrices.pop()
|
||||
|
||||
RenderSystem.disableScissor()
|
||||
|
||||
// Ensure labels are not hidden behind Pokémon render
|
||||
matrices.push()
|
||||
matrices.translate(0.0, 0.0, 100.0)
|
||||
// Level
|
||||
drawScaledText(
|
||||
matrixStack = matrices,
|
||||
text = lang("ui.lv.number", pokemon.level),
|
||||
x = posX + 1,
|
||||
y = posY + 1,
|
||||
shadow = true,
|
||||
scale = PCGUI.SCALE
|
||||
)
|
||||
|
||||
if (pokemon.gender != Gender.GENDERLESS) {
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = if (pokemon.gender == Gender.MALE) genderIconMale else genderIconFemale,
|
||||
x = (posX + 21) / PCGUI.SCALE,
|
||||
y = (posY + 1) / PCGUI.SCALE,
|
||||
width = 6,
|
||||
height = 8,
|
||||
scale = PCGUI.SCALE
|
||||
)
|
||||
}
|
||||
matrices.pop()
|
||||
|
||||
if (isSelected()) {
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = selectPointerResource,
|
||||
x = (posX + 10) / PCGUI.SCALE,
|
||||
y = ((posY - 3) / PCGUI.SCALE) - parent.pcGui.selectPointerOffsetY,
|
||||
width = 11,
|
||||
height = 8,
|
||||
scale = PCGUI.SCALE
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
open fun getPokemon(): Pokemon? {
|
||||
return null
|
||||
}
|
||||
|
||||
open fun isSelected(): Boolean {
|
||||
return getPokemon() == parent.pcGui.previewPokemon
|
||||
}
|
||||
|
||||
open fun shouldRender(): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
fun isHovered(mouseX: Int, mouseY: Int) = mouseX.toFloat() in (x.toFloat()..(x.toFloat() + SIZE)) && mouseY.toFloat() in (y.toFloat()..(y.toFloat() + SIZE))
|
||||
}
|
||||
@@ -0,0 +1,379 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.gui.pc
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonNetwork
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.api.storage.StorePosition
|
||||
import com.cobblemon.mod.common.api.storage.party.PartyPosition
|
||||
import com.cobblemon.mod.common.api.storage.pc.PCPosition
|
||||
import com.cobblemon.mod.common.api.text.bold
|
||||
import com.cobblemon.mod.common.client.CobblemonResources
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.SoundlessWidget
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.client.settings.ServerSettings
|
||||
import com.cobblemon.mod.common.client.storage.ClientPC
|
||||
import com.cobblemon.mod.common.client.storage.ClientParty
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.SwapPCPartyPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.party.MovePartyPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.party.ReleasePartyPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.party.SwapPartyPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.pc.MovePCPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.pc.MovePCPokemonToPartyPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.pc.MovePartyPokemonToPCPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.pc.ReleasePCPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.pc.SwapPCPokemonPacket
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import net.minecraft.client.MinecraftClient
|
||||
import net.minecraft.client.gui.widget.ButtonWidget
|
||||
import net.minecraft.client.sound.PositionedSoundInstance
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
import net.minecraft.sound.SoundEvent
|
||||
import net.minecraft.text.Text
|
||||
|
||||
class StorageWidget(
|
||||
pX: Int, pY: Int,
|
||||
val pcGui: PCGUI,
|
||||
private val pc: ClientPC,
|
||||
private val party: ClientParty
|
||||
) : SoundlessWidget(pX, pY, WIDTH, HEIGHT, Text.literal("PCWidget")) {
|
||||
|
||||
companion object {
|
||||
const val WIDTH = 263
|
||||
const val HEIGHT = 155
|
||||
const val BOX_SLOT_START_OFFSET_X = 7
|
||||
const val BOX_SLOT_START_OFFSET_Y = 11
|
||||
const val PARTY_SLOT_START_OFFSET_X = 193
|
||||
const val PARTY_SLOT_START_OFFSET_Y = 8
|
||||
const val BOX_SLOT_PADDING = 2
|
||||
const val PARTY_SLOT_PADDING = 6
|
||||
|
||||
private val screenOverlayResource = cobblemonResource("ui/pc/pc_screen_overlay.png")
|
||||
}
|
||||
|
||||
private val partySlots = arrayListOf<PartyStorageSlot>()
|
||||
private val boxSlots = arrayListOf<BoxStorageSlot>()
|
||||
private val releaseButton: ReleaseButton
|
||||
private val releaseYesButton: ReleaseConfirmButton
|
||||
private val releaseNoButton: ReleaseConfirmButton
|
||||
|
||||
var displayConfirmRelease = false
|
||||
var screenLoaded = false
|
||||
var selectedPosition: StorePosition? = null
|
||||
var grabbedSlot: GrabbedStorageSlot? = null
|
||||
|
||||
var box = 0
|
||||
set(value) {
|
||||
// If value is within min and max
|
||||
field = if (value > 0 && value < pc.boxes.size) value
|
||||
// If value is less than zero, wrap around to end
|
||||
else if (value < 0) pc.boxes.size - 1
|
||||
// Else it's greater than max, wrap around to start
|
||||
else 0
|
||||
this.setupStorageSlots()
|
||||
}
|
||||
|
||||
init {
|
||||
this.setupStorageSlots()
|
||||
|
||||
this.releaseButton = ReleaseButton(
|
||||
x = x + 194,
|
||||
y = y + 124,
|
||||
parent = this,
|
||||
onPress = {
|
||||
if (!displayConfirmRelease) {
|
||||
displayConfirmRelease = true
|
||||
playSound(CobblemonSounds.GUI_CLICK.get())
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
this.releaseYesButton = ReleaseConfirmButton(
|
||||
x = x + 190,
|
||||
y = y + 131,
|
||||
parent = this,
|
||||
subKey = "ui.generic.yes",
|
||||
onPress = {
|
||||
if (canDeleteSelected() && displayConfirmRelease) {
|
||||
val position = selectedPosition ?: return@ReleaseConfirmButton
|
||||
val pokemon = getSelectedPokemon() ?: return@ReleaseConfirmButton
|
||||
|
||||
val packet = when (position) {
|
||||
is PartyPosition -> ReleasePartyPokemonPacket(pokemon.uuid, position)
|
||||
is PCPosition -> ReleasePCPokemonPacket(pokemon.uuid, position)
|
||||
else -> return@ReleaseConfirmButton
|
||||
}
|
||||
|
||||
CobblemonNetwork.sendToServer(packet)
|
||||
playSound(CobblemonSounds.PC_RELEASE.get())
|
||||
resetSelected()
|
||||
displayConfirmRelease = false
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
this.releaseNoButton = ReleaseConfirmButton(
|
||||
x = x + 226,
|
||||
y = y + 131,
|
||||
parent = this,
|
||||
subKey = "ui.generic.no",
|
||||
onPress = {
|
||||
if (displayConfirmRelease) {
|
||||
displayConfirmRelease = false
|
||||
playSound(CobblemonSounds.GUI_CLICK.get())
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fun canDeleteSelected(): Boolean {
|
||||
return !(selectedPosition is PartyPosition && party.filterNotNull().size <= 1)
|
||||
&& selectedPosition != null
|
||||
&& grabbedSlot != null
|
||||
}
|
||||
|
||||
private fun setupStorageSlots() {
|
||||
this.resetStorageSlots()
|
||||
var index = 0
|
||||
|
||||
// Box Slots
|
||||
val boxStartX = x + BOX_SLOT_START_OFFSET_X
|
||||
val boxStartY = y + BOX_SLOT_START_OFFSET_Y
|
||||
|
||||
for (row in 1..5) {
|
||||
for (col in 1..6) {
|
||||
BoxStorageSlot(
|
||||
x = boxStartX + ((col - 1) * (StorageSlot.SIZE + BOX_SLOT_PADDING)),
|
||||
y = boxStartY + ((row - 1) * (StorageSlot.SIZE + BOX_SLOT_PADDING)),
|
||||
parent = this,
|
||||
pc = pc,
|
||||
position = PCPosition(box, index),
|
||||
onPress = { this.onStorageSlotClicked(it) }
|
||||
).also { widget ->
|
||||
this.addWidget(widget)
|
||||
this.boxSlots.add(widget)
|
||||
}
|
||||
index++
|
||||
}
|
||||
}
|
||||
|
||||
// Party Slots
|
||||
for (partyIndex in 0..5) {
|
||||
var partyX = x + PARTY_SLOT_START_OFFSET_X
|
||||
var partyY = y + PARTY_SLOT_START_OFFSET_Y
|
||||
|
||||
if (partyIndex > 0) {
|
||||
val isEven = partyIndex % 2 == 0
|
||||
val offsetIndex = (partyIndex - (if (isEven) 0 else 1)) / 2
|
||||
val offsetX = if (isEven) 0 else (StorageSlot.SIZE + PARTY_SLOT_PADDING)
|
||||
val offsetY = if (isEven) 0 else 8
|
||||
|
||||
partyX += offsetX
|
||||
partyY += ((StorageSlot.SIZE + PARTY_SLOT_PADDING) * offsetIndex) + offsetY
|
||||
}
|
||||
|
||||
PartyStorageSlot(
|
||||
x = partyX,
|
||||
y = partyY,
|
||||
parent = this,
|
||||
party = party,
|
||||
position = PartyPosition(partyIndex),
|
||||
onPress = { this.onStorageSlotClicked(it) }
|
||||
).also { widget ->
|
||||
this.addWidget(widget)
|
||||
this.partySlots.add(widget)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getSelectedPokemon(): Pokemon? {
|
||||
val selectedPosition = this.selectedPosition ?: return null
|
||||
return when (selectedPosition) {
|
||||
is PCPosition -> pc.get(selectedPosition)
|
||||
is PartyPosition -> party.get(selectedPosition)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
override fun render(matrices: MatrixStack, mouseX: Int, mouseY: Int, delta: Float) {
|
||||
// Party Label
|
||||
drawScaledText(
|
||||
matrixStack = matrices,
|
||||
font = CobblemonResources.DEFAULT_LARGE,
|
||||
text = lang("ui.party").bold(),
|
||||
x = x + 213,
|
||||
y = y - 15.5,
|
||||
centered = true,
|
||||
shadow = true
|
||||
)
|
||||
|
||||
if (canDeleteSelected() && displayConfirmRelease) {
|
||||
drawScaledText(
|
||||
matrixStack = matrices,
|
||||
font = CobblemonResources.DEFAULT_LARGE,
|
||||
text = lang("ui.pc.release").bold(),
|
||||
x = x + 223,
|
||||
y = y + 119,
|
||||
centered = true
|
||||
)
|
||||
}
|
||||
|
||||
this.releaseButton.render(matrices, mouseX, mouseY, delta)
|
||||
this.releaseYesButton.render(matrices, mouseX, mouseY, delta)
|
||||
this.releaseNoButton.render(matrices, mouseX, mouseY, delta)
|
||||
|
||||
// Screen Overlay
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = screenOverlayResource,
|
||||
x = x - 17,
|
||||
y = y - 17,
|
||||
width = 208,
|
||||
height = 189,
|
||||
alpha = if (screenLoaded) 1F else ((pcGui.ticksElapsed).toFloat() / 10F).coerceIn(0F, 1F)
|
||||
)
|
||||
|
||||
if (screenLoaded) {
|
||||
this.boxSlots.forEach { slot ->
|
||||
slot.render(matrices, mouseX, mouseY, delta)
|
||||
val pokemon = slot.getPokemon()
|
||||
if (grabbedSlot == null && slot.isHovered(mouseX, mouseY)
|
||||
&& pokemon != null && pokemon != pcGui.previewPokemon) pcGui.setPreviewPokemon(pokemon)
|
||||
}
|
||||
} else {
|
||||
if (pcGui.ticksElapsed >= 10) screenLoaded = true
|
||||
}
|
||||
|
||||
this.partySlots.forEach { slot ->
|
||||
slot.render(matrices, mouseX, mouseY, delta)
|
||||
val pokemon = slot.getPokemon()
|
||||
if (grabbedSlot == null && slot.isHovered(mouseX, mouseY)
|
||||
&& pokemon != null && pokemon != pcGui.previewPokemon) pcGui.setPreviewPokemon(pokemon)
|
||||
}
|
||||
|
||||
grabbedSlot?.render(matrices, mouseX, mouseY, delta)
|
||||
}
|
||||
|
||||
override fun mouseClicked(pMouseX: Double, pMouseY: Double, pButton: Int): Boolean {
|
||||
if (displayConfirmRelease) {
|
||||
if (releaseYesButton.isHovered(pMouseX, pMouseY)) releaseYesButton.mouseClicked(pMouseX, pMouseY, pButton)
|
||||
if (releaseNoButton.isHovered(pMouseX, pMouseY)) releaseNoButton.mouseClicked(pMouseX, pMouseY, pButton)
|
||||
} else {
|
||||
if (releaseButton.isHovered(pMouseX, pMouseY)) releaseButton.mouseClicked(pMouseX, pMouseY, pButton)
|
||||
}
|
||||
|
||||
return super.mouseClicked(pMouseX, pMouseY, pButton)
|
||||
}
|
||||
|
||||
private fun resetStorageSlots() {
|
||||
this.partySlots.forEach(this::removeWidget)
|
||||
this.partySlots.clear()
|
||||
|
||||
this.boxSlots.forEach(this::removeWidget)
|
||||
this.boxSlots.clear()
|
||||
}
|
||||
|
||||
private fun playSound(soundEvent: SoundEvent) {
|
||||
MinecraftClient.getInstance().soundManager.play(PositionedSoundInstance.master(soundEvent, 1.0F))
|
||||
}
|
||||
|
||||
private fun onStorageSlotClicked(button: ButtonWidget) {
|
||||
|
||||
// Check if storage slot
|
||||
val clickedPosition = when(button) {
|
||||
is BoxStorageSlot -> button.position
|
||||
is PartyStorageSlot -> button.position
|
||||
else -> return
|
||||
}
|
||||
|
||||
// Reset release confirmation
|
||||
displayConfirmRelease = false
|
||||
|
||||
// Clicking on itself, so unselect position
|
||||
if (this.selectedPosition != null && this.selectedPosition == clickedPosition) {
|
||||
if (grabbedSlot != null) playSound(CobblemonSounds.PC_DROP.get())
|
||||
resetSelected()
|
||||
return
|
||||
}
|
||||
|
||||
// Check for selecting a Pokémon
|
||||
val clickedPokemon = when(button) {
|
||||
is BoxStorageSlot -> pc.get(clickedPosition as PCPosition)
|
||||
is PartyStorageSlot -> party.get(clickedPosition as PartyPosition)
|
||||
else -> null
|
||||
}
|
||||
|
||||
if (grabbedSlot == null) {
|
||||
if (clickedPokemon != null) {
|
||||
this.selectedPosition = clickedPosition
|
||||
this.pcGui.setPreviewPokemon(clickedPokemon)
|
||||
grabbedSlot = GrabbedStorageSlot(
|
||||
x = button.x,
|
||||
y = button.y,
|
||||
parent = this,
|
||||
pokemon = clickedPokemon
|
||||
)
|
||||
playSound(CobblemonSounds.PC_GRAB.get())
|
||||
|
||||
}
|
||||
} else {
|
||||
// Handle movement within the Box
|
||||
val selectedPokemon = when(this.selectedPosition) {
|
||||
is PCPosition -> pc.get(this.selectedPosition as PCPosition)
|
||||
is PartyPosition -> party.get(this.selectedPosition as PartyPosition)
|
||||
else -> null
|
||||
} ?: return
|
||||
|
||||
// Box to Box
|
||||
if (this.selectedPosition is PCPosition && clickedPosition is PCPosition) {
|
||||
val packet = clickedPokemon?.let { SwapPCPokemonPacket(it.uuid, clickedPosition, selectedPokemon.uuid, this.selectedPosition as PCPosition) }
|
||||
?: MovePCPokemonPacket(selectedPokemon.uuid, selectedPosition as PCPosition, clickedPosition)
|
||||
packet.sendToServer()
|
||||
playSound(CobblemonSounds.PC_DROP.get())
|
||||
resetSelected()
|
||||
}
|
||||
// Box to Party
|
||||
else if (this.selectedPosition is PCPosition && clickedPosition is PartyPosition) {
|
||||
val packet = clickedPokemon?.let { SwapPCPartyPokemonPacket(clickedPokemon.uuid, clickedPosition, selectedPokemon.uuid, this.selectedPosition as PCPosition) }
|
||||
?: MovePCPokemonToPartyPacket(selectedPokemon.uuid, this.selectedPosition as PCPosition, clickedPosition)
|
||||
packet.sendToServer()
|
||||
playSound(CobblemonSounds.PC_DROP.get())
|
||||
resetSelected()
|
||||
}
|
||||
// Party to Box
|
||||
else if (this.selectedPosition is PartyPosition && clickedPosition is PCPosition) {
|
||||
if (ServerSettings.preventCompletePartyDeposit && this.party.filterNotNull().size == 1 && clickedPokemon == null) {
|
||||
return
|
||||
}
|
||||
val packet = clickedPokemon?.let { SwapPCPartyPokemonPacket(selectedPokemon.uuid, this.selectedPosition as PartyPosition, clickedPokemon.uuid, clickedPosition) }
|
||||
?: MovePartyPokemonToPCPacket(selectedPokemon.uuid, this.selectedPosition as PartyPosition, clickedPosition)
|
||||
packet.sendToServer()
|
||||
playSound(CobblemonSounds.PC_DROP.get())
|
||||
resetSelected()
|
||||
}
|
||||
// Party to Party
|
||||
else if (this.selectedPosition is PartyPosition && clickedPosition is PartyPosition) {
|
||||
val packet = clickedPokemon?.let { SwapPartyPokemonPacket(it.uuid, clickedPosition, selectedPokemon.uuid, this.selectedPosition as PartyPosition) }
|
||||
?: MovePartyPokemonPacket(selectedPokemon.uuid, selectedPosition as PartyPosition, clickedPosition)
|
||||
packet.sendToServer()
|
||||
playSound(CobblemonSounds.PC_DROP.get())
|
||||
resetSelected()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun resetSelected() {
|
||||
selectedPosition = null
|
||||
grabbedSlot = null
|
||||
pcGui.setPreviewPokemon(null)
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.client.gui.summary
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.api.moves.Move
|
||||
import com.cobblemon.mod.common.api.moves.MoveSet
|
||||
@@ -19,6 +20,7 @@ import com.cobblemon.mod.common.api.text.bold
|
||||
import com.cobblemon.mod.common.api.text.text
|
||||
import com.cobblemon.mod.common.client.CobblemonClient
|
||||
import com.cobblemon.mod.common.client.CobblemonResources
|
||||
import com.cobblemon.mod.common.client.gui.ExitButton
|
||||
import com.cobblemon.mod.common.client.gui.TypeIcon
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.EvolutionSelectScreen
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.ModelWidget
|
||||
@@ -26,7 +28,7 @@ import com.cobblemon.mod.common.client.gui.summary.widgets.PartyWidget
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.screens.SummaryTab
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.screens.info.InfoWidget
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.screens.moves.MovesWidget
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.screens.moves.change.MoveSwapScreen
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.screens.moves.MoveSwapScreen
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.screens.stats.StatWidget
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.client.storage.ClientParty
|
||||
@@ -43,7 +45,9 @@ import net.minecraft.client.gui.Element
|
||||
import net.minecraft.client.gui.Selectable
|
||||
import net.minecraft.client.gui.screen.Screen
|
||||
import net.minecraft.client.gui.widget.ClickableWidget
|
||||
import net.minecraft.client.sound.PositionedSoundInstance
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
import net.minecraft.sound.SoundEvent
|
||||
import net.minecraft.text.Text
|
||||
|
||||
class Summary private constructor(): Screen(Text.translatable("cobblemon.ui.summary.title")) {
|
||||
@@ -154,7 +158,12 @@ class Summary private constructor(): Screen(Text.translatable("cobblemon.ui.summ
|
||||
pX = x + 78,
|
||||
pY = y - 1,
|
||||
label = lang("ui.info")
|
||||
) { if (mainScreenIndex != INFO) displayMainScreen(INFO) }
|
||||
) {
|
||||
if (mainScreenIndex != INFO) {
|
||||
displayMainScreen(INFO)
|
||||
playSound(CobblemonSounds.GUI_CLICK.get())
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
summaryTabs.add(
|
||||
@@ -162,7 +171,12 @@ class Summary private constructor(): Screen(Text.translatable("cobblemon.ui.summ
|
||||
pX = x + 119,
|
||||
pY = y - 1,
|
||||
label = lang("ui.moves")
|
||||
) { if (mainScreenIndex != MOVES) displayMainScreen(MOVES) }
|
||||
) {
|
||||
if (mainScreenIndex != MOVES) {
|
||||
displayMainScreen(MOVES)
|
||||
playSound(CobblemonSounds.GUI_CLICK.get())
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
summaryTabs.add(
|
||||
@@ -170,7 +184,12 @@ class Summary private constructor(): Screen(Text.translatable("cobblemon.ui.summ
|
||||
pX = x + 160,
|
||||
pY = y - 1,
|
||||
label = lang("ui.stats")
|
||||
) { if (mainScreenIndex != STATS) displayMainScreen(STATS) }
|
||||
) {
|
||||
if (mainScreenIndex != STATS) {
|
||||
displayMainScreen(STATS)
|
||||
playSound(CobblemonSounds.GUI_CLICK.get())
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
summaryTabs[mainScreenIndex].toggleTab()
|
||||
@@ -182,6 +201,7 @@ class Summary private constructor(): Screen(Text.translatable("cobblemon.ui.summ
|
||||
pX = x + 302,
|
||||
pY = y + 145
|
||||
) {
|
||||
playSound(CobblemonSounds.GUI_CLICK.get())
|
||||
MinecraftClient.getInstance().setScreen(null)
|
||||
}
|
||||
)
|
||||
@@ -512,4 +532,8 @@ class Summary private constructor(): Screen(Text.translatable("cobblemon.ui.summ
|
||||
override fun mouseClicked(d: Double, e: Double, i: Int): Boolean {
|
||||
return children().any { it.mouseClicked(d, e, i) }
|
||||
}
|
||||
|
||||
fun playSound(soundEvent: SoundEvent) {
|
||||
MinecraftClient.getInstance().soundManager.play(PositionedSoundInstance.master(soundEvent, 1.0F))
|
||||
}
|
||||
}
|
||||
@@ -8,12 +8,14 @@
|
||||
|
||||
package com.cobblemon.mod.common.client.gui.summary
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.api.text.bold
|
||||
import com.cobblemon.mod.common.client.CobblemonResources
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder
|
||||
import net.minecraft.client.gui.widget.ButtonWidget
|
||||
import net.minecraft.client.sound.PositionedSoundInstance
|
||||
import net.minecraft.client.sound.SoundManager
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
import net.minecraft.text.MutableText
|
||||
@@ -86,9 +88,9 @@ class SummaryButton(
|
||||
return false
|
||||
}
|
||||
|
||||
override fun playDownSound(soundManager: SoundManager?) {
|
||||
override fun playDownSound(soundManager: SoundManager) {
|
||||
if (!this.silent) {
|
||||
super.playDownSound(soundManager)
|
||||
soundManager.play(PositionedSoundInstance.master(CobblemonSounds.GUI_CLICK.get(), 1.0F))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
@@ -8,6 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.client.gui.summary.widgets
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.client.CobblemonResources
|
||||
import com.cobblemon.mod.common.client.gui.drawProfilePokemon
|
||||
@@ -197,6 +198,7 @@ class PartySlotWidget(
|
||||
} else {
|
||||
if ((index > -1) && (summary.selectedPokemon.uuid != pokemon?.uuid)) {
|
||||
summary.switchSelection(index)
|
||||
if (pokemon != null) partyWidget.playSound(CobblemonSounds.GUI_CLICK.get())
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -213,6 +215,7 @@ class PartySlotWidget(
|
||||
if (partyWidget.swapEnabled && partyWidget.isWithinScreen(mouseX, mouseY) && index < 0) {
|
||||
repositionSlot(mouseX, mouseY)
|
||||
} else {
|
||||
if (partyWidget.swapSource != null) partyWidget.playSound(CobblemonSounds.PC_DROP.get())
|
||||
toggleDrag(false)
|
||||
partyWidget.swapSource = null
|
||||
partyWidget.draggedSlot = null
|
||||
|
||||
+11
-1
@@ -8,6 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.client.gui.summary.widgets
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.api.text.bold
|
||||
import com.cobblemon.mod.common.client.CobblemonResources
|
||||
@@ -17,8 +18,11 @@ import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import net.minecraft.client.MinecraftClient
|
||||
import net.minecraft.client.sound.PositionedSoundInstance
|
||||
import java.security.InvalidParameterException
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
import net.minecraft.sound.SoundEvent
|
||||
import net.minecraft.text.Text
|
||||
|
||||
class PartyWidget(
|
||||
@@ -46,7 +50,7 @@ class PartyWidget(
|
||||
|
||||
private val partySize = partyList.size
|
||||
private val partySlots = arrayListOf<PartySlotWidget>()
|
||||
val swapButton: SummaryButton = SummaryButton(
|
||||
private val swapButton: SummaryButton = SummaryButton(
|
||||
buttonX = x + 80F,
|
||||
buttonY = y - 9F,
|
||||
buttonWidth = 26,
|
||||
@@ -159,6 +163,7 @@ class PartyWidget(
|
||||
index = -1,
|
||||
isClientPartyMember = isParty
|
||||
)
|
||||
playSound(CobblemonSounds.PC_GRAB.get())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -174,6 +179,7 @@ class PartyWidget(
|
||||
}
|
||||
swapSource = null
|
||||
draggedSlot = null
|
||||
playSound(CobblemonSounds.PC_DROP.get())
|
||||
}
|
||||
}
|
||||
return super.mouseReleased(pMouseX, pMouseY, pButton)
|
||||
@@ -205,6 +211,10 @@ class PartyWidget(
|
||||
return -1
|
||||
}
|
||||
|
||||
fun playSound(soundEvent: SoundEvent) {
|
||||
MinecraftClient.getInstance().soundManager.play(PositionedSoundInstance.master(soundEvent, 1.0F))
|
||||
}
|
||||
|
||||
fun isWithinScreen(mouseX: Double, mouseY: Double): Boolean = mouseX.toInt() in x..(x + WIDTH)
|
||||
&& mouseY.toInt() in y..(y + HEIGHT)
|
||||
}
|
||||
+6
@@ -8,12 +8,15 @@
|
||||
|
||||
package com.cobblemon.mod.common.client.gui.summary.widgets.screens
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.api.text.bold
|
||||
import com.cobblemon.mod.common.client.CobblemonResources
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.client.gui.widget.ButtonWidget
|
||||
import net.minecraft.client.sound.PositionedSoundInstance
|
||||
import net.minecraft.client.sound.SoundManager
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
import net.minecraft.text.MutableText
|
||||
|
||||
@@ -47,6 +50,9 @@ class SummaryTab(
|
||||
)
|
||||
}
|
||||
|
||||
override fun playDownSound(soundManager: SoundManager) {
|
||||
}
|
||||
|
||||
fun toggleTab(state: Boolean = true) {
|
||||
isActive = state
|
||||
}
|
||||
|
||||
+4
-3
@@ -18,6 +18,7 @@ import com.cobblemon.mod.common.client.CobblemonResources
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.SoundlessWidget
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.asTranslated
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import net.minecraft.client.MinecraftClient
|
||||
@@ -147,7 +148,7 @@ class InfoWidget(
|
||||
drawScaledText(
|
||||
matrixStack = pMatrixStack,
|
||||
font = CobblemonResources.DEFAULT_LARGE,
|
||||
text = pokemon.nature.displayName.bold(),
|
||||
text = pokemon.nature.displayName.asTranslated().bold(),
|
||||
x = x + 53,
|
||||
y = y + 66,
|
||||
shadow = true
|
||||
@@ -166,7 +167,7 @@ class InfoWidget(
|
||||
drawScaledText(
|
||||
matrixStack = pMatrixStack,
|
||||
font = CobblemonResources.DEFAULT_LARGE,
|
||||
text = pokemon.ability.displayName.bold(),
|
||||
text = pokemon.ability.displayName.asTranslated().bold(),
|
||||
x = x + 53,
|
||||
y = y + 81,
|
||||
shadow = true
|
||||
@@ -177,7 +178,7 @@ class InfoWidget(
|
||||
pMatrixStack.push()
|
||||
pMatrixStack.scale(smallTextScale, smallTextScale, 1F)
|
||||
MultiLineLabelK.create(
|
||||
component = pokemon.ability.description,
|
||||
component = pokemon.ability.description.asTranslated(),
|
||||
width = 117 / smallTextScale,
|
||||
maxLines = 3
|
||||
).renderLeftAligned(
|
||||
|
||||
+3
-2
@@ -6,9 +6,10 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.gui.summary.widgets.screens.moves.change
|
||||
package com.cobblemon.mod.common.client.gui.summary.widgets.screens.moves
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonNetwork
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.api.moves.Move
|
||||
import com.cobblemon.mod.common.api.moves.MoveTemplate
|
||||
@@ -18,7 +19,6 @@ import com.cobblemon.mod.common.client.gui.MoveCategoryIcon
|
||||
import com.cobblemon.mod.common.client.gui.TypeIcon
|
||||
import com.cobblemon.mod.common.client.gui.summary.Summary
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.common.SummaryScrollList
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.screens.moves.MovesWidget
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.net.messages.server.BenchMovePacket
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
@@ -195,6 +195,7 @@ class MoveSwapScreen(
|
||||
newMove = move
|
||||
)
|
||||
)
|
||||
pane.movesWidget.summary.playSound(CobblemonSounds.GUI_CLICK.get())
|
||||
pane.movesWidget.summary.displaySideScreen(Summary.PARTY)
|
||||
return true
|
||||
}
|
||||
+7
@@ -8,9 +8,12 @@
|
||||
|
||||
package com.cobblemon.mod.common.client.gui.summary.widgets.screens.moves
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.client.gui.widget.ButtonWidget
|
||||
import net.minecraft.client.sound.PositionedSoundInstance
|
||||
import net.minecraft.client.sound.SoundManager
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
import net.minecraft.text.Text
|
||||
|
||||
@@ -63,5 +66,9 @@ class ReorderMoveButton(
|
||||
}
|
||||
}
|
||||
|
||||
override fun playDownSound(soundManager: SoundManager) {
|
||||
soundManager.play(PositionedSoundInstance.master(CobblemonSounds.GUI_CLICK.get(), 1.0F))
|
||||
}
|
||||
|
||||
fun isHovered(mouseX: Double, mouseY: Double, offsetY: Float) = mouseX.toFloat() in ((pX - OFFSET_X)..((pX - OFFSET_X) + (WIDTH * SCALE))) && mouseY.toFloat() in ((pY + offsetY)..((pY + offsetY) + (HEIGHT * SCALE) - 0.5F))
|
||||
}
|
||||
|
||||
+7
-1
@@ -8,11 +8,13 @@
|
||||
|
||||
package com.cobblemon.mod.common.client.gui.summary.widgets.screens.moves
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.api.moves.MoveTemplate
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.screens.moves.change.MoveSwapScreen
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.client.gui.widget.ButtonWidget
|
||||
import net.minecraft.client.sound.PositionedSoundInstance
|
||||
import net.minecraft.client.sound.SoundManager
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
import net.minecraft.text.Text
|
||||
|
||||
@@ -57,5 +59,9 @@ class SwapMoveButton(
|
||||
)
|
||||
}
|
||||
|
||||
override fun playDownSound(soundManager: SoundManager) {
|
||||
soundManager.play(PositionedSoundInstance.master(CobblemonSounds.GUI_CLICK.get(), 1.0F))
|
||||
}
|
||||
|
||||
fun isHovered(mouseX: Double, mouseY: Double) = mouseX.toFloat() in ((pX + OFFSET_X)..((pX + OFFSET_X) + (WIDTH * SCALE))) && mouseY.toFloat() in ((pY + OFFSET_Y)..((pY + OFFSET_Y) + (HEIGHT * SCALE) - 0.5F))
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ import com.cobblemon.mod.common.client.net.gui.SummaryUIPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.pokemon.update.EvolutionUpdatePacketHandler
|
||||
import com.cobblemon.mod.common.client.net.pokemon.update.SingleUpdatePacketHandler
|
||||
import com.cobblemon.mod.common.client.net.settings.ServerSettingsPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.sound.UnvalidatedPlaySoundS2CPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.starter.StarterUIPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.storage.RemoveClientPokemonHandler
|
||||
import com.cobblemon.mod.common.client.net.storage.SwapClientPokemonHandler
|
||||
@@ -155,6 +156,9 @@ object ClientPacketRegistrar : SidedPacketRegistrar() {
|
||||
registerHandler(DataRegistrySyncPacketHandler<Species, SpeciesRegistrySyncPacket>())
|
||||
registerHandler(DataRegistrySyncPacketHandler<PropertiesCompletionProvider.SuggestionHolder, PropertiesCompletionRegistrySyncPacket>())
|
||||
|
||||
// Hax
|
||||
registerHandler(UnvalidatedPlaySoundS2CPacketHandler)
|
||||
|
||||
CobblemonNetwork.clientHandlersRegistered.complete(Unit)
|
||||
}
|
||||
}
|
||||
|
||||
+5
@@ -14,6 +14,7 @@ import com.cobblemon.mod.common.client.battle.ActiveClientBattlePokemon
|
||||
import com.cobblemon.mod.common.client.battle.ClientBattle
|
||||
import com.cobblemon.mod.common.client.battle.ClientBattleActor
|
||||
import com.cobblemon.mod.common.client.battle.ClientBattlePokemon
|
||||
import com.cobblemon.mod.common.client.gui.battle.BattleGUI
|
||||
import com.cobblemon.mod.common.client.net.ClientPacketHandler
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleInitializePacket
|
||||
import net.minecraft.client.MinecraftClient
|
||||
@@ -45,7 +46,10 @@ object BattleInitializeHandler : ClientPacketHandler<BattleInitializePacket> {
|
||||
}
|
||||
}
|
||||
}
|
||||
minimised = false
|
||||
}
|
||||
|
||||
MinecraftClient.getInstance().setScreen(BattleGUI())
|
||||
}
|
||||
|
||||
fun actorFromDTO(actorDTO: BattleInitializePacket.BattleActorDTO): ClientBattleActor {
|
||||
@@ -60,6 +64,7 @@ object BattleInitializeHandler : ClientPacketHandler<BattleInitializePacket> {
|
||||
ClientBattlePokemon(
|
||||
uuid = it.uuid,
|
||||
properties = it.properties,
|
||||
aspects = it.aspects,
|
||||
displayName = it.displayName,
|
||||
hpRatio = it.hpRatio,
|
||||
status = it.status,
|
||||
|
||||
+1
@@ -34,6 +34,7 @@ object BattleSwitchPokemonHandler : ClientPacketHandler<BattleSwitchPokemonPacke
|
||||
uuid = uuid,
|
||||
displayName = displayName,
|
||||
properties = properties,
|
||||
aspects = aspects,
|
||||
hpRatio = hpRatio,
|
||||
status = status,
|
||||
statChanges = statChanges
|
||||
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.net.sound
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonNetwork
|
||||
import com.cobblemon.mod.common.client.net.ClientPacketHandler
|
||||
import com.cobblemon.mod.common.net.messages.client.sound.UnvalidatedPlaySoundS2CPacket
|
||||
import net.minecraft.client.MinecraftClient
|
||||
import net.minecraft.sound.SoundEvent
|
||||
|
||||
internal object UnvalidatedPlaySoundS2CPacketHandler : ClientPacketHandler<UnvalidatedPlaySoundS2CPacket> {
|
||||
override fun invokeOnClient(packet: UnvalidatedPlaySoundS2CPacket, ctx: CobblemonNetwork.NetworkContext) {
|
||||
val client = MinecraftClient.getInstance()
|
||||
client.executeSync {
|
||||
// This prevents clients that might not have the required resources installed from getting spammed about missing sound
|
||||
if (client.soundManager.get(packet.sound) != null) {
|
||||
client.world?.playSound(client.player, packet.x, packet.y, packet.z, SoundEvent(packet.sound), packet.category, packet.volume, packet.pitch)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -10,7 +10,7 @@ package com.cobblemon.mod.common.client.net.storage.pc
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonNetwork
|
||||
import com.cobblemon.mod.common.client.CobblemonClient
|
||||
import com.cobblemon.mod.common.client.gui.pc.PCGui
|
||||
import com.cobblemon.mod.common.client.gui.pc.PCGUI
|
||||
import com.cobblemon.mod.common.client.net.ClientPacketHandler
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.pc.OpenPCPacket
|
||||
import net.minecraft.client.MinecraftClient
|
||||
@@ -18,6 +18,6 @@ import net.minecraft.client.MinecraftClient
|
||||
object OpenPCHandler : ClientPacketHandler<OpenPCPacket> {
|
||||
override fun invokeOnClient(packet: OpenPCPacket, ctx: CobblemonNetwork.NetworkContext) {
|
||||
val pc = CobblemonClient.storage.pcStores[packet.storeID] ?: return
|
||||
MinecraftClient.getInstance().setScreen(PCGui(pc, CobblemonClient.storage.myParty))
|
||||
MinecraftClient.getInstance().setScreen(PCGUI(pc, CobblemonClient.storage.myParty))
|
||||
}
|
||||
}
|
||||
+6
-8
@@ -274,23 +274,21 @@ abstract class PoseableEntityModel<T : Entity>(
|
||||
)
|
||||
|
||||
fun bedrock(
|
||||
file: String,
|
||||
animationGroup: String,
|
||||
animation: String,
|
||||
fileSuffix: String = ".animation.json",
|
||||
animationPrefix: String = "animation.${file.substringAfterLast("/")}"
|
||||
animationPrefix: String = "animation.$animationGroup"
|
||||
) = BedrockStatelessAnimation<T>(
|
||||
this,
|
||||
BedrockAnimationRepository.getAnimation(file + fileSuffix, "$animationPrefix.$animation")
|
||||
BedrockAnimationRepository.getAnimation(animationGroup, "$animationPrefix.$animation")
|
||||
)
|
||||
|
||||
fun bedrockStateful(
|
||||
file: String,
|
||||
animationGroup: String,
|
||||
animation: String,
|
||||
fileSuffix: String = ".animation.json",
|
||||
animationPrefix: String = "animation.${file.substringAfterLast("/")}",
|
||||
animationPrefix: String = "animation.$animationGroup",
|
||||
preventsIdleCheck: (T?, PoseableEntityState<T>, StatelessAnimation<T, *>) -> Boolean = { _, _, _ -> true }
|
||||
) = BedrockStatefulAnimation(
|
||||
BedrockAnimationRepository.getAnimation(file + fileSuffix, "$animationPrefix.$animation"),
|
||||
BedrockAnimationRepository.getAnimation(animationGroup, "$animationPrefix.$animation"),
|
||||
preventsIdleCheck
|
||||
)
|
||||
|
||||
|
||||
+1
-1
@@ -28,6 +28,6 @@ class RotationFunctionStatelessAnimation<T : Entity>(
|
||||
) : StatelessAnimation<T, ModelFrame>(frame) {
|
||||
override val targetFrame = ModelFrame::class.java
|
||||
override fun setAngles(entity: T?, model: PoseableEntityModel<T>, state: PoseableEntityState<T>?, limbSwing: Float, limbSwingAmount: Float, ageInTicks: Float, headYaw: Float, headPitch: Float) {
|
||||
part.addRotation(axis, function(timeVariable(entity?.let { model.getState(it) }, limbSwing, ageInTicks) ?: 0F))
|
||||
part.addRotation(axis, function(timeVariable(state, limbSwing, ageInTicks) ?: 0F))
|
||||
}
|
||||
}
|
||||
+20
-15
@@ -8,10 +8,11 @@
|
||||
|
||||
package com.cobblemon.mod.common.client.render.models.blockbench.bedrock.animation
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.Cobblemon.LOGGER
|
||||
import com.cobblemon.mod.common.util.fromJson
|
||||
import com.google.gson.FieldNamingPolicy
|
||||
import com.google.gson.GsonBuilder
|
||||
import net.minecraft.resource.ResourceManager
|
||||
|
||||
|
||||
/**
|
||||
@@ -28,22 +29,26 @@ object BedrockAnimationRepository {
|
||||
.registerTypeAdapter(BedrockAnimation::class.java, BedrockAnimationAdapter)
|
||||
.create()
|
||||
|
||||
private val animations: MutableMap<String, BedrockAnimation> = mutableMapOf()
|
||||
private val animationGroups = mutableMapOf<String, BedrockAnimationGroup>()
|
||||
|
||||
fun loadAnimations(resourceManager: ResourceManager) {
|
||||
LOGGER.info("Loading animations...")
|
||||
var animationCount = 0
|
||||
animationGroups.clear()
|
||||
resourceManager.findResources("bedrock/animations", { it.path.endsWith(".animation.json") }).forEach { identifier, resource ->
|
||||
val animationGroup = gson.fromJson<BedrockAnimationGroup>(resource.inputStream.reader())
|
||||
val animationGroupName = identifier.path.substringAfterLast("/").replace(".animation.json", "")
|
||||
animationGroups[animationGroupName] = animationGroup
|
||||
animationCount += animationGroup.animations.size
|
||||
}
|
||||
LOGGER.info("Loaded $animationCount animations from ${animationGroups.size} animation groups.")
|
||||
}
|
||||
|
||||
fun getAnimation(fileName: String, animationName: String): BedrockAnimation {
|
||||
if (animations[animationName] == null) {
|
||||
loadAnimationsFromFile(fileName)
|
||||
}
|
||||
return animations[animationName] ?: throw IllegalArgumentException("animation is not in specified file")
|
||||
}
|
||||
val animationGroup = animationGroups[fileName]
|
||||
?: throw IllegalArgumentException("Unknown animation group: $fileName")
|
||||
|
||||
fun loadAnimationsFromFile(fileName: String) {
|
||||
val stream = Cobblemon::class.java.getResourceAsStream("/assets/${Cobblemon.MODID}/bedrock/animations/$fileName") ?: throw IllegalStateException("animation file $fileName could not be found")
|
||||
val animationGroup = gson.fromJson<BedrockAnimationGroup>(stream.reader())
|
||||
animationGroup.animations.forEach { (name, animation) -> animations[name] = animation }
|
||||
}
|
||||
|
||||
fun clear() {
|
||||
animations.clear()
|
||||
return animationGroup.animations[animationName]
|
||||
?: throw IllegalArgumentException("Animation $animationName not found in animation group $fileName")
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -150,7 +150,7 @@ class JsonPokemonPoseableModel(override val rootPart: ModelPart) : PokemonPoseab
|
||||
return@mapNotNull JsonPokemonPoseableModelAdapter.model!!.singleBoneLook<PokemonEntity>()
|
||||
} else if (animString.startsWith("bedrock")) {
|
||||
val split = animString.replace("bedrock(", "").replace(")", "").split(",").map(String::trim)
|
||||
return@mapNotNull model.bedrock(file = split[0], animation = split[1])
|
||||
return@mapNotNull model.bedrock(animationGroup = split[0], animation = split[1])
|
||||
}
|
||||
return@mapNotNull null
|
||||
}.toTypedArray()
|
||||
|
||||
+5
-1
@@ -89,7 +89,11 @@ abstract class PokemonPoseableModel : PoseableEntityModel<PokemonEntity>() {
|
||||
if (provider != null) {
|
||||
for (layer in currentLayers) {
|
||||
val texture = layer.texture ?: continue
|
||||
val consumer = provider.getBuffer(RenderLayer.getEntityTranslucent(texture))
|
||||
val consumer = if (layer.emissive) {
|
||||
provider.getBuffer(RenderLayer.getEntityTranslucentEmissive(texture))
|
||||
} else {
|
||||
provider.getBuffer(RenderLayer.getEntityTranslucent(texture))
|
||||
}
|
||||
stack.push()
|
||||
stack.scale(layer.scale.x, layer.scale.y, layer.scale.z)
|
||||
super.render(stack, consumer, packedLight, OverlayTexture.DEFAULT_UV, layer.tint.x, layer.tint.y, layer.tint.z, layer.tint.w)
|
||||
|
||||
+5
-5
@@ -26,7 +26,7 @@ class AbraModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame {
|
||||
override val portraitTranslation = Vec3d(0.0, 0.2, 0.0)
|
||||
|
||||
override val profileScale = 1.0F
|
||||
override val profileTranslation = Vec3d(0.0, 0.0, 0.0)
|
||||
override val profileTranslation = Vec3d(0.0, 0.4, 0.0)
|
||||
|
||||
lateinit var standing: PokemonPose
|
||||
lateinit var walk: PokemonPose
|
||||
@@ -38,7 +38,7 @@ class AbraModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame {
|
||||
transformTicks = 10,
|
||||
idleAnimations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("0063_abra/abra", "ground_idle")
|
||||
bedrock("abra", "ground_idle")
|
||||
)
|
||||
)
|
||||
|
||||
@@ -48,8 +48,8 @@ class AbraModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame {
|
||||
transformTicks = 10,
|
||||
idleAnimations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("0063_abra/abra", "ground_idle")
|
||||
//bedrock("0063_abra/abra", "ground_walk")
|
||||
bedrock("abra", "ground_idle")
|
||||
//bedrock("abra", "ground_walk")
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -57,5 +57,5 @@ class AbraModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame {
|
||||
override fun getFaintAnimation(
|
||||
pokemonEntity: PokemonEntity,
|
||||
state: PoseableEntityState<PokemonEntity>
|
||||
) = if (state.isPosedIn(standing, walk)) bedrockStateful("0063_abra/abra", "faint") else null
|
||||
) = if (state.isPosedIn(standing, walk)) bedrockStateful("abra", "faint") else null
|
||||
}
|
||||
+4
-4
@@ -36,7 +36,7 @@ class AerodactylModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame {
|
||||
poseType = PoseType.STAND,
|
||||
idleAnimations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("0142_aerodactyl/aerodactyl", "ground_idle")
|
||||
bedrock("aerodactyl", "ground_idle")
|
||||
)
|
||||
)
|
||||
|
||||
@@ -45,7 +45,7 @@ class AerodactylModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame {
|
||||
poseTypes = UI_POSES + PoseType.HOVER + PoseType.FLOAT,
|
||||
idleAnimations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("0142_aerodactyl/aerodactyl", "air_idle")
|
||||
bedrock("aerodactyl", "air_idle")
|
||||
)
|
||||
)
|
||||
|
||||
@@ -54,7 +54,7 @@ class AerodactylModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame {
|
||||
poseTypes = setOf(PoseType.FLY, PoseType.SWIM),
|
||||
idleAnimations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("0142_aerodactyl/aerodactyl", "air_fly")
|
||||
bedrock("aerodactyl", "air_fly")
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -62,5 +62,5 @@ class AerodactylModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame {
|
||||
// override fun getFaintAnimation(
|
||||
// pokemonEntity: PokemonEntity,
|
||||
// state: PoseableEntityState<PokemonEntity>
|
||||
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("0142_aerodactyl/aerodactyl", "faint") else null
|
||||
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("aerodactyl", "faint") else null
|
||||
}
|
||||
+4
-4
@@ -36,7 +36,7 @@ class AlakazamModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame {
|
||||
transformTicks = 10,
|
||||
idleAnimations = arrayOf(
|
||||
singleBoneLook() ,
|
||||
bedrock("0065_alakazam/alakazam", "ground_idle")
|
||||
bedrock("alakazam", "ground_idle")
|
||||
)
|
||||
)
|
||||
|
||||
@@ -46,8 +46,8 @@ class AlakazamModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame {
|
||||
transformTicks = 10,
|
||||
idleAnimations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("0065_alakazam/alakazam", "ground_idle")
|
||||
//bedrock("0065_alakazam/alakazam", "ground_walk")
|
||||
bedrock("alakazam", "ground_idle")
|
||||
//bedrock("alakazam", "ground_walk")
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -55,5 +55,5 @@ class AlakazamModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame {
|
||||
// override fun getFaintAnimation(
|
||||
// pokemonEntity: PokemonEntity,
|
||||
// state: PoseableEntityState<PokemonEntity>
|
||||
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("0065_alakazam/alakazam", "faint") else null
|
||||
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("alakazam", "faint") else null
|
||||
}
|
||||
+4
-4
@@ -79,7 +79,7 @@ class ArbokModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame {
|
||||
transformTicks = 10,
|
||||
idleAnimations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("0024_arbok/arbok", "ground_idle"),
|
||||
bedrock("arbok", "ground_idle"),
|
||||
wave
|
||||
)
|
||||
)
|
||||
@@ -90,7 +90,7 @@ class ArbokModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame {
|
||||
transformTicks = 10,
|
||||
idleAnimations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("0024_arbok/arbok", "ground_walk"),
|
||||
bedrock("arbok", "ground_walk"),
|
||||
wave
|
||||
)
|
||||
)
|
||||
@@ -100,7 +100,7 @@ class ArbokModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame {
|
||||
poseTypes = UI_POSES,
|
||||
idleAnimations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("0024_arbok/arbok", "summary_idle")
|
||||
bedrock("arbok", "summary_idle")
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -108,5 +108,5 @@ class ArbokModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame {
|
||||
override fun getFaintAnimation(
|
||||
pokemonEntity: PokemonEntity,
|
||||
state: PoseableEntityState<PokemonEntity>
|
||||
) = if (state.isPosedIn(standing, walk)) bedrockStateful("0024_arbok/arbok", "faint") else null
|
||||
) = if (state.isPosedIn(standing, walk)) bedrockStateful("arbok", "faint") else null
|
||||
}
|
||||
+3
-3
@@ -43,7 +43,7 @@ class ArcanineModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, Quad
|
||||
transformTicks = 10,
|
||||
idleAnimations = arrayOf(
|
||||
singleBoneLook()
|
||||
//bedrock("0059_arcanine/arcanine", "ground_idle")
|
||||
//bedrock("arcanine", "ground_idle")
|
||||
)
|
||||
)
|
||||
|
||||
@@ -54,7 +54,7 @@ class ArcanineModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, Quad
|
||||
idleAnimations = arrayOf(
|
||||
singleBoneLook(),
|
||||
QuadrupedWalkAnimation(this, periodMultiplier = 0.75F, amplitudeMultiplier = 1F)
|
||||
//bedrock("0059_arcanine/arcanine", "ground_walk")
|
||||
//bedrock("arcanine", "ground_walk")
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -62,5 +62,5 @@ class ArcanineModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, Quad
|
||||
// override fun getFaintAnimation(
|
||||
// pokemonEntity: PokemonEntity,
|
||||
// state: PoseableEntityState<PokemonEntity>
|
||||
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("0059_arcanine/arcanine", "faint") else null
|
||||
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("arcanine", "faint") else null
|
||||
}
|
||||
+5
-5
@@ -37,7 +37,7 @@ class ArticunoModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame {
|
||||
poseType = PoseType.STAND,
|
||||
idleAnimations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("0144_articuno/articuno", "ground_idle")
|
||||
bedrock("articuno", "ground_idle")
|
||||
)
|
||||
)
|
||||
|
||||
@@ -46,7 +46,7 @@ class ArticunoModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame {
|
||||
poseType = PoseType.WALK,
|
||||
idleAnimations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("0144_articuno/articuno", "ground_idle")
|
||||
bedrock("articuno", "ground_idle")
|
||||
)
|
||||
)
|
||||
|
||||
@@ -55,7 +55,7 @@ class ArticunoModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame {
|
||||
poseTypes = UI_POSES + PoseType.HOVER + PoseType.FLOAT,
|
||||
idleAnimations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("0144_articuno/articuno", "air_idle")
|
||||
bedrock("articuno", "air_idle")
|
||||
)
|
||||
)
|
||||
|
||||
@@ -64,7 +64,7 @@ class ArticunoModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame {
|
||||
poseTypes = setOf(PoseType.FLY, PoseType.SWIM),
|
||||
idleAnimations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("0144_articuno/articuno", "air_fly")
|
||||
bedrock("articuno", "air_fly")
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -72,5 +72,5 @@ class ArticunoModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame {
|
||||
// override fun getFaintAnimation(
|
||||
// pokemonEntity: PokemonEntity,
|
||||
// state: PoseableEntityState<PokemonEntity>
|
||||
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("0144_articuno/articuno", "faint") else null
|
||||
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("articuno", "faint") else null
|
||||
}
|
||||
+7
-7
@@ -25,11 +25,11 @@ class BeedrillModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, BiWi
|
||||
override val leftWing = getPart("wing_left")
|
||||
override val rightWing = getPart("wing_right")
|
||||
|
||||
override val portraitScale = 1.5F
|
||||
override val portraitTranslation = Vec3d(0.1, 0.2, 0.0)
|
||||
override val portraitScale = 1.9F
|
||||
override val portraitTranslation = Vec3d(0.05, 0.12, 0.0)
|
||||
|
||||
override val profileScale = 1.0F
|
||||
override val profileTranslation = Vec3d(0.0, 0.0, 0.0)
|
||||
override val profileScale = 0.9F
|
||||
override val profileTranslation = Vec3d(0.0, 0.3, 0.0)
|
||||
|
||||
lateinit var sleep: PokemonPose
|
||||
lateinit var standing: PokemonPose
|
||||
@@ -38,7 +38,7 @@ class BeedrillModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, BiWi
|
||||
override fun registerPoses() {
|
||||
sleep = registerPose(
|
||||
poseType = PoseType.SLEEP,
|
||||
idleAnimations = arrayOf(bedrock("0015_beedrill/beedrill", "sleep")),
|
||||
idleAnimations = arrayOf(bedrock("beedrill", "sleep")),
|
||||
transformedParts = arrayOf(
|
||||
rootPart.asTransformed().addPosition(Y_AXIS, -3F)
|
||||
)
|
||||
@@ -49,7 +49,7 @@ class BeedrillModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, BiWi
|
||||
poseTypes = STATIONARY_POSES,
|
||||
idleAnimations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("0015_beedrill/beedrill", "air_idle")
|
||||
bedrock("beedrill", "air_idle")
|
||||
),
|
||||
transformedParts = arrayOf(rootPart.asTransformed().addPosition(Y_AXIS, -10F))
|
||||
)
|
||||
@@ -59,7 +59,7 @@ class BeedrillModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, BiWi
|
||||
poseTypes = MOVING_POSES,
|
||||
idleAnimations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("0015_beedrill/beedrill", "air_fly")
|
||||
bedrock("beedrill", "air_fly")
|
||||
),
|
||||
transformedParts = arrayOf(rootPart.asTransformed().addPosition(Y_AXIS, -5F))
|
||||
)
|
||||
|
||||
+4
-4
@@ -36,7 +36,7 @@ class BellsproutModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame {
|
||||
transformTicks = 10,
|
||||
idleAnimations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("0069_bellsprout/bellsprout", "ground_idle")
|
||||
bedrock("bellsprout", "ground_idle")
|
||||
)
|
||||
)
|
||||
|
||||
@@ -46,8 +46,8 @@ class BellsproutModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame {
|
||||
transformTicks = 10,
|
||||
idleAnimations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("0069_bellsprout/bellsprout", "ground_idle")
|
||||
//bedrock("0069_bellsprout/bellsprout", "ground_walk")
|
||||
bedrock("bellsprout", "ground_idle")
|
||||
//bedrock("bellsprout", "ground_walk")
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -55,5 +55,5 @@ class BellsproutModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame {
|
||||
// override fun getFaintAnimation(
|
||||
// pokemonEntity: PokemonEntity,
|
||||
// state: PoseableEntityState<PokemonEntity>
|
||||
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("0069_bellsprout/bellsprout", "faint") else null
|
||||
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("bellsprout", "faint") else null
|
||||
}
|
||||
+6
-6
@@ -51,7 +51,7 @@ class BlastoiseModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, Bip
|
||||
sleep = registerPose(
|
||||
poseType = PoseType.SLEEP,
|
||||
transformTicks = 10,
|
||||
idleAnimations = arrayOf(bedrock("0009_blastoise/blastoise", "sleep"))
|
||||
idleAnimations = arrayOf(bedrock("blastoise", "sleep"))
|
||||
)
|
||||
|
||||
standing = registerPose(
|
||||
@@ -60,7 +60,7 @@ class BlastoiseModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, Bip
|
||||
transformTicks = 10,
|
||||
idleAnimations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("0009_blastoise/blastoise", "ground_idle")
|
||||
bedrock("blastoise", "ground_idle")
|
||||
)
|
||||
)
|
||||
|
||||
@@ -69,7 +69,7 @@ class BlastoiseModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, Bip
|
||||
poseTypes = setOf(PoseType.FLOAT),
|
||||
transformTicks = 10,
|
||||
idleAnimations = arrayOf(
|
||||
bedrock("0009_blastoise/blastoise", "water_idle"),
|
||||
bedrock("blastoise", "water_idle"),
|
||||
singleBoneLook()
|
||||
)
|
||||
)
|
||||
@@ -80,7 +80,7 @@ class BlastoiseModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, Bip
|
||||
transformTicks = 10,
|
||||
idleAnimations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("0009_blastoise/blastoise", "water_swim")
|
||||
bedrock("blastoise", "water_swim")
|
||||
)
|
||||
)
|
||||
|
||||
@@ -89,7 +89,7 @@ class BlastoiseModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, Bip
|
||||
transformTicks = 10,
|
||||
idleAnimations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("0009_blastoise/blastoise", "ground_walk")
|
||||
bedrock("blastoise", "ground_walk")
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -97,5 +97,5 @@ class BlastoiseModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, Bip
|
||||
override fun getFaintAnimation(
|
||||
pokemonEntity: PokemonEntity,
|
||||
state: PoseableEntityState<PokemonEntity>
|
||||
) = if (state.isPosedIn(standing, walk)) bedrockStateful("0009_blastoise/blastoise", "faint") else null
|
||||
) = if (state.isPosedIn(standing, walk)) bedrockStateful("blastoise", "faint") else null
|
||||
}
|
||||
+4
-4
@@ -38,7 +38,7 @@ class BulbasaurModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, Qua
|
||||
sleep = registerPose(
|
||||
poseType = PoseType.SLEEP,
|
||||
transformTicks = 10,
|
||||
idleAnimations = arrayOf(bedrock("0001_bulbasaur/bulbasaur", "sleep"))
|
||||
idleAnimations = arrayOf(bedrock("bulbasaur", "sleep"))
|
||||
)
|
||||
|
||||
standing = registerPose(
|
||||
@@ -47,7 +47,7 @@ class BulbasaurModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, Qua
|
||||
transformTicks = 10,
|
||||
idleAnimations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("0001_bulbasaur/bulbasaur", "ground_idle")
|
||||
bedrock("bulbasaur", "ground_idle")
|
||||
)
|
||||
)
|
||||
|
||||
@@ -57,7 +57,7 @@ class BulbasaurModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, Qua
|
||||
transformTicks = 10,
|
||||
idleAnimations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("0001_bulbasaur/bulbasaur", "ground_walk")
|
||||
bedrock("bulbasaur", "ground_walk")
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -65,5 +65,5 @@ class BulbasaurModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, Qua
|
||||
override fun getFaintAnimation(
|
||||
pokemonEntity: PokemonEntity,
|
||||
state: PoseableEntityState<PokemonEntity>
|
||||
) = if (state.isPosedIn(standing, walk)) bedrockStateful("0001_bulbasaur/bulbasaur", "faint") else null
|
||||
) = if (state.isPosedIn(standing, walk)) bedrockStateful("bulbasaur", "faint") else null
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user