Compare commits

...
Author SHA1 Message Date
tmetcalfe89 380b6d6cee flexibled the passive options
- Fainting doesn't passively heal unless both percent and timer are greater than 0.
- Health doesn't passively heal unless both percent and timer are greater than 0.
- New option to disable passively healing statuses.
2024-08-27 21:13:02 -07:00
amo b4919d18d1 🌠 Fix: Fix friendship only ever being updated clientside & chance inverted check 2024-08-25 14:05:26 +01:00
amo d9e8283743 🌠 Chore: Remove strict inequality from bobber rendering check 2024-08-25 12:59:15 +01:00
Paul b8d913bd2b Fixed weird waterlogging issues in pasture and PC 2024-08-12 15:34:57 +10:00
Paul 9339d91cbb Missing licenses 2024-08-12 13:47:15 +10:00
Paul 8b255c784a Fixed monitor block rotations from structures maybe 2024-08-11 18:17:27 +10:00
Hiroku 4cdea8d1fc Merge branch 'sprites' into 'sega_bass_pro_fishing_2'
Gui Sprites

See merge request cable-mc/cobblemon!1102
2024-08-10 00:43:54 +00:00
WaterpickerandHiroku 1b6139b386 Gui Sprites 2024-08-10 00:43:54 +00:00
Apion 2bd1382b85 Merge branch 'feature/simplify-modelloader-mixin' into 'sega_bass_pro_fishing_2'
Stop throwing errors in the model loader that generate misleading crash-reports

See merge request cable-mc/cobblemon!1110
2024-08-08 16:11:08 +00:00
PolymetaandApion 7791e72f72 Stop throwing errors in the model loader that generate misleading crash-reports 2024-08-08 16:11:07 +00:00
15 changed files with 256 additions and 170 deletions
+1
View File
@@ -6,6 +6,7 @@
- Fixed a scenario where a Pokémon that rolled to spawn with a special Tera type sometimes has a Tera type that is already a part of their natural typing.
- Fixed PokemonProperty argument suggestions for ``tera`` and ``tera_type`` not suggesting ``stellar``.
- Fixed being able to stack Relic Coin Pouches on top of each other.
- Fixed Model loader generating misleading crash-reports when client is crashing
### Additions
- Added Pokémon (and item) fishing using modified fishing rods - Poké Rods! You'll need a Poké Rod smithing template, a fishing rod, and some type of Poké Ball. Each Poké Ball makes a differently themed rod. Why not?
@@ -9,7 +9,6 @@
package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.client.CobblemonBakingOverrides;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import net.minecraft.client.color.block.BlockColors;
@@ -20,8 +19,6 @@ import net.minecraft.client.resources.model.ModelResourceLocation;
import net.minecraft.client.resources.model.UnbakedModel;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.profiling.ProfilerFiller;
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;
@@ -31,16 +28,10 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(ModelBakery.class)
public abstract class ModelLoaderMixin {
@Shadow abstract UnbakedModel getModel(ResourceLocation resourceLocation);
@Shadow protected abstract void registerModel(ModelResourceLocation modelId, UnbakedModel unbakedModel);
@Final
@Shadow
private Map<ResourceLocation, UnbakedModel> unbakedCache;
@Final
@Shadow
private static Logger LOGGER;
@Inject(
method = "<init>",
at = @At("TAIL")
@@ -51,19 +42,8 @@ public abstract class ModelLoaderMixin {
Map<ResourceLocation, List<BlockStateModelLoader.LoadedJson>> blockStates,
CallbackInfo ci) {
CobblemonBakingOverrides.INSTANCE.getModels().forEach(bakingOverride -> {
try {
BlockModel unbakedModel = this.loadBlockModel(bakingOverride.getModelLocation());
this.unbakedCache.put(bakingOverride.getModelIdentifier().id(), unbakedModel);
this.registerModel(bakingOverride.getModelIdentifier(), unbakedModel);
} catch (IOException e) {
LOGGER.error("Error loading a Cobblemon BakedModel:", e);
throw new RuntimeException(e);
}
var unbakedModel = this.getModel(bakingOverride.getModelLocation());
this.registerModel(bakingOverride.getModelIdentifier(), unbakedModel);
});
}
@Shadow
private BlockModel loadBlockModel(ResourceLocation id) throws IOException {
return null;
}
}
@@ -10,7 +10,9 @@ package com.cobblemon.mod.common.api.gui
import com.cobblemon.mod.common.api.text.font
import com.cobblemon.mod.common.client.gui.battle.BattleOverlay.Companion.PORTRAIT_DIAMETER
import com.cobblemon.mod.common.client.render.SpriteType
import com.cobblemon.mod.common.client.render.models.blockbench.PosableState
import com.cobblemon.mod.common.client.render.models.blockbench.repository.PokemonModelRepository
import com.cobblemon.mod.common.client.render.models.blockbench.repository.RenderContext
import com.cobblemon.mod.common.client.render.models.blockbench.repository.VaryingModelRepository
import com.cobblemon.mod.common.entity.PoseType
@@ -201,58 +203,71 @@ fun drawPosablePortrait(
headYaw: Float = 0F,
headPitch: Float = 0F
) {
val model = repository.getPoser(identifier, aspects)
state.currentAspects = aspects
state.currentModel = model
val texture = repository.getTexture(identifier, aspects, state.animationSeconds)
val context = RenderContext()
model.context = context
repository.getTextureNoSubstitute(identifier, aspects, 0f).let { context.put(RenderContext.TEXTURE, it) }
context.put(RenderContext.SCALE, contextScale)
context.put(RenderContext.SPECIES, identifier)
context.put(RenderContext.ASPECTS, aspects)
context.put(RenderContext.POSABLE_STATE, state)
val renderType = RenderType.entityCutout(texture)
RenderSystem.applyModelViewMatrix()
val quaternion1 = Axis.YP.rotationDegrees(-32F * if (reversed) -1F else 1F)
val quaternion2 = Axis.XP.rotationDegrees(5F)
val originalPose = state.currentPose
state.setPoseToFirstSuitable(PoseType.PORTRAIT)
state.updatePartialTicks(partialTicks)
model.applyAnimations(null, state, limbSwing, limbSwingAmount, ageInTicks, headYaw, headPitch)
originalPose?.let { state.setPose(it) }
matrixStack.pushPose()
matrixStack.translate(0.0, PORTRAIT_DIAMETER.toDouble() + 2.0, 0.0)
matrixStack.scale(scale, scale, -scale)
matrixStack.translate(0.0, -PORTRAIT_DIAMETER / 18.0, 0.0)
matrixStack.translate(model.portraitTranslation.x * if (reversed) -1F else 1F, model.portraitTranslation.y, model.portraitTranslation.z - 4)
matrixStack.scale(model.portraitScale, model.portraitScale, 1 / model.portraitScale)
matrixStack.mulPose(quaternion1) // TODO (techdaan): correct?
matrixStack.mulPose(quaternion2)
val light1 = Vector3f(0.2F, 1.0F, -1.0F)
val light2 = Vector3f(0.1F, 0.0F, 8.0F)
RenderSystem.setShaderLights(light1, light2)
quaternion1.conjugate()
val sprite = repository.getSprite(identifier, aspects, SpriteType.PORTRAIT);
val immediate = Minecraft.getInstance().renderBuffers().bufferSource()
val buffer = immediate.getBuffer(renderType)
val packedLight = LightTexture.pack(11, 7)
if(sprite == null) {
model.withLayerContext(immediate, state, repository.getLayers(identifier, aspects)) {
model.render(context, matrixStack, buffer, packedLight, OverlayTexture.NO_OVERLAY, -0x1)
immediate.endBatch()
val model = repository.getPoser(identifier, aspects)
state.currentAspects = aspects
state.currentModel = model
val texture = repository.getTexture(identifier, aspects, state.animationSeconds)
val context = RenderContext()
model.context = context
repository.getTextureNoSubstitute(identifier, aspects, 0f).let { context.put(RenderContext.TEXTURE, it) }
context.put(RenderContext.SCALE, contextScale)
context.put(RenderContext.SPECIES, identifier)
context.put(RenderContext.ASPECTS, aspects)
context.put(RenderContext.POSABLE_STATE, state)
val renderType = RenderType.entityCutout(texture)
val quaternion1 = Axis.YP.rotationDegrees(-32F * if (reversed) -1F else 1F)
val quaternion2 = Axis.XP.rotationDegrees(5F)
val originalPose = state.currentPose
state.setPoseToFirstSuitable(PoseType.PORTRAIT)
state.updatePartialTicks(partialTicks)
model.applyAnimations(null, state, limbSwing, limbSwingAmount, ageInTicks, headYaw, headPitch)
originalPose?.let { state.setPose(it) }
matrixStack.translate(
model.portraitTranslation.x * if (reversed) -1F else 1F,
model.portraitTranslation.y,
model.portraitTranslation.z - 4
)
matrixStack.scale(model.portraitScale, model.portraitScale, 1 / model.portraitScale)
matrixStack.mulPose(quaternion1) // TODO (techdaan): correct?
matrixStack.mulPose(quaternion2)
val light1 = Vector3f(0.2F, 1.0F, -1.0F)
val light2 = Vector3f(0.1F, 0.0F, 8.0F)
RenderSystem.setShaderLights(light1, light2)
quaternion1.conjugate()
val immediate = Minecraft.getInstance().renderBuffers().bufferSource()
val buffer = immediate.getBuffer(renderType)
val packedLight = LightTexture.pack(11, 7)
model.withLayerContext(immediate, state, repository.getLayers(identifier, aspects)) {
model.render(context, matrixStack, buffer, packedLight, OverlayTexture.NO_OVERLAY, -0x1)
immediate.endBatch()
}
model.setDefault()
Lighting.setupFor3DItems()
} else {
renderSprite(matrixStack, sprite)
}
matrixStack.popPose()
model.setDefault()
Lighting.setupFor3DItems()
}
fun drawProfile(
@@ -264,50 +279,75 @@ fun drawProfile(
partialTicks: Float,
scale: Float = 20F
) {
val model = repository.getPoser(resourceIdentifier, aspects)
val texture = repository.getTexture(resourceIdentifier, aspects, state.animationSeconds)
val context = RenderContext()
model.context = context
repository.getTextureNoSubstitute(resourceIdentifier, aspects, 0f).let { context.put(RenderContext.TEXTURE, it) }
context.put(RenderContext.SCALE, 1F)
context.put(RenderContext.SPECIES, resourceIdentifier)
context.put(RenderContext.ASPECTS, aspects)
context.put(RenderContext.POSABLE_STATE, state)
state.currentAspects = aspects
state.currentModel = model
val renderType = RenderType.entityCutout(texture)//model.getLayer(texture)
RenderSystem.applyModelViewMatrix()
matrixStack.scale(scale, scale, -scale)
state.setPoseToFirstSuitable(PoseType.PORTRAIT)
state.updatePartialTicks(partialTicks)
model.applyAnimations(null, state, 0F, 0F, 0F, 0F, 0F)
matrixStack.translate(model.profileTranslation.x, model.profileTranslation.y, model.profileTranslation.z - 4.0)
matrixStack.scale(model.profileScale, model.profileScale, 1 / model.profileScale)
val sprite = repository.getSprite(resourceIdentifier, aspects, SpriteType.PROFILE);
if(sprite == null) {
val model = repository.getPoser(resourceIdentifier, aspects)
val texture = repository.getTexture(resourceIdentifier, aspects, state.animationSeconds)
val context = RenderContext()
model.context = context
repository.getTextureNoSubstitute(resourceIdentifier, aspects, 0f)
.let { context.put(RenderContext.TEXTURE, it) }
context.put(RenderContext.SCALE, 1F)
context.put(RenderContext.SPECIES, resourceIdentifier)
context.put(RenderContext.ASPECTS, aspects)
context.put(RenderContext.POSABLE_STATE, state)
state.currentAspects = aspects
state.currentModel = model
val renderType = RenderType.entityCutout(texture)//model.getLayer(texture)
state.setPoseToFirstSuitable(PoseType.PORTRAIT)
state.updatePartialTicks(partialTicks)
model.applyAnimations(null, state, 0F, 0F, 0F, 0F, 0F)
matrixStack.translate(model.profileTranslation.x, model.profileTranslation.y, model.profileTranslation.z - 4.0)
matrixStack.scale(model.profileScale, model.profileScale, 1 / model.profileScale)
// matrixStack.multiply(rotation)
val quaternion1 = Axis.YP.rotationDegrees(-32F * if (false) -1F else 1F)
val quaternion2 = Axis.XP.rotationDegrees(5F)
matrixStack.mulPose(quaternion1)
matrixStack.mulPose(quaternion2)
Lighting.setupForEntityInInventory() // TODO (techdaan): Does this map correctly?
val entityRenderDispatcher = Minecraft.getInstance().entityRenderDispatcher
entityRenderDispatcher.setRenderShadow(true)
val quaternion1 = Axis.YP.rotationDegrees(-32F * if (false) -1F else 1F)
val quaternion2 = Axis.XP.rotationDegrees(5F)
matrixStack.mulPose(quaternion1)
matrixStack.mulPose(quaternion2)
Lighting.setupForEntityInInventory() // TODO (techdaan): Does this map correctly?
val entityRenderDispatcher = Minecraft.getInstance().entityRenderDispatcher
entityRenderDispatcher.setRenderShadow(true)
val bufferSource = Minecraft.getInstance().renderBuffers().bufferSource()
val buffer = bufferSource.getBuffer(renderType)
val light1 = Vector3f(-1F, 1F, 1.0F)
val light2 = Vector3f(1.3F, -1F, 1.0F)
RenderSystem.setShaderLights(light1, light2)
val packedLight = LightTexture.pack(11, 7)
val bufferSource = Minecraft.getInstance().renderBuffers().bufferSource()
val buffer = bufferSource.getBuffer(renderType)
val light1 = Vector3f(-1F, 1F, 1.0F)
val light2 = Vector3f(1.3F, -1F, 1.0F)
RenderSystem.setShaderLights(light1, light2)
val packedLight = LightTexture.pack(11, 7)
model.withLayerContext(bufferSource, state, repository.getLayers(resourceIdentifier, aspects)) {
model.render(context, matrixStack, buffer, packedLight, OverlayTexture.NO_OVERLAY, -0x1)
bufferSource.endBatch()
model.withLayerContext(bufferSource, state, repository.getLayers(resourceIdentifier, aspects)) {
model.render(context, matrixStack, buffer, packedLight, OverlayTexture.NO_OVERLAY, -0x1)
bufferSource.endBatch()
}
model.setDefault()
entityRenderDispatcher.setRenderShadow(true)
Lighting.setupFor3DItems()
} else {
renderSprite(matrixStack, sprite)
}
model.setDefault()
entityRenderDispatcher.setRenderShadow(true)
Lighting.setupFor3DItems()
}
fun renderSprite(matrixStack: PoseStack, sprite: ResourceLocation) {
val matrix: PoseStack.Pose = matrixStack.last()
matrix.pose().translate(-1f, 0f, 0f)
RenderSystem.setShaderTexture(0, sprite);
RenderSystem.setShader(GameRenderer::getPositionTexShader)
var buffer = Tesselator.getInstance().begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_TEX)
buffer.addVertex(matrix, 2f, 0f, 0.0f).setUv(1f, 0f)
buffer.addVertex(matrix, 0f, 0f, 0.0f).setUv(0f, 0f)
buffer.addVertex(matrix, 0f, 2f, 0.0f).setUv(0f, 1f)
buffer.addVertex(matrix, 2f, 2f, 0.0f).setUv(1f, 1f)
BufferUploader.drawWithShader(buffer.buildOrThrow())
}
@@ -58,7 +58,7 @@ class FishingSpawnCause(
entity.pokemon.forcedAspects += FISHED_ASPECT
bait?.effects?.forEach { it ->
if (Math.random() < it.chance) return
if (Math.random() > it.chance) return
when (it.type) {
FishingBait.Effects.SHINY_REROLL -> shinyReroll(entity, it)
FishingBait.Effects.NATURE -> alterNatureAttempt(entity, it)
@@ -92,7 +92,7 @@ open class PlayerPartyStore(
val random = Random.Default
for (pokemon in this) {
// Awake from fainted
if (pokemon.isFainted()) {
if (pokemon.isFainted() && Cobblemon.config.faintAwakenHealthPercent > 0 && Cobblemon.config.defaultFaintTimer > 0) {
pokemon.faintedTimer -= 1
if (pokemon.faintedTimer <= -1) {
val php = ceil(pokemon.hp * Cobblemon.config.faintAwakenHealthPercent)
@@ -101,24 +101,26 @@ open class PlayerPartyStore(
}
}
// Passive healing while less than full health
else if (pokemon.currentHealth < pokemon.hp) {
else if (pokemon.currentHealth < pokemon.hp && Cobblemon.config.healTimer > 0 && Cobblemon.config.healPercent > 0) {
pokemon.healTimer--
if (pokemon.healTimer <= -1) {
pokemon.healTimer = Cobblemon.config.healTimer
val healAmount = 1.0.coerceAtLeast(pokemon.hp.toDouble() * Cobblemon.config.healPercent)
pokemon.currentHealth = pokemon.currentHealth + round(healAmount).toInt()
pokemon.currentHealth += round(healAmount).toInt()
}
}
// Statuses
val status = pokemon.status
if (status != null && !player.isSleeping) {
if (status.isExpired()) {
status.status.onStatusExpire(player, pokemon, random)
pokemon.status = null
} else {
status.status.onSecondPassed(player, pokemon, random)
status.tickTimer()
if (Cobblemon.config.healPassiveStatuses) {
val status = pokemon.status
if (status != null && !player.isSleeping) {
if (status.isExpired()) {
status.status.onStatusExpire(player, pokemon, random)
pokemon.status = null
} else {
status.status.onSecondPassed(player, pokemon, random)
status.tickTimer()
}
}
}
@@ -21,9 +21,10 @@ import net.minecraft.world.level.BlockGetter
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.BaseEntityBlock
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.HorizontalDirectionalBlock
import net.minecraft.world.level.block.Rotation
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.block.state.StateDefinition
import net.minecraft.world.level.block.state.properties.BlockStateProperties.HORIZONTAL_FACING
import net.minecraft.world.level.block.state.properties.EnumProperty
import net.minecraft.world.level.pathfinder.PathComputationType
import net.minecraft.world.phys.shapes.CollisionContext
@@ -33,7 +34,7 @@ import net.minecraft.world.phys.shapes.VoxelShape
class MonitorBlock(settings: Properties) : MultiblockBlock(settings) {
init {
registerDefaultState(stateDefinition.any()
.setValue(HorizontalDirectionalBlock.FACING, Direction.NORTH))
.setValue(HORIZONTAL_FACING, Direction.NORTH))
}
override fun createMultiBlockEntity(
@@ -50,11 +51,11 @@ class MonitorBlock(settings: Properties) : MultiblockBlock(settings) {
}
override fun getStateForPlacement(blockPlaceContext: BlockPlaceContext): BlockState {
return defaultBlockState().setValue(HorizontalDirectionalBlock.FACING, blockPlaceContext.horizontalDirection)
return defaultBlockState().setValue(HORIZONTAL_FACING, blockPlaceContext.horizontalDirection)
}
override fun createBlockStateDefinition(builder: StateDefinition.Builder<Block, BlockState>) {
builder.add(HorizontalDirectionalBlock.FACING)
builder.add(HORIZONTAL_FACING)
builder.add(SCREEN)
}
@@ -80,6 +81,12 @@ class MonitorBlock(settings: Properties) : MultiblockBlock(settings) {
): VoxelShape {
return HITBOX
}
@Deprecated("Deprecated in Java")
override fun rotate(state: BlockState, rotation: Rotation): BlockState {
return state.setValue(HORIZONTAL_FACING, rotation.rotate(state.getValue(HORIZONTAL_FACING)))
}
@Deprecated("Deprecated in Java")
override fun isPathfindable(state: BlockState, type: PathComputationType): Boolean {
return false
@@ -38,6 +38,7 @@ import net.minecraft.world.level.block.entity.BlockEntity
import net.minecraft.world.level.block.entity.BlockEntityType
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.block.state.StateDefinition
import net.minecraft.world.level.block.state.properties.BlockStateProperties.WATERLOGGED
import net.minecraft.world.level.block.state.properties.BooleanProperty
import net.minecraft.world.level.block.state.properties.EnumProperty
import net.minecraft.world.level.material.FluidState
@@ -53,7 +54,6 @@ class PCBlock(properties: Properties): BaseEntityBlock(properties), SimpleWaterl
val CODEC = simpleCodec(::PCBlock)
val PART = EnumProperty.create("part", PCPart::class.java)
val ON = BooleanProperty.create("on")
val WATERLOGGED = BooleanProperty.create("waterlogged")
private val NORTH_AABB_TOP = Shapes.or(
Shapes.box(0.1875, 0.0, 0.0, 0.8125, 0.875, 0.125),
@@ -53,6 +53,7 @@ import net.minecraft.world.phys.shapes.CollisionContext
import net.minecraft.world.phys.shapes.Shapes
import net.minecraft.world.phys.shapes.VoxelShape
import java.util.*
import net.minecraft.world.level.block.state.properties.BlockStateProperties.WATERLOGGED
@Suppress("OVERRIDE_DEPRECATION", "DEPRECATION")
class PastureBlock(settings: Properties): BaseEntityBlock(settings), SimpleWaterloggedBlock, PreEmptsExplosion {
@@ -61,7 +62,6 @@ class PastureBlock(settings: Properties): BaseEntityBlock(settings), SimpleWater
val PART: EnumProperty<PasturePart> = EnumProperty.create("part", PasturePart::class.java)
val ON: BooleanProperty = BooleanProperty.create("on")
val WATERLOGGED: BooleanProperty = BooleanProperty.create("waterlogged")
private val SOUTH_AABB_TOP = buildCollider(top = true, Direction.NORTH)
private val NORTH_AABB_TOP = buildCollider(top = true, Direction.SOUTH)
@@ -8,7 +8,9 @@
package com.cobblemon.mod.common.client.gui
import com.cobblemon.mod.common.api.gui.renderSprite
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
import com.cobblemon.mod.common.client.render.SpriteType
import com.cobblemon.mod.common.client.render.models.blockbench.PosableState
import com.cobblemon.mod.common.client.render.models.blockbench.repository.PokemonModelRepository
import com.cobblemon.mod.common.client.render.models.blockbench.repository.RenderContext
@@ -51,52 +53,60 @@ fun drawProfilePokemon(
partialTicks: Float,
scale: Float = 20F
) {
val model = PokemonModelRepository.getPoser(species, aspects)
val texture = PokemonModelRepository.getTexture(species, aspects, state.animationSeconds)
val context = RenderContext()
model.context = context
PokemonModelRepository.getTextureNoSubstitute(species, aspects, 0f).let { context.put(RenderContext.TEXTURE, it) }
context.put(RenderContext.SCALE, PokemonSpecies.getByIdentifier(species)!!.getForm(aspects).baseScale)
context.put(RenderContext.SPECIES, species)
context.put(RenderContext.ASPECTS, aspects)
context.put(RenderContext.RENDER_STATE, RenderContext.RenderState.PROFILE)
context.put(RenderContext.POSABLE_STATE, state)
state.currentModel = model
state.currentAspects = aspects
val renderType = RenderType.entityCutout(texture)
RenderSystem.applyModelViewMatrix()
matrixStack.scale(scale, scale, -scale)
state.setPoseToFirstSuitable(PoseType.PROFILE)
state.updatePartialTicks(partialTicks)
model.applyAnimations(null, state, 0F, 0F, 0F, 0F, 0F)
matrixStack.translate(model.profileTranslation.x, model.profileTranslation.y, model.profileTranslation.z - 4.0)
matrixStack.scale(model.profileScale, model.profileScale, 1 / model.profileScale)
val sprite = PokemonModelRepository.getSprite(species, aspects, SpriteType.PROFILE);
matrixStack.mulPose(rotation)
Lighting.setupForEntityInInventory() // TODO (techdaan): Does this map correctly?
val entityRenderDispatcher = Minecraft.getInstance().entityRenderDispatcher
rotation.conjugate()
entityRenderDispatcher.overrideCameraOrientation(rotation)
entityRenderDispatcher.setRenderShadow(true)
if(sprite == null) {
val bufferSource = Minecraft.getInstance().renderBuffers().bufferSource()
val buffer = bufferSource.getBuffer(renderType)
val light1 = Vector3f(-1F, 1F, 1.0F)
val light2 = Vector3f(1.3F, -1F, 1.0F)
RenderSystem.setShaderLights(light1, light2)
val packedLight = LightTexture.pack(11, 7)
val model = PokemonModelRepository.getPoser(species, aspects)
val texture = PokemonModelRepository.getTexture(species, aspects, state.animationSeconds)
model.withLayerContext(bufferSource, state, PokemonModelRepository.getLayers(species, aspects)) {
model.render(context, matrixStack, buffer, packedLight, OverlayTexture.NO_OVERLAY, -0x1)
bufferSource.endBatch()
val context = RenderContext()
model.context = context
PokemonModelRepository.getTextureNoSubstitute(species, aspects, 0f)
.let { context.put(RenderContext.TEXTURE, it) }
context.put(RenderContext.SCALE, PokemonSpecies.getByIdentifier(species)!!.getForm(aspects).baseScale)
context.put(RenderContext.SPECIES, species)
context.put(RenderContext.ASPECTS, aspects)
context.put(RenderContext.RENDER_STATE, RenderContext.RenderState.PROFILE)
context.put(RenderContext.POSABLE_STATE, state)
state.currentModel = model
state.currentAspects = aspects
val renderType = RenderType.entityCutout(texture)
state.setPoseToFirstSuitable(PoseType.PROFILE)
state.updatePartialTicks(partialTicks)
model.applyAnimations(null, state, 0F, 0F, 0F, 0F, 0F)
matrixStack.translate(model.profileTranslation.x, model.profileTranslation.y, model.profileTranslation.z - 4.0)
matrixStack.scale(model.profileScale, model.profileScale, 1 / model.profileScale)
matrixStack.mulPose(rotation)
Lighting.setupForEntityInInventory() // TODO (techdaan): Does this map correctly?
val entityRenderDispatcher = Minecraft.getInstance().entityRenderDispatcher
rotation.conjugate()
entityRenderDispatcher.overrideCameraOrientation(rotation)
entityRenderDispatcher.setRenderShadow(true)
val bufferSource = Minecraft.getInstance().renderBuffers().bufferSource()
val buffer = bufferSource.getBuffer(renderType)
val light1 = Vector3f(-1F, 1F, 1.0F)
val light2 = Vector3f(1.3F, -1F, 1.0F)
RenderSystem.setShaderLights(light1, light2)
val packedLight = LightTexture.pack(11, 7)
model.withLayerContext(bufferSource, state, PokemonModelRepository.getLayers(species, aspects)) {
model.render(context, matrixStack, buffer, packedLight, OverlayTexture.NO_OVERLAY, -0x1)
bufferSource.endBatch()
}
model.setDefault()
entityRenderDispatcher.setRenderShadow(true)
Lighting.setupFor3DItems()
} else {
renderSprite(matrixStack, sprite)
}
model.setDefault()
entityRenderDispatcher.setRenderShadow(true)
Lighting.setupFor3DItems()
}
@@ -11,10 +11,7 @@ package com.cobblemon.mod.common.client.render
import com.cobblemon.mod.common.client.render.models.blockbench.PosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Bone
import com.cobblemon.mod.common.client.render.models.blockbench.repository.VaryingModelRepository
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
import com.cobblemon.mod.common.util.adapters.ModelTextureSupplierAdapter
import com.cobblemon.mod.common.util.adapters.Vector3fAdapter
import com.cobblemon.mod.common.util.adapters.Vector4fAdapter
import com.cobblemon.mod.common.util.adapters.*
import com.cobblemon.mod.common.util.cobblemonResource
import com.google.gson.GsonBuilder
import com.google.gson.annotations.SerializedName
@@ -52,6 +49,10 @@ class VaryingRenderableResolver<T : PosableModel>(
?: throw IllegalStateException("Unable to find a texture for $name with aspects ${aspects.joinToString()}. This shouldn't be possible if you've defined the fallback variation.")
}
fun getSprite(aspects: Set<String>, type: SpriteType): ResourceLocation? {
return getVariationValue(aspects) { sprites }?.get(type)
}
private fun <T> getVariationValue(aspects: Set<String>, selector: ModelAssetVariation.() -> T?): T? {
return variations.lastOrNull { it.aspects.all { it in aspects } && selector(it) != null }?.let(selector)
}
@@ -86,6 +87,7 @@ class VaryingRenderableResolver<T : PosableModel>(
.registerTypeAdapter(Vector3f::class.java, Vector3fAdapter)
.registerTypeAdapter(Vector4f::class.java, Vector4fAdapter)
.registerTypeAdapter(ModelTextureSupplier::class.java, ModelTextureSupplierAdapter)
.registerTypeAdapter(SpriteType::class.java, SpriteTypeAdapter)
.disableHtmlEscaping()
.setLenient()
.create()
@@ -160,7 +162,8 @@ class ModelAssetVariation(
val poser: ResourceLocation? = null,
val model: ResourceLocation? = null,
val texture: ModelTextureSupplier? = null,
val layers: List<ModelLayer>? = null
val layers: List<ModelLayer>? = null,
val sprites: Map<SpriteType, ResourceLocation>? = null
)
/**
@@ -201,4 +204,9 @@ class ModelLayer {
val texture: ModelTextureSupplier? = null
val emissive: Boolean = false
val translucent: Boolean = false
}
enum class SpriteType {
PORTRAIT,
PROFILE
}
@@ -189,7 +189,7 @@ class PokeBobberEntityRenderer(context: EntityRendererProvider.Context?) : Entit
val sinBodyYaw = Mth.sin(bodyYawRadians).toDouble()
val cosBodyYaw = Mth.cos(bodyYawRadians).toDouble()
val horizontalOffset = armOffset.toDouble() * 0.35
if (!entityRenderDispatcher.options.cameraType.isFirstPerson || playerEntity !== Minecraft.getInstance().player) {
if (!entityRenderDispatcher.options.cameraType.isFirstPerson || playerEntity != Minecraft.getInstance().player) {
playerEyeYWorld = Mth.lerp(tickDelta.toDouble(), playerEntity.xo, playerEntity.x) - cosBodyYaw * horizontalOffset - sinBodyYaw * 0.8
playerPosYWorld = playerEntity.yo + playerEntity.eyeHeight.toDouble() + (playerEntity.y - playerEntity.yo) * tickDelta.toDouble() - 0.45
playerPosZWorld = Mth.lerp(tickDelta.toDouble(), playerEntity.zo, playerEntity.z) - sinBodyYaw * horizontalOffset + cosBodyYaw * 0.8
@@ -13,6 +13,7 @@ import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.client.render.ModelLayer
import com.cobblemon.mod.common.client.render.ModelVariationSet
import com.cobblemon.mod.common.client.render.SpriteType
import com.cobblemon.mod.common.client.render.VaryingRenderableResolver
import com.cobblemon.mod.common.client.render.models.blockbench.*
import com.cobblemon.mod.common.client.render.models.blockbench.bedrock.animation.BedrockAnimationRepository
@@ -232,6 +233,13 @@ abstract class VaryingModelRepository<T : PosableModel> {
return this.variations[fallback]!!.getLayers(aspects)
}
fun getSprite(name: ResourceLocation, aspects: Set<String>, type: SpriteType): ResourceLocation? {
try {
return this.variations[name]?.getSprite(aspects, type)
} catch (_: IllegalStateException) {}
return null
}
companion object {
fun registerFactory(id: String, factory: BiFunction<ResourceLocation, Resource, Pair<ResourceLocation, Function<Boolean, Bone>>>) {
MODEL_FACTORIES[id] = factory
@@ -147,6 +147,9 @@ class CobblemonConfig {
Statuses.BURN.configEntry()
)
@NodeCategory(Category.PassiveStatus)
var healPassiveStatuses = true
@NodeCategory(Category.Healing)
var infiniteHealerCharge = false
@@ -281,7 +281,7 @@ open class Pokemon : ShowdownIdentifiable {
var friendship = this.form.baseFriendship
private set(value) {
// Don't check on client, that way we don't need to actually sync the config value it doesn't affect anything
if (!this.isClient || !this.isPossibleFriendship(value)) {
if (!this.isPossibleFriendship(value)) {
return
}
FRIENDSHIP_UPDATED.post(FriendshipUpdatedEvent(this, value)) {
@@ -996,7 +996,7 @@ open class Pokemon : ShowdownIdentifiable {
*/
fun setFriendship(value: Int, coerceSafe: Boolean = true): Boolean {
val sanitizedAmount = if (coerceSafe) value.absoluteValue.coerceAtMost(Cobblemon.config.maxPokemonFriendship) else value.absoluteValue
if (!this.isClient || !this.isPossibleFriendship(sanitizedAmount)) {
if (!this.isPossibleFriendship(sanitizedAmount)) {
return false
}
this.friendship = sanitizedAmount
@@ -0,0 +1,27 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.util.adapters
import com.cobblemon.mod.common.api.pokemon.egg.EggGroup
import com.cobblemon.mod.common.client.render.SpriteType
import com.google.gson.*
import java.lang.reflect.Type
object SpriteTypeAdapter : JsonDeserializer<SpriteType>, JsonSerializer<SpriteType> {
// Safe to just cache
private val spriteTypes = SpriteType.values()
override fun deserialize(json: JsonElement, typeOfT: Type?, context: JsonDeserializationContext?): SpriteType {
val rawID = json.asString
return this.spriteTypes.firstOrNull { spriteType -> spriteType.name.equals(rawID, true) }
?: throw IllegalStateException("Failed to resolve sprite type from: $rawID")
}
override fun serialize(src: SpriteType, typeOfSrc: Type, context: JsonSerializationContext): JsonElement = JsonPrimitive(src.name.lowercase())
}