forked from mirrors/cobblemon
Compare commits
236
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a7e6e638fe | ||
|
|
9ef3ea2932 | ||
|
|
38dcee3327 | ||
|
|
f81e8ba766 | ||
|
|
2f3ae9bc5e | ||
|
|
ccbe33bfe5 | ||
|
|
0989c90eb3 | ||
|
|
ddcd0ffd37 | ||
|
|
1f5d15e59d | ||
|
|
a3ff4b6b81 | ||
|
|
d2c084e4af | ||
|
|
98eda52866 | ||
|
|
c9d3cbd848 | ||
|
|
e9a2bed304 | ||
|
|
6476f61d09 | ||
|
|
74ae10b342 | ||
|
|
9e2b15e9ec | ||
|
|
d401b987ce | ||
|
|
b7ba3f62f7 | ||
|
|
78d34e0ae6 | ||
|
|
4f7630eee0 | ||
|
|
c1b5e58f8a | ||
|
|
b1904ab3fd | ||
|
|
949925ca9f | ||
|
|
7ebe0551e1 | ||
|
|
6e1d4e0c4d | ||
|
|
7aef56c610 | ||
|
|
27e1a34097 | ||
|
|
b25dc6610e | ||
|
|
fa67bba631 | ||
|
|
9d49ce086a | ||
|
|
5f8c1d5b6d | ||
|
|
e6590bef08 | ||
|
|
60b0e70651 | ||
|
|
0d9f8bbb36 | ||
|
|
bd8d9fa9e3 | ||
|
|
e75dcd63d1 | ||
|
|
a4fc1442bf | ||
|
|
fb85ceacb0 | ||
|
|
9da2e125ac | ||
|
|
7d9644ba51 | ||
|
|
39c856b69a | ||
|
|
4a4c375f66 | ||
|
|
d22df3e554 | ||
|
|
ed4dadc3f6 | ||
|
|
c2e5e39019 | ||
|
|
f383e5a52f | ||
|
|
914b7c63c9 | ||
|
|
5a17a5ed68 | ||
|
|
bb1a46950f | ||
|
|
679d3eae58 | ||
|
|
a9cd80e496 | ||
|
|
a96cc307bb | ||
|
|
f2b2a282e5 | ||
|
|
5bd7695ce8 | ||
|
|
b42387a23f | ||
|
|
6aa1e6f9ad | ||
|
|
414fcf8278 | ||
|
|
a3c26484a4 | ||
|
|
53acf7a628 | ||
|
|
fbc8883c96 | ||
|
|
235b5d062d | ||
|
|
12b92d3f35 | ||
|
|
baba3f669d | ||
|
|
2fe098adac | ||
|
|
1c770049b4 | ||
|
|
71b854f36a | ||
|
|
61b944a293 | ||
|
|
dacfb4f1ff | ||
|
|
4086ba73d3 | ||
|
|
46ed6d0492 | ||
|
|
72058bb56f | ||
|
|
a7b28ed936 | ||
|
|
96fce55688 | ||
|
|
85daf496d8 | ||
|
|
7655ddb25b | ||
|
|
7b4b498877 | ||
|
|
0ee32c7fd3 | ||
|
|
2c2c1b0cf4 | ||
|
|
218edf680b | ||
|
|
7598a0dacc | ||
|
|
7327a4ddb5 | ||
|
|
f1d3e7b12b | ||
|
|
410ea6be87 | ||
|
|
399dfc33c5 | ||
|
|
26e39bb37d | ||
|
|
4ff7df63c0 | ||
|
|
1d1f749d6d | ||
|
|
d6e4b9c1a6 | ||
|
|
15d3ee0d49 | ||
|
|
de0ed1ab41 | ||
|
|
81d930afae | ||
|
|
b83d75f30f | ||
|
|
5814c1a5d6 | ||
|
|
a45fec50a4 | ||
|
|
576b6ea767 | ||
|
|
dd6271ceed | ||
|
|
792287cb5a | ||
|
|
42ad084dbe | ||
|
|
b9bd61f3dc | ||
|
|
c6d6f98d03 | ||
|
|
abbd17faf7 | ||
|
|
c159137a70 | ||
|
|
03628631f7 | ||
|
|
e5e61df4b2 | ||
|
|
f07c4bf5b1 | ||
|
|
0e3fd520f0 | ||
|
|
935f3100d2 | ||
|
|
8b32764ce3 | ||
|
|
3e5a57ea20 | ||
|
|
6ee94aa55b | ||
|
|
05e7e1448b | ||
|
|
bd5185e69e | ||
|
|
5e8df4609b | ||
|
|
289d1474a6 | ||
|
|
e4604c0d13 | ||
|
|
d4f91fa945 | ||
|
|
5c52a9a31a | ||
|
|
db2efcb48e | ||
|
|
3bcbe2fb45 | ||
|
|
c7202cc869 | ||
|
|
269e18786b | ||
|
|
bd79a4ecfb | ||
|
|
3c3a8b1af9 | ||
|
|
11e2ed34e5 | ||
|
|
1500d6cdf1 | ||
|
|
acbbe2a1ba | ||
|
|
0fe6bc918c | ||
|
|
d399b3e29a | ||
|
|
acc6f119e1 | ||
|
|
932a2c375c | ||
|
|
1d3de659a8 | ||
|
|
9e5879edd3 | ||
|
|
4f71340ef8 | ||
|
|
b5c4863e20 | ||
|
|
a3eff4b195 | ||
|
|
142eebe9e6 | ||
|
|
36f19c9180 | ||
|
|
168e034daf | ||
|
|
827e651b22 | ||
|
|
fc34312bbb | ||
|
|
53261b3274 | ||
|
|
9c3a38657c | ||
|
|
656487c868 | ||
|
|
d491f16aff | ||
|
|
29a5b4931d | ||
|
|
42fdcc740e | ||
|
|
3bfc3ca425 | ||
|
|
82682c3710 | ||
|
|
beb8fed6bd | ||
|
|
142284a17c | ||
|
|
261850cc9f | ||
|
|
f1ea86362a | ||
|
|
d1772b0241 | ||
|
|
ec3361ad91 | ||
|
|
ca7c36ce15 | ||
|
|
f7c73728d7 | ||
|
|
1992a23edc | ||
|
|
4bb2564b80 | ||
|
|
4ab72dd0d9 | ||
|
|
7f6eb452be | ||
|
|
0afe50c883 | ||
|
|
a74499a14b | ||
|
|
e6ff24072f | ||
|
|
7693d22e58 | ||
|
|
f3544f9cdf | ||
|
|
9f7800b995 | ||
|
|
022c8ed499 | ||
|
|
dad28135cc | ||
|
|
e41d13dd53 | ||
|
|
64cae53d82 | ||
|
|
c9bf0bd8d7 | ||
|
|
97d2047aee | ||
|
|
811f8abed7 | ||
|
|
ab02a54f28 | ||
|
|
6e0c1aefcc | ||
|
|
e887b6c43c | ||
|
|
25172c2bc9 | ||
|
|
929b90173a | ||
|
|
70a65f6ffe | ||
|
|
db7d3f01d8 | ||
|
|
08565a9823 | ||
|
|
e11245f609 | ||
|
|
b3a6d8eb27 | ||
|
|
093c3683c5 | ||
|
|
2b4b9ca5dd | ||
|
|
ea70d27f87 | ||
|
|
5487b81f10 | ||
|
|
96b8aeb5b8 | ||
|
|
bf1520b1b4 | ||
|
|
0f22da7ff2 | ||
|
|
90e39874e0 | ||
|
|
2d5796de71 | ||
|
|
3b152eafac | ||
|
|
06ed354ebe | ||
|
|
caad276cbf | ||
|
|
093ad6329d | ||
|
|
94d216fd7a | ||
|
|
04c63145e1 | ||
|
|
80b8cebb19 | ||
|
|
b339081128 | ||
|
|
506e685117 | ||
|
|
eceac5fa81 | ||
|
|
a6b5c0bfab | ||
|
|
b1a0d4d5a7 | ||
|
|
627d31d0cc | ||
|
|
d9f1e3c15f | ||
|
|
eca52623e8 | ||
|
|
10740ac1c8 | ||
|
|
b9766486db | ||
|
|
bf6a923e2c | ||
|
|
a073886bc5 | ||
|
|
7c4749ecd1 | ||
|
|
76566669c6 | ||
|
|
5b8e673e53 | ||
|
|
f0a62d56a9 | ||
|
|
565a28de87 | ||
|
|
de35a54f84 | ||
|
|
2c164685f4 | ||
|
|
c3789cd620 | ||
|
|
0905b16a48 | ||
|
|
7881b14c4d | ||
|
|
49c8df2cef | ||
|
|
165b51fde6 | ||
|
|
b020f642f3 | ||
|
|
88e0bf57c8 | ||
|
|
2adb96c6bc | ||
|
|
4094dfa6de | ||
|
|
135ec86291 | ||
|
|
910a8361ec | ||
|
|
125f7d679f | ||
|
|
04abd73f35 | ||
|
|
f3ba33f7ba | ||
|
|
ed4dff66b6 | ||
|
|
0f16290c34 | ||
|
|
9725c46b30 |
@@ -1,5 +1,19 @@
|
||||
# Changelog
|
||||
|
||||
## [1.6.0 - The Bass Pro Fishing Update (Month Xth, 2024)](#1-6-0)
|
||||
#### "Now that there's a fishing mechanic, the mod is actually good!"
|
||||
|
||||
### Additions
|
||||
- Added Pokémon (and item) fishing using modified fishing rods - Poké Rods! You'll need a Poké Rod smithing template, a fishing rod, and some type of Poké Ball. Each Poké Ball makes a differently themed rod. Why not?
|
||||
- Added Lure Ball functionality, increasing the catch rate of Pokémon that were caught on a fishing rod.
|
||||
- Added property chaining support for duplicate CustomPokemonPropertyType elements.
|
||||
- Added aspect and unaspect PokemonProperty arguments (which also includes commands such as /pokemonedit, /spawnpokemon, and /givepokemon) to allow forcing or un-forcing an aspect on a Pokémon.
|
||||
|
||||
### Developer
|
||||
- SpawnCause is now an implementation of SpawningInfluence.
|
||||
- Added "forcedAspects" to Pokemon to make it easier to easily add basic aspects to a Pokémon in a way that persists. We already know that everyone is going to overuse this.
|
||||
- Made the Pokemon.aspects setter private. This could technically break sidemods but if you are affected by this then you were using it wrong! Use Pokemon.forcedAspects to fix it.
|
||||
|
||||
## [1.5.1](#1-5-1)
|
||||
|
||||
### Additions
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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;
|
||||
|
||||
import com.cobblemon.mod.common.entity.npc.NPCEntity;
|
||||
import net.minecraft.entity.ai.brain.Brain;
|
||||
import net.minecraft.entity.ai.brain.MemoryModuleType;
|
||||
import net.minecraft.entity.ai.brain.sensor.Sensor;
|
||||
import net.minecraft.entity.ai.brain.sensor.SensorType;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public class GenericsCheatClass {
|
||||
// For some reason, doing this in the NPCEntity class in Kotlin gives confusing generic errors I could not resolve.
|
||||
public static Brain.Profile<NPCEntity> createNPCBrain(Collection<MemoryModuleType<?>> memories, Collection<SensorType<? extends Sensor<? super NPCEntity>>> sensors) {
|
||||
return Brain.createProfile(memories, sensors);
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,7 @@ import com.cobblemon.mod.common.api.events.CobblemonEvents.TRADE_COMPLETED
|
||||
import com.cobblemon.mod.common.api.net.serializers.IdentifierDataSerializer
|
||||
import com.cobblemon.mod.common.api.net.serializers.PoseTypeDataSerializer
|
||||
import com.cobblemon.mod.common.api.net.serializers.StringSetDataSerializer
|
||||
import com.cobblemon.mod.common.api.net.serializers.UUIDSetDataSerializer
|
||||
import com.cobblemon.mod.common.api.net.serializers.Vec3DataSerializer
|
||||
import com.cobblemon.mod.common.api.permission.PermissionValidator
|
||||
import com.cobblemon.mod.common.api.pokeball.catching.calculators.CaptureCalculator
|
||||
@@ -49,8 +50,13 @@ import com.cobblemon.mod.common.api.scheduling.ServerRealTimeTaskTracker
|
||||
import com.cobblemon.mod.common.api.scheduling.ServerTaskTracker
|
||||
import com.cobblemon.mod.common.api.spawning.BestSpawner
|
||||
import com.cobblemon.mod.common.api.spawning.CobblemonSpawningProspector
|
||||
import com.cobblemon.mod.common.api.spawning.WorldSlice
|
||||
import com.cobblemon.mod.common.api.spawning.context.AreaContextResolver
|
||||
import com.cobblemon.mod.common.api.spawning.context.AreaSpawningContext
|
||||
import com.cobblemon.mod.common.api.spawning.context.calculators.AreaSpawningContextCalculator
|
||||
import com.cobblemon.mod.common.api.spawning.context.calculators.AreaSpawningInput
|
||||
import com.cobblemon.mod.common.api.spawning.prospecting.SpawningProspector
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.Spawner
|
||||
import com.cobblemon.mod.common.api.starter.StarterHandler
|
||||
import com.cobblemon.mod.common.api.storage.PokemonStoreManager
|
||||
import com.cobblemon.mod.common.api.storage.adapter.conversions.ReforgedConversion
|
||||
@@ -87,6 +93,7 @@ import com.cobblemon.mod.common.config.constraint.IntConstraint
|
||||
import com.cobblemon.mod.common.config.starter.StarterConfig
|
||||
import com.cobblemon.mod.common.data.CobblemonDataProvider
|
||||
import com.cobblemon.mod.common.events.AdvancementHandler
|
||||
import com.cobblemon.mod.common.events.FlowHandler
|
||||
import com.cobblemon.mod.common.events.ServerTickHandler
|
||||
import com.cobblemon.mod.common.item.PokeBallItem
|
||||
import com.cobblemon.mod.common.net.messages.client.settings.ServerSettingsPacket
|
||||
@@ -98,20 +105,16 @@ import com.cobblemon.mod.common.pokemon.aspects.SHINY_ASPECT
|
||||
import com.cobblemon.mod.common.pokemon.evolution.variants.BlockClickEvolution
|
||||
import com.cobblemon.mod.common.pokemon.feature.TagSeasonResolver
|
||||
import com.cobblemon.mod.common.pokemon.helditem.CobblemonHeldItemManager
|
||||
import com.cobblemon.mod.common.pokemon.properties.AspectPropertyType
|
||||
import com.cobblemon.mod.common.pokemon.properties.HiddenAbilityPropertyType
|
||||
import com.cobblemon.mod.common.pokemon.properties.UnaspectPropertyType
|
||||
import com.cobblemon.mod.common.pokemon.properties.UncatchableProperty
|
||||
import com.cobblemon.mod.common.pokemon.properties.tags.PokemonFlagProperty
|
||||
import com.cobblemon.mod.common.pokemon.stat.CobblemonStatProvider
|
||||
import com.cobblemon.mod.common.sherds.CobblemonSherds
|
||||
import com.cobblemon.mod.common.starter.CobblemonStarterHandler
|
||||
import com.cobblemon.mod.common.trade.TradeManager
|
||||
import com.cobblemon.mod.common.util.DataKeys
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.ifDedicatedServer
|
||||
import com.cobblemon.mod.common.util.isLaterVersion
|
||||
import com.cobblemon.mod.common.util.party
|
||||
import com.cobblemon.mod.common.util.removeAmountIf
|
||||
import com.cobblemon.mod.common.util.server
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import com.cobblemon.mod.common.world.feature.CobblemonPlacedFeatures
|
||||
import com.cobblemon.mod.common.world.feature.ore.CobblemonOrePlacedFeatures
|
||||
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules
|
||||
@@ -126,6 +129,7 @@ import net.minecraft.item.Items
|
||||
import net.minecraft.item.NameTagItem
|
||||
import net.minecraft.registry.RegistryKey
|
||||
import net.minecraft.util.WorldSavePath
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import net.minecraft.world.World
|
||||
import org.apache.logging.log4j.LogManager
|
||||
import org.apache.logging.log4j.Logger
|
||||
@@ -254,6 +258,8 @@ object Cobblemon {
|
||||
TrackedDataHandlerRegistry.register(StringSetDataSerializer)
|
||||
TrackedDataHandlerRegistry.register(PoseTypeDataSerializer)
|
||||
TrackedDataHandlerRegistry.register(IdentifierDataSerializer)
|
||||
TrackedDataHandlerRegistry.register(IdentifierDataSerializer)
|
||||
TrackedDataHandlerRegistry.register(UUIDSetDataSerializer)
|
||||
|
||||
// Lowest priority because this applies after luxury ball bonus as of gen 4
|
||||
CobblemonEvents.FRIENDSHIP_UPDATED.subscribe(Priority.LOWEST) { event ->
|
||||
@@ -291,6 +297,10 @@ object Cobblemon {
|
||||
CustomPokemonProperty.register(UncatchableProperty)
|
||||
CustomPokemonProperty.register(PokemonFlagProperty)
|
||||
CustomPokemonProperty.register(HiddenAbilityPropertyType)
|
||||
CustomPokemonProperty.register(AspectPropertyType)
|
||||
CustomPokemonProperty.register(UnaspectPropertyType)
|
||||
|
||||
FlowHandler.setup()
|
||||
|
||||
ifDedicatedServer {
|
||||
isDedicatedServer = true
|
||||
|
||||
@@ -13,6 +13,7 @@ import net.minecraft.entity.ai.brain.Activity
|
||||
object CobblemonActivities {
|
||||
val activities = mutableListOf<Activity>()
|
||||
val BATTLING_ACTIVITY = Activity("pokemon_battling")
|
||||
val NPC_BATTLING = Activity("npc_battling")
|
||||
|
||||
fun register(activity: Activity): Activity {
|
||||
activities.add(activity)
|
||||
|
||||
@@ -48,6 +48,7 @@ object CobblemonCommands {
|
||||
PokemonRestartCommand.register(dispatcher)
|
||||
BedrockParticleCommand.register(dispatcher)
|
||||
OpenDialogueCommand.register(dispatcher)
|
||||
NPCEditCommand.register(dispatcher)
|
||||
|
||||
// Possibly lock down registration if and only if under dev environment or running in an environment
|
||||
// with a certain system environment variable set
|
||||
|
||||
@@ -11,6 +11,8 @@ package com.cobblemon.mod.common
|
||||
import com.cobblemon.mod.common.api.pokeball.PokeBalls
|
||||
import com.cobblemon.mod.common.entity.boat.CobblemonBoatEntity
|
||||
import com.cobblemon.mod.common.entity.boat.CobblemonChestBoatEntity
|
||||
import com.cobblemon.mod.common.entity.fishing.PokeRodFishingBobberEntity
|
||||
import com.cobblemon.mod.common.entity.npc.NPCEntity
|
||||
import com.cobblemon.mod.common.entity.generic.GenericBedrockEntity
|
||||
import com.cobblemon.mod.common.entity.pokeball.EmptyPokeBallEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
@@ -66,6 +68,15 @@ object CobblemonEntities : PlatformRegistry<Registry<EntityType<*>>, RegistryKey
|
||||
.build(CHEST_BOAT_KEY.toString())
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val POKE_BOBBER_KEY = cobblemonResource("poke_bobber")
|
||||
@JvmField
|
||||
val POKE_BOBBER: EntityType<PokeRodFishingBobberEntity> = this.create(
|
||||
POKE_BOBBER_KEY.path,
|
||||
EntityType.Builder.create(::PokeRodFishingBobberEntity, SpawnGroup.MISC).setDimensions(0.5F, 0.5F).maxTrackingRange(10)
|
||||
.build(POKE_BOBBER_KEY.toString())
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val GENERIC_BEDROCK_ENTITY_KEY = cobblemonResource("generic_bedrock")
|
||||
@JvmField
|
||||
@@ -75,8 +86,16 @@ object CobblemonEntities : PlatformRegistry<Registry<EntityType<*>>, RegistryKey
|
||||
.build(GENERIC_BEDROCK_ENTITY_KEY.toString())
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val NPC_KEY = cobblemonResource("npc")
|
||||
@JvmField
|
||||
val NPC: EntityType<NPCEntity> = create(
|
||||
NPC_KEY.path,
|
||||
EntityType.Builder.create({ _, world -> NPCEntity(world) }, SpawnGroup.CREATURE).build("$NPC_KEY")
|
||||
)
|
||||
|
||||
fun registerAttributes(consumer: (EntityType<out LivingEntity>, DefaultAttributeContainer.Builder) -> Unit) {
|
||||
consumer(POKEMON, PokemonEntity.createAttributes())
|
||||
consumer(NPC, NPCEntity.createAttributes())
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.bedrockk.molang.runtime.value.MoValue
|
||||
import com.cobblemon.mod.common.api.data.DataRegistry
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.api.scripting.CobblemonScripts
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.endsWith
|
||||
import java.util.concurrent.ExecutionException
|
||||
import net.minecraft.resource.ResourceManager
|
||||
import net.minecraft.resource.ResourceType
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
/**
|
||||
* Holds all the flows that are loaded from the server's data packs. A flow is foldered under the event identifier,
|
||||
* which can be cobblemon's namespace but can also be minecraft or any other namespace someone has added hooks for.
|
||||
* The value of the map is a list of MoLang scripts that will execute when that event occurs.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since February 24th, 2024
|
||||
*/
|
||||
object CobblemonFlows : DataRegistry {
|
||||
override val id = cobblemonResource("flows")
|
||||
override val observable = SimpleObservable<CobblemonFlows>()
|
||||
override val type = ResourceType.SERVER_DATA
|
||||
override fun sync(player: ServerPlayerEntity) {}
|
||||
|
||||
val runtime by lazy { MoLangRuntime().setup() }
|
||||
|
||||
val clientFlows = hashMapOf<Identifier, MutableList<ExpressionLike>>()
|
||||
val flows = hashMapOf<Identifier, MutableList<ExpressionLike>>()
|
||||
|
||||
override fun reload(manager: ResourceManager) {
|
||||
val folderBeforeNameRegex = ".*\\/([^\\/]+)\\/[^\\/]+\$".toRegex()
|
||||
manager.findResources("flows") { path -> path.endsWith(CobblemonScripts.MOLANG_EXTENSION) }.forEach { (identifier, resource) ->
|
||||
resource.inputStream.use { stream ->
|
||||
stream.bufferedReader().use { reader ->
|
||||
try {
|
||||
val expression = reader.readText().asExpressionLike()
|
||||
val event = folderBeforeNameRegex.find(identifier.path)?.groupValues?.get(1)
|
||||
?: throw IllegalArgumentException("Invalid flow path: $identifier. Should have a folder structure that includes the name of the event being flowed.")
|
||||
if (identifier.path.startsWith("flows/client/")) {
|
||||
clientFlows.getOrPut(Identifier(identifier.namespace, event)) { mutableListOf() }.add(expression)
|
||||
} else {
|
||||
flows.getOrPut(Identifier(identifier.namespace, event)) { mutableListOf() }.add(expression)
|
||||
}
|
||||
} catch (exception: Exception) {
|
||||
throw ExecutionException("Error loading MoLang script for flow: $identifier", exception)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Cobblemon.LOGGER.info("Loaded ${CobblemonScripts.scripts.size} flows and ${CobblemonScripts.clientScripts.size} client flows")
|
||||
observable.emit(this)
|
||||
}
|
||||
|
||||
fun run(eventIdentifier: Identifier, context: Map<String, MoValue>) {
|
||||
flows[eventIdentifier]?.forEach { it.resolve(runtime, context) }
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,8 @@ import com.cobblemon.mod.common.api.pokeball.PokeBalls
|
||||
import com.cobblemon.mod.common.api.pokemon.Natures
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||
import com.cobblemon.mod.common.api.pokemon.status.Statuses
|
||||
import com.cobblemon.mod.common.api.text.blue
|
||||
import com.cobblemon.mod.common.api.text.gray
|
||||
import com.cobblemon.mod.common.block.BerryBlock
|
||||
import com.cobblemon.mod.common.block.MintBlock
|
||||
import com.cobblemon.mod.common.block.MintBlock.MintType
|
||||
@@ -45,6 +47,7 @@ import net.minecraft.registry.Registries
|
||||
import net.minecraft.registry.Registry
|
||||
import net.minecraft.registry.RegistryKey
|
||||
import net.minecraft.registry.RegistryKeys
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.world.World
|
||||
|
||||
@@ -932,12 +935,121 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
|
||||
@JvmField
|
||||
val BLACK_TUMBLESTONE_BLOCK = blockItem("black_tumblestone_block", CobblemonBlocks.BLACK_TUMBLESTONE_BLOCK)
|
||||
|
||||
@JvmField
|
||||
val POKEROD_SMITHING_TEMPLATE = create("pokerod_smithing_template", SmithingTemplateItem(
|
||||
Text.translatable("item.minecraft.fishing_rod").blue(),
|
||||
Text.translatable("item.cobblemon.smithing_template.pokerod.ingredients").blue(),
|
||||
Text.translatable("upgrade.cobblemon.pokerod").gray(),
|
||||
Text.translatable("item.cobblemon.smithing_template.pokerod.base_slot_description"),
|
||||
Text.translatable("item.cobblemon.smithing_template.pokerod.additions_slot_description"),
|
||||
listOf(cobblemonResource("item/empty_slot_fishing_rod")),
|
||||
listOf(cobblemonResource("item/empty_slot_pokeball"))
|
||||
))
|
||||
|
||||
@JvmField
|
||||
val AUTOMATON_ARMOR_TRIM_SMITHING_TEMPLATE: SmithingTemplateItem = this.create(
|
||||
"automaton_armor_trim_smithing_template",
|
||||
SmithingTemplateItem.of(CobblemonArmorTrims.AUTOMATON)
|
||||
)
|
||||
|
||||
val pokeRods = mutableListOf<PokerodItem>()
|
||||
@JvmField
|
||||
val POKE_ROD = pokerodItem(cobblemonResource("poke_rod"))
|
||||
@JvmField
|
||||
val CITRINE_ROD = pokerodItem(cobblemonResource("citrine_rod"))
|
||||
@JvmField
|
||||
val VERDANT_ROD = pokerodItem(cobblemonResource("verdant_rod"))
|
||||
@JvmField
|
||||
val AZURE_ROD = pokerodItem(cobblemonResource("azure_rod"))
|
||||
@JvmField
|
||||
val ROSEATE_ROD = pokerodItem(cobblemonResource("roseate_rod"))
|
||||
@JvmField
|
||||
val SLATE_ROD = pokerodItem(cobblemonResource("slate_rod"))
|
||||
@JvmField
|
||||
val PREMIER_ROD = pokerodItem(cobblemonResource("premier_rod"))
|
||||
@JvmField
|
||||
val GREAT_ROD = pokerodItem(cobblemonResource("great_rod"))
|
||||
@JvmField
|
||||
val ULTRA_ROD = pokerodItem(cobblemonResource("ultra_rod"))
|
||||
@JvmField
|
||||
val SAFARI_ROD = pokerodItem(cobblemonResource("safari_rod"))
|
||||
@JvmField
|
||||
val FAST_ROD = pokerodItem(cobblemonResource("fast_rod"))
|
||||
@JvmField
|
||||
val LEVEL_ROD = pokerodItem(cobblemonResource("level_rod"))
|
||||
@JvmField
|
||||
val LURE_ROD = pokerodItem(cobblemonResource("lure_rod"))
|
||||
@JvmField
|
||||
val HEAVY_ROD = pokerodItem(cobblemonResource("heavy_rod"))
|
||||
@JvmField
|
||||
val LOVE_ROD = pokerodItem(cobblemonResource("love_rod"))
|
||||
@JvmField
|
||||
val FRIEND_ROD = pokerodItem(cobblemonResource("friend_rod"))
|
||||
@JvmField
|
||||
val MOON_ROD = pokerodItem(cobblemonResource("moon_rod"))
|
||||
@JvmField
|
||||
val SPORT_ROD = pokerodItem(cobblemonResource("sport_rod"))
|
||||
@JvmField
|
||||
val PARK_ROD = pokerodItem(cobblemonResource("park_rod"))
|
||||
@JvmField
|
||||
val NET_ROD = pokerodItem(cobblemonResource("net_rod"))
|
||||
@JvmField
|
||||
val DIVE_ROD = pokerodItem(cobblemonResource("dive_rod"))
|
||||
@JvmField
|
||||
val NEST_ROD = pokerodItem(cobblemonResource("nest_rod"))
|
||||
@JvmField
|
||||
val REPEAT_ROD = pokerodItem(cobblemonResource("repeat_rod"))
|
||||
@JvmField
|
||||
val TIMER_ROD = pokerodItem(cobblemonResource("timer_rod"))
|
||||
@JvmField
|
||||
val LUXURY_ROD = pokerodItem(cobblemonResource("luxury_rod"))
|
||||
@JvmField
|
||||
val DUSK_ROD = pokerodItem(cobblemonResource("dusk_rod"))
|
||||
@JvmField
|
||||
val HEAL_ROD = pokerodItem(cobblemonResource("heal_rod"))
|
||||
@JvmField
|
||||
val QUICK_ROD = pokerodItem(cobblemonResource("quick_rod"))
|
||||
@JvmField
|
||||
val DREAM_ROD = pokerodItem(cobblemonResource("dream_rod"))
|
||||
@JvmField
|
||||
val BEAST_ROD = pokerodItem(cobblemonResource("beast_rod"))
|
||||
@JvmField
|
||||
val MASTER_ROD = pokerodItem(cobblemonResource("master_rod"))
|
||||
@JvmField
|
||||
val CHERISH_ROD = pokerodItem(cobblemonResource("cherish_rod"))
|
||||
@JvmField
|
||||
val ANCIENT_POKE_ROD = pokerodItem(cobblemonResource("ancient_poke_rod"))
|
||||
@JvmField
|
||||
val ANCIENT_CITRINE_ROD = pokerodItem(cobblemonResource("ancient_citrine_rod"))
|
||||
@JvmField
|
||||
val ANCIENT_VERDANT_ROD = pokerodItem(cobblemonResource("ancient_verdant_rod"))
|
||||
@JvmField
|
||||
val ANCIENT_AZURE_ROD = pokerodItem(cobblemonResource("ancient_azure_rod"))
|
||||
@JvmField
|
||||
val ANCIENT_ROSEATE_ROD = pokerodItem(cobblemonResource("ancient_roseate_rod"))
|
||||
@JvmField
|
||||
val ANCIENT_SLATE_ROD = pokerodItem(cobblemonResource("ancient_slate_rod"))
|
||||
@JvmField
|
||||
val ANCIENT_IVORY_ROD = pokerodItem(cobblemonResource("ancient_ivory_rod"))
|
||||
@JvmField
|
||||
val ANCIENT_GREAT_ROD = pokerodItem(cobblemonResource("ancient_great_rod"))
|
||||
@JvmField
|
||||
val ANCIENT_ULTRA_ROD = pokerodItem(cobblemonResource("ancient_ultra_rod"))
|
||||
@JvmField
|
||||
val ANCIENT_FEATHER_ROD = pokerodItem(cobblemonResource("ancient_feather_rod"))
|
||||
@JvmField
|
||||
val ANCIENT_WING_ROD = pokerodItem(cobblemonResource("ancient_wing_rod"))
|
||||
@JvmField
|
||||
val ANCIENT_JET_ROD = pokerodItem(cobblemonResource("ancient_jet_rod"))
|
||||
@JvmField
|
||||
val ANCIENT_HEAVY_ROD = pokerodItem(cobblemonResource("ancient_heavy_rod"))
|
||||
@JvmField
|
||||
val ANCIENT_LEADEN_ROD = pokerodItem(cobblemonResource("ancient_leaden_rod"))
|
||||
@JvmField
|
||||
val ANCIENT_GIGATON_ROD = pokerodItem(cobblemonResource("ancient_gigaton_rod"))
|
||||
@JvmField
|
||||
val ANCIENT_ORIGIN_ROD = pokerodItem(cobblemonResource("ancient_origin_rod"))
|
||||
|
||||
// Misc
|
||||
@JvmField
|
||||
val POKEMON_MODEL = this.create("pokemon_model", PokemonItem())
|
||||
@@ -1003,6 +1115,13 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
|
||||
|
||||
private fun candyItem(name: String, calculator: CandyItem.Calculator): CandyItem = this.create(name, CandyItem(calculator))
|
||||
|
||||
private fun pokerodItem(pokeRodId: Identifier): PokerodItem {
|
||||
val settings = Item.Settings().maxCount(1).maxDamage(Items.FISHING_ROD.maxDamage)
|
||||
val item = create(pokeRodId.path, PokerodItem(pokeRodId, settings))
|
||||
pokeRods.add(item)
|
||||
return item
|
||||
}
|
||||
|
||||
private fun heldItem(name: String, remappedName: String? = null): CobblemonItem = create(
|
||||
name,
|
||||
CobblemonItem(Item.Settings()).also {
|
||||
|
||||
@@ -10,11 +10,13 @@ package com.cobblemon.mod.common
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.api.data.DataRegistry
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.mechanics.BerriesMechanic
|
||||
import com.cobblemon.mod.common.mechanics.PotionsMechanic
|
||||
import com.cobblemon.mod.common.mechanics.RemediesMechanic
|
||||
import com.cobblemon.mod.common.util.adapters.ExpressionAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.ExpressionLikeAdapter
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.google.gson.GsonBuilder
|
||||
import net.minecraft.resource.ResourceManager
|
||||
@@ -29,6 +31,7 @@ object CobblemonMechanics : DataRegistry {
|
||||
val gson = GsonBuilder()
|
||||
.setPrettyPrinting()
|
||||
.registerTypeAdapter(Expression::class.java, ExpressionAdapter)
|
||||
.registerTypeAdapter(ExpressionLike::class.java, ExpressionLikeAdapter)
|
||||
.create()
|
||||
|
||||
var remedies = RemediesMechanic()
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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
|
||||
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.codecs.ListCodec
|
||||
import com.mojang.serialization.codecs.PrimitiveCodec
|
||||
import java.util.Optional
|
||||
import net.minecraft.entity.ai.brain.MemoryModuleType
|
||||
import net.minecraft.util.Uuids
|
||||
|
||||
object CobblemonMemories {
|
||||
val memories = mutableMapOf<String, MemoryModuleType<*>>()
|
||||
|
||||
val BATTLING_POKEMON = register("battling_pokemon", ListCodec(Uuids.INT_STREAM_CODEC))
|
||||
val NPC_BATTLING = register("npc_battling", PrimitiveCodec.BOOL)
|
||||
|
||||
fun <U> register(id: String, codec: Codec<U>): MemoryModuleType<U> {
|
||||
val memoryModule = MemoryModuleType(Optional.of(codec))
|
||||
memories[id] = memoryModule
|
||||
return memoryModule
|
||||
}
|
||||
|
||||
fun <U> register(id: String): MemoryModuleType<U> {
|
||||
val memoryModule = MemoryModuleType<U>(Optional.empty())
|
||||
memories[id] = memoryModule
|
||||
return memoryModule
|
||||
}
|
||||
}
|
||||
@@ -20,13 +20,15 @@ import com.cobblemon.mod.common.client.net.callback.party.OpenPartyCallbackHandl
|
||||
import com.cobblemon.mod.common.client.net.callback.partymove.OpenPartyMoveCallbackHandler
|
||||
import com.cobblemon.mod.common.client.net.data.DataRegistrySyncPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.data.UnlockReloadPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.effect.RunPosableMoLangHandler
|
||||
import com.cobblemon.mod.common.client.net.dialogue.DialogueClosedHandler
|
||||
import com.cobblemon.mod.common.client.net.dialogue.DialogueOpenedHandler
|
||||
import com.cobblemon.mod.common.client.net.effect.RunPosableMoLangHandler
|
||||
import com.cobblemon.mod.common.client.net.effect.SpawnSnowstormEntityParticleHandler
|
||||
import com.cobblemon.mod.common.client.net.effect.SpawnSnowstormParticleHandler
|
||||
import com.cobblemon.mod.common.client.net.gui.InteractPokemonUIPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.gui.SummaryUIPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.npc.CloseNPCEditorHandler
|
||||
import com.cobblemon.mod.common.client.net.npc.OpenNPCEditorHandler
|
||||
import com.cobblemon.mod.common.client.net.pasture.ClosePastureHandler
|
||||
import com.cobblemon.mod.common.client.net.pasture.OpenPastureHandler
|
||||
import com.cobblemon.mod.common.client.net.pasture.PokemonPasturedHandler
|
||||
@@ -64,13 +66,16 @@ import com.cobblemon.mod.common.net.messages.client.callback.OpenPartyCallbackPa
|
||||
import com.cobblemon.mod.common.net.messages.client.callback.OpenPartyMoveCallbackPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.AbilityRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.BerryRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.FlowRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.GlobalSpeciesFeatureSyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.MovesRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.NPCRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.PropertiesCompletionRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.SpeciesFeatureAssignmentSyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.SpeciesRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.StandardSpeciesFeatureSyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.UnlockReloadPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.*
|
||||
import com.cobblemon.mod.common.net.messages.client.dialogue.DialogueClosedPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.dialogue.DialogueOpenedPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.RunPosableMoLangPacket
|
||||
@@ -78,6 +83,8 @@ import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormEntityP
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormParticlePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.fossil.FossilRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.fossil.NaturalMaterialRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.npc.CloseNPCEditorPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.npc.OpenNPCEditorPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pasture.ClosePasturePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pasture.OpenPasturePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pasture.PokemonPasturedPacket
|
||||
@@ -115,7 +122,12 @@ import com.cobblemon.mod.common.net.messages.client.trade.TradeStartedPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.trade.TradeUpdatedPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.ui.InteractPokemonUIPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.ui.SummaryUIPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.*
|
||||
import com.cobblemon.mod.common.net.messages.server.BattleChallengePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.BenchMovePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.RequestMoveSwapPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.RequestPlayerInteractionsPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.SelectStarterPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.SendOutPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.battle.BattleSelectActionsPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.battle.RemoveSpectatorPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.battle.SpectateBattlePacket
|
||||
@@ -127,6 +139,7 @@ import com.cobblemon.mod.common.net.messages.server.callback.partymove.PartyMove
|
||||
import com.cobblemon.mod.common.net.messages.server.callback.partymove.PartyPokemonMoveSelectedPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.dialogue.EscapeDialoguePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.dialogue.InputToDialoguePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.npc.SaveNPCPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pasture.PasturePokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pasture.UnpastureAllPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pasture.UnpasturePokemonPacket
|
||||
@@ -163,6 +176,7 @@ import com.cobblemon.mod.common.net.serverhandling.callback.partymove.PartyPokem
|
||||
import com.cobblemon.mod.common.net.serverhandling.dialogue.EscapeDialogueHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.dialogue.InputToDialogueHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.evolution.AcceptEvolutionHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.npc.SaveNPCHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pasture.PasturePokemonHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pasture.UnpastureAllPokemonHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pasture.UnpasturePokemonHandler
|
||||
@@ -189,12 +203,12 @@ import com.cobblemon.mod.common.net.serverhandling.trade.ChangeTradeAcceptanceHa
|
||||
import com.cobblemon.mod.common.net.serverhandling.trade.OfferTradeHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.trade.UpdateTradeOfferHandler
|
||||
import com.cobblemon.mod.common.util.server
|
||||
import kotlin.reflect.KClass
|
||||
import net.minecraft.network.PacketByteBuf
|
||||
import net.minecraft.network.listener.ClientPlayPacketListener
|
||||
import net.minecraft.network.packet.Packet
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.util.Identifier
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
/**
|
||||
* Registers Cobblemon network packets.
|
||||
@@ -300,6 +314,7 @@ object CobblemonNetwork : NetworkManager {
|
||||
this.createClientBound(MovesRegistrySyncPacket.ID, MovesRegistrySyncPacket::decode, DataRegistrySyncPacketHandler())
|
||||
this.createClientBound(SpeciesRegistrySyncPacket.ID, SpeciesRegistrySyncPacket::decode, DataRegistrySyncPacketHandler())
|
||||
this.createClientBound(PropertiesCompletionRegistrySyncPacket.ID, PropertiesCompletionRegistrySyncPacket::decode, DataRegistrySyncPacketHandler())
|
||||
this.createClientBound(NPCRegistrySyncPacket.ID, NPCRegistrySyncPacket::decode, DataRegistrySyncPacketHandler())
|
||||
this.createClientBound(UnlockReloadPacket.ID, UnlockReloadPacket::decode, UnlockReloadPacketHandler)
|
||||
this.createClientBound(BerryRegistrySyncPacket.ID, BerryRegistrySyncPacket::decode, DataRegistrySyncPacketHandler())
|
||||
this.createClientBound(StandardSpeciesFeatureSyncPacket.ID, StandardSpeciesFeatureSyncPacket::decode, DataRegistrySyncPacketHandler())
|
||||
@@ -307,6 +322,8 @@ object CobblemonNetwork : NetworkManager {
|
||||
this.createClientBound(SpeciesFeatureAssignmentSyncPacket.ID, SpeciesFeatureAssignmentSyncPacket::decode, DataRegistrySyncPacketHandler())
|
||||
this.createClientBound(NaturalMaterialRegistrySyncPacket.ID, NaturalMaterialRegistrySyncPacket::decode, DataRegistrySyncPacketHandler())
|
||||
this.createClientBound(FossilRegistrySyncPacket.ID, FossilRegistrySyncPacket::decode, DataRegistrySyncPacketHandler())
|
||||
this.createClientBound(PokeRodRegistrySyncPacket.ID, PokeRodRegistrySyncPacket::decode, DataRegistrySyncPacketHandler())
|
||||
this.createClientBound(FlowRegistrySyncPacket.ID, FlowRegistrySyncPacket::decode, DataRegistrySyncPacketHandler())
|
||||
|
||||
// Effects
|
||||
this.createClientBound(SpawnSnowstormParticlePacket.ID, SpawnSnowstormParticlePacket::decode, SpawnSnowstormParticleHandler)
|
||||
@@ -350,6 +367,10 @@ object CobblemonNetwork : NetworkManager {
|
||||
// Dialogue packets
|
||||
this.createClientBound(DialogueClosedPacket.ID, DialogueClosedPacket::decode, DialogueClosedHandler)
|
||||
this.createClientBound(DialogueOpenedPacket.ID, DialogueOpenedPacket::decode, DialogueOpenedHandler)
|
||||
|
||||
// NPCs
|
||||
this.createClientBound(CloseNPCEditorPacket.ID, CloseNPCEditorPacket::decode, CloseNPCEditorHandler)
|
||||
this.createClientBound(OpenNPCEditorPacket.ID, OpenNPCEditorPacket::decode, OpenNPCEditorHandler)
|
||||
}
|
||||
|
||||
override fun registerServerBound() {
|
||||
@@ -419,6 +440,9 @@ object CobblemonNetwork : NetworkManager {
|
||||
// Dialogue packets
|
||||
this.createServerBound(EscapeDialoguePacket.ID, EscapeDialoguePacket::decode, EscapeDialogueHandler)
|
||||
this.createServerBound(InputToDialoguePacket.ID, InputToDialoguePacket::decode, InputToDialogueHandler)
|
||||
|
||||
// NPC packets
|
||||
this.createServerBound(SaveNPCPacket.ID, SaveNPCPacket::decode, SaveNPCHandler)
|
||||
}
|
||||
|
||||
private inline fun <reified T : NetworkPacket<T>> createClientBound(identifier: Identifier, noinline decoder: (PacketByteBuf) -> T, handler: ClientNetworkPacketHandler<T>) {
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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
|
||||
|
||||
import com.cobblemon.mod.common.entity.sensor.BattlingPokemonSensor
|
||||
import com.cobblemon.mod.common.entity.sensor.NPCBattlingSensor
|
||||
import java.util.function.Supplier
|
||||
import net.minecraft.entity.Entity
|
||||
import net.minecraft.entity.ai.brain.sensor.Sensor
|
||||
import net.minecraft.entity.ai.brain.sensor.SensorType
|
||||
|
||||
object CobblemonSensors {
|
||||
val sensors = mutableMapOf<String, SensorType<*>>()
|
||||
|
||||
val NPC_BATTLING = register("npc_battling", ::NPCBattlingSensor)
|
||||
val BATTLING_POKEMON = register("battling_pokemon", ::BattlingPokemonSensor)
|
||||
|
||||
fun <E : Entity, U : Sensor<E>> register(id: String, supplier: Supplier<U>): SensorType<U> {
|
||||
val sensor = SensorType(supplier)
|
||||
sensors[id] = sensor
|
||||
return sensor
|
||||
}
|
||||
}
|
||||
@@ -134,6 +134,14 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, RegistryKey<Regi
|
||||
@JvmField
|
||||
val RELIC_COIN_POUCH_PLACE = this.create("relic_coin_pouch.place")
|
||||
|
||||
@JvmField
|
||||
val FISHING_NOTIFICATION = this.create("fishing.notification")
|
||||
@JvmField
|
||||
val FISHING_SPLASH_BIG = this.create("fishing.splash_big")
|
||||
@JvmField
|
||||
val FISHING_SPLASH_SMALL = this.create("fishing.splash_small")
|
||||
@JvmField
|
||||
val FISHING_BOBBER_LAND = this.create("fishing.bobber_land")
|
||||
@JvmField
|
||||
val TUMBLESTONE_BREAK = this.create("tumblestone.break")
|
||||
@JvmField
|
||||
|
||||
@@ -32,7 +32,14 @@ object CobblemonTradeOffers {
|
||||
* @return The resulting list.
|
||||
*/
|
||||
fun tradeOffersFor(profession: VillagerProfession): List<VillagerTradeOffer> = when (profession) {
|
||||
VillagerProfession.FARMER -> listOf(VillagerTradeOffer(VillagerProfession.FARMER, 3, listOf(TradeOffers.SellItemFactory(CobblemonItems.VIVICHOKE_SEEDS, 24, 1, 1, 6))))
|
||||
VillagerProfession.FARMER -> listOf(
|
||||
VillagerTradeOffer(VillagerProfession.FARMER, 3, listOf(TradeOffers.SellItemFactory(CobblemonItems.VIVICHOKE_SEEDS, 24, 1, 1, 6)))
|
||||
)
|
||||
VillagerProfession.FISHERMAN -> listOf(
|
||||
VillagerTradeOffer(VillagerProfession.FISHERMAN, 5, listOf(
|
||||
TradeOffers.SellItemFactory(CobblemonItems.POKEROD_SMITHING_TEMPLATE, 12, 3, 30)
|
||||
))
|
||||
)
|
||||
else -> emptyList()
|
||||
}
|
||||
|
||||
|
||||
@@ -113,6 +113,13 @@ object CobblemonCriteria {
|
||||
)
|
||||
)
|
||||
|
||||
val CAST_POKE_ROD = this.create(
|
||||
SimpleCriterionTrigger(
|
||||
cobblemonResource("cast_poke_rod"),
|
||||
CastPokeRodCriterionCondition::class.java
|
||||
)
|
||||
)
|
||||
|
||||
// Advancement criteria for [grow_tumblestone.json]
|
||||
val PLANT_TUMBLESTONE = this.create(
|
||||
SimpleCriterionTrigger(
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.advancement.criterion
|
||||
|
||||
import com.google.gson.JsonObject
|
||||
import net.minecraft.predicate.entity.LootContextPredicate
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
class CastPokeRodCriterionCondition(id: Identifier, predicate: LootContextPredicate): SimpleCriterionCondition<Boolean>(id, predicate) {
|
||||
var hasBait: Boolean = false
|
||||
|
||||
override fun toJson(json: JsonObject) {
|
||||
json.addProperty("hasBait", hasBait)
|
||||
}
|
||||
|
||||
override fun fromJson(json: JsonObject) {
|
||||
hasBait = json.get("hasBait").asBoolean
|
||||
}
|
||||
|
||||
override fun matches(player: ServerPlayerEntity, context: Boolean): Boolean {
|
||||
return hasBait == context
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.battles.model
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
@@ -20,6 +21,8 @@ import com.cobblemon.mod.common.api.battles.model.actor.EntityBackedBattleActor
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.FleeableBattleActor
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents
|
||||
import com.cobblemon.mod.common.api.events.battles.BattleFledEvent
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.getQueryStruct
|
||||
import com.cobblemon.mod.common.api.net.NetworkPacket
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonItemTags
|
||||
import com.cobblemon.mod.common.api.text.red
|
||||
@@ -46,8 +49,10 @@ import com.cobblemon.mod.common.pokemon.evolution.progress.LastBattleCriticalHit
|
||||
import com.cobblemon.mod.common.pokemon.evolution.requirements.DefeatRequirement
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
import com.cobblemon.mod.common.util.getPlayer
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import java.io.File
|
||||
import java.util.UUID
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.text.Text
|
||||
import java.util.concurrent.ConcurrentLinkedDeque
|
||||
@@ -66,6 +71,10 @@ open class PokemonBattle(
|
||||
) {
|
||||
/** Whether logging will be silenced for this battle. */
|
||||
var mute = true
|
||||
val struct = this.asMoLangValue()
|
||||
val runtime = MoLangRuntime().also { it.environment.structs["query"] = struct }
|
||||
|
||||
val onEndHandlers: MutableList<(PokemonBattle) -> Unit> = mutableListOf()
|
||||
|
||||
init {
|
||||
side1.battle = this
|
||||
@@ -97,6 +106,8 @@ open class PokemonBattle(
|
||||
val battleLog = mutableListOf<String>()
|
||||
val chatLog = mutableListOf<Text>()
|
||||
var started = false
|
||||
var winners = listOf<BattleActor>()
|
||||
var losers = listOf<BattleActor>()
|
||||
var ended = false
|
||||
// TEMP battle showcase stuff
|
||||
var announcingRules = false
|
||||
@@ -266,6 +277,7 @@ open class PokemonBattle(
|
||||
}
|
||||
sendUpdate(BattleEndPacket())
|
||||
BattleRegistry.closeBattle(this)
|
||||
onEndHandlers.forEach { it(this) }
|
||||
}
|
||||
|
||||
fun finishCaptureAction(captureAction: BattleCaptureAction) {
|
||||
@@ -353,6 +365,14 @@ open class PokemonBattle(
|
||||
}
|
||||
}
|
||||
|
||||
fun dispatchFuture(future: () -> CompletableFuture<*>) {
|
||||
val dispatch = BattleDispatch {
|
||||
val generatedFuture = future()
|
||||
return@BattleDispatch DispatchResult { generatedFuture.isDone }
|
||||
}
|
||||
dispatches.add(dispatch)
|
||||
}
|
||||
|
||||
fun dispatchInsert(dispatcher: () -> Iterable<BattleDispatch>) {
|
||||
dispatch {
|
||||
val newDispatches = dispatcher()
|
||||
|
||||
@@ -145,4 +145,7 @@ abstract class BattleActor(
|
||||
}
|
||||
open fun awardExperience(battlePokemon: BattlePokemon, experience: Int) {}
|
||||
open fun sendUpdate(packet: NetworkPacket<*>) {}
|
||||
|
||||
open fun win(otherWinners: List<BattleActor>, losers: List<BattleActor>) {}
|
||||
open fun lose(winners: List<BattleActor>, otherLosers: List<BattleActor>) {}
|
||||
}
|
||||
@@ -27,10 +27,13 @@ object DialogueManager {
|
||||
val activeDialogues = mutableMapOf<UUID, ActiveDialogue>()
|
||||
|
||||
fun startDialogue(playerEntity: ServerPlayerEntity, dialogue: Dialogue) {
|
||||
val activeDialogue = ActiveDialogue(playerEntity, dialogue)
|
||||
activeDialogues[playerEntity.uuid] = activeDialogue
|
||||
val packet = DialogueOpenedPacket(activeDialogue, includeFaces = true)
|
||||
playerEntity.sendPacket(packet)
|
||||
startDialogue(ActiveDialogue(playerEntity, dialogue))
|
||||
}
|
||||
|
||||
fun startDialogue(activeDialogue: ActiveDialogue) {
|
||||
activeDialogues[activeDialogue.playerEntity.uuid] = activeDialogue
|
||||
val packet = DialogueOpenedPacket(activeDialogue, true)
|
||||
activeDialogue.playerEntity.sendPacket(packet)
|
||||
}
|
||||
|
||||
fun stopDialogue(playerEntity: ServerPlayerEntity) {
|
||||
|
||||
@@ -12,6 +12,7 @@ import com.google.gson.JsonDeserializationContext
|
||||
import com.google.gson.JsonDeserializer
|
||||
import com.google.gson.JsonElement
|
||||
import com.google.gson.JsonObject
|
||||
import com.google.gson.JsonPrimitive
|
||||
import com.google.gson.JsonSerializationContext
|
||||
import com.google.gson.JsonSerializer
|
||||
import java.lang.reflect.Type
|
||||
@@ -28,6 +29,10 @@ object EntityDimensionsAdapter : JsonSerializer<EntityDimensions>, JsonDeseriali
|
||||
const val WIDTH = "width"
|
||||
const val HEIGHT = "height"
|
||||
|
||||
val templates = mutableMapOf(
|
||||
"player" to { EntityDimensions(0.6F, 1.8F, false) }
|
||||
)
|
||||
|
||||
override fun serialize(dimensions: EntityDimensions, type: Type, ctx: JsonSerializationContext): JsonElement {
|
||||
val json = JsonObject()
|
||||
json.addProperty(WIDTH, dimensions.width)
|
||||
@@ -36,6 +41,9 @@ object EntityDimensionsAdapter : JsonSerializer<EntityDimensions>, JsonDeseriali
|
||||
}
|
||||
|
||||
override fun deserialize(json: JsonElement, type: Type, ctx: JsonDeserializationContext): EntityDimensions {
|
||||
if (json is JsonPrimitive) {
|
||||
return templates[json.asString]?.invoke() ?: throw IllegalStateException("Dimensions provided by template name $json but no such template is set.")
|
||||
}
|
||||
json as JsonObject
|
||||
return EntityDimensions(json.get(WIDTH).asFloat, json.get(HEIGHT).asFloat, false)
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.entity
|
||||
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import net.minecraft.entity.Entity
|
||||
import net.minecraft.entity.data.TrackedData
|
||||
|
||||
@@ -18,4 +19,5 @@ interface EntitySideDelegate<T : Entity> {
|
||||
fun initialize(entity: T) {}
|
||||
fun tick(entity: T) {}
|
||||
fun onTrackedDataSet(data: TrackedData<*>) {}
|
||||
fun addToStruct(struct: QueryStruct) {}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.entity
|
||||
|
||||
import com.cobblemon.mod.common.entity.npc.NPCEntity
|
||||
|
||||
/**
|
||||
* A delegate for some actions that can be different for an NPC on client versus server.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since August 25th, 2023
|
||||
*/
|
||||
interface NPCSideDelegate : EntitySideDelegate<NPCEntity>
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.entity
|
||||
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
/**
|
||||
* Interface for custom entities that can send out and recall Pokémon. They get notified
|
||||
* when either of those actions are occurring.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since August 25th, 2023
|
||||
*
|
||||
*/
|
||||
interface PokemonSender {
|
||||
fun sendingOut(): CompletableFuture<Unit>
|
||||
fun recalling(pokemonEntity: PokemonEntity): CompletableFuture<Unit>
|
||||
}
|
||||
+12
-1
@@ -8,12 +8,23 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.events.pokemon
|
||||
|
||||
import com.bedrockk.molang.runtime.value.MoValue
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
|
||||
import com.cobblemon.mod.common.entity.pokeball.EmptyPokeBallEntity
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.itemRegistry
|
||||
import net.minecraft.registry.RegistryKeys
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
|
||||
data class PokemonCapturedEvent (
|
||||
val pokemon: Pokemon,
|
||||
val player: ServerPlayerEntity,
|
||||
val pokeBallEntity: EmptyPokeBallEntity
|
||||
)
|
||||
) {
|
||||
val context = mapOf<String, MoValue>(
|
||||
"pokemon" to pokemon.struct,
|
||||
"player" to player.asMoLangValue(),
|
||||
"poke_ball" to pokeBallEntity.struct,
|
||||
"item" to player.world.itemRegistry.getEntry(pokeBallEntity.pokeBall.item).asMoLangValue(RegistryKeys.ITEM)
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.fishing
|
||||
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.nbt.NbtCompound
|
||||
import net.minecraft.nbt.NbtList
|
||||
import net.minecraft.nbt.NbtString
|
||||
|
||||
data class FishingBait(
|
||||
val item: Identifier,
|
||||
val effects: List<Effect>,
|
||||
) {
|
||||
data class Effect(
|
||||
val type: Identifier,
|
||||
val subcategory: Identifier?,
|
||||
val chance: Double = 0.0,
|
||||
val value: Double = 0.0
|
||||
) {
|
||||
fun toNbt(): NbtCompound {
|
||||
val nbt = NbtCompound()
|
||||
nbt.putString("Type", type.toString())
|
||||
subcategory?.let { nbt.putString("Subcategory", it.toString()) }
|
||||
nbt.putDouble("Chance", chance)
|
||||
nbt.putDouble("Value", value)
|
||||
return nbt
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun fromNbt(nbt: NbtCompound): Effect {
|
||||
val type = Identifier(nbt.getString("Type"))
|
||||
val subcategory = if (nbt.contains("Subcategory")) Identifier(nbt.getString("Subcategory")) else null
|
||||
val chance = nbt.getDouble("Chance")
|
||||
val value = nbt.getDouble("Value")
|
||||
return Effect(type, subcategory, chance, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun toNbt(): NbtCompound {
|
||||
val nbt = NbtCompound()
|
||||
nbt.putString("Item", item.toString())
|
||||
val effectsList = NbtList()
|
||||
effects.forEach { effectsList.add(it.toNbt()) }
|
||||
nbt.put("Effects", effectsList)
|
||||
return nbt
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun fromNbt(nbt: NbtCompound): FishingBait {
|
||||
val item = Identifier(nbt.getString("Item"))
|
||||
val effectsList = nbt.getList("Effects", 10) // 10 is the type for NbtCompound
|
||||
val effects = mutableListOf<Effect>()
|
||||
for (i in 0 until effectsList.size) {
|
||||
effects.add(Effect.fromNbt(effectsList.getCompound(i)))
|
||||
}
|
||||
return FishingBait(item, effects)
|
||||
}
|
||||
}
|
||||
|
||||
object Effects {
|
||||
val NATURE = cobblemonResource("nature")
|
||||
val IV = cobblemonResource("iv")
|
||||
val EV = cobblemonResource("ev")
|
||||
val BITE_TIME = cobblemonResource("bite_time")
|
||||
val GENDER_CHANCE = cobblemonResource("gender_chance")
|
||||
val LEVEL_RAISE = cobblemonResource("level_raise")
|
||||
val TERA = cobblemonResource("tera")
|
||||
val SHINY_REROLL = cobblemonResource("shiny_reroll")
|
||||
val HIDDEN_ABILITY_CHANCE = cobblemonResource("ha_chance")
|
||||
val POKEMON_CHANCE = cobblemonResource("pokemon_chance")
|
||||
val FRIENDSHIP = cobblemonResource("friendship")
|
||||
val INERT = cobblemonResource("inert")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.fishing
|
||||
|
||||
import com.cobblemon.mod.common.api.data.JsonDataRegistry
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.net.messages.client.fishing.FishingBaitRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
|
||||
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.item.ItemStack
|
||||
import net.minecraft.registry.Registries
|
||||
import net.minecraft.resource.ResourceType
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
object FishingBaits : JsonDataRegistry<FishingBait>{
|
||||
override val id = cobblemonResource("fishing_baits")
|
||||
override val type = ResourceType.SERVER_DATA
|
||||
override val observable = SimpleObservable<FishingBaits>()
|
||||
override val typeToken: TypeToken<FishingBait> = TypeToken.get(FishingBait::class.java)
|
||||
override val resourcePath = "fishing_baits"
|
||||
override val gson: Gson = GsonBuilder()
|
||||
.registerTypeAdapter(Identifier::class.java, IdentifierAdapter)
|
||||
.setPrettyPrinting()
|
||||
.create()
|
||||
|
||||
private val itemMap = mutableMapOf<Identifier, FishingBait>()
|
||||
|
||||
override fun sync(player: ServerPlayerEntity) {
|
||||
FishingBaitRegistrySyncPacket(this.itemMap.values.toList()).sendToPlayer(player)
|
||||
}
|
||||
|
||||
override fun reload(data: Map<Identifier, FishingBait>) {
|
||||
itemMap.clear()
|
||||
data.forEach { id, bait ->
|
||||
itemMap[bait.item] = bait
|
||||
}
|
||||
}
|
||||
|
||||
fun getFromItemStack(stack: ItemStack): FishingBait? {
|
||||
return itemMap[Registries.ITEM.getId(stack.item)]
|
||||
}
|
||||
|
||||
fun isFishingBait(stack: ItemStack) = itemMap.containsKey(Registries.ITEM.getId(stack.item))
|
||||
|
||||
//
|
||||
//
|
||||
// fun getBaitSubcategory(item: ItemStack): String? {
|
||||
// val itemId = Registries.ITEM.getId(item.item)
|
||||
// if (itemId in itemMap.keys) {
|
||||
// return itemMap[itemId]?.subcategory
|
||||
// }
|
||||
// val tag = tagMap.keys.firstOrNull { it.fits(item.item, Registries.ITEM) }
|
||||
// if (tag != null) {
|
||||
// return tagMap[tag]?.subcategory
|
||||
// }
|
||||
// return null
|
||||
// }
|
||||
//
|
||||
// fun getBaitSuccessChance(item: ItemStack): Double? {
|
||||
// val itemId = Registries.ITEM.getId(item.item)
|
||||
// if (itemId in itemMap.keys) {
|
||||
// return itemMap[itemId]?.chance
|
||||
// }
|
||||
// val tag = tagMap.keys.firstOrNull { it.fits(item.item, Registries.ITEM) }
|
||||
// if (tag != null) {
|
||||
// return tagMap[tag]?.chance
|
||||
// }
|
||||
// return null
|
||||
// }
|
||||
//
|
||||
// fun getBaitEffectValue(item: ItemStack): Double? {
|
||||
// val itemId = Registries.ITEM.getId(item.item)
|
||||
// if (itemId in itemMap.keys) {
|
||||
// return itemMap[itemId]?.value
|
||||
// }
|
||||
// val tag = tagMap.keys.firstOrNull { it.fits(item.item, Registries.ITEM) }
|
||||
// if (tag != null) {
|
||||
// return tagMap[tag]?.value
|
||||
// }
|
||||
// return null
|
||||
// }
|
||||
//
|
||||
//
|
||||
// fun getBaitNote(item: ItemStack): String? {
|
||||
// val itemId = Registries.ITEM.getId(item.item)
|
||||
// if (itemId in itemMap.keys) {
|
||||
// return itemMap[itemId]?.note
|
||||
// }
|
||||
// val tag = tagMap.keys.firstOrNull { it.fits(item.item, Registries.ITEM) }
|
||||
// if (tag != null) {
|
||||
// return tagMap[tag]?.note
|
||||
// }
|
||||
// return null
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.fishing
|
||||
|
||||
import com.cobblemon.mod.common.api.pokeball.PokeBalls
|
||||
import com.cobblemon.mod.common.pokeball.PokeBall
|
||||
import net.minecraft.network.PacketByteBuf
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
/**
|
||||
* Base poke rod object
|
||||
* It is intended that there is one poke rod object initialized for a given poke rod type.
|
||||
*
|
||||
* @property name the poke rod registry name
|
||||
* @property pokeBallId The [Identifier] of the pokeball that is used as the bobber for this rod
|
||||
* @property lineColor list of [RGB] values that apply to the fishing line of the Pokérod
|
||||
*/
|
||||
data class PokeRod(
|
||||
val pokeBallId: Identifier,
|
||||
//Hex string of color
|
||||
val lineColor: String,
|
||||
var name: Identifier?
|
||||
) {
|
||||
internal fun encode(buffer: PacketByteBuf) {
|
||||
buffer.writeIdentifier(name)
|
||||
buffer.writeIdentifier(pokeBallId)
|
||||
buffer.writeString(lineColor)
|
||||
}
|
||||
|
||||
companion object {
|
||||
internal fun decode(buffer: PacketByteBuf): PokeRod {
|
||||
val name = buffer.readIdentifier()
|
||||
val pokeBallId = buffer.readIdentifier()
|
||||
val lineColor = buffer.readString()
|
||||
return PokeRod(pokeBallId, lineColor, name)
|
||||
}
|
||||
}
|
||||
|
||||
fun getPokeBall(): PokeBall? {
|
||||
return PokeBalls.getPokeBall(pokeBallId)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.fishing
|
||||
|
||||
import com.cobblemon.mod.common.api.data.JsonDataRegistry
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.net.messages.client.data.PokeRodRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
|
||||
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.resource.ResourceType
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
/**
|
||||
* The data registry for [PokeRod]s.
|
||||
* All the pokerod fields are guaranteed to exist
|
||||
*/
|
||||
object PokeRods : JsonDataRegistry<PokeRod> {
|
||||
|
||||
override val id = cobblemonResource("pokerods")
|
||||
override val type = ResourceType.SERVER_DATA
|
||||
override val observable = SimpleObservable<PokeRods>()
|
||||
|
||||
// ToDo once datapack pokerod is implemented add required adapters here
|
||||
override val gson: Gson = GsonBuilder()
|
||||
.disableHtmlEscaping()
|
||||
.registerTypeAdapter(Identifier::class.java, IdentifierAdapter)
|
||||
.setPrettyPrinting()
|
||||
.create()
|
||||
override val typeToken: TypeToken<PokeRod> = TypeToken.get(PokeRod::class.java)
|
||||
override val resourcePath = "pokerods"
|
||||
|
||||
private val rods = mutableMapOf<Identifier, PokeRod>()
|
||||
|
||||
override fun reload(data: Map<Identifier, PokeRod>) {
|
||||
data.forEach {
|
||||
it.value.name = it.key
|
||||
rods[it.key] = it.value
|
||||
}
|
||||
this.observable.emit(this)
|
||||
}
|
||||
|
||||
override fun sync(player: ServerPlayerEntity) {
|
||||
PokeRodRegistrySyncPacket(rods.values).sendToPlayer(player)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a Pokerod from registry name.
|
||||
* @return the pokerod object if found otherwise null.
|
||||
*/
|
||||
fun getPokeRod(name : Identifier): PokeRod? = rods[name]
|
||||
|
||||
}
|
||||
@@ -10,12 +10,11 @@ package com.cobblemon.mod.common.api.gui
|
||||
|
||||
import com.cobblemon.mod.common.api.text.font
|
||||
import com.cobblemon.mod.common.client.gui.battle.BattleOverlay.Companion.PORTRAIT_DIAMETER
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.PoseableEntityModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.PoseableEntityState
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.repository.PokemonModelRepository
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.repository.RenderContext
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.repository.VaryingModelRepository
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.pokemon.Species
|
||||
import com.mojang.blaze3d.platform.GlStateManager
|
||||
import com.mojang.blaze3d.systems.RenderSystem
|
||||
import net.minecraft.client.MinecraftClient
|
||||
@@ -29,14 +28,17 @@ import net.minecraft.client.render.Tessellator
|
||||
import net.minecraft.client.render.VertexFormat
|
||||
import net.minecraft.client.render.VertexFormats
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
import net.minecraft.entity.Entity
|
||||
import net.minecraft.text.MutableText
|
||||
import net.minecraft.text.OrderedText
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.math.RotationAxis
|
||||
import org.joml.Matrix4f
|
||||
import org.joml.Quaternionf
|
||||
import org.joml.Vector3f
|
||||
|
||||
@JvmOverloads
|
||||
fun blitk(
|
||||
matrixStack: MatrixStack,
|
||||
texture: Identifier? = null,
|
||||
@@ -100,6 +102,7 @@ fun drawRectangle(
|
||||
BufferRenderer.drawWithGlobalProgram(bufferbuilder.end())
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun drawCenteredText(
|
||||
context: DrawContext,
|
||||
font: Identifier? = null,
|
||||
@@ -114,6 +117,7 @@ fun drawCenteredText(
|
||||
context.drawText(textRenderer, comp, x.toInt() - textRenderer.getWidth(comp) / 2, y.toInt(), colour, shadow)
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun drawText(
|
||||
context: DrawContext,
|
||||
font: Identifier? = null,
|
||||
@@ -145,6 +149,7 @@ fun drawText(
|
||||
return isHovered
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun drawText(
|
||||
context: DrawContext,
|
||||
text: OrderedText,
|
||||
@@ -163,6 +168,7 @@ fun drawText(
|
||||
context.drawText(textRenderer, text, tweakedX.toInt(), y.toInt(), colour, shadow)
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun drawString(
|
||||
context: DrawContext,
|
||||
text: String,
|
||||
@@ -181,22 +187,30 @@ fun drawString(
|
||||
context.drawText(textRenderer, comp, x.toInt(), y.toInt(), colour, shadow)
|
||||
}
|
||||
|
||||
fun drawPortraitPokemon(
|
||||
species: Species,
|
||||
@JvmOverloads
|
||||
fun <T : Entity, M : PoseableEntityModel<T>> drawPoseablePortrait(
|
||||
identifier: Identifier,
|
||||
aspects: Set<String>,
|
||||
matrixStack: MatrixStack,
|
||||
scale: Float = 13F,
|
||||
contextScale: Float = 1F,
|
||||
reversed: Boolean = false,
|
||||
state: PoseableEntityState<PokemonEntity>? = null,
|
||||
partialTicks: Float
|
||||
state: PoseableEntityState<T>? = null,
|
||||
repository: VaryingModelRepository<T, M>,
|
||||
partialTicks: Float,
|
||||
limbSwing: Float = 0F,
|
||||
limbSwingAmount: Float = 0F,
|
||||
ageInTicks: Float = 0F,
|
||||
headYaw: Float = 0F,
|
||||
headPitch: Float = 0F
|
||||
) {
|
||||
val model = PokemonModelRepository.getPoser(species.resourceIdentifier, aspects)
|
||||
val texture = PokemonModelRepository.getTexture(species.resourceIdentifier, aspects, state?.animationSeconds ?: 0F)
|
||||
val model = repository.getPoser(identifier, aspects)
|
||||
val texture = repository.getTexture(identifier, aspects, state?.animationSeconds ?: 0F)
|
||||
|
||||
val context = RenderContext()
|
||||
PokemonModelRepository.getTextureNoSubstitute(species.resourceIdentifier, aspects, 0f).let { it -> context.put(RenderContext.TEXTURE, it) }
|
||||
context.put(RenderContext.SCALE, species.getForm(aspects).baseScale)
|
||||
context.put(RenderContext.SPECIES, species.resourceIdentifier)
|
||||
repository.getTextureNoSubstitute(identifier, aspects, 0f).let { context.put(RenderContext.TEXTURE, it) }
|
||||
context.put(RenderContext.SCALE, contextScale)
|
||||
context.put(RenderContext.SPECIES, identifier)
|
||||
context.put(RenderContext.ASPECTS, aspects)
|
||||
|
||||
val renderType = model.getLayer(texture)
|
||||
@@ -212,7 +226,7 @@ fun drawPortraitPokemon(
|
||||
model.getPose(PoseType.PORTRAIT)?.let { state.setPose(it.poseName) }
|
||||
state.timeEnteredPose = 0F
|
||||
state.updatePartialTicks(partialTicks)
|
||||
model.setupAnimStateful(null, state, 0F, 0F, 0F, 0F, 0F)
|
||||
model.setupAnimStateful(null, state, limbSwing, limbSwingAmount, ageInTicks, headYaw, headPitch)
|
||||
originalPose?.let { state.setPose(it) }
|
||||
}
|
||||
|
||||
@@ -234,7 +248,7 @@ fun drawPortraitPokemon(
|
||||
val buffer = immediate.getBuffer(renderType)
|
||||
val packedLight = LightmapTextureManager.pack(11, 7)
|
||||
|
||||
model.withLayerContext(immediate, state, PokemonModelRepository.getLayers(species.resourceIdentifier, aspects)) {
|
||||
model.withLayerContext(immediate, state, repository.getLayers(identifier, aspects)) {
|
||||
model.render(context, matrixStack, buffer, packedLight, OverlayTexture.DEFAULT_UV, 1F, 1F, 1F, 1F)
|
||||
immediate.draw()
|
||||
}
|
||||
@@ -242,5 +256,58 @@ fun drawPortraitPokemon(
|
||||
matrixStack.pop()
|
||||
model.setDefault()
|
||||
|
||||
DiffuseLighting.enableGuiDepthLighting()
|
||||
}
|
||||
|
||||
fun <E : Entity, M : PoseableEntityModel<E>> drawProfile(
|
||||
repository: VaryingModelRepository<E, M>,
|
||||
resourceIdentifier: Identifier,
|
||||
aspects: Set<String>,
|
||||
matrixStack: MatrixStack,
|
||||
state: PoseableEntityState<E>,
|
||||
partialTicks: Float,
|
||||
scale: Float = 20F
|
||||
) {
|
||||
val model = repository.getPoser(resourceIdentifier, aspects)
|
||||
val texture = repository.getTexture(resourceIdentifier, aspects, state.animationSeconds)
|
||||
|
||||
val context = RenderContext()
|
||||
repository.getTextureNoSubstitute(resourceIdentifier, aspects, 0f).let { context.put(RenderContext.TEXTURE, it) }
|
||||
context.put(RenderContext.SCALE, 1F)
|
||||
context.put(RenderContext.SPECIES, resourceIdentifier)
|
||||
context.put(RenderContext.ASPECTS, aspects)
|
||||
|
||||
val renderType = model.getLayer(texture)
|
||||
|
||||
RenderSystem.applyModelViewMatrix()
|
||||
matrixStack.scale(scale, scale, -scale)
|
||||
model.getPose(PoseType.PROFILE)?.let { state.setPose(it.poseName) }
|
||||
state.timeEnteredPose = 0F
|
||||
state.updatePartialTicks(partialTicks)
|
||||
model.setupAnimStateful(null, state, 0F, 0F, 0F, 0F, 0F)
|
||||
matrixStack.translate(model.profileTranslation.x, model.profileTranslation.y, model.profileTranslation.z - 4.0)
|
||||
matrixStack.scale(model.profileScale, model.profileScale, 1 / model.profileScale)
|
||||
// matrixStack.multiply(rotation)
|
||||
val quaternion1 = RotationAxis.POSITIVE_Y.rotationDegrees(-32F * if (false) -1F else 1F)
|
||||
val quaternion2 = RotationAxis.POSITIVE_X.rotationDegrees(5F)
|
||||
matrixStack.multiply(quaternion1)
|
||||
matrixStack.multiply(quaternion2)
|
||||
DiffuseLighting.method_34742()
|
||||
val entityRenderDispatcher = MinecraftClient.getInstance().entityRenderDispatcher
|
||||
entityRenderDispatcher.setRenderShadows(true)
|
||||
|
||||
val bufferSource = MinecraftClient.getInstance().bufferBuilders.entityVertexConsumers
|
||||
val buffer = bufferSource.getBuffer(renderType)
|
||||
val light1 = Vector3f(-1F, 1F, 1.0F)
|
||||
val light2 = Vector3f(1.3F, -1F, 1.0F)
|
||||
RenderSystem.setShaderLights(light1, light2)
|
||||
val packedLight = LightmapTextureManager.pack(11, 7)
|
||||
|
||||
model.withLayerContext(bufferSource, state, repository.getLayers(resourceIdentifier, aspects)) {
|
||||
model.render(context, matrixStack, buffer, packedLight, OverlayTexture.DEFAULT_UV, 1F, 1F, 1F, 1F)
|
||||
bufferSource.draw()
|
||||
}
|
||||
model.setDefault()
|
||||
entityRenderDispatcher.setRenderShadows(true)
|
||||
DiffuseLighting.enableGuiDepthLighting()
|
||||
}
|
||||
@@ -19,8 +19,10 @@ import com.bedrockk.molang.runtime.value.MoValue
|
||||
* @since October 22nd, 2023
|
||||
*/
|
||||
interface ExpressionLike {
|
||||
override fun toString(): String
|
||||
/** Produces a [MoValue] for a [MoLangRuntime] to supply an environment. */
|
||||
fun resolve(runtime: MoLangRuntime): MoValue
|
||||
fun resolve(runtime: MoLangRuntime, context: Map<String, MoValue> = emptyMap()): MoValue
|
||||
fun getString(): String = toString()
|
||||
|
||||
fun resolveDouble(runtime: MoLangRuntime) = resolve(runtime).asDouble()
|
||||
fun resolveFloat(runtime: MoLangRuntime) = resolveDouble(runtime).toFloat()
|
||||
@@ -28,4 +30,5 @@ interface ExpressionLike {
|
||||
fun resolveInt(runtime: MoLangRuntime) = resolveDouble(runtime).toInt()
|
||||
fun resolveBoolean(runtime: MoLangRuntime) = resolveDouble(runtime) == 1.0
|
||||
fun resolveObject(runtime: MoLangRuntime) = resolve(runtime) as ObjectValue<*>
|
||||
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ package com.cobblemon.mod.common.api.molang
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.bedrockk.molang.runtime.value.MoValue
|
||||
import com.cobblemon.mod.common.util.getString
|
||||
import com.cobblemon.mod.common.util.resolve
|
||||
|
||||
/**
|
||||
@@ -19,5 +21,6 @@ import com.cobblemon.mod.common.util.resolve
|
||||
* @since October 22nd, 2023
|
||||
*/
|
||||
class ListExpression(val exprs: List<Expression>): ExpressionLike {
|
||||
override fun resolve(runtime: MoLangRuntime) = exprs.resolve(runtime)
|
||||
override fun toString() = exprs.joinToString("\n") { it.getString().let { if (it.endsWith(";")) it else "$it;" } }
|
||||
override fun resolve(runtime: MoLangRuntime, context: Map<String, MoValue>) = exprs.resolve(runtime, context)
|
||||
}
|
||||
|
||||
@@ -18,12 +18,27 @@ import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.bedrockk.molang.runtime.value.MoValue
|
||||
import com.bedrockk.molang.runtime.value.StringValue
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.dialogue.PlayerDialogueFaceProvider
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.wavefunction.WaveFunction
|
||||
import com.cobblemon.mod.common.api.dialogue.ReferenceDialogueFaceProvider
|
||||
import com.cobblemon.mod.common.api.scripting.CobblemonScripts
|
||||
import com.cobblemon.mod.common.api.text.text
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.wavefunction.WaveFunctions
|
||||
import com.cobblemon.mod.common.entity.npc.NPCEntity
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.RunPosableMoLangPacket
|
||||
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
import com.cobblemon.mod.common.util.getBooleanOrNull
|
||||
import com.cobblemon.mod.common.util.getDoubleOrNull
|
||||
import com.cobblemon.mod.common.util.isInt
|
||||
import com.cobblemon.mod.common.util.itemRegistry
|
||||
import com.cobblemon.mod.common.util.server
|
||||
import com.cobblemon.mod.common.util.worldRegistry
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.block.Block
|
||||
import net.minecraft.entity.LivingEntity
|
||||
import net.minecraft.entity.damage.DamageSource
|
||||
import net.minecraft.entity.damage.DamageTypes
|
||||
import net.minecraft.entity.player.PlayerEntity
|
||||
import net.minecraft.nbt.NbtCompound
|
||||
import net.minecraft.nbt.NbtDouble
|
||||
import net.minecraft.nbt.NbtElement
|
||||
@@ -35,6 +50,7 @@ import net.minecraft.registry.RegistryKeys
|
||||
import net.minecraft.registry.entry.RegistryEntry
|
||||
import net.minecraft.registry.tag.TagKey
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.server.world.ServerWorld
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.world.World
|
||||
import net.minecraft.world.biome.Biome
|
||||
@@ -48,6 +64,11 @@ import net.minecraft.world.dimension.DimensionType
|
||||
*/
|
||||
object MoLangFunctions {
|
||||
val generalFunctions = hashMapOf<String, java.util.function.Function<MoParams, Any>>(
|
||||
"run_command" to java.util.function.Function { params ->
|
||||
val command = params.getString(0)
|
||||
val server = server() ?: return@Function DoubleValue(0)
|
||||
server.commandManager.executeWithPrefix(server.commandSource, command)
|
||||
},
|
||||
"is_int" to java.util.function.Function { params -> DoubleValue(params.get<MoValue>(0).asString().isInt()) },
|
||||
"is_number" to java.util.function.Function { params -> DoubleValue(params.get<MoValue>(0).asString().toDoubleOrNull() != null) },
|
||||
"to_number" to java.util.function.Function { params -> DoubleValue(params.get<MoValue>(0).asString().toDoubleOrNull() ?: 0.0) },
|
||||
@@ -75,23 +96,134 @@ object MoLangFunctions {
|
||||
val array = ArrayStruct(hashMapOf())
|
||||
values.forEachIndexed { index, moValue -> array.setDirectly("$index", moValue) }
|
||||
return@Function array
|
||||
},
|
||||
"run_script" to java.util.function.Function { params ->
|
||||
val runtime = MoLangRuntime()
|
||||
runtime.environment.structs.putAll(params.environment.structs)
|
||||
val script = params.getString(0).asIdentifierDefaultingNamespace()
|
||||
CobblemonScripts.run(script, runtime) ?: DoubleValue(0)
|
||||
}
|
||||
)
|
||||
val biomeFunctions = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
|
||||
val worldFunctions = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
|
||||
val dimensionTypeFunctions = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
|
||||
val blockFunctions = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
|
||||
val playerFunctions = mutableListOf<(ServerPlayerEntity) -> HashMap<String, java.util.function.Function<MoParams, Any>>>(
|
||||
val playerFunctions = mutableListOf<(PlayerEntity) -> HashMap<String, java.util.function.Function<MoParams, Any>>>(
|
||||
{ player ->
|
||||
hashMapOf(
|
||||
"username" to java.util.function.Function { _ -> StringValue(player.gameProfile.name) },
|
||||
"uuid" to java.util.function.Function { _ -> StringValue(player.gameProfile.id.toString()) },
|
||||
"data" to java.util.function.Function { _ -> return@Function Cobblemon.molangData.load(player.uuid) },
|
||||
"save_data" to java.util.function.Function { _ -> Cobblemon.molangData.save(player.uuid) },
|
||||
"main_held_item" to java.util.function.Function { _ -> player.world.itemRegistry.getEntry(player.mainHandStack.item).asMoLangValue(RegistryKeys.ITEM) },
|
||||
"off_held_item" to java.util.function.Function { _ -> player.world.itemRegistry.getEntry(player.offHandStack.item).asMoLangValue(RegistryKeys.ITEM) },
|
||||
"face" to java.util.function.Function { _ -> ObjectValue(PlayerDialogueFaceProvider(player.uuid)) }
|
||||
)
|
||||
val map = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
|
||||
map.put("username") { _ -> StringValue(player.gameProfile.name) }
|
||||
map.put("uuid") { _ -> StringValue(player.gameProfile.id.toString()) }
|
||||
map.put("data") { _ -> return@put if (player is ServerPlayerEntity) Cobblemon.molangData.load(player.uuid) else DoubleValue(0) }
|
||||
map.put("save_data") { _ -> if (player is ServerPlayerEntity) Cobblemon.molangData.save(player.uuid) else DoubleValue(0) }
|
||||
map.put("main_held_item") { _ -> player.world.itemRegistry.getEntry(player.mainHandStack.item).asMoLangValue(RegistryKeys.ITEM) }
|
||||
map.put("off_held_item") { _ -> player.world.itemRegistry.getEntry(player.offHandStack.item).asMoLangValue(RegistryKeys.ITEM) }
|
||||
map.put("face") { _ -> ObjectValue(PlayerDialogueFaceProvider(player.uuid)) }
|
||||
map.put("swing_hand") { _ -> player.swingHand(player.activeHand) }
|
||||
map.put("food_level") { _ -> DoubleValue(player.hungerManager.foodLevel) }
|
||||
map.put("saturation_level") { _ -> DoubleValue(player.hungerManager.saturationLevel) }
|
||||
map.put("tell") { params ->
|
||||
val message = params.getString(0).text()
|
||||
val overlay = params.getBooleanOrNull(1) ?: false
|
||||
player.sendMessage(message, overlay)
|
||||
}
|
||||
map.put("teleport") { params ->
|
||||
val x = params.getDouble(0)
|
||||
val y = params.getDouble(1)
|
||||
val z = params.getDouble(2)
|
||||
player.teleport(x, y, z)
|
||||
}
|
||||
map.put("heal") { params ->
|
||||
val amount = params.getDoubleOrNull(0) ?: player.maxHealth
|
||||
player.heal(amount.toFloat())
|
||||
}
|
||||
map.put("environment") {
|
||||
val environment = MoLangEnvironment()
|
||||
environment.structs["query"] = player.asMoLangValue()
|
||||
environment
|
||||
}
|
||||
map.put("run_command") { params ->
|
||||
val command = params.getString(0)
|
||||
val server = server() ?: return@put DoubleValue(0)
|
||||
server.commandManager.executeWithPrefix(player.commandSource, command)
|
||||
}
|
||||
map
|
||||
}
|
||||
)
|
||||
val entityFunctions = mutableListOf<(LivingEntity) -> HashMap<String, java.util.function.Function<MoParams, Any>>>(
|
||||
{ entity ->
|
||||
val map = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
|
||||
map.put("damage") { params ->
|
||||
val amount = params.getDouble(0)
|
||||
val source = DamageSource(entity.world.registryManager.get(RegistryKeys.DAMAGE_TYPE).getEntry(DamageTypes.GENERIC).get())
|
||||
entity.damage(source, amount.toFloat())
|
||||
}
|
||||
map.put("is_sneaking") { _ -> DoubleValue(entity.isSneaking) }
|
||||
map.put("is_sprinting") { _ -> DoubleValue(entity.isSprinting) }
|
||||
map.put("is_flying") { _ -> DoubleValue(entity.isFallFlying) }
|
||||
map.put("is_in_water") { _ -> DoubleValue(entity.isSubmergedInWater) }
|
||||
map.put("is_touching_water_or_rain") { _ -> DoubleValue(entity.isWet) }
|
||||
map.put("is_touching_water") { _ -> DoubleValue(entity.isTouchingWater) }
|
||||
map.put("is_in_lava") { _ -> DoubleValue(entity.isInLava) }
|
||||
map.put("is_on_fire") { _ -> DoubleValue(entity.isOnFire) }
|
||||
map.put("is_invisible") { _ -> DoubleValue(entity.isInvisible) }
|
||||
map.put("is_sleeping") { _ -> DoubleValue(entity.isSleeping) }
|
||||
map.put("is_riding") { _ -> DoubleValue(entity.hasVehicle()) }
|
||||
map.put("health") { _ -> DoubleValue(entity.health) }
|
||||
map.put("max_health") { _ -> DoubleValue(entity.maxHealth) }
|
||||
map.put("name") { _ -> StringValue(entity.entityName) }
|
||||
map.put("yaw") { _ -> DoubleValue(entity.yaw.toDouble()) }
|
||||
map.put("pitch") { _ -> DoubleValue(entity.pitch.toDouble()) }
|
||||
map.put("x") { _ -> DoubleValue(entity.x) }
|
||||
map.put("y") { _ -> DoubleValue(entity.y) }
|
||||
map.put("z") { _ -> DoubleValue(entity.z) }
|
||||
map.put("velocity_x") { _ -> DoubleValue(entity.velocity.x) }
|
||||
map.put("velocity_y") { _ -> DoubleValue(entity.velocity.y) }
|
||||
map.put("velocity_z") { _ -> DoubleValue(entity.velocity.z) }
|
||||
map.put("horizontal_velocity") { _ -> DoubleValue(entity.velocity.horizontalLength()) }
|
||||
map.put("is_on_ground") { _ -> DoubleValue(entity.isOnGround) }
|
||||
map.put("world") { _ -> entity.world.worldRegistry.getEntry(entity.world).asWorldMoLangValue() }
|
||||
map.put("biome") { _ -> entity.world.getBiome(entity.blockPos).asBiomeMoLangValue() }
|
||||
map
|
||||
}
|
||||
)
|
||||
val npcFunctions = mutableListOf<(NPCEntity) -> HashMap<String, java.util.function.Function<MoParams, Any>>>(
|
||||
{ npc ->
|
||||
val map = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
|
||||
map.put("class") { StringValue(npc.npc.resourceIdentifier.toString()) }
|
||||
map.put("name") { StringValue(npc.name.string) }
|
||||
map.put("face") { ObjectValue(ReferenceDialogueFaceProvider(npc.id)) }
|
||||
map.put("in_battle") { DoubleValue(npc.isInBattle()) }
|
||||
map.put("run_script_on_client") { params ->
|
||||
val world = npc.world
|
||||
if (world is ServerWorld) {
|
||||
val script = params.getString(0)
|
||||
val packet = RunPosableMoLangPacket(npc.id, setOf("q.run_script('$script')"))
|
||||
packet.sendToPlayers(world.players.toList())
|
||||
}
|
||||
Unit
|
||||
}
|
||||
map.put("run_script") { params ->
|
||||
val script = params.getString(0).asIdentifierDefaultingNamespace()
|
||||
val environment = params.environment
|
||||
val runtime = MoLangRuntime()
|
||||
runtime.environment.structs.putAll(environment.structs)
|
||||
CobblemonScripts.run(script, runtime) ?: DoubleValue(0)
|
||||
}
|
||||
map.put("environment") { _ -> npc.runtime.environment }
|
||||
map
|
||||
}
|
||||
)
|
||||
|
||||
val battleFunctions = mutableListOf<(PokemonBattle) -> HashMap<String, java.util.function.Function<MoParams, Any>>>(
|
||||
{ battle ->
|
||||
val map = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
|
||||
map.put("battle_id") { StringValue(battle.battleId.toString()) }
|
||||
map.put("is_pvn") { DoubleValue(battle.isPvN) }
|
||||
map.put("is_pvp") { DoubleValue(battle.isPvP) }
|
||||
map.put("is_pvw") { DoubleValue(battle.isPvW) }
|
||||
map.put("battle_type") { StringValue(battle.format.toString()) }
|
||||
map.put("environment") { battle.runtime.environment }
|
||||
map
|
||||
}
|
||||
)
|
||||
|
||||
@@ -99,15 +231,35 @@ object MoLangFunctions {
|
||||
fun RegistryEntry<World>.asWorldMoLangValue() = asMoLangValue(RegistryKeys.WORLD).addFunctions(worldFunctions)
|
||||
fun RegistryEntry<Block>.asBlockMoLangValue() = asMoLangValue(RegistryKeys.BLOCK).addFunctions(blockFunctions)
|
||||
fun RegistryEntry<DimensionType>.asDimensionTypeMoLangValue() = asMoLangValue(RegistryKeys.DIMENSION_TYPE).addFunctions(dimensionTypeFunctions)
|
||||
fun ServerPlayerEntity.asMoLangValue(): ObjectValue<ServerPlayerEntity> {
|
||||
fun PlayerEntity.asMoLangValue(): ObjectValue<PlayerEntity> {
|
||||
val value = ObjectValue(
|
||||
obj = this,
|
||||
stringify = { it.entityName }
|
||||
)
|
||||
value.addFunctions(entityFunctions.flatMap { it(this).entries.map { it.key to it.value } }.toMap())
|
||||
value.addFunctions(playerFunctions.flatMap { it(this).entries.map { it.key to it.value } }.toMap())
|
||||
return value
|
||||
}
|
||||
|
||||
fun NPCEntity.asMoLangValue(): ObjectValue<NPCEntity> {
|
||||
val value = ObjectValue(
|
||||
obj = this,
|
||||
stringify = { it.name.string }
|
||||
)
|
||||
value.addFunctions(entityFunctions.flatMap { it(this).entries.map { it.key to it.value } }.toMap())
|
||||
value.addFunctions(npcFunctions.flatMap { it(this).entries.map { it.key to it.value } }.toMap())
|
||||
return value
|
||||
}
|
||||
|
||||
fun PokemonBattle.asMoLangValue(): ObjectValue<PokemonBattle> {
|
||||
val value = ObjectValue(
|
||||
obj = this,
|
||||
stringify = { it.battleId.toString() }
|
||||
)
|
||||
value.addFunctions(battleFunctions.flatMap { it(this).entries.map { it.key to it.value } }.toMap())
|
||||
return value
|
||||
}
|
||||
|
||||
fun <T> RegistryEntry<T>.asMoLangValue(key: RegistryKey<Registry<T>>): ObjectValue<RegistryEntry<T>> {
|
||||
val value = ObjectValue(
|
||||
obj = this,
|
||||
@@ -134,11 +286,6 @@ object MoLangFunctions {
|
||||
return this
|
||||
}
|
||||
|
||||
fun <T : QueryStruct> T.addFunction(name: String, function: java.util.function.Function<MoParams, Any>): T {
|
||||
this.functions[name] = function
|
||||
return this
|
||||
}
|
||||
|
||||
fun MoLangEnvironment.getQueryStruct(name: String = "query") = structs.getOrPut(name) { QueryStruct(hashMapOf()) } as QueryStruct
|
||||
|
||||
fun MoLangRuntime.setup(): MoLangRuntime {
|
||||
@@ -193,4 +340,6 @@ object MoLangFunctions {
|
||||
else -> null
|
||||
} ?: throw IllegalArgumentException("Invalid NBT element type: ${nbt.type}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun Either<Identifier, ExpressionLike>.runScript(runtime: MoLangRuntime) = map({ CobblemonScripts.run(it, runtime) }, { it.resolve(runtime) })
|
||||
@@ -10,6 +10,8 @@ package com.cobblemon.mod.common.api.molang
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.bedrockk.molang.runtime.value.MoValue
|
||||
import com.cobblemon.mod.common.util.getString
|
||||
import com.cobblemon.mod.common.util.resolve
|
||||
|
||||
/**
|
||||
@@ -20,5 +22,6 @@ import com.cobblemon.mod.common.util.resolve
|
||||
* @since October 22nd, 2023
|
||||
*/
|
||||
class SingleExpression(val expr: Expression) : ExpressionLike {
|
||||
override fun resolve(runtime: MoLangRuntime) = runtime.resolve(expr)
|
||||
override fun toString() = expr.getString()
|
||||
override fun resolve(runtime: MoLangRuntime, context: Map<String, MoValue>) = runtime.resolve(expr, context)
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@ import com.bedrockk.molang.runtime.struct.MoStruct
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.bedrockk.molang.runtime.value.StringValue
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addFunction
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectTimeline
|
||||
import com.cobblemon.mod.common.api.moves.categories.DamageCategories
|
||||
import com.cobblemon.mod.common.api.moves.categories.DamageCategory
|
||||
|
||||
+4
-2
@@ -11,9 +11,11 @@ package com.cobblemon.mod.common.api.moves.animations
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.bedrockk.molang.runtime.struct.VariableStruct
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.api.moves.animations.keyframes.ActionEffectKeyframe
|
||||
import com.cobblemon.mod.common.api.scheduling.ScheduledTask
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.asExpressions
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import net.minecraft.entity.Entity
|
||||
@@ -29,7 +31,7 @@ import net.minecraft.entity.Entity
|
||||
*/
|
||||
class ActionEffectTimeline(
|
||||
val timeline: List<ActionEffectKeyframe> = mutableListOf(),
|
||||
val condition: Expression = "true".asExpression()
|
||||
val condition: ExpressionLike = "true".asExpressionLike()
|
||||
) {
|
||||
companion object {
|
||||
val NONE = ActionEffectTimeline()
|
||||
|
||||
+1
-1
@@ -49,6 +49,6 @@ class AnimationActionEffectKeyframe : ConditionalActionEffectKeyframe(), EntityC
|
||||
players.forEach { it.sendPacket(pkt) }
|
||||
}
|
||||
|
||||
return delayedFuture(seconds = delay.resolveFloat(context.runtime), serverThread = true)
|
||||
return delayedFuture(seconds = delay.resolveFloat(context.runtime))
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -46,6 +46,6 @@ class EntityMoLangActionEffectKeyframe : ConditionalActionEffectKeyframe(), Enti
|
||||
players.forEach { it.sendPacket(pkt) }
|
||||
}
|
||||
|
||||
return delayedFuture(seconds = delay.resolveFloat(context.runtime), serverThread = true)
|
||||
return delayedFuture(seconds = delay.resolveFloat(context.runtime))
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -51,6 +51,6 @@ class EntityParticlesActionEffectKeyframe : ConditionalActionEffectKeyframe(), E
|
||||
packet.sendToPlayers(players)
|
||||
}
|
||||
|
||||
return delayedFuture(seconds = delay.resolveFloat(context.runtime), serverThread = true)
|
||||
return delayedFuture(seconds = delay.resolveFloat(context.runtime))
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -45,6 +45,6 @@ class EntitySoundActionEffectKeyframe : ConditionalActionEffectKeyframe(), Entit
|
||||
entity.playSound(soundEvent, 1f, 1f)
|
||||
}
|
||||
|
||||
return delayedFuture(seconds = delay.resolveFloat(context.runtime), serverThread = true)
|
||||
return delayedFuture(seconds = delay.resolveFloat(context.runtime))
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -25,6 +25,6 @@ class MoLangActionEffectKeyframe : ActionEffectKeyframe {
|
||||
val delay: ExpressionLike = "0".asExpressionLike()
|
||||
override fun play(context: ActionEffectContext): CompletableFuture<Unit> {
|
||||
expressions.resolve(context.runtime)
|
||||
return delayedFuture(seconds = delay.resolveFloat(context.runtime), serverThread = true)
|
||||
return delayedFuture(seconds = delay.resolveFloat(context.runtime))
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -14,5 +14,5 @@ import com.cobblemon.mod.common.util.asExpressionLike
|
||||
|
||||
class PauseActionEffectKeyframe : ConditionalActionEffectKeyframe() {
|
||||
val pause = "1".asExpressionLike()
|
||||
override fun playWhenTrue(context: ActionEffectContext) = delayedFuture(seconds = pause.resolveFloat(context.runtime), serverThread = true)
|
||||
override fun playWhenTrue(context: ActionEffectContext) = delayedFuture(seconds = pause.resolveFloat(context.runtime))
|
||||
}
|
||||
+1
-1
@@ -24,7 +24,7 @@ class RemoveHoldsActionEffectKeyframe : ActionEffectKeyframe {
|
||||
val delay = 0F
|
||||
val holds = mutableSetOf<String>()
|
||||
override fun play(context: ActionEffectContext): CompletableFuture<Unit> {
|
||||
return delayedFuture(seconds = delay, serverThread = true).thenApply {
|
||||
return delayedFuture(seconds = delay).thenApply {
|
||||
if (holds.isEmpty()) {
|
||||
context.holds.clear()
|
||||
} else {
|
||||
|
||||
+1
-1
@@ -56,7 +56,7 @@ class ReturnToPositionActionEffectKeyframe : ActionEffectKeyframe {
|
||||
}
|
||||
)
|
||||
|
||||
after(seconds = timeout.resolveFloat(context.runtime), serverThread = true) {
|
||||
after(seconds = timeout.resolveFloat(context.runtime)) {
|
||||
if (!future.isDone && !timedOut) {
|
||||
timedOut = true
|
||||
timeoutEffect.run(context).thenApply { future.complete(Unit) }
|
||||
|
||||
-1
@@ -29,5 +29,4 @@ object StringSetDataSerializer : TrackedDataHandler<Set<String>> {
|
||||
}
|
||||
|
||||
override fun copy(set: Set<String>) = set.toSet()
|
||||
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.net.serializers
|
||||
|
||||
import com.cobblemon.mod.common.net.IntSize
|
||||
import com.cobblemon.mod.common.util.readSizedInt
|
||||
import com.cobblemon.mod.common.util.writeSizedInt
|
||||
import java.util.UUID
|
||||
import net.minecraft.entity.data.TrackedDataHandler
|
||||
import net.minecraft.network.PacketByteBuf
|
||||
|
||||
object UUIDSetDataSerializer : TrackedDataHandler<Set<UUID>> {
|
||||
override fun write(buffer: PacketByteBuf, set: Set<UUID>) {
|
||||
buffer.writeSizedInt(IntSize.U_BYTE, set.size)
|
||||
set.forEach(buffer::writeUuid)
|
||||
}
|
||||
|
||||
override fun read(buffer: PacketByteBuf): Set<UUID> {
|
||||
val set = mutableSetOf<UUID>()
|
||||
repeat(times = buffer.readSizedInt(IntSize.U_BYTE)) {
|
||||
set.add(buffer.readUuid())
|
||||
}
|
||||
return set
|
||||
}
|
||||
|
||||
override fun copy(set: Set<UUID>) = set.toSet()
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.npc
|
||||
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.bedrockk.molang.runtime.value.MoValue
|
||||
import com.bedrockk.molang.runtime.value.StringValue
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.api.npc.configuration.NPCBattleConfiguration
|
||||
import com.cobblemon.mod.common.net.IntSize
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import com.cobblemon.mod.common.util.readMapK
|
||||
import com.cobblemon.mod.common.util.writeMapK
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.entity.EntityDimensions
|
||||
import net.minecraft.network.PacketByteBuf
|
||||
import net.minecraft.text.MutableText
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
/**
|
||||
* A class of NPC. This can contain a lot of preset information about the NPC's behaviour. Consider this the Pokémon
|
||||
* species but for NPCs.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since August 14th, 2023
|
||||
*/
|
||||
class NPCClass {
|
||||
@Transient
|
||||
lateinit var resourceIdentifier: Identifier
|
||||
|
||||
var names = mutableListOf<MutableText>(lang("npc.name.default"))
|
||||
var hitbox = EntityDimensions(0.6F, 1.8F, false)
|
||||
var battleConfiguration = NPCBattleConfiguration()
|
||||
var interaction: Either<Identifier, ExpressionLike>? = null
|
||||
var variables = mutableMapOf<String, MoValue>()
|
||||
|
||||
fun encode(buffer: PacketByteBuf) {
|
||||
buffer.writeCollection(names, PacketByteBuf::writeText)
|
||||
buffer.writeFloat(this.hitbox.width)
|
||||
buffer.writeFloat(this.hitbox.height)
|
||||
buffer.writeBoolean(this.hitbox.fixed)
|
||||
battleConfiguration.encode(buffer)
|
||||
buffer.writeNullable(interaction) { _, value ->
|
||||
buffer.writeBoolean(value.map({ true }, { false }))
|
||||
buffer.writeString(value.map({ it.toString() }, { it.toString() }))
|
||||
}
|
||||
buffer.writeMapK(size = IntSize.U_BYTE, map = variables) { (key, value) ->
|
||||
buffer.writeString(key)
|
||||
buffer.writeString(value.asString())
|
||||
}
|
||||
}
|
||||
|
||||
fun decode(buffer: PacketByteBuf) {
|
||||
names = buffer.readList { buffer.readText().copy() }.toMutableList()
|
||||
hitbox = EntityDimensions(buffer.readFloat(), buffer.readFloat(), buffer.readBoolean())
|
||||
battleConfiguration = NPCBattleConfiguration()
|
||||
battleConfiguration.decode(buffer)
|
||||
interaction = buffer.readNullable {
|
||||
if (buffer.readBoolean()) {
|
||||
Either.left(Identifier(buffer.readString()))
|
||||
} else {
|
||||
Either.right(buffer.readString().asExpressionLike())
|
||||
}
|
||||
}
|
||||
buffer.readMapK(size = IntSize.U_BYTE, map = variables) {
|
||||
val key = buffer.readString()
|
||||
val value = buffer.readString()
|
||||
if (value.toDoubleOrNull() != null) {
|
||||
return@readMapK key to DoubleValue(value.toDouble())
|
||||
} else {
|
||||
return@readMapK key to StringValue(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.npc
|
||||
|
||||
import com.bedrockk.molang.runtime.value.MoValue
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.ai.SleepDepth
|
||||
import com.cobblemon.mod.common.api.conditional.RegistryLikeCondition
|
||||
import com.cobblemon.mod.common.api.data.JsonDataRegistry
|
||||
import com.cobblemon.mod.common.api.drop.DropEntry
|
||||
import com.cobblemon.mod.common.api.drop.ItemDropMethod
|
||||
import com.cobblemon.mod.common.api.entity.EntityDimensionsAdapter
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.api.spawning.TimeRange
|
||||
import com.cobblemon.mod.common.net.messages.client.data.NPCRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.pokemon.Species
|
||||
import com.cobblemon.mod.common.util.adapters.*
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.block.Block
|
||||
import net.minecraft.entity.EntityDimensions
|
||||
import net.minecraft.item.Item
|
||||
import net.minecraft.nbt.NbtCompound
|
||||
import net.minecraft.resource.ResourceType
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.math.Box
|
||||
import net.minecraft.world.biome.Biome
|
||||
|
||||
object NPCClasses : JsonDataRegistry<NPCClass> {
|
||||
|
||||
override val id = cobblemonResource("npc")
|
||||
override val type = ResourceType.SERVER_DATA
|
||||
|
||||
override val gson: Gson = GsonBuilder()
|
||||
.registerTypeAdapter(EntityDimensions::class.java, EntityDimensionsAdapter)
|
||||
.registerTypeAdapter(Box::class.java, BoxAdapter)
|
||||
.registerTypeAdapter(IntRange::class.java, IntRangeAdapter)
|
||||
.registerTypeAdapter(PokemonProperties::class.java, pokemonPropertiesShortAdapter)
|
||||
.registerTypeAdapter(Identifier::class.java, IdentifierAdapter)
|
||||
.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)
|
||||
.registerTypeAdapter(NbtCompound::class.java, NbtCompoundAdapter)
|
||||
.registerTypeAdapter(NPCPartyProvider::class.java, NPCPartyProviderAdapter)
|
||||
.registerTypeAdapter(MoValue::class.java, MoValueAdapter)
|
||||
.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, Item::class.java).type, ItemLikeConditionAdapter)
|
||||
.registerTypeAdapter(TypeToken.getParameterized(Either::class.java, Identifier::class.java, ExpressionLike::class.java).type, NPCScriptAdapter)
|
||||
.disableHtmlEscaping()
|
||||
.enableComplexMapKeySerialization()
|
||||
.create()
|
||||
|
||||
override val typeToken: TypeToken<NPCClass> = TypeToken.get(NPCClass::class.java)
|
||||
override val resourcePath = "npcs"
|
||||
override val observable = SimpleObservable<NPCClasses>()
|
||||
private val npcClassesByIdentifier = hashMapOf<Identifier, NPCClass>()
|
||||
|
||||
val classes: Collection<NPCClass>
|
||||
get() = this.npcClassesByIdentifier.values
|
||||
|
||||
init {
|
||||
// NPC additions would be useful
|
||||
// SpeciesAdditions.observable.subscribe {
|
||||
// this.species.forEach(Species::initialize)
|
||||
// this.species.forEach(Species::resolveEvolutionMoves)
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds an NPC class by the pathname of their [Identifier].
|
||||
* This method exists for the convenience of finding Cobble default NPC classes.
|
||||
* This uses [getByIdentifier] using the [Cobblemon.MODID] as the namespace and the [name] as the path.
|
||||
*
|
||||
* @param name The path of the NPC class asset.
|
||||
* @return The [NPCClass] if existing.
|
||||
*/
|
||||
fun getByName(name: String) = this.getByIdentifier(cobblemonResource(name))
|
||||
|
||||
/**
|
||||
* Finds an [NPCClass] by its unique [Identifier].
|
||||
*
|
||||
* @param identifier The unique [NPCClass.resourceIdentifier] of the [NPCClass].
|
||||
* @return The [NPCClass] if existing.
|
||||
*/
|
||||
fun getByIdentifier(identifier: Identifier) = this.npcClassesByIdentifier[identifier]
|
||||
|
||||
/**
|
||||
* Counts the currently loaded NPC classes.
|
||||
*
|
||||
* @return The loaded NPC class amount.
|
||||
*/
|
||||
fun count() = this.npcClassesByIdentifier.size
|
||||
|
||||
/**
|
||||
* Picks a random [NPCClass].
|
||||
*
|
||||
* @throws [NoSuchElementException] if there are no NPC classes loaded.
|
||||
*
|
||||
* @return A randomly selected [Species].
|
||||
*/
|
||||
fun random(): NPCClass = this.npcClassesByIdentifier.values.random()
|
||||
|
||||
override fun reload(data: Map<Identifier, NPCClass>) {
|
||||
this.npcClassesByIdentifier.clear()
|
||||
data.forEach { (identifier, species) ->
|
||||
species.resourceIdentifier = identifier
|
||||
this.npcClassesByIdentifier[identifier] = species
|
||||
}
|
||||
}
|
||||
|
||||
override fun sync(player: ServerPlayerEntity) {
|
||||
NPCRegistrySyncPacket(npcClassesByIdentifier.values.toList()).sendToPlayer(player)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.npc
|
||||
|
||||
import com.cobblemon.mod.common.api.npc.configuration.NPCBattleConfiguration
|
||||
import com.cobblemon.mod.common.entity.npc.NPCEntity
|
||||
|
||||
/**
|
||||
* An NPC configuration is like a snapshot of an NPC setup. It can be taken from an existing NPC and loaded onto
|
||||
* others. Useful as a backup mechanism or as shorthand for copying an NPC's configuration without building an
|
||||
* entire class for them.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since August 16th, 2023
|
||||
*/
|
||||
class NPCConfiguration {
|
||||
var battle: NPCBattleConfiguration? = null
|
||||
|
||||
fun applyTo(npc: NPCEntity) {
|
||||
}
|
||||
|
||||
fun loadFrom(npc: NPCEntity) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.npc
|
||||
|
||||
import com.cobblemon.mod.common.api.npc.partyproviders.SimplePartyProvider
|
||||
import com.cobblemon.mod.common.api.storage.party.PartyStore
|
||||
import com.cobblemon.mod.common.entity.npc.NPCEntity
|
||||
import com.google.gson.JsonElement
|
||||
import net.minecraft.nbt.NbtCompound
|
||||
import net.minecraft.network.PacketByteBuf
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
|
||||
/**
|
||||
* A provider of a party for battling the NPC. Completely custom party providers will only display
|
||||
* as text labels in any GUIs.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since August 16th, 2023
|
||||
*/
|
||||
interface NPCPartyProvider {
|
||||
companion object {
|
||||
val types = mutableMapOf<String, (String) -> NPCPartyProvider>(
|
||||
SimplePartyProvider.TYPE to { SimplePartyProvider() }
|
||||
)
|
||||
}
|
||||
|
||||
val type: String
|
||||
fun provide(npc: NPCEntity, challengers: List<ServerPlayerEntity>): PartyStore
|
||||
fun encode(buffer: PacketByteBuf)
|
||||
fun decode(buffer: PacketByteBuf)
|
||||
fun saveToNBT(nbt: NbtCompound)
|
||||
fun loadFromNBT(nbt: NbtCompound)
|
||||
|
||||
fun loadFromJSON(json: JsonElement)
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.npc
|
||||
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
class NPCPreset {
|
||||
lateinit var id: Identifier
|
||||
var aspects: Set<String>? = null
|
||||
var party: NPCPartyProvider? = null
|
||||
// var mergeMode = MergeMode.KEEP
|
||||
}
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.npc.configuration
|
||||
|
||||
import com.cobblemon.mod.common.api.npc.NPCPartyProvider
|
||||
import com.cobblemon.mod.common.util.DataKeys
|
||||
import net.minecraft.nbt.NbtCompound
|
||||
import net.minecraft.network.PacketByteBuf
|
||||
|
||||
class NPCBattleConfiguration {
|
||||
var canChallenge = false
|
||||
var party: NPCPartyProvider? = null
|
||||
var simultaneousBattles = false
|
||||
var healAfterwards = true
|
||||
|
||||
fun encode(buffer: PacketByteBuf) {
|
||||
buffer.writeBoolean(canChallenge)
|
||||
buffer.writeBoolean(simultaneousBattles)
|
||||
buffer.writeBoolean(healAfterwards)
|
||||
buffer.writeNullable(party) { _, provider ->
|
||||
buffer.writeString(provider.type)
|
||||
provider.encode(buffer)
|
||||
}
|
||||
}
|
||||
|
||||
fun decode(buffer: PacketByteBuf) {
|
||||
canChallenge = buffer.readBoolean()
|
||||
simultaneousBattles = buffer.readBoolean()
|
||||
healAfterwards = buffer.readBoolean()
|
||||
party = buffer.readNullable {
|
||||
val type = buffer.readString()
|
||||
val providerBuilder = NPCPartyProvider.types[type]
|
||||
?: throw IllegalArgumentException("Failed to load NPC party provider of type: $type")
|
||||
|
||||
providerBuilder(type)
|
||||
}
|
||||
}
|
||||
|
||||
fun saveToNBT(nbt: NbtCompound) {
|
||||
nbt.putBoolean(DataKeys.NPC_CAN_CHALLENGE, canChallenge)
|
||||
nbt.putBoolean(DataKeys.NPC_SIMULTANEOUS_BATTLES, simultaneousBattles)
|
||||
nbt.putBoolean(DataKeys.NPC_HEAL_AFTERWARDS, healAfterwards)
|
||||
val party = party
|
||||
if (party != null) {
|
||||
val partyNBT = NbtCompound()
|
||||
partyNBT.putString(DataKeys.NPC_PARTY_TYPE, party.type)
|
||||
party.saveToNBT(partyNBT)
|
||||
nbt.put(DataKeys.NPC_PARTY, partyNBT)
|
||||
}
|
||||
}
|
||||
|
||||
fun loadFromNBT(nbt: NbtCompound) {
|
||||
canChallenge = nbt.getBoolean(DataKeys.NPC_CAN_CHALLENGE)
|
||||
simultaneousBattles = nbt.getBoolean(DataKeys.NPC_SIMULTANEOUS_BATTLES)
|
||||
healAfterwards = nbt.getBoolean(DataKeys.NPC_HEAL_AFTERWARDS)
|
||||
val partyNBT = nbt.getCompound(DataKeys.NPC_PARTY)
|
||||
if (!partyNBT.isEmpty) {
|
||||
val type = partyNBT.getString(DataKeys.NPC_PARTY_TYPE)
|
||||
val providerBuilder = NPCPartyProvider.types[type]
|
||||
?: throw IllegalArgumentException("Failed to load NPC party provider of type: $type")
|
||||
party = providerBuilder(type).also { it.loadFromNBT(partyNBT) }
|
||||
}
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.npc.configuration
|
||||
|
||||
import net.minecraft.nbt.NbtCompound
|
||||
import net.minecraft.network.PacketByteBuf
|
||||
|
||||
class NPCBehaviourConfiguration {
|
||||
var canBeHurt = true
|
||||
|
||||
fun encode(buffer: PacketByteBuf) {
|
||||
|
||||
}
|
||||
|
||||
fun decode(buffer: PacketByteBuf) {
|
||||
|
||||
}
|
||||
|
||||
fun saveToNBT(nbt: NbtCompound) {
|
||||
|
||||
}
|
||||
|
||||
fun loadFromNBT(nbt: NbtCompound) {
|
||||
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.npc.configuration
|
||||
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
|
||||
/**
|
||||
* A type of interaction handler for when a player right clicks the NPC.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since August 19th, 2023
|
||||
*/
|
||||
interface NPCInteractConfiguration {
|
||||
val type: String
|
||||
fun interact(player: ServerPlayerEntity): Boolean
|
||||
}
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.npc.partyproviders
|
||||
|
||||
import com.cobblemon.mod.common.api.npc.NPCPartyProvider
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
|
||||
import com.cobblemon.mod.common.api.storage.party.NPCPartyStore
|
||||
import com.cobblemon.mod.common.api.storage.party.PartyStore
|
||||
import com.cobblemon.mod.common.entity.npc.NPCEntity
|
||||
import com.cobblemon.mod.common.net.IntSize
|
||||
import com.cobblemon.mod.common.util.DataKeys
|
||||
import com.cobblemon.mod.common.util.readSizedInt
|
||||
import com.cobblemon.mod.common.util.writeSizedInt
|
||||
import com.google.gson.JsonElement
|
||||
import com.google.gson.JsonObject
|
||||
import net.minecraft.nbt.NbtCompound
|
||||
import net.minecraft.network.PacketByteBuf
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
|
||||
class SimplePartyProvider : NPCPartyProvider {
|
||||
companion object {
|
||||
const val TYPE = "simple"
|
||||
}
|
||||
|
||||
@Transient
|
||||
override val type = TYPE
|
||||
|
||||
val pokemon = mutableListOf<PokemonProperties>()
|
||||
|
||||
override fun encode(buffer: PacketByteBuf) {
|
||||
buffer.writeSizedInt(IntSize.U_BYTE, pokemon.size)
|
||||
for (pokemon in this.pokemon) {
|
||||
buffer.writeString(pokemon.originalString)
|
||||
}
|
||||
}
|
||||
|
||||
override fun decode(buffer: PacketByteBuf) {
|
||||
repeat(times = buffer.readSizedInt(IntSize.U_BYTE)) {
|
||||
pokemon.add(PokemonProperties.parse(buffer.readString()))
|
||||
}
|
||||
}
|
||||
|
||||
override fun saveToNBT(nbt: NbtCompound) {
|
||||
for ((index, pokemon) in this.pokemon.withIndex()) {
|
||||
nbt.putString(DataKeys.NPC_PARTY_POKEMON + index, pokemon.originalString)
|
||||
}
|
||||
}
|
||||
|
||||
override fun loadFromNBT(nbt: NbtCompound) {
|
||||
var index = 0
|
||||
while (nbt.contains(DataKeys.NPC_PARTY_POKEMON + index)) {
|
||||
this.pokemon.add(PokemonProperties.parse(nbt.getString(DataKeys.POKEMON_PROPERTIES + index)))
|
||||
index++
|
||||
}
|
||||
}
|
||||
|
||||
override fun loadFromJSON(json: JsonElement) {
|
||||
json as JsonObject
|
||||
if (json.has(DataKeys.NPC_PARTY_POKEMON.lowercase())) {
|
||||
json.get(DataKeys.NPC_PARTY_POKEMON.lowercase()).asJsonArray.forEach { pokemon.add(PokemonProperties.parse(it.asString)) }
|
||||
}
|
||||
}
|
||||
|
||||
override fun provide(npc: NPCEntity, challengers: List<ServerPlayerEntity>): PartyStore {
|
||||
return NPCPartyStore(npc).apply {
|
||||
for (properties in pokemon) {
|
||||
add(properties.create())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -70,6 +70,8 @@ object CobblemonPermissions {
|
||||
val CLEAR_PARTY = this.create("${COMMAND_PREFIX}clearparty", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
|
||||
val CLEAR_PC = this.create("${COMMAND_PREFIX}clearpc", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
|
||||
|
||||
val NPC_EDIT = this.create("${COMMAND_PREFIX}npcedit", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
|
||||
|
||||
fun all(): Iterable<Permission> = this.permissions
|
||||
|
||||
private fun create(node: String, level: PermissionLevel): Permission {
|
||||
|
||||
@@ -168,7 +168,7 @@ object PokeBalls : JsonDataRegistry<PokeBall> {
|
||||
createDefault("fast_ball", BaseStatModifier(Stats.SPEED, { it >= 100 }, 4F))
|
||||
createDefault("level_ball", CatchRateModifiers.LEVEL)
|
||||
// ToDo we will need fishing context here once fishing is implemented for a multiplier
|
||||
createDefault("lure_ball", CatchRateModifiers.typeBoosting(2F, ElementalTypes.WATER))
|
||||
createDefault("lure_ball", CatchRateModifiers.LURE)
|
||||
createDefault("heavy_ball", CatchRateModifiers.WEIGHT_BASED)
|
||||
createDefault("love_ball", CatchRateModifiers.LOVE)
|
||||
createDefault("friend_ball", effects = listOf(CaptureEffects.friendshipSetter(150)))
|
||||
|
||||
+13
@@ -11,6 +11,7 @@ package com.cobblemon.mod.common.api.pokeball.catching.modifiers
|
||||
import com.cobblemon.mod.common.api.pokeball.PokeBalls
|
||||
import com.cobblemon.mod.common.api.pokeball.catching.CatchRateModifier
|
||||
import com.cobblemon.mod.common.api.pokemon.status.Status
|
||||
import com.cobblemon.mod.common.api.spawning.fishing.FishingSpawnCause
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonBiomeTags
|
||||
import com.cobblemon.mod.common.api.types.ElementalType
|
||||
import com.cobblemon.mod.common.battles.BattleRegistry
|
||||
@@ -121,6 +122,18 @@ object CatchRateModifiers {
|
||||
1F
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by [PokeBalls.LURE_BALL].
|
||||
* Checks if the entity has an aspect for being spawned from fishing.
|
||||
* If yes boosts the catch rate by *4
|
||||
*/
|
||||
val LURE = WorldStateModifier { _, entity ->
|
||||
if (FishingSpawnCause.FISHED_ASPECT in entity.aspects)
|
||||
4f
|
||||
else
|
||||
1F
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by [PokeBalls.HEAVY_BALL].
|
||||
* The base implementation of the heavy ball modifier mechanics.
|
||||
|
||||
@@ -59,9 +59,9 @@ open class PokemonProperties {
|
||||
val props = PokemonProperties()
|
||||
props.originalString = string
|
||||
val keyPairs = string.splitMap(delimiter, assigner)
|
||||
props.customProperties = CustomPokemonProperty.properties.mapNotNull { property ->
|
||||
val matchedKeyPair = keyPairs.find { it.first.lowercase() in property.keys }
|
||||
if (matchedKeyPair == null) {
|
||||
props.customProperties = CustomPokemonProperty.properties.flatMap { property ->
|
||||
val matchedKeyPairs = keyPairs.filter { it.first.lowercase() in property.keys }
|
||||
if (matchedKeyPairs.isEmpty()) {
|
||||
if (!property.needsKey) {
|
||||
var savedProperty: CustomPokemonProperty? = null
|
||||
val keyPair = keyPairs.find { keyPair ->
|
||||
@@ -71,13 +71,20 @@ open class PokemonProperties {
|
||||
if (keyPair != null) {
|
||||
keyPairs.remove(keyPair)
|
||||
}
|
||||
return@mapNotNull savedProperty
|
||||
return@flatMap savedProperty?.let { listOf(it) } ?: emptyList()
|
||||
} else {
|
||||
return@mapNotNull null
|
||||
return@flatMap emptyList()
|
||||
}
|
||||
} else {
|
||||
keyPairs.remove(matchedKeyPair)
|
||||
return@mapNotNull property.fromString(matchedKeyPair.second)
|
||||
val properties = mutableListOf<CustomPokemonProperty>()
|
||||
for ((customKey, customValue) in matchedKeyPairs) {
|
||||
val property = property.fromString(customValue)
|
||||
keyPairs.remove(customKey to customValue)
|
||||
if (property != null) {
|
||||
properties.add(property)
|
||||
}
|
||||
}
|
||||
return@flatMap properties
|
||||
}
|
||||
}.toMutableList()
|
||||
props.gender = Gender.values().toList().parsePropertyOfCollection(keyPairs, listOf("gender"), labelsOptional = true) { it.name.lowercase() }
|
||||
|
||||
@@ -96,7 +96,7 @@ object PokemonSpecies : JsonDataRegistry<Species> {
|
||||
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Item::class.java).type, ItemLikeConditionAdapter)
|
||||
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Structure::class.java).type, StructureLikeConditionAdapter)
|
||||
.registerTypeAdapter(EggGroup::class.java, EggGroupAdapter)
|
||||
.registerTypeAdapter(StatusEffect::class.java, RegistryElementAdapter<StatusEffect> { Registries.STATUS_EFFECT })
|
||||
.registerTypeAdapter(StatusEffect::class.java, RegistryElementAdapter<StatusEffect>(Registries::STATUS_EFFECT))
|
||||
.registerTypeAdapter(NbtItemPredicate::class.java, NbtItemPredicateAdapter)
|
||||
.disableHtmlEscaping()
|
||||
.enableComplexMapKeySerialization()
|
||||
|
||||
@@ -51,6 +51,7 @@ enum class Stats(override val identifier: Identifier, override val displayName:
|
||||
|
||||
/** Gets the [Stat] from the respective Showdown id. */
|
||||
fun getStat(statKey: String) = when(statKey) {
|
||||
"hp" -> HP
|
||||
"atk" -> ATTACK
|
||||
"def" -> DEFENCE
|
||||
"spa" -> SPECIAL_ATTACK
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.scheduling
|
||||
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
/**
|
||||
* An interface for which an implementation must provide a [SchedulingTracker] so that the standard scheduling
|
||||
* functions can be executed.
|
||||
@@ -52,5 +54,13 @@ interface Schedulable {
|
||||
}
|
||||
}
|
||||
|
||||
fun delayedFuture(seconds: Float): CompletableFuture<Unit> {
|
||||
val future = CompletableFuture<Unit>()
|
||||
after(seconds = seconds) {
|
||||
future.complete(Unit)
|
||||
}
|
||||
return future
|
||||
}
|
||||
|
||||
fun taskBuilder(): ScheduledTask.Builder = ScheduledTask.Builder().tracker(schedulingTracker)
|
||||
}
|
||||
+10
-1
@@ -9,6 +9,7 @@
|
||||
package com.cobblemon.mod.common.api.scheduling
|
||||
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import com.cobblemon.mod.common.util.runOnServer
|
||||
|
||||
@Deprecated("Use afterOnServer or afterOnClient; ambiguous side is not good for your health")
|
||||
@JvmOverloads
|
||||
@@ -45,4 +46,12 @@ fun lerp(seconds: Float = 0F, serverThread: Boolean = false, action: (Float) ->
|
||||
fun lerpOnServer(seconds: Float = 0F, action: (Float) -> Unit) = ServerTaskTracker.lerp(seconds = seconds, action = action)
|
||||
@JvmOverloads
|
||||
fun lerpOnClient(seconds: Float = 0F, action: (Float) -> Unit) = ClientTaskTracker.lerp(seconds = seconds, action = action)
|
||||
fun taskBuilder() = ScheduledTask.Builder()
|
||||
fun taskBuilder() = ScheduledTask.Builder()
|
||||
|
||||
fun delayedFuture(seconds: Float): CompletableFuture<Unit> {
|
||||
val future = CompletableFuture<Unit>()
|
||||
afterOnServer(seconds = seconds) {
|
||||
future.complete(Unit)
|
||||
}
|
||||
return future
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.scripting
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.bedrockk.molang.runtime.value.MoValue
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
|
||||
import com.cobblemon.mod.common.api.data.DataRegistry
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.net.messages.client.data.ScriptRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.endsWith
|
||||
import java.io.File
|
||||
import java.util.concurrent.ExecutionException
|
||||
import net.minecraft.resource.ResourceManager
|
||||
import net.minecraft.resource.ResourceType
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
object CobblemonScripts : DataRegistry {
|
||||
const val MOLANG_EXTENSION = ".molang"
|
||||
override val id = cobblemonResource("molang")
|
||||
override val type = ResourceType.SERVER_DATA
|
||||
override val observable = SimpleObservable<CobblemonScripts>()
|
||||
|
||||
val clientScripts = mutableMapOf<Identifier, ExpressionLike>()
|
||||
val scripts = mutableMapOf<Identifier, ExpressionLike>()
|
||||
|
||||
override fun reload(manager: ResourceManager) {
|
||||
manager.findResources("molang") { path -> path.endsWith(MOLANG_EXTENSION) }.forEach { (identifier, resource) ->
|
||||
resource.inputStream.use { stream ->
|
||||
stream.bufferedReader().use { reader ->
|
||||
val resolvedIdentifier = Identifier(identifier.namespace, File(identifier.path).nameWithoutExtension)
|
||||
try {
|
||||
val expression = reader.readText().asExpressionLike()
|
||||
if (identifier.path.startsWith("molang/client/")) {
|
||||
clientScripts[resolvedIdentifier] = expression
|
||||
} else {
|
||||
scripts[resolvedIdentifier] = expression
|
||||
}
|
||||
} catch (exception: Exception) {
|
||||
throw ExecutionException("Error loading MoLang script: $identifier", exception)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Cobblemon.LOGGER.info("Loaded ${scripts.size} server scripts and ${clientScripts.size} client scripts")
|
||||
observable.emit(this)
|
||||
}
|
||||
|
||||
|
||||
override fun sync(player: ServerPlayerEntity) {
|
||||
player.sendPacket(ScriptRegistrySyncPacket(clientScripts.entries))
|
||||
}
|
||||
|
||||
fun run(identifier: Identifier, runtime: MoLangRuntime): MoValue? {
|
||||
return scripts[identifier]?.resolve(runtime)
|
||||
}
|
||||
}
|
||||
@@ -12,11 +12,13 @@ import com.cobblemon.mod.common.Cobblemon.LOGGER
|
||||
import com.cobblemon.mod.common.api.entity.Despawner
|
||||
import com.cobblemon.mod.common.api.spawning.condition.AreaSpawningCondition
|
||||
import com.cobblemon.mod.common.api.spawning.condition.BasicSpawningCondition
|
||||
import com.cobblemon.mod.common.api.spawning.condition.FishingSpawningCondition
|
||||
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.FishingSpawningContext
|
||||
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
|
||||
@@ -29,9 +31,11 @@ import com.cobblemon.mod.common.api.spawning.context.calculators.SeafloorSpawnin
|
||||
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.NPCSpawnDetail
|
||||
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
|
||||
import com.cobblemon.mod.common.api.spawning.fishing.FishingSpawner
|
||||
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
|
||||
@@ -83,6 +87,7 @@ object BestSpawner {
|
||||
var config = BestSpawnerConfig()
|
||||
val spawnerManagers = mutableListOf<SpawnerManager>(CobblemonWorldSpawnerManager)
|
||||
var defaultPokemonDespawner: Despawner<PokemonEntity> = CobblemonAgingDespawner(getAgeTicks = { it.ticksLived })
|
||||
lateinit var fishingSpawner: FishingSpawner
|
||||
|
||||
fun loadConfig() {
|
||||
LOGGER.info("Starting the Best Spawner...")
|
||||
@@ -91,6 +96,7 @@ object BestSpawner {
|
||||
SpawningCondition.register(SubmergedSpawningCondition.NAME, SubmergedSpawningCondition::class.java)
|
||||
SpawningCondition.register(GroundedSpawningCondition.NAME, GroundedSpawningCondition::class.java)
|
||||
SpawningCondition.register(SurfaceSpawningCondition.NAME, SurfaceSpawningCondition::class.java)
|
||||
SpawningCondition.register(FishingSpawningCondition.NAME, FishingSpawningCondition::class.java)
|
||||
|
||||
LOGGER.info("Loaded ${SpawningCondition.conditionTypes.size} spawning condition types.")
|
||||
SpawningContextCalculator.register(GroundedSpawningContextCalculator)
|
||||
@@ -104,10 +110,12 @@ object BestSpawner {
|
||||
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)
|
||||
SpawningContext.register(name = "fishing", clazz = FishingSpawningContext::class.java, defaultCondition = FishingSpawningCondition.NAME)
|
||||
|
||||
LOGGER.info("Loaded ${SpawningContext.contexts.size} spawning context types.")
|
||||
|
||||
SpawnDetail.registerSpawnType(name = PokemonSpawnDetail.TYPE, PokemonSpawnDetail::class.java)
|
||||
SpawnDetail.registerSpawnType(name = NPCSpawnDetail.TYPE, NPCSpawnDetail::class.java)
|
||||
LOGGER.info("Loaded ${SpawnDetail.spawnDetailTypes.size} spawn detail types.")
|
||||
|
||||
config = BestSpawnerConfig.load()
|
||||
@@ -118,5 +126,6 @@ object BestSpawner {
|
||||
|
||||
fun onServerStarted() {
|
||||
spawnerManagers.forEach(SpawnerManager::onServerStarted)
|
||||
fishingSpawner = FishingSpawner()
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ package com.cobblemon.mod.common.api.spawning
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.api.data.JsonDataRegistry
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.api.spawning.condition.SpawningCondition
|
||||
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
|
||||
@@ -24,6 +25,7 @@ import com.cobblemon.mod.common.api.spawning.rules.selector.ExpressionSpawningCo
|
||||
import com.cobblemon.mod.common.api.spawning.rules.selector.SpawnDetailSelector
|
||||
import com.cobblemon.mod.common.api.spawning.rules.selector.SpawningContextSelector
|
||||
import com.cobblemon.mod.common.util.adapters.ExpressionAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.ExpressionLikeAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.SpawnDetailSelectorAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.SpawnRuleComponentAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.SpawningConditionAdapter
|
||||
@@ -50,6 +52,7 @@ object CobblemonSpawnRules : JsonDataRegistry<SpawnRule> {
|
||||
.registerTypeAdapter(SpawningContextSelector::class.java, SpawningContextSelectorAdapter)
|
||||
.registerTypeAdapter(SpawningCondition::class.java, SpawningConditionAdapter)
|
||||
.registerTypeAdapter(Expression::class.java, ExpressionAdapter)
|
||||
.registerTypeAdapter(ExpressionLike::class.java, ExpressionLikeAdapter)
|
||||
.registerTypeAdapter(Text::class.java, TextAdapter)
|
||||
.create()
|
||||
|
||||
|
||||
@@ -8,11 +8,22 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.spawning
|
||||
|
||||
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.Spawner
|
||||
import com.cobblemon.mod.common.util.server
|
||||
import net.minecraft.entity.Entity
|
||||
import net.minecraft.entity.EntityType
|
||||
|
||||
open class SpawnCause(
|
||||
val spawner: Spawner,
|
||||
val bucket: SpawnBucket,
|
||||
val entity: Entity? = null
|
||||
)
|
||||
entity: Entity? = null
|
||||
): SpawningInfluence {
|
||||
val entityWorldId = entity?.world?.registryKey
|
||||
val entityId = entity?.id
|
||||
val entityUUID = entity?.uuid
|
||||
val entityType = entity?.type
|
||||
|
||||
val entity: Entity?
|
||||
get() = if (entityType == EntityType.PLAYER) server()?.playerManager?.getPlayer(entityUUID) else server()?.getWorld(entityWorldId)?.getEntityById(entityId!!)
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.FishingSpawningContext
|
||||
import com.cobblemon.mod.common.util.itemRegistry
|
||||
import net.minecraft.block.Block
|
||||
import net.minecraft.item.Item
|
||||
|
||||
/**
|
||||
* A spawning condition that applies to [FishingSpawningContext]s.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since February 3rd, 2024
|
||||
*/
|
||||
class FishingSpawningCondition: SpawningCondition<FishingSpawningContext>() {
|
||||
override fun contextClass() = FishingSpawningContext::class.java
|
||||
|
||||
var rod: RegistryLikeCondition<Item>? = null
|
||||
var neededNearbyBlocks: MutableList<RegistryLikeCondition<Block>>? = null
|
||||
|
||||
override fun fits(ctx: FishingSpawningContext): Boolean {
|
||||
if (!super.fits(ctx)) {
|
||||
return false
|
||||
} else if (rod != null && !rod!!.fits(ctx.rodItem ?: return false, ctx.world.itemRegistry)) {
|
||||
return false
|
||||
} else if (neededNearbyBlocks != null && neededNearbyBlocks!!.none { cond -> ctx.nearbyBlockTypes.any { cond.fits(it, ctx.blockRegistry) } }) {
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val NAME = "fishing"
|
||||
}
|
||||
}
|
||||
+35
@@ -11,12 +11,17 @@ 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.context.FishingSpawningContext
|
||||
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
|
||||
import com.cobblemon.mod.common.item.interactive.PokerodItem
|
||||
import com.cobblemon.mod.common.util.Merger
|
||||
import com.cobblemon.mod.common.util.math.orMax
|
||||
import com.cobblemon.mod.common.util.math.orMin
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.enchantment.EnchantmentHelper
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.registry.Registries
|
||||
import net.minecraft.registry.tag.TagKey
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.world.biome.Biome
|
||||
@@ -56,6 +61,10 @@ abstract class SpawningCondition<T : SpawningContext> {
|
||||
var isThundering: Boolean? = null
|
||||
var timeRange: TimeRange? = null
|
||||
var structures: MutableList<Either<Identifier, TagKey<Structure>>>? = null
|
||||
var minLureLevel: Int? = null
|
||||
var maxLureLevel: Int? = null
|
||||
var bait: String? = null
|
||||
var rodType: String? = null
|
||||
|
||||
@Transient
|
||||
var appendages = mutableListOf<AppendageCondition>()
|
||||
@@ -108,8 +117,34 @@ abstract class SpawningCondition<T : SpawningContext> {
|
||||
}
|
||||
) {
|
||||
return false
|
||||
} else if (minLureLevel != null && ctx is FishingSpawningContext) { // check for the lureLevel of the rod
|
||||
val pokerodStack = (ctx as FishingSpawningContext).rodStack
|
||||
|
||||
if (EnchantmentHelper.getLure(pokerodStack) < minLureLevel!!)
|
||||
return false
|
||||
if (maxLureLevel != null && EnchantmentHelper.getLure(pokerodStack) > maxLureLevel!!)
|
||||
return false
|
||||
} else if (bait != null && ctx is FishingSpawningContext) { // check for the bait on the bobber
|
||||
val pokerodBait = (ctx as FishingSpawningContext).rodBait
|
||||
|
||||
if (Registries.ITEM.getId(PokerodItem.getBait(pokerodBait)?.item).path != bait)
|
||||
return false
|
||||
} else if (rodType != null && ctx is FishingSpawningContext) { // check for the type of pokerod being used
|
||||
val pokerodItem = (ctx as FishingSpawningContext).rodItem
|
||||
|
||||
if (pokerodItem?.pokeRodId?.path != rodType)
|
||||
return false
|
||||
}
|
||||
|
||||
/*else if (ctx is FishingSpawningContext && (ctx as FishingSpawningContext).rodItem != null) { // check if the bait attracts certain EV yields
|
||||
val pokerodItem = (ctx as FishingSpawningContext).rodItem
|
||||
|
||||
// todo check if the EV yield of the berry matches the bait EV attract maybe?
|
||||
|
||||
if (// todo if bait EV yield != EV yield of pokemon consideration //Registries.ITEM.getId(pokerodItem?.bait?.item).path == )
|
||||
return false
|
||||
}*/
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
+51
-3
@@ -56,9 +56,10 @@ interface AreaContextResolver {
|
||||
if (context != null) {
|
||||
contexts.add(context)
|
||||
// The position BlockPos has been used in a context, editing the same one
|
||||
// will cause entities to spawn at the wrong location (buried in walls, usually)
|
||||
// I made it so that our context calculators specifically take a copy of the
|
||||
// BlockPos but it'd still be exposed in custom contexts so fixing it here too.
|
||||
// will cause entities to spawn at the wrong location (buried in walls, usually).
|
||||
// I made it so that built-in context calculators explicitly take a copy of the
|
||||
// BlockPos but it'd still be exposed in custom contexts so fixing it here too so
|
||||
// custom context calculators don't have to remember to do it. - Hiroku
|
||||
pos = BlockPos.Mutable(1, 2, 3)
|
||||
input.position = pos
|
||||
}
|
||||
@@ -76,4 +77,51 @@ interface AreaContextResolver {
|
||||
|
||||
return contexts
|
||||
}
|
||||
|
||||
// fun resolveFishing(
|
||||
// spawner: Spawner,
|
||||
// contextCalculators: List<AreaSpawningContextCalculator<*>>,
|
||||
// slice: WorldSlice
|
||||
// ): List<AreaSpawningContext> {
|
||||
// var pos = BlockPos.Mutable(1, 2, 3)
|
||||
// val input = AreaSpawningInput(spawner, pos, slice)
|
||||
// val contexts = mutableListOf<AreaSpawningContext>()
|
||||
//
|
||||
// var x = slice.baseX
|
||||
// var y = slice.baseY
|
||||
// var z = slice.baseZ
|
||||
//
|
||||
// while (x < slice.baseX + slice.length) {
|
||||
// while (y < slice.baseY + slice.height) {
|
||||
// while (z < slice.baseZ + slice.width) {
|
||||
// pos.set(x, y, z)
|
||||
// val vec = pos.toVec3d()
|
||||
// if (slice.nearbyEntityPositions.none { it.isInRange(vec, 50.0) && it != slice.cause.entity }) {
|
||||
// val fittedContextCalculator = contextCalculators
|
||||
// .firstOrNull { calc -> calc.fits(input) && input.spawner.influences.none { !it.isAllowedPosition(input.world, input.position, calc) } }
|
||||
// if (fittedContextCalculator != null) {
|
||||
// val context = fittedContextCalculator.calculate(input)
|
||||
// if (context != null) {
|
||||
// contexts.add(context)
|
||||
// // The position BlockPos has been used in a context, editing the same one
|
||||
// // will cause entities to spawn at the wrong location (buried in walls, usually)
|
||||
// // I made it so that our context calculators specifically take a copy of the
|
||||
// // BlockPos but it'd still be exposed in custom contexts so fixing it here too.
|
||||
// pos = BlockPos.Mutable(1, 2, 3)
|
||||
// input.position = pos
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// z++
|
||||
// }
|
||||
// y++
|
||||
// z = slice.baseZ
|
||||
// }
|
||||
// x++
|
||||
// y = slice.baseY
|
||||
// z = slice.baseZ
|
||||
// }
|
||||
//
|
||||
// return contexts
|
||||
// }
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.context
|
||||
|
||||
import com.cobblemon.mod.common.api.spawning.fishing.FishingSpawnCause
|
||||
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
|
||||
import com.cobblemon.mod.common.util.getBlockStates
|
||||
import com.cobblemon.mod.common.util.toVec3d
|
||||
import net.minecraft.block.Block
|
||||
import net.minecraft.server.world.ServerWorld
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import net.minecraft.util.math.Box
|
||||
|
||||
/**
|
||||
* A spawning context that was generated for a fishing action.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since February 3rd, 2024
|
||||
*/
|
||||
class FishingSpawningContext(
|
||||
cause: FishingSpawnCause,
|
||||
world: ServerWorld,
|
||||
pos: BlockPos,
|
||||
influences: MutableList<SpawningInfluence>
|
||||
) : TriggerSpawningContext(
|
||||
cause = cause,
|
||||
world = world,
|
||||
position = pos,
|
||||
light = world.getLightLevel(pos),
|
||||
skyLight = world.getLightLevel(pos.up()),
|
||||
canSeeSky = world.isSkyVisibleAllowingSea(pos),
|
||||
influences = influences
|
||||
) {
|
||||
val nearbyBlocks = world.getBlockStates(Box.of(pos.toVec3d(), 10.0, 10.0, 10.0))
|
||||
val nearbyBlockTypes: List<Block> by lazy { nearbyBlocks.mapNotNull { it.block }.distinct() }
|
||||
val rodStack = cause.rodStack
|
||||
val rodItem = cause.rodItem
|
||||
val rodBait = cause.bait
|
||||
}
|
||||
+34
-6
@@ -68,7 +68,7 @@ abstract class SpawningContext {
|
||||
abstract val skyLight: Int
|
||||
/** Whether or not the sky is visible at this location. */
|
||||
abstract val canSeeSky: Boolean
|
||||
/** A list of [SpawningInfluence]s that apply due to this specific context. */
|
||||
/** A list of [SpawningInfluence]s that apply due to this specific context. This generally shouldn't be consumed; use [getAllInfluences].*/
|
||||
abstract val influences: MutableList<SpawningInfluence>
|
||||
/** Gets a cache of structures by block coordinates, grouped by chunk. */
|
||||
abstract fun getStructureCache(pos: BlockPos): StructureChunkCache
|
||||
@@ -147,7 +147,7 @@ abstract class SpawningContext {
|
||||
*/
|
||||
open fun preFilter(detail: SpawnDetail): Boolean {
|
||||
/** Returns true if none of the influences.affectSpawnable return false */
|
||||
return influences.none { !it.affectSpawnable(detail, this) }
|
||||
return !anyForInfluences { !it.affectSpawnable(detail, this) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -157,14 +157,12 @@ abstract class SpawningContext {
|
||||
open fun postFilter(detail: SpawnDetail): Boolean = true
|
||||
|
||||
open fun afterSpawn(entity: Entity) {
|
||||
influences.forEach { it.affectSpawn(entity) }
|
||||
applyInfluences { it.affectSpawn(entity) }
|
||||
}
|
||||
|
||||
open fun getWeight(detail: SpawnDetail): Float {
|
||||
var weight = detail.weight
|
||||
for (influence in influences + detail.weightMultipliers) {
|
||||
weight = influence.affectWeight(detail, this, weight)
|
||||
}
|
||||
applyInfluences(extraInfluences = detail.weightMultipliers) { weight = it.affectWeight(detail, this, weight) }
|
||||
return weight
|
||||
}
|
||||
|
||||
@@ -184,4 +182,34 @@ abstract class SpawningContext {
|
||||
structCompiled = true
|
||||
return struct
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all influences that apply to this context, including the cause, and does something with them.
|
||||
*
|
||||
* Technically we could simple make a list of influences + cause and run that, but influences MUST be able
|
||||
* to run extremely frequently in performance-critical code, so we don't want to have to allocate a list.
|
||||
*/
|
||||
fun applyInfluences(extraInfluences: List<SpawningInfluence>? = null, usage: (SpawningInfluence) -> Unit) {
|
||||
influences.forEach(usage)
|
||||
usage(cause)
|
||||
extraInfluences?.forEach(usage)
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates through every operable influence to find if any match the predicate.
|
||||
*/
|
||||
fun anyForInfluences(extraInfluences: List<SpawningInfluence>? = null, usage: (SpawningInfluence) -> Boolean): Boolean {
|
||||
if (influences.any(usage)) {
|
||||
return true
|
||||
}
|
||||
if (usage(cause)) {
|
||||
return true
|
||||
}
|
||||
extraInfluences?.forEach {
|
||||
if (usage(it)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.context
|
||||
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnCause
|
||||
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
|
||||
import net.minecraft.server.world.ServerWorld
|
||||
import net.minecraft.util.math.BlockPos
|
||||
|
||||
/**
|
||||
* A spawning context relating to triggered spawning. Uses a single-point structure cache which is
|
||||
* the only contribution of this implementation.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since February 3rd, 2024
|
||||
*/
|
||||
open class TriggerSpawningContext(
|
||||
override val cause: SpawnCause,
|
||||
override val world: ServerWorld,
|
||||
override val position: BlockPos,
|
||||
override val light: Int,
|
||||
override val skyLight: Int,
|
||||
override val canSeeSky: Boolean,
|
||||
override val influences: MutableList<SpawningInfluence>
|
||||
) : SpawningContext() {
|
||||
val triggerStructureCache = StructureChunkCache()
|
||||
override fun getStructureCache(pos: BlockPos) = triggerStructureCache
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.detail
|
||||
|
||||
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
|
||||
import com.cobblemon.mod.common.entity.npc.NPCEntity
|
||||
|
||||
/**
|
||||
* A [SpawnAction] for creating [NPCEntity]s.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since October 8th, 2023
|
||||
*/
|
||||
class NPCSpawnAction(ctx: SpawningContext, override val detail: NPCSpawnDetail) : SpawnAction<NPCEntity>(ctx, detail) {
|
||||
override fun run(): NPCEntity {
|
||||
val npc = NPCEntity(ctx.world)
|
||||
npc.npc = detail.npcClass
|
||||
npc.appliedAspects.addAll(detail.aspects)
|
||||
return npc
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.detail
|
||||
|
||||
import com.cobblemon.mod.common.api.npc.NPCClass
|
||||
import com.cobblemon.mod.common.api.npc.NPCConfiguration
|
||||
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
|
||||
import com.cobblemon.mod.common.entity.npc.NPCEntity
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
/**
|
||||
* A [SpawnDetail] describing an [NPCEntity] spawn.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since October 8th, 2023
|
||||
*/
|
||||
class NPCSpawnDetail : SpawnDetail() {
|
||||
companion object {
|
||||
val TYPE = "npc"
|
||||
val blankClass = NPCClass()
|
||||
}
|
||||
|
||||
override val type = TYPE
|
||||
|
||||
@SerializedName(value = "npcClass", alternate = ["class", "npc"])
|
||||
val npcClass: NPCClass = blankClass
|
||||
val configuration: NPCConfiguration? = null
|
||||
val aspects: Set<String> = emptySet()
|
||||
|
||||
override fun doSpawn(ctx: SpawningContext) = NPCSpawnAction(ctx, this)
|
||||
}
|
||||
+1
@@ -45,6 +45,7 @@ class PokemonSpawnAction(
|
||||
null
|
||||
}?.createStack(ctx)
|
||||
val entity = props.createEntity(ctx.world)
|
||||
entity.spawnCause = ctx.cause
|
||||
SeasonFeatureHandler.updateSeason(entity.pokemon, Cobblemon.seasonResolver(ctx.world, ctx.position))
|
||||
if (heldItem != null) {
|
||||
entity.pokemon.swapHeldItem(heldItem)
|
||||
|
||||
@@ -39,7 +39,7 @@ abstract class SpawnAction<R>(
|
||||
return null
|
||||
}
|
||||
|
||||
ctx.influences.forEach { it.affectAction(this) }
|
||||
ctx.applyInfluences { it.affectAction(this) }
|
||||
val result = run()
|
||||
if (result != null) {
|
||||
future.complete(result)
|
||||
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.fishing
|
||||
|
||||
import com.cobblemon.mod.common.api.fishing.FishingBait
|
||||
import com.cobblemon.mod.common.api.fishing.FishingBaits
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnBucket
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnCause
|
||||
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
|
||||
import com.cobblemon.mod.common.api.spawning.detail.PokemonSpawnDetail
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.Spawner
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.item.interactive.PokerodItem
|
||||
import com.cobblemon.mod.common.pokemon.Species
|
||||
import net.minecraft.entity.Entity
|
||||
import net.minecraft.item.FishingRodItem
|
||||
import net.minecraft.item.ItemStack
|
||||
|
||||
/**
|
||||
* A spawning cause that is embellished with fishing information. Could probably also
|
||||
* have the bobber entity or something.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since February 3rd, 2024
|
||||
*/
|
||||
class FishingSpawnCause(
|
||||
spawner: Spawner,
|
||||
bucket: SpawnBucket,
|
||||
entity: Entity?,
|
||||
val rodStack: ItemStack
|
||||
) : SpawnCause(spawner, bucket, entity) {
|
||||
companion object {
|
||||
const val FISHED_ASPECT = "fished"
|
||||
}
|
||||
|
||||
val rodItem = rodStack.item as? PokerodItem
|
||||
val bait = PokerodItem.getBait(rodStack)
|
||||
|
||||
override fun affectSpawn(entity: Entity) {
|
||||
super.affectSpawn(entity)
|
||||
if (entity is PokemonEntity) {
|
||||
entity.pokemon.forcedAspects += FISHED_ASPECT
|
||||
}
|
||||
}
|
||||
|
||||
override fun affectWeight(detail: SpawnDetail, ctx: SpawningContext, weight: Float): Float {
|
||||
if (!ItemStack.areItemsEqual(ItemStack.EMPTY, bait) && bait != null ){
|
||||
val bait = FishingBaits.getFromItemStack(bait)
|
||||
|
||||
if (detail is PokemonSpawnDetail) {
|
||||
val detailSpecies = detail.pokemon.species?.let { PokemonSpecies.getByName(it) }
|
||||
|
||||
val baitEVEffect = bait!!.effects.firstOrNull() { it.type == FishingBait.Effects.EV && detailSpecies?.evYield?.get(Stats.getStat(it.subcategory?.path.toString()))!! > 0 }
|
||||
|
||||
if(detailSpecies != null && baitEVEffect != null) {
|
||||
return super.affectWeight(detail, ctx, weight * baitEVEffect.value.toFloat())
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.affectWeight(detail, ctx, weight)
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.fishing
|
||||
|
||||
import com.cobblemon.mod.common.api.spawning.CobblemonSpawnPools
|
||||
import com.cobblemon.mod.common.api.spawning.context.FishingSpawningContext
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnPool
|
||||
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.TriggerSpawner
|
||||
import net.minecraft.server.world.ServerWorld
|
||||
import net.minecraft.util.math.BlockPos
|
||||
|
||||
/**
|
||||
* A spawner that takes in a [FishingSpawnCause] and spawns things.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since February 3rd, 2024
|
||||
*/
|
||||
open class FishingSpawner(
|
||||
override val name: String = "fishing",
|
||||
pool: SpawnPool = CobblemonSpawnPools.WORLD_SPAWN_POOL
|
||||
) : TriggerSpawner<FishingSpawnCause>(name, pool) {
|
||||
override fun parseContext(cause: FishingSpawnCause, world: ServerWorld, pos: BlockPos): FishingSpawningContext? {
|
||||
// Maybe confirm that it's water we're fishing in?
|
||||
val ctx = FishingSpawningContext(
|
||||
cause = cause,
|
||||
world = world,
|
||||
pos = pos,
|
||||
influences = influences
|
||||
)
|
||||
return ctx
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -19,6 +19,7 @@ import com.cobblemon.mod.common.api.molang.ObjectValue
|
||||
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
|
||||
import com.cobblemon.mod.common.api.spawning.context.calculators.SpawningContextCalculator
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import net.minecraft.registry.RegistryKeys
|
||||
import net.minecraft.registry.entry.RegistryEntry
|
||||
@@ -49,7 +50,7 @@ class LocationRuleCalculator : SpawnRuleComponent {
|
||||
@Transient
|
||||
private lateinit var reusableDimensionTypeValue: ObjectValue<RegistryEntry<DimensionType>>
|
||||
|
||||
val allow = "true".asExpression()
|
||||
val allow = "true".asExpressionLike()
|
||||
|
||||
override fun isAllowedPosition(
|
||||
world: ServerWorld,
|
||||
|
||||
+2
-1
@@ -19,6 +19,7 @@ import com.cobblemon.mod.common.api.spawning.rules.selector.AllSpawningContextSe
|
||||
import com.cobblemon.mod.common.api.spawning.rules.selector.SpawnDetailSelector
|
||||
import com.cobblemon.mod.common.api.spawning.rules.selector.SpawningContextSelector
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.resolveFloat
|
||||
|
||||
/**
|
||||
@@ -30,7 +31,7 @@ import com.cobblemon.mod.common.util.resolveFloat
|
||||
class WeightTweakRuleComponent : SpawnRuleComponent {
|
||||
val spawnSelector: SpawnDetailSelector = AllSpawnDetailSelector
|
||||
val contextSelector: SpawningContextSelector = AllSpawningContextSelector
|
||||
val weight: Expression = "v.weight".asExpression()
|
||||
val weight = "v.weight".asExpressionLike()
|
||||
|
||||
@Transient
|
||||
val runtime = MoLangRuntime().setup()
|
||||
|
||||
+2
-1
@@ -12,12 +12,13 @@ import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
|
||||
class ExpressionSpawnDetailSelector : SpawnDetailSelector {
|
||||
@Transient
|
||||
val runtime = MoLangRuntime().setup()
|
||||
var expression = "true".asExpression()
|
||||
var expression = "true".asExpressionLike()
|
||||
|
||||
override fun selects(spawnDetail: SpawnDetail): Boolean {
|
||||
runtime.environment.setSimpleVariable("spawn", spawnDetail.struct)
|
||||
|
||||
+2
-1
@@ -12,12 +12,13 @@ import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
|
||||
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
|
||||
class ExpressionSpawningContextSelector : SpawningContextSelector {
|
||||
@Transient
|
||||
val runtime = MoLangRuntime().setup()
|
||||
var expression = "true".asExpression()
|
||||
var expression = "true".asExpressionLike()
|
||||
|
||||
override fun selects(ctx: SpawningContext): Boolean {
|
||||
runtime.environment.setSimpleVariable("context", ctx.getOrSetupStruct())
|
||||
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.spawner
|
||||
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnCause
|
||||
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnPool
|
||||
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.selection.FlatContextWeightedSelector
|
||||
import com.cobblemon.mod.common.api.spawning.selection.SpawningSelector
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import net.minecraft.server.world.ServerWorld
|
||||
import net.minecraft.util.math.BlockPos
|
||||
|
||||
/**
|
||||
* A type of spawner that occurs at a single point and provides its own means of generating a
|
||||
* context from a particular cause and position. The trigger spawner must be directly called to
|
||||
* spawn things (almost as if it was being triggered) as opposed to being scheduled on a ticker.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since February 3rd, 2024
|
||||
*/
|
||||
abstract class TriggerSpawner<T : SpawnCause>(override val name: String, var spawns: SpawnPool) : Spawner {
|
||||
private var selector: SpawningSelector = FlatContextWeightedSelector()
|
||||
override val influences = mutableListOf<SpawningInfluence>()
|
||||
|
||||
open fun run(cause: T, world: ServerWorld, pos: BlockPos): CompletableFuture<*>? {
|
||||
val context = parseContext(cause, world, pos) ?: return null
|
||||
selector.select(this, listOf(context))?.let { (_, spawn) ->
|
||||
val action = spawn.doSpawn(context)
|
||||
action.complete()
|
||||
return action.future
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/** Parses a context, if possible, from the given cause and position. */
|
||||
abstract fun parseContext(cause: T, world: ServerWorld, pos: BlockPos): SpawningContext?
|
||||
|
||||
override fun canSpawn() = true
|
||||
override fun getSpawningSelector() = selector
|
||||
override fun setSpawningSelector(selector: SpawningSelector) { this.selector = selector }
|
||||
override fun getSpawnPool() = spawns
|
||||
override fun setSpawnPool(spawnPool: SpawnPool) { spawns = spawnPool }
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.storage.party
|
||||
|
||||
import com.cobblemon.mod.common.entity.npc.NPCEntity
|
||||
|
||||
class NPCPartyStore(val npc: NPCEntity) : PartyStore(npc.uuid) {
|
||||
val isLiving: Boolean get() = npc.isLiving
|
||||
}
|
||||
@@ -9,19 +9,20 @@
|
||||
package com.cobblemon.mod.common.battles
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
|
||||
import com.cobblemon.mod.common.api.storage.party.PartyStore
|
||||
import com.cobblemon.mod.common.battles.actor.PlayerBattleActor
|
||||
import com.cobblemon.mod.common.battles.actor.PokemonBattleActor
|
||||
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||
import com.cobblemon.mod.common.entity.npc.NPCBattleActor
|
||||
import com.cobblemon.mod.common.entity.npc.NPCEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
import com.cobblemon.mod.common.util.getBattleTheme
|
||||
import com.cobblemon.mod.common.util.getPlayer
|
||||
import com.cobblemon.mod.common.util.party
|
||||
import java.util.Optional
|
||||
import com.cobblemon.mod.common.util.update
|
||||
import java.util.UUID
|
||||
import net.minecraft.entity.Entity
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
@@ -63,6 +64,7 @@ object BattleBuilder {
|
||||
}
|
||||
|
||||
return if (errors.isEmpty) {
|
||||
var result: BattleStartResult = errors
|
||||
BattleRegistry.startBattle(
|
||||
battleFormat = battleFormat,
|
||||
side1 = BattleSide(player1Actor),
|
||||
@@ -70,7 +72,9 @@ object BattleBuilder {
|
||||
).ifSuccessful {
|
||||
player1Actor.battleTheme = player2.getBattleTheme()
|
||||
player2Actor.battleTheme = player1.getBattleTheme()
|
||||
result = SuccessfulBattleStart(it)
|
||||
}
|
||||
result
|
||||
} else {
|
||||
errors
|
||||
}
|
||||
@@ -129,6 +133,7 @@ object BattleBuilder {
|
||||
}
|
||||
|
||||
return if (errors.isEmpty) {
|
||||
var result: BattleStartResult = errors
|
||||
BattleRegistry.startBattle(
|
||||
battleFormat = battleFormat,
|
||||
side1 = BattleSide(playerActor),
|
||||
@@ -138,7 +143,72 @@ object BattleBuilder {
|
||||
pokemonEntity.battleId = it.battleId
|
||||
}
|
||||
playerActor.battleTheme = pokemonEntity.getBattleTheme()
|
||||
result = SuccessfulBattleStart(it)
|
||||
}
|
||||
result
|
||||
} else {
|
||||
errors
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to create a PvE battle against the given Pokémon.
|
||||
*
|
||||
* @param player The player battling the wild Pokémon.
|
||||
* @param pokemonEntity The Pokémon to battle.
|
||||
* @param leadingPokemon The Pokémon in the player's party to send out first. If null, it uses the first in the party.
|
||||
* @param battleFormat The format to use for the battle. By default it is [BattleFormat.GEN_9_SINGLES].
|
||||
* @param cloneParties Whether the player's party should be cloned so that damage will not affect their party afterwards. Defaults to false.
|
||||
* @param healFirst Whether the player's Pokémon should be healed before the battle starts. Defaults to false.
|
||||
* @param fleeDistance How far away the player must get to flee the Pokémon. If the value is -1, it cannot be fled.
|
||||
* @param party The party of the player to use for the battle. This does not need to be their actual party. Defaults to it though.
|
||||
*/
|
||||
@JvmOverloads
|
||||
fun pvn(
|
||||
player: ServerPlayerEntity,
|
||||
npcEntity: NPCEntity,
|
||||
leadingPokemon: UUID? = null,
|
||||
battleFormat: BattleFormat = BattleFormat.GEN_9_SINGLES,
|
||||
cloneParties: Boolean = false,
|
||||
healFirst: Boolean = false,
|
||||
party: PartyStore = player.party()
|
||||
): BattleStartResult {
|
||||
val playerTeam = party.toBattleTeam(clone = cloneParties, checkHealth = !healFirst, leadingPokemon = leadingPokemon)
|
||||
val playerActor = PlayerBattleActor(player.uuid, playerTeam)
|
||||
|
||||
val party = npcEntity.getBattleConfiguration().party?.provide(npcEntity, listOf(player)) ?: TODO("Deal with this issue!")
|
||||
val npcActor = NPCBattleActor(npcEntity, party)
|
||||
val errors = ErroredBattleStart()
|
||||
|
||||
if (playerActor.pokemonList.size < battleFormat.battleType.slotsPerActor) {
|
||||
errors.participantErrors[playerActor] += BattleStartError.insufficientPokemon(
|
||||
player = player,
|
||||
requiredCount = battleFormat.battleType.slotsPerActor,
|
||||
hadCount = playerActor.pokemonList.size
|
||||
)
|
||||
}
|
||||
|
||||
if (BattleRegistry.getBattleByParticipatingPlayer(player) != null) {
|
||||
errors.participantErrors[playerActor] += BattleStartError.alreadyInBattle(playerActor)
|
||||
}
|
||||
|
||||
// if (npcEntity.battleIds.get().isPresent) {
|
||||
// errors.participantErrors[npcActor] += BattleStartError.alreadyInBattle(npcActor)
|
||||
// }
|
||||
|
||||
return if (errors.isEmpty) {
|
||||
var result: BattleStartResult = errors
|
||||
BattleRegistry.startBattle(
|
||||
battleFormat = battleFormat,
|
||||
side1 = BattleSide(playerActor),
|
||||
side2 = BattleSide(npcActor)
|
||||
).ifSuccessful { battle ->
|
||||
// TODO NPC battle themes
|
||||
// playerActor.battleTheme = pokemonEntity.getBattleTheme()
|
||||
npcEntity.dataTracker.update(NPCEntity.BATTLE_IDS) { it + battle.battleId }
|
||||
result = SuccessfulBattleStart(battle)
|
||||
}
|
||||
result
|
||||
} else {
|
||||
errors
|
||||
}
|
||||
|
||||
+23
-9
@@ -11,13 +11,17 @@ package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleContext
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.EntityBackedBattleActor
|
||||
import com.cobblemon.mod.common.api.entity.PokemonSender
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents
|
||||
import com.cobblemon.mod.common.api.events.battles.BattleFaintedEvent
|
||||
import com.cobblemon.mod.common.api.scheduling.delayedFuture
|
||||
import com.cobblemon.mod.common.api.text.red
|
||||
import com.cobblemon.mod.common.battles.ShowdownInterpreter
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleFaintPacket
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
/**
|
||||
* Format: |faint|POKEMON
|
||||
@@ -32,18 +36,28 @@ class FaintInstruction(battle: PokemonBattle, val message: BattleMessage) : Inte
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
|
||||
battle.dispatchWaiting(waitTime) {
|
||||
val (pnx, _) = message.pnxAndUuid(0) ?: return@dispatchWaiting
|
||||
battle.dispatchFuture {
|
||||
val (pnx, _) = message.pnxAndUuid(0) ?: return@dispatchFuture CompletableFuture.completedFuture(Unit)
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return@dispatchFuture CompletableFuture.completedFuture(Unit)
|
||||
battle.sendUpdate(BattleFaintPacket(pnx))
|
||||
faintingPokemon.effectedPokemon.currentHealth = 0
|
||||
faintingPokemon.sendUpdate()
|
||||
val actor = pokemon.actor
|
||||
pokemon.effectedPokemon.currentHealth = 0
|
||||
val preamble = if (actor is EntityBackedBattleActor<*>) {
|
||||
(actor.entity as? PokemonSender)?.let { sender -> pokemon.entity?.recallWithAnimation()}
|
||||
} else {
|
||||
null
|
||||
} ?: delayedFuture(seconds = waitTime)
|
||||
val context = ShowdownInterpreter.getContextFromFaint(faintingPokemon, battle)
|
||||
CobblemonEvents.BATTLE_FAINTED.post(BattleFaintedEvent(battle, faintingPokemon, context))
|
||||
|
||||
battle.getActorAndActiveSlotFromPNX(pnx).second.battlePokemon = null
|
||||
faintingPokemon.contextManager.add(context)
|
||||
faintingPokemon.contextManager.clear(BattleContext.Type.STATUS, BattleContext.Type.VOLATILE, BattleContext.Type.BOOST, BattleContext.Type.UNBOOST)
|
||||
battle.majorBattleActions[faintingPokemon.uuid] = message
|
||||
preamble.thenAccept {
|
||||
faintingPokemon.effectedPokemon.currentHealth = 0
|
||||
faintingPokemon.sendUpdate()
|
||||
CobblemonEvents.BATTLE_FAINTED.post(BattleFaintedEvent(battle, pokemon, context))
|
||||
battle.getActorAndActiveSlotFromPNX(pnx).second.battlePokemon = null
|
||||
faintingPokemon.contextManager.add(context)
|
||||
faintingPokemon.contextManager.clear(BattleContext.Type.STATUS, BattleContext.Type.VOLATILE, BattleContext.Type.BOOST, BattleContext.Type.UNBOOST)
|
||||
battle.majorBattleActions[faintingPokemon.uuid] = message
|
||||
}
|
||||
}
|
||||
battle.dispatchWaiting(0.5F) {
|
||||
val faintMessage = battleLang("fainted", faintingPokemon.getName()).red()
|
||||
|
||||
-1
@@ -13,7 +13,6 @@ import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.Effect
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addFunction
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addStandardFunctions
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.getQueryStruct
|
||||
import com.cobblemon.mod.common.api.moves.Moves
|
||||
|
||||
@@ -10,12 +10,12 @@ package com.cobblemon.mod.common.client
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.Cobblemon.LOGGER
|
||||
import com.cobblemon.mod.common.api.berry.Berries
|
||||
import com.cobblemon.mod.common.CobblemonBlockEntities
|
||||
import com.cobblemon.mod.common.CobblemonBlocks
|
||||
import com.cobblemon.mod.common.CobblemonClientImplementation
|
||||
import com.cobblemon.mod.common.CobblemonEntities
|
||||
import com.cobblemon.mod.common.CobblemonItems
|
||||
import com.cobblemon.mod.common.api.berry.Berries
|
||||
import com.cobblemon.mod.common.api.scheduling.ClientTaskTracker
|
||||
import com.cobblemon.mod.common.api.text.gray
|
||||
import com.cobblemon.mod.common.client.battle.ClientBattle
|
||||
@@ -23,12 +23,13 @@ import com.cobblemon.mod.common.client.gui.PartyOverlay
|
||||
import com.cobblemon.mod.common.client.gui.battle.BattleOverlay
|
||||
import com.cobblemon.mod.common.client.particle.BedrockParticleEffectRepository
|
||||
import com.cobblemon.mod.common.client.render.block.BerryBlockRenderer
|
||||
import com.cobblemon.mod.common.client.render.block.DisplayCaseRenderer
|
||||
import com.cobblemon.mod.common.client.render.block.FossilAnalyzerRenderer
|
||||
import com.cobblemon.mod.common.client.render.block.RestorationTankRenderer
|
||||
import com.cobblemon.mod.common.client.render.block.GildedChestBlockRenderer
|
||||
import com.cobblemon.mod.common.client.render.block.HealingMachineRenderer
|
||||
import com.cobblemon.mod.common.client.render.block.*
|
||||
import com.cobblemon.mod.common.client.render.block.RestorationTankRenderer
|
||||
import com.cobblemon.mod.common.client.render.boat.CobblemonBoatRenderer
|
||||
import com.cobblemon.mod.common.client.render.entity.PokeBobberEntityRenderer
|
||||
import com.cobblemon.mod.common.client.render.generic.GenericBedrockRenderer
|
||||
import com.cobblemon.mod.common.client.render.item.CobblemonBuiltinItemRendererRegistry
|
||||
import com.cobblemon.mod.common.client.render.item.PokemonItemRenderer
|
||||
@@ -36,8 +37,13 @@ import com.cobblemon.mod.common.client.render.layer.PokemonOnShoulderRenderer
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.bedrock.animation.BedrockAnimationRepository
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.repository.BerryModelRepository
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.repository.BlockEntityModelRepository
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.repository.FossilModelRepository
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.repository.GenericBedrockEntityModelRepository
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.repository.MiscModelRepository
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.repository.NPCModelRepository
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.repository.PokeBallModelRepository
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.repository.PokemonModelRepository
|
||||
import com.cobblemon.mod.common.client.render.npc.NPCRenderer
|
||||
import com.cobblemon.mod.common.client.render.pokeball.PokeBallRenderer
|
||||
import com.cobblemon.mod.common.client.render.pokemon.PokemonRenderer
|
||||
import com.cobblemon.mod.common.client.sound.battle.BattleMusicController
|
||||
@@ -47,9 +53,6 @@ import com.cobblemon.mod.common.client.trade.ClientTrade
|
||||
import com.cobblemon.mod.common.data.CobblemonDataProvider
|
||||
import com.cobblemon.mod.common.entity.boat.CobblemonBoatType
|
||||
import com.cobblemon.mod.common.item.PokeBallItem
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.repository.FossilModelRepository
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.repository.GenericBedrockEntityModelRepository
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.repository.MiscModelRepository
|
||||
import com.cobblemon.mod.common.platform.events.PlatformEvents
|
||||
import com.cobblemon.mod.common.util.DataKeys
|
||||
import com.cobblemon.mod.common.util.asTranslated
|
||||
@@ -264,8 +267,14 @@ object CobblemonClient {
|
||||
this.implementation.registerEntityRenderer(CobblemonEntities.BOAT) { ctx -> CobblemonBoatRenderer(ctx, false) }
|
||||
LOGGER.info("Registering Boat with Chest renderer")
|
||||
this.implementation.registerEntityRenderer(CobblemonEntities.CHEST_BOAT) { ctx -> CobblemonBoatRenderer(ctx, true) }
|
||||
LOGGER.info("Registering Generic Bedrock renderer")
|
||||
this.implementation.registerEntityRenderer(CobblemonEntities.GENERIC_BEDROCK_ENTITY, ::GenericBedrockRenderer)
|
||||
LOGGER.info("Registering NPC renderer")
|
||||
this.implementation.registerEntityRenderer(CobblemonEntities.NPC, ::NPCRenderer)
|
||||
LOGGER.info("Registering Generic Bedrock Entity renderer")
|
||||
this.implementation.registerEntityRenderer(CobblemonEntities.GENERIC_BEDROCK_ENTITY, ::GenericBedrockRenderer)
|
||||
LOGGER.info("Registering PokeRod Bobber renderer")
|
||||
this.implementation.registerEntityRenderer(CobblemonEntities.POKE_BOBBER) { ctx -> PokeBobberEntityRenderer(ctx) }
|
||||
}
|
||||
|
||||
fun reloadCodedAssets(resourceManager: ResourceManager) {
|
||||
@@ -273,10 +282,11 @@ object CobblemonClient {
|
||||
BedrockParticleEffectRepository.loadEffects(resourceManager)
|
||||
BedrockAnimationRepository.loadAnimations(
|
||||
resourceManager = resourceManager,
|
||||
directories = PokemonModelRepository.animationDirectories + PokeBallModelRepository.animationDirectories + FossilModelRepository.animationDirectories + BlockEntityModelRepository.animationDirectories + GenericBedrockEntityModelRepository.animationDirectories
|
||||
directories = PokemonModelRepository.animationDirectories + PokeBallModelRepository.animationDirectories + FossilModelRepository.animationDirectories + BlockEntityModelRepository.animationDirectories + GenericBedrockEntityModelRepository.animationDirectories + NPCModelRepository.animationDirectories
|
||||
)
|
||||
PokemonModelRepository.reload(resourceManager)
|
||||
PokeBallModelRepository.reload(resourceManager)
|
||||
NPCModelRepository.reload(resourceManager)
|
||||
BerryModelRepository.reload(resourceManager)
|
||||
FossilModelRepository.reload(resourceManager)
|
||||
BlockEntityModelRepository.reload(resourceManager)
|
||||
|
||||
+1
-5
@@ -40,11 +40,7 @@ class EmptyPokeBallClientDelegate : PokeBallPoseableState(), EntitySideDelegate<
|
||||
this.currentEntity = entity
|
||||
age = entity.age
|
||||
initSubscriptions()
|
||||
this.runtime.environment.getQueryStruct().addFunctions(mapOf(
|
||||
"pokeball_type" to java.util.function.Function {
|
||||
return@Function DoubleValue(currentEntity.pokeBall.name.toString())
|
||||
}
|
||||
))
|
||||
this.runtime.environment.getQueryStruct().addFunctions(getEntity().struct.functions)
|
||||
}
|
||||
|
||||
override fun tick(entity: EmptyPokeBallEntity) {
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.entity
|
||||
|
||||
import com.cobblemon.mod.common.api.entity.NPCSideDelegate
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.PoseableEntityState
|
||||
import com.cobblemon.mod.common.entity.npc.NPCEntity
|
||||
|
||||
class NPCClientDelegate : PoseableEntityState<NPCEntity>(), NPCSideDelegate {
|
||||
lateinit var npcEntity: NPCEntity
|
||||
override val schedulingTracker
|
||||
get() = npcEntity.schedulingTracker
|
||||
override fun initialize(entity: NPCEntity) {
|
||||
this.npcEntity = entity
|
||||
this.age = entity.age
|
||||
}
|
||||
|
||||
override fun tick(entity: NPCEntity) {
|
||||
super.tick(entity)
|
||||
updateLocatorPosition(entity.pos)
|
||||
incrementAge(entity)
|
||||
}
|
||||
|
||||
override fun getEntity() = npcEntity
|
||||
|
||||
override fun updatePartialTicks(partialTicks: Float) {
|
||||
this.currentPartialTicks = partialTicks
|
||||
}
|
||||
}
|
||||
+37
-29
@@ -10,6 +10,7 @@ package com.cobblemon.mod.common.client.entity
|
||||
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.bedrockk.molang.runtime.value.StringValue
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.api.entity.PokemonSideDelegate
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addFunctions
|
||||
@@ -18,6 +19,7 @@ import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
|
||||
import com.cobblemon.mod.common.api.scheduling.SchedulingTracker
|
||||
import com.cobblemon.mod.common.api.scheduling.afterOnClient
|
||||
import com.cobblemon.mod.common.api.scheduling.lerpOnClient
|
||||
import com.cobblemon.mod.common.client.ClientMoLangFunctions
|
||||
import com.cobblemon.mod.common.client.particle.BedrockParticleEffectRepository
|
||||
import com.cobblemon.mod.common.client.particle.ParticleStorm
|
||||
import com.cobblemon.mod.common.client.render.MatrixWrapper
|
||||
@@ -50,6 +52,7 @@ class PokemonClientDelegate : PoseableEntityState<PokemonEntity>(), PokemonSideD
|
||||
|
||||
override val schedulingTracker: SchedulingTracker
|
||||
get() = currentEntity.schedulingTracker
|
||||
|
||||
lateinit var currentEntity: PokemonEntity
|
||||
var phaseTarget: Entity? = null
|
||||
var entityScaleModifier = 1F
|
||||
@@ -117,7 +120,7 @@ class PokemonClientDelegate : PoseableEntityState<PokemonEntity>(), PokemonSideD
|
||||
currentEntity.isInvisible = true
|
||||
ballDone = false
|
||||
var soundPos = currentEntity.pos
|
||||
currentEntity.pokemon.getOwnerUUID()?.let{
|
||||
currentEntity.ownerUuid?.let{
|
||||
currentEntity.world.getPlayerByUuid(it)?.let {
|
||||
val offset = it.pos.subtract(currentEntity.pos.add(0.0, 2.0 - (ballOffset.toDouble()/10f), 0.0)).normalize().multiply(-ease(ballOffset.toDouble()))
|
||||
with(it.pos.subtract(currentEntity.pos)) {
|
||||
@@ -131,7 +134,7 @@ class PokemonClientDelegate : PoseableEntityState<PokemonEntity>(), PokemonSideD
|
||||
}
|
||||
val client = MinecraftClient.getInstance()
|
||||
val sound = MovingSoundInstance(SoundEvent.of(CobblemonSounds.POKE_BALL_TRAIL.id), SoundCategory.PLAYERS, { sendOutPosition?.add(sendOutOffset) }, 0.1f, 1f, false, 20, 0)
|
||||
if(!playedThrowingSound){
|
||||
if (!playedThrowingSound){
|
||||
client.soundManager.play(sound)
|
||||
playedThrowingSound = true
|
||||
}
|
||||
@@ -145,33 +148,31 @@ class PokemonClientDelegate : PoseableEntityState<PokemonEntity>(), PokemonSideD
|
||||
client.world?.playSound(client.player, soundPos.x, soundPos.y, soundPos.z, SoundEvent.of(CobblemonSounds.POKE_BALL_SEND_OUT.id), SoundCategory.PLAYERS, 0.6f, 1f)
|
||||
playedSendOutSound = true
|
||||
}
|
||||
// Display ball-specific particles
|
||||
sendOutPosition?.let{
|
||||
val newPos = it.add(sendOutOffset)
|
||||
val ballType = currentEntity.pokemon.caughtBall.name.path.lowercase().replace("_","")
|
||||
val mode = if(currentEntity.isBattling) "battle" else "casual"
|
||||
val sendflash = BedrockParticleEffectRepository.getEffect(cobblemonResource("${ballType}/${mode}/sendflash"))
|
||||
sendflash?.let { effect ->
|
||||
val wrapper = MatrixWrapper()
|
||||
val matrix = MatrixStack()
|
||||
matrix.translate(newPos.x, newPos.y, newPos.z)
|
||||
wrapper.updateMatrix(matrix.peek().positionMatrix)
|
||||
val world = MinecraftClient.getInstance().world ?: return@let
|
||||
ParticleStorm(effect, wrapper, world).spawn()
|
||||
val ballsparks = BedrockParticleEffectRepository.getEffect(cobblemonResource("${ballType}/${mode}/ballsparks"))
|
||||
val ballsendsparkle = BedrockParticleEffectRepository.getEffect(cobblemonResource("${ballType}/${mode}/ballsendsparkle"))
|
||||
// using afterOnClient because it's such a small timeframe that it's unlikely the entity has been removed & we'd like the precision
|
||||
afterOnClient(seconds = 0.01667f) {
|
||||
ballsparks?.let { effect ->
|
||||
ParticleStorm(effect, wrapper, world).spawn()
|
||||
}
|
||||
ballsendsparkle?.let { effect ->
|
||||
ParticleStorm(effect, wrapper, world).spawn()
|
||||
}
|
||||
currentEntity.after(seconds = 0.4f) {
|
||||
val ballsparkle = BedrockParticleEffectRepository.getEffect(cobblemonResource("${ballType}/ballsparkle"))
|
||||
ballsparkle?.let { effect ->
|
||||
ParticleStorm(effect, wrapper, world).spawn()
|
||||
currentEntity.ownerUuid?.let {
|
||||
client.world?.playSound(client.player, soundPos.x, soundPos.y, soundPos.z, SoundEvent.of(CobblemonSounds.POKE_BALL_SEND_OUT.id), SoundCategory.PLAYERS, 0.6f, 1f)
|
||||
playedSendOutSound = true
|
||||
/// create end rod particles in a 0.1 radius around the soundPos with a count of 50 and a random velocity of 0.1
|
||||
sendOutPosition?.let{
|
||||
val newPos = it.add(sendOutOffset)
|
||||
val ballType = currentEntity.pokemon.caughtBall.name.path.toLowerCase().replace("_","")
|
||||
val mode = if(currentEntity.isBattling) "battle" else "casual"
|
||||
val sendflash = BedrockParticleEffectRepository.getEffect(cobblemonResource("${ballType}/${mode}/sendflash"))
|
||||
sendflash?.let { effect ->
|
||||
val wrapper = MatrixWrapper()
|
||||
val matrix = MatrixStack()
|
||||
matrix.translate(newPos.x, newPos.y, newPos.z)
|
||||
wrapper.updateMatrix(matrix.peek().positionMatrix)
|
||||
val world = MinecraftClient.getInstance().world ?: return@let
|
||||
ParticleStorm(effect, wrapper, world).spawn()
|
||||
val ballsparks = BedrockParticleEffectRepository.getEffect(cobblemonResource("${ballType}/${mode}/ballsparks"))
|
||||
val ballsendsparkle = BedrockParticleEffectRepository.getEffect(cobblemonResource("${ballType}/${mode}/ballsendsparkle"))
|
||||
// using afterOnClient because it's such a small timeframe that it's unlikely the entity has been removed & we'd like the precision
|
||||
afterOnClient(seconds = 0.01667f) {
|
||||
ballsparks?.let { effect -> ParticleStorm(effect, wrapper, world).spawn() }
|
||||
ballsendsparkle?.let { effect -> ParticleStorm(effect, wrapper, world).spawn() }
|
||||
currentEntity.after(seconds = 0.4f) {
|
||||
val ballsparkle = BedrockParticleEffectRepository.getEffect(cobblemonResource("${ballType}/ballsparkle"))
|
||||
ballsparkle?.let { effect -> ParticleStorm(effect, wrapper, world).spawn() }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -250,6 +251,13 @@ class PokemonClientDelegate : PoseableEntityState<PokemonEntity>(), PokemonSideD
|
||||
pokemon.isClient = true
|
||||
}
|
||||
|
||||
override fun addToStruct(struct: QueryStruct) {
|
||||
super.addToStruct(struct)
|
||||
struct.addFunctions(functions.functions)
|
||||
struct.addFunctions(ClientMoLangFunctions.clientFunctions)
|
||||
runtime.environment.structs["query"] = struct
|
||||
}
|
||||
|
||||
override fun initialize(entity: PokemonEntity) {
|
||||
this.currentEntity = entity
|
||||
this.age = entity.age
|
||||
|
||||
@@ -10,7 +10,7 @@ package com.cobblemon.mod.common.client.gui
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonItems
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.api.gui.drawPortraitPokemon
|
||||
import com.cobblemon.mod.common.api.gui.drawPoseablePortrait
|
||||
import com.cobblemon.mod.common.api.text.darkGray
|
||||
import com.cobblemon.mod.common.api.text.red
|
||||
import com.cobblemon.mod.common.api.text.text
|
||||
@@ -23,6 +23,7 @@ import com.cobblemon.mod.common.client.keybind.keybinds.HidePartyBinding
|
||||
import com.cobblemon.mod.common.client.keybind.keybinds.SummaryBinding
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.client.render.getDepletableRedGreen
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.repository.PokemonModelRepository
|
||||
import com.cobblemon.mod.common.client.render.renderScaledGuiItemIcon
|
||||
import com.cobblemon.mod.common.pokemon.Gender
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
@@ -148,7 +149,14 @@ class PartyOverlay : InGameHud(MinecraftClient.getInstance(), MinecraftClient.ge
|
||||
0.0
|
||||
)
|
||||
|
||||
drawPortraitPokemon(pokemon.species, pokemon.aspects, matrices, partialTicks = partialDeltaTicks)
|
||||
drawPoseablePortrait(
|
||||
identifier = pokemon.species.resourceIdentifier,
|
||||
aspects = pokemon.aspects,
|
||||
matrixStack = matrices,
|
||||
partialTicks = partialDeltaTicks,
|
||||
contextScale = pokemon.form.baseScale,
|
||||
repository = PokemonModelRepository
|
||||
)
|
||||
matrices.pop()
|
||||
context.disableScissor()
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
package com.cobblemon.mod.common.client.gui.battle
|
||||
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.api.gui.drawPortraitPokemon
|
||||
import com.cobblemon.mod.common.api.gui.drawPoseablePortrait
|
||||
import com.cobblemon.mod.common.api.scheduling.Schedulable
|
||||
import com.cobblemon.mod.common.api.scheduling.SchedulingTracker
|
||||
import com.cobblemon.mod.common.api.text.bold
|
||||
@@ -25,6 +25,7 @@ import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.client.render.getDepletableRedGreen
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.PoseableEntityState
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.repository.PokeBallModelRepository
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.repository.PokemonModelRepository
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.wavefunction.sineFunction
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokeball.EmptyPokeBallEntity
|
||||
@@ -238,11 +239,13 @@ class BattleOverlay : InGameHud(MinecraftClient.getInstance(), MinecraftClient.g
|
||||
)
|
||||
} else {
|
||||
matrixStack.push()
|
||||
drawPortraitPokemon(
|
||||
species = species,
|
||||
drawPoseablePortrait(
|
||||
identifier = species.resourceIdentifier,
|
||||
aspects = aspects,
|
||||
matrixStack = matrixStack,
|
||||
scale = 18F * (ballState?.scale ?: 1F),
|
||||
contextScale = species.getForm(aspects).baseScale,
|
||||
repository = PokemonModelRepository,
|
||||
reversed = reversed,
|
||||
state = state,
|
||||
partialTicks = partialTicks
|
||||
|
||||
+1
-2
@@ -28,7 +28,6 @@ import com.cobblemon.mod.common.entity.Poseable
|
||||
import com.cobblemon.mod.common.net.messages.client.dialogue.dto.DialogueDTO
|
||||
import com.cobblemon.mod.common.net.messages.client.dialogue.dto.DialogueInputDTO
|
||||
import com.cobblemon.mod.common.net.messages.server.dialogue.EscapeDialoguePacket
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.asExpressions
|
||||
import com.cobblemon.mod.common.util.asTranslated
|
||||
@@ -116,7 +115,7 @@ class DialogueScreen(var dialogueDTO: DialogueDTO) : Screen("gui.dialogue".asTra
|
||||
.associate { it.key to it.value }
|
||||
)
|
||||
|
||||
dialogueDTO.currentPageDTO.clientActions.forEach { runtime.resolve(it.asExpression()) }
|
||||
dialogueDTO.currentPageDTO.clientActions.forEach { runtime.resolve(it.asExpressionLike()) }
|
||||
val centerX = scaledWidth / 2F
|
||||
val boxMinY = (scaledHeight / 2F - BOX_HEIGHT / 2F) - 10
|
||||
val boxMaxY = boxMinY + BOX_HEIGHT
|
||||
|
||||
+53
-17
@@ -9,12 +9,17 @@
|
||||
package com.cobblemon.mod.common.client.gui.dialogue
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.gui.drawPortraitPokemon
|
||||
import com.cobblemon.mod.common.api.gui.drawPoseablePortrait
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
|
||||
import com.cobblemon.mod.common.client.entity.NPCClientDelegate
|
||||
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.PoseableEntityState
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.npc.NPCFloatingState
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonFloatingState
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.repository.NPCModelRepository
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.repository.PokemonModelRepository
|
||||
import com.cobblemon.mod.common.entity.Poseable
|
||||
import com.cobblemon.mod.common.entity.npc.NPCEntity
|
||||
import java.util.UUID
|
||||
import kotlin.math.atan
|
||||
import net.minecraft.client.MinecraftClient
|
||||
@@ -39,8 +44,8 @@ class PlayerRenderableFace(val playerId: UUID) : RenderableFace {
|
||||
// All of the maths below is shamelessly stolen from InventoryScreen.drawEntity.
|
||||
// the -20 and 5 divided by 40 are for configuring the yaw and pitch tilt of the body and head respectively.
|
||||
// For more information, pray for divine inspiration or something idk.
|
||||
val f = atan((-20 / 40.0f).toDouble()).toFloat()
|
||||
val g = atan((5 / 40.0f).toDouble()).toFloat()
|
||||
val f = atan((-40 / 40.0f).toDouble()).toFloat()
|
||||
val g = atan((-10 / 40.0f).toDouble()).toFloat()
|
||||
val quaternionf = Quaternionf().rotateZ(Math.PI.toFloat())
|
||||
val quaternionf2 = Quaternionf().rotateX(g * 20.0f * (Math.PI.toFloat() / 180))
|
||||
quaternionf.mul(quaternionf2)
|
||||
@@ -50,14 +55,14 @@ class PlayerRenderableFace(val playerId: UUID) : RenderableFace {
|
||||
val oldPrevHeadYaw = entity.prevHeadYaw
|
||||
val oldHeadYaw = entity.headYaw
|
||||
// Modifies the entity for rendering based on our f and g values
|
||||
entity.bodyYaw = 180.0f + f * 20.0f
|
||||
entity.setYaw(180.0f + f * 40.0f)
|
||||
entity.setPitch(-g * 20.0f)
|
||||
entity.bodyYaw = 180.0F + f * 20.0F
|
||||
entity.setYaw(180.0F + f * 40.0F)
|
||||
entity.setPitch(0F)
|
||||
entity.headYaw = entity.yaw
|
||||
entity.prevHeadYaw = entity.yaw
|
||||
val size = 37
|
||||
val size = 34
|
||||
val xOffset = 0
|
||||
val yOffset = 75
|
||||
val yOffset = 72
|
||||
InventoryScreen.drawEntity(drawContext, xOffset, yOffset, size, quaternionf, quaternionf2, entity)
|
||||
// Resets the entity
|
||||
entity.bodyYaw = oldBodyYaw
|
||||
@@ -68,18 +73,36 @@ class PlayerRenderableFace(val playerId: UUID) : RenderableFace {
|
||||
}
|
||||
}
|
||||
|
||||
class ReferenceRenderableFace(entity: Poseable): RenderableFace {
|
||||
class ReferenceRenderableFace(val entity: Poseable): RenderableFace {
|
||||
val state = entity.delegate as PoseableEntityState<*>
|
||||
override fun render(drawContext: DrawContext, partialTicks: Float) {
|
||||
val state = this.state
|
||||
if (state is PokemonClientDelegate) {
|
||||
drawPortraitPokemon(
|
||||
species = state.currentEntity.pokemon.species,
|
||||
drawPoseablePortrait(
|
||||
identifier = state.currentEntity.pokemon.species.resourceIdentifier,
|
||||
aspects = state.currentEntity.pokemon.aspects,
|
||||
repository = PokemonModelRepository,
|
||||
contextScale = state.currentEntity.pokemon.form.baseScale,
|
||||
matrixStack = drawContext.matrices,
|
||||
state = state,
|
||||
partialTicks = 0F // It's already being rendered potentially so we don't need to tick the state.
|
||||
)
|
||||
} else if (state is NPCClientDelegate) {
|
||||
|
||||
entity as NPCEntity
|
||||
val limbSwing = entity.limbAnimator.getPos(partialTicks)
|
||||
val limbSwingAmount = entity.limbAnimator.getSpeed(partialTicks)
|
||||
drawPoseablePortrait(
|
||||
identifier = state.npcEntity.npc.resourceIdentifier,
|
||||
aspects = state.npcEntity.aspects,
|
||||
repository = NPCModelRepository,
|
||||
matrixStack = drawContext.matrices,
|
||||
state = state,
|
||||
partialTicks = 0F, // It's already being rendered potentially so we don't need to tick the state.
|
||||
limbSwing = limbSwing,
|
||||
limbSwingAmount = limbSwingAmount,
|
||||
ageInTicks = entity.age.toFloat(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -89,12 +112,10 @@ class ArtificialRenderableFace(
|
||||
val identifier: Identifier,
|
||||
val aspects: Set<String>
|
||||
): RenderableFace {
|
||||
val species = PokemonSpecies.getByIdentifier(identifier) ?: run {
|
||||
Cobblemon.LOGGER.error("Unable to find species for $identifier for a dialogue face. Defaulting to first species.")
|
||||
PokemonSpecies.species.first()
|
||||
}
|
||||
val state: PoseableEntityState<*> = if (modelType == "pokemon") {
|
||||
PokemonFloatingState()
|
||||
} else if (modelType == "npc") {
|
||||
NPCFloatingState()
|
||||
} else {
|
||||
throw IllegalArgumentException("Unknown model type: $modelType")
|
||||
}
|
||||
@@ -102,11 +123,26 @@ class ArtificialRenderableFace(
|
||||
override fun render(drawContext: DrawContext, partialTicks: Float) {
|
||||
val state = this.state
|
||||
if (state is PokemonFloatingState) {
|
||||
drawPortraitPokemon(
|
||||
species = species,
|
||||
val species = PokemonSpecies.getByIdentifier(identifier) ?: run {
|
||||
Cobblemon.LOGGER.error("Unable to find species for $identifier for a dialogue face. Defaulting to first species.")
|
||||
PokemonSpecies.species.first()
|
||||
}
|
||||
drawPoseablePortrait(
|
||||
identifier = species.resourceIdentifier,
|
||||
aspects = aspects,
|
||||
matrixStack = drawContext.matrices,
|
||||
contextScale = species.getForm(aspects).baseScale,
|
||||
state = state,
|
||||
repository = PokemonModelRepository,
|
||||
partialTicks = partialTicks
|
||||
)
|
||||
} else if (state is NPCFloatingState) {
|
||||
drawPoseablePortrait(
|
||||
identifier = identifier,
|
||||
aspects = aspects,
|
||||
matrixStack = drawContext.matrices,
|
||||
state = state,
|
||||
repository = NPCModelRepository,
|
||||
partialTicks = partialTicks
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.npc
|
||||
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.api.text.text
|
||||
import com.cobblemon.mod.common.client.gui.dialogue.widgets.DialogueTextInputWidget
|
||||
import com.cobblemon.mod.common.client.gui.npc.widgets.NPCRenderWidget
|
||||
import com.cobblemon.mod.common.client.gui.npc.widgets.SimpleNPCTextInputWidget
|
||||
import com.cobblemon.mod.common.net.messages.client.npc.dto.NPCConfigurationDTO
|
||||
import com.cobblemon.mod.common.net.messages.server.npc.SaveNPCPacket
|
||||
import com.cobblemon.mod.common.util.asTranslated
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.client.gui.DrawContext
|
||||
import net.minecraft.client.gui.screen.Screen
|
||||
import net.minecraft.client.gui.screen.report.ChatSelectionScreen.SelectionListWidget
|
||||
import net.minecraft.client.gui.widget.ButtonWidget
|
||||
|
||||
class NPCEditorScreen(
|
||||
val npcId: Int,
|
||||
val dto: NPCConfigurationDTO
|
||||
) : Screen("gui.npc_editor.title".asTranslated()) {
|
||||
companion object {
|
||||
const val BASE_WIDTH = 331
|
||||
const val BASE_HEIGHT = 161
|
||||
|
||||
private val baseResource = cobblemonResource("textures/gui/npc/editor_base.png")
|
||||
}
|
||||
|
||||
val middleX: Int
|
||||
get() = this.client!!.window.scaledWidth / 2
|
||||
val middleY: Int
|
||||
get() = this.client!!.window.scaledHeight / 2
|
||||
|
||||
val leftX: Int
|
||||
get() = middleX - BASE_WIDTH / 2
|
||||
val topY: Int
|
||||
get() = middleY - BASE_HEIGHT / 2
|
||||
|
||||
override fun init() {
|
||||
super.init()
|
||||
addDrawable(NPCRenderWidget(leftX + 6, topY + 32, dto.npcClass, dto.aspects))
|
||||
addDrawableChild(SimpleNPCTextInputWidget(
|
||||
texture = cobblemonResource("textures/gui/npc/basic_text_input.png"),
|
||||
getter = { dto.npcName.string },
|
||||
setter = { dto.npcName = it.text() },
|
||||
x = leftX + 79,
|
||||
y = topY + 14,
|
||||
width = 130,
|
||||
height = 22
|
||||
))
|
||||
addDrawableChild(SimpleNPCTextInputWidget(
|
||||
texture = cobblemonResource("textures/gui/npc/aspects_text_input.png"),
|
||||
getter = { dto.aspects.joinToString() },
|
||||
setter = {
|
||||
dto.aspects.clear()
|
||||
dto.aspects.addAll(it.split(",").map { it.trim() })
|
||||
},
|
||||
x = leftX + 79,
|
||||
y = topY + 36,
|
||||
width = 130,
|
||||
height = 40,
|
||||
maxLength = 75,
|
||||
wrap = true
|
||||
))
|
||||
addDrawableChild(
|
||||
ButtonWidget
|
||||
.builder("Save".text()) {
|
||||
SaveNPCPacket(npcId, dto).sendToServer()
|
||||
this.client!!.setScreen(null)
|
||||
}
|
||||
.position(leftX + BASE_WIDTH - 42, topY + BASE_HEIGHT - 18)
|
||||
.size(40, 16)
|
||||
.build()
|
||||
)
|
||||
}
|
||||
|
||||
override fun render(context: DrawContext, mouseX: Int, mouseY: Int, delta: Float) {
|
||||
blitk(
|
||||
matrixStack = context.matrices,
|
||||
texture = baseResource,
|
||||
x = leftX,
|
||||
y = topY,
|
||||
height = BASE_HEIGHT,
|
||||
width = BASE_WIDTH
|
||||
)
|
||||
super.render(context, mouseX, mouseY, delta)
|
||||
}
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.npc.widgets
|
||||
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.api.gui.drawProfile
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.npc.NPCFloatingState
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.repository.NPCModelRepository
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.client.gui.DrawContext
|
||||
import net.minecraft.client.gui.Drawable
|
||||
import net.minecraft.client.gui.Element
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.math.RotationAxis
|
||||
|
||||
class NPCRenderWidget(
|
||||
val x: Int,
|
||||
val y: Int,
|
||||
var identifier: Identifier,
|
||||
val aspects: MutableSet<String>
|
||||
) : Drawable, Element {
|
||||
val state = NPCFloatingState()
|
||||
companion object {
|
||||
val profileBackgroundResource = cobblemonResource("textures/gui/npc/profile_background.png")
|
||||
const val WIDTH = 66
|
||||
const val HEIGHT = 66
|
||||
}
|
||||
|
||||
override fun isFocused() = false
|
||||
override fun setFocused(focused: Boolean) {}
|
||||
override fun render(context: DrawContext, mouseX: Int, mouseY: Int, delta: Float) {
|
||||
blitk(
|
||||
matrixStack = context.matrices,
|
||||
texture = profileBackgroundResource,
|
||||
x = x,
|
||||
y = y,
|
||||
width = WIDTH,
|
||||
height = HEIGHT
|
||||
)
|
||||
|
||||
context.matrices.push()
|
||||
context.matrices.translate(x + WIDTH / 2F, y + HEIGHT / 2F, 0F)
|
||||
|
||||
drawProfile(
|
||||
repository = NPCModelRepository,
|
||||
resourceIdentifier = identifier,
|
||||
aspects = aspects,
|
||||
matrixStack = context.matrices,
|
||||
partialTicks = delta,
|
||||
scale = 30F,
|
||||
state = state
|
||||
)
|
||||
|
||||
context.matrices.pop()
|
||||
}
|
||||
}
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.npc.widgets
|
||||
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.api.gui.drawCenteredText
|
||||
import com.cobblemon.mod.common.api.text.text
|
||||
import com.cobblemon.mod.common.client.gui.dialogue.DialogueScreen
|
||||
import com.cobblemon.mod.common.net.messages.client.dialogue.dto.DialogueInputDTO
|
||||
import com.cobblemon.mod.common.net.messages.server.dialogue.InputToDialoguePacket
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.client.MinecraftClient
|
||||
import net.minecraft.client.gui.DrawContext
|
||||
import net.minecraft.client.gui.widget.TextFieldWidget
|
||||
import net.minecraft.client.util.InputUtil
|
||||
import net.minecraft.text.LiteralTextContent
|
||||
import net.minecraft.text.MutableText
|
||||
import net.minecraft.util.Identifier
|
||||
import org.lwjgl.glfw.GLFW
|
||||
|
||||
class SimpleNPCTextInputWidget(
|
||||
getter: () -> String,
|
||||
val texture: Identifier,
|
||||
private val setter: (String) -> Unit,
|
||||
x: Int,
|
||||
y: Int,
|
||||
width: Int,
|
||||
height: Int,
|
||||
maxLength: Int = 100,
|
||||
val wrap: Boolean = false
|
||||
) : TextFieldWidget(
|
||||
MinecraftClient.getInstance().textRenderer,
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
"input".text()
|
||||
) {
|
||||
|
||||
init {
|
||||
setMaxLength(maxLength)
|
||||
isFocused = true
|
||||
text = getter()
|
||||
this.setChangedListener { setter(it) }
|
||||
}
|
||||
|
||||
override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
|
||||
return if (mouseX.toInt() in x..(x + width) && mouseY.toInt() in y..(y + height)) {
|
||||
isFocused = true
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
override fun render(context: DrawContext, mouseX: Int, mouseY: Int, delta: Float) {
|
||||
if (cursor != text.length) {
|
||||
setCursorToEnd()
|
||||
}
|
||||
|
||||
blitk(
|
||||
matrixStack = context.matrices,
|
||||
x = x,
|
||||
y = y,
|
||||
width = width,
|
||||
height = height,
|
||||
texture = texture
|
||||
)
|
||||
|
||||
context.matrices.push()
|
||||
val scale = 0.8F
|
||||
context.matrices.scale(scale, scale, 1F)
|
||||
if (wrap) {
|
||||
val wrappedLines = MinecraftClient.getInstance().textRenderer.wrapLines(MutableText.of(LiteralTextContent(text)), ((width - 8) / scale).toInt())
|
||||
for ((index, line) in wrappedLines.withIndex()) {
|
||||
context.drawText(
|
||||
MinecraftClient.getInstance().textRenderer,
|
||||
line,
|
||||
((x + 4) / scale).toInt(),
|
||||
((y + index * 10 + 5) / scale).toInt(),
|
||||
0xFFFFFF,
|
||||
false
|
||||
)
|
||||
}
|
||||
} else {
|
||||
drawCenteredText(
|
||||
context = context,
|
||||
text = text.text(),
|
||||
x = (x + width / 2F) / scale,
|
||||
y = (y + height / 2 - 4) / scale,
|
||||
shadow = true,
|
||||
colour = 0xFFFFFF
|
||||
)
|
||||
}
|
||||
context.matrices.pop()
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -13,6 +13,7 @@ import com.cobblemon.mod.common.client.render.models.blockbench.PoseableEntitySt
|
||||
import com.cobblemon.mod.common.entity.Poseable
|
||||
import com.cobblemon.mod.common.net.messages.client.animation.PlayPoseableAnimationPacket
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.resolve
|
||||
import net.minecraft.client.MinecraftClient
|
||||
|
||||
@@ -24,7 +25,7 @@ object PlayPoseableAnimationHandler : ClientNetworkPacketHandler<PlayPoseableAni
|
||||
val delegate = entity.delegate
|
||||
if (delegate is PoseableEntityState<*>) {
|
||||
for (expr in packet.expressions) {
|
||||
delegate.runtime.resolve(expr.asExpression())
|
||||
delegate.runtime.resolve(expr.asExpressionLike())
|
||||
}
|
||||
delegate.addFirstAnimation(packet.animation)
|
||||
}
|
||||
|
||||
+2
-2
@@ -12,7 +12,7 @@ import com.cobblemon.mod.common.api.net.ClientNetworkPacketHandler
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.PoseableEntityState
|
||||
import com.cobblemon.mod.common.entity.Poseable
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.RunPosableMoLangPacket
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.resolve
|
||||
import net.minecraft.client.MinecraftClient
|
||||
|
||||
@@ -22,7 +22,7 @@ object RunPosableMoLangHandler : ClientNetworkPacketHandler<RunPosableMoLangPack
|
||||
val entity = world.getEntityById(packet.entityId) ?: return
|
||||
if (entity is Poseable) {
|
||||
val state = entity.delegate as? PoseableEntityState<*> ?: return
|
||||
for (expression in packet.expressions.map { it.asExpression() }) {
|
||||
for (expression in packet.expressions.map { it.asExpressionLike() }) {
|
||||
state.runtime.resolve(expression)
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user