Compare commits

..
Author SHA1 Message Date
Hiroku d6c543e965 Fixed Porygon evolution 2023-05-28 01:04:26 +00:00
Hiroku 505eb06406 Merge branch '1.3.2-dupe-fix' into '1.3.2-dupe-fix'
Fix a crash introduced by issue !482

See merge request cable-mc/cobblemon!483
2023-05-28 00:59:56 +00:00
Neovitalism 83963d038d Clean my unused imports 2023-05-23 20:01:37 -04:00
Neovitalism cedcf1aacf Only force recall when the player teleports
Sadly teleporting the mon caused too many issues and crashes
2023-05-23 16:41:54 -04:00
Neovitalism 5613726acd Merge branch '1.3.2-dupe-fix' of https://gitlab.com/Neovitalism/cobblemon into 1.3.2-dupe-fix 2023-05-23 06:23:43 -04:00
Neovitalism 4be346d96d Make pokemon being manually recalled not trigger onStoppedTrackingBy 2023-05-23 06:23:27 -04:00
Neovitalism 29e6861f88 Merge branch '1.3.2-dupe-fix' into '1.3.2-dupe-fix'
# Conflicts:
#   common/src/main/kotlin/com/cobblemon/mod/common/util/EntityExtensions.kt
2023-05-23 01:42:03 +00:00
Neovitalism 6deb272ec3 Change to teleport since teleport loads the chunk 2023-05-22 21:33:36 -04:00
Neovitalism 18caae05ca Load the chunk the PokemonEntity is being recalled from 2023-05-21 20:35:28 -04:00
Hiroku 1bb4692273 Merge branch '1.3.2-dupe-fix' into '1.3.2-dupe-fix'
Change ticking the GoalSelector to our own teleportToOwner attempt

See merge request cable-mc/cobblemon!482
2023-05-21 12:32:40 +00:00
NeovitalismandHiroku 6a4bd4dfa6 Change ticking the GoalSelector to our own teleportToOwner attempt 2023-05-21 12:32:40 +00:00
Neovitalism 28ff02cc3e Merge branch '1.3.2-dupe-fix' of https://gitlab.com/Neovitalism/cobblemon into 1.3.2-dupe-fix 2023-05-21 08:00:53 -04:00
Neovitalism b8378bf11c Move teleport methods to EntityExtensions.kt
This also moves the larger part of the methods to TameableEntity instead of PokemonEntity, allowing for more vanilla use, as well. (Not that it's a huge change lol)
2023-05-21 08:00:49 -04:00
Neovitalism 8d8cf6d071 Merge branch '1.3.2-dupe-fix' into '1.3.2-dupe-fix'
# Conflicts:
#   common/src/main/kotlin/com/cobblemon/mod/common/entity/pokemon/PokemonEntity.kt
2023-05-20 20:30:37 +00:00
Neovitalism 6b2b9fb064 Change ticking the GoalSelector to our own teleportToOwner attempt
This just moves the methods we need instead of ticking the GoalSelector, this not only saves all goals from ticking but allows us to do custom logic when the teleport fails (recall)
2023-05-20 16:16:27 -04:00
Hiroku 2c151ddcec Merge branch '1.3.1' into '1.3.2-dupe-fix'
Fix owned PokemonEntity from not returning to the player when left in unloaded chunks

See merge request cable-mc/cobblemon!481
2023-05-20 12:03:43 +00:00
NeovitalismandHiroku 1b4584557d Fix owned PokemonEntity from not returning to the player when left in unloaded chunks 2023-05-20 12:03:42 +00:00
Neovitalism 6773084212 Fix owned PokemonEntity from not returning to the player when left in unloaded chunks
This just ticks the pokemon's goal once when the owning player stops loading the mon, so this works in unloaded chunks and does nothing different in loaded chunks
2023-05-19 14:00:50 -04:00
13671 changed files with 77301 additions and 1013085 deletions
-6
View File
@@ -21,8 +21,6 @@ build
# other
eclipse
run
runClient
runServer
# Files from Forge MDK
forge*changelog.txt
@@ -35,7 +33,3 @@ common/src/main/resources/assets/cobblemon/showdown
# Generated files
*/generated/resources/*
/fabric/src/generated/resources/cobblemon-common.accesswidener
/.ignored/
# MacOS
.DS_Store
+5 -26
View File
@@ -7,14 +7,12 @@ stages:
#TODO add client reference test process, search for import com.cobblemon.mod.common.client
build:
build-job:
stage: build
only:
- branches@cable-mc/cobblemon
script:
- export GRADLE_OPTS="-Xmx4G -Xms4G"
- chmod +x ./gradlew
- ./gradlew build
- export GRADLE_OPTS="-Xmx4G -Xms4G"
- chmod +x ./gradlew
- ./gradlew build
cache:
key: "$CI_COMMIT_REF_NAME"
policy: push
@@ -22,28 +20,9 @@ build:
- forge/build/libs
- fabric/build/libs
publish:
stage: deploy
dependencies:
- build
cache:
key: "CI_COMMIT_REF_NAME"
policy: pull
paths:
- forge/build/libs/*.jar
- fabric/build/libs/*.jar
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
script:
- export GRADLE_OPTS="-Xmx4G -Xms4G"
- chmod +x ./gradlew
- ./gradlew publish
# Separate step to deploy the artifacts, save Norry the headache of keeping even more shit around
deploy:
deploy-job:
stage: deploy
dependencies:
- build
when: manual
cache:
key: "$CI_COMMIT_REF_NAME"
-30
View File
@@ -1,30 +0,0 @@
<!-- 1. START HERE: (Before filling all this out, please quickly go to the list of all issues: (https://gitlab.com/cable-mc/cobblemon/-/issues/?sort=created_date&state=all) and do a quick search to see if your issue has already been reported. If it has, please add a comment to the existing issue instead of creating a new one.)-->
<!-- 2. If the issue was not already reported, please fill out the following template. -->
<!-- 3. If you do not know something, don't worry! Just fill out as much as you can to make sure the issue can get fixed asap. -->
## Summary
(Please summarize the bug encountered concisely)
## Steps to reproduce
(How one can reproduce the issue - this is very important)
## What is the current bug behavior?
(What actually happens)
## What is the expected correct behavior?
(What you should see instead)
## Cobblemon Version and Mod Loader
(Are you using Forge or Fabric? And what version of Cobblemon are you using?)
## Mods used besides Cobblemon
(Did you have any other mods installed besides Cobblemon? If so, please list them here)
## Relevant logs, screenshots and/or videos
(Paste any relevant logs - use code blocks (```) at the start and end to format console output, logs, and code, as
it's very hard to read otherwise. Or just put a link here)
## Additional Information
(If you can, link to the line of code that might be responsible for the problem, or any other info that might be useful)
/label ~bug
@@ -1,31 +0,0 @@
<!-- 1. START HERE: (Before filling all this out, please quickly go to the list of all issues: (https://gitlab.com/cable-mc/cobblemon/-/issues/?sort=created_date&state=all) and do a quick search to see if your feature was already requested. If it is, please add a comment to the existing issue instead of creating a new one.)-->
<!-- 2. If the feature request was not already reported, please fill out the following template. -->
<!-- 3. If you do not know something, don't worry! Just fill out as much as you can. -->
<!-- 4. The more info you provide here, the greater the chance of it being considered by the Design team. -->
## Summary
(Please summarize your feature request concisely)
## What are the projected benefits of this feature?
- (List)
- (benefits)
- (here)
## What could speak against this feature?
- (List)
- (possible)
- (cons)
## Why do you think the benefits outweigh the cons?
(Explain why you think the benefits outweigh the cons)
## Mods involved besides Cobblemon
(Does your suggestion require any other mods besides Cobblemon? If so, please list them here)
## Sketches, screenshots and/or videos
(Feel free to add any sketches, screenshots or videos that might help the Design team understand your suggestion)
## Additional Information
(Is there anything else you would like to add?)
/label ~feature ~suggestion ~needs-design
+16 -965
View File
File diff suppressed because it is too large Load Diff
+8 -9
View File
@@ -4,15 +4,14 @@ An open-source Pokémon mod for Minecraft Java Edition, written in Kotlin for Fa
## Getting started
To set up the development workspace, first clone the project and open the build.gradle with Intellij. Make sure that you clone it to a folder that has no spaces in its path (for example, C:/Development/Cobblemon Stuff/cobblemon/ is bad) since Architectury Plugin seems to dislike it.
To set up the development workspace, first clone the project and open the build.gradle with Intellij. There will be
errors until you go to File -> Settings -> Build, Execution, Deployment -> Build Tools -> Gradle and change the Gradle JVM
to 17. After changing this, click the icon for reloading the project. This will automatically
put together all the dependencies and project setup.
After it takes ages to load, you should hopefully have runnable configurations of the project in the top right, such as Minecraft Client (:fabric). If not, try running `./gradlew genEclipseRuns`.
Troubleshooting:
- Try running `./gradlew --refresh-dependencies`
- Try File -> Invalidate Caches.
- Try deleting the `.idea` folder in the project root (make sure IntelliJ is closed when you try it).
- Try completely reclone the thing lmao.
Run `./gradlew genEclipseRuns`, and then in Intellij go to your run configurations, and change whichever you plan on
running to use a Java 17 JRE. runClient is as if you booted up in singleplayer, runServer is a server without a client,
and runData is for summoning the Eldritch gods or something, idk.
## Contributing
@@ -20,4 +19,4 @@ If you're interested in contributing to the project, you can simply fork the rep
[here](https://gitlab.com/cable-mc/cobblemon/-/issues?scope=all&state=opened&label_name[]=accepted&assignee_id=None).
If you want a more involved role in the project, involving branches on the main repository instead of forking and involvement
in design discussions, you can either apply in the `application-box` forum of our Discord or add and message Hiroku (`hiroku_dev`) on our Discord here: https://discord.gg/cobblemon.
in design discussions, add and message Hiroku#4373 on our Discord here: https://discord.gg/AsNpJSST7G.
+18
View File
@@ -0,0 +1,18 @@
plugins {
`kotlin-dsl`
}
repositories {
gradlePluginPortal()
maven("https://maven.architectury.dev/")
maven("https://maven.fabricmc.net/")
maven("https://maven.minecraftforge.net/")
}
dependencies {
implementation(libs.kotlin)
implementation(libs.licenser)
implementation(libs.shadow)
implementation(libs.loom)
implementation(libs.architecturyPlugin)
}
+10
View File
@@ -0,0 +1,10 @@
import ca.stellardrift.build.configurate.ConfigFormats
import ca.stellardrift.build.configurate.catalog.PolyglotVersionCatalogExtension
plugins {
id("ca.stellardrift.polyglot-version-catalogs") version "5.0.1"
}
extensions.configure<PolyglotVersionCatalogExtension> {
from(ConfigFormats.YAML, file("../gradle/libs.versions.yml"))
}
@@ -0,0 +1,57 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
val accessWidenerFile = "src/main/resources/cobblemon-common.accesswidener"
plugins {
`java-library`
id("org.cadixdev.licenser")
id("dev.architectury.loom")
id("architectury-plugin")
kotlin("jvm")
}
repositories {
mavenCentral()
}
license {
header(rootProject.file("HEADER"))
}
java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
architectury {
minecraft = project.property("mc_version").toString()
}
loom {
silentMojangMappingsLicense()
accessWidenerPath.set(project(":common").file(ACCESS_WIDENER))
mixin {
defaultRefmapName.set("cobblemon-${project.name}-refmap.json")
}
}
dependencies {
minecraft("net.minecraft:minecraft:${rootProject.property("mc_version")}")
mappings("net.fabricmc:yarn:${rootProject.property("yarn_version")}")
}
tasks {
withType<JavaCompile> {
options.encoding = "UTF-8"
options.release.set(17)
}
withType<KotlinCompile> {
kotlinOptions.jvmTarget = "17"
}
withType<Jar> {
from(rootProject.file("LICENSE"))
}
}
@@ -0,0 +1,32 @@
plugins {
id("cobblemon.base-conventions")
id("com.github.johnrengelman.shadow")
}
val bundle: Configuration by configurations.creating {
isCanBeConsumed = false
isCanBeResolved = true
}
tasks {
jar {
archiveBaseName.set("Cobblemon-${project.name}")
archiveClassifier.set("dev-slim")
}
shadowJar {
archiveClassifier.set("dev-shadow")
archiveBaseName.set("Cobblemon-${project.name}")
configurations = listOf(bundle)
mergeServiceFiles()
}
remapJar {
dependsOn(shadowJar)
inputFile.set(shadowJar.flatMap { it.archiveFile })
archiveBaseName.set("Cobblemon-${project.name}")
archiveVersion.set("${rootProject.version}")
}
}
@@ -0,0 +1,37 @@
plugins {
java
`java-library`
id("maven-publish")
id("dev.architectury.loom")
}
java {
withSourcesJar()
withJavadocJar()
}
publishing {
repositories {
maven("https://maven.impactdev.net/repository/development/") {
name = "ImpactDev-Public"
credentials {
username = System.getenv("NEXUS_USER")
password = System.getenv("NEXUS_PW")
}
}
}
publications {
create<MavenPublication>(project.name) {
artifact(tasks.remapJar)
artifact(tasks.remapSourcesJar)
@Suppress("UnstableApiUsage")
loom.disableDeprecatedPomGeneration(this)
groupId = "com.cobblemon"
artifactId = project.findProperty("maven.artifactId")?.toString() ?: project.name
version = rootProject.version.toString()
}
}
}
@@ -0,0 +1,21 @@
plugins {
`java-library`
}
tasks {
val collectJars by registering(Copy::class) {
val tasks = subprojects.filter { it.path != ":common" }.map { it.tasks.named("remapJar") }
dependsOn(tasks)
from(tasks)
into(buildDir.resolve("libs"))
}
assemble {
dependsOn(collectJars)
}
}
tasks.withType<Test> {
useJUnitPlatform()
}
@@ -1,3 +1,2 @@
package utilities
const val ACCESS_WIDENER = "src/main/resources/cobblemon-common.accesswidener"
+4 -4
View File
@@ -1,12 +1,12 @@
plugins {
base
id("cobblemon.root-conventions")
id ("net.nemerosa.versioning") version "2.8.2"
}
group = "com.cobblemon.mod"
version = "${project.property("mod_version")}+${project.property("mc_version")}"
val isSnapshot = project.property("snapshot")?.equals("true") ?: false
if (isSnapshot) {
val fixedBranchName = versioning.info.branch.substringAfter("/")
version = "$version-${fixedBranchName}-${versioning.info.build}"
}
version = "$version-SNAPSHOT"
}
+16 -71
View File
@@ -1,95 +1,40 @@
import utilities.isSnapshot
import utilities.version
import java.time.OffsetDateTime
import java.time.ZoneOffset
import java.time.format.DateTimeFormatter
/*
*
* * 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/.
*
*/
plugins {
id("cobblemon.base-conventions")
id("cobblemon.publish-conventions")
id("net.kyori.blossom")
id("org.jetbrains.gradle.plugin.idea-ext")
id("net.nemerosa.versioning") version "2.8.2"
}
architectury {
common("forge", "fabric")
common()
}
repositories {
maven(url = "${rootProject.projectDir}/deps")
maven(url = "https://api.modrinth.com/maven")
mavenLocal()
}
dependencies {
implementation(libs.bundles.kotlin)
modImplementation(libs.fabric.loader)
implementation(libs.stdlib)
implementation(libs.reflect)
modImplementation(libs.fabricLoader)
modApi(libs.architectury)
modApi(libs.molang)
// Integrations
compileOnlyApi(libs.jei.api)
modCompileOnly(libs.bundles.fabric.integrations.compileOnly) {
isTransitive = false
}
// Flywheel has no common dep so just pick one and don't use any platform specific code in common
// modCompileOnly(libs.flywheelFabric)
// Showdown
// For Showdown
modCompileOnly(libs.graal)
// Data Storage
modCompileOnly(libs.bundles.mongo)
//shadowCommon group: 'commons-io', name: 'commons-io', version: '2.6'
// Unit Testing
testImplementation(libs.bundles.unitTesting)
testRuntimeOnly(libs.junitEngine)
testImplementation(libs.junitApi)
testImplementation(libs.junitParams)
testImplementation(libs.mockito)
testImplementation(libs.mockk)
compileOnly("net.luckperms:api:${rootProject.property("luckperms_version")}")
}
tasks.withType<Test> {
useJUnitPlatform()
testLogging {
setEvents(listOf("failed"))
setExceptionFormat("full")
}
}
sourceSets {
main {
blossom {
kotlinSources {
fun generateLicenseHeader() : String {
val builder = StringBuilder()
builder.append("/*\n")
rootProject.file("HEADER").forEachLine {
if(it.isEmpty()) {
builder.append(" *").append("\n")
} else {
builder.append(" * ").append(it).append("\n")
}
}
return builder.append(" */").append("\n").toString()
}
property("license", generateLicenseHeader())
property("modid", "cobblemon")
property("version", project.version())
property("isSnapshot", if(rootProject.isSnapshot()) "true" else "false")
property("gitCommit", versioning.info.commit)
property("branch", versioning.info.branch)
System.getProperty("buildNumber")?.let { property("buildNumber", it) }
}
}
}
}
@@ -1,16 +0,0 @@
/*
* 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.bridges;
import net.minecraft.structure.processor.StructureProcessor;
public interface StructureProcessorListBridge {
void append(StructureProcessor processor);
void clear();
}
@@ -1,70 +0,0 @@
/*
* 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.render.models.blockbench.pose;
import com.cobblemon.mod.common.client.render.models.blockbench.repository.RenderContext;
import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.util.math.MatrixStack;
import java.util.Map;
/**
* A bone represents a particular joint of a model. Bones are capable of containing child bones identifiable
* by a String ideally representing the name of a particular bone.
*
* This interface is meant to allow projects and sidemods to implement their own rendering logic in reference
* to the bones.
*
* @author Waterpicker
* @since 1.4.0
*/
public interface Bone {
/**
* A map of identifiable names to child bones
*
* @since 1.4.0
*/
Map<String, Bone> getChildren();
/**
* Renders a particular bone in relation to a particular entity.
*
* @param context The render context this bone is being drawn for.
* @param stack The current [MatrixStack] for the renderer
* @param buffer The vertex consumer deployed by the renderer
* @param packedLight The light level to be applied to the bone
* @param packedOverlay The overlay value to be applied to the bone
* @param r A value representing the amount of red coloring that should be applied on the RGB scale
* @param g A value representing the amount of green coloring that should be applied on the RGB scale
* @param b A value representing the amount of blue coloring that should be applied on the RGB scale
* @param a The alpha value to apply to the model based on the RGB scale
*
* @since 1.4.0
*/
void render(
RenderContext context,
MatrixStack stack,
VertexConsumer buffer,
int packedLight,
int packedOverlay,
float r,
float g,
float b,
float a
);
/**
* Allows for direct transformation of a bone via a given matrix stack
*
* @since 1.4.0
*/
void transform(MatrixStack matrixStack);
}
@@ -1,96 +0,0 @@
/*
* 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.compat;
import com.cobblemon.mod.common.CobblemonEntities;
import com.cobblemon.mod.common.client.render.layer.PokemonOnShoulderRenderer;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import com.cobblemon.mod.common.pokemon.FormData;
import com.cobblemon.mod.common.pokemon.lighthing.LightingData;
import dev.lambdaurora.lambdynlights.api.DynamicLightHandler;
import dev.lambdaurora.lambdynlights.api.DynamicLightHandlers;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.Pair;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Optional;
// Java class due to relying on entrypoint on Fabric side
public class LambDynamicLightsCompat {
// This is all called on client side
// These things are checked every tick so try to keep it as free as possible
// That being said it's unlikely school Toshiba person is running dynamic lighting and shaders to enjoy this
// Make sure not to call anything Fabric specific :)
public static void hookCompat() {
// Pokémon entities
DynamicLightHandlers.registerDynamicLightHandler(
CobblemonEntities.POKEMON,
DynamicLightHandler.makeHandler(
pokemon -> resolvedPokemonLightLevel(pokemon, false),
pokemon -> true
)
);
DynamicLightHandlers.registerDynamicLightHandler(
CobblemonEntities.POKEMON,
DynamicLightHandler.makeHandler(
pokemon -> resolvedPokemonLightLevel(pokemon, true),
pokemon -> false
)
);
// Shouldered Pokémon
DynamicLightHandlers.registerDynamicLightHandler(
EntityType.PLAYER,
DynamicLightHandler.makeHandler(
player -> resolvedShoulderLightLevel(player, false),
player -> true
)
);
DynamicLightHandlers.registerDynamicLightHandler(
EntityType.PLAYER,
DynamicLightHandler.makeHandler(
player -> resolvedShoulderLightLevel(player, true),
player -> false
)
);
}
private static int resolvedPokemonLightLevel(PokemonEntity pokemon, boolean underwater) {
return extractFormLightLevel(pokemon.getForm(), underwater).orElse(0);
}
private static int resolvedShoulderLightLevel(PlayerEntity player, boolean underwater) {
final Pair<PokemonOnShoulderRenderer.ShoulderData, PokemonOnShoulderRenderer.ShoulderData> shoulderDataPair = PokemonOnShoulderRenderer.shoulderDataOf(player);
final Optional<Integer> leftLightLevel = extractShoulderLightLevel(shoulderDataPair.getLeft(), underwater);
final Optional<Integer> rightLightLevel = extractShoulderLightLevel(shoulderDataPair.getRight(), underwater);
return Math.max(leftLightLevel.orElse(0), rightLightLevel.orElse(0));
}
private static Optional<Integer> extractFormLightLevel(@NotNull FormData form, boolean underwater) {
if (form.getLightingData() == null || !liquidGlowModeSupport(form.getLightingData().getLiquidGlowMode(), underwater)) {
return Optional.empty();
}
return Optional.of(form.getLightingData().getLightLevel());
}
private static Optional<Integer> extractShoulderLightLevel(@Nullable PokemonOnShoulderRenderer.ShoulderData shoulderData, boolean underwater) {
if (shoulderData == null) {
return Optional.empty();
}
return extractFormLightLevel(shoulderData.getForm(), underwater);
}
private static boolean liquidGlowModeSupport(@NotNull LightingData.LiquidGlowMode liquidGlowMode, boolean underwater) {
return underwater ? liquidGlowMode.getGlowsUnderwater() : liquidGlowMode.getGlowsInLand();
}
}
@@ -1,20 +0,0 @@
/*
* 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.duck;
import net.minecraft.sound.SoundCategory;
import net.minecraft.util.Identifier;
import org.jetbrains.annotations.Nullable;
public interface SoundManagerDuck {
void pauseSounds(@Nullable Identifier id, @Nullable SoundCategory category);
void resumeSounds(@Nullable Identifier id, @Nullable SoundCategory category);
}
@@ -1,25 +0,0 @@
/*
* 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.duck;
import net.minecraft.client.sound.SoundInstance;
import net.minecraft.sound.SoundCategory;
import net.minecraft.util.Identifier;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
public interface SoundSystemDuck {
void pauseSounds(@Nullable Identifier id, @Nullable SoundCategory category);
void resumeSounds(@Nullable Identifier id, @Nullable SoundCategory category);
Collection<SoundInstance> getSounds(@Nullable SoundCategory category);
}
@@ -0,0 +1,40 @@
/*
* 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.mixin;
import com.cobblemon.mod.common.command.argument.*;
import com.mojang.brigadier.arguments.ArgumentType;
import net.minecraft.command.argument.ArgumentTypes;
import net.minecraft.command.argument.serialize.ArgumentSerializer;
import net.minecraft.command.argument.serialize.ConstantArgumentSerializer;
import net.minecraft.util.registry.Registry;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(ArgumentTypes.class)
public class ArgumentTypesMixin {
@Shadow
private static <A extends ArgumentType<?>, T extends ArgumentSerializer.ArgumentTypeProperties<A>> ArgumentSerializer<A, T> register(Registry<ArgumentSerializer<?, ?>> registry, String string, Class<? extends A> clazz, ArgumentSerializer<A, T> argumentSerializer) {
throw new AssertionError("Should not be executed.");
}
@Inject(method = "register(Lnet/minecraft/util/registry/Registry;)Lnet/minecraft/command/argument/serialize/ArgumentSerializer;", at = @At("RETURN"))
private static void register(Registry<ArgumentSerializer<?, ?>> registry, CallbackInfoReturnable<ArgumentSerializer<?, ?>> ci) {
register(registry, "cobblemon:pokemon", PokemonArgumentType.class, ConstantArgumentSerializer.of(PokemonArgumentType.Companion::pokemon));
register(registry, "cobblemon:pokemonproperties", PokemonPropertiesArgumentType.class, ConstantArgumentSerializer.of(PokemonPropertiesArgumentType.Companion::properties));
register(registry, "cobblemon:spawnbucket", SpawnBucketArgumentType.class, ConstantArgumentSerializer.of(SpawnBucketArgumentType.Companion::spawnBucket));
register(registry, "cobblemon:move", MoveArgumentType.class, ConstantArgumentSerializer.of(MoveArgumentType.Companion::move));
register(registry, "cobblemon:partyslot", PartySlotArgumentType.class, ConstantArgumentSerializer.of(PartySlotArgumentType.Companion::partySlot));
}
}
@@ -13,7 +13,6 @@ import com.cobblemon.mod.common.client.render.item.CobblemonBuiltinItemRendererR
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.item.BuiltinModelItemRenderer;
import net.minecraft.client.render.model.json.ModelTransformation;
import net.minecraft.client.render.model.json.ModelTransformationMode;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.item.ItemStack;
import org.spongepowered.asm.mixin.Mixin;
@@ -25,7 +24,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
public class BuiltinModelItemRendererMixin {
@Inject(method = "render", at = @At("HEAD"), cancellable = true)
private void cobblemon$useDynamicItemRenderer(ItemStack stack, ModelTransformationMode mode, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay, CallbackInfo ci) {
private void cobblemon$useDynamicItemRenderer(ItemStack stack, ModelTransformation.Mode mode, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay, CallbackInfo ci) {
CobblemonBuiltinItemRenderer renderer = CobblemonBuiltinItemRendererRegistry.INSTANCE.rendererOf(stack.getItem());
if (renderer != null) {
renderer.render(stack, mode, matrices, vertexConsumers, light, overlay);
@@ -1,34 +0,0 @@
/*
* 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.mixin;
import com.cobblemon.mod.common.CobblemonBuildDetails;
import net.minecraft.util.crash.CrashReport;
import net.minecraft.util.crash.CrashReportSection;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(CrashReport.class)
public final class CrashReportMixin {
@Inject(method = "addStackTrace", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/SystemDetails;writeTo(Ljava/lang/StringBuilder;)V"))
public void cobblemon$printCobblemonDetails(StringBuilder builder, CallbackInfo callback) {
CrashReportSection cobblemon = new CrashReportSection("Cobblemon");
cobblemon.add("Version", CobblemonBuildDetails.VERSION);
cobblemon.add("Is Snapshot", CobblemonBuildDetails.SNAPSHOT);
cobblemon.add("Git Commit", CobblemonBuildDetails.INSTANCE.smallCommitHash() + " (" + "https://gitlab.com/cable-mc/cobblemon/-/commit/" + CobblemonBuildDetails.GIT_COMMIT + ")");
cobblemon.add("Branch", CobblemonBuildDetails.BRANCH);
cobblemon.addStackTrace(builder);
builder.append("\n\n");
}
}
@@ -1,30 +0,0 @@
/*
* 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.mixin;
import com.cobblemon.mod.common.sherds.CobblemonSherds;
import net.minecraft.block.DecoratedPotPatterns;
import net.minecraft.item.Item;
import net.minecraft.registry.RegistryKey;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(DecoratedPotPatterns.class)
public abstract class DecoratedPotPatternsMixin {
@Inject(method = "fromSherd", at=@At("HEAD"), cancellable = true)
private static void cobblemon$getCobblemonSherdTexture(Item sherd,
CallbackInfoReturnable<RegistryKey<String>> cir) {
if (CobblemonSherds.INSTANCE.getSherdToPattern().containsKey(sherd)) {
cir.setReturnValue(CobblemonSherds.INSTANCE.getSherdToPattern().get(sherd));
return;
}
}
}
@@ -1,33 +0,0 @@
/*
* 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.mixin;
import net.minecraft.entity.passive.VillagerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.village.VillagerProfession;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import com.cobblemon.mod.common.villager.VillagerGatherableItems;
import java.util.Objects;
@Mixin(VillagerEntity.class)
public abstract class EntityVillagerMixin {
@Inject(method = "canGather", at = @At(value = "RETURN"), cancellable = true)
private void cobblemon$canGather(ItemStack stack, CallbackInfoReturnable<Boolean> ci) {
final VillagerEntity villager = (VillagerEntity) (Object) this;
if(ci.getReturnValue() == false && Objects.equals(villager.getVillagerData().getProfession(), VillagerProfession.FARMER) && villager.getInventory().canInsert(stack)) {
if(VillagerGatherableItems.INSTANCE.getVillagerGatherableItems().contains(stack.getItem()))
ci.setReturnValue(true);
}
}
}
@@ -1,38 +0,0 @@
/*
* 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.mixin;
import com.cobblemon.mod.common.block.PreEmptsExplosion;
import net.minecraft.block.BlockState;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraft.world.explosion.Explosion;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(value = Explosion.class)
public class ExplosionMixin {
@Redirect(
method = "affectWorld",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/World;getBlockState(Lnet/minecraft/util/math/BlockPos;)Lnet/minecraft/block/BlockState;",
ordinal = 0
)
)
public BlockState cobblemon$whenExploded(World world, BlockPos pos) {
BlockState blockState = world.getBlockState(pos);
if(blockState.getBlock() instanceof PreEmptsExplosion preExplosionBlock) {
preExplosionBlock.whenExploded(world, blockState, pos);
}
return blockState;
}
}
@@ -8,37 +8,20 @@
package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.api.scheduling.ClientTaskTracker;
import net.minecraft.client.MinecraftClient;
import com.cobblemon.mod.common.api.scheduling.ScheduledTaskTracker;
import net.minecraft.client.render.GameRenderer;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(GameRenderer.class)
public class GameRendererMixin {
@Unique
long lastTime = -1;
@Inject(
method = "render",
at = @At(value = "TAIL")
)
public void render(float tickDelta, long startTime, boolean tick, CallbackInfo ci) {
MinecraftClient client = MinecraftClient.getInstance();
long newTime = System.currentTimeMillis();
// Don't play scheduled animations when the game is paused
if (client.isPaused()) {
lastTime = newTime;
return;
}
if (lastTime != -1) {
ClientTaskTracker.INSTANCE.update((newTime - lastTime) / 1000F);
}
lastTime = newTime;
ScheduledTaskTracker.INSTANCE.update();
}
}
@@ -1,31 +0,0 @@
/*
* 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.mixin;
import com.cobblemon.mod.common.api.pokemon.effect.ShoulderEffectRegistry;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.effect.StatusEffectInstance;
import net.minecraft.server.network.ServerPlayerEntity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(LivingEntity.class)
public abstract class LivingEntityMixin {
@Inject(method = "onStatusEffectRemoved", at = @At(value = "TAIL"))
private void cobblemon$onStatusEffectRemoved(StatusEffectInstance effect, CallbackInfo ci) {
final LivingEntity entity = (LivingEntity) (Object) this;
if (entity instanceof ServerPlayerEntity) {
ShoulderEffectRegistry.INSTANCE.onEffectEnd((ServerPlayerEntity) entity);
}
}
}
@@ -1,69 +0,0 @@
/*
* 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.mixin;
import com.cobblemon.mod.common.client.CobblemonBakingOverrides;
import java.io.IOException;
import java.util.Arrays;
import java.util.Map;
import net.minecraft.client.color.block.BlockColors;
import net.minecraft.client.render.model.ModelLoader;
import net.minecraft.client.render.model.UnbakedModel;
import net.minecraft.client.render.model.json.JsonUnbakedModel;
import net.minecraft.client.util.ModelIdentifier;
import net.minecraft.util.Identifier;
import net.minecraft.util.profiler.Profiler;
import org.slf4j.Logger;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.InjectionPoint;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.points.BeforeStringInvoke;
@Mixin(ModelLoader.class)
public abstract class ModelLoaderMixin {
@Shadow protected abstract void addModel(ModelIdentifier modelId);
@Final
@Shadow
private Map<Identifier, UnbakedModel> unbakedModels;
@Final
@Shadow
private static Logger LOGGER;
@Inject(
method = "<init>",
at = @At("TAIL")
)
public void init(BlockColors blockColors,
Profiler profiler,
Map jsonUnbakedModels,
Map blockStates,
CallbackInfo ci) {
CobblemonBakingOverrides.INSTANCE.getModels().forEach(bakingOverride -> {
try {
this.unbakedModels.put(bakingOverride.getModelIdentifier(), this.loadModelFromJson(bakingOverride.getModelLocation()));
this.addModel(bakingOverride.getModelIdentifier());
} catch (IOException e) {
LOGGER.error("Error loading a Cobblemon BakedModel:", e);
throw new RuntimeException(e);
}
});
}
@Shadow
private JsonUnbakedModel loadModelFromJson(Identifier id) throws IOException {
return null;
}
}
@@ -1,49 +0,0 @@
/*
* 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.mixin;
import com.cobblemon.mod.common.client.render.models.blockbench.PoseableEntityModel;
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Bone;
import com.cobblemon.mod.common.client.render.models.blockbench.repository.RenderContext;
import net.minecraft.client.model.ModelPart;
import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.Entity;
import org.jetbrains.annotations.NotNull;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import java.util.Map;
@Mixin(ModelPart.class)
public abstract class ModelPartMixin implements Bone {
@Shadow public abstract void render(MatrixStack matrices, VertexConsumer vertices, int light, int overlay, float red, float green, float blue, float alpha);
@Shadow public abstract void rotate(MatrixStack matrixStack);
@Shadow @Final
public Map<String, ModelPart> children;
@NotNull
@Override
public Map<String, Bone> getChildren() {
return (Map<String, Bone>) (Object) children;
}
@Override
public void render(RenderContext context, MatrixStack stack, VertexConsumer buffer, int packedLight, int packedOverlay, float r, float g, float b, float a) {
this.render(stack, buffer, packedLight, packedOverlay, r, g, b, a);
}
@Override
public void transform(MatrixStack matrixStack) {
this.rotate(matrixStack);
}
}
@@ -1,37 +0,0 @@
/*
* 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.mixin;
import com.cobblemon.mod.common.client.sound.battle.BattleMusicController;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.sound.MusicTracker;
import net.minecraft.client.sound.SoundInstance;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(MusicTracker.class)
public class MusicTrackerMixin {
@Shadow @Final
private MinecraftClient client;
@Shadow @Nullable
private SoundInstance current;
/** Freezes the tracker while a BattleMusicInstance is in progress. Current SoundInstance being tracked will be paused by BattleMusicHandler. */
@Inject(method = "tick()V", at = @At("HEAD"), cancellable = true)
public void tick(CallbackInfo cb) {
if (this.client.getSoundManager().isPlaying(BattleMusicController.INSTANCE.getMusic())) cb.cancel();
}
}
@@ -1,37 +0,0 @@
/*
* 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.mixin;
import com.cobblemon.mod.common.api.snowstorm.ParticleMaterials;
import com.google.common.collect.ImmutableList;
import net.minecraft.client.particle.ParticleManager;
import net.minecraft.client.particle.ParticleTextureSheet;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Mutable;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.List;
@Mixin(ParticleManager.class)
final class ParticleManagerMixin {
@Mutable
@Final
@Shadow
private static List<ParticleTextureSheet> PARTICLE_TEXTURE_SHEETS;
@Inject(at = @At("RETURN"), method = "<clinit>")
private static void lodestone$addTypes(CallbackInfo ci) {
PARTICLE_TEXTURE_SHEETS = ImmutableList.<ParticleTextureSheet>builder().addAll(PARTICLE_TEXTURE_SHEETS)
.add(ParticleMaterials.INSTANCE.getADD(), ParticleMaterials.INSTANCE.getALPHA(), ParticleMaterials.INSTANCE.getBLEND(), ParticleMaterials.INSTANCE.getOPAQUE()).build();
}
}
@@ -1,33 +0,0 @@
/*
* 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.mixin;
import com.cobblemon.mod.common.CobblemonItems;
import net.minecraft.entity.mob.PiglinBrain;
import net.minecraft.item.ItemStack;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(PiglinBrain.class)
public class PiglinBarterMixin {
@Inject(method = "acceptsForBarter", at = @At(value = "RETURN"), cancellable = true)
private static void cobblemon$acceptsForBarter(ItemStack stack, CallbackInfoReturnable<Boolean> ci) {
if(!ci.getReturnValue()) {
//TODO: Make a tag?
if(stack.isOf(CobblemonItems.RELIC_COIN_POUCH))
ci.setReturnValue(true);
}
}
}
@@ -1,31 +0,0 @@
/*
* 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.mixin;
import com.cobblemon.mod.common.CobblemonItems;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.mob.PiglinEntity;
import net.minecraft.item.ItemStack;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(PiglinEntity.class)
public abstract class PiglinEntityMixin {
@Inject(method = "equipToOffHand", at = @At(value = "HEAD"), cancellable = true)
public void cobblemon$isValidBarteringItem(ItemStack stack, CallbackInfo ci) {
PiglinEntity entity = (PiglinEntity)(Object) this;
if (stack.isOf(CobblemonItems.RELIC_COIN_POUCH)) {
entity.equipStack(EquipmentSlot.OFFHAND, stack);
entity.updateDropChances(EquipmentSlot.OFFHAND);
ci.cancel();
}
}
}
@@ -14,7 +14,6 @@ import com.cobblemon.mod.common.api.events.CobblemonEvents;
import com.cobblemon.mod.common.api.events.item.LeftoversCreatedEvent;
import com.cobblemon.mod.common.api.storage.NoPokemonStoreException;
import com.cobblemon.mod.common.api.storage.party.PartyStore;
import com.cobblemon.mod.common.api.tags.CobblemonItemTags;
import com.cobblemon.mod.common.pokemon.Pokemon;
import com.cobblemon.mod.common.util.CompoundTagExtensionsKt;
import com.cobblemon.mod.common.util.DataKeys;
@@ -23,8 +22,11 @@ import net.minecraft.entity.ItemEntity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.sound.SoundEvent;
import net.minecraft.sound.SoundEvents;
import net.minecraft.text.Text;
import net.minecraft.world.World;
import org.objectweb.asm.Opcodes;
@@ -38,6 +40,8 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.Objects;
import java.util.UUID;
import static com.cobblemon.mod.common.util.LocalizationUtilsKt.lang;
@Mixin(PlayerEntity.class)
public abstract class PlayerMixin extends LivingEntity {
@@ -140,8 +144,8 @@ public abstract class PlayerMixin extends LivingEntity {
)
public void onEatFood(World world, ItemStack stack, CallbackInfoReturnable<ItemStack> cir) {
if (!getWorld().isClient) {
if (stack.isIn(CobblemonItemTags.LEAVES_LEFTOVERS) && getWorld().random.nextDouble() < Cobblemon.config.getAppleLeftoversChance()) {
ItemStack leftovers = new ItemStack(CobblemonItems.LEFTOVERS);
if (stack.getItem() == Items.APPLE && getWorld().random.nextDouble() < Cobblemon.config.getAppleLeftoversChance()) {
ItemStack leftovers = new ItemStack(CobblemonItems.LEFTOVERS.get());
ServerPlayerEntity player = Objects.requireNonNull(getServer()).getPlayerManager().getPlayer(uuid);
assert player != null;
CobblemonEvents.LEFTOVERS_CREATED.postThen(
@@ -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.mixin;
import com.cobblemon.mod.common.api.spawning.mixins.CachedOnlyChunkAccessor;
import com.mojang.datafixers.util.Either;
import net.minecraft.server.world.ChunkHolder;
import net.minecraft.server.world.ServerChunkManager;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.ChunkManager;
import net.minecraft.world.chunk.ChunkStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import java.util.concurrent.CompletableFuture;
@Mixin(ServerChunkManager.class)
public abstract class ServerChunkManagerMixin extends ChunkManager implements CachedOnlyChunkAccessor {
@Shadow @Nullable protected abstract ChunkHolder getChunkHolder(long pos);
@Override
public Chunk cobblemon$request(int x, int z, @NotNull ChunkStatus status) {
long l = ChunkPos.toLong(x, z);
ChunkHolder holder = getChunkHolder(l);
if (holder != null) {
CompletableFuture<Either<Chunk, ChunkHolder.Unloaded>> future = holder.getFutureFor(status);
if (future.isDone()) {
return future.join().left().orElse(null);
}
}
return null;
}
}
@@ -8,12 +8,14 @@
package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.block.ShearableBlock;
import kotlin.Unit;
import com.cobblemon.mod.common.block.ApricornBlock;
import net.minecraft.block.BlockState;
import net.minecraft.block.dispenser.ShearsDispenserBehavior;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.sound.SoundCategory;
import net.minecraft.sound.SoundEvents;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.event.GameEvent;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
@@ -22,12 +24,15 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(ShearsDispenserBehavior.class)
public abstract class ShearsDispenserBehaviorMixin {
// This exists, so we can execute our custom interaction only if no one redirected shears interactions to overwrite the vanilla ones.
// This exists so we can execute our custom interaction only if no one redirected shears interactions to overwrite the vanilla ones.
@Inject(method = "tryShearBlock", at = @At("HEAD"), cancellable = true)
private static void cobblemon$tryApricornHarvest(ServerWorld world, BlockPos pos, CallbackInfoReturnable<Boolean> cir) {
final BlockState state = world.getBlockState(pos);
if (state.getBlock() instanceof ShearableBlock shearableBlock) {
cir.setReturnValue(shearableBlock.attemptShear(world, state, pos, () -> Unit.INSTANCE));
if (state.getBlock() instanceof ApricornBlock apricornBlock && state.get(ApricornBlock.Companion.getAGE()) == ApricornBlock.MAX_AGE) {
world.playSound(null, pos, SoundEvents.ENTITY_SHEEP_SHEAR, SoundCategory.BLOCKS, 1F, 1F);
apricornBlock.harvest(world, state, pos);
world.emitGameEvent(null, GameEvent.SHEAR, pos);
cir.setReturnValue(true);
}
}
@@ -1,84 +0,0 @@
/*
* 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.mixin;
import com.cobblemon.mod.common.client.sound.battle.BattleMusicController;
import com.cobblemon.mod.common.duck.SoundManagerDuck;
import com.cobblemon.mod.common.duck.SoundSystemDuck;
import net.minecraft.client.sound.*;
import net.minecraft.sound.SoundCategory;
import net.minecraft.util.Identifier;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(SoundManager.class)
public abstract class SoundManagerMixin implements SoundManagerDuck {
@Shadow
public abstract boolean isPlaying(SoundInstance sound);
@Shadow @Final
private SoundSystem soundSystem;
// Never-ending ambient loops are a special exception (they are only initiated once) and should always be paused if filtered.
private boolean isAmbientLoop(SoundInstance sound) {
return sound instanceof BiomeEffectSoundPlayer.MusicLoop || sound instanceof AmbientSoundLoops.Underwater;
}
private boolean filterCondition(SoundInstance sound) {
return !isAmbientLoop(sound) &&
this.isPlaying(BattleMusicController.INSTANCE.getMusic()) &&
BattleMusicController.INSTANCE.getFilteredCategories().contains(sound.getCategory());
}
private boolean ambientLoopCondition(SoundInstance sound) {
return isAmbientLoop(sound) &&
this.isPlaying(BattleMusicController.INSTANCE.getMusic()) &&
BattleMusicController.INSTANCE.getFilteredCategories().contains(sound.getCategory());
}
/** Pauses the queried SoundInstance(s). If id is null, will pause all sounds belonging to the SoundCategory. */
@Override
public void pauseSounds(@Nullable Identifier id, @Nullable SoundCategory category) {
((SoundSystemDuck)soundSystem).pauseSounds(id, category);
}
/** Resumes the queried SoundInstance(s). If id is null, will resume all sounds belonging to the SoundCategory. */
@Override
public void resumeSounds(@Nullable Identifier id, @Nullable SoundCategory category) {
((SoundSystemDuck)soundSystem).resumeSounds(id, category);
}
/** Blocks filtered sounds from being played while a BattleMusicInstance is in progress. */
@Inject(method = "play(Lnet/minecraft/client/sound/SoundInstance;)V", at = @At("HEAD"), cancellable = true)
public void playStart(SoundInstance sound, CallbackInfo cb) {
if (filterCondition(sound)) cb.cancel();
}
@Inject(method = "play(Lnet/minecraft/client/sound/SoundInstance;I)V", at = @At("HEAD"), cancellable = true)
public void playStart(SoundInstance sound, int delay, CallbackInfo cb) {
if (filterCondition(sound)) cb.cancel();
}
/** Pauses ambient loops while a BattleMusicInstance is in progress. */
@Inject(method = "play(Lnet/minecraft/client/sound/SoundInstance;)V", at = @At("TAIL"))
public void playEnd(SoundInstance sound, CallbackInfo cb) {
if (ambientLoopCondition(sound)) this.pauseSounds(sound.getId(), SoundCategory.AMBIENT);
}
@Inject(method = "play(Lnet/minecraft/client/sound/SoundInstance;I)V", at = @At("TAIL"))
public void playEnd(SoundInstance sound, int delay, CallbackInfo cb) {
if (ambientLoopCondition(sound)) this.pauseSounds(sound.getId(), SoundCategory.AMBIENT);
}
}
@@ -1,110 +0,0 @@
/*
* 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.mixin;
import com.cobblemon.mod.common.client.sound.battle.BattleMusicController;
import com.cobblemon.mod.common.duck.SoundSystemDuck;
import com.google.common.collect.Multimap;
import net.minecraft.client.sound.*;
import net.minecraft.sound.SoundCategory;
import net.minecraft.util.Identifier;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.Map;
@Mixin(SoundSystem.class)
public abstract class SoundSystemMixin implements SoundSystemDuck {
@Shadow
private boolean started;
@Shadow
private Multimap<SoundCategory, SoundInstance> sounds;
@Shadow @Final
private Map<SoundInstance, Channel.SourceManager> sources;
@Shadow
protected abstract void stop(SoundInstance sound);
@Shadow
public abstract boolean isPlaying(SoundInstance sound);
/** Resumes the Source belonging to the queried SoundInstance. */
private void resume(SoundInstance sound) {
Channel.SourceManager sourceManager = this.sources.get(sound);
if (this.started && sourceManager != null) sourceManager.run(Source::resume);
}
/** Pauses the Source belonging to the queried SoundInstance. */
private void pause(SoundInstance sound) {
Channel.SourceManager sourceManager = this.sources.get(sound);
if (this.started && sourceManager != null) sourceManager.run(Source::pause);
}
/** Resumes the SoundInstance(s) queried by id and/or category. */
@Override
public void resumeSounds(@Nullable Identifier id, @Nullable SoundCategory category) {
if (category != null) {
this.sounds.get(category).forEach((sound) -> {
if (id == null || sound.getId().equals(id)) resume(sound);
});
} else if (id == null) {
this.sources.keySet().forEach(this::resume);
} else {
this.sources.keySet().forEach(sound -> {
if (sound.getId().equals(id)) resume(sound);
});
}
}
/** Pauses the SoundInstances queried by id and/or category. */
@Override
public void pauseSounds(@Nullable Identifier id, @Nullable SoundCategory category) {
if (category != null) {
this.sounds.get(category).forEach((sound) -> {
if (id == null || sound.getId().equals(id)) pause(sound);
});
} else if (id == null) {
this.sources.keySet().forEach(this::pause);
} else {
this.sources.keySet().forEach(sound -> {
if (sound.getId().equals(id)) pause(sound);
});
}
}
/** Allows stopping all SoundInstances that belong to a queried category. */
@Inject(method = "stopSounds(Lnet/minecraft/util/Identifier;Lnet/minecraft/sound/SoundCategory;)V", at = @At("HEAD"), cancellable = true)
public void stopSounds(@Nullable Identifier id, @Nullable SoundCategory category, CallbackInfo cb) {
if (id == null && category != null) {
this.sounds.get(category).forEach(this::stop);
cb.cancel();
}
}
/** Different behavior for resuming SoundInstances while a BattleMusicInstance is being played. We do not want to resume filtered sounds. */
@Inject(method = "resumeAll()V", at = @At("HEAD"), cancellable = true)
public void resumeAll(CallbackInfo cb) {
if (this.isPlaying(BattleMusicController.INSTANCE.getMusic())) {
this.sounds.values().forEach(sound -> {
if (sound == BattleMusicController.INSTANCE.getMusic() || !BattleMusicController.INSTANCE.getFilteredCategories().contains(sound.getCategory())) {
resume(sound);
}
});
cb.cancel();
}
}
}
@@ -1,32 +0,0 @@
/*
* 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.mixin;
import com.mojang.datafixers.util.Pair;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import net.minecraft.structure.pool.StructurePool;
import net.minecraft.structure.pool.StructurePoolElement;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Mutable;
import org.spongepowered.asm.mixin.gen.Accessor;
import java.util.List;
@Mixin(StructurePool.class)
public interface StructurePoolAccessor {
@Accessor("elementCounts")
List<Pair<StructurePoolElement, Integer>> getElementCounts();
@Mutable
@Accessor("elementCounts")
void setElementCounts(List<Pair<StructurePoolElement, Integer>> elementCounts);
@Accessor("elements")
ObjectArrayList<StructurePoolElement> getElements();
}
@@ -1,217 +0,0 @@
/*
* 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.mixin;
import com.cobblemon.mod.common.world.CobblemonStructureIDs;
import net.minecraft.registry.Registry;
import net.minecraft.structure.PoolStructurePiece;
import net.minecraft.structure.StructureTemplateManager;
import net.minecraft.structure.pool.*;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.random.Random;
import net.minecraft.util.shape.VoxelShape;
import net.minecraft.world.HeightLimitView;
import net.minecraft.world.gen.chunk.ChunkGenerator;
import net.minecraft.world.gen.noise.NoiseConfig;
import org.apache.commons.lang3.mutable.MutableObject;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Mutable;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.ModifyVariable;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.*;
@Mixin(StructurePoolBasedGenerator.StructurePoolGenerator.class)
public abstract class StructurePoolGeneratorMixin {
@Final
@Mutable
@Shadow Deque<StructurePoolBasedGenerator.ShapedPoolStructurePiece> structurePieces;
Map<String, Integer> generatedStructureGroupCounts;
private static final Map<String, Integer> structureMaxes;
private static final Map<Identifier, Set<String>> structureGroups = new HashMap<>();
static {
String pokecenter = "pokecenter";
String berry = "berry_farm";
structureGroups.put(CobblemonStructureIDs.PLAINS_POKECENTER, Set.of(pokecenter));
structureGroups.put(CobblemonStructureIDs.DESERT_POKECENTER, Set.of(pokecenter));
structureGroups.put(CobblemonStructureIDs.SAVANNA_POKECENTER, Set.of(pokecenter));
structureGroups.put(CobblemonStructureIDs.SNOWY_POKECENTER, Set.of(pokecenter));
structureGroups.put(CobblemonStructureIDs.TAIGA_POKECENTER, Set.of(pokecenter));
structureGroups.put(CobblemonStructureIDs.SAVANNA_BERRY_SMALL, Set.of(berry));
structureGroups.put(CobblemonStructureIDs.SAVANNA_BERRY_LARGE, Set.of(berry));
structureGroups.put(CobblemonStructureIDs.PLAINS_BERRY_SMALL, Set.of(berry));
structureGroups.put(CobblemonStructureIDs.PLAINS_BERRY_LARGE, Set.of(berry));
structureGroups.put(CobblemonStructureIDs.SNOWY_BERRY_SMALL, Set.of(berry));
structureGroups.put(CobblemonStructureIDs.SNOWY_BERRY_LARGE, Set.of(berry));
structureGroups.put(CobblemonStructureIDs.DESERT_BERRY_SMALL, Set.of(berry));
structureGroups.put(CobblemonStructureIDs.DESERT_BERRY_LARGE, Set.of(berry));
structureGroups.put(CobblemonStructureIDs.TAIGA_BERRY_SMALL, Set.of(berry));
structureGroups.put(CobblemonStructureIDs.TAIGA_BERRY_LARGE, Set.of(berry));
//Mapped using location string as key
Map<String, Integer> aMap = new HashMap<>();
aMap.put(pokecenter, 1);
aMap.put(berry, 2);
// aMap.put(CobblemonStructureIDs.PLAINS_LONG_PATH, 3);
// aMap.put(CobblemonStructureIDs.DESERT_LONG_PATH, 3);
// aMap.put(CobblemonStructureIDs.SAVANNA_LONG_PATH, 3);
// aMap.put(CobblemonStructureIDs.SNOWY_LONG_PATH, 3);
// aMap.put(CobblemonStructureIDs.TAIGA_LONG_PATH, 3);
structureMaxes = Collections.unmodifiableMap(aMap);
}
public Set<String> getGroups(Identifier structureIdentifier) {
return structureGroups.getOrDefault(structureIdentifier, Set.of());
}
public boolean hasReachedMaximum(Identifier structureIdentifier) {
Set<String> groups = getGroups(structureIdentifier);
for (String group : groups) {
int count = generatedStructureGroupCounts.getOrDefault(group, 0);
if (count >= structureMaxes.getOrDefault(group, Integer.MAX_VALUE)) {
return true;
}
}
return false;
}
public void incrementStructureCount(Identifier structureIdentifier) {
Set<String> groups = getGroups(structureIdentifier);
for (String group : groups) {
generatedStructureGroupCounts.put(group, generatedStructureGroupCounts.getOrDefault(group, 0) + 1);
}
}
@Inject(method = "<init>", at = @At("RETURN"))
private void onStructurePoolGeneratorCreation(Registry<StructurePool> registry, int maxSize, ChunkGenerator chunkGenerator, StructureTemplateManager structureTemplateManager, List<? super PoolStructurePiece> children, Random random, CallbackInfo ci) {
generatedStructureGroupCounts = new HashMap<>();
}
@ModifyVariable(method = "generatePiece", at = @At("STORE"), ordinal = 1)
private Iterator<StructurePoolElement> reduceStructurePoolElementIterator(Iterator<StructurePoolElement> iterator) {
List<StructurePoolElement> reducedList = new ArrayList<>();
while (iterator.hasNext()) {
StructurePoolElement structure = iterator.next();
Identifier structurePieceLocationKey = getCobblemonOnlyLocation(structure);
if (structurePieceLocationKey == null) {
reducedList.add(structure);
continue;
}
if (!hasReachedMaximum(structurePieceLocationKey)) {
reducedList.add(structure);
}
}
return reducedList.iterator();
}
@ModifyVariable(method = "generatePiece", at = @At("STORE"), ordinal = 1)
private PoolStructurePiece injected(PoolStructurePiece poolStructurePiece) {
Identifier structureLocationKey = getCobblemonOnlyLocation(poolStructurePiece.getPoolElement());
if (structureLocationKey != null) {
incrementStructureCount(structureLocationKey);
}
return poolStructurePiece;
}
// This doesn't SEEM necessary? It appears to work without.
@Inject(method = "generatePiece", at = @At("HEAD"))
private void beforeGeneratePiece(PoolStructurePiece piece, MutableObject<VoxelShape> pieceShape, int minY, boolean modifyBoundingBox, HeightLimitView world, NoiseConfig noiseConfig, CallbackInfo ci) {
// Identifier structureLocationKey = getCobblemonOnlyLocation(piece.getPoolElement());
//
// if (structureLocationKey != null) {
// Integer currentlyGenerated = generatedStructureCounts.get(structureLocationKey);
// if (currentlyGenerated == null) currentlyGenerated = 0;
// generatedStructureCounts.put(structureLocationKey, currentlyGenerated + 1);
// }
//
// List<StructurePoolBasedGenerator.ShapedPoolStructurePiece> reducedStructurePiecesList = structurePieces.stream().toList();
//
// for (Identifier maxStructureLocationKey : structureMaxes.keySet()) {
// Integer maxAllowed = structureMaxes.get(maxStructureLocationKey);
//
// Integer currentlyGenerated = generatedStructureCounts.get(maxStructureLocationKey);
// if (currentlyGenerated == null) currentlyGenerated = 0;
// if (currentlyGenerated < maxAllowed) {
// continue;
// }
//
// //Already have max so need to remove
// reducedStructurePiecesList = reducedStructurePiecesList.stream()
// .filter(shapedStructurePiece -> {
// Identifier locationKey = getCobblemonOnlyLocation(shapedStructurePiece.piece.getPoolElement());
// if (locationKey == null) {
// return true;
// }
//
// return !locationKey.equals(maxStructureLocationKey);
// })
// .collect(Collectors.toList());
// }
//
// structurePieces = new ArrayDeque<>(reducedStructurePiecesList);
}
private static Identifier getCobblemonOnlyLocation(StructurePoolElement structurePoolElement) {
Identifier location = getLocationIfAvailable(structurePoolElement);
if (location == null) return null;
if (!location.getNamespace().equals("cobblemon")) return null;
return location;
}
private static Identifier getLocationIfAvailable(StructurePoolElement structurePoolElement) {
if (structurePoolElement instanceof LegacySinglePoolElement legacySinglePoolElement) {
if (legacySinglePoolElement.location.left().isEmpty()) return null;
return legacySinglePoolElement.location.left().get();
} else if (structurePoolElement instanceof SinglePoolElement singlePoolElement) {
if (singlePoolElement.location.left().isEmpty()) return null;
return singlePoolElement.location.left().get();
} else {
return null;
}
}
// private List<StructurePoolElement> removeInstanceOfLocationKeyFrom(List<StructurePoolElement> structureList, Integer allowedNumberOfInstances, Identifier locationKey) {
// List<StructurePoolElement> reducedList = new ArrayList<>();
// int instancesFound = 0;
//
// for (StructurePoolElement structurePoolElement: structureList) {
// Identifier structureKey = getCobblemonOnlyLocation(structurePoolElement);
// if (structureKey == null || !structureKey.equals(locationKey)) {
// reducedList.add(structurePoolElement);
// continue;
// }
//
// if (instancesFound >= allowedNumberOfInstances) {
// continue;
// }
//
// reducedList.add(structurePoolElement);
// instancesFound++;
// }
//
// return reducedList;
// }
}
@@ -1,43 +0,0 @@
/*
* 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.mixin;
import com.cobblemon.mod.common.bridges.StructureProcessorListBridge;
import com.google.common.collect.ImmutableList;
import java.util.ArrayList;
import java.util.List;
import net.minecraft.structure.processor.StructureProcessor;
import net.minecraft.structure.processor.StructureProcessorList;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Mutable;
import org.spongepowered.asm.mixin.Shadow;
@Mixin(StructureProcessorList.class)
public class StructureProcessorListMixin implements StructureProcessorListBridge {
@Final
@Mutable
@Shadow
private List<StructureProcessor> list;
@Override
public void append(StructureProcessor processor) {
List<StructureProcessor> mutable = new ArrayList<>(this.list);
mutable.add(processor);
this.list = ImmutableList.copyOf(mutable);
}
@Override
public void clear() {
this.list = ImmutableList.of();
}
}
@@ -1,23 +0,0 @@
/*
* 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.mixin.accessor;
import net.minecraft.entity.vehicle.BoatEntity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(BoatEntity.class)
public interface BoatEntityAccessor {
@Accessor
void setFallVelocity(double fallVelocity);
@Accessor
BoatEntity.Location getLocation();
}
@@ -1,26 +0,0 @@
/*
* 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.mixin.accessor;
import net.minecraft.entity.effect.StatusEffectInstance;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(StatusEffectInstance.class)
public interface StatusEffectInstanceAccessor {
@Accessor
void setAmplifier(int amplifier);
@Accessor
void setShowParticles(boolean showParticles);
@Accessor
void setShowIcon(boolean showIcon);
}
@@ -1,33 +0,0 @@
/*
* 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.mixin.invoker;
import com.cobblemon.mod.common.integration.adorn.AdornCompatibility;
import java.util.List;
import juuxel.adorn.block.variant.BlockVariantSet;
import juuxel.adorn.block.variant.BlockVariantSets;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
//This is a yucky hack but better than what we were doing before
@Mixin(BlockVariantSets.class)
public abstract class AdornRegisterInvoker {
@Final
@Shadow(remap = false)
private static List<BlockVariantSet> variantSets;
@Inject(method = "register()V", at = @At("HEAD"), remap = false)
void register(CallbackInfo ci) {
variantSets.add(AdornCompatibility.INSTANCE);
}
}
@@ -1,41 +0,0 @@
/*
* 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.mixin.invoker;
import net.minecraft.block.*;
import net.minecraft.resource.featuretoggle.FeatureFlag;
import net.minecraft.sound.BlockSoundGroup;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;
@SuppressWarnings("unused")
@Mixin(Blocks.class)
public interface BlocksInvoker {
@Invoker("createLogBlock")
static PillarBlock createLogBlock(MapColor topMapColor, MapColor sideMapColor) {
throw new UnsupportedOperationException();
}
@Invoker("createLeavesBlock")
static LeavesBlock createLeavesBlock(BlockSoundGroup soundGroup) {
throw new UnsupportedOperationException();
}
@Invoker("createWoodenButtonBlock")
static ButtonBlock createWoodenButtonBlock(BlockSetType blockSetType, FeatureFlag... requiredFeatures) {
throw new UnsupportedOperationException();
}
@Invoker("createFlowerPotBlock")
static FlowerPotBlock createFlowerPotBlock(Block flower, FeatureFlag... requiredFeatures) {
throw new UnsupportedOperationException();
}
}
@@ -1,21 +0,0 @@
/*
* 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.mixin.invoker;
import net.minecraft.world.GameRules;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;
@Mixin(GameRules.BooleanRule.class)
public interface BooleanRuleInvoker {
@Invoker("create")
static GameRules.Type<GameRules.BooleanRule> cobblemon$create(boolean initialValue) {
throw new UnsupportedOperationException();
}
}
@@ -1,20 +0,0 @@
/*
* 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.mixin.invoker;
import net.minecraft.client.network.ClientPlayNetworkHandler;
import net.minecraft.entity.Entity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;
@Mixin(ClientPlayNetworkHandler.class)
public interface ClientPlayNetworkHandlerInvoker {
@Invoker
void callPlaySpawnSound(Entity entity);
}
@@ -1,24 +0,0 @@
/*
* 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.mixin.invoker;
import net.minecraft.block.AbstractBlock;
import net.minecraft.block.BlockSetType;
import net.minecraft.block.DoorBlock;
import net.minecraft.sound.SoundEvent;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;
@Mixin(DoorBlock.class)
public interface DoorBlockInvoker {
@Invoker("<init>")
static DoorBlock cobblemon$create(AbstractBlock.Settings settings, BlockSetType blockSetType) {
throw new UnsupportedOperationException();
}
}
@@ -1,20 +0,0 @@
/*
* 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.mixin.invoker;
import net.minecraft.block.Block;
import org.spongepowered.asm.mixin.Mixin;
import net.minecraft.block.FireBlock;
import net.minecraft.block.Blocks;
import org.spongepowered.asm.mixin.gen.Invoker;
@Mixin(FireBlock.class)
public interface FireBlockInvoker {
@Invoker("registerFlammableBlock") void registerNewFlammableBlock(Block block, int burnChance, int spreadChance);
}
@@ -1,24 +0,0 @@
/*
* 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.mixin.invoker;
import net.minecraft.block.AbstractBlock;
import net.minecraft.block.BlockSetType;
import net.minecraft.block.PressurePlateBlock;
import net.minecraft.sound.SoundEvent;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;
@Mixin(PressurePlateBlock.class)
public interface PressurePlateBlockInvoker {
@Invoker("<init>")
static PressurePlateBlock cobblemon$create(PressurePlateBlock.ActivationRule type, AbstractBlock.Settings settings, BlockSetType blockSetType) {
throw new UnsupportedOperationException();
}
}
@@ -1,23 +0,0 @@
/*
* 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.mixin.invoker;
import net.minecraft.block.AbstractBlock;
import net.minecraft.block.BlockState;
import net.minecraft.block.StairsBlock;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;
@Mixin(StairsBlock.class)
public interface StairsBlockInvoker {
@Invoker("<init>")
static StairsBlock cobblemon$create(BlockState baseBlockState, AbstractBlock.Settings settings) {
throw new UnsupportedOperationException();
}
}
@@ -1,24 +0,0 @@
/*
* 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.mixin.invoker;
import net.minecraft.block.AbstractBlock;
import net.minecraft.block.BlockSetType;
import net.minecraft.block.TrapdoorBlock;
import net.minecraft.sound.SoundEvent;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;
@Mixin(TrapdoorBlock.class)
public interface TrapdoorBlockInvoker {
@Invoker("<init>")
static TrapdoorBlock cobblemon$create(AbstractBlock.Settings settings, BlockSetType blockSetType) {
throw new UnsupportedOperationException();
}
}
@@ -14,7 +14,6 @@ import net.minecraft.client.render.item.ItemModels;
import net.minecraft.client.render.item.ItemRenderer;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.render.model.json.ModelTransformation;
import net.minecraft.client.render.model.json.ModelTransformationMode;
import net.minecraft.client.util.ModelIdentifier;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.client.world.ClientWorld;
@@ -34,12 +33,13 @@ public abstract class ItemRendererMixin {
@Shadow @Final private ItemModels models;
@Shadow public abstract void renderItem(ItemStack stack, ModelTransformationMode renderMode, boolean leftHanded, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay, BakedModel model);
@Shadow public abstract void renderItem(ItemStack stack, ModelTransformation.Mode renderMode, boolean leftHanded, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay, BakedModel model);
@Inject(method = "getModel", at = @At("HEAD"), cancellable = true)
private void cobblemon$bakePokeballModel(ItemStack stack, World world, LivingEntity entity, int seed, CallbackInfoReturnable<BakedModel> cir) {
if (stack.getItem() instanceof PokeBallItem pokeBallItem) {
BakedModel model = this.models.getModelManager().getModel(new ModelIdentifier(pokeBallItem.getPokeBall().getModel3d(), "inventory"));
ModelIdentifier modelIdentifier = new ModelIdentifier(pokeBallItem.getPokeBall().getModel3d());
BakedModel model = this.models.getModelManager().getModel(modelIdentifier);
ClientWorld clientWorld = world instanceof ClientWorld ? (ClientWorld) world : null;
BakedModel overriddenModel = model.getOverrides().apply(model, stack, clientWorld, entity, seed);
cir.setReturnValue(overriddenModel == null ? this.models.getModelManager().getMissingModel() : overriddenModel);
@@ -47,14 +47,15 @@ public abstract class ItemRendererMixin {
}
@Inject(
method = "renderItem(Lnet/minecraft/item/ItemStack;Lnet/minecraft/client/render/model/json/ModelTransformationMode;ZLnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;IILnet/minecraft/client/render/model/BakedModel;)V",
method = "renderItem(Lnet/minecraft/item/ItemStack;Lnet/minecraft/client/render/model/json/ModelTransformation$Mode;ZLnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;IILnet/minecraft/client/render/model/BakedModel;)V",
at = @At("HEAD"),
cancellable = true
)
private void cobblemon$determinePokeballModel(ItemStack stack, ModelTransformationMode renderMode, boolean leftHanded, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay, BakedModel model, CallbackInfo ci) {
boolean shouldBe2d = renderMode == ModelTransformationMode.GUI || renderMode == ModelTransformationMode.FIXED;
private void cobblemon$determinePokeballModel(ItemStack stack, ModelTransformation.Mode renderMode, boolean leftHanded, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay, BakedModel model, CallbackInfo ci) {
boolean shouldBe2d = renderMode == ModelTransformation.Mode.GUI || renderMode == ModelTransformation.Mode.FIXED;
if (shouldBe2d && stack.getItem() instanceof PokeBallItem pokeBallItem) {
BakedModel replacementModel = this.models.getModelManager().getModel(new ModelIdentifier(pokeBallItem.getPokeBall().getModel2d(), "inventory"));
ModelIdentifier modelIdentifier = new ModelIdentifier(pokeBallItem.getPokeBall().getModel2d());
BakedModel replacementModel = this.models.getModelManager().getModel(modelIdentifier);
if (!model.equals(replacementModel)) {
ci.cancel();
renderItem(stack, renderMode, leftHanded, matrices, vertexConsumers, light, overlay, replacementModel);
@@ -1,35 +0,0 @@
/*
* 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.mixin.pokeball;
import com.cobblemon.mod.common.entity.pokeball.WaterDragModifier;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.projectile.thrown.ThrownEntity;
import net.minecraft.world.World;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.ModifyVariable;
@Mixin(ThrownEntity.class)
public abstract class ThrownEntityMixin extends Entity {
public ThrownEntityMixin(EntityType<?> type, World world) {
super(type, world);
}
@ModifyVariable(method = "tick", at = @At("STORE"), ordinal = 0)
private float cobblemon$waterDragModifier(float value) {
if (this.isTouchingWater() && this instanceof WaterDragModifier) {
return ((WaterDragModifier) this).waterDrag();
}
return value;
}
}
@@ -1,17 +0,0 @@
{{ license }}
package com.cobblemon.mod.common
object CobblemonBuildDetails {
const val MOD_ID = "{{ modid }}"
const val VERSION = "{{ version }}"
const val SNAPSHOT = {{ isSnapshot }}
const val GIT_COMMIT = "{{ gitCommit | default("Not Specified") }}"
const val BRANCH = "{{ branch | default("Not Specified") }}"
fun smallCommitHash(): String {
return this.GIT_COMMIT.substring(0, 7)
}
}
@@ -1,29 +0,0 @@
/*
* 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 net.minecraft.client.MinecraftClient
import net.minecraft.client.render.model.BakedModel
import net.minecraft.client.util.ModelIdentifier
import net.minecraft.util.Identifier
/**
* Contains information for forcing a model to be baked
*
* @param modelLocation The location of the model
* @param modelIdentifier The identifier that the BakedModel will be registered to
*/
data class BakingOverride(
val modelLocation: Identifier,
val modelIdentifier: ModelIdentifier
) {
fun getModel(): BakedModel {
return MinecraftClient.getInstance().bakedModelManager.getModel(modelIdentifier)
}
}
@@ -8,23 +8,22 @@
package com.cobblemon.mod.common
import com.cobblemon.mod.common.CobblemonBuildDetails.smallCommitHash
import com.cobblemon.mod.common.advancement.CobblemonCriteria
import com.cobblemon.mod.common.advancement.criterion.EvolvePokemonContext
import com.cobblemon.mod.common.api.Priority
import com.cobblemon.mod.common.api.SeasonResolver
import com.cobblemon.mod.common.api.data.DataProvider
import com.cobblemon.mod.common.api.drop.CommandDropEntry
import com.cobblemon.mod.common.api.drop.DropEntry
import com.cobblemon.mod.common.api.drop.ItemDropEntry
import com.cobblemon.mod.common.api.events.CobblemonEvents
import com.cobblemon.mod.common.api.events.CobblemonEvents.BATTLE_VICTORY
import com.cobblemon.mod.common.api.events.CobblemonEvents.DATA_SYNCHRONIZED
import com.cobblemon.mod.common.api.events.CobblemonEvents.EVOLUTION_COMPLETE
import com.cobblemon.mod.common.api.events.CobblemonEvents.LEVEL_UP_EVENT
import com.cobblemon.mod.common.api.events.CobblemonEvents.LIVING_DEATH
import com.cobblemon.mod.common.api.events.CobblemonEvents.PLAYER_QUIT
import com.cobblemon.mod.common.api.events.CobblemonEvents.POKEMON_CAPTURED
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.events.CobblemonEvents.SERVER_STARTED
import com.cobblemon.mod.common.api.events.CobblemonEvents.SERVER_STOPPED
import com.cobblemon.mod.common.api.events.CobblemonEvents.TICK_POST
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.Vec3DataSerializer
@@ -38,15 +37,15 @@ import com.cobblemon.mod.common.api.pokemon.experience.ExperienceGroups
import com.cobblemon.mod.common.api.pokemon.experience.StandardExperienceCalculator
import com.cobblemon.mod.common.api.pokemon.feature.ChoiceSpeciesFeatureProvider
import com.cobblemon.mod.common.api.pokemon.feature.FlagSpeciesFeatureProvider
import com.cobblemon.mod.common.api.pokemon.feature.IntSpeciesFeatureProvider
import com.cobblemon.mod.common.api.pokemon.feature.SpeciesFeatures
import com.cobblemon.mod.common.api.pokemon.helditem.HeldItemProvider
import com.cobblemon.mod.common.api.pokemon.stats.EvCalculator
import com.cobblemon.mod.common.api.pokemon.stats.Generation8EvCalculator
import com.cobblemon.mod.common.api.pokemon.stats.StatProvider
import com.cobblemon.mod.common.api.properties.CustomPokemonProperty
import com.cobblemon.mod.common.api.scheduling.ServerRealTimeTaskTracker
import com.cobblemon.mod.common.api.scheduling.ServerTaskTracker
import com.cobblemon.mod.common.api.reactive.Observable.Companion.filter
import com.cobblemon.mod.common.api.reactive.Observable.Companion.map
import com.cobblemon.mod.common.api.scheduling.ScheduledTaskTracker
import com.cobblemon.mod.common.api.spawning.BestSpawner
import com.cobblemon.mod.common.api.spawning.CobblemonSpawningProspector
import com.cobblemon.mod.common.api.spawning.context.AreaContextResolver
@@ -54,33 +53,21 @@ import com.cobblemon.mod.common.api.spawning.prospecting.SpawningProspector
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
import com.cobblemon.mod.common.api.storage.adapter.database.MongoDBStoreAdapter
import com.cobblemon.mod.common.api.storage.adapter.flatfile.FileStoreAdapter
import com.cobblemon.mod.common.api.storage.adapter.flatfile.JSONStoreAdapter
import com.cobblemon.mod.common.api.storage.adapter.flatfile.NBTStoreAdapter
import com.cobblemon.mod.common.api.storage.adapter.flatifle.FileStoreAdapter
import com.cobblemon.mod.common.api.storage.adapter.flatifle.JSONStoreAdapter
import com.cobblemon.mod.common.api.storage.adapter.flatifle.NBTStoreAdapter
import com.cobblemon.mod.common.api.storage.factory.FileBackedPokemonStoreFactory
import com.cobblemon.mod.common.api.storage.molang.NbtMoLangDataStoreFactory
import com.cobblemon.mod.common.api.storage.pc.PCStore
import com.cobblemon.mod.common.api.storage.pc.link.PCLinkManager
import com.cobblemon.mod.common.api.storage.player.PlayerDataStoreManager
import com.cobblemon.mod.common.api.storage.player.factory.JsonPlayerDataStoreFactory
import com.cobblemon.mod.common.api.storage.player.factory.MongoPlayerDataStoreFactory
import com.cobblemon.mod.common.api.tags.CobblemonEntityTypeTags
import com.cobblemon.mod.common.api.tags.CobblemonItemTags
import com.cobblemon.mod.common.battles.BagItems
import com.cobblemon.mod.common.battles.BattleFormat
import com.cobblemon.mod.common.battles.BattleRegistry
import com.cobblemon.mod.common.battles.BattleSide
import com.cobblemon.mod.common.battles.ShowdownThread
import com.cobblemon.mod.common.battles.actor.PokemonBattleActor
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
import com.cobblemon.mod.common.command.argument.DialogueArgumentType
import com.cobblemon.mod.common.command.argument.MoveArgumentType
import com.cobblemon.mod.common.command.argument.PartySlotArgumentType
import com.cobblemon.mod.common.command.argument.PokemonArgumentType
import com.cobblemon.mod.common.command.argument.PokemonPropertiesArgumentType
import com.cobblemon.mod.common.command.argument.PokemonStoreArgumentType
import com.cobblemon.mod.common.command.argument.SpawnBucketArgumentType
import com.cobblemon.mod.common.battles.runner.ShowdownService
import com.cobblemon.mod.common.config.CobblemonConfig
import com.cobblemon.mod.common.config.LastChangedVersion
import com.cobblemon.mod.common.config.constraint.IntConstraint
@@ -90,61 +77,60 @@ import com.cobblemon.mod.common.events.AdvancementHandler
import com.cobblemon.mod.common.events.ServerTickHandler
import com.cobblemon.mod.common.item.PokeBallItem
import com.cobblemon.mod.common.net.messages.client.settings.ServerSettingsPacket
import com.cobblemon.mod.common.net.serverhandling.ServerPacketRegistrar
import com.cobblemon.mod.common.particle.CobblemonParticles
import com.cobblemon.mod.common.permission.LaxPermissionValidator
import com.cobblemon.mod.common.platform.events.PlatformEvents
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.aspects.GENDER_ASPECT
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.feature.*
import com.cobblemon.mod.common.pokemon.helditem.CobblemonHeldItemManager
import com.cobblemon.mod.common.pokemon.properties.HiddenAbilityPropertyType
import com.cobblemon.mod.common.pokemon.properties.UncatchableProperty
import com.cobblemon.mod.common.pokemon.properties.UntradeableProperty
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.registry.CompletableRegistry
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.getServer
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.world.feature.CobblemonPlacedFeatures
import com.cobblemon.mod.common.world.feature.ore.CobblemonOrePlacedFeatures
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules
import com.mongodb.ConnectionString
import com.mongodb.MongoClientSettings
import com.mongodb.client.MongoClient
import com.mongodb.client.MongoClients
import net.minecraft.client.MinecraftClient
import net.minecraft.command.argument.serialize.ConstantArgumentSerializer
import net.minecraft.entity.data.TrackedDataHandlerRegistry
import net.minecraft.item.Items
import net.minecraft.item.NameTagItem
import net.minecraft.registry.RegistryKey
import net.minecraft.util.WorldSavePath
import net.minecraft.world.World
import org.apache.logging.log4j.LogManager
import org.apache.logging.log4j.Logger
import com.cobblemon.mod.common.world.feature.CobblemonOrePlacedFeatures
import com.cobblemon.mod.common.world.placement.CobblemonPlacementTypes
import dev.architectury.event.EventResult
import dev.architectury.event.events.common.CommandRegistrationEvent
import dev.architectury.event.events.common.InteractionEvent
import dev.architectury.event.events.common.PlayerEvent
import dev.architectury.hooks.item.tool.AxeItemHooks
import java.io.File
import java.io.FileReader
import java.io.FileWriter
import java.io.PrintWriter
import java.util.*
import java.util.UUID
import kotlin.properties.Delegates
import kotlin.reflect.full.memberProperties
import kotlin.reflect.jvm.isAccessible
import kotlin.reflect.jvm.javaField
import kotlin.math.roundToInt
import net.minecraft.client.MinecraftClient
import net.minecraft.entity.data.TrackedDataHandlerRegistry
import net.minecraft.item.NameTagItem
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.util.WorldSavePath
import net.minecraft.util.registry.RegistryKey
import net.minecraft.world.World
import org.apache.logging.log4j.LogManager
object Cobblemon {
const val MODID = CobblemonBuildDetails.MOD_ID
const val VERSION = CobblemonBuildDetails.VERSION
const val MODID = "cobblemon"
const val VERSION = "1.3.1"
const val CONFIG_PATH = "config/$MODID/main.json"
val LOGGER: Logger = LogManager.getLogger()
val LOGGER = LogManager.getLogger()
lateinit var implementation: CobblemonImplementation
@Deprecated("This field is now a config value", ReplaceWith("Cobblemon.config.captureCalculator"))
@@ -164,7 +150,6 @@ object Cobblemon {
val bestSpawner = BestSpawner
val battleRegistry = BattleRegistry
var storage = PokemonStoreManager()
var molangData = NbtMoLangDataStoreFactory
lateinit var playerData: PlayerDataStoreManager
lateinit var starterConfig: StarterConfig
val dataProvider: DataProvider = CobblemonDataProvider
@@ -173,24 +158,6 @@ object Cobblemon {
var seasonResolver: SeasonResolver = TagSeasonResolver
fun preInitialize(implementation: CobblemonImplementation) {
this.implementation = implementation
this.LOGGER.info("Launching Cobblemon ${CobblemonBuildDetails.VERSION}${if(CobblemonBuildDetails.SNAPSHOT) "-SNAPSHOT" else ""} ")
if(CobblemonBuildDetails.SNAPSHOT) {
this.LOGGER.info(" - Git Commit: ${smallCommitHash()} (https://gitlab.com/cable-mc/cobblemon/-/commit/${CobblemonBuildDetails.GIT_COMMIT})")
this.LOGGER.info(" - Branch: ${CobblemonBuildDetails.BRANCH}")
}
implementation.registerPermissionValidator()
implementation.registerSoundEvents()
implementation.registerBlocks()
implementation.registerItems()
implementation.registerEntityTypes()
implementation.registerEntityAttributes()
implementation.registerBlockEntityTypes()
implementation.registerWorldGenFeatures()
implementation.registerParticles()
DropEntry.register("command", CommandDropEntry::class.java)
DropEntry.register("item", ItemDropEntry::class.java, isDefault = true)
@@ -198,13 +165,18 @@ object Cobblemon {
CaptureCalculators.registerDefaults()
this.loadConfig()
// CobblemonBlockPredicates.touch()
CobblemonOrePlacedFeatures.register()
CobblemonPlacedFeatures.register()
this.registerArgumentTypes()
this.implementation = implementation
CobblemonCriteria // Init the fields and register the criteria
CobblemonGameRules // Init fields and register
CobblemonEntities.register()
CobblemonBlocks.register()
CobblemonBlockEntities.register()
CobblemonItems.register()
ServerPacketRegistrar.registerHandlers()
CobblemonSounds.register()
CobblemonFeatures.register()
CobblemonGameRules.register()
CobblemonParticles.register()
ShoulderEffectRegistry.register()
@@ -212,28 +184,26 @@ object Cobblemon {
storage.onPlayerDataSync(it)
playerData.get(it).sendToPlayer(it)
starterHandler.handleJoin(it)
ServerSettingsPacket(this.config.preventCompletePartyDeposit, this.config.displayEntityLevelLabel).sendToPlayer(it)
ServerSettingsPacket().sendToPlayer(it)
}
PlatformEvents.SERVER_PLAYER_LOGOUT.subscribe {
PCLinkManager.removeLink(it.player.uuid)
BattleRegistry.getBattleByParticipatingPlayer(it.player)?.stop()
storage.onPlayerDisconnect(it.player)
playerData.onPlayerDisconnect(it.player)
TradeManager.onLogoff(it.player)
PLAYER_QUIT.subscribe {
PCLinkManager.removeLink(it.uuid)
BattleRegistry.getBattleByParticipatingPlayer(it)?.stop()
}
PlatformEvents.PLAYER_DEATH.subscribe {
PCLinkManager.removeLink(it.player.uuid)
battleRegistry.getBattleByParticipatingPlayer(it.player)?.stop()
LIVING_DEATH.pipe(filter { it is ServerPlayerEntity }, map { it as ServerPlayerEntity }).subscribe {
PCLinkManager.removeLink(it.uuid)
battleRegistry.getBattleByParticipatingPlayer(it)?.stop()
}
PlatformEvents.RIGHT_CLICK_ENTITY.subscribe { event ->
if (event.player.getStackInHand(event.hand).item is NameTagItem && event.entity.type.isIn(CobblemonEntityTypeTags.CANNOT_HAVE_NAME_TAG)) {
event.cancel()
}
}
PlatformEvents.RIGHT_CLICK_BLOCK.subscribe { event ->
val player = event.player
val block = player.world.getBlockState(event.pos).block
InteractionEvent.INTERACT_ENTITY.register(InteractionEvent.InteractEntity { player, entity, hand ->
if (player.getStackInHand(hand).item is NameTagItem && entity.type.isIn(CobblemonEntityTypeTags.CANNOT_HAVE_NAME_TAG))
EventResult.interruptTrue()
else
EventResult.pass()
})
InteractionEvent.RIGHT_CLICK_BLOCK.register(InteractionEvent.RightClickBlock { pl, _, pos, _ ->
val player = pl as? ServerPlayerEntity ?: return@RightClickBlock EventResult.pass()
val block = player.world.getBlockState(pos).block
player.party().forEach { pokemon ->
pokemon.evolutions
.filterIsInstance<BlockClickEvolution>()
@@ -241,29 +211,16 @@ object Cobblemon {
evolution.attemptEvolution(pokemon, BlockClickEvolution.BlockInteractionContext(block, player.world))
}
}
}
return@RightClickBlock EventResult.pass()
})
// Register the grow_tumblestone advancement
PlatformEvents.RIGHT_CLICK_BLOCK.subscribe { AdvancementHandler.onTumbleStonePlaced(it) }
PlatformEvents.CHANGE_DIMENSION.subscribe {
it.player.party().forEach { pokemon -> pokemon.entity?.recallWithAnimation() }
}
PlayerEvent.CHANGE_DIMENSION.register(PlayerEvent.ChangeDimension{ player, _, _ ->
player.party().forEach { pokemon -> pokemon.entity?.recallWithAnimation() }
})
TrackedDataHandlerRegistry.register(Vec3DataSerializer)
TrackedDataHandlerRegistry.register(StringSetDataSerializer)
TrackedDataHandlerRegistry.register(PoseTypeDataSerializer)
TrackedDataHandlerRegistry.register(IdentifierDataSerializer)
// Lowest priority because this applies after luxury ball bonus as of gen 4
CobblemonEvents.FRIENDSHIP_UPDATED.subscribe(Priority.LOWEST) { event ->
var increment = (event.newFriendship - event.pokemon.friendship).toFloat()
// Our Luxury ball spec is diff from official, but we will still assume these stack
if (event.pokemon.heldItemNoCopy().isIn(CobblemonItemTags.IS_FRIENDSHIP_BOOSTER)) {
increment += increment * 0.5F
}
event.newFriendship = event.pokemon.friendship + increment.roundToInt()
}
HeldItemProvider.register(CobblemonHeldItemManager, Priority.LOWEST)
}
@@ -271,6 +228,13 @@ object Cobblemon {
fun initialize() {
showdownThread.launch()
CompletableRegistry.allRegistriesCompleted.thenAccept {
LOGGER.info("All registries loaded.")
}
CobblemonPlacementTypes.register()
CobblemonOrePlacedFeatures.register()
// Start up the data provider.
CobblemonDataProvider.registerDefaults()
@@ -279,7 +243,6 @@ object Cobblemon {
SpeciesFeatures.types["choice"] = ChoiceSpeciesFeatureProvider::class.java
SpeciesFeatures.types["flag"] = FlagSpeciesFeatureProvider::class.java
SpeciesFeatures.types["integer"] = IntSpeciesFeatureProvider::class.java
SpeciesFeatures.register(
DataKeys.CAN_BE_MILKED,
@@ -288,85 +251,51 @@ object Cobblemon {
DataKeys.HAS_BEEN_SHEARED,
FlagSpeciesFeatureProvider(keys = listOf(DataKeys.HAS_BEEN_SHEARED), default = false))
CustomPokemonProperty.register(UntradeableProperty)
CustomPokemonProperty.register(UncatchableProperty)
CustomPokemonProperty.register(PokemonFlagProperty)
CustomPokemonProperty.register(HiddenAbilityPropertyType)
CommandRegistrationEvent.EVENT.register(CobblemonCommands::register)
ifDedicatedServer {
isDedicatedServer = true
TICK_POST.subscribe { ScheduledTaskTracker.update() }
CobblemonNetwork.clientHandlersRegistered.complete(Unit)
}
PlatformEvents.SERVER_TICK_POST.subscribe {
ServerTaskTracker.update(1/20F)
ServerRealTimeTaskTracker.update()
CobblemonBlocks.completed.thenAccept {
AxeItemHooks.addStrippable(CobblemonBlocks.APRICORN_LOG.get(), CobblemonBlocks.STRIPPED_APRICORN_LOG.get())
AxeItemHooks.addStrippable(CobblemonBlocks.APRICORN_WOOD.get(), CobblemonBlocks.STRIPPED_APRICORN_WOOD.get())
}
PlatformEvents.SERVER_TICK_PRE.subscribe {
ServerRealTimeTaskTracker.update()
}
PlatformEvents.SERVER_STARTING.subscribe { event ->
val server = event.server
SERVER_STARTED.subscribe { server ->
playerData = PlayerDataStoreManager().also { it.setup(server) }
val mongoClient: MongoClient?
val pokemonStoreRoot = server.getSavePath(WorldSavePath.ROOT).resolve("pokemon").toFile()
val storeAdapter = when (config.storageFormat) {
"nbt", "json" -> {
val jsonFactory = JsonPlayerDataStoreFactory()
jsonFactory.setup(server)
playerData.setFactory(jsonFactory)
if (config.storageFormat == "nbt") {
NBTStoreAdapter(pokemonStoreRoot.absolutePath, useNestedFolders = true, folderPerClass = true)
} else {
JSONStoreAdapter(
pokemonStoreRoot.absolutePath,
useNestedFolders = true,
folderPerClass = true
)
}
}
"mongodb" -> {
try {
Class.forName("com.mongodb.client.MongoClient")
val mongoClientSettings = MongoClientSettings.builder()
.applyConnectionString(ConnectionString(config.mongoDBConnectionString))
.build()
mongoClient = MongoClients.create(mongoClientSettings)
val mongoFactory = MongoPlayerDataStoreFactory(mongoClient, config.mongoDBDatabaseName)
playerData.setFactory(mongoFactory)
MongoDBStoreAdapter(mongoClient, config.mongoDBDatabaseName)
} catch (e: ClassNotFoundException) {
LOGGER.error("MongoDB driver not found.")
throw e
}
}
else -> throw IllegalArgumentException("Unsupported storageFormat: ${config.storageFormat}")
}
.with(ReforgedConversion(server.getSavePath(WorldSavePath.ROOT))) as FileStoreAdapter<*>
storage.registerFactory(
priority = Priority.LOWEST,
factory = FileBackedPokemonStoreFactory(
adapter = storeAdapter,
adapter = if (config.storageFormat == "nbt") {
NBTStoreAdapter(pokemonStoreRoot.absolutePath, useNestedFolders = true, folderPerClass = true)
} else {
JSONStoreAdapter(pokemonStoreRoot.absolutePath, useNestedFolders = true, folderPerClass = true)
}.with(ReforgedConversion(server.getSavePath(WorldSavePath.ROOT))) as FileStoreAdapter<*>,
createIfMissing = true,
pcConstructor = { uuid -> PCStore(uuid).also { it.resize(config.defaultBoxCount) } }
)
)
}
PlatformEvents.SERVER_STOPPED.subscribe {
SERVER_STOPPED.subscribe {
storage.unregisterAll()
playerData.saveAll()
}
PlatformEvents.SERVER_STARTED.subscribe {
SERVER_STARTED.subscribe {
bestSpawner.onServerStarted()
battleRegistry.onServerStarted()
}
PlatformEvents.SERVER_TICK_POST.subscribe { ServerTickHandler.onTick(it.server) }
TICK_POST.subscribe { ServerTickHandler.onTick(it) }
POKEMON_CAPTURED.subscribe { AdvancementHandler.onCapture(it) }
// EGG_HATCH.subscribe { AdvancementHandler.onHatch(it) }
BATTLE_VICTORY.subscribe { AdvancementHandler.onWinBattle(it) }
@@ -377,51 +306,30 @@ object Cobblemon {
// Ensure the config option is enabled and that the result was a ninjask and that shedinja exists
if (this.config.ninjaskCreatesShedinja && pokemon.species.resourceIdentifier == ninjaskIdentifier && PokemonSpecies.getByIdentifier(Pokemon.SHEDINJA) != null) {
val player = pokemon.getOwnerPlayer() ?: return@subscribe
if (player.isCreative || player.inventory.containsAny { it.item is PokeBallItem }) {
var pokeball = Items.AIR
player.inventory.combinedInventory.forEach {
it.forEach {
itemStack -> if (itemStack.item is PokeBallItem && pokeball == Items.AIR) {
pokeball = itemStack.item as PokeBallItem
}
}
}
if (!player.isCreative) {
player.inventory.removeAmountIf(1) { it.item is PokeBallItem }
}
if (pokeball == Items.AIR) {
pokeball = CobblemonItems.POKE_BALL
}
if (player.inventory.containsAny { it.item is PokeBallItem }) {
player.inventory.removeAmountIf(1) { it.item is PokeBallItem }
val properties = event.evolution.result.copy()
properties.species = Pokemon.SHEDINJA.toString()
val product = pokemon.clone()
product.removeHeldItem()
properties.apply(product)
product.caughtBall = (pokeball as PokeBallItem).pokeBall
pokemon.storeCoordinates.get()?.store?.add(product)
CobblemonCriteria.EVOLVE_POKEMON.trigger(player, EvolvePokemonContext(event.pokemon.preEvolution!!.species.resourceIdentifier, product.species.resourceIdentifier, playerData.get(player).advancementData.totalEvolvedCount))
}
}
}
LEVEL_UP_EVENT.subscribe { AdvancementHandler.onLevelUp(it) }
TRADE_COMPLETED.subscribe { AdvancementHandler.onTradeCompleted(it) }
BagItems.observable.subscribe {
PokemonSpecies.observable.subscribe {
LOGGER.info("Starting dummy Showdown battle to force it to pre-load data.")
battleRegistry.startBattle(
BattleFormat.GEN_9_SINGLES,
BattleSide(PokemonBattleActor(UUID.randomUUID(), BattlePokemon(Pokemon().initialize()), -1F)),
BattleSide(PokemonBattleActor(UUID.randomUUID(), BattlePokemon(Pokemon().initialize()), -1F)),
true
).ifSuccessful { it.mute = true }
BattleSide(PokemonBattleActor(UUID.randomUUID(), BattlePokemon(Pokemon().initialize()), -1F))
).apply { mute = true }
}
CobblemonSherds.registerSherds()
}
fun getLevel(dimension: RegistryKey<World>): World? {
return if (isDedicatedServer) {
server()?.getWorld(dimension)
getServer()?.getWorld(dimension)
} else {
val mc = MinecraftClient.getInstance()
return mc.server?.getWorld(dimension) ?: mc.world
@@ -512,15 +420,4 @@ object Cobblemon {
exception.printStackTrace()
}
}
private fun registerArgumentTypes() {
this.implementation.registerCommandArgument(cobblemonResource("pokemon"), PokemonArgumentType::class, ConstantArgumentSerializer.of(PokemonArgumentType::pokemon))
this.implementation.registerCommandArgument(cobblemonResource("pokemon_properties"), PokemonPropertiesArgumentType::class, ConstantArgumentSerializer.of(PokemonPropertiesArgumentType::properties))
this.implementation.registerCommandArgument(cobblemonResource("spawn_bucket"), SpawnBucketArgumentType::class, ConstantArgumentSerializer.of(SpawnBucketArgumentType::spawnBucket))
this.implementation.registerCommandArgument(cobblemonResource("move"), MoveArgumentType::class, ConstantArgumentSerializer.of(MoveArgumentType::move))
this.implementation.registerCommandArgument(cobblemonResource("party_slot"), PartySlotArgumentType::class, ConstantArgumentSerializer.of(PartySlotArgumentType::partySlot))
this.implementation.registerCommandArgument(cobblemonResource("pokemon_store"), PokemonStoreArgumentType::class, ConstantArgumentSerializer.of(PokemonStoreArgumentType::pokemonStore))
this.implementation.registerCommandArgument(cobblemonResource("dialogue"), DialogueArgumentType::class, ConstantArgumentSerializer.of(DialogueArgumentType::dialogue))
}
}
@@ -1,21 +0,0 @@
/*
* 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 net.minecraft.entity.ai.brain.Activity
object CobblemonActivities {
val activities = mutableListOf<Activity>()
val BATTLING_ACTIVITY = Activity("pokemon_battling")
fun register(activity: Activity): Activity {
activities.add(activity)
return activity
}
}
@@ -8,79 +8,31 @@
package com.cobblemon.mod.common
import com.cobblemon.mod.common.block.entity.BerryBlockEntity
import com.cobblemon.mod.common.registry.CompletableRegistry
import com.cobblemon.mod.common.block.entity.HealingMachineBlockEntity
import com.cobblemon.mod.common.block.entity.PCBlockEntity
import com.cobblemon.mod.common.block.entity.PokemonPastureBlockEntity
import com.cobblemon.mod.common.block.entity.FossilAnalyzerBlockEntity
import com.cobblemon.mod.common.block.entity.FossilMultiblockEntity
import com.cobblemon.mod.common.block.entity.RestorationTankBlockEntity
import com.cobblemon.mod.common.block.multiblock.FossilMultiblockBuilder
import com.cobblemon.mod.common.block.entity.*
import com.cobblemon.mod.common.block.entity.DisplayCaseBlockEntity
import com.cobblemon.mod.common.platform.PlatformRegistry
import dev.architectury.registry.registries.RegistrySupplier
import java.util.function.Supplier
import net.minecraft.block.entity.BlockEntityType
import net.minecraft.registry.Registries
import net.minecraft.registry.Registry
import net.minecraft.registry.RegistryKey
import net.minecraft.registry.RegistryKeys
import net.minecraft.util.registry.Registry
object CobblemonBlockEntities : PlatformRegistry<Registry<BlockEntityType<*>>, RegistryKey<Registry<BlockEntityType<*>>>, BlockEntityType<*>>() {
override val registry: Registry<BlockEntityType<*>> = Registries.BLOCK_ENTITY_TYPE
override val registryKey: RegistryKey<Registry<BlockEntityType<*>>> = RegistryKeys.BLOCK_ENTITY_TYPE
object CobblemonBlockEntities : CompletableRegistry<BlockEntityType<*>>(Registry.BLOCK_ENTITY_TYPE_KEY) {
private fun <T : BlockEntityType<*>> register(name: String, blockEntityType: Supplier<T>) : RegistrySupplier<T> {
return queue(name, blockEntityType)
}
@JvmField
val HEALING_MACHINE: BlockEntityType<HealingMachineBlockEntity> = this.create("healing_machine", BlockEntityType.Builder.create(::HealingMachineBlockEntity, CobblemonBlocks.HEALING_MACHINE).build(null))
@JvmField
val PC: BlockEntityType<PCBlockEntity> = this.create("pc", BlockEntityType.Builder.create(::PCBlockEntity, CobblemonBlocks.PC).build(null))
@JvmField
val BERRY = this.create("berry", BlockEntityType.Builder.create(::BerryBlockEntity, *CobblemonBlocks.berries().values.toTypedArray()).build(null))
@JvmField
val PASTURE: BlockEntityType<PokemonPastureBlockEntity> = this.create("pasture", BlockEntityType.Builder.create(::PokemonPastureBlockEntity, CobblemonBlocks.PASTURE).build(null))
@JvmField
val SIGN: BlockEntityType<CobblemonSignBlockEntity> = this.create("sign", BlockEntityType.Builder.create(::CobblemonSignBlockEntity, CobblemonBlocks.APRICORN_SIGN, CobblemonBlocks.APRICORN_WALL_SIGN).build(null))
@JvmField
val HANGING_SIGN: BlockEntityType<CobblemonHangingSignBlockEntity> = this.create("hanging_sign", BlockEntityType.Builder.create(::CobblemonHangingSignBlockEntity, CobblemonBlocks.APRICORN_HANGING_SIGN, CobblemonBlocks.APRICORN_WALL_HANGING_SIGN).build(null))
@JvmField
val GILDED_CHEST: BlockEntityType<GildedChestBlockEntity> = this.create("chest", BlockEntityType.Builder.create(::GildedChestBlockEntity,
CobblemonBlocks.GILDED_CHEST,
CobblemonBlocks.BLUE_GILDED_CHEST,
CobblemonBlocks.YELLOW_GILDED_CHEST,
CobblemonBlocks.PINK_GILDED_CHEST,
CobblemonBlocks.BLACK_GILDED_CHEST,
CobblemonBlocks.WHITE_GILDED_CHEST,
CobblemonBlocks.GREEN_GILDED_CHEST,
CobblemonBlocks.GIMMIGHOUL_CHEST
).build(null))
@JvmField
val FOSSIL_MULTIBLOCK: BlockEntityType<FossilMultiblockEntity> = this.create("fossil_multiblock",
BlockEntityType.Builder.create({ pos, state -> FossilMultiblockEntity(pos, state, FossilMultiblockBuilder(pos)) },
CobblemonBlocks.MONITOR
val HEALING_MACHINE = com.cobblemon.mod.common.CobblemonBlockEntities.register("healing_machine") {
BlockEntityType.Builder.create(
::HealingMachineBlockEntity,
CobblemonBlocks.HEALING_MACHINE.get()
).build(null)
)
}
@JvmField
val RESTORATION_TANK: BlockEntityType<RestorationTankBlockEntity> = this.create("restoration_tank",
BlockEntityType.Builder.create({ pos, state -> RestorationTankBlockEntity(pos, state, FossilMultiblockBuilder(pos)) },
CobblemonBlocks.RESTORATION_TANK
val PC = com.cobblemon.mod.common.CobblemonBlockEntities.register("pc") {
BlockEntityType.Builder.create(
::PCBlockEntity,
CobblemonBlocks.PC.get()
).build(null)
)
@JvmField
val FOSSIL_ANALYZER: BlockEntityType<FossilAnalyzerBlockEntity> = this.create("fossil_analyzer",
BlockEntityType.Builder.create({ pos, state -> FossilAnalyzerBlockEntity(pos, state, FossilMultiblockBuilder(pos)) },
CobblemonBlocks.FOSSIL_ANALYZER
).build(null)
)
@JvmField
val DISPLAY_CASE: BlockEntityType<DisplayCaseBlockEntity> = this.create("display_case",
BlockEntityType.Builder.create(::DisplayCaseBlockEntity, CobblemonBlocks.DISPLAY_CASE).build(null)
)
}
}
}
@@ -9,74 +9,50 @@
package com.cobblemon.mod.common
import com.cobblemon.mod.common.api.apricorn.Apricorn
import com.cobblemon.mod.common.block.*
import com.cobblemon.mod.common.block.MintBlock.MintType
import com.cobblemon.mod.common.block.FossilAnalyzerBlock
import com.cobblemon.mod.common.block.MonitorBlock
import com.cobblemon.mod.common.block.RestorationTankBlock
import com.cobblemon.mod.common.mixin.invoker.DoorBlockInvoker
import com.cobblemon.mod.common.mixin.invoker.PressurePlateBlockInvoker
import com.cobblemon.mod.common.mixin.invoker.StairsBlockInvoker
import com.cobblemon.mod.common.mixin.invoker.TrapdoorBlockInvoker
import com.cobblemon.mod.common.mixin.invoker.*
import com.cobblemon.mod.common.platform.PlatformRegistry
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.block.BerryBlock
import com.cobblemon.mod.common.block.chest.GildedChestBlock
import com.cobblemon.mod.common.block.sign.CobblemonHangingSignBlock
import com.cobblemon.mod.common.block.sign.CobblemonSignBlock
import com.cobblemon.mod.common.block.sign.CobblemonWallHangingSignBlock
import com.cobblemon.mod.common.block.sign.CobblemonWallSignBlock
import com.cobblemon.mod.common.registry.CompletableRegistry
import com.cobblemon.mod.common.block.ApricornBlock
import com.cobblemon.mod.common.block.ApricornSaplingBlock
import com.cobblemon.mod.common.block.HealingMachineBlock
import com.cobblemon.mod.common.block.PCBlock
import dev.architectury.registry.registries.RegistrySupplier
import net.minecraft.block.*
import net.minecraft.block.enums.Instrument
import net.minecraft.block.piston.PistonBehavior
import net.minecraft.entity.effect.StatusEffects
import net.minecraft.registry.Registries
import net.minecraft.registry.Registry
import net.minecraft.registry.RegistryKey
import net.minecraft.registry.RegistryKeys
import net.minecraft.entity.EntityType
import net.minecraft.sound.BlockSoundGroup
import net.minecraft.util.Identifier
import net.minecraft.util.math.Direction
import net.minecraft.util.math.intprovider.UniformIntProvider
import net.minecraft.util.registry.Registry
import java.util.function.ToIntFunction
@Suppress("SameParameterValue", "HasPlatformType", "MemberVisibilityCanBePrivate", "unused")
object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<Block>>, Block>() {
object CobblemonBlocks : CompletableRegistry<Block>(Registry.BLOCK_KEY) {
/**
* Evolution Ores
*/
@JvmField
val DAWN_STONE_ORE = this.evolutionStoneOre("dawn_stone_ore")
@JvmField
val DUSK_STONE_ORE = this.evolutionStoneOre("dusk_stone_ore")
@JvmField
val FIRE_STONE_ORE = this.evolutionStoneOre("fire_stone_ore")
@JvmField
val ICE_STONE_ORE = this.evolutionStoneOre("ice_stone_ore")
@JvmField
val LEAF_STONE_ORE = this.evolutionStoneOre("leaf_stone_ore")
@JvmField
val MOON_STONE_ORE = this.evolutionStoneOre("moon_stone_ore")
@JvmField
val DRIPSTONE_MOON_STONE_ORE = this.evolutionStoneOre("dripstone_moon_stone_ore")
@JvmField
val SHINY_STONE_ORE = this.evolutionStoneOre("shiny_stone_ore")
@JvmField
val SUN_STONE_ORE = this.evolutionStoneOre("sun_stone_ore")
@JvmField
val THUNDER_STONE_ORE = this.evolutionStoneOre("thunder_stone_ore")
@JvmField
val WATER_STONE_ORE = this.evolutionStoneOre("water_stone_ore")
override val registry: Registry<Block> = Registries.BLOCK
override val registryKey: RegistryKey<Registry<Block>> = RegistryKeys.BLOCK
val APRICORN_BLOCK_SET_TYPE = BlockSetType("apricorn")
val APRICORN_WOOD_TYPE = WoodType.register(WoodType("apricorn", APRICORN_BLOCK_SET_TYPE))
// Evolution Ores
@JvmField
val DAWN_STONE_ORE = evolutionStoneOre("dawn_stone_ore")
@JvmField
val DUSK_STONE_ORE = evolutionStoneOre("dusk_stone_ore")
@JvmField
val FIRE_STONE_ORE = evolutionStoneOre("fire_stone_ore")
@JvmField
val NETHER_FIRE_STONE_ORE = evolutionStoneOre("nether_fire_stone_ore")
@JvmField
val ICE_STONE_ORE = evolutionStoneOre("ice_stone_ore")
@JvmField
val LEAF_STONE_ORE = evolutionStoneOre("leaf_stone_ore")
@JvmField
val MOON_STONE_ORE = evolutionStoneOre("moon_stone_ore")
@JvmField
val DRIPSTONE_MOON_STONE_ORE = evolutionStoneOre("dripstone_moon_stone_ore")
@JvmField
val SHINY_STONE_ORE = evolutionStoneOre("shiny_stone_ore")
@JvmField
val SUN_STONE_ORE = evolutionStoneOre("sun_stone_ore")
@JvmField
val TERRACOTTA_SUN_STONE_ORE = evolutionStoneOre("terracotta_sun_stone_ore")
@JvmField
val THUNDER_STONE_ORE = evolutionStoneOre("thunder_stone_ore")
@JvmField
val WATER_STONE_ORE = evolutionStoneOre("water_stone_ore")
/**
* Deepslate separator
*/
@JvmField
val DEEPSLATE_DAWN_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_dawn_stone_ore")
@@ -99,497 +75,130 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
@JvmField
val DEEPSLATE_WATER_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_water_stone_ore")
// Apricorns
@JvmField
val APRICORN_LOG = log("apricorn_log", arg2 = MapColor.BROWN)
@JvmField
val STRIPPED_APRICORN_LOG = log("stripped_apricorn_log")
@JvmField
val APRICORN_WOOD = log("apricorn_wood")
@JvmField
val STRIPPED_APRICORN_WOOD = log("stripped_apricorn_wood")
@JvmField
val APRICORN_PLANKS = this.create("apricorn_planks", Block(AbstractBlock.Settings.create().mapColor(MapColor.DIRT_BROWN).instrument(Instrument.BASS).strength(2.0f, 3.0f).sounds(BlockSoundGroup.WOOD)))
@JvmField
val APRICORN_LEAVES = leaves("apricorn_leaves")
@JvmField
val APRICORN_FENCE = this.create("apricorn_fence", FenceBlock(AbstractBlock.Settings.create().mapColor(APRICORN_PLANKS.defaultMapColor).instrument(Instrument.BASS).strength(2.0f, 3.0f).sounds(BlockSoundGroup.WOOD)))
@JvmField
val APRICORN_FENCE_GATE = this.create("apricorn_fence_gate", FenceGateBlock(AbstractBlock.Settings.create().mapColor(APRICORN_PLANKS.defaultMapColor).instrument(Instrument.BASS).strength(2.0f, 3.0f).sounds(BlockSoundGroup.WOOD), APRICORN_WOOD_TYPE))
@JvmField // Note At the time of 1.20.0 we don't need our own BlockSetType for Apricorn wood
val APRICORN_BUTTON = this.create("apricorn_button", BlocksInvoker.createWoodenButtonBlock(BlockSetType.OAK))
@JvmField
val APRICORN_PRESSURE_PLATE = this.create("apricorn_pressure_plate", PressurePlateBlockInvoker.`cobblemon$create`(PressurePlateBlock.ActivationRule.EVERYTHING, AbstractBlock.Settings.create().mapColor(APRICORN_PLANKS.defaultMapColor).instrument(Instrument.BASS).noCollision().strength(0.5f).sounds(BlockSoundGroup.WOOD), APRICORN_BLOCK_SET_TYPE))
@JvmField
val APRICORN_SIGN = this.create("apricorn_sign", CobblemonSignBlock(AbstractBlock.Settings.copy(Blocks.OAK_SIGN), APRICORN_WOOD_TYPE))
@JvmField
val APRICORN_WALL_SIGN = this.create("apricorn_wall_sign", CobblemonWallSignBlock(AbstractBlock.Settings.copy(Blocks.OAK_WALL_SIGN), APRICORN_WOOD_TYPE))
@JvmField
val APRICORN_HANGING_SIGN = this.create("apricorn_hanging_sign", CobblemonHangingSignBlock(AbstractBlock.Settings.copy(Blocks.OAK_WALL_HANGING_SIGN), APRICORN_WOOD_TYPE))
@JvmField
val APRICORN_WALL_HANGING_SIGN = this.create("apricorn_wall_hanging_sign", CobblemonWallHangingSignBlock(AbstractBlock.Settings.copy(Blocks.OAK_HANGING_SIGN), APRICORN_WOOD_TYPE))
@JvmField
val APRICORN_SLAB = this.create("apricorn_slab", SlabBlock(AbstractBlock.Settings.create().mapColor(MapColor.OAK_TAN).instrument(Instrument.BASS).strength(2.0f, 3.0f).sounds(BlockSoundGroup.WOOD)))
@JvmField
val APRICORN_STAIRS = this.create("apricorn_stairs", StairsBlockInvoker.`cobblemon$create`(APRICORN_PLANKS.defaultState, AbstractBlock.Settings.copy(APRICORN_PLANKS)))
@JvmField
val APRICORN_DOOR = this.create("apricorn_door", DoorBlockInvoker.`cobblemon$create`(AbstractBlock.Settings.create().mapColor(APRICORN_PLANKS.defaultMapColor).instrument(Instrument.BASS).strength(3.0F).sounds(BlockSoundGroup.WOOD).nonOpaque(), APRICORN_BLOCK_SET_TYPE))
@JvmField
val APRICORN_TRAPDOOR = this.create("apricorn_trapdoor", TrapdoorBlockInvoker.`cobblemon$create`(AbstractBlock.Settings.create().mapColor(MapColor.OAK_TAN).instrument(Instrument.BASS).strength(3.0F).sounds(BlockSoundGroup.WOOD).nonOpaque().allowsSpawning { _, _, _, _ -> false }, APRICORN_BLOCK_SET_TYPE))
private val PLANT_PROPERTIES = AbstractBlock.Settings.create().mapColor(MapColor.DARK_GREEN).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.GRASS).pistonBehavior(PistonBehavior.DESTROY)
@JvmField
val BLACK_APRICORN_SAPLING = this.create("black_apricorn_sapling", ApricornSaplingBlock(PLANT_PROPERTIES, Apricorn.BLACK))
@JvmField
val BLUE_APRICORN_SAPLING = this.create("blue_apricorn_sapling", ApricornSaplingBlock(PLANT_PROPERTIES, Apricorn.BLUE))
@JvmField
val GREEN_APRICORN_SAPLING = this.create("green_apricorn_sapling", ApricornSaplingBlock(PLANT_PROPERTIES, Apricorn.GREEN))
@JvmField
val PINK_APRICORN_SAPLING = this.create("pink_apricorn_sapling", ApricornSaplingBlock(PLANT_PROPERTIES, Apricorn.PINK))
@JvmField
val RED_APRICORN_SAPLING = this.create("red_apricorn_sapling", ApricornSaplingBlock(PLANT_PROPERTIES, Apricorn.RED))
@JvmField
val WHITE_APRICORN_SAPLING = this.create("white_apricorn_sapling", ApricornSaplingBlock(PLANT_PROPERTIES, Apricorn.WHITE))
@JvmField
val YELLOW_APRICORN_SAPLING = this.create("yellow_apricorn_sapling", ApricornSaplingBlock(PLANT_PROPERTIES, Apricorn.YELLOW))
@JvmField
val MEDICINAL_LEEK = this.create("medicinal_leek", MedicinalLeekBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).burnable().mapColor(MapColor.DULL_RED).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.MEDICINAL_LEEK_SOUNDS)))
@JvmField
val ENERGY_ROOT = this.create("energy_root", EnergyRootBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).burnable().mapColor(MapColor.DIRT_BROWN).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.ENERGY_ROOT_SOUNDS)))
@JvmField
val BIG_ROOT = this.create("big_root", BigRootBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).burnable().mapColor(MapColor.DARK_GREEN).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.BIG_ROOT_SOUNDS)))
@JvmField
val REVIVAL_HERB = this.create("revival_herb", RevivalHerbBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).mapColor(MapColor.DARK_GREEN).burnable().noCollision().breakInstantly().sounds(CobblemonSounds.REVIVAL_HERB_SOUNDS)))
@JvmField
val TUMBLESTONE_CLUSTER = tumblestoneBlock("tumblestone_cluster", GrowableStoneBlock.STAGE_3, 7, 3, null)
@JvmField
val LARGE_BUDDING_TUMBLESTONE = tumblestoneBlock("large_budding_tumblestone", GrowableStoneBlock.STAGE_2, 5, 3, TUMBLESTONE_CLUSTER)
@JvmField
val MEDIUM_BUDDING_TUMBLESTONE = tumblestoneBlock("medium_budding_tumblestone", GrowableStoneBlock.STAGE_1, 4, 3, LARGE_BUDDING_TUMBLESTONE)
@JvmField
val SMALL_BUDDING_TUMBLESTONE = tumblestoneBlock("small_budding_tumblestone", GrowableStoneBlock.STAGE_0, 3, 4, MEDIUM_BUDDING_TUMBLESTONE)
@JvmField
val SKY_TUMBLESTONE_CLUSTER = tumblestoneBlock("sky_tumblestone_cluster", GrowableStoneBlock.STAGE_3, 7, 3, null)
@JvmField
val LARGE_BUDDING_SKY_TUMBLESTONE = tumblestoneBlock("large_budding_sky_tumblestone", GrowableStoneBlock.STAGE_2, 5, 3, SKY_TUMBLESTONE_CLUSTER)
@JvmField
val MEDIUM_BUDDING_SKY_TUMBLESTONE = tumblestoneBlock("medium_budding_sky_tumblestone", GrowableStoneBlock.STAGE_1, 4, 3, LARGE_BUDDING_SKY_TUMBLESTONE)
@JvmField
val SMALL_BUDDING_SKY_TUMBLESTONE = tumblestoneBlock("small_budding_sky_tumblestone", GrowableStoneBlock.STAGE_0, 3, 4, MEDIUM_BUDDING_SKY_TUMBLESTONE)
@JvmField
val BLACK_TUMBLESTONE_CLUSTER = tumblestoneBlock("black_tumblestone_cluster", GrowableStoneBlock.STAGE_3, 7, 3, null)
@JvmField
val LARGE_BUDDING_BLACK_TUMBLESTONE = tumblestoneBlock("large_budding_black_tumblestone", GrowableStoneBlock.STAGE_2, 5, 3, BLACK_TUMBLESTONE_CLUSTER)
@JvmField
val MEDIUM_BUDDING_BLACK_TUMBLESTONE = tumblestoneBlock("medium_budding_black_tumblestone", GrowableStoneBlock.STAGE_1, 4, 3, LARGE_BUDDING_BLACK_TUMBLESTONE)
@JvmField
val SMALL_BUDDING_BLACK_TUMBLESTONE = tumblestoneBlock("small_budding_black_tumblestone", GrowableStoneBlock.STAGE_0, 3, 4, MEDIUM_BUDDING_BLACK_TUMBLESTONE)
@JvmField
val TUMBLESTONE_BLOCK = this.create("tumblestone_block", Block(AbstractBlock.Settings.create()
.mapColor(MapColor.TERRACOTTA_ORANGE)
.strength(1.0F)
.sounds(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS)
.requiresTool()
.instrument(Instrument.BASEDRUM)
))
@JvmField
val SKY_TUMBLESTONE_BLOCK = this.create("sky_tumblestone_block", Block(AbstractBlock.Settings.create()
.mapColor(MapColor.LIGHT_BLUE)
.strength(1.0F)
.sounds(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS)
.requiresTool()
.instrument(Instrument.BASEDRUM)
))
@JvmField
val BLACK_TUMBLESTONE_BLOCK = this.create("black_tumblestone_block", Block(AbstractBlock.Settings.create()
.mapColor(MapColor.TERRACOTTA_BLACK)
.strength(1.0F)
.sounds(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS)
.requiresTool()
.instrument(Instrument.BASEDRUM)
))
@JvmField
val BLACK_APRICORN = apricornBlock("black_apricorn", Apricorn.BLACK)
@JvmField
val BLUE_APRICORN = apricornBlock("blue_apricorn", Apricorn.BLUE)
@JvmField
val GREEN_APRICORN = apricornBlock("green_apricorn", Apricorn.GREEN)
@JvmField
val PINK_APRICORN = apricornBlock("pink_apricorn", Apricorn.PINK)
@JvmField
val RED_APRICORN = apricornBlock("red_apricorn", Apricorn.RED)
@JvmField
val WHITE_APRICORN = apricornBlock("white_apricorn", Apricorn.WHITE)
@JvmField
val YELLOW_APRICORN = apricornBlock("yellow_apricorn", Apricorn.YELLOW)
@JvmField
val RELIC_COIN_POUCH = create(
"relic_coin_pouch",
CoinPouchBlock(
AbstractBlock.Settings.create()
.sounds(CobblemonSounds.COIN_POUCH_SOUNDS)
.pistonBehavior(PistonBehavior.DESTROY)
.strength(0.4f)
.nonOpaque(), true
)
)
@JvmField
val RELIC_COIN_SACK = create(
"relic_coin_sack",
CoinPouchBlock(
AbstractBlock.Settings.create()
.sounds(CobblemonSounds.COIN_POUCH_SOUNDS)
.pistonBehavior(PistonBehavior.DESTROY)
.strength(0.4f), false
))
@JvmField
val GILDED_CHEST = create(
"gilded_chest",
GildedChestBlock(
AbstractBlock.Settings.copy(Blocks.CHEST).nonOpaque().sounds(CobblemonSounds.GILDED_CHEST_SOUNDS),
GildedChestBlock.Type.RED
)
)
@JvmField
val BLUE_GILDED_CHEST = create(
"blue_gilded_chest",
GildedChestBlock(
AbstractBlock.Settings.copy(Blocks.CHEST).nonOpaque().sounds(CobblemonSounds.GILDED_CHEST_SOUNDS),
GildedChestBlock.Type.BLUE
)
)
@JvmField
val BLACK_GILDED_CHEST = create(
"black_gilded_chest",
GildedChestBlock(
AbstractBlock.Settings.copy(Blocks.CHEST).nonOpaque().sounds(CobblemonSounds.GILDED_CHEST_SOUNDS),
GildedChestBlock.Type.BLACK
)
)
@JvmField
val YELLOW_GILDED_CHEST = create(
"yellow_gilded_chest",
GildedChestBlock(
AbstractBlock.Settings.copy(Blocks.CHEST).nonOpaque().sounds(CobblemonSounds.GILDED_CHEST_SOUNDS),
GildedChestBlock.Type.YELLOW
)
)
@JvmField
val WHITE_GILDED_CHEST = create(
"white_gilded_chest",
GildedChestBlock(
AbstractBlock.Settings.copy(Blocks.CHEST).nonOpaque().sounds(CobblemonSounds.GILDED_CHEST_SOUNDS),
GildedChestBlock.Type.WHITE
)
)
@JvmField
val GREEN_GILDED_CHEST = create(
"green_gilded_chest",
GildedChestBlock(
AbstractBlock.Settings.copy(Blocks.CHEST).nonOpaque().sounds(CobblemonSounds.GILDED_CHEST_SOUNDS),
GildedChestBlock.Type.GREEN
)
)
@JvmField
val PINK_GILDED_CHEST = create(
"pink_gilded_chest",
GildedChestBlock(
AbstractBlock.Settings.copy(Blocks.CHEST).nonOpaque().sounds(CobblemonSounds.GILDED_CHEST_SOUNDS),
GildedChestBlock.Type.PINK
)
)
@JvmField
val GIMMIGHOUL_CHEST = create(
"gimmighoul_chest",
GildedChestBlock(
AbstractBlock.Settings.copy(Blocks.CHEST).nonOpaque().sounds(CobblemonSounds.GILDED_CHEST_SOUNDS),
GildedChestBlock.Type.FAKE
)
)
@JvmField
val MONITOR = create(
"monitor",
MonitorBlock(
AbstractBlock.Settings.create()
.mapColor(MapColor.IRON_GRAY)
.sounds(BlockSoundGroup.METAL)
.pistonBehavior(PistonBehavior.BLOCK)
.requiresTool()
.strength(5.0F, 6.0F)
.luminance { if (it.get(MonitorBlock.SCREEN) != MonitorBlock.MonitorScreen.OFF) 15 else 0 }
)
)
@JvmField
val FOSSIL_ANALYZER = create(
"fossil_analyzer",
FossilAnalyzerBlock(
AbstractBlock.Settings.create()
.mapColor(MapColor.IRON_GRAY)
.sounds(BlockSoundGroup.METAL)
.pistonBehavior(PistonBehavior.BLOCK)
.requiresTool()
.strength(5.0F, 6.0F)
.nonOpaque()
)
)
@JvmField
val RESTORATION_TANK = create(
"restoration_tank",
RestorationTankBlock(
AbstractBlock.Settings.create()
.mapColor(MapColor.IRON_GRAY)
.sounds(BlockSoundGroup.GLASS)
.pistonBehavior(PistonBehavior.BLOCK)
.requiresTool()
.strength(5.0F, 6.0F)
.nonOpaque()
)
)
@JvmField
val HEALING_MACHINE = create(
"healing_machine",
HealingMachineBlock(
AbstractBlock.Settings.create()
.mapColor(MapColor.IRON_GRAY)
.sounds(BlockSoundGroup.METAL)
.pistonBehavior(PistonBehavior.BLOCK)
.strength(2f)
.nonOpaque()
.luminance { if (it.get(HealingMachineBlock.CHARGE_LEVEL) >= HealingMachineBlock.MAX_CHARGE_LEVEL) 7 else 2 }
)
)
@JvmField
val PC = create(
"pc",
PCBlock(
AbstractBlock.Settings.create()
.mapColor(MapColor.IRON_GRAY)
.sounds(BlockSoundGroup.METAL)
.pistonBehavior(PistonBehavior.BLOCK)
.strength(2F)
.nonOpaque()
.luminance { if ((it.get(PCBlock.ON) as Boolean) && (it.get(PCBlock.PART) == PCBlock.PCPart.TOP)) 10 else 0 }
)
)
@JvmField
val DISPLAY_CASE = create(
"display_case",
DisplayCaseBlock(
AbstractBlock.Settings.create()
.sounds(CobblemonSounds.DISPLAY_CASE_SOUNDS)
.nonOpaque()
.pistonBehavior(PistonBehavior.BLOCK)
.mapColor(MapColor.STONE_GRAY)
.strength(0.3f)
)
)
val RED_MINT = create("red_mint", MintBlock(MintType.RED, AbstractBlock.Settings.create().mapColor(MapColor.RED).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.MINT_SOUNDS)))
@JvmField
val BLUE_MINT = create("blue_mint", MintBlock(MintType.BLUE, AbstractBlock.Settings.create().mapColor(MapColor.BLUE).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.MINT_SOUNDS)))
@JvmField
val CYAN_MINT = create("cyan_mint", MintBlock(MintType.CYAN, AbstractBlock.Settings.create().mapColor(MapColor.CYAN).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.MINT_SOUNDS)))
@JvmField
val PINK_MINT = create("pink_mint", MintBlock(MintType.PINK, AbstractBlock.Settings.create().mapColor(MapColor.PINK).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.MINT_SOUNDS)))
@JvmField
val GREEN_MINT = create("green_mint", MintBlock(MintType.GREEN, AbstractBlock.Settings.create().mapColor(MapColor.GREEN).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.MINT_SOUNDS)))
@JvmField
val WHITE_MINT = create("white_mint", MintBlock(MintType.WHITE, AbstractBlock.Settings.create().mapColor(MapColor.WHITE).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.MINT_SOUNDS)))
@JvmField
val PASTURE = create(
"pasture",
PastureBlock(
AbstractBlock.Settings.create()
.mapColor(MapColor.BROWN)
.sounds(BlockSoundGroup.WOOD)
.strength(2F)
.nonOpaque()
.pistonBehavior(PistonBehavior.BLOCK)
.luminance { if ((it.get(PastureBlock.ON) as Boolean) && (it.get(PastureBlock.PART) == PastureBlock.PasturePart.TOP)) 10 else 0 }
)
)
@JvmField
val VIVICHOKE_SEEDS = this.create("vivichoke_seeds", VivichokeBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).burnable().mapColor(MapColor.DARK_GREEN).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.VIVICHOKE_SOUNDS)))
@JvmField
val PEP_UP_FLOWER = this.create("pep_up_flower", FlowerBlock(StatusEffects.LEVITATION, 10, AbstractBlock.Settings.create().mapColor(MapColor.DARK_GREEN).noCollision().breakInstantly().sounds(BlockSoundGroup.GRASS).offset(AbstractBlock.OffsetType.XZ).pistonBehavior(PistonBehavior.DESTROY)))
@JvmField
val POTTED_PEP_UP_FLOWER = this.create("potted_pep_up_flower", BlocksInvoker.createFlowerPotBlock(PEP_UP_FLOWER))
/**
* Returns a map of all the blocks that can be stripped with an axe in the format of input - output.
*
* @return A map of all the blocks that can be stripped with an axe in the format of input - output.
* Apricorns
*/
fun strippedBlocks(): Map<Block, Block> = mapOf(
APRICORN_WOOD to STRIPPED_APRICORN_WOOD,
APRICORN_LOG to STRIPPED_APRICORN_LOG
)
private fun apricornBlock(name: String, apricorn: Apricorn): ApricornBlock = this.create(name, ApricornBlock(AbstractBlock.Settings.create().mapColor(apricorn.mapColor()).ticksRandomly().strength(Blocks.OAK_LOG.hardness, Blocks.OAK_LOG.blastResistance).sounds(BlockSoundGroup.WOOD).nonOpaque(), apricorn))
private fun tumblestoneBlock(name: String, stage: Int, height: Int, xzOffset: Int, nextStage: Block?) : Block {
return this.create(name, TumblestoneBlock(AbstractBlock.Settings.create()
.pistonBehavior(PistonBehavior.DESTROY)
.nonOpaque()
.strength(1.5F)
.sounds(CobblemonSounds.TUMBLESTONE_SOUNDS),
stage, height, xzOffset, nextStage))
@JvmField
val APRICORN_LOG = queue("apricorn_log") {
log(
MapColor.DIRT_BROWN,
MapColor.BROWN
)
}
private val berries = mutableMapOf<Identifier, BerryBlock>()
val AGUAV_BERRY = this.berryBlock("aguav")
val APICOT_BERRY = this.berryBlock("apicot")
val ASPEAR_BERRY = this.berryBlock("aspear")
val BABIRI_BERRY = this.berryBlock("babiri")
val BELUE_BERRY = this.berryBlock("belue")
val BLUK_BERRY = this.berryBlock("bluk")
val CHARTI_BERRY = this.berryBlock("charti")
val CHERI_BERRY = this.berryBlock("cheri")
val CHESTO_BERRY = this.berryBlock("chesto")
val CHILAN_BERRY = this.berryBlock("chilan")
val CHOPLE_BERRY = this.berryBlock("chople")
val COBA_BERRY = this.berryBlock("coba")
val COLBUR_BERRY = this.berryBlock("colbur")
val CORNN_BERRY = this.berryBlock("cornn")
val CUSTAP_BERRY = this.berryBlock("custap")
val DURIN_BERRY = this.berryBlock("durin")
val ENIGMA_BERRY = this.berryBlock("enigma")
val FIGY_BERRY = this.berryBlock("figy")
val GANLON_BERRY = this.berryBlock("ganlon")
val GREPA_BERRY = this.berryBlock("grepa")
val HABAN_BERRY = this.berryBlock("haban")
val HONDEW_BERRY = this.berryBlock("hondew")
val HOPO_BERRY = this.berryBlock("hopo")
val IAPAPA_BERRY = this.berryBlock("iapapa")
val JABOCA_BERRY = this.berryBlock("jaboca")
val KASIB_BERRY = this.berryBlock("kasib")
val KEBIA_BERRY = this.berryBlock("kebia")
val KEE_BERRY = this.berryBlock("kee")
val KELPSY_BERRY = this.berryBlock("kelpsy")
val LANSAT_BERRY = this.berryBlock("lansat")
val LEPPA_BERRY = this.berryBlock("leppa")
val LIECHI_BERRY = this.berryBlock("liechi")
val LUM_BERRY = this.berryBlock("lum")
val MAGO_BERRY = this.berryBlock("mago")
val MAGOST_BERRY = this.berryBlock("magost")
val MARANGA_BERRY = this.berryBlock("maranga")
val MICLE_BERRY = this.berryBlock("micle")
val NANAB_BERRY = this.berryBlock("nanab")
val NOMEL_BERRY = this.berryBlock("nomel")
val OCCA_BERRY = this.berryBlock("occa")
val ORAN_BERRY = this.berryBlock("oran")
val PAMTRE_BERRY = this.berryBlock("pamtre")
val PASSHO_BERRY = this.berryBlock("passho")
val PAYAPA_BERRY = this.berryBlock("payapa")
val PECHA_BERRY = this.berryBlock("pecha")
val PERSIM_BERRY = this.berryBlock("persim")
val PETAYA_BERRY = this.berryBlock("petaya")
val PINAP_BERRY = this.berryBlock("pinap")
val POMEG_BERRY = this.berryBlock("pomeg")
val QUALOT_BERRY = this.berryBlock("qualot")
val RABUTA_BERRY = this.berryBlock("rabuta")
val RAWST_BERRY = this.berryBlock("rawst")
val RAZZ_BERRY = this.berryBlock("razz")
val RINDO_BERRY = this.berryBlock("rindo")
val ROSELI_BERRY = this.berryBlock("roseli")
val ROWAP_BERRY = this.berryBlock("rowap")
val SALAC_BERRY = this.berryBlock("salac")
val SHUCA_BERRY = this.berryBlock("shuca")
val SITRUS_BERRY = this.berryBlock("sitrus")
val SPELON_BERRY = this.berryBlock("spelon")
val STARF_BERRY = this.berryBlock("starf")
val TAMATO_BERRY = this.berryBlock("tamato")
val TANGA_BERRY = this.berryBlock("tanga")
val TOUGA_BERRY = this.berryBlock("touga")
val WACAN_BERRY = this.berryBlock("wacan")
val WATMEL_BERRY = this.berryBlock("watmel")
val WEPEAR_BERRY = this.berryBlock("wepear")
val WIKI_BERRY = this.berryBlock("wiki")
val YACHE_BERRY = this.berryBlock("yache")
init {
/**
* Makes all blocks in array flammable by adding them to FireBlock's flammableRegistry.
* second value is burn chance and third value is spread chance
*/
arrayOf(
Triple(APRICORN_LOG, 5, 5),
Triple(STRIPPED_APRICORN_LOG, 5, 5),
Triple(APRICORN_WOOD, 5, 5),
Triple(STRIPPED_APRICORN_WOOD, 5, 5),
Triple(APRICORN_PLANKS, 5, 20),
Triple(APRICORN_LEAVES, 30, 60),
Triple(APRICORN_FENCE, 5, 20),
Triple(APRICORN_FENCE_GATE, 5, 20),
Triple(APRICORN_SLAB, 5, 20),
Triple(APRICORN_STAIRS, 5, 20)
).onEach{ data -> setFlammable(data.first, data.second, data.third) }
@JvmField
val STRIPPED_APRICORN_LOG = queue("stripped_apricorn_log") {
log(
MapColor.DIRT_BROWN,
MapColor.DIRT_BROWN
)
}
@JvmField
val APRICORN_WOOD = queue("apricorn_wood") {
log(
MapColor.DIRT_BROWN,
MapColor.DIRT_BROWN
)
}
@JvmField
val STRIPPED_APRICORN_WOOD = queue("stripped_apricorn_wood") {
log(
MapColor.DIRT_BROWN,
MapColor.DIRT_BROWN
)
}
@JvmField
val APRICORN_PLANKS = queue("apricorn_planks") { Block(AbstractBlock.Settings.of(Material.WOOD, MapColor.DIRT_BROWN).strength(2.0f, 3.0f).sounds(BlockSoundGroup.WOOD)) }
@JvmField
val APRICORN_LEAVES = queue("apricorn_leaves") { com.cobblemon.mod.common.CobblemonBlocks.leaves(BlockSoundGroup.GRASS) }
@JvmField
val APRICORN_FENCE = queue("apricorn_fence") { FenceBlock(AbstractBlock.Settings.of(Material.WOOD, APRICORN_PLANKS.get().defaultMapColor).strength(2.0f, 3.0f).sounds(BlockSoundGroup.WOOD)) }
@JvmField
val APRICORN_FENCE_GATE = queue("apricorn_fence_gate") { FenceGateBlock(AbstractBlock.Settings.of(Material.WOOD, APRICORN_PLANKS.get().defaultMapColor).strength(2.0f, 3.0f).sounds(BlockSoundGroup.WOOD)) }
@JvmField
val APRICORN_BUTTON = queue("apricorn_button") { WoodenButtonBlock(AbstractBlock.Settings.of(Material.DECORATION).noCollision().strength(0.5f).sounds(BlockSoundGroup.WOOD)) }
@JvmField
val APRICORN_PRESSURE_PLATE = queue("apricorn_pressure_plate") { PressurePlateBlock(PressurePlateBlock.ActivationRule.EVERYTHING, AbstractBlock.Settings.of(Material.WOOD, APRICORN_PLANKS.get().defaultMapColor).noCollision().strength(0.5f).sounds(BlockSoundGroup.WOOD)) }
// Tag was removed be sure to add it back when implemented
// @JvmField
// val APRICORN_SIGN = queue("apricorn_sign") { StandingSignBlock(AbstractBlock.Settings.of(Material.WOOD).noCollission().strength(1.0f).sounds(BlockSoundGroup.WOOD), APRICORN_WOOD_TYPE) }
//@JvmField
// val APRICORN_WALL_SIGN = queue("apricorn_wall_sign") { WallSignBlock(AbstractBlock.Settings.of(Material.WOOD).noCollission().strength(1.0f).sounds(BlockSoundGroup.WOOD).dropsLike(APRICORN_SIGN), APRICORN_WOOD_TYPE) }
@JvmField
val APRICORN_SLAB = queue("apricorn_slab") { SlabBlock(AbstractBlock.Settings.of(Material.WOOD, MapColor.OAK_TAN).strength(2.0f, 3.0f).sounds(BlockSoundGroup.WOOD)) }
@JvmField
val APRICORN_STAIRS = queue("apricorn_stairs") { StairsBlock(
APRICORN_PLANKS.get().defaultState, AbstractBlock.Settings.copy(
APRICORN_PLANKS.get())) }
@JvmField
val APRICORN_DOOR = queue("apricorn_door") { DoorBlock(AbstractBlock.Settings.of(Material.WOOD, APRICORN_PLANKS.get().defaultMapColor).strength(3.0F).sounds(BlockSoundGroup.WOOD).nonOpaque()) }
@JvmField
val APRICORN_TRAPDOOR = queue("apricorn_trapdoor") { TrapdoorBlock(AbstractBlock.Settings.of(Material.WOOD, MapColor.OAK_TAN).strength(3.0F).sounds(BlockSoundGroup.WOOD).nonOpaque().allowsSpawning { _, _, _, _ -> false }) }
fun berries() = this.berries.toMap()
private val PLANT_PROPERTIES = AbstractBlock.Settings.of(Material.PLANT).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.GRASS)
@JvmField
val BLACK_APRICORN_SAPLING = queue("black_apricorn_sapling") { ApricornSaplingBlock(PLANT_PROPERTIES, Apricorn.BLACK) }
@JvmField
val BLUE_APRICORN_SAPLING = queue("blue_apricorn_sapling") { ApricornSaplingBlock(PLANT_PROPERTIES, Apricorn.BLUE) }
@JvmField
val GREEN_APRICORN_SAPLING = queue("green_apricorn_sapling") { ApricornSaplingBlock(PLANT_PROPERTIES, Apricorn.GREEN) }
@JvmField
val PINK_APRICORN_SAPLING = queue("pink_apricorn_sapling") { ApricornSaplingBlock(PLANT_PROPERTIES, Apricorn.PINK) }
@JvmField
val RED_APRICORN_SAPLING = queue("red_apricorn_sapling") { ApricornSaplingBlock(PLANT_PROPERTIES, Apricorn.RED) }
@JvmField
val WHITE_APRICORN_SAPLING = queue("white_apricorn_sapling") { ApricornSaplingBlock(PLANT_PROPERTIES, Apricorn.WHITE) }
@JvmField
val YELLOW_APRICORN_SAPLING = queue("yellow_apricorn_sapling") { ApricornSaplingBlock(PLANT_PROPERTIES, Apricorn.YELLOW) }
private fun berryBlock(name: String): BerryBlock {
val identifier = cobblemonResource("${name}_berry")
val block = this.create(identifier.path, BerryBlock(identifier, AbstractBlock.Settings.copy(Blocks.WHEAT).dynamicBounds().sounds(CobblemonSounds.BERRY_BUSH_SOUNDS).strength(0.2F)))
this.berries[identifier] = block
return block
@JvmField
val BLACK_APRICORN = registerApricornBlock("black_apricorn", Apricorn.BLACK)
@JvmField
val BLUE_APRICORN = registerApricornBlock("blue_apricorn", Apricorn.BLUE)
@JvmField
val GREEN_APRICORN = registerApricornBlock("green_apricorn", Apricorn.GREEN)
@JvmField
val PINK_APRICORN = registerApricornBlock("pink_apricorn", Apricorn.PINK)
@JvmField
val RED_APRICORN = registerApricornBlock("red_apricorn", Apricorn.RED)
@JvmField
val WHITE_APRICORN = registerApricornBlock("white_apricorn", Apricorn.WHITE)
@JvmField
val YELLOW_APRICORN = registerApricornBlock("yellow_apricorn", Apricorn.YELLOW)
@JvmField
val HEALING_MACHINE = queue("healing_machine") { HealingMachineBlock(AbstractBlock.Settings.of(Material.METAL, MapColor.IRON_GRAY).sounds(BlockSoundGroup.METAL).strength(2f).nonOpaque().luminance(ToIntFunction { state: BlockState -> if (state.get(HealingMachineBlock.CHARGE_LEVEL) >= HealingMachineBlock.MAX_CHARGE_LEVEL) 7 else 2 })) }
@JvmField
val PC = queue("pc") { PCBlock(AbstractBlock.Settings.of(Material.METAL, MapColor.IRON_GRAY).sounds(BlockSoundGroup.METAL).strength(2F).nonOpaque().luminance(ToIntFunction { state: BlockState -> if ((state.get(
PCBlock.ON) as Boolean) && (state.get(PCBlock.PART) == PCBlock.PCPart.TOP)) 10 else 0 })) }
private fun registerApricornBlock(id: String, apricorn: Apricorn): RegistrySupplier<ApricornBlock> {
return queue(id) { ApricornBlock(AbstractBlock.Settings.of(Material.PLANT, apricorn.mapColor()).ticksRandomly().strength(Blocks.OAK_LOG.hardness, Blocks.OAK_LOG.blastResistance).sounds(BlockSoundGroup.WOOD).nonOpaque(), apricorn) }
}
/**
* Calls helper method from Vanilla
* Helper method for creating logs
* copied over from Vanilla
*/
private fun log(name: String, arg: MapColor = MapColor.DIRT_BROWN, arg2: MapColor = MapColor.DIRT_BROWN): PillarBlock {
val block = BlocksInvoker.createLogBlock(arg, arg2)
return this.create(name, block)
private fun log(arg: MapColor, arg2: MapColor): PillarBlock {
return PillarBlock(AbstractBlock.Settings.of(Material.WOOD) { arg3: BlockState ->
if (arg3.get(PillarBlock.AXIS) === Direction.Axis.Y) arg else arg2
}.strength(2.0f).sounds(BlockSoundGroup.WOOD))
}
/**
* Method uses generic E in order to keep the block as the same return type.
* If E is not a block then it will not be set as flammable.
* Calls Vanilla implementation of registering a flammable block.
* Mixins looks cursed but it is java's fault.
*/
private fun <E> setFlammable(block: E, burnChance: Int, spreadChance: Int): E {
if(block !is Block) return block
private fun evolutionStoneOre(name: String) = this.queue(name) { OreBlock(AbstractBlock.Settings.copy(Blocks.IRON_ORE), UniformIntProvider.create(1, 2)) }
var fireBlock: FireBlock = Blocks.FIRE as FireBlock
//Cursed Mixin stuff
(fireBlock as FireBlockInvoker).registerNewFlammableBlock(block as Block, burnChance, spreadChance)
return block
}
private fun evolutionStoneOre(name: String) = this.create(name, ExperienceDroppingBlock(AbstractBlock.Settings.copy(Blocks.IRON_ORE), UniformIntProvider.create(1, 2)))
private fun deepslateEvolutionStoneOre(name: String) = this.create(name, ExperienceDroppingBlock(AbstractBlock.Settings.copy(Blocks.DEEPSLATE_IRON_ORE), UniformIntProvider.create(1, 2)))
private fun deepslateEvolutionStoneOre(name: String) = this.queue(name) { OreBlock(AbstractBlock.Settings.copy(Blocks.DEEPSLATE_IRON_ORE), UniformIntProvider.create(1, 2)) }
/**
* Helper method for creating leaves
* copied over from Vanilla
*/
private fun leaves(name: String): LeavesBlock {
val block = BlocksInvoker.createLeavesBlock(BlockSoundGroup.GRASS)
return this.create(name, block)
private fun leaves(sound: BlockSoundGroup): LeavesBlock {
return LeavesBlock(
AbstractBlock.Settings.of(Material.LEAVES).strength(0.2f).ticksRandomly().sounds(sound).nonOpaque()
.allowsSpawning { _, _, _, type -> type === EntityType.OCELOT || type === EntityType.PARROT }
.suffocates { _, _, _ -> false }
.blockVision { _, _, _ -> false })
}
}
}
@@ -8,24 +8,13 @@
package com.cobblemon.mod.common
import net.minecraft.block.Block
import net.minecraft.block.entity.BlockEntity
import net.minecraft.block.entity.BlockEntityType
import net.minecraft.client.color.block.BlockColorProvider
import net.minecraft.client.color.item.ItemColorProvider
import java.util.function.Supplier
import net.minecraft.client.model.TexturedModelData
import net.minecraft.client.particle.ParticleFactory
import net.minecraft.client.particle.SpriteProvider
import net.minecraft.client.render.RenderLayer
import net.minecraft.client.render.block.entity.BlockEntityRendererFactory
import net.minecraft.client.render.entity.EntityRendererFactory
import net.minecraft.client.render.entity.model.EntityModelLayer
import net.minecraft.entity.Entity
import net.minecraft.entity.EntityType
import net.minecraft.item.Item
import net.minecraft.particle.ParticleEffect
import net.minecraft.particle.ParticleType
import java.util.function.Supplier
interface CobblemonClientImplementation {
fun registerLayer(modelLayer: EntityModelLayer, supplier: Supplier<TexturedModelData>)
@@ -33,14 +22,4 @@ interface CobblemonClientImplementation {
type: ParticleType<T>,
factory: (SpriteProvider) -> ParticleFactory<T>
)
fun registerBlockRenderType(layer: RenderLayer, vararg blocks: Block)
fun registerItemColors(provider: ItemColorProvider, vararg items: Item)
fun registerBlockColors(provider: BlockColorProvider, vararg blocks: Block)
fun <T : BlockEntity> registerBlockEntityRenderer(type: BlockEntityType<out T>, factory: BlockEntityRendererFactory<T>)
fun <T : Entity> registerEntityRenderer(type: EntityType<out T>, factory: EntityRendererFactory<T>)
}
@@ -20,7 +20,6 @@ object CobblemonCommands {
GivePokemon.register(dispatcher)
TakePokemon.register(dispatcher)
ChangeScaleAndSize.register(dispatcher)
ChangeWalkSpeed.register(dispatcher)
TestCommand.register(dispatcher)
ReloadShowdownCommand.register(dispatcher)
ClickTextCommand.register(dispatcher)
@@ -39,18 +38,5 @@ object CobblemonCommands {
PcCommand.register(dispatcher)
SpawnPokemonFromPool.register(dispatcher)
PokeboxCommand.register(dispatcher)
TestStoreCommand.register(dispatcher)
QueryLearnsetCommand.register(dispatcher)
TestPcSlotCommand.register(dispatcher)
TestPartySlotCommand.register(dispatcher)
ClearPartyCommand.register(dispatcher)
ClearPCCommand.register(dispatcher)
PokemonRestartCommand.register(dispatcher)
BedrockParticleCommand.register(dispatcher)
OpenDialogueCommand.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
CobblemonInfoCommand.register(dispatcher)
}
}
@@ -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
import net.minecraft.util.registry.RegistryEntry
import net.minecraft.world.gen.feature.ConfiguredFeature
import net.minecraft.world.gen.feature.ConfiguredFeatures
import net.minecraft.world.gen.feature.SingleStateFeatureConfig
object CobblemonConfiguredFeatures {
lateinit var BLACK_APRICORN_TREE: RegistryEntry<ConfiguredFeature<SingleStateFeatureConfig, *>>
lateinit var BLUE_APRICORN_TREE: RegistryEntry<ConfiguredFeature<SingleStateFeatureConfig, *>>
lateinit var GREEN_APRICORN_TREE: RegistryEntry<ConfiguredFeature<SingleStateFeatureConfig, *>>
lateinit var PINK_APRICORN_TREE: RegistryEntry<ConfiguredFeature<SingleStateFeatureConfig, *>>
lateinit var RED_APRICORN_TREE: RegistryEntry<ConfiguredFeature<SingleStateFeatureConfig, *>>
lateinit var WHITE_APRICORN_TREE: RegistryEntry<ConfiguredFeature<SingleStateFeatureConfig, *>>
lateinit var YELLOW_APRICORN_TREE: RegistryEntry<ConfiguredFeature<SingleStateFeatureConfig, *>>
fun register() {
BLACK_APRICORN_TREE = ConfiguredFeatures.register("black_apricorn_tree", CobblemonFeatures.APRICORN_TREE_FEATURE.get(), SingleStateFeatureConfig(
CobblemonBlocks.BLACK_APRICORN.get().defaultState))
BLUE_APRICORN_TREE = ConfiguredFeatures.register("blue_apricorn_tree", CobblemonFeatures.APRICORN_TREE_FEATURE.get(), SingleStateFeatureConfig(
CobblemonBlocks.BLUE_APRICORN.get().defaultState))
GREEN_APRICORN_TREE = ConfiguredFeatures.register("green_apricorn_tree", CobblemonFeatures.APRICORN_TREE_FEATURE.get(), SingleStateFeatureConfig(
CobblemonBlocks.GREEN_APRICORN.get().defaultState))
PINK_APRICORN_TREE = ConfiguredFeatures.register("pink_apricorn_tree", CobblemonFeatures.APRICORN_TREE_FEATURE.get(), SingleStateFeatureConfig(
CobblemonBlocks.PINK_APRICORN.get().defaultState))
RED_APRICORN_TREE = ConfiguredFeatures.register("red_apricorn_tree", CobblemonFeatures.APRICORN_TREE_FEATURE.get(), SingleStateFeatureConfig(
CobblemonBlocks.RED_APRICORN.get().defaultState))
WHITE_APRICORN_TREE = ConfiguredFeatures.register("white_apricorn_tree", CobblemonFeatures.APRICORN_TREE_FEATURE.get(), SingleStateFeatureConfig(
CobblemonBlocks.WHITE_APRICORN.get().defaultState))
YELLOW_APRICORN_TREE = ConfiguredFeatures.register("yellow_apricorn_tree", CobblemonFeatures.APRICORN_TREE_FEATURE.get(), SingleStateFeatureConfig(
CobblemonBlocks.YELLOW_APRICORN.get().defaultState))
}
}
@@ -8,75 +8,66 @@
package com.cobblemon.mod.common
import com.cobblemon.mod.common.api.events.CobblemonEvents
import com.cobblemon.mod.common.api.events.entity.EntityAttributeEvent
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.generic.GenericBedrockEntity
import com.cobblemon.mod.common.entity.data.CobblemonTrackedDataHandlerRegistry
import com.cobblemon.mod.common.entity.pokeball.EmptyPokeBallEntity
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.platform.PlatformRegistry
import com.cobblemon.mod.common.registry.CompletableRegistry
import com.cobblemon.mod.common.util.cobblemonResource
import dev.architectury.registry.level.entity.EntityAttributeRegistry
import dev.architectury.registry.registries.RegistrySupplier
import net.minecraft.entity.Entity
import net.minecraft.entity.EntityType
import net.minecraft.entity.LivingEntity
import net.minecraft.entity.SpawnGroup
import net.minecraft.entity.attribute.DefaultAttributeContainer
import net.minecraft.registry.Registries
import net.minecraft.registry.Registry
import net.minecraft.registry.RegistryKey
import net.minecraft.registry.RegistryKeys
import net.minecraft.entity.attribute.EntityAttributes
import net.minecraft.util.registry.Registry
object CobblemonEntities : PlatformRegistry<Registry<EntityType<*>>, RegistryKey<Registry<EntityType<*>>>, EntityType<*>>() {
object CobblemonEntities : CompletableRegistry<EntityType<*>>(Registry.ENTITY_TYPE_KEY) {
override val registry: Registry<EntityType<*>> = Registries.ENTITY_TYPE
override val registryKey: RegistryKey<Registry<EntityType<*>>> = RegistryKeys.ENTITY_TYPE
@JvmField
val POKEMON_KEY = cobblemonResource("pokemon")
@JvmField
val POKEMON: EntityType<PokemonEntity> = this.create(
POKEMON_KEY.path,
EntityType.Builder.create({ _, world -> PokemonEntity(world) }, SpawnGroup.CREATURE)
.build(POKEMON_KEY.toString())
)
@JvmField
val EMPTY_POKEBALL_KEY = cobblemonResource("empty_pokeball")
@JvmField
val EMPTY_POKEBALL: EntityType<EmptyPokeBallEntity> = this.create(
EMPTY_POKEBALL_KEY.path,
EntityType.Builder.create({ _, world -> EmptyPokeBallEntity(PokeBalls.POKE_BALL, world) }, SpawnGroup.MISC)
.build(EMPTY_POKEBALL_KEY.toString())
)
@JvmField
val BOAT_KEY = cobblemonResource("boat")
@JvmField
val BOAT: EntityType<CobblemonBoatEntity> = this.create(
BOAT_KEY.path,
EntityType.Builder.create(::CobblemonBoatEntity, SpawnGroup.MISC).setDimensions(1.375F, 0.5625F).maxTrackingRange(10)
.build(BOAT_KEY.toString())
)
@JvmField
val CHEST_BOAT_KEY = cobblemonResource("chest_boat")
@JvmField
val CHEST_BOAT: EntityType<CobblemonChestBoatEntity> = this.create(
CHEST_BOAT_KEY.path,
EntityType.Builder.create(::CobblemonChestBoatEntity, SpawnGroup.MISC).setDimensions(1.375F, 0.5625F).maxTrackingRange(10)
.build(CHEST_BOAT_KEY.toString())
)
@JvmField
val GENERIC_BEDROCK_ENTITY_KEY = cobblemonResource("generic_bedrock")
@JvmField
val GENERIC_BEDROCK_ENTITY: EntityType<GenericBedrockEntity> = this.create(
GENERIC_BEDROCK_ENTITY_KEY.path,
EntityType.Builder.create({ _, world -> GenericBedrockEntity(world) }, SpawnGroup.MISC)
.build(GENERIC_BEDROCK_ENTITY_KEY.toString())
)
fun registerAttributes(consumer: (EntityType<out LivingEntity>, DefaultAttributeContainer.Builder) -> Unit) {
consumer(POKEMON, PokemonEntity.createAttributes())
override fun register() {
super.register()
CobblemonTrackedDataHandlerRegistry.register()
EntityAttributeRegistry.register(
{ POKEMON.get() },
{
LivingEntity.createLivingAttributes()
.add(EntityAttributes.GENERIC_FOLLOW_RANGE)
.also { CobblemonEvents.ENTITY_ATTRIBUTE.post(EntityAttributeEvent(POKEMON.get(), it)) }
}
)
}
private fun <T : Entity> entity(
name: String,
entityTypeBuilder: EntityType.Builder<T>
): RegistrySupplier<EntityType<T>> {
return queue(name) { entityTypeBuilder.build(cobblemonResource(name).toString()) }
}
private fun <T : LivingEntity> livingEntity(
name: String,
entityTypeBuilder: EntityType.Builder<T>
): RegistrySupplier<EntityType<T>> {
return queue(name) { entityTypeBuilder.build(cobblemonResource("pokemon").toString()) }
}
@JvmField
val POKEMON = livingEntity(
name = "pokemon",
entityTypeBuilder = EntityType.Builder.create<PokemonEntity>(
{ _, world -> PokemonEntity(world) },
SpawnGroup.CREATURE
)
)
@JvmField
val EMPTY_POKEBALL = entity(
name = "empty_pokeball",
entityTypeBuilder = EntityType.Builder.create<EmptyPokeBallEntity>(
{ _, world -> EmptyPokeBallEntity(PokeBalls.POKE_BALL, world) },
SpawnGroup.MISC
)
)
}
@@ -0,0 +1,26 @@
/*
* 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.registry.CompletableRegistry
import com.cobblemon.mod.common.world.feature.ApricornTreeFeature
import dev.architectury.registry.registries.RegistrySupplier
import java.util.function.Supplier
import net.minecraft.util.registry.Registry
import net.minecraft.world.gen.feature.Feature
import net.minecraft.world.gen.feature.SingleStateFeatureConfig
object CobblemonFeatures : CompletableRegistry<Feature<*>>(Registry.FEATURE_KEY) {
private fun <T : Feature<*>> register(name: String, feature: Supplier<T>) : RegistrySupplier<T> {
return queue(name, feature)
}
@JvmField
val APRICORN_TREE_FEATURE = register("apricorn_tree_feature") { ApricornTreeFeature(SingleStateFeatureConfig.CODEC) }
}
@@ -8,208 +8,12 @@
package com.cobblemon.mod.common
import com.cobblemon.mod.common.api.data.JsonDataRegistry
import com.cobblemon.mod.common.api.net.ClientNetworkPacketHandler
import com.cobblemon.mod.common.api.net.NetworkPacket
import com.cobblemon.mod.common.api.net.ServerNetworkPacketHandler
import com.mojang.brigadier.arguments.ArgumentType
import kotlin.reflect.KClass
import net.minecraft.advancement.criterion.Criterion
import net.minecraft.block.ComposterBlock
import net.minecraft.command.argument.serialize.ArgumentSerializer
import net.minecraft.item.ItemConvertible
import net.minecraft.network.PacketByteBuf
import net.minecraft.network.listener.ClientPlayPacketListener
import net.minecraft.network.packet.Packet
import net.minecraft.registry.RegistryKey
import net.minecraft.registry.tag.TagKey
import net.minecraft.resource.ResourceManager
import net.minecraft.resource.ResourceReloader
import net.minecraft.resource.ResourceType
import net.minecraft.server.MinecraftServer
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.text.Text
import net.minecraft.util.Identifier
import net.minecraft.world.GameRules
import net.minecraft.world.biome.Biome
import net.minecraft.world.gen.GenerationStep
import net.minecraft.world.gen.feature.PlacedFeature
interface CobblemonImplementation {
val modAPI: ModAPI
/**
*
*/
val networkManager: NetworkManager
/**
* TODO
*
* @return
*/
fun environment(): Environment
/**
* TODO
*
* @param id
* @return
*/
fun isModInstalled(id: String): Boolean
/**
* TODO
*
*/
fun registerPermissionValidator()
/**
* TODO
*
*/
fun registerSoundEvents()
/**
* TODO
*
*/
fun registerItems()
/**
* TODO
*
*/
fun registerBlocks()
/**
* TODO
*
*/
fun registerEntityTypes()
/**
* TODO
*
*/
fun registerEntityAttributes()
/**
* TODO
*
*/
fun registerBlockEntityTypes()
/**
* TODO
*
*/
fun registerWorldGenFeatures()
fun registerParticles()
/**
* Add a feature to the current platform implementation.
*
* @param feature The [PlacedFeature] being added.
* @param step The [GenerationStep.Feature] of this feature.
* @param validTag The [TagKey] required by the [Biome] for this feature to generate in, if null all biomes are valid.
*/
fun addFeatureToWorldGen(feature: RegistryKey<PlacedFeature>, step: GenerationStep.Feature, validTag: TagKey<Biome>?)
/**
* TODO
*
* @param A
* @param T
* @param identifier
* @param argumentClass
* @param serializer
*/
fun <A : ArgumentType<*>, T : ArgumentSerializer.ArgumentTypeProperties<A>> registerCommandArgument(identifier: Identifier, argumentClass: KClass<A>, serializer: ArgumentSerializer<A, T>)
/**
* TODO
*
* @param T
* @param name
* @param category
* @param type
* @return
*/
fun <T : GameRules.Rule<T>> registerGameRule(name: String, category: GameRules.Category, type: GameRules.Type<T>): GameRules.Key<T>
/**
* TODO
*
* @param T
* @param criteria
* @return
*/
fun <T : Criterion<*>> registerCriteria(criteria: T): T
/**
* TODO
*
* @param identifier
* @param reloader
* @param type
* @param dependencies
*/
fun registerResourceReloader(identifier: Identifier, reloader: ResourceReloader, type: ResourceType, dependencies: Collection<Identifier>)
/**
* TODO
*
* @return
*/
fun server(): MinecraftServer?
/**
* Handles platform independent reloading of a [JsonDataRegistry].
*
* @param registry The [JsonDataRegistry] to reload.
* @param manager The [ResourceManager] to reload from.
*/
fun <T> reloadJsonRegistry(registry: JsonDataRegistry<T>, manager: ResourceManager): HashMap<Identifier, T>
/**
* Registers an item to the [ComposterBlock].
*
* @param item The [ItemConvertible] being registered.
* @param chance The chance % of increasing the composter level, 0 to 1 expected.
*/
fun registerCompostable(item: ItemConvertible, chance: Float)
/**
* Registers a builtin resource pack.
*
* @param id The unique [Identifier] of this pack.
* @param title The title displayed in the resource pack GUI, the description is still a part of the pack metadata.
* @param activationBehaviour The [ResourcePackActivationBehaviour] for this pack.
*/
fun registerBuiltinResourcePack(id: Identifier, title: Text, activationBehaviour: ResourcePackActivationBehaviour)
}
enum class ResourcePackActivationBehaviour {
/**
* The resource pack will start disabled.
*/
NORMAL,
/**
* The resource pack will start enabled.
*/
DEFAULT_ENABLED,
/**
* The resource pack will always be enabled.
* The user can reorder it but cannot remove it.
*/
ALWAYS_ENABLED;
}
enum class ModAPI {
@@ -217,27 +21,12 @@ enum class ModAPI {
FORGE
}
interface NetworkManager {
interface NetworkDelegate {
fun registerClientBound()
fun registerServerBound()
fun <T: NetworkPacket<T>> createClientBound(identifier: Identifier, kClass: KClass<T>, encoder: (T, PacketByteBuf) -> Unit, decoder: (PacketByteBuf) -> T, handler: ClientNetworkPacketHandler<T>)
fun <T: NetworkPacket<T>> createServerBound(identifier: Identifier, kClass: KClass<T>, encoder: (T, PacketByteBuf) -> Unit, decoder: (PacketByteBuf) -> T, handler: ServerNetworkPacketHandler<T>)
fun sendPacketToPlayer(player: ServerPlayerEntity, packet: NetworkPacket<*>)
fun sendPacketToServer(packet: NetworkPacket<*>)
fun <T : NetworkPacket<*>> asVanillaClientBound(packet: T): Packet<ClientPlayPacketListener>
}
enum class Environment {
CLIENT,
SERVER
}
fun sendPacketToPlayer(player: ServerPlayerEntity, packet: NetworkPacket)
fun sendPacketToServer(packet: NetworkPacket)
fun <T : NetworkPacket> buildMessage(
packetClass: Class<T>,
toServer: Boolean
): CobblemonNetwork.PreparedMessage<T>
}
File diff suppressed because it is too large Load Diff
@@ -1,50 +0,0 @@
/*
* 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.Expression
import com.cobblemon.mod.common.api.data.DataRegistry
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.cobblemonResource
import com.google.gson.GsonBuilder
import net.minecraft.resource.ResourceManager
import net.minecraft.resource.ResourceType
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.util.Identifier
object CobblemonMechanics : DataRegistry {
override val id: Identifier = cobblemonResource("mechanics")
override val type = ResourceType.SERVER_DATA
override val observable = SimpleObservable<CobblemonMechanics>()
val gson = GsonBuilder()
.setPrettyPrinting()
.registerTypeAdapter(Expression::class.java, ExpressionAdapter)
.create()
var remedies = RemediesMechanic()
var berries = BerriesMechanic()
var potions = PotionsMechanic()
override fun sync(player: ServerPlayerEntity) {}
override fun reload(manager: ResourceManager) {
remedies = loadMechanic(manager, "remedies", RemediesMechanic::class.java)
berries = loadMechanic(manager, "berries", BerriesMechanic::class.java)
potions = loadMechanic(manager, "potions", PotionsMechanic::class.java)
}
private fun <T> loadMechanic(manager: ResourceManager, name: String, clazz: Class<T>): T {
manager.getResourceOrThrow(cobblemonResource("mechanics/$name.json")).inputStream.use {
return gson.fromJson(it.reader(), clazz)
}
}
}
@@ -8,89 +8,35 @@
package com.cobblemon.mod.common
import com.cobblemon.mod.common.api.net.ClientNetworkPacketHandler
import com.cobblemon.mod.common.net.messages.client.battle.BattlePersistentStatusPacket
import com.cobblemon.mod.common.api.events.CobblemonEvents
import com.cobblemon.mod.common.api.events.net.MessageBuiltEvent
import com.cobblemon.mod.common.api.net.NetworkPacket
import com.cobblemon.mod.common.api.net.ServerNetworkPacketHandler
import com.cobblemon.mod.common.client.net.PlayerInteractOptionsHandler
import com.cobblemon.mod.common.client.net.SetClientPlayerDataHandler
import com.cobblemon.mod.common.client.net.animation.PlayPoseableAnimationHandler
import com.cobblemon.mod.common.client.net.battle.*
import com.cobblemon.mod.common.client.net.callback.move.OpenMoveCallbackHandler
import com.cobblemon.mod.common.client.net.callback.party.OpenPartyCallbackHandler
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.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.pasture.ClosePastureHandler
import com.cobblemon.mod.common.client.net.pasture.OpenPastureHandler
import com.cobblemon.mod.common.client.net.pasture.PokemonPasturedHandler
import com.cobblemon.mod.common.client.net.pasture.PokemonUnpasturedHandler
import com.cobblemon.mod.common.client.net.pokemon.update.PokemonUpdatePacketHandler
import com.cobblemon.mod.common.client.net.settings.ServerSettingsPacketHandler
import com.cobblemon.mod.common.client.net.sound.UnvalidatedPlaySoundS2CPacketHandler
import com.cobblemon.mod.common.client.net.spawn.SpawnExtraDataEntityHandler
import com.cobblemon.mod.common.client.net.starter.StarterUIPacketHandler
import com.cobblemon.mod.common.client.net.storage.RemoveClientPokemonHandler
import com.cobblemon.mod.common.client.net.storage.SwapClientPokemonHandler
import com.cobblemon.mod.common.client.net.storage.party.InitializePartyHandler
import com.cobblemon.mod.common.client.net.storage.party.MoveClientPartyPokemonHandler
import com.cobblemon.mod.common.client.net.storage.party.SetPartyPokemonHandler
import com.cobblemon.mod.common.client.net.storage.party.SetPartyReferenceHandler
import com.cobblemon.mod.common.client.net.storage.pc.ClosePCHandler
import com.cobblemon.mod.common.client.net.storage.pc.InitializePCHandler
import com.cobblemon.mod.common.client.net.storage.pc.MoveClientPCPokemonHandler
import com.cobblemon.mod.common.client.net.storage.pc.OpenPCHandler
import com.cobblemon.mod.common.client.net.storage.pc.SetPCBoxPokemonHandler
import com.cobblemon.mod.common.client.net.storage.pc.SetPCPokemonHandler
import com.cobblemon.mod.common.client.net.toast.ToastPacketHandler
import com.cobblemon.mod.common.client.net.trade.TradeAcceptanceChangedHandler
import com.cobblemon.mod.common.client.net.trade.TradeCancelledHandler
import com.cobblemon.mod.common.client.net.trade.TradeCompletedHandler
import com.cobblemon.mod.common.client.net.trade.TradeOfferExpiredHandler
import com.cobblemon.mod.common.client.net.trade.TradeOfferNotificationHandler
import com.cobblemon.mod.common.client.net.trade.TradeStartedHandler
import com.cobblemon.mod.common.client.net.trade.TradeUpdatedHandler
import com.cobblemon.mod.common.net.messages.client.PlayerInteractOptionsPacket
import com.cobblemon.mod.common.net.messages.client.animation.PlayPoseableAnimationPacket
import com.cobblemon.mod.common.net.messages.client.battle.*
import com.cobblemon.mod.common.net.messages.client.callback.OpenMoveCallbackPacket
import com.cobblemon.mod.common.net.messages.client.callback.OpenPartyCallbackPacket
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.GlobalSpeciesFeatureSyncPacket
import com.cobblemon.mod.common.net.messages.client.data.MovesRegistrySyncPacket
import com.cobblemon.mod.common.net.PacketHandler
import com.cobblemon.mod.common.net.messages.client.battle.BattleApplyCaptureResponsePacket
import com.cobblemon.mod.common.net.messages.client.battle.BattleCaptureEndPacket
import com.cobblemon.mod.common.net.messages.client.battle.BattleCaptureShakePacket
import com.cobblemon.mod.common.net.messages.client.battle.BattleCaptureStartPacket
import com.cobblemon.mod.common.net.messages.client.battle.BattleEndPacket
import com.cobblemon.mod.common.net.messages.client.battle.BattleFaintPacket
import com.cobblemon.mod.common.net.messages.client.battle.BattleHealthChangePacket
import com.cobblemon.mod.common.net.messages.client.battle.BattleInitializePacket
import com.cobblemon.mod.common.net.messages.client.battle.BattleMakeChoicePacket
import com.cobblemon.mod.common.net.messages.client.battle.BattleMessagePacket
import com.cobblemon.mod.common.net.messages.client.battle.BattleQueueRequestPacket
import com.cobblemon.mod.common.net.messages.client.battle.BattleSetTeamPokemonPacket
import com.cobblemon.mod.common.net.messages.client.battle.BattleSwitchPokemonPacket
import com.cobblemon.mod.common.net.messages.client.battle.BattleUpdateTeamPokemonPacket
import com.cobblemon.mod.common.net.messages.client.battle.ChallengeNotificationPacket
import com.cobblemon.mod.common.net.messages.client.data.*
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.dialogue.DialogueClosedPacket
import com.cobblemon.mod.common.net.messages.client.dialogue.DialogueOpenedPacket
import com.cobblemon.mod.common.net.messages.client.effect.RunPosableMoLangPacket
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormEntityParticlePacket
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.pasture.ClosePasturePacket
import com.cobblemon.mod.common.net.messages.client.pasture.OpenPasturePacket
import com.cobblemon.mod.common.net.messages.client.pasture.PokemonPasturedPacket
import com.cobblemon.mod.common.net.messages.client.pasture.PokemonUnpasturedPacket
import com.cobblemon.mod.common.net.messages.client.pokemon.update.*
import com.cobblemon.mod.common.net.messages.client.pokemon.update.evolution.AddEvolutionPacket
import com.cobblemon.mod.common.net.messages.client.pokemon.update.evolution.ClearEvolutionsPacket
import com.cobblemon.mod.common.net.messages.client.pokemon.update.evolution.RemoveEvolutionPacket
import com.cobblemon.mod.common.net.messages.client.settings.ServerSettingsPacket
import com.cobblemon.mod.common.net.messages.client.sound.UnvalidatedPlaySoundS2CPacket
import com.cobblemon.mod.common.net.messages.client.spawn.SpawnGenericBedrockPacket
import com.cobblemon.mod.common.net.messages.client.spawn.SpawnPokeballPacket
import com.cobblemon.mod.common.net.messages.client.spawn.SpawnPokemonPacket
import com.cobblemon.mod.common.net.messages.client.starter.OpenStarterUIPacket
import com.cobblemon.mod.common.net.messages.client.starter.SetClientPlayerDataPacket
import com.cobblemon.mod.common.net.messages.client.storage.RemoveClientPokemonPacket
@@ -105,353 +51,203 @@ import com.cobblemon.mod.common.net.messages.client.storage.pc.MoveClientPCPokem
import com.cobblemon.mod.common.net.messages.client.storage.pc.OpenPCPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.SetPCBoxPokemonPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.SetPCPokemonPacket
import com.cobblemon.mod.common.net.messages.client.toast.ToastPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeAcceptanceChangedPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeCancelledPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeCompletedPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeOfferExpiredPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeOfferNotificationPacket
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.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
import com.cobblemon.mod.common.net.messages.server.callback.move.MoveSelectCancelledPacket
import com.cobblemon.mod.common.net.messages.server.callback.move.MoveSelectedPacket
import com.cobblemon.mod.common.net.messages.server.callback.party.PartyPokemonSelectedPacket
import com.cobblemon.mod.common.net.messages.server.callback.party.PartySelectCancelledPacket
import com.cobblemon.mod.common.net.messages.server.callback.partymove.PartyMoveSelectCancelledPacket
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.pasture.PasturePokemonPacket
import com.cobblemon.mod.common.net.messages.server.pasture.UnpastureAllPokemonPacket
import com.cobblemon.mod.common.net.messages.server.pasture.UnpasturePokemonPacket
import com.cobblemon.mod.common.net.messages.server.pokemon.interact.InteractPokemonPacket
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetNicknamePacket
import com.cobblemon.mod.common.net.messages.server.pokemon.update.evolution.AcceptEvolutionPacket
import com.cobblemon.mod.common.net.messages.server.starter.RequestStarterScreenPacket
import com.cobblemon.mod.common.net.messages.server.storage.SwapPCPartyPokemonPacket
import com.cobblemon.mod.common.net.messages.server.storage.party.MovePartyPokemonPacket
import com.cobblemon.mod.common.net.messages.server.storage.party.ReleasePartyPokemonPacket
import com.cobblemon.mod.common.net.messages.server.storage.party.SwapPartyPokemonPacket
import com.cobblemon.mod.common.net.messages.server.storage.pc.MovePCPokemonPacket
import com.cobblemon.mod.common.net.messages.server.storage.pc.MovePCPokemonToPartyPacket
import com.cobblemon.mod.common.net.messages.server.storage.pc.MovePartyPokemonToPCPacket
import com.cobblemon.mod.common.net.messages.server.storage.pc.ReleasePCPokemonPacket
import com.cobblemon.mod.common.net.messages.server.storage.pc.SwapPCPokemonPacket
import com.cobblemon.mod.common.net.messages.server.storage.pc.UnlinkPlayerFromPCPacket
import com.cobblemon.mod.common.net.messages.server.trade.AcceptTradeRequestPacket
import com.cobblemon.mod.common.net.messages.server.trade.CancelTradePacket
import com.cobblemon.mod.common.net.messages.server.trade.ChangeTradeAcceptancePacket
import com.cobblemon.mod.common.net.messages.server.trade.OfferTradePacket
import com.cobblemon.mod.common.net.messages.server.trade.UpdateTradeOfferPacket
import com.cobblemon.mod.common.net.serverhandling.ChallengeHandler
import com.cobblemon.mod.common.net.serverhandling.RequestInteractionsHandler
import com.cobblemon.mod.common.net.serverhandling.battle.BattleSelectActionsHandler
import com.cobblemon.mod.common.net.serverhandling.battle.RemoveSpectatorHandler
import com.cobblemon.mod.common.net.serverhandling.battle.SpectateBattleHandler
import com.cobblemon.mod.common.net.serverhandling.callback.move.MoveSelectCancelledHandler
import com.cobblemon.mod.common.net.serverhandling.callback.move.MoveSelectedHandler
import com.cobblemon.mod.common.net.serverhandling.callback.party.PartyPokemonSelectedHandler
import com.cobblemon.mod.common.net.serverhandling.callback.party.PartySelectCancelledHandler
import com.cobblemon.mod.common.net.serverhandling.callback.partymove.PartyMoveSelectCancelledHandler
import com.cobblemon.mod.common.net.serverhandling.callback.partymove.PartyPokemonMoveSelectedHandler
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.pasture.PasturePokemonHandler
import com.cobblemon.mod.common.net.serverhandling.pasture.UnpastureAllPokemonHandler
import com.cobblemon.mod.common.net.serverhandling.pasture.UnpasturePokemonHandler
import com.cobblemon.mod.common.net.serverhandling.pokemon.interact.InteractPokemonHandler
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetNicknameHandler
import com.cobblemon.mod.common.net.serverhandling.starter.RequestStarterScreenHandler
import com.cobblemon.mod.common.net.serverhandling.starter.SelectStarterPacketHandler
import com.cobblemon.mod.common.net.serverhandling.storage.BenchMoveHandler
import com.cobblemon.mod.common.net.serverhandling.storage.RequestMoveSwapHandler
import com.cobblemon.mod.common.net.serverhandling.storage.SendOutPokemonHandler
import com.cobblemon.mod.common.net.serverhandling.storage.SwapPCPartyPokemonHandler
import com.cobblemon.mod.common.net.serverhandling.storage.party.MovePartyPokemonHandler
import com.cobblemon.mod.common.net.serverhandling.storage.party.ReleasePCPokemonHandler
import com.cobblemon.mod.common.net.serverhandling.storage.party.SwapPartyPokemonHandler
import com.cobblemon.mod.common.net.serverhandling.storage.pc.MovePCPokemonHandler
import com.cobblemon.mod.common.net.serverhandling.storage.pc.MovePCPokemonToPartyHandler
import com.cobblemon.mod.common.net.serverhandling.storage.pc.MovePartyPokemonToPCHandler
import com.cobblemon.mod.common.net.serverhandling.storage.pc.ReleasePartyPokemonHandler
import com.cobblemon.mod.common.net.serverhandling.storage.pc.SwapPCPokemonHandler
import com.cobblemon.mod.common.net.serverhandling.storage.pc.UnlinkPlayerFromPCHandler
import com.cobblemon.mod.common.net.serverhandling.trade.AcceptTradeRequestHandler
import com.cobblemon.mod.common.net.serverhandling.trade.CancelTradeHandler
import com.cobblemon.mod.common.net.serverhandling.trade.ChangeTradeAcceptanceHandler
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 net.minecraft.network.PacketByteBuf
import net.minecraft.network.listener.ClientPlayPacketListener
import net.minecraft.network.packet.Packet
import com.cobblemon.mod.common.net.messages.server.storage.pc.*
import com.cobblemon.mod.common.util.getServer
import java.util.concurrent.CompletableFuture
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.util.Identifier
import kotlin.reflect.KClass
/**
* Registers Cobblemon network packets.
* Registers Cobblemon packets. Packet handlers are set up on handling the [MessageBuiltEvent] dispatched from here.
*
* This class also contains short functions for dispatching our packets to a player, all players, or to the entire server.
*
* @author Hiroku, Licious
* @author Hiroku
* @since November 27th, 2021
*/
object CobblemonNetwork : NetworkManager {
object CobblemonNetwork {
const val PROTOCOL_VERSION = "1"
fun ServerPlayerEntity.sendPacket(packet: NetworkPacket<*>) = sendPacketToPlayer(this, packet)
fun sendToServer(packet: NetworkPacket<*>) = this.sendPacketToServer(packet)
fun sendToAllPlayers(packet: NetworkPacket<*>) = sendPacketToPlayers(server()!!.playerManager.playerList, packet)
fun sendPacketToPlayers(players: Iterable<ServerPlayerEntity>, packet: NetworkPacket<*>) = players.forEach { sendPacketToPlayer(it, packet) }
var clientHandlersRegistered = CompletableFuture<Unit>()
var serverHandlersRegistered = CompletableFuture<Unit>()
init {
clientHandlersRegistered.runAfterBoth(serverHandlersRegistered) { register() }
}
lateinit var networkDelegate: NetworkDelegate
fun ServerPlayerEntity.sendPacket(packet: NetworkPacket) = sendToPlayer(this, packet)
fun sendToPlayer(player: ServerPlayerEntity, packet: NetworkPacket) = networkDelegate.sendPacketToPlayer(player, packet)
fun sendToServer(packet: NetworkPacket) = networkDelegate.sendPacketToServer(packet)
fun sendToAllPlayers(packet: NetworkPacket) = sendToPlayers(getServer()!!.playerManager.playerList, packet)
fun sendToPlayers(players: Iterable<ServerPlayerEntity>, packet: NetworkPacket) = players.forEach { sendToPlayer(it, packet) }
interface PreparedMessage<T : NetworkPacket> {
fun registerMessage()
fun registerHandler(handler: PacketHandler<T>)
}
interface NetworkContext {
val player: ServerPlayerEntity?
}
fun register() {
// Don't forget to register handlers in either ClientPacketRegistrar or ServerPacketRegistrar!
/**
* Client Packets
*/
override fun registerClientBound() {
// Pokemon Update Packets
this.createClientBound(FriendshipUpdatePacket.ID, FriendshipUpdatePacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(MoveSetUpdatePacket.ID, MoveSetUpdatePacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(NatureUpdatePacket.ID, NatureUpdatePacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(ShinyUpdatePacket.ID, ShinyUpdatePacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(SpeciesUpdatePacket.ID, SpeciesUpdatePacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(NicknameUpdatePacket.ID, NicknameUpdatePacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(HealthUpdatePacket.ID, HealthUpdatePacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(ExperienceUpdatePacket.ID, ExperienceUpdatePacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(StatusUpdatePacket.ID, StatusUpdatePacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(CaughtBallUpdatePacket.ID, CaughtBallUpdatePacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(BenchedMovesUpdatePacket.ID, BenchedMovesUpdatePacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(GenderUpdatePacket.ID, GenderUpdatePacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(AspectsUpdatePacket.ID, AspectsUpdatePacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(AbilityUpdatePacket.ID, AbilityUpdatePacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(EVsUpdatePacket.ID, EVsUpdatePacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(IVsUpdatePacket.ID, IVsUpdatePacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(HeldItemUpdatePacket.ID, HeldItemUpdatePacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(PokemonStateUpdatePacket.ID, PokemonStateUpdatePacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(TetheringUpdatePacket.ID, TetheringUpdatePacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(TradeableUpdatePacket.ID, TradeableUpdatePacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(SpeciesFeatureUpdatePacket.ID, SpeciesFeatureUpdatePacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(OriginalTrainerUpdatePacket.ID, OriginalTrainerUpdatePacket::decode, PokemonUpdatePacketHandler())
buildClientMessage<FriendshipUpdatePacket>()
buildClientMessage<MoveSetUpdatePacket>()
buildClientMessage<NatureUpdatePacket>()
buildClientMessage<ShinyUpdatePacket>()
buildClientMessage<SpeciesUpdatePacket>()
buildClientMessage<HealthUpdatePacket>()
buildClientMessage<ExperienceUpdatePacket>()
buildClientMessage<StatusUpdatePacket>()
buildClientMessage<CaughtBallUpdatePacket>()
buildClientMessage<BenchedMovesUpdatePacket>()
buildClientMessage<GenderUpdatePacket>()
buildClientMessage<AspectsUpdatePacket>()
buildClientMessage<AbilityUpdatePacket>()
buildClientMessage<EVsUpdatePacket>()
buildClientMessage<IVsUpdatePacket>()
buildClientMessage<HeldItemUpdatePacket>()
// Evolution start
this.createClientBound(AddEvolutionPacket.ID, AddEvolutionPacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(ClearEvolutionsPacket.ID, ClearEvolutionsPacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(RemoveEvolutionPacket.ID, RemoveEvolutionPacket::decode, PokemonUpdatePacketHandler())
buildClientMessage<AddEvolutionPacket>()
buildClientMessage<ClearEvolutionsPacket>()
buildClientMessage<RemoveEvolutionPacket>()
// Evolution End
buildClientMessage<PokemonStateUpdatePacket>()
// Storage Packets
this.createClientBound(InitializePartyPacket.ID, InitializePartyPacket::decode, InitializePartyHandler)
this.createClientBound(SetPartyPokemonPacket.ID, SetPartyPokemonPacket::decode, SetPartyPokemonHandler)
this.createClientBound(MoveClientPartyPokemonPacket.ID, MoveClientPartyPokemonPacket::decode, MoveClientPartyPokemonHandler)
this.createClientBound(SetPartyReferencePacket.ID, SetPartyReferencePacket::decode, SetPartyReferenceHandler)
buildClientMessage<InitializePartyPacket>()
buildClientMessage<SetPartyPokemonPacket>()
buildClientMessage<MoveClientPartyPokemonPacket>()
buildClientMessage<SetPartyReferencePacket>()
this.createClientBound(InitializePCPacket.ID, InitializePCPacket::decode, InitializePCHandler)
this.createClientBound(MoveClientPCPokemonPacket.ID, MoveClientPCPokemonPacket::decode, MoveClientPCPokemonHandler)
this.createClientBound(SetPCBoxPokemonPacket.ID, SetPCBoxPokemonPacket::decode, SetPCBoxPokemonHandler)
this.createClientBound(SetPCPokemonPacket.ID, SetPCPokemonPacket::decode, SetPCPokemonHandler)
this.createClientBound(OpenPCPacket.ID, OpenPCPacket::decode, OpenPCHandler)
this.createClientBound(ClosePCPacket.ID, ClosePCPacket::decode, ClosePCHandler)
buildClientMessage<InitializePCPacket>()
buildClientMessage<MoveClientPCPokemonPacket>()
buildClientMessage<SetPCBoxPokemonPacket>()
buildClientMessage<SetPCPokemonPacket>()
buildClientMessage<OpenPCPacket>()
buildClientMessage<ClosePCPacket>()
this.createClientBound(SwapClientPokemonPacket.ID, SwapClientPokemonPacket::decode, SwapClientPokemonHandler)
this.createClientBound(RemoveClientPokemonPacket.ID, RemoveClientPokemonPacket::decode, RemoveClientPokemonHandler)
buildClientMessage<SwapClientPokemonPacket>()
buildClientMessage<RemoveClientPokemonPacket>()
// UI Packets
this.createClientBound(SummaryUIPacket.ID, SummaryUIPacket::decode, SummaryUIPacketHandler)
this.createClientBound(InteractPokemonUIPacket.ID, InteractPokemonUIPacket::decode, InteractPokemonUIPacketHandler)
this.createClientBound(PlayerInteractOptionsPacket.ID, PlayerInteractOptionsPacket::decode, PlayerInteractOptionsHandler)
buildClientMessage<SummaryUIPacket>()
buildClientMessage<InteractPokemonUIPacket>()
// Starter packets
this.createClientBound(OpenStarterUIPacket.ID, OpenStarterUIPacket::decode, StarterUIPacketHandler)
this.createClientBound(SetClientPlayerDataPacket.ID, SetClientPlayerDataPacket::decode, SetClientPlayerDataHandler)
buildClientMessage<OpenStarterUIPacket>()
buildClientMessage<SetClientPlayerDataPacket>()
// Battle packets
this.createClientBound(BattleEndPacket.ID, BattleEndPacket::decode, BattleEndHandler)
this.createClientBound(BattleInitializePacket.ID, BattleInitializePacket::decode, BattleInitializeHandler)
this.createClientBound(BattleQueueRequestPacket.ID, BattleQueueRequestPacket::decode, BattleQueueRequestHandler)
this.createClientBound(BattleFaintPacket.ID, BattleFaintPacket::decode, BattleFaintHandler)
this.createClientBound(BattleMakeChoicePacket.ID, BattleMakeChoicePacket::decode, BattleMakeChoiceHandler)
this.createClientBound(BattleHealthChangePacket.ID, BattleHealthChangePacket::decode, BattleHealthChangeHandler)
this.createClientBound(BattleSetTeamPokemonPacket.ID, BattleSetTeamPokemonPacket::decode, BattleSetTeamPokemonHandler)
this.createClientBound(BattleSwitchPokemonPacket.ID, BattleSwitchPokemonPacket::decode, BattleSwitchPokemonHandler)
this.createClientBound(BattleMessagePacket.ID, BattleMessagePacket::decode, BattleMessageHandler)
this.createClientBound(BattleCaptureStartPacket.ID, BattleCaptureStartPacket::decode, BattleCaptureStartHandler)
this.createClientBound(BattleCaptureEndPacket.ID, BattleCaptureEndPacket::decode, BattleCaptureEndHandler)
this.createClientBound(BattleCaptureShakePacket.ID, BattleCaptureShakePacket::decode, BattleCaptureShakeHandler)
this.createClientBound(BattleApplyPassResponsePacket.ID, BattleApplyPassResponsePacket::decode, BattleApplyPassResponseHandler)
this.createClientBound(BattleChallengeNotificationPacket.ID, BattleChallengeNotificationPacket::decode, BattleChallengeNotificationHandler)
this.createClientBound(BattleUpdateTeamPokemonPacket.ID, BattleUpdateTeamPokemonPacket::decode, BattleUpdateTeamPokemonHandler)
this.createClientBound(BattlePersistentStatusPacket.ID, BattlePersistentStatusPacket::decode, BattlePersistentStatusHandler)
this.createClientBound(BattleMadeInvalidChoicePacket.ID, BattleMadeInvalidChoicePacket::decode, BattleMadeInvalidChoiceHandler)
this.createClientBound(BattleMusicPacket.ID, BattleMusicPacket::decode, BattleMusicHandler)
this.createClientBound(BattleChallengeExpiredPacket.ID, BattleChallengeExpiredPacket::decode, BattleChallengeExpiredHandler)
this.createClientBound(BattleReplacePokemonPacket.ID, BattleReplacePokemonPacket::decode, BattleReplacePokemonHandler)
this.createClientBound(BattleTransformPokemonPacket.ID, BattleTransformPokemonPacket::decode, BattleTransformPokemonHandler)
buildClientMessage<BattleEndPacket>()
buildClientMessage<BattleInitializePacket>()
buildClientMessage<BattleQueueRequestPacket>()
buildClientMessage<BattleFaintPacket>()
buildClientMessage<BattleMakeChoicePacket>()
buildClientMessage<BattleHealthChangePacket>()
buildClientMessage<BattleSetTeamPokemonPacket>()
buildClientMessage<BattleSwitchPokemonPacket>()
buildClientMessage<BattleMessagePacket>()
buildClientMessage<BattleCaptureStartPacket>()
buildClientMessage<BattleCaptureEndPacket>()
buildClientMessage<BattleCaptureShakePacket>()
buildClientMessage<BattleApplyCaptureResponsePacket>()
buildClientMessage<ChallengeNotificationPacket>()
buildClientMessage<BattleUpdateTeamPokemonPacket>()
buildClientMessage<BattlePersistentStatusPacket>()
// Settings packets
this.createClientBound(ServerSettingsPacket.ID, ServerSettingsPacket::decode, ServerSettingsPacketHandler)
buildClientMessage<ServerSettingsPacket>()
// Data registries
this.createClientBound(AbilityRegistrySyncPacket.ID, AbilityRegistrySyncPacket::decode, DataRegistrySyncPacketHandler())
this.createClientBound(MovesRegistrySyncPacket.ID, MovesRegistrySyncPacket::decode, DataRegistrySyncPacketHandler())
this.createClientBound(SpeciesRegistrySyncPacket.ID, SpeciesRegistrySyncPacket::decode, DataRegistrySyncPacketHandler())
this.createClientBound(PropertiesCompletionRegistrySyncPacket.ID, PropertiesCompletionRegistrySyncPacket::decode, DataRegistrySyncPacketHandler())
this.createClientBound(UnlockReloadPacket.ID, UnlockReloadPacket::decode, UnlockReloadPacketHandler)
this.createClientBound(BerryRegistrySyncPacket.ID, BerryRegistrySyncPacket::decode, DataRegistrySyncPacketHandler())
this.createClientBound(StandardSpeciesFeatureSyncPacket.ID, StandardSpeciesFeatureSyncPacket::decode, DataRegistrySyncPacketHandler())
this.createClientBound(GlobalSpeciesFeatureSyncPacket.ID, GlobalSpeciesFeatureSyncPacket::decode, DataRegistrySyncPacketHandler())
this.createClientBound(SpeciesFeatureAssignmentSyncPacket.ID, SpeciesFeatureAssignmentSyncPacket::decode, DataRegistrySyncPacketHandler())
this.createClientBound(NaturalMaterialRegistrySyncPacket.ID, NaturalMaterialRegistrySyncPacket::decode, DataRegistrySyncPacketHandler())
this.createClientBound(FossilRegistrySyncPacket.ID, FossilRegistrySyncPacket::decode, DataRegistrySyncPacketHandler())
buildClientMessage<UnlockReloadPacket>()
buildClientMessage<AbilityRegistrySyncPacket>()
buildClientMessage<MovesRegistrySyncPacket>()
buildClientMessage<SpeciesRegistrySyncPacket>()
buildClientMessage<PropertiesCompletionRegistrySyncPacket>()
// Effects
this.createClientBound(SpawnSnowstormParticlePacket.ID, SpawnSnowstormParticlePacket::decode, SpawnSnowstormParticleHandler)
this.createClientBound(SpawnSnowstormEntityParticlePacket.ID, SpawnSnowstormEntityParticlePacket::decode, SpawnSnowstormEntityParticleHandler)
this.createClientBound(RunPosableMoLangPacket.ID, RunPosableMoLangPacket::decode, RunPosableMoLangHandler)
buildClientMessage<SpawnSnowstormParticlePacket>()
// Hax
this.createClientBound(UnvalidatedPlaySoundS2CPacket.ID, UnvalidatedPlaySoundS2CPacket::decode, UnvalidatedPlaySoundS2CPacketHandler)
this.createClientBound(SpawnPokemonPacket.ID, SpawnPokemonPacket::decode, SpawnExtraDataEntityHandler())
this.createClientBound(SpawnPokeballPacket.ID, SpawnPokeballPacket::decode, SpawnExtraDataEntityHandler())
this.createClientBound(ToastPacket.ID, ToastPacket::decode, ToastPacketHandler)
this.createClientBound(SpawnGenericBedrockPacket.ID, SpawnGenericBedrockPacket::decode, SpawnExtraDataEntityHandler())
buildClientMessage<UnvalidatedPlaySoundS2CPacket>()
// Trade packets
this.createClientBound(TradeAcceptanceChangedPacket.ID, TradeAcceptanceChangedPacket::decode, TradeAcceptanceChangedHandler)
this.createClientBound(TradeCancelledPacket.ID, TradeCancelledPacket::decode, TradeCancelledHandler)
this.createClientBound(TradeCompletedPacket.ID, TradeCompletedPacket::decode, TradeCompletedHandler)
this.createClientBound(TradeUpdatedPacket.ID, TradeUpdatedPacket::decode, TradeUpdatedHandler)
this.createClientBound(TradeOfferNotificationPacket.ID, TradeOfferNotificationPacket::decode, TradeOfferNotificationHandler)
this.createClientBound(TradeOfferExpiredPacket.ID, TradeOfferExpiredPacket::decode, TradeOfferExpiredHandler)
this.createClientBound(TradeStartedPacket.ID, TradeStartedPacket::decode, TradeStartedHandler)
/**
* Server Packets
*/
// Pasture
this.createClientBound(OpenPasturePacket.ID, OpenPasturePacket::decode, OpenPastureHandler)
this.createClientBound(ClosePasturePacket.ID, ClosePasturePacket::decode, ClosePastureHandler)
this.createClientBound(PokemonPasturedPacket.ID, PokemonPasturedPacket::decode, PokemonPasturedHandler)
this.createClientBound(PokemonUnpasturedPacket.ID, PokemonUnpasturedPacket::decode, PokemonUnpasturedHandler)
// Behaviours
this.createClientBound(PlayPoseableAnimationPacket.ID, PlayPoseableAnimationPacket::decode, PlayPoseableAnimationHandler)
// Move select packets
this.createClientBound(OpenMoveCallbackPacket.ID, OpenMoveCallbackPacket::decode, OpenMoveCallbackHandler)
// Party select packets
this.createClientBound(OpenPartyCallbackPacket.ID, OpenPartyCallbackPacket::decode, OpenPartyCallbackHandler)
// Party move select packets
this.createClientBound(OpenPartyMoveCallbackPacket.ID, OpenPartyMoveCallbackPacket::decode, OpenPartyMoveCallbackHandler)
// Dialogue packets
this.createClientBound(DialogueClosedPacket.ID, DialogueClosedPacket::decode, DialogueClosedHandler)
this.createClientBound(DialogueOpenedPacket.ID, DialogueOpenedPacket::decode, DialogueOpenedHandler)
}
override fun registerServerBound() {
// Pokemon Update Packets
this.createServerBound(SetNicknamePacket.ID, SetNicknamePacket::decode, SetNicknameHandler)
// Evolution Packets
this.createServerBound(AcceptEvolutionPacket.ID, AcceptEvolutionPacket::decode, AcceptEvolutionHandler)
// Evolution start
buildServerMessage<AcceptEvolutionPacket>()
// Evolution End
// Interaction Packets
this.createServerBound(InteractPokemonPacket.ID, InteractPokemonPacket::decode, InteractPokemonHandler)
this.createServerBound(RequestPlayerInteractionsPacket.ID, RequestPlayerInteractionsPacket::decode, RequestInteractionsHandler)
buildServerMessage<InteractPokemonPacket>()
// Storage Packets
this.createServerBound(SendOutPokemonPacket.ID, SendOutPokemonPacket::decode, SendOutPokemonHandler)
this.createServerBound(RequestMoveSwapPacket.ID, RequestMoveSwapPacket::decode, RequestMoveSwapHandler)
this.createServerBound(BenchMovePacket.ID, BenchMovePacket::decode, BenchMoveHandler)
this.createServerBound(BattleChallengePacket.ID, BattleChallengePacket::decode, ChallengeHandler)
buildServerMessage<SendOutPokemonPacket>()
buildServerMessage<RequestMoveSwapPacket>()
buildServerMessage<BenchMovePacket>()
buildServerMessage<BattleChallengePacket>()
this.createServerBound(MovePCPokemonToPartyPacket.ID, MovePCPokemonToPartyPacket::decode, MovePCPokemonToPartyHandler)
this.createServerBound(MovePartyPokemonToPCPacket.ID, MovePartyPokemonToPCPacket::decode, MovePartyPokemonToPCHandler)
this.createServerBound(ReleasePartyPokemonPacket.ID, ReleasePartyPokemonPacket::decode, ReleasePartyPokemonHandler)
this.createServerBound(ReleasePCPokemonPacket.ID, ReleasePCPokemonPacket::decode, ReleasePCPokemonHandler)
this.createServerBound(UnlinkPlayerFromPCPacket.ID, UnlinkPlayerFromPCPacket::decode, UnlinkPlayerFromPCHandler)
buildServerMessage<MovePCPokemonToPartyPacket>()
buildServerMessage<MovePartyPokemonToPCPacket>()
buildServerMessage<ReleasePartyPokemonPacket>()
buildServerMessage<ReleasePCPokemonPacket>()
buildServerMessage<UnlinkPlayerFromPCPacket>()
// Starter packets
this.createServerBound(SelectStarterPacket.ID, SelectStarterPacket::decode, SelectStarterPacketHandler)
this.createServerBound(RequestStarterScreenPacket.ID, RequestStarterScreenPacket::decode, RequestStarterScreenHandler)
buildServerMessage<SelectStarterPacket>()
buildServerMessage<RequestStarterScreenPacket>()
this.createServerBound(SwapPCPokemonPacket.ID, SwapPCPokemonPacket::decode, SwapPCPokemonHandler)
this.createServerBound(SwapPartyPokemonPacket.ID, SwapPartyPokemonPacket::decode, SwapPartyPokemonHandler)
buildServerMessage<SwapPCPokemonPacket>()
buildServerMessage<SwapPartyPokemonPacket>()
this.createServerBound(MovePCPokemonPacket.ID, MovePCPokemonPacket::decode, MovePCPokemonHandler)
this.createServerBound(MovePartyPokemonPacket.ID, MovePartyPokemonPacket::decode, MovePartyPokemonHandler)
buildServerMessage<MovePCPokemonPacket>()
buildServerMessage<MovePartyPokemonPacket>()
this.createServerBound(SwapPCPartyPokemonPacket.ID, SwapPCPartyPokemonPacket::decode, SwapPCPartyPokemonHandler)
buildServerMessage<SwapPCPartyPokemonPacket>()
// Battle packets
this.createServerBound(BattleSelectActionsPacket.ID, BattleSelectActionsPacket::decode, BattleSelectActionsHandler)
this.createServerBound(SpectateBattlePacket.ID, SpectateBattlePacket::decode, SpectateBattleHandler)
this.createServerBound(RemoveSpectatorPacket.ID, RemoveSpectatorPacket::decode, RemoveSpectatorHandler)
// Trade
this.createServerBound(AcceptTradeRequestPacket.ID, AcceptTradeRequestPacket::decode, AcceptTradeRequestHandler)
this.createServerBound(CancelTradePacket.ID, CancelTradePacket::decode, CancelTradeHandler)
this.createServerBound(ChangeTradeAcceptancePacket.ID, ChangeTradeAcceptancePacket::decode, ChangeTradeAcceptanceHandler)
this.createServerBound(OfferTradePacket.ID, OfferTradePacket::decode, OfferTradeHandler)
this.createServerBound(UpdateTradeOfferPacket.ID, UpdateTradeOfferPacket::decode, UpdateTradeOfferHandler)
// Pasture
this.createServerBound(PasturePokemonPacket.ID, PasturePokemonPacket::decode, PasturePokemonHandler)
this.createServerBound(UnpasturePokemonPacket.ID, UnpasturePokemonPacket::decode, UnpasturePokemonHandler)
this.createServerBound(UnpastureAllPokemonPacket.ID, UnpastureAllPokemonPacket::decode, UnpastureAllPokemonHandler)
// Move select packets
this.createServerBound(MoveSelectedPacket.ID, MoveSelectedPacket::decode, MoveSelectedHandler)
this.createServerBound(MoveSelectCancelledPacket.ID, MoveSelectCancelledPacket::decode, MoveSelectCancelledHandler)
// Party select packets
this.createServerBound(PartyPokemonSelectedPacket.ID, PartyPokemonSelectedPacket::decode, PartyPokemonSelectedHandler)
this.createServerBound(PartySelectCancelledPacket.ID, PartySelectCancelledPacket::decode, PartySelectCancelledHandler)
// Party move select packets
this.createServerBound(PartyPokemonMoveSelectedPacket.ID, PartyPokemonMoveSelectedPacket::decode, PartyPokemonMoveSelectedHandler)
this.createServerBound(PartyMoveSelectCancelledPacket.ID, PartyMoveSelectCancelledPacket::decode, PartyMoveSelectCancelledHandler)
// Dialogue packets
this.createServerBound(EscapeDialoguePacket.ID, EscapeDialoguePacket::decode, EscapeDialogueHandler)
this.createServerBound(InputToDialoguePacket.ID, InputToDialoguePacket::decode, InputToDialogueHandler)
buildServerMessage<BattleSelectActionsPacket>()
}
private inline fun <reified T : NetworkPacket<T>> createClientBound(identifier: Identifier, noinline decoder: (PacketByteBuf) -> T, handler: ClientNetworkPacketHandler<T>) {
Cobblemon.implementation.networkManager.createClientBound(identifier, T::class, { message, buffer -> message.encode(buffer) }, decoder, handler)
private inline fun <reified P : NetworkPacket> buildClientMessage() =
buildMessage<P>(toServer = false)
private inline fun <reified P : NetworkPacket> buildServerMessage() =
buildMessage<P>(toServer = true)
private inline fun <reified P : NetworkPacket> buildMessage(toServer: Boolean) {
val message = networkDelegate.buildMessage(P::class.java, toServer)
// Gives client or server the chance to attach its packet handler
CobblemonEvents.MESSAGE_BUILT.post(MessageBuiltEvent(P::class.java, toServer, message))
message.registerMessage()
}
private inline fun <reified T : NetworkPacket<T>> createServerBound(identifier: Identifier, noinline decoder: (PacketByteBuf) -> T, handler: ServerNetworkPacketHandler<T>) {
Cobblemon.implementation.networkManager.createServerBound(identifier, T::class, { message, buffer -> message.encode(buffer) }, decoder, handler)
}
override fun <T : NetworkPacket<T>> createClientBound(
identifier: Identifier,
kClass: KClass<T>,
encoder: (T, PacketByteBuf) -> Unit,
decoder: (PacketByteBuf) -> T,
handler: ClientNetworkPacketHandler<T>
) {
Cobblemon.implementation.networkManager.createClientBound(identifier, kClass, encoder, decoder, handler)
}
override fun <T : NetworkPacket<T>> createServerBound(
identifier: Identifier,
kClass: KClass<T>,
encoder: (T, PacketByteBuf) -> Unit,
decoder: (PacketByteBuf) -> T,
handler: ServerNetworkPacketHandler<T>
) {
Cobblemon.implementation.networkManager.createServerBound(identifier, kClass, encoder, decoder, handler)
}
override fun sendPacketToPlayer(player: ServerPlayerEntity, packet: NetworkPacket<*>) = Cobblemon.implementation.networkManager.sendPacketToPlayer(player, packet)
override fun sendPacketToServer(packet: NetworkPacket<*>) = Cobblemon.implementation.networkManager.sendPacketToServer(packet)
override fun <T : NetworkPacket<*>> asVanillaClientBound(packet: T): Packet<ClientPlayPacketListener> = Cobblemon.implementation.networkManager.asVanillaClientBound(packet)
}
@@ -0,0 +1,73 @@
/*
* 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.util.cobblemonResource
import dev.architectury.registry.level.biome.BiomeModifications
import net.minecraft.util.registry.RegistryEntry
import net.minecraft.util.registry.RegistryEntryList
import net.minecraft.world.gen.GenerationStep
import net.minecraft.world.gen.feature.ConfiguredFeatures
import net.minecraft.world.gen.feature.Feature
import net.minecraft.world.gen.feature.PlacedFeature
import net.minecraft.world.gen.feature.PlacedFeatures
import net.minecraft.world.gen.feature.SimpleRandomFeatureConfig
import net.minecraft.world.gen.feature.VegetationPlacedFeatures
import net.minecraft.world.gen.placementmodifier.RarityFilterPlacementModifier
object CobblemonPlacements {
lateinit var BLACK_APRICORN_TREE: RegistryEntry<PlacedFeature>
lateinit var BLUE_APRICORN_TREE: RegistryEntry<PlacedFeature>
lateinit var GREEN_APRICORN_TREE: RegistryEntry<PlacedFeature>
lateinit var PINK_APRICORN_TREE: RegistryEntry<PlacedFeature>
lateinit var RED_APRICORN_TREE: RegistryEntry<PlacedFeature>
lateinit var WHITE_APRICORN_TREE: RegistryEntry<PlacedFeature>
lateinit var YELLOW_APRICORN_TREE: RegistryEntry<PlacedFeature>
lateinit var APRICORN_TREES: RegistryEntry<PlacedFeature>
fun register() {
BLACK_APRICORN_TREE = PlacedFeatures.register(cobblemonResource("black_apricorn_tree").toString(), CobblemonConfiguredFeatures.BLACK_APRICORN_TREE, PlacedFeatures.wouldSurvive(
CobblemonBlocks.BLACK_APRICORN_SAPLING.get()))
BLUE_APRICORN_TREE = PlacedFeatures.register(cobblemonResource("blue_apricorn_tree").toString(), CobblemonConfiguredFeatures.BLUE_APRICORN_TREE, PlacedFeatures.wouldSurvive(
CobblemonBlocks.BLUE_APRICORN_SAPLING.get()))
GREEN_APRICORN_TREE = PlacedFeatures.register(cobblemonResource("green_apricorn_tree").toString(), CobblemonConfiguredFeatures.GREEN_APRICORN_TREE, PlacedFeatures.wouldSurvive(
CobblemonBlocks.GREEN_APRICORN_SAPLING.get()))
PINK_APRICORN_TREE = PlacedFeatures.register(cobblemonResource("pink_apricorn_tree").toString(), CobblemonConfiguredFeatures.PINK_APRICORN_TREE, PlacedFeatures.wouldSurvive(
CobblemonBlocks.PINK_APRICORN_SAPLING.get()))
RED_APRICORN_TREE = PlacedFeatures.register(cobblemonResource("red_apricorn_tree").toString(), CobblemonConfiguredFeatures.RED_APRICORN_TREE, PlacedFeatures.wouldSurvive(
CobblemonBlocks.RED_APRICORN_SAPLING.get()))
WHITE_APRICORN_TREE = PlacedFeatures.register(cobblemonResource("white_apricorn_tree").toString(), CobblemonConfiguredFeatures.WHITE_APRICORN_TREE, PlacedFeatures.wouldSurvive(
CobblemonBlocks.WHITE_APRICORN_SAPLING.get()))
YELLOW_APRICORN_TREE = PlacedFeatures.register(cobblemonResource("yellow_apricorn_tree").toString(), CobblemonConfiguredFeatures.YELLOW_APRICORN_TREE, PlacedFeatures.wouldSurvive(
CobblemonBlocks.YELLOW_APRICORN_SAPLING.get()))
val apricornTreeVariety = ConfiguredFeatures.register(
cobblemonResource("apricorn_trees").toString(), Feature.SIMPLE_RANDOM_SELECTOR, SimpleRandomFeatureConfig(
RegistryEntryList.of(
BLACK_APRICORN_TREE,
BLUE_APRICORN_TREE,
GREEN_APRICORN_TREE,
PINK_APRICORN_TREE,
RED_APRICORN_TREE,
WHITE_APRICORN_TREE,
YELLOW_APRICORN_TREE
)
)
)
APRICORN_TREES = PlacedFeatures.register(cobblemonResource("apricorn_trees").toString(), apricornTreeVariety, VegetationPlacedFeatures.modifiers(RarityFilterPlacementModifier.of(8)))
BiomeModifications.addProperties({ context -> true}, { context, properties ->
properties.generationProperties.addFeature(GenerationStep.Feature.VEGETAL_DECORATION, APRICORN_TREES)
})
}
}
@@ -8,342 +8,50 @@
package com.cobblemon.mod.common
import com.cobblemon.mod.common.platform.PlatformRegistry
import com.cobblemon.mod.common.registry.CompletableRegistry
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.registry.Registries
import net.minecraft.registry.Registry
import net.minecraft.registry.RegistryKey
import net.minecraft.registry.RegistryKeys
import net.minecraft.sound.BlockSoundGroup
import net.minecraft.sound.SoundEvent
import net.minecraft.sound.SoundEvents
import net.minecraft.util.registry.Registry
object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, RegistryKey<Registry<SoundEvent>>, SoundEvent>() {
override val registry: Registry<SoundEvent> = Registries.SOUND_EVENT
override val registryKey: RegistryKey<Registry<SoundEvent>> = RegistryKeys.SOUND_EVENT
object CobblemonSounds : CompletableRegistry<SoundEvent>(Registry.SOUND_EVENT_KEY) {
private fun queue(name: String) = queue(name) { SoundEvent(cobblemonResource(name)) }
@JvmField
val GUI_CLICK = this.create("gui.click")
val GUI_CLICK = queue("gui.click")
@JvmField
val PC_ON = this.create("pc.on")
val PC_ON = queue("pc.on")
@JvmField
val PC_OFF = this.create("pc.off")
val PC_OFF = queue("pc.off")
@JvmField
val PC_GRAB = this.create("pc.grab")
val PC_GRAB = queue("pc.grab")
@JvmField
val PC_DROP = this.create("pc.drop")
val PC_DROP = queue("pc.drop")
@JvmField
val PC_RELEASE = this.create("pc.release")
@JvmField
val PC_CLICK = this.create("pc.click")
val PC_RELEASE = queue("pc.release")
@JvmField
val HEALING_MACHINE_ACTIVE = this.create("healing_machine.active")
val HEALING_MACHINE_ACTIVE = queue("healing_machine.active")
@JvmField
val POKE_BALL_CAPTURE_STARTED = this.create("poke_ball.capture_started")
val POKE_BALL_CAPTURE_STARTED = queue("poke_ball.capture_started")
@JvmField
val POKE_BALL_CAPTURE_SUCCEEDED = this.create("poke_ball.capture_succeeded")
val POKE_BALL_CAPTURE_SUCCEEDED = queue("poke_ball.capture_succeeded")
@JvmField
val POKE_BALL_SHAKE = this.create("poke_ball.shake")
val POKE_BALL_SHAKE = queue("poke_ball.shake")
@JvmField
val POKE_BALL_OPEN = this.create("poke_ball.open")
val POKE_BALL_OPEN = queue("poke_ball.open")
@JvmField
val POKE_BALL_HIT = this.create("poke_ball.hit")
val POKE_BALL_HIT = queue("poke_ball.hit")
@JvmField
val POKE_BALL_SEND_OUT = this.create("poke_ball.send_out")
val POKE_BALL_SEND_OUT = queue("poke_ball.send_out")
@JvmField
val POKE_BALL_RECALL = this.create("poke_ball.recall")
@JvmField
val POKE_BALL_THROW = this.create("poke_ball.throw")
@JvmField
val POKE_BALL_TRAIL = this.create("poke_ball.trail")
val POKE_BALL_RECALL = queue("poke_ball.recall")
@JvmField
val ITEM_USE = this.create("item.use")
val ITEM_USE = queue("item.use")
@JvmField
val CAN_EVOLVE = this.create("pokemon.can_evolve")
val CAN_EVOLVE = queue("pokemon.can_evolve")
@JvmField
val EVOLVING = this.create("pokemon.evolving")
@JvmField
val EVOLVE = this.create("evolution.evolve")
@JvmField
val PVN_BATTLE = this.create("battle.pvn.default")
@JvmField
val PVP_BATTLE = this.create("battle.pvp.default")
@JvmField
val PVW_BATTLE = this.create("battle.pvw.default")
@JvmField
val MEDICINE_HERB_USE = this.create("medicine_herb.use")
@JvmField
val MEDICINE_LIQUID_USE = this.create("medicine_liquid.use")
@JvmField
val MEDICINE_PILLS_USE = this.create("medicine_pills.use")
@JvmField
val MEDICINE_SPRAY_USE = this.create("medicine_spray.use")
@JvmField
val MEDICINE_FEATHER_USE = this.create("medicine_feather.use")
@JvmField
val BERRY_HARVEST = this.create("berry.harvest")
@JvmField
val BERRY_EAT = this.create("berry.eat")
@JvmField
val MULCH_PLACE = this.create("mulch.place")
@JvmField
val MULCH_REMOVE = this.create("mulch.remove")
@JvmField
val FOSSIL_MACHINE_ACTIVATE = this.create("fossil_machine.activate")
@JvmField
val FOSSIL_MACHINE_ACTIVE_LOOP = this.create("fossil_machine.active_loop")
@JvmField
val FOSSIL_MACHINE_ASSEMBLE = this.create("fossil_machine.assemble")
@JvmField
val FOSSIL_MACHINE_DNA_FULL = this.create("fossil_machine.dna_full")
@JvmField
val FOSSIL_MACHINE_FINISHED = this.create("fossil_machine.finished")
@JvmField
val FOSSIL_MACHINE_INSERT_DNA = this.create("fossil_machine.insert_dna")
@JvmField
val FOSSIL_MACHINE_INSERT_DNA_SMALL = this.create("fossil_machine.insert_dna_small")
@JvmField
val FOSSIL_MACHINE_INSERT_FOSSIL = this.create("fossil_machine.insert_fossil")
@JvmField
val FOSSIL_MACHINE_RETRIEVE_FOSSIL = this.create("fossil_machine.retrieve_fossil")
@JvmField
val FOSSIL_MACHINE_RETRIEVE_POKEMON = this.create("fossil_machine.retrieve_pokemon")
@JvmField
val FOSSIL_MACHINE_UNPROTECTED = this.create("fossil_machine.unprotected")
@JvmField
val COIN_POUCH_BREAK = this.create("coin_pouch.break")
@JvmField
val COIN_POUCH_HIT = this.create("coin_pouch.hit")
@JvmField
val COIN_POUCH_STEP = this.create("coin_pouch.step")
@JvmField
val COIN_POUCH_PLACE = this.create("coin_pouch.place")
@JvmField
val TUMBLESTONE_BREAK = this.create("tumblestone.break")
@JvmField
val TUMBLESTONE_BLOCK_BREAK = this.create("tumblestone.block_break")
@JvmField
val TUMBLESTONE_HIT = this.create("tumblestone.hit")
@JvmField
val TUMBLESTONE_PLACE = this.create("tumblestone.place")
@JvmField
val TUMBLESTONE_STEP = this.create("tumblestone.step")
@JvmField
val GIMMIGHOUL_GIVE_ITEM_SMALL = this.create("gimmighoul.give_item_small")
@JvmField
val GIMMIGHOUL_REVEAL = this.create("gimmighoul.reveal")
@JvmField
val BERRY_BUSH_BREAK = this.create("berry_bush.break")
@JvmField
val BERRY_BUSH_PLACE = this.create("berry_bush.place")
@JvmField
val BIG_ROOT_BREAK = this.create("big_root.break")
@JvmField
val ENERGY_ROOT_PLACE = this.create("energy_root.place")
@JvmField
val VIVICHOKE_BREAK = this.create("vivichoke.break")
@JvmField
val VIVICHOKE_PLACE = this.create("vivichoke.place")
@JvmField
val MINT_BREAK = this.create("mint.break")
@JvmField
val MINT_PLACE = this.create("mint.place")
@JvmField
val REVIVAL_HERB_BREAK = this.create("revival_herb.break")
@JvmField
val REVIVAL_HERB_PLACE = this.create("revival_herb.place")
@JvmField
val MEDICINAL_LEEK_BREAK = this.create("medicinal_leek.break")
@JvmField
val MEDICINAL_LEEK_PLACE = this.create("medicinal_leek.plant")
@JvmField
val GILDED_CHEST_OPEN = this.create("gilded_chest.open")
@JvmField
val GILDED_CHEST_CLOSE = this.create("gilded_chest.close")
@JvmField
val GILDED_CHEST_STEP = this.create("gilded_chest.step")
@JvmField
val GILDED_CHEST_HIT = this.create("gilded_chest.hit")
@JvmField
val GILDED_CHEST_BREAK = this.create("gilded_chest.break")
@JvmField
val GILDED_CHEST_PLACE = this.create("gilded_chest.place")
@JvmField
val COIN_POUCH_SOUNDS = BlockSoundGroup(1f, 1f,
COIN_POUCH_BREAK,
COIN_POUCH_STEP,
COIN_POUCH_PLACE,
COIN_POUCH_HIT,
COIN_POUCH_STEP
)
@JvmField
val IMPACT_NORMAL = this.create("impact.normal")
@JvmField
val IMPACT_BUG = this.create("impact.bug")
@JvmField
val IMPACT_DARK = this.create("impact.dark")
@JvmField
val IMPACT_DRAGON = this.create("impact.dragon")
@JvmField
val IMPACT_ELECTRIC = this.create("impact.electric")
@JvmField
val IMPACT_FAIRY = this.create("impact.fairy")
@JvmField
val IMPACT_FIGHTING = this.create("impact.fighting")
@JvmField
val IMPACT_FIRE = this.create("impact.fire")
@JvmField
val IMPACT_FLYING = this.create("impact.flying")
@JvmField
val IMPACT_GHOST = this.create("impact.ghost")
@JvmField
val IMPACT_GRASS = this.create("impact.grass")
@JvmField
val IMPACT_GROUND = this.create("impact.ground")
@JvmField
val IMPACT_ICE = this.create("impact.ice")
@JvmField
val IMPACT_POISON = this.create("impact.poison")
@JvmField
val IMPACT_PSYCHIC = this.create("impact.psychic")
@JvmField
val IMPACT_ROCK = this.create("impact.rock")
@JvmField
val IMPACT_STEEL = this.create("impact.steel")
@JvmField
val IMPACT_WATER = this.create("impact.water")
@JvmField
val TUMBLESTONE_SOUNDS = BlockSoundGroup(1f, 1f,
TUMBLESTONE_BREAK,
TUMBLESTONE_STEP,
TUMBLESTONE_PLACE,
TUMBLESTONE_HIT,
TUMBLESTONE_STEP
)
@JvmField
val TUMBLESTONE_BLOCK_SOUNDS = BlockSoundGroup(1f, 1f,
TUMBLESTONE_BLOCK_BREAK,
TUMBLESTONE_STEP,
TUMBLESTONE_PLACE,
TUMBLESTONE_HIT,
TUMBLESTONE_STEP
)
@JvmField
val BERRY_BUSH_SOUNDS = BlockSoundGroup(1f, 1f,
BERRY_BUSH_BREAK,
SoundEvents.BLOCK_GRASS_STEP,
BERRY_BUSH_PLACE,
SoundEvents.BLOCK_GRASS_HIT,
SoundEvents.BLOCK_GRASS_STEP
)
@JvmField
val BIG_ROOT_SOUNDS = BlockSoundGroup(1f, 1f,
BIG_ROOT_BREAK,
SoundEvents.BLOCK_ROOTS_STEP,
SoundEvents.BLOCK_ROOTS_PLACE,
SoundEvents.BLOCK_ROOTS_HIT,
SoundEvents.BLOCK_ROOTS_FALL
)
@JvmField
val ENERGY_ROOT_SOUNDS = BlockSoundGroup(1f, 1f,
SoundEvents.BLOCK_ROOTS_BREAK,
SoundEvents.BLOCK_ROOTS_STEP,
ENERGY_ROOT_PLACE,
SoundEvents.BLOCK_ROOTS_HIT,
SoundEvents.BLOCK_ROOTS_FALL
)
@JvmField
val MEDICINAL_LEEK_SOUNDS = BlockSoundGroup(1f, 1f,
MEDICINAL_LEEK_BREAK,
SoundEvents.BLOCK_GRASS_STEP,
MEDICINAL_LEEK_PLACE,
SoundEvents.BLOCK_GRASS_HIT,
SoundEvents.BLOCK_GRASS_FALL
)
@JvmField
val VIVICHOKE_SOUNDS = BlockSoundGroup(1f, 1f,
VIVICHOKE_BREAK,
SoundEvents.BLOCK_GRASS_STEP,
VIVICHOKE_PLACE,
SoundEvents.BLOCK_GRASS_HIT,
SoundEvents.BLOCK_GRASS_FALL
)
@JvmField
val MINT_SOUNDS = BlockSoundGroup(1f, 1f,
MINT_BREAK,
SoundEvents.BLOCK_GRASS_STEP,
MINT_PLACE,
SoundEvents.BLOCK_GRASS_HIT,
SoundEvents.BLOCK_GRASS_FALL
)
@JvmField
val REVIVAL_HERB_SOUNDS = BlockSoundGroup(1f, 1f,
REVIVAL_HERB_BREAK,
SoundEvents.BLOCK_GRASS_STEP,
REVIVAL_HERB_PLACE,
SoundEvents.BLOCK_GRASS_HIT,
SoundEvents.BLOCK_GRASS_FALL
)
@JvmField
val GILDED_CHEST_SOUNDS = BlockSoundGroup(1f, 1f,
GILDED_CHEST_BREAK,
GILDED_CHEST_STEP,
GILDED_CHEST_PLACE,
GILDED_CHEST_HIT,
GILDED_CHEST_STEP
)
@JvmField
val DISPLAY_CASE_ADD_ITEM = this.create("display_case.add_item")
@JvmField
val DISPLAY_CASE_REMOVE_ITEM = this.create("display_case.remove_item")
@JvmField
val DISPLAY_CASE_BREAK = this.create("display_case.break")
@JvmField
val DISPLAY_CASE_HIT = this.create("display_case.hit")
@JvmField
val DISPLAY_CASE_PLACE = this.create("display_case.place")
@JvmField
val DISPLAY_CASE_STEP = this.create("display_case.step")
@JvmField
val DISPLAY_CASE_SOUNDS = BlockSoundGroup(1f, 1f,
DISPLAY_CASE_BREAK,
DISPLAY_CASE_STEP,
DISPLAY_CASE_PLACE,
DISPLAY_CASE_HIT,
DISPLAY_CASE_STEP
)
private fun create(name: String): SoundEvent = this.create(name, SoundEvent.of(cobblemonResource(name)))
val EVOLVING = queue("pokemon.evolving")
}
@@ -1,92 +0,0 @@
/*
* 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 net.minecraft.registry.Registries
import net.minecraft.village.TradeOffers
import net.minecraft.village.VillagerData
import net.minecraft.village.VillagerProfession
/**
* A generator for various trade offers in the mod.
*/
object CobblemonTradeOffers {
/**
* Creates a list of all Cobblemon trade offers for every villager profession.
*
* @return The resulting list.
*/
fun tradeOffersForAll(): List<VillagerTradeOffer> = Registries.VILLAGER_PROFESSION.map(this::tradeOffersFor).flatten()
/**
* Creates a list of all Cobblemon trade offers for the given [VillagerProfession].
*
* @param profession The [VillagerProfession] being queried.
* @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))))
else -> emptyList()
}
/**
* Creates a list of all Cobblemon trade offers for the Wandering trader.
*
* @return The resulting list.
*/
fun resolveWanderingTradeOffers(): List<WandererTradeOffer> = listOf(
WandererTradeOffer(false, listOf(TradeOffers.SellItemFactory(CobblemonItems.VIVICHOKE_SEEDS, 24, 1, 1, 6)))
)
/**
* Represents a trade offer that can be attached to a villager or a wandering trader.
*/
interface TradeOfferHolder {
/**
* The list of the possible [TradeOffers.Factory].
*/
val tradeOffers: List<TradeOffers.Factory>
}
/**
* Represents a trade offer from a villager.
*
* @property profession The target profession for this trade.
* @property requiredLevel The level required must be a possible level.
* @property tradeOffers The list of the possible [TradeOffers.Factory].
*
* @throws IllegalArgumentException If the [requiredLevel] is not within the bounds of [VillagerData.MIN_LEVEL] & [VillagerData.MAX_LEVEL].
*/
data class VillagerTradeOffer(
val profession: VillagerProfession,
val requiredLevel: Int,
override val tradeOffers: List<TradeOffers.Factory>
) : TradeOfferHolder {
init {
if (this.requiredLevel < VillagerData.MIN_LEVEL || this.requiredLevel > VillagerData.MAX_LEVEL) {
throw IllegalArgumentException("${this.requiredLevel} is not a valid level for a villager trade accepted range is ${VillagerData.MIN_LEVEL}-${VillagerData.MAX_LEVEL}")
}
}
}
/**
* Represents a trade offer from a wandering trader.
*
* @property isRareTrade If this is rare or common trade.
* @property tradeOffers The list of the possible [TradeOffers.Factory].
*/
data class WandererTradeOffer(
val isRareTrade: Boolean,
override val tradeOffers: List<TradeOffers.Factory>
) : TradeOfferHolder
}
@@ -8,10 +8,12 @@
package com.cobblemon.mod.common.advancement
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.advancement.criterion.*
import com.cobblemon.mod.common.advancement.criterion.CaughtPokemonCriterionCondition
import com.cobblemon.mod.common.advancement.criterion.PickStarterCriterionCondition
import com.cobblemon.mod.common.advancement.criterion.SimpleCountableCriterionCondition
import com.cobblemon.mod.common.advancement.criterion.SimpleCriterionTrigger
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.advancement.criterion.Criterion
import net.minecraft.advancement.criterion.Criteria
/**
* Contains all the advancement criteria in Cobblemon.
@@ -20,107 +22,40 @@ import net.minecraft.advancement.criterion.Criterion
* @since October 26th, 2022
*/
object CobblemonCriteria {
val PICK_STARTER = this.create(
val PICK_STARTER = Criteria.register(
SimpleCriterionTrigger(
cobblemonResource("pick_starter"),
PickStarterCriterionCondition::class.java
)
)
val CATCH_POKEMON = this.create(
val CATCH_POKEMON = Criteria.register(
SimpleCriterionTrigger(
cobblemonResource("catch_pokemon"),
CaughtPokemonCriterionCondition::class.java
)
)
val CATCH_SHINY_POKEMON = this.create(
val CATCH_SHINY_POKEMON = Criteria.register(
SimpleCriterionTrigger(
cobblemonResource("catch_shiny_pokemon"),
SimpleCountableCriterionCondition::class.java
)
)
val EGG_HATCH = this.create(
val EGG_HATCH = Criteria.register(
SimpleCriterionTrigger(
cobblemonResource("eggs_hatched"),
SimpleCountableCriterionCondition::class.java
)
)
val EVOLVE_POKEMON = this.create(
val EVOLVE_POKEMON = Criteria.register(
SimpleCriterionTrigger(
cobblemonResource("pokemon_evolved"),
EvolvePokemonCriterionCondition::class.java
)
)
val WIN_BATTLE = this.create(
BattleCountableCriterionTrigger(
cobblemonResource("battles_won"),
BattleCountableCriterionCondition::class.java
)
)
val DEFEAT_POKEMON = this.create(
SimpleCriterionTrigger(
cobblemonResource("pokemon_defeated"),
SimpleCountableCriterionCondition::class.java
)
)
val COLLECT_ASPECT = this.create(
AspectCriterionTrigger(
cobblemonResource("aspects_collected"),
AspectCriterionCondition::class.java
)
)
val POKEMON_INTERACT = this.create(
val WIN_BATTLE = Criteria.register(
SimpleCriterionTrigger(
cobblemonResource("pokemon_interact"),
PokemonInteractCriterion::class.java
cobblemonResource("battles_won"),
SimpleCountableCriterionCondition::class.java
)
)
val PARTY_CHECK = this.create(
SimpleCriterionTrigger(
cobblemonResource("party"),
PartyCheckCriterion::class.java
)
)
val LEVEL_UP = this.create(
SimpleCriterionTrigger(
cobblemonResource("level_up"),
LevelUpCriterionCondition::class.java
)
)
val PASTURE_USE = this.create(
SimpleCriterionTrigger(
cobblemonResource("pasture_use"),
PickStarterCriterionCondition::class.java
)
)
val RESURRECT_POKEMON = this.create(
SimpleCriterionTrigger(
cobblemonResource("resurrect_pokemon"),
PickStarterCriterionCondition::class.java
)
)
val TRADE_POKEMON = this.create(
SimpleCriterionTrigger(
cobblemonResource("trade_pokemon"),
TradePokemonCriterionCondition::class.java
)
)
// Advancement criteria for [grow_tumblestone.json]
val PLANT_TUMBLESTONE = this.create(
SimpleCriterionTrigger(
cobblemonResource("plant_tumblestone"),
PlantTumblestoneCriterionCondition::class.java
)
)
private fun <T : Criterion<*>> create(criteria: T): T = Cobblemon.implementation.registerCriteria(criteria)
}
@@ -1,45 +0,0 @@
/*
* 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.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
import com.google.gson.JsonArray
import com.google.gson.JsonObject
import net.minecraft.predicate.entity.LootContextPredicate
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.util.Identifier
open class AspectCriterionTrigger(identifier: Identifier, criterionClass: Class<AspectCriterionCondition>) : SimpleCriterionTrigger<MutableMap<Identifier, MutableSet<String>>, AspectCriterionCondition>(identifier, criterionClass) {
}
class AspectCriterionCondition(id: Identifier, predicate: LootContextPredicate) : SimpleCriterionCondition<MutableMap<Identifier, MutableSet<String>>>(id, predicate) {
var pokemon = Identifier("cobblemon:pikachu")
var aspects = mutableListOf<String>()
override fun toJson(json: JsonObject) {
json.add("aspects", JsonArray(aspects.size).also {
aspects.forEach { aspect -> it.add(aspect) }
})
json.addProperty("pokemon", pokemon.toString())
}
override fun fromJson(json: JsonObject) {
aspects.clear()
json.getAsJsonArray("aspects").forEach { element ->
aspects.add(element.asString)
}
pokemon = json.get("pokemon").asString.asIdentifierDefaultingNamespace()
}
override fun matches(player: ServerPlayerEntity, context: MutableMap<Identifier, MutableSet<String>>): Boolean {
val caughtAspects = context.getOrDefault(pokemon, mutableSetOf())
return this.aspects.all { it in caughtAspects }
}
}
@@ -1,67 +0,0 @@
/*
* 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.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
import com.cobblemon.mod.common.util.toJsonArray
import com.google.gson.JsonObject
import net.minecraft.predicate.entity.LootContextPredicate
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.util.Identifier
open class BattleCountableCriterionTrigger(identifier: Identifier, criterionClass: Class<BattleCountableCriterionCondition>) : SimpleCriterionTrigger<BattleCountableContext, BattleCountableCriterionCondition>(identifier, criterionClass) {
}
class BattleCountableCriterionCondition(id: Identifier, predicate: LootContextPredicate) : CountableCriterionCondition<BattleCountableContext>(id, predicate) {
private var battleTypes = mutableListOf("any")
override fun fromJson(json: JsonObject) {
super.fromJson(json)
if(!json.get("battle_types").isJsonNull) {
battleTypes.clear()
json.get("battle_types").asJsonArray.asList().forEach() {
battleTypes.add(it.asString)
}
}
}
override fun toJson(json: JsonObject) {
super.toJson(json)
json.add("battle_types", battleTypes.toJsonArray())
}
override fun matches(player: ServerPlayerEntity, context: BattleCountableContext): Boolean {
var typeCheck = false
val advancementData = Cobblemon.playerData.get(player).advancementData
if (battleTypes.isEmpty() || battleTypes.contains("any")) {
typeCheck = true
}
if (battleTypes.contains("pvp")) {
typeCheck = context.battle.isPvP
context.times = advancementData.totalPvPBattleVictoryCount
}
if (battleTypes.contains("pvw")) {
typeCheck = context.battle.isPvW
context.times = advancementData.totalPvWBattleVictoryCount
}
if (battleTypes.contains("pvn")) {
typeCheck = context.battle.isPvN
context.times = advancementData.totalPvWBattleVictoryCount
}
if (battleTypes.size > 1) {
context.times = advancementData.totalBattleVictoryCount
}
return context.times >= count && typeCheck
}
}
open class BattleCountableContext(times : Int, var battle : PokemonBattle) : CountableContext(times)
@@ -9,7 +9,7 @@
package com.cobblemon.mod.common.advancement.criterion
import com.google.gson.JsonObject
import net.minecraft.predicate.entity.LootContextPredicate
import net.minecraft.predicate.entity.EntityPredicate.Extended
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.util.Identifier
@@ -21,7 +21,7 @@ import net.minecraft.util.Identifier
*/
open class CountablePokemonTypeContext(times: Int, var type: String) : CountableContext(times)
class CaughtPokemonCriterionCondition(id: Identifier, predicate: LootContextPredicate) : CountableCriterionCondition<CountablePokemonTypeContext>(id, predicate) {
class CaughtPokemonCriterionCondition(id: Identifier, entity: Extended) : CountableCriterionCondition<CountablePokemonTypeContext>(id, entity) {
var type = "any"
override fun toJson(json: JsonObject) {
super.toJson(json)
@@ -34,6 +34,6 @@ class CaughtPokemonCriterionCondition(id: Identifier, predicate: LootContextPred
}
override fun matches(player: ServerPlayerEntity, context: CountablePokemonTypeContext): Boolean {
return super.matches(player, context) && (context.type == type || type == "any")
return super.matches(player, context) && context.type == type
}
}
@@ -9,7 +9,7 @@
package com.cobblemon.mod.common.advancement.criterion
import com.google.gson.JsonObject
import net.minecraft.predicate.entity.LootContextPredicate
import net.minecraft.predicate.entity.EntityPredicate.Extended
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.util.Identifier
@@ -20,7 +20,7 @@ import net.minecraft.util.Identifier
* @author Hiroku
* @since November 4th, 2022
*/
abstract class CountableCriterionCondition<T : CountableContext>(id: Identifier, predicate: LootContextPredicate) : SimpleCriterionCondition<T>(id, predicate) {
abstract class CountableCriterionCondition<T : CountableContext>(id: Identifier, entity: Extended) : SimpleCriterionCondition<T>(id, entity) {
var count = 0
override fun fromJson(json: JsonObject) {
count = json.get("count")?.asInt ?: 0
@@ -43,7 +43,7 @@ abstract class CountableCriterionCondition<T : CountableContext>(id: Identifier,
* @author Hiroku
* @since November 4th, 2022
*/
class SimpleCountableCriterionCondition(id: Identifier, predicate: LootContextPredicate) : CountableCriterionCondition<CountableContext>(id, predicate)
class SimpleCountableCriterionCondition(id: Identifier, entity: Extended) : CountableCriterionCondition<CountableContext>(id, entity)
fun SimpleCriterionTrigger<CountableContext, SimpleCountableCriterionCondition>.trigger(player: ServerPlayerEntity, times: Int) = trigger(player, CountableContext(times))
/**
@@ -1,38 +0,0 @@
/*
* 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.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
import com.google.gson.JsonObject
import net.minecraft.predicate.entity.LootContextPredicate
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.util.Identifier
class EvolvePokemonCriterionCondition(id: Identifier, entity: LootContextPredicate) : CountableCriterionCondition<EvolvePokemonContext>(id, entity) {
var species = "any"
var evolution = "any"
override fun toJson(json: JsonObject) {
super.toJson(json)
json.addProperty("species", species)
json.addProperty("evolution", evolution)
}
override fun fromJson(json: JsonObject) {
super.fromJson(json)
species = json.get("species")?.asString ?: "any"
evolution = json.get("evolution")?.asString ?: "any"
}
override fun matches(player: ServerPlayerEntity, context: EvolvePokemonContext): Boolean {
return context.times >= count && (context.species == species.asIdentifierDefaultingNamespace() || species == "any") &&
(context.evolution == evolution.asIdentifierDefaultingNamespace() || evolution == "any")
}
}
open class EvolvePokemonContext(val species : Identifier, val evolution : Identifier, times: Int) : CountableContext(times)
@@ -1,41 +0,0 @@
/*
* 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.cobblemon.mod.common.pokemon.Pokemon
import com.google.gson.JsonObject
import net.minecraft.predicate.entity.LootContextPredicate
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.util.Identifier
class LevelUpCriterionCondition(id: Identifier, entity: LootContextPredicate) : SimpleCriterionCondition<LevelUpContext>(id, entity) {
var level = 0
var evolved = true
override fun toJson(json: JsonObject) {
json.addProperty("level", level)
json.addProperty("has_evolved", evolved)
}
override fun fromJson(json: JsonObject) {
level = json.get("level")?.asInt ?: 0
evolved = json.get("has_evolved")?.asBoolean ?: true
}
override fun matches(player: ServerPlayerEntity, context: LevelUpContext): Boolean {
val preEvo = context.pokemon.preEvolution == null
val hasEvolution = !context.pokemon.evolutions.none()
var evolutionCheck = true
if (preEvo || hasEvolution) {
evolutionCheck = !(preEvo == hasEvolution)
}
return level == context.level && evolutionCheck == evolved
}
}
open class LevelUpContext(var level : Int, var pokemon : Pokemon)
@@ -1,54 +0,0 @@
/*
* 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.cobblemon.mod.common.api.storage.party.PlayerPartyStore
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
import com.cobblemon.mod.common.util.party
import com.google.gson.JsonArray
import com.google.gson.JsonObject
import net.minecraft.predicate.entity.LootContextPredicate
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.util.Identifier
class PartyCheckCriterion(id: Identifier, entity: LootContextPredicate) : SimpleCriterionCondition<PartyCheckContext>(id, entity){
val party = mutableListOf<Identifier>()
override fun toJson(json: JsonObject) {
json.add("party", JsonArray(party.size).also {
party.forEach { pokemon -> it.add(pokemon.toString()) }
})
}
override fun fromJson(json: JsonObject) {
party.clear()
json.getAsJsonArray("party").forEach { element ->
party.add(element.asString.asIdentifierDefaultingNamespace())
}
}
override fun matches(player: ServerPlayerEntity, context: PartyCheckContext): Boolean {
val playerParty = player.party()
val matches = mutableListOf<Identifier>()
party.forEach {
if (it == "any".asIdentifierDefaultingNamespace()) {
matches.add(it)
}
}
val partyCount = playerParty.count()
if (matches.containsAll(party) && party.size == partyCount && matches.size == partyCount) return true
playerParty.iterator().forEach {
if (party.contains(it.species.resourceIdentifier)) {
matches.add(it.species.resourceIdentifier)
}
}
return matches.containsAll(party) && matches.size == partyCount
}
}
open class PartyCheckContext(val party : PlayerPartyStore)
@@ -11,7 +11,7 @@ package com.cobblemon.mod.common.advancement.criterion
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
import com.cobblemon.mod.common.pokemon.Pokemon
import com.google.gson.JsonObject
import net.minecraft.predicate.entity.LootContextPredicate
import net.minecraft.predicate.entity.EntityPredicate.Extended
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.util.Identifier
@@ -21,7 +21,7 @@ import net.minecraft.util.Identifier
* @author Licious, Hiroku
* @since October 26th, 2022
*/
class PickStarterCriterionCondition(id: Identifier, predicate: LootContextPredicate) : SimpleCriterionCondition<Pokemon>(id, predicate) {
class PickStarterCriterionCondition(id: Identifier, entity: Extended) : SimpleCriterionCondition<Pokemon>(id, entity) {
var properties = PokemonProperties()
override fun toJson(json: JsonObject) {
json.addProperty("properties", properties.originalString)
@@ -1,52 +0,0 @@
/*
* 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.cobblemon.mod.common.block.TumblestoneBlock
import com.google.gson.JsonObject
import net.minecraft.predicate.entity.LootContextPredicate
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.util.Identifier
import net.minecraft.util.math.BlockPos
/**
* A criterion condition for when a tumblestone block is planted
* @param id The identifier of the criterion
* @param predicate The predicate for the criterion
*
* @author Aethen
* @since 02/28/2024
*/
class PlantTumblestoneCriterionCondition(id: Identifier, predicate: LootContextPredicate) :
SimpleCriterionCondition<PlantTumblestoneContext>(id, predicate) {
override fun toJson(json: JsonObject) {
// Add properties to json if needed. None needed for this criterion
}
override fun fromJson(json: JsonObject) {
// Parse properties from json if needed. None needed for this criterion
}
/**
* Checks if the tumblestone block can grow at the given position
* @param player The player that planted the tumblestone block
* @param context The context of the criterion
* @return True if the tumblestone block can grow at the given position, false otherwise
*/
override fun matches(player: ServerPlayerEntity, context: PlantTumblestoneContext): Boolean {
return context.tumbleStoneBlock.canGrow(context.pos, player.world)
}
}
/**
* The context of the [PlantTumblestoneCriterionCondition]
* @param pos The position of the tumblestone block
* @param tumbleStoneBlock The tumblestone block
*/
open class PlantTumblestoneContext(var pos: BlockPos, var tumbleStoneBlock: TumblestoneBlock)
@@ -1,34 +0,0 @@
/*
* 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.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
import com.google.gson.JsonObject
import net.minecraft.predicate.entity.LootContextPredicate
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.util.Identifier
open class PokemonInteractContext(var type: Identifier, var item : Identifier)
class PokemonInteractCriterion(id: Identifier, entity: LootContextPredicate) : SimpleCriterionCondition<PokemonInteractContext>(id, entity) {
var type = "any"
var item = "any"
override fun toJson(json: JsonObject) {
json.addProperty("type", type)
json.addProperty("item", item)
}
override fun fromJson(json: JsonObject) {
type = json.get("type")?.asString ?: "any"
item = json.get("item")?.asString ?: "any"
}
override fun matches(player: ServerPlayerEntity, context: PokemonInteractContext): Boolean {
return (context.type == type.asIdentifierDefaultingNamespace() || type == "any") && (context.item == item.asIdentifierDefaultingNamespace() || item == "any")
}
}
@@ -13,7 +13,7 @@ import net.minecraft.advancement.criterion.AbstractCriterion
import net.minecraft.advancement.criterion.AbstractCriterionConditions
import net.minecraft.predicate.entity.AdvancementEntityPredicateDeserializer
import net.minecraft.predicate.entity.AdvancementEntityPredicateSerializer
import net.minecraft.predicate.entity.LootContextPredicate
import net.minecraft.predicate.entity.EntityPredicate.Extended
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.util.Identifier
@@ -31,17 +31,16 @@ open class SimpleCriterionTrigger<T, C : SimpleCriterionCondition<T>>(
val criterionClass: Class<C>
) : AbstractCriterion<C>() {
override fun getId() = _id
fun trigger(player: ServerPlayerEntity, context: T) = this.trigger(player) { it.matches(player, context) }
override fun conditionsFromJson(
obj: JsonObject,
playerPredicate: LootContextPredicate,
playerPredicate: Extended,
predicateDeserializer: AdvancementEntityPredicateDeserializer
): C {
val instance = criterionClass.getConstructor(Identifier::class.java, LootContextPredicate::class.java).newInstance(id, playerPredicate)
val instance = criterionClass.getConstructor(Identifier::class.java, Extended::class.java).newInstance(id, playerPredicate)
instance.fromJson(obj)
return instance
}
fun trigger(player: ServerPlayerEntity, context: T) = this.trigger(player) { it.matches(player, context) }
}
/**
@@ -53,8 +52,8 @@ open class SimpleCriterionTrigger<T, C : SimpleCriterionCondition<T>>(
*/
abstract class SimpleCriterionCondition<T>(
id: Identifier,
playerPredicate: LootContextPredicate
): AbstractCriterionConditions(id, playerPredicate) {
entity: Extended
): AbstractCriterionConditions(id, entity) {
override fun toJson(predicateSerializer: AdvancementEntityPredicateSerializer): JsonObject {
val json = super.toJson(predicateSerializer)
toJson(json)
@@ -1,47 +0,0 @@
/*
* 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.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
import com.google.gson.JsonObject
import net.minecraft.predicate.entity.LootContextPredicate
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.util.Identifier
class TradePokemonCriterionCondition(id: Identifier, entity: LootContextPredicate) : SimpleCriterionCondition<TradePokemonContext>(id, entity) {
var traded = "any"
var received = "any"
var tradedHeldItem = "any"
var receivedHeldItem = "any"
override fun toJson(json: JsonObject) {
json.addProperty("traded", traded)
json.addProperty("received", received)
json.addProperty("traded_held_item", tradedHeldItem)
json.addProperty("received_held_item", receivedHeldItem)
}
override fun fromJson(json: JsonObject) {
traded = json.get("traded")?.asString ?: "any"
received = json.get("received")?.asString ?: "any"
tradedHeldItem = json.get("traded_held_item")?.asString ?: "minecraft:air"
receivedHeldItem = json.get("received_held_item")?.asString ?: "minecraft:air"
}
override fun matches(player: ServerPlayerEntity, context: TradePokemonContext): Boolean {
val heldItem1 = context.traded.heldItem().item.registryEntry.registryKey().value
val heldItem2 = context.received.heldItem().item.registryEntry.registryKey().value
return (context.traded.species.resourceIdentifier == traded.asIdentifierDefaultingNamespace() || traded == "any") &&
(context.received.species.resourceIdentifier == received.asIdentifierDefaultingNamespace() || received == "any") &&
(heldItem1 == tradedHeldItem.asIdentifierDefaultingNamespace() || heldItem1 == "minecraft:air".asIdentifierDefaultingNamespace()) &&
(heldItem2 == receivedHeldItem.asIdentifierDefaultingNamespace() || heldItem2 == "minecraft:air".asIdentifierDefaultingNamespace())
}
}
open class TradePokemonContext(val traded: Pokemon, val received: Pokemon)
@@ -37,7 +37,7 @@ object Abilities : DataRegistry {
PotentialAbility.types.add(CommonAbilityType)
PotentialAbility.types.add(HiddenAbilityType)
this.abilityMap.clear()
val abilitiesJson = ShowdownService.service.getAbilityIds()
val abilitiesJson = ShowdownService.get().getAbilityIds()
for (i in 0 until abilitiesJson.size()) {
val id = abilitiesJson[i].asString
val ability = AbilityTemplate(id)
@@ -9,7 +9,6 @@
package com.cobblemon.mod.common.api.abilities
import com.cobblemon.mod.common.api.Priority
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.DataKeys
import com.google.gson.JsonObject
import net.minecraft.nbt.NbtCompound
@@ -22,7 +21,7 @@ import net.minecraft.nbt.NbtCompound
* @author Qu
* @since January 9th, 2022
*/
open class Ability internal constructor(var template: AbilityTemplate, forced: Boolean) {
open class Ability internal constructor(var template: AbilityTemplate, var forced: Boolean) {
val name: String
get() = template.name
@@ -35,26 +34,16 @@ open class Ability internal constructor(var template: AbilityTemplate, forced: B
/**
* This represents the last known index of this backing ability in the species data.
* @see [Pokemon.updateAbility].
*/
var forced: Boolean = forced
internal set
/**
* This represents the last known index of this backing ability in the species data.
*
* @see [Pokemon.updateAbility].
* If -1 the ability will attempt to find the correct index or reroll itself, this is done in order to be compatible with existing data
* The value can be mutated however this is not recommended by API users.
*/
var index: Int = -1
internal set
/**
* The last known priority of this ability in the species data.
*
* @see [Pokemon.updateAbility].
* The value can be mutated however this is not recommended by API users.
*/
var priority = Priority.LOWEST
internal set
open fun saveToNBT(nbt: NbtCompound): NbtCompound {
nbt.putString(DataKeys.POKEMON_ABILITY_NAME, name)
@@ -73,23 +62,19 @@ open class Ability internal constructor(var template: AbilityTemplate, forced: B
}
open fun loadFromNBT(nbt: NbtCompound): Ability {
this.template = Abilities.getOrException(nbt.getString(DataKeys.POKEMON_ABILITY_NAME))
this.forced = nbt.getBoolean(DataKeys.POKEMON_ABILITY_FORCED)
forced = nbt.getBoolean(DataKeys.POKEMON_ABILITY_FORCED)
if (nbt.contains(DataKeys.POKEMON_ABILITY_INDEX) && nbt.contains(DataKeys.POKEMON_ABILITY_PRIORITY)) {
this.index = nbt.getInt(DataKeys.POKEMON_ABILITY_INDEX)
this.priority = Priority.valueOf(nbt.getString(DataKeys.POKEMON_ABILITY_PRIORITY))
}
return this
}
open fun loadFromJSON(json: JsonObject): Ability {
this.template = Abilities.getOrException(json.get(DataKeys.POKEMON_ABILITY_NAME).asString)
this.forced = json.get(DataKeys.POKEMON_ABILITY_FORCED)?.asBoolean ?: false
forced = json.get(DataKeys.POKEMON_ABILITY_FORCED)?.asBoolean ?: false
if (json.has(DataKeys.POKEMON_ABILITY_INDEX) && json.has(DataKeys.POKEMON_ABILITY_PRIORITY)) {
this.index = json.get(DataKeys.POKEMON_ABILITY_INDEX).asInt
this.priority = Priority.valueOf(json.get(DataKeys.POKEMON_ABILITY_PRIORITY).asString)
}
return this
}
}
@@ -28,6 +28,7 @@ class AbilityTemplate(
*/
fun create(forced: Boolean = false) = builder(this, forced)
/**
* Returns the Ability and loads the given NBT Tag into it.
*
@@ -41,5 +42,4 @@ class AbilityTemplate(
* Ability extensions need to write and read their needed data from here.
*/
fun create(json: JsonObject) = create().loadFromJSON(json)
}
@@ -35,7 +35,7 @@ interface SleepDepth {
override fun shouldWake(pokemonEntity: PokemonEntity): Boolean {
val nearbyPlayers = pokemonEntity.world.getPlayers(TargetPredicate.createNonAttackable(), pokemonEntity, Box.of(pokemonEntity.pos, 16.0, 16.0, 16.0))
return nearbyPlayers.any { !it.isSneaking }
return nearbyPlayers.none { !it.isSneaking }
}
}
@@ -10,9 +10,9 @@ package com.cobblemon.mod.common.api.apricorn
import com.cobblemon.mod.common.CobblemonBlocks
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.item.ApricornItem
import com.cobblemon.mod.common.block.ApricornBlock
import com.cobblemon.mod.common.block.ApricornSaplingBlock
import com.cobblemon.mod.common.item.ApricornItem
import net.minecraft.block.MapColor
import net.minecraft.item.BlockItem
@@ -33,43 +33,43 @@ enum class Apricorn {
YELLOW;
fun item(): ApricornItem = when(this) {
BLACK -> CobblemonItems.BLACK_APRICORN
BLUE -> CobblemonItems.BLUE_APRICORN
GREEN -> CobblemonItems.GREEN_APRICORN
PINK -> CobblemonItems.PINK_APRICORN
RED -> CobblemonItems.RED_APRICORN
WHITE -> CobblemonItems.WHITE_APRICORN
YELLOW -> CobblemonItems.YELLOW_APRICORN
BLACK -> CobblemonItems.BLACK_APRICORN.get()
BLUE -> CobblemonItems.BLUE_APRICORN.get()
GREEN -> CobblemonItems.GREEN_APRICORN.get()
PINK -> CobblemonItems.PINK_APRICORN.get()
RED -> CobblemonItems.RED_APRICORN.get()
WHITE -> CobblemonItems.WHITE_APRICORN.get()
YELLOW -> CobblemonItems.YELLOW_APRICORN.get()
}
fun seed(): BlockItem = when(this) {
BLACK -> CobblemonItems.BLACK_APRICORN_SEED
BLUE -> CobblemonItems.BLUE_APRICORN_SEED
GREEN -> CobblemonItems.GREEN_APRICORN_SEED
PINK -> CobblemonItems.PINK_APRICORN_SEED
RED -> CobblemonItems.RED_APRICORN_SEED
WHITE -> CobblemonItems.WHITE_APRICORN_SEED
YELLOW -> CobblemonItems.YELLOW_APRICORN_SEED
BLACK -> CobblemonItems.BLACK_APRICORN_SEED.get()
BLUE -> CobblemonItems.BLUE_APRICORN_SEED.get()
GREEN -> CobblemonItems.GREEN_APRICORN_SEED.get()
PINK -> CobblemonItems.PINK_APRICORN_SEED.get()
RED -> CobblemonItems.RED_APRICORN_SEED.get()
WHITE -> CobblemonItems.WHITE_APRICORN_SEED.get()
YELLOW -> CobblemonItems.YELLOW_APRICORN_SEED.get()
}
fun block(): ApricornBlock = when(this) {
BLACK -> CobblemonBlocks.BLACK_APRICORN
BLUE -> CobblemonBlocks.BLUE_APRICORN
GREEN -> CobblemonBlocks.GREEN_APRICORN
PINK -> CobblemonBlocks.PINK_APRICORN
RED -> CobblemonBlocks.RED_APRICORN
WHITE -> CobblemonBlocks.WHITE_APRICORN
YELLOW -> CobblemonBlocks.YELLOW_APRICORN
BLACK -> CobblemonBlocks.BLACK_APRICORN.get()
BLUE -> CobblemonBlocks.BLUE_APRICORN.get()
GREEN -> CobblemonBlocks.GREEN_APRICORN.get()
PINK -> CobblemonBlocks.PINK_APRICORN.get()
RED -> CobblemonBlocks.RED_APRICORN.get()
WHITE -> CobblemonBlocks.WHITE_APRICORN.get()
YELLOW -> CobblemonBlocks.YELLOW_APRICORN.get()
}
fun sapling(): ApricornSaplingBlock = when(this) {
BLACK -> CobblemonBlocks.BLACK_APRICORN_SAPLING
BLUE -> CobblemonBlocks.BLUE_APRICORN_SAPLING
GREEN -> CobblemonBlocks.GREEN_APRICORN_SAPLING
PINK -> CobblemonBlocks.PINK_APRICORN_SAPLING
RED -> CobblemonBlocks.RED_APRICORN_SAPLING
WHITE -> CobblemonBlocks.WHITE_APRICORN_SAPLING
YELLOW -> CobblemonBlocks.YELLOW_APRICORN_SAPLING
BLACK -> CobblemonBlocks.BLACK_APRICORN_SAPLING.get()
BLUE -> CobblemonBlocks.BLUE_APRICORN_SAPLING.get()
GREEN -> CobblemonBlocks.GREEN_APRICORN_SAPLING.get()
PINK -> CobblemonBlocks.PINK_APRICORN_SAPLING.get()
RED -> CobblemonBlocks.RED_APRICORN_SAPLING.get()
WHITE -> CobblemonBlocks.WHITE_APRICORN_SAPLING.get()
YELLOW -> CobblemonBlocks.YELLOW_APRICORN_SAPLING.get()
}
fun mapColor(): MapColor = when(this) {
@@ -1,73 +0,0 @@
/*
* 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.battles.interpreter
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
/**
* The context of how a condition was created or changed during a battle.
*
* @author Segfault Guy
* @since April 10th, 2023
*/
interface BattleContext {
/** The effect or condition this [BattleContext] represents. */
val id: String
/** The turn this [BattleContext] was created. */
val turn: Int
/** The [BattleContext.Type] tied to this [BattleContext]. */
val type: Type
/** The [BattlePokemon] that directly or indirectly caused this [BattleContext]. */
val origin: BattlePokemon?
/**
* The type of [BattleContext].
*
* @property damaging Whether a context of this type is a source of damage.
* @property exclusive Whether only one context of this type can exist.
*
* @author Segfault Guy
* @since April 10th, 2023
*/
enum class Type(val damaging: Boolean, val exclusive: Boolean) {
ITEM(true, true),
STATUS(true, false),
VOLATILE(true, false),
HAZARD(true, false),
WEATHER(true, true),
ROOM(false, true),
SPORT(false, false),
TERRAIN(false, true),
GRAVITY(false, true),
TAILWIND(false, true),
SCREEN(false, false),
FAINT(false, false),
BOOST(false, false),
UNBOOST(false, false),
MISC(false, false);
}
}
data class BasicContext(
override val id: String,
override val turn: Int,
override val type: BattleContext.Type,
override val origin: BattlePokemon?
) : BattleContext
data class MissingContext(
override val id: String = "error",
override val turn: Int = 0,
override val type: BattleContext.Type = BattleContext.Type.MISC,
override val origin: BattlePokemon? = null
) : BattleContext
@@ -10,11 +10,7 @@ package com.cobblemon.mod.common.api.battles.interpreter
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.moves.MoveTemplate
import com.cobblemon.mod.common.api.moves.Moves
import com.cobblemon.mod.common.battles.ActiveBattlePokemon
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
import java.util.UUID
/**
* A class responsible for parsing a raw simulator protocol message received from Showdown.
@@ -28,6 +24,7 @@ import java.util.UUID
* @since December 31st, 2022
*/
class BattleMessage(rawMessage: String) {
/**
* The ID of the action received in the message.
*/
@@ -119,10 +116,6 @@ class BattleMessage(rawMessage: String) {
return this
}
fun pokemonByUuid(index: Int, battle: PokemonBattle): BattlePokemon? {
return this.argumentAt(index)?.let { UUID.fromString(it) }?.let { uuid -> battle.actors.flatMap { it.pokemonList }.find { it.uuid == uuid } }
}
/**
* Queries an argument at the given [index] for a 'pnx' that will be parsed into a [BattleActor] and [ActiveBattlePokemon].
*
@@ -131,52 +124,10 @@ class BattleMessage(rawMessage: String) {
* @return A pair of [BattleActor] and [ActiveBattlePokemon] if the argument exists and successfully parses them otherwise null.
*/
fun actorAndActivePokemon(index: Int, battle: PokemonBattle): Pair<BattleActor, ActiveBattlePokemon>? {
val (pnx, _) = this.pnxAndUuid(index) ?: return null
val pnx = this.argumentAt(index)?.takeIf { it.length >= 3 }?.substring(0, 3) ?: return null
return this.actorAndActivePokemon(pnx, battle)
}
/**
* Queries an argument at the given [index] for a 'pnx' and uuid that will be parsed into a [BattlePokemon].
*
* @param index The index of the argument referencing the [BattlePokemon].
* @param battle The [PokemonBattle] being queried.
* @return The [BattlePokemon] if the argument exists and is successfully parsed; otherwise null.
*/
fun battlePokemon(index: Int, battle: PokemonBattle): BattlePokemon? {
val (actorID, pokemonID) = this.pnxAndUuid(index) ?: return null
return this.battlePokemon(actorID, pokemonID, battle)
}
/**
* Queries an optional argument identified by [optionalArg] for a 'pnx' and uuid that will be parsed into a [BattlePokemon].
*
* @param optionalArg The id of the optional argument referencing the [BattlePokemon].
* @param battle The [PokemonBattle] being queried.
* @return The [BattlePokemon] if the argument exists and is successfully parsed; otherwise null.
*/
fun battlePokemonFromOptional(battle: PokemonBattle, optionalArg: String = "of"): BattlePokemon? {
val optional = this.optionalArguments.get(optionalArg) ?: return null
val pokemonID = optional.takeIf { it.length >= 2 }?.split(":")?.takeIf { it.size == 2 } ?: return null
val pnx = pokemonID[0].takeIf { it.matches(PNX_MATCHER) || it.matches(PN_MATCHER) } ?: return null
val uuid = pokemonID[1].trim()
return this.battlePokemon(pnx, uuid, battle)
}
/**
* Deconstructs the Showdown ID of a Pokemon at the given [index] into its 'pnx' and 'uuid' parts.
*
* @param index The index of the argument containing the Showdown ID of a Pokemon.
* @return A 'pnx' String representing position and a 'uuid' String representing the unique Pokemon if parsed correctly, otherwise null.
*/
fun pnxAndUuid(index: Int): Pair<String, String>? {
val argument = this.argumentAt(index)?.takeIf { it.length >= 2 }?.split(":")?.takeIf { it.size == 2 } ?: return null
val pnx = argument[0].takeIf { it.matches(PNX_MATCHER) || it.matches(PN_MATCHER) } ?: return null
val uuid = argument[1].trim()
return pnx to uuid
}
/**
* Attempts to parse an [Effect] from an argument at the given [index].
*
@@ -199,11 +150,6 @@ class BattleMessage(rawMessage: String) {
return Effect.parse(data)
}
fun moveAt(index: Int): MoveTemplate? {
val argument = argumentAt(index)?.lowercase()?.replace("[^a-z0-9]".toRegex(), "") ?: return null
return Moves.getByName(argument)
}
/**
* Queries an optional argument with given [argumentName] for a 'pnx' that will be parsed into a [BattleActor] and [ActiveBattlePokemon].
*
@@ -212,7 +158,7 @@ class BattleMessage(rawMessage: String) {
* @return A pair of [BattleActor] and [ActiveBattlePokemon] if the argument exists and successfully parses them otherwise null.
*/
fun actorAndActivePokemonFromOptional(battle: PokemonBattle, argumentName: String = "of"): Pair<BattleActor, ActiveBattlePokemon>? {
val pnx = this.optionalArgument(argumentName)?.takeIf { it.length >= 3 }?.substring(0, 3) ?: return null
val pnx = this.optionalArgument(argumentName)?.substring(0, 3) ?: return null
return this.actorAndActivePokemon(pnx, battle)
}
@@ -237,26 +183,12 @@ class BattleMessage(rawMessage: String) {
null
}
private fun battlePokemon(pnx: String, pokemonID: String, battle: PokemonBattle): BattlePokemon? = try {
battle.getBattlePokemon(pnx, pokemonID)
} catch (_: Exception) {
null
}
companion object {
private const val SEPARATOR = "|"
private const val OPTIONAL_ARG_START = "["
private const val OPTIONAL_ARG_END = "]"
/**
* Pattern to match a Showdown position e.g. p2a, p1b
*/
val PNX_MATCHER = Regex("p\\d[a-c]")
/**
* Pattern to match a Showdown side position e.g. p2, p1
*/
val PN_MATCHER = Regex("p\\d")
}
}
@@ -36,9 +36,6 @@ interface Effect {
*/
val rawData: String
val typelessData: String
get() = rawData.substringAfter(type.prefix).trim()
/**
* Represents the type of the [Effect].
*
@@ -52,7 +49,6 @@ interface Effect {
ABILITY("ability:"),
ITEM("item:"),
MOVE("move:"),
BAGITEM("bagitem:"),
PURE(""),
}
@@ -8,8 +8,6 @@
package com.cobblemon.mod.common.api.battles.model
import com.bedrockk.molang.runtime.struct.QueryStruct
import com.bedrockk.molang.runtime.value.DoubleValue
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.Cobblemon.LOGGER
import com.cobblemon.mod.common.CobblemonNetwork
@@ -18,8 +16,6 @@ import com.cobblemon.mod.common.api.battles.model.actor.ActorType
import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
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.net.NetworkPacket
import com.cobblemon.mod.common.api.tags.CobblemonItemTags
import com.cobblemon.mod.common.api.text.red
@@ -34,23 +30,16 @@ import com.cobblemon.mod.common.battles.dispatch.BattleDispatch
import com.cobblemon.mod.common.battles.dispatch.DispatchResult
import com.cobblemon.mod.common.battles.dispatch.GO
import com.cobblemon.mod.common.battles.dispatch.WaitDispatch
import com.cobblemon.mod.common.battles.interpreter.ContextManager
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
import com.cobblemon.mod.common.battles.runner.ShowdownService
import com.cobblemon.mod.common.battles.ForfeitActionResponse
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.net.messages.client.battle.BattleEndPacket
import com.cobblemon.mod.common.net.messages.client.battle.BattleMessagePacket
import com.cobblemon.mod.common.pokemon.evolution.progress.DefeatEvolutionProgress
import com.cobblemon.mod.common.pokemon.evolution.progress.LastBattleCriticalHitsEvolutionProgress
import com.cobblemon.mod.common.pokemon.evolution.requirements.DefeatRequirement
import com.cobblemon.mod.common.util.battleLang
import com.cobblemon.mod.common.util.getPlayer
import java.io.File
import java.util.UUID
import com.cobblemon.mod.common.util.party
import net.minecraft.server.network.ServerPlayerEntity
import java.util.UUID
import java.util.concurrent.ConcurrentLinkedQueue
import net.minecraft.text.Text
import java.util.concurrent.ConcurrentLinkedDeque
/**
* Individual battle instance
@@ -58,24 +47,20 @@ import java.util.concurrent.ConcurrentLinkedDeque
* @since January 16th, 2022
* @author Deltric, Hiroku
*/
@Suppress("unused", "MemberVisibilityCanBePrivate")
open class PokemonBattle(
val format: BattleFormat,
val side1: BattleSide,
val side2: BattleSide
) {
/** Whether logging will be silenced for this battle. */
/** Whether or not logging will be silenced for this battle. */
var mute = true
init {
side1.battle = this
side2.battle = this
this.actors.forEach { actor ->
actor.battle = this
actor.pokemonList.forEach { battlePokemon ->
battlePokemon.effectedPokemon.evolutionProxy.current().progress()
.filterIsInstance<LastBattleCriticalHitsEvolutionProgress>()
.forEach { it.reset() }
battlePokemon.criticalHits = 0
}
}
}
@@ -89,13 +74,11 @@ open class PokemonBattle(
val playerUUIDs: Iterable<UUID>
get() = actors.flatMap { it.getPlayerUUIDs() }
val players = playerUUIDs.mapNotNull { it.getPlayer() }
val spectators = mutableSetOf<UUID>()
val spectators = mutableListOf<UUID>()
val battleId = UUID.randomUUID()
val showdownMessages = mutableListOf<String>()
val battleLog = mutableListOf<String>()
val chatLog = mutableListOf<Text>()
var started = false
var ended = false
// TEMP battle showcase stuff
@@ -103,22 +86,13 @@ open class PokemonBattle(
var turn: Int = 1
private set
private var ticks: Int = 0
set(value) { field = value.coerceAtMost(Int.MAX_VALUE) } // go outside
/** The current duration of the battle in seconds. */
val time: Int get() = ticks % 20
var dispatchResult = GO
val dispatches = ConcurrentLinkedDeque<BattleDispatch>()
val dispatches = ConcurrentLinkedQueue<BattleDispatch>()
val afterDispatches = mutableListOf<() -> Unit>()
val captureActions = mutableListOf<BattleCaptureAction>()
val majorBattleActions = hashMapOf<UUID, BattleMessage>()
val minorBattleActions = hashMapOf<UUID, BattleMessage>()
val contextManager = ContextManager()
/** Whether or not there is one side with at least one player, and the other only has wild Pokémon. */
val isPvW: Boolean
get() {
@@ -162,12 +136,7 @@ open class PokemonBattle(
}
/**
* Gets the first battle actor whom the given player controls, or null if there is no such actor.
*/
fun getActor(player: ServerPlayerEntity) = actors.firstOrNull { it.isForPlayer(player) }
/**
* Gets a [BattleActor] and an [ActiveBattlePokemon] from a pnx key, e.g. p2a
* Gets a BattleActor and an [ActiveBattlePokemon] from a pnx key, e.g. p2a
*
* Returns null if either the pn or x is invalid.
*/
@@ -180,27 +149,13 @@ open class PokemonBattle(
return actor to pokemon
}
/**
* Gets a [BattlePokemon] from a pnx key and uuid.
*
* Returns null if the pnx key is invalid or the uuid does not exist.
*/
fun getBattlePokemon(pnx: String, pokemonID: String): BattlePokemon {
val actor = actors.find { it.showdownId == pnx.substring(0, 2) }
?: throw IllegalStateException("Invalid pnx: $pnx - unknown actor")
return actor.pokemonList.find { it.uuid.toString() == pokemonID }
?: throw IllegalStateException("Invalid pnx: $pnx - unknown pokemon")
}
fun broadcastChatMessage(component: Text) {
chatLog.add(component)
sendSpectatorUpdate(BattleMessagePacket(component))
return actors.forEach { it.sendMessage(component) }
}
fun writeShowdownAction(vararg messages: String) {
log(messages.joinToString("\n"))
ShowdownService.service.send(battleId, messages.toList().toTypedArray())
ShowdownService.get().send(battleId, messages.toList().toTypedArray())
}
fun turn(newTurnNumber: Int) {
@@ -224,16 +179,11 @@ open class PokemonBattle(
faintedPokemons.forEach { faintedPokemon ->
for (opponentPokemon in opponentNonFaintedPokemons) {
val facedFainted = opponentPokemon.facedOpponents.contains(faintedPokemon)
val defeatProgress = DefeatEvolutionProgress()
val pokemon = opponentPokemon.effectedPokemon
if (facedFainted) {
pokemon.evolutions.forEach { evolution ->
evolution.requirements.filterIsInstance<DefeatRequirement>().forEach { defeatRequirement ->
if (defeatRequirement.target.matches(faintedPokemon.effectedPokemon)) {
val progress = pokemon.evolutionProxy.current().progressFirstOrCreate({ it is DefeatEvolutionProgress && it.currentProgress().target == defeatRequirement.target }) { DefeatEvolutionProgress() }
progress.updateProgress(DefeatEvolutionProgress.Progress(defeatRequirement.target, progress.currentProgress().amount + 1))
}
}
}
if (facedFainted && defeatProgress.shouldKeep(pokemon)) {
val progress = pokemon.evolutionProxy.current().progressFirstOrCreate({ it is DefeatEvolutionProgress && it.currentProgress().target.matches(faintedPokemon.effectedPokemon) }) { defeatProgress }
progress.updateProgress(DefeatEvolutionProgress.Progress(progress.currentProgress().target, progress.currentProgress().amount + 1))
}
val multiplier = when {
// ToDo when Exp. All is implement if enabled && !facedFainted return 2.0, probably should be a configurable value too, this will have priority over the Exp. Share
@@ -246,24 +196,13 @@ open class PokemonBattle(
if (experience > 0) {
opponent.awardExperience(opponentPokemon, experience)
}
Cobblemon.evYieldCalculator.calculate(opponentPokemon, faintedPokemon).forEach { (stat, amount) ->
Cobblemon.evYieldCalculator.calculate(opponentPokemon).forEach { (stat, amount) ->
pokemon.evs.add(stat, amount)
}
}
}
}
}
// Heal Mon if wild
actors.filter { it.type == ActorType.WILD }
.filterIsInstance<EntityBackedBattleActor<*>>()
.mapNotNull { it.entity }
.filterIsInstance<PokemonEntity>()
.forEach{it.pokemon.heal()}
actors.forEach { actor ->
actor.pokemonList.forEach { battlePokemon ->
battlePokemon.entity?.let { entity -> battlePokemon.postBattleEntityOperation(entity) }
}
}
sendUpdate(BattleEndPacket())
BattleRegistry.closeBattle(this)
}
@@ -277,27 +216,9 @@ open class PokemonBattle(
if (!mute) {
LOGGER.info(message)
}
battleLog.add(message)
}
fun saveBattleLog() {
val battleLogsDir = File("./battle_logs/")
if (!battleLogsDir.exists()) {
battleLogsDir.mkdirs()
}
val logFile = File(battleLogsDir, "$battleId.txt")
logFile.bufferedWriter().use { out ->
battleLog.forEach {
out.write(it)
out.newLine()
}
}
LOGGER.info("Saved battle log as $battleId.txt")
}
fun sendUpdate(packet: NetworkPacket<*>) {
fun sendUpdate(packet: NetworkPacket) {
actors.forEach { it.sendUpdate(packet) }
sendSpectatorUpdate(packet)
}
@@ -310,33 +231,27 @@ open class PokemonBattle(
* @param opponentPacket The packet sent to the opposing actors.
* @param spectatorsAsAlly If the spectators receive the [allyPacket] or the [opponentPacket], default is false.
*/
fun sendSidedUpdate(source: BattleActor, allyPacket: NetworkPacket<*>, opponentPacket: NetworkPacket<*>, spectatorsAsAlly: Boolean = false) {
fun sendSidedUpdate(source: BattleActor, allyPacket: NetworkPacket, opponentPacket: NetworkPacket, spectatorsAsAlly: Boolean = false) {
source.getSide().actors.forEach { it.sendUpdate(allyPacket) }
source.getSide().getOppositeSide().actors.forEach { it.sendUpdate(opponentPacket) }
sendSpectatorUpdate(if (spectatorsAsAlly) allyPacket else opponentPacket)
}
fun sendToActors(packet: NetworkPacket<*>) {
CobblemonNetwork.sendPacketToPlayers(actors.flatMap { it.getPlayerUUIDs().mapNotNull { it.getPlayer() } }, packet)
fun sendToActors(packet: NetworkPacket) {
CobblemonNetwork.sendToPlayers(actors.flatMap { it.getPlayerUUIDs().mapNotNull { it.getPlayer() } }, packet)
}
fun sendSplitUpdate(privateActor: BattleActor, publicPacket: NetworkPacket<*>, privatePacket: NetworkPacket<*>) {
fun sendSplitUpdate(privateActor: BattleActor, publicPacket: NetworkPacket, privatePacket: NetworkPacket) {
actors.forEach { it.sendUpdate(if (it == privateActor) privatePacket else publicPacket) }
sendSpectatorUpdate(publicPacket)
}
fun sendSpectatorUpdate(packet: NetworkPacket<*>) {
CobblemonNetwork.sendPacketToPlayers(spectators.mapNotNull { it.getPlayer() }, packet)
fun sendSpectatorUpdate(packet: NetworkPacket) {
CobblemonNetwork.sendToPlayers(spectators.mapNotNull { it.getPlayer() }, packet)
}
fun dispatch(dispatcher: () -> DispatchResult) {
dispatches.add(BattleDispatch { dispatcher() })
}
fun dispatchToFront(dispatcher: () -> DispatchResult) {
dispatches.addFirst(BattleDispatch { dispatcher() })
}
fun dispatchGo(dispatcher: () -> Unit) {
@@ -368,37 +283,23 @@ open class PokemonBattle(
dispatches.add(dispatcher)
}
fun dispatchToFront(dispatcher: BattleDispatch) {
dispatches.addFirst(dispatcher)
}
fun doWhenClear(action: () -> Unit) {
afterDispatches.add(action)
}
fun tick() {
try {
while (dispatchResult.canProceed()) {
val dispatch = dispatches.poll() ?: break
dispatchResult = dispatch(this)
}
if (dispatches.isEmpty()) {
afterDispatches.toList().forEach { it() }
afterDispatches.clear()
}
} catch (e: Exception) {
LOGGER.error("Exception while ticking a battle. Saving battle log.", e)
val message = battleLang("crash").red()
this.actors.filterIsInstance<PlayerBattleActor>().forEach { it.entity?.sendMessage(message) }
this.saveBattleLog()
this.stop()
return
while (dispatchResult.canProceed()) {
val dispatch = dispatches.poll() ?: break
dispatchResult = dispatch(this)
}
if (started) {
ticks++
if (isPvW && !ended && dispatches.isEmpty()) checkFlee()
if (dispatches.isEmpty()) {
afterDispatches.toList().forEach { it() }
afterDispatches.clear()
}
if (started && isPvW && !ended) {
checkFlee()
}
}
@@ -421,14 +322,8 @@ open class PokemonBattle(
nearestPlayerActorDistance != null && nearestPlayerActorDistance < pokemonActor.fleeDistance
}
}
if (wildPokemonOutOfRange) {
// Heal Wild Pokemon
actors.filter { it.type == ActorType.WILD }
.filterIsInstance<EntityBackedBattleActor<*>>()
.mapNotNull { it.entity }
.filterIsInstance<PokemonEntity>()
.forEach{it.pokemon.heal()}
CobblemonEvents.BATTLE_FLED.post(BattleFledEvent(this, actors.asSequence().filterIsInstance<PlayerBattleActor>().iterator().next()))
actors.filterIsInstance<EntityBackedBattleActor<*>>().mapNotNull { it.entity }.forEach { it.sendMessage(battleLang("flee").yellow()) }
stop()
}
@@ -440,24 +335,13 @@ open class PokemonBattle(
}
fun checkForInputDispatch() {
if (checkForfeit()) return // ignore actors that are still choosing, their choices don't matter anymore
val readyToInput = (actors.any { !it.mustChoose && it.responses.isNotEmpty() } && actors.none { it.mustChoose })
val readyToInput = actors.any { !it.mustChoose && it.responses.isNotEmpty() } && actors.none { it.mustChoose }
if (readyToInput && captureActions.isEmpty()) {
actors.filter { it.responses.isNotEmpty() }.forEach { it.writeShowdownResponse() }
actors.forEach { it.responses.clear() ; it.request = null }
}
}
/** Forces Showdown to end the battle when a [BattleActor] chooses to forfeit. */
private fun checkForfeit(): Boolean {
val forfeit = actors.find { it.responses.any { it is ForfeitActionResponse } }
return forfeit?.let {
this.dispatchWaiting { this.broadcastChatMessage(battleLang("forfeit", it.getName()).red()) }
writeShowdownAction(">forcelose ${it.showdownId}")
true
} ?: false
}
/**
* Creates a [Text] representation of an error to interpret a battle message.
* This also logs the error, the goal of this function is to make sure users see missing interpretations and report them to us.
@@ -489,12 +373,4 @@ open class PokemonBattle(
return Text.literal("Missing interpretation on '${publicMessage.id}' action please report to the developers").red()
}
fun addQueryFunctions(queryStruct: QueryStruct): QueryStruct {
queryStruct.addFunction("pvp") { DoubleValue(isPvP) }
queryStruct.addFunction("pvn") { DoubleValue(isPvN) }
queryStruct.addFunction("pvw") { DoubleValue(isPvW) }
queryStruct.addFunction("has_rule") { params -> DoubleValue(params.getString(0) in format.ruleSet) }
return queryStruct
}
}
}
@@ -8,12 +8,9 @@
package com.cobblemon.mod.common.api.battles.model.actor
import com.cobblemon.mod.common.Cobblemon.LOGGER
import com.cobblemon.mod.common.api.battles.model.ai.BattleAI
import com.cobblemon.mod.common.api.net.NetworkPacket
import com.cobblemon.mod.common.battles.PassActionResponse
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
import com.cobblemon.mod.common.exception.IllegalActionChoiceException
import com.cobblemon.mod.common.net.messages.client.battle.BattleMakeChoicePacket
import java.util.UUID
@@ -22,24 +19,11 @@ abstract class AIBattleActor(
pokemonList: List<BattlePokemon>,
val battleAI: BattleAI
) : BattleActor(gameId, pokemonList.toMutableList()) {
override fun sendUpdate(packet: NetworkPacket<*>) {
override fun sendUpdate(packet: NetworkPacket) {
super.sendUpdate(packet)
if (packet is BattleMakeChoicePacket) {
this.onChoiceRequested()
}
}
/**
* Called when the AI is requested to make a choice.
*/
open fun onChoiceRequested() {
try {
setActionResponses(request!!.iterate(this.activePokemon, battleAI::choose))
} catch (exception: IllegalActionChoiceException) {
LOGGER.error("AI was unable to choose a move, we're going to need to pass!")
exception.printStackTrace()
setActionResponses(request!!.iterate(this.activePokemon) { _, _, _ -> PassActionResponse })
setActionResponses(request!!.iterate(this.activePokemon, battleAI::choose) )
}
}
}
@@ -11,13 +11,12 @@ package com.cobblemon.mod.common.api.battles.model.actor
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
import com.cobblemon.mod.common.api.net.NetworkPacket
import com.cobblemon.mod.common.battles.ActiveBattlePokemon
import com.cobblemon.mod.common.battles.ForcePassActionResponse
import com.cobblemon.mod.common.battles.BallActionResponse
import com.cobblemon.mod.common.battles.ShowdownActionRequest
import com.cobblemon.mod.common.battles.ShowdownActionResponse
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.exception.IllegalActionChoiceException
import com.cobblemon.mod.common.net.messages.client.battle.BattleApplyPassResponsePacket
import com.cobblemon.mod.common.net.messages.client.battle.BattleMakeChoicePacket
import com.cobblemon.mod.common.net.messages.client.battle.BattleMessagePacket
import java.util.UUID
@@ -41,24 +40,11 @@ abstract class BattleActor(
var request: ShowdownActionRequest? = null
var responses = mutableListOf<ShowdownActionResponse>()
val expectingPassActions = mutableListOf<ShowdownActionResponse>()
var expectingCaptureActions = 0
var mustChoose = false
/** For when battles start, it's the number of Pokémon that are still in the process of being sent out (animation wise) */
var stillSendingOutCount = 0
abstract val type: ActorType
fun canFitForcedAction() = mustChoose && request?.let { request ->
val countMovable = (request.active?.count() ?: 0) - request.forceSwitch.count { it }
return@let countMovable > expectingPassActions.size && !battle.ended
} ?: false
fun forceChoose(response: ShowdownActionResponse) {
expectingPassActions.add(response)
sendUpdate(BattleApplyPassResponsePacket())
}
fun getSide() = if (this in battle.side1.actors) battle.side1 else battle.side2
open fun getPlayerUUIDs(): Iterable<UUID> = emptyList()
@@ -74,7 +60,7 @@ abstract class BattleActor(
val requestActive = request.active
if (requestActive == null || requestActive.isEmpty() || request.wait) {
this.request = null
expectingPassActions.clear()
expectingCaptureActions = 0
return
}
}
@@ -92,24 +78,23 @@ abstract class BattleActor(
fun setActionResponses(responses: List<ShowdownActionResponse>) {
val request = request ?: return
val originalPassActions = expectingPassActions.toList()
val originalCaptureActions = expectingCaptureActions
responses.forEachIndexed { index, response ->
val activeBattlePokemon = activePokemon.let { if (it.size > index) it[index] else return }
val showdownMoveSet = request.active?.let { if (it.size > index) it[index] else null }
val forceSwitch = request.forceSwitch.let { if (it.size > index) it[index] else false }
if (!response.isValid(activeBattlePokemon, showdownMoveSet, forceSwitch)) {
expectingPassActions.clear()
expectingPassActions.addAll(originalPassActions)
expectingCaptureActions = originalCaptureActions
throw IllegalActionChoiceException(this, "Invalid action choice for ${activeBattlePokemon.battlePokemon!!.getName().string}: $response")
} else if (response is ForcePassActionResponse) {
this.responses.add(expectingPassActions.removeAt(0))
} else {
this.responses.add(response)
} else if (response is BallActionResponse) {
expectingCaptureActions--
}
this.responses.add(response)
}
if (expectingPassActions.size > 0) {
if (expectingCaptureActions > 0) {
throw IllegalActionChoiceException(this, "Invalid action choice: a capture was expected. Are you hacking me?")
}
expectingCaptureActions = originalCaptureActions
mustChoose = false
battle.checkForInputDispatch()
}
@@ -125,7 +110,7 @@ abstract class BattleActor(
}
responses.clear()
request = null
expectingPassActions.clear()
expectingCaptureActions = 0
battle.writeShowdownAction(">$showdownId ${showdownMessages.joinToString()}")
}
@@ -144,5 +129,5 @@ abstract class BattleActor(
sendUpdate(BattleMessagePacket(component))
}
open fun awardExperience(battlePokemon: BattlePokemon, experience: Int) {}
open fun sendUpdate(packet: NetworkPacket<*>) {}
open fun sendUpdate(packet: NetworkPacket) {}
}
@@ -1,106 +0,0 @@
/*
* 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.berry
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.berry.spawncondition.BerrySpawnCondition
import com.cobblemon.mod.common.api.data.JsonDataRegistry
import com.cobblemon.mod.common.api.mulch.MulchVariant
import com.cobblemon.mod.common.api.pokemon.stats.Stat
import com.cobblemon.mod.common.api.pokemon.status.Status
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.net.messages.client.data.BerryRegistrySyncPacket
import com.cobblemon.mod.common.pokemon.adapters.CobblemonStatTypeAdapter
import com.cobblemon.mod.common.util.adapters.*
import com.cobblemon.mod.common.util.cobblemonResource
import com.google.gson.GsonBuilder
import com.google.gson.reflect.TypeToken
import java.awt.Color
import net.minecraft.predicate.NumberRange
import net.minecraft.registry.RegistryKeys
import net.minecraft.registry.tag.TagKey
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.util.math.Vec3d
import net.minecraft.world.biome.Biome
/**
* The data registry for [Berry].
*
* @author Licious
* @since November 28th, 2022
*/
object Berries : JsonDataRegistry<Berry> {
override val id: Identifier = cobblemonResource("berries")
override val type: ResourceType = ResourceType.SERVER_DATA
override val observable = SimpleObservable<Berries>()
override val gson = GsonBuilder()
.disableHtmlEscaping()
.setPrettyPrinting()
.registerTypeAdapter(MulchVariant::class.java, MulchVariantAdapter)
.registerTypeAdapter(NumberRange.FloatRange::class.java, FloatNumberRangeAdapter)
.registerTypeAdapter(Status::class.java, StatusAdapter)
.registerTypeAdapter(TypeToken.getParameterized(Collection::class.java, Box::class.java).type, BoxCollectionAdapter)
.registerTypeAdapter(Box::class.java, BoxAdapter)
.registerTypeAdapter(Vec3d::class.java, VerboseVec3dAdapter)
.registerTypeAdapter(Identifier::class.java, IdentifierAdapter)
.registerTypeAdapter(GrowthFactor::class.java, CobblemonGrowthFactorAdapter)
.registerTypeAdapter(IntRange::class.java, VerboseIntRangeAdapter)
.registerTypeAdapter(Color::class.java, LiteralHexColorAdapter)
.registerTypeAdapter(Stat::class.java, CobblemonStatTypeAdapter)
.registerTypeAdapter(TypeToken.getParameterized(TagKey::class.java, Biome::class.java).type, TagKeyAdapter(RegistryKeys.BIOME))
.registerTypeAdapter(BerrySpawnCondition::class.java, CobblemonBerrySpawnConditionAdapter)
.create()
override val typeToken: TypeToken<Berry> = TypeToken.get(Berry::class.java)
override val resourcePath = "berries"
private val berries = hashMapOf<Identifier, Berry>()
override fun reload(data: Map<Identifier, Berry>) {
this.berries.clear()
data.forEach { (identifier, berry) ->
try {
berry.identifier = identifier
berry.validate()
this.berries[identifier] = berry
} catch (e: Exception) {
Cobblemon.LOGGER.error("Skipped loading the {} berry", identifier, e)
}
}
Cobblemon.LOGGER.info("Loaded {} berries", this.berries.size)
this.observable.emit(this)
}
override fun sync(player: ServerPlayerEntity) {
BerryRegistrySyncPacket(this.all()).sendToPlayer(player)
}
fun all() = this.berries.values.toList()
/**
* Gets a berry if loaded.
*
* @param identifier The identifier of the berry.
* @return The [Berry] if loaded otherwise null.
*/
fun getByIdentifier(identifier: Identifier): Berry? = this.berries[identifier]
/**
* Gets a berry if loaded.
*
* @param name The path of the identifier of the berry under the [Cobblemon.MODID] namespace.
* @return The [Berry] if loaded otherwise null.
*/
fun getByName(name: String): Berry? = this.getByIdentifier(cobblemonResource(name))
}
@@ -1,347 +0,0 @@
/*
* 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.berry
import com.cobblemon.mod.common.CobblemonBlocks
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.api.berry.spawncondition.BerrySpawnCondition
import com.cobblemon.mod.common.api.events.CobblemonEvents
import com.cobblemon.mod.common.api.events.berry.BerryYieldCalculationEvent
import com.cobblemon.mod.common.api.mulch.MulchVariant
import com.cobblemon.mod.common.block.BerryBlock
import com.cobblemon.mod.common.block.entity.BerryBlockEntity
import com.cobblemon.mod.common.item.BerryItem
import com.cobblemon.mod.common.pokemon.Nature
import com.cobblemon.mod.common.util.readBox
import com.cobblemon.mod.common.util.writeBox
import com.google.gson.annotations.SerializedName
import java.awt.Color
import java.util.EnumSet
import kotlin.math.min
import net.minecraft.block.Block
import net.minecraft.block.BlockState
import net.minecraft.client.model.ModelPart
import net.minecraft.entity.LivingEntity
import net.minecraft.network.PacketByteBuf
import net.minecraft.registry.tag.TagKey
import net.minecraft.util.Identifier
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.Box
import net.minecraft.util.math.Vec3d
import net.minecraft.util.shape.VoxelShape
import net.minecraft.util.shape.VoxelShapes
import net.minecraft.world.World
import net.minecraft.world.biome.Biome
/**
* Represents the data behind a berry.
*
* @property identifier The [Identifier] of this berry.
* @property baseYield The [IntRange] possible for the berry tree before [bonusYield] is calculated.
* @property preferredBiomeTags The [TagKey]s of the berries preffered biomes. Determines spawning and yield
* @property growthTime The [IntRange] possible in minutes for how long the berry tree takes to grow.
* @property refreshRate The [IntRange] possible in minutes for how long the berry tree takes to regrow its berries once it has been harvested.
* @depreciated @property lifeCycles The [IntRange] possible for the berry to live for between harvests.
* @property favoriteMulches The types of mulches that benefit this berries yield
* @property growthFactors An array of [GrowthFactor]s that will affect this berry. The client is not aware of these.
* @property mutations A map of the partner berry as the key and the value as the resulting mutation with this berry.
* @property growthPoints A collection of [GrowthPoint]s for the berry flowers and fruit.
* @property sproutShapeBoxes A collection of [Box]es that make up the tree [VoxelShape] during the sprouting stages.
* @property matureShapeBoxes A collection of [Box]es that make up the tree [VoxelShape] during the mature stages.
* @property flavors The [Flavor] values.
* @property tintIndexes Determines tints at specific indexes if any.
* @property flowerModelIdentifier The [Identifier] for the model of the berry in flower form.
* @property flowerTexture The [Identifier] for the texture of the berry in flower form. This is resolved into a [ModelPart] on the client.
* @property fruitModelIdentifier The [Identifier] for the model of the berry in flower form. This is resolved into a [ModelPart] on the client.
* @property fruitTexture The [Identifier] for the texture of the berry in flower form.
*
* @throws IllegalArgumentException if the any yield range argument is not a positive range.
*/
class Berry(
identifier: Identifier,
val baseYield: IntRange,
val preferredBiomeTags: List<TagKey<Biome>>,
val growthTime: IntRange,
val refreshRate: IntRange,
//val lifeCycles: IntRange,
val favoriteMulches: EnumSet<MulchVariant>,
val growthFactors: Collection<GrowthFactor>,
val spawnConditions: List<BerrySpawnCondition>,
var growthPoints: Array<GrowthPoint>,
val randomizedGrowthPoints: Boolean = true,
val mutations: Map<Identifier, Identifier>,
@SerializedName("sproutShape")
private val sproutShapeBoxes: Collection<Box>,
@SerializedName("matureShape")
private val matureShapeBoxes: Collection<Box>,
private val flavors: Map<Flavor, Int>,
val tintIndexes: Map<Int, Color>,
@SerializedName("flowerModel")
val flowerModelIdentifier: Identifier,
val flowerTexture: Identifier,
@SerializedName("fruitModel")
val fruitModelIdentifier: Identifier,
val fruitTexture: Identifier,
val weight: Float
) {
@Transient
var identifier: Identifier = identifier
internal set
@Transient
private lateinit var shapedFlower: HashMap<Int, VoxelShape>
@Transient
private lateinit var shapedFruit: HashMap<Int, VoxelShape>
/**
* The [VoxelShape] of the tree during the sprouting stages.
*/
@Transient
lateinit var sproutShape: VoxelShape
private set
/**
* The [VoxelShape] of the tree during the mature stages.
*/
@Transient
lateinit var matureShape: VoxelShape
private set
init {
this.validate()
}
/**
* Finds the [BerryItem] that uses this berry for data.
*
* @return The [BerryItem] if existing.
*/
fun item(): BerryItem? = CobblemonItems.berries()[this.identifier]
/**
* Finds the [BerryBlock] that uses this berry for data.
*
* @return The [BerryBlock] if existing.
*/
fun block(): BerryBlock? = CobblemonBlocks.berries()[this.identifier]
/**
* Query the value of a certain flavor.
*
* @param flavor The [Flavor] being queried.
* @return The value if any or 0.
*/
fun flavor(flavor: Flavor): Int = this.flavors[flavor] ?: 0
fun dislikedBy(nature: Nature): Boolean {
val dislikedFlavor = nature.dislikedFlavor ?: return false
return flavor(dislikedFlavor) > 0
}
/**
* Calculates the yield for a berry tree being planted or replanted after a life cycle.
* Triggers [BerryYieldCalculationEvent].
*
* @param world The [World] the tree is present in.
* @param state The [BlockState] of the tree.
* @param pos The [BlockPos] of the tree.
* @param placer The [LivingEntity] tending to the tree, if any.
* @return The total berry stack count.
*/
fun calculateYield(world: World, state: BlockState, pos: BlockPos, placer: LivingEntity? = null): Int {
val base = this.baseYield.random()
val bonus = this.bonusYield(world, state, pos)
var yield = base + bonus.first
val treeEntity = world.getBlockEntity(pos) as BerryBlockEntity
if (BerryBlock.getMulch(state) == MulchVariant.RICH) {
yield = min(yield + 1, maxYield())
treeEntity.decrementMulchDuration(world, pos, state)
}
val event = BerryYieldCalculationEvent(this, world, state, pos, placer, yield, bonus.second)
CobblemonEvents.BERRY_YIELD.post(event) { yield = it.yield }
return yield
}
/**
* Calculates and returns the minimum possible yield by summing [baseYield] and [growthFactors] minimum values.
*
* @return The minimum possible yield.
*/
fun minYield() = this.baseYield.first + this.growthFactors.sumOf { it.minYield() }
/**
* Calculates and returns the maximum possible yield by summing [baseYield] and [growthFactors] max values.
*
* @return The maximum possible yield.
*/
fun maxYield() = this.baseYield.last + this.growthFactors.sumOf { it.maxYield() }
/**
* Checks if this berry can mutate with the given [partner].
* For the berry the mutations may produce use [mutationWith].
*
* @param partner The [Berry] being checked as a possible mutation partner.
* @return If a mutation is possible.
*/
fun canMutateWith(partner: Berry) = this.mutationWith(partner) != null
/**
* Query for the possible mutation with the given [partner].
*
* @param partner The [Berry] being mutated with.
* @return The resulting [Berry] if the mutation is possible.
*/
fun mutationWith(partner: Berry): Berry? {
val berryIdentifier = this.mutations[partner.identifier] ?: return null
return Berries.getByIdentifier(berryIdentifier)
}
/**
* Query for a possible partner to mutate into the given [resulting].
*
* @param resulting The [Berry] the mutation should result in.
* @return The [Berry] that mutates with this berry into the given [resulting] if possible.
*/
fun partnerForMutation(resulting: Berry): Berry? {
return this.mutations.firstNotNullOfOrNull { (partner, result) ->
if (result == resulting.identifier)
Berries.getByIdentifier(partner)
else
null
}
}
// A cheat since gson doesn't invoke init block
internal fun validate() {
if (this.baseYield.first < 0 || this.baseYield.last < 0) {
throw IllegalArgumentException("A berry base yield must be a positive range")
}
if (this.growthTime.first < 0 || this.growthTime.last < 0) {
throw IllegalArgumentException("The growth time must be a positive range")
}
if (this.refreshRate.first < 0 || this.refreshRate.last < 0) {
throw IllegalArgumentException("The refresh rate must be a positive range")
}
/*
if (this.lifeCycles.first < 0 || this.lifeCycles.last < 0) {
throw IllegalArgumentException("A berry life cycle must be a positive range")
}
*/
this.growthFactors.forEach { it.validateArguments() }
val maxYield = this.maxYield()
if (this.growthPoints.size < maxYield) {
throw IllegalArgumentException("Anchor points must have enough elements for the max possible yield of $maxYield you've provided ${this.growthPoints.size} points")
}
this.shapedFlower = hashMapOf()
this.shapedFruit = hashMapOf()
this.sproutShape = this.createAndUniteShapes(this.sproutShapeBoxes)
this.matureShape = this.createAndUniteShapes(this.matureShapeBoxes)
}
internal fun encode(buffer: PacketByteBuf) {
buffer.writeIdentifier(this.identifier)
buffer.writeInt(this.baseYield.first)
buffer.writeInt(this.baseYield.last)
buffer.writeEnumSet(favoriteMulches, MulchVariant::class.java)
//buffer.writeInt(this.lifeCycles.first)
//buffer.writeInt(this.lifeCycles.last)
buffer.writeInt(this.growthTime.first)
buffer.writeInt(this.growthTime.last)
buffer.writeInt(this.refreshRate.first)
buffer.writeInt(this.refreshRate.last)
buffer.writeCollection(this.growthPoints.toList()) { writer, value ->
writer.writeDouble(value.position.x)
writer.writeDouble(value.position.y)
writer.writeDouble(value.position.z)
writer.writeDouble(value.rotation.x)
writer.writeDouble(value.rotation.y)
writer.writeDouble(value.rotation.z)
}
buffer.writeBoolean(this.randomizedGrowthPoints)
buffer.writeMap(this.mutations, { writer, key -> writer.writeIdentifier(key) }, { writer, value -> writer.writeIdentifier(value) })
buffer.writeCollection(this.sproutShapeBoxes) { writer, value ->
writer.writeBox(value)
}
buffer.writeCollection(this.matureShapeBoxes) { writer, value ->
writer.writeBox(value)
}
buffer.writeMap(this.flavors, { writer, key -> writer.writeEnumConstant(key) }, { writer, value -> writer.writeInt(value) })
buffer.writeMap(this.tintIndexes, { writer, key -> writer.writeInt(key) }, { writer, value -> writer.writeInt(value.rgb) })
buffer.writeIdentifier(this.flowerModelIdentifier)
buffer.writeIdentifier(this.flowerTexture)
buffer.writeIdentifier(this.fruitModelIdentifier)
buffer.writeIdentifier(this.fruitTexture)
}
/**
* Calculates the bonus yield for the berry tree.
*
* @param world The [World] the tree is present in.
* @param state The [BlockState] of the tree.
* @param pos The [BlockPos] of the tree.
* @return The bonus yield, the growth factors that passed.
*/
private fun bonusYield(world: World, state: BlockState, pos: BlockPos): Pair<Int, Collection<GrowthFactor>> {
var bonus = 0
val passed = arrayListOf<GrowthFactor>()
val mulchVariant = BerryBlock.getMulch(state)
val hasBiomeMulch = mulchVariant in favoriteMulches
this.growthFactors.forEach { factor ->
if (factor.isValid(world, state, pos)) {
bonus += factor.yield()
passed += factor
} else if (hasBiomeMulch) {
bonus += factor.yield()
}
}
return bonus to passed
}
private fun createAndUniteShapes(boxes: Collection<Box>): VoxelShape {
var shape: VoxelShape? = null
boxes.forEach { box ->
shape = if (shape == null) {
Block.createCuboidShape(box.minX, box.minY, box.minZ, box.maxX, box.maxY, box.maxZ)
} else {
VoxelShapes.union(shape, Block.createCuboidShape(box.minX, box.minY, box.minZ, box.maxX, box.maxY, box.maxZ))
}
}
return shape ?: VoxelShapes.fullCube()
}
companion object {
internal fun decode(buffer: PacketByteBuf): Berry {
val identifier = buffer.readIdentifier()
val baseYield = IntRange(buffer.readInt(), buffer.readInt())
val favMulchs = buffer.readEnumSet(MulchVariant::class.java)
//val lifeCycles = IntRange(buffer.readInt(), buffer.readInt())
val growthTime = IntRange(buffer.readInt(), buffer.readInt())
val refreshRate = IntRange(buffer.readInt(), buffer.readInt())
val growthPoints = buffer.readList { reader ->
GrowthPoint(Vec3d(reader.readDouble(), reader.readDouble(), reader.readDouble()), Vec3d(reader.readDouble(), reader.readDouble(), reader.readDouble()))
}.toTypedArray()
val randomizedGrowthPoints = buffer.readBoolean()
val mutations = buffer.readMap({ reader -> reader.readIdentifier() }, { reader -> reader.readIdentifier() })
val sproutShapeBoxes = buffer.readList { it.readBox() }
val matureShapeBoxes = buffer.readList { it.readBox() }
val flavors = buffer.readMap({ reader -> reader.readEnumConstant(Flavor::class.java) }, { reader -> reader.readInt() })
val tintIndexes = buffer.readMap({ reader -> reader.readInt() }, { reader -> Color(reader.readInt()) })
val flowerModelIdentifier = buffer.readIdentifier()
val flowerTexture = buffer.readIdentifier()
val fruitModelIdentifier = buffer.readIdentifier()
val fruitTexture = buffer.readIdentifier()
return Berry(identifier, baseYield, emptyList(), growthTime, refreshRate, favMulchs, emptySet(), emptyList(), growthPoints, randomizedGrowthPoints, mutations, sproutShapeBoxes, matureShapeBoxes, flavors, tintIndexes, flowerModelIdentifier, flowerTexture, fruitModelIdentifier, fruitTexture, 0F)
}
}
}
@@ -1,47 +0,0 @@
/*
* 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.berry
import com.cobblemon.mod.common.CobblemonBlocks
import com.cobblemon.mod.common.block.BerryBlock
import com.cobblemon.mod.common.world.feature.BerryGroveFeature
import com.google.common.cache.CacheBuilder
import com.google.common.cache.CacheLoader
import com.google.common.cache.LoadingCache
import net.minecraft.registry.entry.RegistryEntry
import net.minecraft.world.biome.Biome
object BerryHelper {
private val CACHE_LOADER = object : CacheLoader<RegistryEntry<Biome>, List<BerryBlock>>() {
override fun load(key: RegistryEntry<Biome>): List<BerryBlock> {
return naturalBerries.filter { berryBlock ->
val berry = berryBlock.berry()
berry?.spawnConditions?.any { it.canSpawn(berry, key) } ?: false
}
}
}
private val naturalBerries = CobblemonBlocks.berries().values.filter {
(it.berry()?.spawnConditions?.size ?: 0) > 0
}
private val validBerryCache: LoadingCache<RegistryEntry<Biome>, List<BerryBlock>> = CacheBuilder.newBuilder()
.maximumSize(4)
.build(CACHE_LOADER)
fun getBerriesForBiome(biome: RegistryEntry<Biome>): List<BerryBlock> {
return validBerryCache.get(biome)
}
fun getNaturallyGeneratingBerries(): List<BerryBlock> {
return naturalBerries
}
}

Some files were not shown because too many files have changed in this diff Show More