mirror of
https://github.com/FatherToast/SpecialMobs.git
synced 2025-09-01 15:01:30 +00:00
Merge branch '1.16.5' of https://github.com/FatherToast/SpecialMobs into 1.16.5
This commit is contained in:
commit
0c8deef601
220 changed files with 4893 additions and 755 deletions
|
@ -2,7 +2,6 @@ package fathertoast.specialmobs.client;
|
|||
|
||||
import fathertoast.specialmobs.common.config.Config;
|
||||
import fathertoast.specialmobs.common.core.SpecialMobs;
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.util.Util;
|
||||
|
@ -14,10 +13,6 @@ import net.minecraftforge.fml.ExtensionPoint;
|
|||
import net.minecraftforge.fml.ModLoadingContext;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
@Mod.EventBusSubscriber( value = Dist.CLIENT, modid = SpecialMobs.MOD_ID, bus = Mod.EventBusSubscriber.Bus.FORGE )
|
||||
public class ClientEventHandler {
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ import fathertoast.specialmobs.common.entity.ghast.CorporealShiftGhastEntity;
|
|||
import fathertoast.specialmobs.common.entity.skeleton.NinjaSkeletonEntity;
|
||||
import fathertoast.specialmobs.common.entity.witherskeleton.NinjaWitherSkeletonEntity;
|
||||
import fathertoast.specialmobs.common.entity.zombie.MadScientistZombieEntity;
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import fathertoast.specialmobs.common.entity.zombifiedpiglin.VampireZombifiedPiglinEntity;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.ItemRenderer;
|
||||
import net.minecraft.client.renderer.entity.SpriteRenderer;
|
||||
|
@ -23,11 +23,8 @@ import net.minecraftforge.fml.client.registry.RenderingRegistry;
|
|||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
@Mod.EventBusSubscriber( value = Dist.CLIENT, modid = SpecialMobs.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD )
|
||||
public class ClientRegister {
|
||||
|
||||
|
@ -56,8 +53,11 @@ public class ClientRegister {
|
|||
|
||||
// Species overrides
|
||||
registerSpeciesRenderer( MadScientistZombieEntity.SPECIES, SpecialZombieVillagerRenderer::new );
|
||||
registerSpeciesRenderer( VampireZombifiedPiglinEntity.SPECIES, SpecialPiglinRenderer::newBothEars );
|
||||
|
||||
registerSpeciesRenderer( NinjaSkeletonEntity.SPECIES, NinjaSkeletonRenderer::new );
|
||||
registerSpeciesRenderer( NinjaWitherSkeletonEntity.SPECIES, NinjaSkeletonRenderer::new );
|
||||
|
||||
registerSpeciesRenderer( CorporealShiftGhastEntity.SPECIES, CorporealShiftGhastRenderer::new );
|
||||
|
||||
// Other
|
||||
|
@ -74,6 +74,7 @@ public class ClientRegister {
|
|||
RenderingRegistry.registerEntityRenderingHandler( species.entityType.get(), renderFactory );
|
||||
}
|
||||
|
||||
@SuppressWarnings( "SameParameterValue" )
|
||||
private static <T extends Entity & IRendersAsItem> void registerSpriteRenderer( EntityType<T> entityType, Supplier<Minecraft> minecraftSupplier, float scale, boolean fullBright ) {
|
||||
ItemRenderer itemRenderer = minecraftSupplier.get().getItemRenderer();
|
||||
RenderingRegistry.registerEntityRenderingHandler( entityType, ( renderManager ) -> new SpriteRenderer<>( renderManager, itemRenderer, scale, fullBright ) );
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
@MethodsReturnNonnullByDefault
|
||||
@ParametersAreNonnullByDefault
|
||||
package fathertoast.specialmobs.client.misc;
|
||||
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
|
@ -0,0 +1,7 @@
|
|||
@MethodsReturnNonnullByDefault
|
||||
@ParametersAreNonnullByDefault
|
||||
package fathertoast.specialmobs.client;
|
||||
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
|
@ -7,49 +7,54 @@ import net.minecraft.client.renderer.model.ModelRenderer;
|
|||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
||||
import java.util.Random;
|
||||
import java.util.function.Function;
|
||||
|
||||
/** Copy of {@link net.minecraft.client.renderer.entity.model.GhastModel} */
|
||||
@OnlyIn( Dist.CLIENT )
|
||||
public class CorporealShiftGhastModel<T extends Entity> extends SegmentedModel<T> {
|
||||
private final ModelRenderer[] tentacles = new ModelRenderer[9];
|
||||
private final ImmutableList<ModelRenderer> parts;
|
||||
|
||||
|
||||
public CorporealShiftGhastModel() {
|
||||
ImmutableList.Builder<ModelRenderer> builder = ImmutableList.builder();
|
||||
ModelRenderer modelrenderer = new ModelRenderer(this, 0, 0);
|
||||
modelrenderer.addBox(-8.0F, -8.0F, -8.0F, 16.0F, 16.0F, 16.0F);
|
||||
ModelRenderer modelrenderer = new ModelRenderer( this, 0, 0 );
|
||||
modelrenderer.addBox( -8.0F, -8.0F, -8.0F, 16.0F, 16.0F, 16.0F );
|
||||
modelrenderer.y = 17.6F;
|
||||
builder.add(modelrenderer);
|
||||
Random random = new Random(1660L);
|
||||
|
||||
for (int i = 0; i < this.tentacles.length; ++i) {
|
||||
this.tentacles[i] = new ModelRenderer(this, 0, 0);
|
||||
builder.add( modelrenderer );
|
||||
Random random = new Random( 1660L );
|
||||
|
||||
for( int i = 0; i < this.tentacles.length; ++i ) {
|
||||
this.tentacles[i] = new ModelRenderer( this, 0, 0 );
|
||||
float f = (((float) (i % 3) - (float) (i / 3 % 2) * 0.5F + 0.25F) / 2.0F * 2.0F - 1.0F) * 5.0F;
|
||||
float f1 = ((float) (i / 3) / 2.0F * 2.0F - 1.0F) * 5.0F;
|
||||
int j = random.nextInt(7) + 8;
|
||||
this.tentacles[i].addBox(-1.0F, 0.0F, -1.0F, 2.0F, (float) j, 2.0F);
|
||||
int j = random.nextInt( 7 ) + 8;
|
||||
this.tentacles[i].addBox( -1.0F, 0.0F, -1.0F, 2.0F, (float) j, 2.0F );
|
||||
this.tentacles[i].x = f;
|
||||
this.tentacles[i].z = f1;
|
||||
this.tentacles[i].y = 24.6F;
|
||||
builder.add(this.tentacles[i]);
|
||||
builder.add( this.tentacles[i] );
|
||||
}
|
||||
|
||||
|
||||
this.parts = builder.build();
|
||||
}
|
||||
|
||||
public void setRenderType(Function<ResourceLocation, RenderType> renderTypeFunc) {
|
||||
|
||||
public void setRenderType( Function<ResourceLocation, RenderType> renderTypeFunc ) {
|
||||
this.renderType = renderTypeFunc;
|
||||
}
|
||||
|
||||
public void setupAnim(T ghast, float p_225597_2_, float p_225597_3_, float p_225597_4_, float p_225597_5_, float p_225597_6_) {
|
||||
for (int i = 0; i < this.tentacles.length; ++i) {
|
||||
this.tentacles[i].xRot = 0.2F * MathHelper.sin(p_225597_4_ * 0.3F + (float) i) + 0.4F;
|
||||
|
||||
@Override
|
||||
public void setupAnim( T ghast, float p_225597_2_, float p_225597_3_, float p_225597_4_, float p_225597_5_, float p_225597_6_ ) {
|
||||
for( int i = 0; i < this.tentacles.length; ++i ) {
|
||||
this.tentacles[i].xRot = 0.2F * MathHelper.sin( p_225597_4_ * 0.3F + (float) i ) + 0.4F;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Iterable<ModelRenderer> parts() {
|
||||
return this.parts;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,7 +7,6 @@ import fathertoast.specialmobs.common.core.SpecialMobs;
|
|||
import fathertoast.specialmobs.common.entity.ISpecialMob;
|
||||
import fathertoast.specialmobs.common.entity.SpecialMobData;
|
||||
import fathertoast.specialmobs.common.entity.ghast.CorporealShiftGhastEntity;
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.client.renderer.IRenderTypeBuffer;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.client.renderer.entity.EntityRendererManager;
|
||||
|
@ -16,11 +15,8 @@ import net.minecraft.util.ResourceLocation;
|
|||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import java.util.function.Function;
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
@OnlyIn( Dist.CLIENT )
|
||||
public class CorporealShiftGhastRenderer extends MobRenderer<CorporealShiftGhastEntity, CorporealShiftGhastModel<CorporealShiftGhastEntity>> {
|
||||
|
||||
|
@ -47,7 +43,7 @@ public class CorporealShiftGhastRenderer extends MobRenderer<CorporealShiftGhast
|
|||
@Override
|
||||
public ResourceLocation getTextureLocation( CorporealShiftGhastEntity entity ) {
|
||||
final SpecialMobData<?> data = ((ISpecialMob<?>) entity).getSpecialData();
|
||||
return entity.isCharging() && data.hasOverlayTexture() ? data.getTextureOverlay() : data.getTexture();
|
||||
return entity.isCharging() && data.getTextureOverlay() != null ? data.getTextureOverlay() : data.getTexture();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -5,7 +5,6 @@ import com.mojang.blaze3d.vertex.IVertexBuilder;
|
|||
import com.mojang.blaze3d.vertex.MatrixApplyingVertexBuilder;
|
||||
import com.mojang.blaze3d.vertex.VertexBuilderUtils;
|
||||
import fathertoast.specialmobs.common.entity.ai.INinja;
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.*;
|
||||
|
@ -30,11 +29,9 @@ import javax.annotation.ParametersAreNonnullByDefault;
|
|||
import java.util.Random;
|
||||
import java.util.SortedSet;
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
@OnlyIn( Dist.CLIENT )
|
||||
public class NinjaSkeletonRenderer extends SpecialSkeletonRenderer {
|
||||
|
||||
|
||||
private final BlockRendererDispatcher blockRenderer;
|
||||
|
||||
public NinjaSkeletonRenderer( EntityRendererManager rendererManager ) {
|
||||
|
@ -45,10 +42,10 @@ public class NinjaSkeletonRenderer extends SpecialSkeletonRenderer {
|
|||
@Override
|
||||
public void render( AbstractSkeletonEntity entity, float rotation, float partialTicks,
|
||||
MatrixStack matrixStack, IRenderTypeBuffer buffer, int packedLight ) {
|
||||
|
||||
|
||||
INinja ninja = (INinja) entity;
|
||||
final BlockState disguiseBlock = ninja.getHiddenDragon();
|
||||
|
||||
|
||||
if( disguiseBlock == null ) {
|
||||
super.render( entity, rotation, partialTicks, matrixStack, buffer, packedLight );
|
||||
}
|
||||
|
@ -61,7 +58,7 @@ public class NinjaSkeletonRenderer extends SpecialSkeletonRenderer {
|
|||
private void renderBlockDisguise( BlockState block, BlockPos pos, IBlockDisplayReader displayReader, MatrixStack matrixStack, IRenderTypeBuffer buffer, Random random ) {
|
||||
matrixStack.pushPose();
|
||||
matrixStack.translate( -0.5, 0.0, -0.5 );
|
||||
blockRenderer.renderModel(block, pos, displayReader, matrixStack, buffer.getBuffer(RenderType.cutout()), false, random, EmptyModelData.INSTANCE);
|
||||
blockRenderer.renderModel( block, pos, displayReader, matrixStack, buffer.getBuffer( RenderType.cutout() ), false, random, EmptyModelData.INSTANCE );
|
||||
matrixStack.popPose();
|
||||
}
|
||||
}
|
|
@ -2,7 +2,6 @@ package fathertoast.specialmobs.client.renderer.entity;
|
|||
|
||||
import com.mojang.blaze3d.matrix.MatrixStack;
|
||||
import fathertoast.specialmobs.common.entity.ISpecialMob;
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.client.renderer.entity.BlazeRenderer;
|
||||
import net.minecraft.client.renderer.entity.EntityRendererManager;
|
||||
import net.minecraft.entity.monster.BlazeEntity;
|
||||
|
@ -10,10 +9,6 @@ import net.minecraft.util.ResourceLocation;
|
|||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
@OnlyIn( Dist.CLIENT )
|
||||
public class SpecialBlazeRenderer extends BlazeRenderer {
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@ import fathertoast.specialmobs.client.renderer.entity.layers.SpecialCreeperCharg
|
|||
import fathertoast.specialmobs.client.renderer.entity.layers.SpecialMobEyesLayer;
|
||||
import fathertoast.specialmobs.client.renderer.entity.layers.SpecialMobOverlayLayer;
|
||||
import fathertoast.specialmobs.common.entity.ISpecialMob;
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.client.renderer.entity.CreeperRenderer;
|
||||
import net.minecraft.client.renderer.entity.EntityRendererManager;
|
||||
import net.minecraft.client.renderer.entity.layers.CreeperChargeLayer;
|
||||
|
@ -15,10 +14,6 @@ import net.minecraft.util.ResourceLocation;
|
|||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
@OnlyIn( Dist.CLIENT )
|
||||
public class SpecialCreeperRenderer extends CreeperRenderer {
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@ import com.mojang.blaze3d.matrix.MatrixStack;
|
|||
import fathertoast.specialmobs.client.renderer.entity.layers.SpecialMobEyesLayer;
|
||||
import fathertoast.specialmobs.client.renderer.entity.layers.SpecialMobOverlayLayer;
|
||||
import fathertoast.specialmobs.common.entity.ISpecialMob;
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.client.renderer.entity.EndermanRenderer;
|
||||
import net.minecraft.client.renderer.entity.EntityRendererManager;
|
||||
import net.minecraft.client.renderer.entity.layers.EndermanEyesLayer;
|
||||
|
@ -14,10 +13,6 @@ import net.minecraft.util.ResourceLocation;
|
|||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
@OnlyIn( Dist.CLIENT )
|
||||
public class SpecialEndermanRenderer extends EndermanRenderer {
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@ package fathertoast.specialmobs.client.renderer.entity;
|
|||
import com.mojang.blaze3d.matrix.MatrixStack;
|
||||
import fathertoast.specialmobs.common.entity.ISpecialMob;
|
||||
import fathertoast.specialmobs.common.entity.SpecialMobData;
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.client.renderer.entity.EntityRendererManager;
|
||||
import net.minecraft.client.renderer.entity.GhastRenderer;
|
||||
import net.minecraft.entity.monster.GhastEntity;
|
||||
|
@ -11,10 +10,6 @@ import net.minecraft.util.ResourceLocation;
|
|||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
@OnlyIn( Dist.CLIENT )
|
||||
public class SpecialGhastRenderer extends GhastRenderer {
|
||||
|
||||
|
@ -32,7 +27,7 @@ public class SpecialGhastRenderer extends GhastRenderer {
|
|||
@Override
|
||||
public ResourceLocation getTextureLocation( GhastEntity entity ) {
|
||||
final SpecialMobData<?> data = ((ISpecialMob<?>) entity).getSpecialData();
|
||||
return entity.isCharging() && data.hasOverlayTexture() ? data.getTextureOverlay() : data.getTexture();
|
||||
return entity.isCharging() && data.getTextureOverlay() != null ? data.getTextureOverlay() : data.getTexture();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -2,7 +2,6 @@ package fathertoast.specialmobs.client.renderer.entity;
|
|||
|
||||
import com.mojang.blaze3d.matrix.MatrixStack;
|
||||
import fathertoast.specialmobs.common.entity.ISpecialMob;
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.client.renderer.entity.EntityRendererManager;
|
||||
import net.minecraft.client.renderer.entity.MagmaCubeRenderer;
|
||||
import net.minecraft.entity.monster.MagmaCubeEntity;
|
||||
|
@ -10,10 +9,6 @@ import net.minecraft.util.ResourceLocation;
|
|||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
@OnlyIn( Dist.CLIENT )
|
||||
public class SpecialMagmaCubeRenderer extends MagmaCubeRenderer {
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@ import com.mojang.blaze3d.matrix.MatrixStack;
|
|||
import fathertoast.specialmobs.client.renderer.entity.layers.SpecialMobEyesLayer;
|
||||
import fathertoast.specialmobs.client.renderer.entity.layers.SpecialMobOverlayLayer;
|
||||
import fathertoast.specialmobs.common.entity.ISpecialMob;
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.client.renderer.entity.EntityRendererManager;
|
||||
import net.minecraft.client.renderer.entity.PiglinRenderer;
|
||||
import net.minecraft.client.renderer.entity.model.PiglinModel;
|
||||
|
@ -13,10 +12,6 @@ import net.minecraft.util.ResourceLocation;
|
|||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
@OnlyIn( Dist.CLIENT )
|
||||
public class SpecialPiglinRenderer extends PiglinRenderer {
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@ package fathertoast.specialmobs.client.renderer.entity;
|
|||
import com.mojang.blaze3d.matrix.MatrixStack;
|
||||
import fathertoast.specialmobs.client.renderer.entity.layers.SpecialMobEyesLayer;
|
||||
import fathertoast.specialmobs.common.entity.ISpecialMob;
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.client.renderer.entity.EntityRendererManager;
|
||||
import net.minecraft.client.renderer.entity.SilverfishRenderer;
|
||||
import net.minecraft.entity.monster.SilverfishEntity;
|
||||
|
@ -11,10 +10,6 @@ import net.minecraft.util.ResourceLocation;
|
|||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
@OnlyIn( Dist.CLIENT )
|
||||
public class SpecialSilverfishRenderer extends SilverfishRenderer {
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@ import com.mojang.blaze3d.matrix.MatrixStack;
|
|||
import fathertoast.specialmobs.client.renderer.entity.layers.SpecialMobEyesLayer;
|
||||
import fathertoast.specialmobs.client.renderer.entity.layers.SpecialMobOverlayLayer;
|
||||
import fathertoast.specialmobs.common.entity.ISpecialMob;
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.client.renderer.entity.EntityRendererManager;
|
||||
import net.minecraft.client.renderer.entity.SkeletonRenderer;
|
||||
import net.minecraft.client.renderer.entity.model.SkeletonModel;
|
||||
|
@ -13,10 +12,6 @@ import net.minecraft.util.ResourceLocation;
|
|||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
@OnlyIn( Dist.CLIENT )
|
||||
public class SpecialSkeletonRenderer extends SkeletonRenderer {
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@ package fathertoast.specialmobs.client.renderer.entity;
|
|||
import com.mojang.blaze3d.matrix.MatrixStack;
|
||||
import fathertoast.specialmobs.client.renderer.entity.layers.SpecialMobEyesLayer;
|
||||
import fathertoast.specialmobs.common.entity.ISpecialMob;
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.client.renderer.entity.EntityRendererManager;
|
||||
import net.minecraft.client.renderer.entity.SlimeRenderer;
|
||||
import net.minecraft.entity.monster.SlimeEntity;
|
||||
|
@ -11,10 +10,6 @@ import net.minecraft.util.ResourceLocation;
|
|||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
@OnlyIn( Dist.CLIENT )
|
||||
public class SpecialSlimeRenderer extends SlimeRenderer {
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@ package fathertoast.specialmobs.client.renderer.entity;
|
|||
import com.mojang.blaze3d.matrix.MatrixStack;
|
||||
import fathertoast.specialmobs.client.renderer.entity.layers.SpecialMobEyesLayer;
|
||||
import fathertoast.specialmobs.common.entity.ISpecialMob;
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.client.renderer.entity.EntityRendererManager;
|
||||
import net.minecraft.client.renderer.entity.SpiderRenderer;
|
||||
import net.minecraft.client.renderer.entity.layers.SpiderEyesLayer;
|
||||
|
@ -12,10 +11,6 @@ import net.minecraft.util.ResourceLocation;
|
|||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
@OnlyIn( Dist.CLIENT )
|
||||
public class SpecialSpiderRenderer extends SpiderRenderer<SpiderEntity> {
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@ import com.mojang.blaze3d.matrix.MatrixStack;
|
|||
import fathertoast.specialmobs.client.renderer.entity.layers.SpecialMobEyesLayer;
|
||||
import fathertoast.specialmobs.client.renderer.entity.layers.SpecialMobOverlayLayer;
|
||||
import fathertoast.specialmobs.common.entity.ISpecialMob;
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.client.renderer.entity.EntityRendererManager;
|
||||
import net.minecraft.client.renderer.entity.WitchRenderer;
|
||||
import net.minecraft.client.renderer.entity.model.WitchModel;
|
||||
|
@ -13,10 +12,6 @@ import net.minecraft.util.ResourceLocation;
|
|||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
@OnlyIn( Dist.CLIENT )
|
||||
public class SpecialWitchRenderer extends WitchRenderer {
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@ import com.mojang.blaze3d.matrix.MatrixStack;
|
|||
import fathertoast.specialmobs.client.renderer.entity.layers.SpecialMobEyesLayer;
|
||||
import fathertoast.specialmobs.client.renderer.entity.layers.SpecialMobOverlayLayer;
|
||||
import fathertoast.specialmobs.common.entity.ISpecialMob;
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.client.renderer.entity.EntityRendererManager;
|
||||
import net.minecraft.client.renderer.entity.ZombieRenderer;
|
||||
import net.minecraft.client.renderer.entity.model.ZombieModel;
|
||||
|
@ -13,33 +12,29 @@ import net.minecraft.util.ResourceLocation;
|
|||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
@OnlyIn( Dist.CLIENT )
|
||||
public class SpecialZombieRenderer extends ZombieRenderer {
|
||||
|
||||
|
||||
private final float baseShadowRadius;
|
||||
|
||||
public SpecialZombieRenderer(EntityRendererManager rendererManager) {
|
||||
super(rendererManager);
|
||||
|
||||
public SpecialZombieRenderer( EntityRendererManager rendererManager ) {
|
||||
super( rendererManager );
|
||||
baseShadowRadius = shadowRadius;
|
||||
addLayer( new SpecialMobEyesLayer<>( this ) );
|
||||
addLayer( new SpecialMobOverlayLayer<>( this, new ZombieModel<>( 0.25F, true ) ) );
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ResourceLocation getTextureLocation(ZombieEntity entity ) {
|
||||
public ResourceLocation getTextureLocation( ZombieEntity entity ) {
|
||||
return ((ISpecialMob<?>) entity).getSpecialData().getTexture();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void scale(ZombieEntity entity, MatrixStack matrixStack, float partialTick ) {
|
||||
protected void scale( ZombieEntity entity, MatrixStack matrixStack, float partialTick ) {
|
||||
super.scale( entity, matrixStack, partialTick );
|
||||
|
||||
|
||||
final float scale = ((ISpecialMob<?>) entity).getSpecialData().getRenderScale();
|
||||
shadowRadius = baseShadowRadius * scale;
|
||||
matrixStack.scale( scale, scale, scale );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,7 +4,6 @@ import com.mojang.blaze3d.matrix.MatrixStack;
|
|||
import fathertoast.specialmobs.client.renderer.entity.layers.SpecialMobEyesLayer;
|
||||
import fathertoast.specialmobs.client.renderer.entity.layers.SpecialMobOverlayLayer;
|
||||
import fathertoast.specialmobs.common.entity.ISpecialMob;
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.client.renderer.entity.BipedRenderer;
|
||||
import net.minecraft.client.renderer.entity.EntityRendererManager;
|
||||
import net.minecraft.client.renderer.entity.layers.BipedArmorLayer;
|
||||
|
@ -14,10 +13,6 @@ import net.minecraft.util.ResourceLocation;
|
|||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
@OnlyIn( Dist.CLIENT )
|
||||
public class SpecialZombieVillagerRenderer extends BipedRenderer<ZombieEntity, ZombieVillagerModel<ZombieEntity>> {
|
||||
|
||||
|
|
|
@ -12,38 +12,41 @@ import net.minecraft.client.renderer.entity.model.EntityModel;
|
|||
import net.minecraft.client.renderer.texture.OverlayTexture;
|
||||
import net.minecraft.entity.monster.CreeperEntity;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
||||
@OnlyIn( Dist.CLIENT )
|
||||
public class SpecialCreeperChargeLayer<T extends CreeperEntity, M extends EntityModel<T>> extends LayerRenderer<T, M> {
|
||||
|
||||
|
||||
private static final ResourceLocation[] CHARGED = new ResourceLocation[] {
|
||||
new ResourceLocation("textures/entity/creeper/creeper_armor.png"),
|
||||
SpecialMobs.resourceLoc("textures/entity/creeper/super_charged.png")
|
||||
new ResourceLocation( "textures/entity/creeper/creeper_armor.png" ),
|
||||
SpecialMobs.resourceLoc( "textures/entity/creeper/super_charged.png" )
|
||||
};
|
||||
|
||||
|
||||
private final M model;
|
||||
|
||||
|
||||
|
||||
|
||||
public SpecialCreeperChargeLayer( IEntityRenderer<T, M> renderer, M model ) {
|
||||
super( renderer );
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void render(MatrixStack matrixStack, IRenderTypeBuffer buffer, int packedLight, T creeper, float limbSwing, float limbSwingAmount, float partialTicks, float ageInTicks, float netHeadYaw, float headPitch) {
|
||||
if (creeper.isPowered() || ((_SpecialCreeperEntity)creeper).isSupercharged()) {
|
||||
float tickAndPartial = (float)creeper.tickCount + partialTicks;
|
||||
public void render( MatrixStack matrixStack, IRenderTypeBuffer buffer, int packedLight, T creeper, float limbSwing, float limbSwingAmount, float partialTicks, float ageInTicks, float netHeadYaw, float headPitch ) {
|
||||
if( creeper.isPowered() || ((_SpecialCreeperEntity) creeper).isSupercharged() ) {
|
||||
float tickAndPartial = (float) creeper.tickCount + partialTicks;
|
||||
float textureOffset = tickAndPartial * 0.01F;
|
||||
|
||||
model.prepareMobModel(creeper, limbSwing, limbSwingAmount, partialTicks);
|
||||
this.getParentModel().copyPropertiesTo(model);
|
||||
IVertexBuilder ivertexbuilder = buffer.getBuffer(RenderType.energySwirl(this.getTextureLocation(creeper), textureOffset, textureOffset));
|
||||
model.setupAnim(creeper, limbSwing, limbSwingAmount, ageInTicks, netHeadYaw, headPitch);
|
||||
model.renderToBuffer(matrixStack, ivertexbuilder, packedLight, OverlayTexture.NO_OVERLAY, 0.5F, 0.5F, 0.5F, 1.0F);
|
||||
|
||||
model.prepareMobModel( creeper, limbSwing, limbSwingAmount, partialTicks );
|
||||
this.getParentModel().copyPropertiesTo( model );
|
||||
IVertexBuilder ivertexbuilder = buffer.getBuffer( RenderType.energySwirl( this.getTextureLocation( creeper ), textureOffset, textureOffset ) );
|
||||
model.setupAnim( creeper, limbSwing, limbSwingAmount, ageInTicks, netHeadYaw, headPitch );
|
||||
model.renderToBuffer( matrixStack, ivertexbuilder, packedLight, OverlayTexture.NO_OVERLAY, 0.5F, 0.5F, 0.5F, 1.0F );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected ResourceLocation getTextureLocation(CreeperEntity creeper) {
|
||||
return ((_SpecialCreeperEntity)creeper).isSupercharged() ? CHARGED[1] : CHARGED[0];
|
||||
protected ResourceLocation getTextureLocation( CreeperEntity creeper ) {
|
||||
return ((_SpecialCreeperEntity) creeper).isSupercharged() ? CHARGED[1] : CHARGED[0];
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,31 +12,34 @@ import net.minecraft.client.renderer.entity.model.EntityModel;
|
|||
import net.minecraft.client.renderer.texture.OverlayTexture;
|
||||
import net.minecraft.entity.monster.GhastEntity;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
||||
@OnlyIn( Dist.CLIENT )
|
||||
public class SpecialGhastEyesLayer<T extends GhastEntity, M extends EntityModel<T>> extends AbstractEyesLayer<T, M> {
|
||||
private final RenderType FALLBACK = RenderType.eyes( new ResourceLocation( "textures/entity/spider_eyes.png" ) );
|
||||
private final ResourceLocation eyes;
|
||||
private final ResourceLocation shootEyes;
|
||||
|
||||
|
||||
|
||||
|
||||
public SpecialGhastEyesLayer( IEntityRenderer<T, M> renderer, ResourceLocation eyes, ResourceLocation shootEyes ) {
|
||||
super( renderer );
|
||||
this.eyes = eyes;
|
||||
this.shootEyes = shootEyes;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void render(MatrixStack matrixStack, IRenderTypeBuffer buffer, int packedLight, T ghast, float limbSwing,
|
||||
float limbSwingAmount, float partialTicks, float ageInTicks, float netHeadYaw, float headPitch ) {
|
||||
|
||||
IVertexBuilder vertexBuilder = buffer.getBuffer( RenderType.entityCutout(ghast.isCharging() ? shootEyes : eyes) );
|
||||
this.getParentModel().renderToBuffer( matrixStack, vertexBuilder, LightTexture.pack(15, 15), OverlayTexture.NO_OVERLAY,
|
||||
public void render( MatrixStack matrixStack, IRenderTypeBuffer buffer, int packedLight, T ghast, float limbSwing,
|
||||
float limbSwingAmount, float partialTicks, float ageInTicks, float netHeadYaw, float headPitch ) {
|
||||
|
||||
final IVertexBuilder vertexBuilder = buffer.getBuffer( RenderType.entityCutout( ghast.isCharging() ? shootEyes : eyes ) );
|
||||
getParentModel().renderToBuffer( matrixStack, vertexBuilder, LightTexture.pack( 15, 15 ), OverlayTexture.NO_OVERLAY,
|
||||
1.0F, 1.0F, 1.0F, 1.0F );
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public RenderType renderType() {
|
||||
SpecialMobs.LOG.warn( "Something is attempting to get eye layer 'render type' for some reason! :(" );
|
||||
return FALLBACK;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,7 +4,6 @@ import com.mojang.blaze3d.matrix.MatrixStack;
|
|||
import com.mojang.blaze3d.vertex.IVertexBuilder;
|
||||
import fathertoast.specialmobs.common.core.SpecialMobs;
|
||||
import fathertoast.specialmobs.common.entity.ISpecialMob;
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.client.renderer.IRenderTypeBuffer;
|
||||
import net.minecraft.client.renderer.LightTexture;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
|
@ -17,27 +16,20 @@ import net.minecraft.util.ResourceLocation;
|
|||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
@OnlyIn( Dist.CLIENT )
|
||||
public class SpecialMobEyesLayer<T extends Entity, M extends EntityModel<T>> extends AbstractEyesLayer<T, M> {
|
||||
private final RenderType FALLBACK = RenderType.eyes( new ResourceLocation( "textures/entity/spider_eyes.png" ) );
|
||||
private static final RenderType FALLBACK = RenderType.eyes( new ResourceLocation( "textures/entity/spider_eyes.png" ) );
|
||||
|
||||
public SpecialMobEyesLayer( IEntityRenderer<T, M> renderer ) { super( renderer ); }
|
||||
|
||||
public SpecialMobEyesLayer( IEntityRenderer<T, M> renderer ) {
|
||||
super( renderer );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render( MatrixStack matrixStack, IRenderTypeBuffer buffer, int packedLight, T entity, float limbSwing,
|
||||
float limbSwingAmount, float partialTicks, float ageInTicks, float netHeadYaw, float headPitch ) {
|
||||
final ResourceLocation eyesTexture = ((ISpecialMob<?>) entity).getSpecialData().getTextureEyes();
|
||||
if( eyesTexture == null ) return;
|
||||
|
||||
//TODO does not work; for some reason, all the transparency renders as white
|
||||
IVertexBuilder vertexBuilder = buffer.getBuffer( RenderType.eyes(eyesTexture) );
|
||||
this.getParentModel().renderToBuffer( matrixStack, vertexBuilder, LightTexture.pack(15, 15), OverlayTexture.NO_OVERLAY,
|
||||
final IVertexBuilder vertexBuilder = buffer.getBuffer( RenderType.eyes( eyesTexture ) );
|
||||
getParentModel().renderToBuffer( matrixStack, vertexBuilder, LightTexture.pack( 15, 15 ), OverlayTexture.NO_OVERLAY,
|
||||
1.0F, 1.0F, 1.0F, 1.0F );
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@ package fathertoast.specialmobs.client.renderer.entity.layers;
|
|||
import com.mojang.blaze3d.matrix.MatrixStack;
|
||||
import com.mojang.blaze3d.vertex.IVertexBuilder;
|
||||
import fathertoast.specialmobs.common.entity.ISpecialMob;
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.client.renderer.IRenderTypeBuffer;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.client.renderer.entity.IEntityRenderer;
|
||||
|
@ -15,10 +14,6 @@ import net.minecraft.util.ResourceLocation;
|
|||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
@OnlyIn( Dist.CLIENT )
|
||||
public class SpecialMobOverlayLayer<T extends Entity, M extends EntityModel<T>> extends LayerRenderer<T, M> {
|
||||
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
@MethodsReturnNonnullByDefault
|
||||
@ParametersAreNonnullByDefault
|
||||
package fathertoast.specialmobs.client.renderer.entity.layers;
|
||||
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
|
@ -0,0 +1,7 @@
|
|||
@MethodsReturnNonnullByDefault
|
||||
@ParametersAreNonnullByDefault
|
||||
package fathertoast.specialmobs.client.renderer.entity;
|
||||
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
|
@ -1,6 +1,8 @@
|
|||
package fathertoast.specialmobs.common.bestiary;
|
||||
|
||||
import fathertoast.specialmobs.common.config.field.DoubleField;
|
||||
import fathertoast.specialmobs.common.config.util.*;
|
||||
import fathertoast.specialmobs.common.config.util.environment.biome.BiomeCategory;
|
||||
import fathertoast.specialmobs.common.core.SpecialMobs;
|
||||
import fathertoast.specialmobs.common.util.References;
|
||||
import net.minecraft.block.Block;
|
||||
|
@ -13,7 +15,10 @@ import net.minecraft.potion.Effects;
|
|||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
|
||||
import java.util.*;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This class serves solely to store data for mob species in an organized way, providing builder methods as applicable.
|
||||
|
@ -22,24 +27,76 @@ import java.util.*;
|
|||
public class BestiaryInfo {
|
||||
|
||||
public enum DefaultWeight {
|
||||
DEFAULT( 600 ),
|
||||
DISABLED( 0 ),
|
||||
LOWEST( DEFAULT.value / 8 ),
|
||||
LOW( DEFAULT.value / 4 ),
|
||||
HIGH( DEFAULT.value * 4 ),
|
||||
HIGHEST( DEFAULT.value * 8 );
|
||||
DEFAULT( 60.0 ),
|
||||
DISABLED( 0.0 ),
|
||||
LOWEST( DEFAULT.value / 8.0 ),
|
||||
LOW( DEFAULT.value / 4.0 ),
|
||||
HIGH( DEFAULT.value * 2.5 ),
|
||||
HIGHEST( DEFAULT.value * 5.0 );
|
||||
|
||||
public final int value;
|
||||
public final double value;
|
||||
|
||||
DefaultWeight( int v ) { value = v; }
|
||||
DefaultWeight( double v ) { value = v; }
|
||||
}
|
||||
|
||||
public enum Theme {
|
||||
NONE,
|
||||
FIRE, ICE,
|
||||
DESERT, WATER,
|
||||
FOREST, MOUNTAIN,
|
||||
FISHING
|
||||
NONE( new EnvironmentList() ),
|
||||
FIRE( new EnvironmentList(
|
||||
EnvironmentEntry.builder( DefaultWeight.HIGHEST.value ).inUltraWarmDimension().build(),
|
||||
EnvironmentEntry.builder( DefaultWeight.LOWEST.value ).isRaining().canSeeSky().notInDryBiome().build(),
|
||||
EnvironmentEntry.builder( DefaultWeight.HIGHEST.value ).isHot().build(),
|
||||
EnvironmentEntry.builder( DefaultWeight.HIGH.value ).isWarm().build(),
|
||||
EnvironmentEntry.builder( DefaultWeight.LOWEST.value ).isFreezing().build()
|
||||
) ),
|
||||
ICE( new EnvironmentList(
|
||||
EnvironmentEntry.builder( DefaultWeight.LOWEST.value ).inUltraWarmDimension().build(),
|
||||
EnvironmentEntry.builder( DefaultWeight.HIGHEST.value ).isFreezing().build(),
|
||||
EnvironmentEntry.builder( DefaultWeight.LOW.value ).isWarm().build(),
|
||||
EnvironmentEntry.builder( DefaultWeight.LOWEST.value ).isHot().build()
|
||||
) ),
|
||||
DESERT( new EnvironmentList(
|
||||
EnvironmentEntry.builder( DefaultWeight.HIGHEST.value ).inUltraWarmDimension().build(),
|
||||
EnvironmentEntry.builder( DefaultWeight.HIGHEST.value ).inDryBiome().build(),
|
||||
EnvironmentEntry.builder( DefaultWeight.LOWEST.value ).inWaterBiome().build(),
|
||||
EnvironmentEntry.builder( DefaultWeight.LOWEST.value ).inHumidBiome().build(),
|
||||
EnvironmentEntry.builder( DefaultWeight.LOWEST.value ).isRaining().canSeeSky().build(),
|
||||
EnvironmentEntry.builder( DefaultWeight.HIGH.value ).belowHalfMoonLight().build()
|
||||
) ),
|
||||
WATER( new EnvironmentList(
|
||||
EnvironmentEntry.builder( DefaultWeight.LOWEST.value ).inUltraWarmDimension().build(),
|
||||
EnvironmentEntry.builder( DefaultWeight.LOWEST.value ).inDryBiome().build(),
|
||||
EnvironmentEntry.builder( DefaultWeight.HIGHEST.value ).inWaterBiome().build(),
|
||||
EnvironmentEntry.builder( DefaultWeight.HIGHEST.value ).inHumidBiome().build(),
|
||||
EnvironmentEntry.builder( DefaultWeight.HIGHEST.value ).isRaining().canSeeSky().build(),
|
||||
EnvironmentEntry.builder( DefaultWeight.HIGH.value ).aboveHalfMoonLight().build()
|
||||
) ),
|
||||
FOREST( new EnvironmentList(
|
||||
EnvironmentEntry.builder( DefaultWeight.HIGHEST.value ).inBiomeCategory( BiomeCategory.TAIGA ).build(),
|
||||
EnvironmentEntry.builder( DefaultWeight.HIGHEST.value ).inBiomeCategory( BiomeCategory.JUNGLE ).build(),
|
||||
EnvironmentEntry.builder( DefaultWeight.HIGHEST.value ).inBiomeCategory( BiomeCategory.FOREST ).build(),
|
||||
EnvironmentEntry.builder( DefaultWeight.HIGHEST.value ).inBiomeCategory( BiomeCategory.SWAMP ).build(),
|
||||
EnvironmentEntry.builder( DefaultWeight.HIGH.value ).atMaxMoonLight().build()
|
||||
) ),
|
||||
MOUNTAIN( new EnvironmentList(
|
||||
EnvironmentEntry.builder( DefaultWeight.HIGHEST.value ).inMountainBiome().build(),
|
||||
EnvironmentEntry.builder( DefaultWeight.HIGHEST.value ).aboveMountainLevel().build(),
|
||||
EnvironmentEntry.builder( DefaultWeight.HIGH.value ).atNoMoonLight().build(),
|
||||
EnvironmentEntry.builder( DefaultWeight.LOW.value ).belowSeaLevel().build()
|
||||
) ),
|
||||
STORM( new EnvironmentList(
|
||||
EnvironmentEntry.builder( DefaultWeight.HIGHEST.value ).isThundering().build(),
|
||||
EnvironmentEntry.builder( DefaultWeight.HIGH.value ).isRaining().build(),
|
||||
EnvironmentEntry.builder( DefaultWeight.LOW.value ).cannotSeeSky().build()
|
||||
) ),
|
||||
FISHING( new EnvironmentList(
|
||||
EnvironmentEntry.builder( DefaultWeight.HIGHEST.value ).inWaterBiome().build(),
|
||||
EnvironmentEntry.builder( DefaultWeight.HIGH.value ).atMaxMoonLight().build(),
|
||||
EnvironmentEntry.builder( DefaultWeight.HIGH.value ).isRaining().notInDryBiome().build()
|
||||
) );
|
||||
|
||||
public final EnvironmentList value;
|
||||
|
||||
Theme( EnvironmentList v ) { value = v.setRange( DoubleField.Range.NON_NEGATIVE ); }
|
||||
}
|
||||
|
||||
/** The spot color for spawn eggs of this species. The base color is determined by the family. */
|
||||
|
@ -280,13 +337,13 @@ public class BestiaryInfo {
|
|||
public Builder vanillaTextureBaseOnly( String tex ) { return vanillaBaseTexture( tex ).noEyesTexture().noOverlayTexture(); }
|
||||
|
||||
/** Sets the species default base texture. */
|
||||
private Builder vanillaBaseTexture( String tex ) { return baseTexture( tex == null ? null : new ResourceLocation( tex ) ); }
|
||||
private Builder vanillaBaseTexture( String tex ) { return baseTexture( new ResourceLocation( tex ) ); }
|
||||
|
||||
/** Sets the species default glowing eyes texture. */
|
||||
private Builder vanillaEyesTexture( String eyeTex ) { return eyesTexture( eyeTex == null ? null : new ResourceLocation( eyeTex ) ); }
|
||||
private Builder vanillaEyesTexture( String eyeTex ) { return eyesTexture( new ResourceLocation( eyeTex ) ); }
|
||||
|
||||
/** Sets the species default overlay texture. */
|
||||
private Builder vanillaOverlayTexture( String ovrTex ) { return overlayTexture( ovrTex == null ? null : new ResourceLocation( ovrTex ) ); }
|
||||
private Builder vanillaOverlayTexture( String ovrTex ) { return overlayTexture( new ResourceLocation( ovrTex ) ); }
|
||||
|
||||
|
||||
//--------------- Textures (Auto-selected) ----------------
|
||||
|
@ -351,19 +408,19 @@ public class BestiaryInfo {
|
|||
public Builder noAnimationTexture() { return noOverlayTexture(); }
|
||||
|
||||
/** Sets the species default base texture. */
|
||||
private Builder baseTexture( ResourceLocation tex ) {
|
||||
private Builder baseTexture( @Nullable ResourceLocation tex ) {
|
||||
texture = tex;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Sets the species default glowing eyes texture. */
|
||||
private Builder eyesTexture( ResourceLocation eyeTex ) {
|
||||
private Builder eyesTexture( @Nullable ResourceLocation eyeTex ) {
|
||||
eyesTexture = eyeTex;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Sets the species default overlay texture. */
|
||||
private Builder overlayTexture( ResourceLocation ovrTex ) {
|
||||
private Builder overlayTexture( @Nullable ResourceLocation ovrTex ) {
|
||||
overlayTexture = ovrTex;
|
||||
return this;
|
||||
}
|
||||
|
@ -435,6 +492,12 @@ public class BestiaryInfo {
|
|||
return this;
|
||||
}
|
||||
|
||||
/** Sets the species as NOT damaged by water. */
|
||||
public Builder waterInsensitive() {
|
||||
isDamagedByWater = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Sets the species as leashable (can have a lead attached). */
|
||||
public Builder leashable() {
|
||||
allowLeashing = true;
|
||||
|
@ -476,6 +539,11 @@ public class BestiaryInfo {
|
|||
return rangedDamage( damage ).rangedSpread( spread ).rangedWalkSpeed( walkSpeed ).rangedCooldown( cooldown ).rangedMaxRange( range );
|
||||
}
|
||||
|
||||
/** Sets the species ranged attack stats (for a throwing item user). */
|
||||
public Builder throwAttack( double spread, double walkSpeed, int cooldown, double range ) {
|
||||
return rangedSpread( spread ).rangedWalkSpeed( walkSpeed ).rangedCooldown( cooldown ).rangedMaxRange( range );
|
||||
}
|
||||
|
||||
/** Sets the species ranged attack stats (for a fireball shooter). */
|
||||
public Builder fireballAttack( double spread, int charge, int cooldown, double range ) {
|
||||
return rangedSpread( spread ).rangedCooldown( charge ).rangedMaxCooldown( charge + cooldown ).rangedMaxRange( range );
|
||||
|
|
|
@ -6,7 +6,6 @@ import fathertoast.specialmobs.common.core.register.SMEntities;
|
|||
import fathertoast.specialmobs.common.core.register.SMItems;
|
||||
import fathertoast.specialmobs.common.util.AnnotationHelper;
|
||||
import fathertoast.specialmobs.common.util.References;
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityType;
|
||||
|
@ -18,7 +17,6 @@ import net.minecraftforge.common.ForgeSpawnEggItem;
|
|||
import net.minecraftforge.fml.RegistryObject;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
|
||||
|
@ -28,8 +26,6 @@ import java.util.function.Function;
|
|||
*
|
||||
* @see MobFamily.Species
|
||||
*/
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
public class MobFamily<T extends LivingEntity, V extends FamilyConfig> {
|
||||
/** List of all families, generated to make iteration possible. */
|
||||
private static final ArrayList<MobFamily<?, ?>> FAMILY_LIST = new ArrayList<>();
|
||||
|
@ -44,18 +40,22 @@ public class MobFamily<T extends LivingEntity, V extends FamilyConfig> {
|
|||
public static final MobFamily<CreeperEntity, CreeperFamilyConfig> CREEPER = new MobFamily<>( CreeperFamilyConfig::new,
|
||||
"Creeper", "creepers", 0x0DA70B, new EntityType[] { EntityType.CREEPER },
|
||||
"Dark", "Death", "Dirt", "Doom", "Drowning", "Ender", "Fire", "Gravel", "Jumping", "Lightning",
|
||||
"Mini", /*"Scope",*/ "Skeleton", "Splitting"
|
||||
);
|
||||
"Mini", "Sand", /*"Scope",*/ "Snow", "Skeleton", "Splitting"
|
||||
);//TODO scope
|
||||
|
||||
public static final MobFamily<ZombieEntity, FamilyConfig> ZOMBIE = new MobFamily<>( FamilyConfig::newLessSpecial,
|
||||
"Zombie", "zombies", 0x00AFAF, new EntityType[] { EntityType.ZOMBIE, EntityType.HUSK },
|
||||
"Brute", "Fire", /*"Fishing",*/ "Giant", "Hungry", "Husk", "MadScientist", "Plague"
|
||||
);
|
||||
);//TODO fishing
|
||||
// TODO Drowned family and zombie transform mechanic
|
||||
// public static final MobFamily<ZombieEntity, FamilyConfig> DROWNED = new MobFamily<>( FamilyConfig::new,
|
||||
// "Zombie", "zombies", 0x8FF1D7, new EntityType[] { EntityType.DROWNED }, //VR egg: 0x799C65
|
||||
// "Brute", /*"Fishing",*/ "Giant", "Hungry", "Knight", "Plague"
|
||||
// );
|
||||
public static final MobFamily<ZombifiedPiglinEntity, FamilyConfig> ZOMBIFIED_PIGLIN = new MobFamily<>( FamilyConfig::new,
|
||||
"ZombifiedPiglin", "zombified piglins", 0xEA9393, new EntityType[] { EntityType.ZOMBIFIED_PIGLIN },
|
||||
"Brute", /*"Fishing",*/ "Giant", "Hungry", "Knight", "Plague", "Vampire"//TODO figure out crossbows
|
||||
);
|
||||
);//TODO fishing
|
||||
|
||||
public static final MobFamily<AbstractSkeletonEntity, SkeletonFamilyConfig> SKELETON = new MobFamily<>( SkeletonFamilyConfig::new,
|
||||
"Skeleton", "skeletons", 0xC1C1C1, new EntityType[] { EntityType.SKELETON, EntityType.STRAY },
|
||||
|
@ -77,21 +77,21 @@ public class MobFamily<T extends LivingEntity, V extends FamilyConfig> {
|
|||
|
||||
public static final MobFamily<SpiderEntity, FamilyConfig> SPIDER = new MobFamily<>( FamilyConfig::newMoreSpecial,
|
||||
"Spider", "spiders", 0x342D27, new EntityType[] { EntityType.SPIDER },
|
||||
"Baby", "Desert", "Flying", "Giant", "Hungry", "Mother", "Pale", "Poison", /*"Water",*/ "Web", "Witch"
|
||||
"Baby", "Desert", "Fire", "Flying", "Giant", "Hungry", "Mother", "Pale", "Poison", "Water", "Web", "Witch"
|
||||
);
|
||||
public static final MobFamily<CaveSpiderEntity, FamilyConfig> CAVE_SPIDER = new MobFamily<>( FamilyConfig::newMoreSpecial,
|
||||
"CaveSpider", "cave spiders", 0x0C424E, new EntityType[] { EntityType.CAVE_SPIDER },
|
||||
"Baby", "Flying", "Mother", /*"Water",*/ "Web", "Witch"
|
||||
"Baby", "Desert", "Fire", "Flying", "Mother", "Pale", "Water", "Web", "Witch"
|
||||
);
|
||||
|
||||
public static final MobFamily<SilverfishEntity, SilverfishFamilyConfig> SILVERFISH = new MobFamily<>( SilverfishFamilyConfig::new,
|
||||
"Silverfish", "silverfish", 0x6E6E6E, new EntityType[] { EntityType.SILVERFISH },
|
||||
"Blinding", /*"Fishing",*/ "Flying", "Poison", /*"Puffer",*/ "Tough"
|
||||
);
|
||||
"Blinding", "Desiccated", /*"Fishing",*/ "Flying", "Poison", /*"Puffer",*/ "Tough"
|
||||
);//TODO fishing, puffer
|
||||
|
||||
public static final MobFamily<EndermanEntity, FamilyConfig> ENDERMAN = new MobFamily<>( FamilyConfig::new,
|
||||
"Enderman", "endermen", 0x161616, new EntityType[] { EntityType.ENDERMAN },
|
||||
"Blinding", "Icy", "Lightning", "Mini", "Mirage", "Thief"
|
||||
"Blinding", "Flame", "Icy", "Lightning", "Mini", "Mirage", "Runic", "Thief"
|
||||
);
|
||||
|
||||
public static final MobFamily<WitchEntity, WitchFamilyConfig> WITCH = new MobFamily<>( WitchFamilyConfig::new,
|
||||
|
@ -101,7 +101,7 @@ public class MobFamily<T extends LivingEntity, V extends FamilyConfig> {
|
|||
|
||||
public static final MobFamily<GhastEntity, GhastFamilyConfig> GHAST = new MobFamily<>( GhastFamilyConfig::new,
|
||||
"Ghast", "ghasts", 0xF9F9F9, new EntityType[] { EntityType.GHAST },
|
||||
"Baby", "Fighter", "King", "Queen", "Unholy", "CorporealShift"
|
||||
"Baby", "CorporealShift", "Fighter", "King", "Queen", "Unholy"
|
||||
);
|
||||
|
||||
public static final MobFamily<BlazeEntity, FamilyConfig> BLAZE = new MobFamily<>( FamilyConfig::new,
|
||||
|
@ -196,31 +196,10 @@ public class MobFamily<T extends LivingEntity, V extends FamilyConfig> {
|
|||
}
|
||||
|
||||
/** Pick a new species from this family, based on the location. */
|
||||
public Species<? extends T> nextVariant( World world, BlockPos pos ) {
|
||||
// Build weights for the current location
|
||||
int totalWeight = 0;
|
||||
final int[] variantWeights = new int[variants.length];
|
||||
for( int i = 0; i < variants.length; i++ ) {
|
||||
final int weight = config.GENERAL.specialVariantWeights[i].get(); //TODO environment exceptions
|
||||
if( weight > 0 ) {
|
||||
totalWeight += weight;
|
||||
variantWeights[i] = weight;
|
||||
}
|
||||
}
|
||||
|
||||
// Pick one item at random
|
||||
if( totalWeight > 0 ) {
|
||||
int weight = world.random.nextInt( totalWeight );
|
||||
for( int i = 0; i < variants.length; i++ ) {
|
||||
if( variantWeights[i] > 0 ) {
|
||||
weight -= variantWeights[i];
|
||||
if( weight < 0 ) {
|
||||
return variants[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return vanillaReplacement;
|
||||
public Species<? extends T> nextVariant( World world, @Nullable BlockPos pos ) {
|
||||
final Species<?> species = config.GENERAL.specialVariantList.next( world.random, world, pos );
|
||||
//noinspection unchecked
|
||||
return species == null ? vanillaReplacement : (Species<? extends T>) species;
|
||||
}
|
||||
|
||||
|
||||
|
@ -238,8 +217,6 @@ public class MobFamily<T extends LivingEntity, V extends FamilyConfig> {
|
|||
*
|
||||
* @see MobFamily
|
||||
*/
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
public static class Species<T extends LivingEntity> {
|
||||
/** The special mob family this species belongs to. */
|
||||
public final MobFamily<? super T, ?> family;
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
@MethodsReturnNonnullByDefault
|
||||
@ParametersAreNonnullByDefault
|
||||
package fathertoast.specialmobs.common.bestiary;
|
||||
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
|
@ -0,0 +1,7 @@
|
|||
@MethodsReturnNonnullByDefault
|
||||
@ParametersAreNonnullByDefault
|
||||
package fathertoast.specialmobs.common.compat.top;
|
||||
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
|
@ -24,6 +24,7 @@ public class Config {
|
|||
/** Performs initial loading of all configs in this mod. */
|
||||
public static void initialize() {
|
||||
ToastConfigSpec.freezeFileWatcher = true;
|
||||
ReadMeConfig.makeReadMe( CONFIG_DIR );
|
||||
MAIN.SPEC.initialize();
|
||||
MobFamily.initBestiary();
|
||||
ToastConfigSpec.freezeFileWatcher = false;
|
||||
|
|
|
@ -15,20 +15,6 @@ public class MainConfig extends Config.AbstractConfig {
|
|||
super( dir, fileName,
|
||||
"This config contains options that apply to the mod as a whole, including some master settings",
|
||||
"toggles for convenience." );
|
||||
SPEC.newLine();
|
||||
SPEC.comment(
|
||||
"Terminology used in Special Mobs configs:",
|
||||
" * Mob - An entity that is 'alive', short for \"Mobile\" or MobEntity.",
|
||||
" * Family - The group of mobs based on (but not including) a particular vanilla mob; e.g., Creepers.",
|
||||
" * Species - A specific type of mob within a family; e.g., Fire Creepers or vanilla-replacement Creepers.",
|
||||
" * Vanilla Replacement - The one species within a family that is intended to be a replica of the base vanilla mob.",
|
||||
" * Special Variant - Any species that is not the family's vanilla replacement. Includes species that are",
|
||||
" replicas of 'vanilla special variants'; i.e. Husks and Strays.",
|
||||
" * Mob Replacer - The tool that watches vanilla mob spawns and cancels them to spawn this mod's entities." );
|
||||
SPEC.newLine();
|
||||
SPEC.describeAttributeList();
|
||||
SPEC.newLine();
|
||||
SPEC.describeRegistryEntryList();
|
||||
|
||||
GENERAL = new General( SPEC );
|
||||
}
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
package fathertoast.specialmobs.common.config;
|
||||
|
||||
import fathertoast.specialmobs.common.config.field.BooleanField;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class ReadMeConfig extends Config.AbstractConfig {
|
||||
@SuppressWarnings( "SameParameterValue" )
|
||||
static void makeReadMe( File dir ) { new ReadMeConfig( dir ).SPEC.initialize(); }
|
||||
|
||||
/** Builds the config spec that should be used for this config. */
|
||||
private ReadMeConfig( File dir ) {
|
||||
super( dir, "__README__", "This file contains helpful information about how to use the config files in this mod." );
|
||||
SPEC.newLine( 2 );
|
||||
SPEC.comment(
|
||||
"Terminology used in Special Mobs configs:",
|
||||
" * Mob - An entity that is 'alive', short for \"Mobile\" or MobEntity.",
|
||||
" * Family - The group of mobs based on (but not including) a particular vanilla mob; e.g., Creepers.",
|
||||
" * Species - A specific type of mob within a family; e.g., Fire Creepers or vanilla-replacement Creepers.",
|
||||
" * Vanilla Replacement - The one species within a family that is intended to be a replica of the base vanilla mob.",
|
||||
" * Special Variant - Any species that is not the family's vanilla replacement. Includes species that are",
|
||||
" replicas of 'vanilla special variants'; i.e. Husks and Strays.",
|
||||
" * Mob Replacer - The tool that watches vanilla mob spawns and cancels them to spawn this mod's entities." );
|
||||
SPEC.newLine( 2 );
|
||||
SPEC.describeAttributeList();
|
||||
SPEC.newLine( 2 );
|
||||
SPEC.describeRegistryEntryList();
|
||||
SPEC.newLine( 2 );
|
||||
SPEC.describeEnvironmentListPart1of2();
|
||||
SPEC.newLine();
|
||||
SPEC.describeEnvironmentListPart2of2();
|
||||
|
||||
SPEC.newLine( 4 );
|
||||
SPEC.define( new BooleanField( "secret_mode", false, (String[]) null ) );
|
||||
}
|
||||
}
|
|
@ -4,10 +4,12 @@ import fathertoast.specialmobs.common.bestiary.MobFamily;
|
|||
import fathertoast.specialmobs.common.config.Config;
|
||||
import fathertoast.specialmobs.common.config.field.BooleanField;
|
||||
import fathertoast.specialmobs.common.config.field.DoubleField;
|
||||
import fathertoast.specialmobs.common.config.field.IntField;
|
||||
import fathertoast.specialmobs.common.config.field.EnvironmentListField;
|
||||
import fathertoast.specialmobs.common.config.file.ToastConfigSpec;
|
||||
import fathertoast.specialmobs.common.config.file.TomlHelper;
|
||||
import fathertoast.specialmobs.common.config.util.ConfigUtil;
|
||||
import fathertoast.specialmobs.common.config.util.EnvironmentEntry;
|
||||
import fathertoast.specialmobs.common.config.util.EnvironmentList;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
@ -51,9 +53,9 @@ public class FamilyConfig extends Config.AbstractConfig {
|
|||
|
||||
public final DoubleField familyRandomScaling;
|
||||
|
||||
public final DoubleField specialVariantChance;
|
||||
public final DoubleField.EnvironmentSensitive specialVariantChance;
|
||||
|
||||
public final IntField[] specialVariantWeights;
|
||||
public final DoubleField.EnvironmentSensitiveWeightedList<MobFamily.Species<?>> specialVariantList;
|
||||
|
||||
General( ToastConfigSpec parent, MobFamily<?, ?> family, double variantChance ) {
|
||||
super( parent, "general",
|
||||
|
@ -72,27 +74,49 @@ public class FamilyConfig extends Config.AbstractConfig {
|
|||
|
||||
SPEC.newLine();
|
||||
|
||||
specialVariantChance = SPEC.define( new DoubleField( "special_variant_chance", variantChance, DoubleField.Range.PERCENT,
|
||||
"The chance for " + family.configName + " to spawn as special variants." ) );
|
||||
// TODO special variant chance exceptions
|
||||
specialVariantChance = new DoubleField.EnvironmentSensitive(
|
||||
SPEC.define( new DoubleField( "special_variant_chance.base", variantChance, DoubleField.Range.PERCENT,
|
||||
"The chance for " + family.configName + " to spawn as special variants." ) ),
|
||||
SPEC.define( new EnvironmentListField( "special_variant_chance.exceptions", new EnvironmentList(
|
||||
EnvironmentEntry.builder( (float) variantChance * 0.5F ).beforeDays( 5 ).build(), // Also skips first night's full moon
|
||||
EnvironmentEntry.builder( (float) variantChance * 2.0F ).atMaxMoonLight().aboveDifficulty( 0.5F ).build(),
|
||||
EnvironmentEntry.builder( (float) variantChance * 1.5F ).atMaxMoonLight().build(),
|
||||
EnvironmentEntry.builder( (float) variantChance * 1.5F ).aboveDifficulty( 0.5F ).build() )
|
||||
.setRange( DoubleField.Range.PERCENT ),
|
||||
"The chance for " + family.configName + " to spawn as special variants when specific environmental conditions are met." ) )
|
||||
);
|
||||
|
||||
SPEC.newLine();
|
||||
|
||||
List<String> comment;
|
||||
final DoubleField[] baseWeights = new DoubleField[family.variants.length];
|
||||
final EnvironmentListField[] weightExceptions = new EnvironmentListField[family.variants.length];
|
||||
|
||||
// TODO consider wrapping this all up into an 'environment sensitive weighted list' config object? seems handy
|
||||
comment = TomlHelper.newComment(
|
||||
"The weight of each " + ConfigUtil.camelCaseToLowerSpace( family.name ) + " species to be chosen as the replacement when",
|
||||
family.configName + " spawn as special variants. Higher weight is more common." );
|
||||
comment.add( TomlHelper.multiFieldInfo( IntField.Range.NON_NEGATIVE ) );
|
||||
comment.add( TomlHelper.multiFieldInfo( DoubleField.Range.NON_NEGATIVE ) );
|
||||
SPEC.comment( comment );
|
||||
specialVariantWeights = new IntField[family.variants.length];
|
||||
for( int i = 0; i < specialVariantWeights.length; i++ ) {
|
||||
specialVariantWeights[i] = SPEC.define( new IntField(
|
||||
"weight." + ConfigUtil.camelCaseToLowerUnderscore( family.variants[i].specialVariantName ),
|
||||
family.variants[i].bestiaryInfo.defaultWeight.value, IntField.Range.NON_NEGATIVE, (String[]) null ) );
|
||||
for( int i = 0; i < family.variants.length; i++ ) {
|
||||
baseWeights[i] = SPEC.define( new DoubleField(
|
||||
"weight." + ConfigUtil.camelCaseToLowerUnderscore( family.variants[i].specialVariantName ) + ".base",
|
||||
family.variants[i].bestiaryInfo.defaultWeight.value, DoubleField.Range.NON_NEGATIVE, (String[]) null ) );
|
||||
}
|
||||
// TODO special variant weights exceptions
|
||||
|
||||
SPEC.newLine();
|
||||
|
||||
comment = TomlHelper.newComment(
|
||||
"The weight of each " + ConfigUtil.camelCaseToLowerSpace( family.name ) + " species to be chosen as the replacement when",
|
||||
family.configName + " spawn as special variants when specific environmental conditions are met. Higher weight is more common." );
|
||||
comment.add( TomlHelper.multiFieldInfo( DoubleField.Range.NON_NEGATIVE ) );
|
||||
SPEC.comment( comment );
|
||||
for( int i = 0; i < family.variants.length; i++ ) {
|
||||
weightExceptions[i] = SPEC.define( new EnvironmentListField(
|
||||
"weight." + ConfigUtil.camelCaseToLowerUnderscore( family.variants[i].specialVariantName ) + ".exceptions",
|
||||
family.variants[i].bestiaryInfo.theme.value, (String[]) null ) );
|
||||
}
|
||||
|
||||
specialVariantList = new DoubleField.EnvironmentSensitiveWeightedList<>( family.variants, baseWeights, weightExceptions );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
@MethodsReturnNonnullByDefault
|
||||
@ParametersAreNonnullByDefault
|
||||
package fathertoast.specialmobs.common.config.family;
|
||||
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
|
@ -25,7 +25,7 @@ public abstract class AbstractConfigField {
|
|||
* Creates a new field with the supplied key and description.
|
||||
* If the description is null, it will cancel the entire comment, including the automatic field info text.
|
||||
*/
|
||||
protected AbstractConfigField( String key, String... description ) {
|
||||
protected AbstractConfigField( String key, @Nullable String... description ) {
|
||||
this( loadingCategory + key, description == null ? null : TomlHelper.newComment( description ) );
|
||||
}
|
||||
|
||||
|
@ -33,7 +33,7 @@ public abstract class AbstractConfigField {
|
|||
* Creates a new field with the supplied key and comment. This method is only used for very special circumstances.
|
||||
* If the comment is null, it will cancel the entire comment, including the automatic field info text.
|
||||
*/
|
||||
AbstractConfigField( String key, List<String> comment ) {
|
||||
AbstractConfigField( String key, @Nullable List<String> comment ) {
|
||||
KEY = key;
|
||||
COMMENT = comment;
|
||||
}
|
||||
|
|
|
@ -42,16 +42,10 @@ public class AttributeListField extends GenericField<AttributeList> {
|
|||
public ConfigDrivenAttributeModifierMap linkedAttributeMap;
|
||||
|
||||
/** Creates a new field. */
|
||||
public AttributeListField( String key, AttributeList defaultValue, String... description ) {
|
||||
public AttributeListField( String key, AttributeList defaultValue, @Nullable String... description ) {
|
||||
super( key, defaultValue, description );
|
||||
}
|
||||
|
||||
/** Applies all attribute changes in this list to the entity attribute builder. */
|
||||
public void apply( AttributeModifierMap.MutableAttribute builder ) { get().apply( builder ); }
|
||||
|
||||
/** Applies all attribute changes in this list to the entity. */
|
||||
public void apply( LivingEntity entity ) { get().apply( entity ); }
|
||||
|
||||
/** Adds info about the field type, format, and bounds to the end of a field's description. */
|
||||
public void appendFieldInfo( List<String> comment ) {
|
||||
comment.add( TomlHelper.fieldInfoFormat( "Attribute List", valueDefault,
|
||||
|
@ -81,7 +75,7 @@ public class AttributeListField extends GenericField<AttributeList> {
|
|||
if( linkedAttributeMap != null ) linkedAttributeMap.invalidate();
|
||||
}
|
||||
|
||||
/** Parses a single entry line and returns a valid result if possible, or null if the entry is completely invalid. */
|
||||
/** Parses a single entry line and returns a valid result. */
|
||||
private AttributeEntry parseEntry( final String line ) {
|
||||
// Parse the attribute-operation-value array
|
||||
final String[] args = line.split( " ", 4 );
|
||||
|
@ -148,4 +142,13 @@ public class AttributeListField extends GenericField<AttributeList> {
|
|||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
// Convenience methods
|
||||
|
||||
/** Applies all attribute changes in this list to the entity attribute builder. */
|
||||
public void apply( AttributeModifierMap.MutableAttribute builder ) { get().apply( builder ); }
|
||||
|
||||
/** Applies all attribute changes in this list to the entity. */
|
||||
public void apply( LivingEntity entity ) { get().apply( entity ); }
|
||||
}
|
|
@ -28,7 +28,7 @@ public class BlockListField extends GenericField<BlockList> {
|
|||
}
|
||||
|
||||
/** Creates a new field. */
|
||||
public BlockListField( String key, BlockList defaultValue, String... description ) {
|
||||
public BlockListField( String key, BlockList defaultValue, @Nullable String... description ) {
|
||||
super( key, defaultValue, description );
|
||||
}
|
||||
|
||||
|
@ -53,6 +53,15 @@ public class BlockListField extends GenericField<BlockList> {
|
|||
value = new BlockList( this, TomlHelper.parseStringList( raw ) );
|
||||
}
|
||||
|
||||
|
||||
// Convenience methods
|
||||
|
||||
/** @return Returns true if there are no entries in this block list. */
|
||||
public boolean isEmpty() { return get().isEmpty(); }
|
||||
|
||||
/** @return Returns true if the block is contained in this list. */
|
||||
public boolean matches( BlockState blockState ) { return get().matches( blockState ); }
|
||||
|
||||
/**
|
||||
* Represents two block list fields, a blacklist and a whitelist, combined into one.
|
||||
*/
|
||||
|
@ -73,7 +82,7 @@ public class BlockListField extends GenericField<BlockList> {
|
|||
|
||||
/** @return Returns true if the block is contained in this list. */
|
||||
public boolean matches( BlockState blockState ) {
|
||||
return blockState != null && !BLACKLIST.get().matches( blockState ) && WHITELIST.get().matches( blockState );
|
||||
return !BLACKLIST.get().matches( blockState ) && WHITELIST.get().matches( blockState );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -18,7 +18,7 @@ public class BooleanField extends AbstractConfigField {
|
|||
private boolean value;
|
||||
|
||||
/** Creates a new field. */
|
||||
public BooleanField( String key, boolean defaultValue, String... description ) {
|
||||
public BooleanField( String key, boolean defaultValue, @Nullable String... description ) {
|
||||
super( key, description );
|
||||
valueDefault = defaultValue;
|
||||
}
|
||||
|
|
|
@ -2,8 +2,12 @@ package fathertoast.specialmobs.common.config.field;
|
|||
|
||||
import fathertoast.specialmobs.common.config.file.TomlHelper;
|
||||
import fathertoast.specialmobs.common.core.SpecialMobs;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
|
@ -23,12 +27,12 @@ public class DoubleField extends AbstractConfigField {
|
|||
private double value;
|
||||
|
||||
/** Creates a new field that accepts a common range of values. */
|
||||
public DoubleField( String key, double defaultValue, Range range, String... description ) {
|
||||
public DoubleField( String key, double defaultValue, Range range, @Nullable String... description ) {
|
||||
this( key, defaultValue, range.MIN, range.MAX, description );
|
||||
}
|
||||
|
||||
/** Creates a new field that accepts a specialized range of values. */
|
||||
public DoubleField( String key, double defaultValue, double min, double max, String... description ) {
|
||||
public DoubleField( String key, double defaultValue, double min, double max, @Nullable String... description ) {
|
||||
super( key, description );
|
||||
valueDefault = defaultValue;
|
||||
valueMin = min;
|
||||
|
@ -156,4 +160,89 @@ public class DoubleField extends AbstractConfigField {
|
|||
return getMin();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a double field and an environment exception list, combined into one.
|
||||
* This has convenience methods for returning the value that should be used based on the environment.
|
||||
*/
|
||||
public static class EnvironmentSensitive {
|
||||
/** The base value. */
|
||||
private final DoubleField BASE;
|
||||
/** The environment exceptions list. */
|
||||
private final EnvironmentListField EXCEPTIONS;
|
||||
|
||||
/** Links two fields together as base and exceptions. */
|
||||
public EnvironmentSensitive( DoubleField base, EnvironmentListField exceptions ) {
|
||||
BASE = base;
|
||||
EXCEPTIONS = exceptions;
|
||||
}
|
||||
|
||||
/** @return Returns the config field's value. */
|
||||
public double get( World world, @Nullable BlockPos pos ) { return EXCEPTIONS.getOrElse( world, pos, BASE ); }
|
||||
|
||||
/** @return Treats the config field's value as a percent chance (from 0 to 1) and returns the result of a single roll. */
|
||||
public boolean rollChance( Random random, World world, @Nullable BlockPos pos ) { return random.nextDouble() < get( world, pos ); }
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an environment sensitive list of weighted values. Unlike the normal weighted list, this is just a simple
|
||||
* wrapper class, and its weights are doubles.
|
||||
* It sacrifices automation for flexibility, largely to help with the craziness of environment list fields.
|
||||
*/
|
||||
public static class EnvironmentSensitiveWeightedList<T> {
|
||||
|
||||
private final List<Entry<T>> UNDERLYING_LIST;
|
||||
|
||||
/** Links an array of values to two arrays of fields as base weights and exceptions. */
|
||||
public EnvironmentSensitiveWeightedList( T[] values, DoubleField[] baseWeights, EnvironmentListField[] weightExceptions ) {
|
||||
if( values.length != baseWeights.length || values.length != weightExceptions.length )
|
||||
throw new IllegalArgumentException( "All arrays must be equal length!" );
|
||||
|
||||
final ArrayList<Entry<T>> list = new ArrayList<>();
|
||||
for( int i = 0; i < values.length; i++ ) {
|
||||
list.add( new Entry<>( values[i], new EnvironmentSensitive( baseWeights[i], weightExceptions[i] ) ) );
|
||||
|
||||
// Do a bit of error checking; allows us to ignore the possibility of negative weights
|
||||
if( baseWeights[i].valueMin < 0.0 || weightExceptions[i].valueDefault.getMinValue() < 0.0 ) {
|
||||
throw new IllegalArgumentException( "Weight is not allowed to be negative! See " +
|
||||
baseWeights[i].getKey() + " and/or " + weightExceptions[i].getKey() );
|
||||
}
|
||||
}
|
||||
list.trimToSize();
|
||||
UNDERLYING_LIST = Collections.unmodifiableList( list );
|
||||
}
|
||||
|
||||
/** @return Returns a random item from this weighted list. Null if none of the items have a positive weight. */
|
||||
@Nullable
|
||||
public T next( Random random, World world, @Nullable BlockPos pos ) {
|
||||
// Due to the 'nebulous' nature of environment-based weights, we must recalculate weights for EVERY call
|
||||
final double[] weights = new double[UNDERLYING_LIST.size()];
|
||||
double targetWeight = 0.0;
|
||||
for( int i = 0; i < weights.length; i++ ) {
|
||||
targetWeight += weights[i] = UNDERLYING_LIST.get( i ).WEIGHT.get( world, pos );
|
||||
}
|
||||
if( targetWeight <= 0.0 ) return null;
|
||||
|
||||
// Now we unravel the target weight to a random point
|
||||
targetWeight *= random.nextDouble();
|
||||
for( int i = 0; i < weights.length; i++ ) {
|
||||
targetWeight -= weights[i];
|
||||
if( targetWeight < 0.0 ) return UNDERLYING_LIST.get( i ).VALUE;
|
||||
}
|
||||
|
||||
SpecialMobs.LOG.error( "Environment-sensitive weight list was unable to return a value when it should have! " +
|
||||
"This is probably due to error in floating point calculations, perhaps try changing the scale of weights." );
|
||||
return null;
|
||||
}
|
||||
|
||||
private static class Entry<T> {
|
||||
final T VALUE;
|
||||
final DoubleField.EnvironmentSensitive WEIGHT;
|
||||
|
||||
Entry( T value, DoubleField.EnvironmentSensitive weight ) {
|
||||
VALUE = value;
|
||||
WEIGHT = weight;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,10 +5,8 @@ import fathertoast.specialmobs.common.config.util.EntityEntry;
|
|||
import fathertoast.specialmobs.common.config.util.EntityList;
|
||||
import fathertoast.specialmobs.common.core.SpecialMobs;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
|
@ -35,7 +33,7 @@ public class EntityListField extends GenericField<EntityList> {
|
|||
}
|
||||
|
||||
/** Creates a new field. */
|
||||
public EntityListField( String key, EntityList defaultValue, String... description ) {
|
||||
public EntityListField( String key, EntityList defaultValue, @Nullable String... description ) {
|
||||
super( key, defaultValue, description );
|
||||
}
|
||||
|
||||
|
@ -85,16 +83,12 @@ public class EntityListField extends GenericField<EntityList> {
|
|||
List<String> list = TomlHelper.parseStringList( raw );
|
||||
List<EntityEntry> entryList = new ArrayList<>();
|
||||
for( String line : list ) {
|
||||
EntityEntry entry = parseEntry( line );
|
||||
if( entry != null ) {
|
||||
entryList.add( entry );
|
||||
}
|
||||
entryList.add( parseEntry( line ) );
|
||||
}
|
||||
value = new EntityList( entryList );
|
||||
}
|
||||
|
||||
/** Parses a single entry line and returns a valid result if possible, or null if the entry is completely invalid. */
|
||||
@Nullable
|
||||
/** Parses a single entry line and returns the result. */
|
||||
private EntityEntry parseEntry( final String line ) {
|
||||
String modifiedLine = line;
|
||||
|
||||
|
@ -110,20 +104,14 @@ public class EntityListField extends GenericField<EntityList> {
|
|||
|
||||
// Parse the entity-value array
|
||||
final String[] args = modifiedLine.split( " " );
|
||||
final EntityType<? extends Entity> entityType;
|
||||
final ResourceLocation regKey;
|
||||
if( REG_KEY_DEFAULT.equalsIgnoreCase( args[0].trim() ) ) {
|
||||
// Handle the special case of a default entry
|
||||
entityType = null;
|
||||
regKey = null;
|
||||
}
|
||||
else {
|
||||
// Normal entry
|
||||
final ResourceLocation regKey = new ResourceLocation( args[0].trim() );
|
||||
if( !ForgeRegistries.ENTITIES.containsKey( regKey ) ) {
|
||||
SpecialMobs.LOG.warn( "Invalid entry for {} \"{}\"! Deleting entry. Invalid entry: {}",
|
||||
getClass(), getKey(), line );
|
||||
return null;
|
||||
}
|
||||
entityType = ForgeRegistries.ENTITIES.getValue( regKey );
|
||||
regKey = new ResourceLocation( args[0].trim() );
|
||||
}
|
||||
final List<Double> valuesList = new ArrayList<>();
|
||||
final int reqValues = valueDefault.getRequiredValues();
|
||||
|
@ -173,7 +161,7 @@ public class EntityListField extends GenericField<EntityList> {
|
|||
for( int i = 0; i < values.length; i++ ) {
|
||||
values[i] = valuesList.get( i );
|
||||
}
|
||||
return new EntityEntry( entityType, extendable, values );
|
||||
return new EntityEntry( this, regKey, extendable, values );
|
||||
}
|
||||
|
||||
/** Parses a single value argument and returns a valid result. */
|
||||
|
@ -203,6 +191,36 @@ public class EntityListField extends GenericField<EntityList> {
|
|||
return value;
|
||||
}
|
||||
|
||||
|
||||
// Convenience methods
|
||||
|
||||
/** @return True if the entity is contained in this list. */
|
||||
public boolean contains( @Nullable Entity entity ) { return get().contains( entity ); }
|
||||
|
||||
/**
|
||||
* @param entity The entity to retrieve values for.
|
||||
* @return The array of values of the best-match entry. Returns null if the entity is not contained in this entity list.
|
||||
*/
|
||||
@Nullable
|
||||
public double[] getValues( @Nullable Entity entity ) { return get().getValues( entity ); }
|
||||
|
||||
/**
|
||||
* @param entity The entity to retrieve a value for.
|
||||
* @return The first value in the best-match entry's value array. Returns 0 if the entity is not contained in this
|
||||
* entity list or has no values specified. This should only be used for 'single value' lists.
|
||||
* @see EntityList#setSingleValue()
|
||||
* @see EntityList#setSinglePercent()
|
||||
*/
|
||||
public double getValue( @Nullable Entity entity ) { return get().getValue( entity ); }
|
||||
|
||||
/**
|
||||
* @param entity The entity to roll a value for.
|
||||
* @return Randomly rolls the first percentage value in the best-match entry's value array. Returns false if the entity
|
||||
* is not contained in this entity list or has no values specified. This should only be used for 'single percent' lists.
|
||||
* @see EntityList#setSinglePercent()
|
||||
*/
|
||||
public boolean rollChance( @Nullable LivingEntity entity ) { return get().rollChance( entity ); }
|
||||
|
||||
/**
|
||||
* Represents two entity list fields, a blacklist and a whitelist, combined into one.
|
||||
* The blacklist cannot contain values, but the whitelist can have any settings.
|
||||
|
@ -222,17 +240,21 @@ public class EntityListField extends GenericField<EntityList> {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// Convenience methods
|
||||
|
||||
/** @return True if the entity is contained in this list. */
|
||||
public boolean contains( Entity entity ) {
|
||||
return entity != null && !BLACKLIST.get().contains( entity ) && WHITELIST.get().contains( entity );
|
||||
public boolean contains( @Nullable Entity entity ) {
|
||||
return entity != null && !BLACKLIST.contains( entity ) && WHITELIST.contains( entity );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param entity The entity to retrieve values for.
|
||||
* @return The array of values of the best-match entry. Returns null if the entity is not contained in this entity list.
|
||||
*/
|
||||
public double[] getValues( Entity entity ) {
|
||||
return entity != null && !BLACKLIST.get().contains( entity ) ? WHITELIST.get().getValues( entity ) : null;
|
||||
@Nullable
|
||||
public double[] getValues( @Nullable Entity entity ) {
|
||||
return entity != null && !BLACKLIST.contains( entity ) ? WHITELIST.getValues( entity ) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -242,8 +264,8 @@ public class EntityListField extends GenericField<EntityList> {
|
|||
* @see EntityList#setSingleValue()
|
||||
* @see EntityList#setSinglePercent()
|
||||
*/
|
||||
public double getValue( Entity entity ) {
|
||||
return entity != null && !BLACKLIST.get().contains( entity ) ? WHITELIST.get().getValue( entity ) : 0.0;
|
||||
public double getValue( @Nullable Entity entity ) {
|
||||
return entity != null && !BLACKLIST.contains( entity ) ? WHITELIST.getValue( entity ) : 0.0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -252,8 +274,8 @@ public class EntityListField extends GenericField<EntityList> {
|
|||
* is not contained in this entity list or has no values specified. This should only be used for 'single percent' lists.
|
||||
* @see EntityList#setSinglePercent()
|
||||
*/
|
||||
public boolean rollChance( LivingEntity entity ) {
|
||||
return entity != null && !BLACKLIST.get().contains( entity ) && WHITELIST.get().rollChance( entity );
|
||||
public boolean rollChance( @Nullable LivingEntity entity ) {
|
||||
return entity != null && !BLACKLIST.contains( entity ) && WHITELIST.rollChance( entity );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,13 +14,13 @@ public class EnumField<T extends Enum<T>> extends GenericField<T> {
|
|||
private final T[] valuesValid;
|
||||
|
||||
/** Creates a new field that accepts any enum value. */
|
||||
public EnumField( String key, T defaultValue, String... description ) {
|
||||
public EnumField( String key, T defaultValue, @Nullable String... description ) {
|
||||
//noinspection unchecked
|
||||
this( key, defaultValue, (T[]) defaultValue.getClass().getEnumConstants(), description );
|
||||
}
|
||||
|
||||
/** Creates a new field that accepts the specified set of enum values. */
|
||||
public EnumField( String key, T defaultValue, T[] validValues, String... description ) {
|
||||
public EnumField( String key, T defaultValue, T[] validValues, @Nullable String... description ) {
|
||||
super( key, defaultValue, description );
|
||||
valuesValid = validValues;
|
||||
}
|
||||
|
@ -55,6 +55,7 @@ public class EnumField<T extends Enum<T>> extends GenericField<T> {
|
|||
}
|
||||
|
||||
/** @return Attempts to parse the string literal as one of the valid values for this field and returns it, or null if invalid. */
|
||||
@Nullable
|
||||
private T parseValue( String name ) {
|
||||
for( T val : valuesValid ) {
|
||||
if( val.name().equalsIgnoreCase( name ) ) return val;
|
||||
|
|
|
@ -0,0 +1,312 @@
|
|||
package fathertoast.specialmobs.common.config.field;
|
||||
|
||||
import fathertoast.specialmobs.common.config.file.TomlHelper;
|
||||
import fathertoast.specialmobs.common.config.util.EnvironmentEntry;
|
||||
import fathertoast.specialmobs.common.config.util.EnvironmentList;
|
||||
import fathertoast.specialmobs.common.config.util.environment.*;
|
||||
import fathertoast.specialmobs.common.config.util.environment.biome.*;
|
||||
import fathertoast.specialmobs.common.config.util.environment.dimension.DimensionPropertyEnvironment;
|
||||
import fathertoast.specialmobs.common.config.util.environment.dimension.DimensionTypeEnvironment;
|
||||
import fathertoast.specialmobs.common.config.util.environment.dimension.DimensionTypeGroupEnvironment;
|
||||
import fathertoast.specialmobs.common.config.util.environment.position.*;
|
||||
import fathertoast.specialmobs.common.config.util.environment.time.*;
|
||||
import fathertoast.specialmobs.common.core.SpecialMobs;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Represents a config field with an environment list value.
|
||||
*/
|
||||
public class EnvironmentListField extends GenericField<EnvironmentList> {
|
||||
|
||||
/* When adding new environment conditions, you must:
|
||||
* - Add a new constant for its name here
|
||||
* - Create the environment class and ensure #name() returns the new name constant
|
||||
* - Link the name to construction and valid name array in #parseCondition(String,String) below
|
||||
* - Add any applicable builder methods in EnvironmentEntry.Builder
|
||||
* - Describe the new environment condition's usage/format in #environmentDescriptions() below
|
||||
*/
|
||||
// Dimension-based
|
||||
public static final String ENV_DIMENSION_PROPERTY = "dimension_property";
|
||||
public static final String ENV_DIMENSION_TYPE = "dimension_type";
|
||||
// Biome-based
|
||||
public static final String ENV_TERRAIN_DEPTH = "terrain_depth";
|
||||
public static final String ENV_TERRAIN_SCALE = "terrain_scale";
|
||||
public static final String ENV_RAINFALL = "rainfall";
|
||||
public static final String ENV_BIOME_TEMPERATURE = "biome_temp";
|
||||
public static final String ENV_TEMPERATURE = "temp";
|
||||
public static final String ENV_BIOME_CATEGORY = "biome_category";
|
||||
public static final String ENV_BIOME = "biome";
|
||||
// Position-based
|
||||
public static final String ENV_STRUCTURE = "structure";
|
||||
public static final String ENV_Y = "y";
|
||||
public static final String ENV_Y_FROM_SEA = "y_from_sea";
|
||||
public static final String ENV_POSITION = "position";
|
||||
// Time-based
|
||||
public static final String ENV_DIFFICULTY = "difficulty";
|
||||
public static final String ENV_SPECIAL_DIFFICULTY = "special_difficulty";
|
||||
public static final String ENV_WEATHER = "weather";
|
||||
public static final String ENV_MOON_BRIGHTNESS = "moon_brightness";
|
||||
public static final String ENV_MOON_PHASE = "moon_phase";
|
||||
public static final String ENV_DAY_TIME = "day_time";
|
||||
public static final String ENV_TIME_FROM_MIDNIGHT = "time_from_midnight";
|
||||
public static final String ENV_WORLD_TIME = "world_time";
|
||||
public static final String ENV_CHUNK_TIME = "chunk_time";
|
||||
|
||||
/**
|
||||
* Provides a description of how to use environment lists. Recommended to put at the top of any file using environment lists.
|
||||
* Always use put the environment condition descriptions at the bottom of the file if this is used!
|
||||
*/
|
||||
public static List<String> verboseDescription() {
|
||||
List<String> comment = new ArrayList<>();
|
||||
comment.add( "Environment List fields: General format = [ \"value environment1 condition1 & environment2 condition2 & ...\", ... ]" );
|
||||
comment.add( " Environment lists are arrays of environment entries. Each entry is a value followed by the environment conditions that must be" );
|
||||
comment.add( " satisfied for the value to be chosen. The environments are tested in the order listed, and the first matching entry is chosen." );
|
||||
comment.add( " See the bottom of this file for an explanation on each environment condition available." );
|
||||
return comment;
|
||||
}
|
||||
|
||||
/** Provides a detailed description of how to use each environment condition. Recommended to put at the bottom of any file using environment lists. */
|
||||
public static List<String> environmentDescriptions() {
|
||||
List<String> comment = new ArrayList<>();
|
||||
comment.add( "Environment conditions (for Environment List entries):" );
|
||||
comment.add( " Many environment conditions can be inverted by using \"!\"; these are shown with (!) in the appropriate location." );
|
||||
comment.add( " Other environment conditions are numerical comparisons; these use the operators (shown as op) <, >, =, <=, >=, or != to compare value." );
|
||||
comment.add( "Valid environment conditions are:" );
|
||||
// Dimension-based
|
||||
comment.add( " \"" + ENV_DIMENSION_PROPERTY + " (!)property\":" );
|
||||
comment.add( " Valid property values: " + TomlHelper.literalList( (Object[]) DimensionPropertyEnvironment.Value.values() ) );
|
||||
comment.add( " Dimension properties are the true/false values available to dimension types in data packs." );
|
||||
comment.add( " See the wiki for more info: [https://minecraft.fandom.com/wiki/Custom_dimension#Syntax]." );
|
||||
comment.add( " \"" + ENV_DIMENSION_TYPE + " (!)namespace:dimension_type_name\":" );
|
||||
comment.add( " The world's dimension type. In vanilla, these are only \"minecraft:overworld\", \"minecraft:the_nether\", or \"minecraft:the_end\"." );
|
||||
// Biome-based
|
||||
comment.add( " \"" + ENV_TERRAIN_DEPTH + " op value\":" );//TODO see if this changes in MC 1.18
|
||||
comment.add( " Biome's depth parameter. A measure of how high the terrain generates; depth < 0 makes a watery biome. For reference, generally vanilla" );
|
||||
comment.add( " plateaus are 1.5, mountains are 1, plains are 0.125, swamps are -0.2, rivers are -0.5, oceans are -1, and deep oceans are -1.8." );
|
||||
comment.add( " \"" + ENV_TERRAIN_SCALE + " op value\":" );
|
||||
comment.add( " Biome's scale parameter. A measure of how 'wavy' the terrain generates. For reference, generally vanilla mountains are 0.5 and plains are 0.05." );
|
||||
comment.add( " \"" + ENV_RAINFALL + " op value\":" );
|
||||
comment.add( " Biome's rainfall parameter. If this is \"= 0\", it checks that rain is disabled. For reference, rainfall > 0.85 suppresses fire." );
|
||||
comment.add( " \"" + ENV_BIOME_TEMPERATURE + " op value\" or \"" + ENV_BIOME_TEMPERATURE + " (!)" + TemperatureEnvironment.FREEZING + "\":" );
|
||||
comment.add( " Biome's temperature parameter. For reference, freezing is < 0.15 and hot is generally considered > 0.95." );
|
||||
comment.add( " \"" + ENV_TEMPERATURE + " op value\" or \"" + ENV_TEMPERATURE + " (!)" + TemperatureEnvironment.FREEZING + "\":" );
|
||||
comment.add( " Height-adjusted temperature. For reference, freezing is < 0.15 and hot is generally considered > 0.95." );
|
||||
comment.add( " \"" + ENV_BIOME_CATEGORY + " (!)category\":" );
|
||||
comment.add( " Valid category values: " + TomlHelper.literalList( (Object[]) BiomeCategory.values() ) );
|
||||
comment.add( " \"" + ENV_BIOME + " (!)namespace:biome_name\":" );
|
||||
comment.add( " The biome. See the wiki for vanilla biome names (resource locations) [https://minecraft.fandom.com/wiki/Biome#Biome_IDs]." );
|
||||
// Position-based
|
||||
comment.add( " \"" + ENV_STRUCTURE + " (!)namespace:structure_name\":" );
|
||||
comment.add( " The structure. See the wiki for vanilla structure names [https://minecraft.fandom.com/wiki/Generated_structures#Locating]." );
|
||||
comment.add( " \"" + ENV_Y + " op value\":" );
|
||||
comment.add( " The y-value. For reference, sea level is normally 63 and lava level is normally 10." );//TODO change lava level to -54 for MC 1.18
|
||||
comment.add( " \"" + ENV_Y_FROM_SEA + " op value\":" );
|
||||
comment.add( " The y-value from sea level. Expect the only air <= 0 to be in caves/ravines (which may still have direct view of the sky)." );
|
||||
comment.add( " \"" + ENV_POSITION + " (!)state\":" );
|
||||
comment.add( " Valid state values: " + TomlHelper.literalList( (Object[]) PositionEnvironment.Value.values() ) );
|
||||
comment.add( " Miscellaneous conditions that generally do what you expect. For reference, 'near' a village is ~3 chunks, and redstone checks weak power." );
|
||||
// Time-based
|
||||
comment.add( " \"" + ENV_DIFFICULTY + " op value\":" );
|
||||
comment.add( " The regional difficulty (0 to 6.75). This is based on many factors such as difficulty setting, moon brightness, chunk inhabited time, and world time." );
|
||||
comment.add( " For reference, this scales up to the max after 63 days in the world and 150 days in a particular chunk, and peaks during full moons." );
|
||||
comment.add( " On Peaceful this is always 0, on Easy this is 0.75 to 1.5, on Normal this is 1.5 to 4.0, and on Hard this is 2.25 to 6.75." );
|
||||
comment.add( " \"" + ENV_SPECIAL_DIFFICULTY + " op value\":" );
|
||||
comment.add( " The 'special multiplier' for regional difficulty (0 to 1). For reference, this is 0 when difficulty <= 2 and 1 when difficulty >= 4." );
|
||||
comment.add( " This is always 0 in Easy and below. In Normal, it maxes at absolute peak regional difficulty. In Hard, it starts at 0.125 and maxes out in ~50 days." );
|
||||
comment.add( " \"" + ENV_WEATHER + " (!)type\":" );
|
||||
comment.add( " Valid type values: " + TomlHelper.literalList( (Object[]) WeatherEnvironment.Value.values() ) );
|
||||
comment.add( " \"" + ENV_MOON_BRIGHTNESS + " op value\":" );
|
||||
comment.add( " The moon brightness (0 to 1). New moon has 0 brightness, full moon has 1 brightness. Intermediate phases are 0.25, 0.5, or 0.75." );
|
||||
comment.add( " \"" + ENV_MOON_PHASE + " (!)phase\":" );
|
||||
comment.add( " Valid phase values: " + TomlHelper.literalList( (Object[]) MoonPhaseEnvironment.Value.values() ) );
|
||||
comment.add( " \"" + ENV_DAY_TIME + " (!)time\":" );
|
||||
comment.add( " Valid time values: " + TomlHelper.literalList( (Object[]) DayTimeEnvironment.Value.values() ) );
|
||||
comment.add( " Note that the transition periods, sunset & sunrise, are considered as part of day & night, respectively." );
|
||||
comment.add( " \"" + ENV_TIME_FROM_MIDNIGHT + " op value\":" );
|
||||
comment.add( " The absolute time in ticks away from midnight. Value must be 0 to 12000." );
|
||||
comment.add( " \"" + ENV_MOON_PHASE + " (!)phase\":" );
|
||||
comment.add( " Valid phase values: " + TomlHelper.literalList( (Object[]) MoonPhaseEnvironment.Value.values() ) );
|
||||
comment.add( " For reference, the first day in a new world is always a full moon." );
|
||||
comment.add( " \"" + ENV_WORLD_TIME + " op value\":" );
|
||||
comment.add( " The total time the world has existed, in ticks. For reference, each day cycle is 24000 ticks and each lunar cycle is 192000 ticks." );
|
||||
comment.add( " \"" + ENV_CHUNK_TIME + " op value\":" );
|
||||
comment.add( " The total time the chunk has been loaded, in ticks. For reference, each day cycle is 24000 ticks and each lunar cycle is 192000 ticks." );
|
||||
return comment;
|
||||
}
|
||||
|
||||
/** Creates a new field. */
|
||||
public EnvironmentListField( String key, EnvironmentList defaultValue, @Nullable String... description ) {
|
||||
super( key, defaultValue, description );
|
||||
}
|
||||
|
||||
/** Adds info about the field type, format, and bounds to the end of a field's description. */
|
||||
public void appendFieldInfo( List<String> comment ) {
|
||||
comment.add( TomlHelper.fieldInfoFormat( "Environment List", valueDefault, "[ \"value condition1 state1 & condition2 state2 & ...\", ... ]" ) );
|
||||
comment.add( " Range for Values: " + TomlHelper.fieldRange( valueDefault.getMinValue(), valueDefault.getMaxValue() ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads this field's value from the given raw toml value. If anything goes wrong, correct it at the lowest level possible.
|
||||
* <p>
|
||||
* For example, a missing value should be set to the default, while an out-of-range value should be adjusted to the
|
||||
* nearest in-range value
|
||||
*/
|
||||
@Override
|
||||
public void load( @Nullable Object raw ) {
|
||||
if( raw == null ) {
|
||||
value = valueDefault;
|
||||
return;
|
||||
}
|
||||
List<String> list = TomlHelper.parseStringList( raw );
|
||||
List<EnvironmentEntry> entryList = new ArrayList<>();
|
||||
for( String line : list ) {
|
||||
entryList.add( parseEntry( line ) );
|
||||
}
|
||||
value = new EnvironmentList( entryList );
|
||||
}
|
||||
|
||||
/** Parses a single entry line and returns the result. */
|
||||
private EnvironmentEntry parseEntry( final String line ) {
|
||||
// Parse the value out of the conditions
|
||||
final String[] args = line.split( " ", 2 );
|
||||
final double value = parseValue( args[0], line );
|
||||
|
||||
final List<AbstractEnvironment> conditions = new ArrayList<>();
|
||||
if( args.length > 1 ) {
|
||||
final String[] condArgs = args[1].split( "&" );
|
||||
for( String condArg : condArgs ) {
|
||||
conditions.add( parseCondition( condArg.trim(), line ) );
|
||||
}
|
||||
}
|
||||
if( conditions.isEmpty() ) {
|
||||
SpecialMobs.LOG.warn( "No environments defined in entry for {} \"{}\"! Invalid entry: {}",
|
||||
getClass(), getKey(), line );
|
||||
}
|
||||
|
||||
return new EnvironmentEntry( value, conditions );
|
||||
}
|
||||
|
||||
/** Parses a single value argument and returns a valid result. */
|
||||
private double parseValue( final String arg, final String line ) {
|
||||
// Try to parse the value
|
||||
double value;
|
||||
try {
|
||||
value = Double.parseDouble( arg );
|
||||
}
|
||||
catch( NumberFormatException ex ) {
|
||||
// This is thrown if the string is not a parsable number
|
||||
SpecialMobs.LOG.warn( "Invalid value for {} \"{}\"! Falling back to 0. Invalid entry: {}",
|
||||
getClass(), getKey(), line );
|
||||
value = 0.0;
|
||||
}
|
||||
// Verify value is within range
|
||||
if( value < valueDefault.getMinValue() ) {
|
||||
SpecialMobs.LOG.warn( "Value for {} \"{}\" is below the minimum ({})! Clamping value. Invalid value: {}",
|
||||
getClass(), getKey(), valueDefault.getMinValue(), value );
|
||||
value = valueDefault.getMinValue();
|
||||
}
|
||||
else if( value > valueDefault.getMaxValue() ) {
|
||||
SpecialMobs.LOG.warn( "Value for {} \"{}\" is above the maximum ({})! Clamping value. Invalid value: {}",
|
||||
getClass(), getKey(), valueDefault.getMaxValue(), value );
|
||||
value = valueDefault.getMaxValue();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/** Parses a single environment condition argument and returns a valid result. */
|
||||
private AbstractEnvironment parseCondition( final String arg, final String line ) {
|
||||
// First parse the environment name, since it defines the format for the rest
|
||||
final String[] args = arg.split( " ", 2 );
|
||||
|
||||
final String value;
|
||||
if( args.length < 2 ) value = "";
|
||||
else value = args[1].trim();
|
||||
|
||||
switch( args[0].toLowerCase( Locale.ROOT ) ) {
|
||||
// Dimension-based
|
||||
case ENV_DIMENSION_PROPERTY:
|
||||
return new DimensionPropertyEnvironment( this, value );
|
||||
case ENV_DIMENSION_TYPE:
|
||||
return value.endsWith( "*" ) ? new DimensionTypeGroupEnvironment( this, value ) : new DimensionTypeEnvironment( this, value );
|
||||
// Biome-based
|
||||
case ENV_TERRAIN_DEPTH:
|
||||
return new TerrainDepthEnvironment( this, value );
|
||||
case ENV_TERRAIN_SCALE:
|
||||
return new TerrainScaleEnvironment( this, value );
|
||||
case ENV_RAINFALL:
|
||||
return new RainfallEnvironment( this, value );
|
||||
case ENV_BIOME_TEMPERATURE:
|
||||
return new BiomeTemperatureEnvironment( this, value );
|
||||
case ENV_TEMPERATURE:
|
||||
return new TemperatureEnvironment( this, value );
|
||||
case ENV_BIOME_CATEGORY:
|
||||
return new BiomeCategoryEnvironment( this, value );
|
||||
case ENV_BIOME:
|
||||
return value.endsWith( "*" ) ? new BiomeGroupEnvironment( this, value ) : new BiomeEnvironment( this, value );
|
||||
// Position-based
|
||||
case ENV_STRUCTURE:
|
||||
return value.endsWith( "*" ) ? new StructureGroupEnvironment( this, value ) : new StructureEnvironment( this, value );
|
||||
case ENV_Y:
|
||||
return new YEnvironment( this, value );
|
||||
case ENV_Y_FROM_SEA:
|
||||
return new YFromSeaEnvironment( this, value );
|
||||
case ENV_POSITION:
|
||||
return new PositionEnvironment( this, value );
|
||||
// Time-based
|
||||
case ENV_DIFFICULTY:
|
||||
return new DifficultyEnvironment( this, value );
|
||||
case ENV_SPECIAL_DIFFICULTY:
|
||||
return new SpecialDifficultyEnvironment( this, value );
|
||||
case ENV_WEATHER:
|
||||
return new WeatherEnvironment( this, value );
|
||||
case ENV_MOON_BRIGHTNESS:
|
||||
return new MoonBrightnessEnvironment( this, value );
|
||||
case ENV_MOON_PHASE:
|
||||
return new MoonPhaseEnvironment( this, value );
|
||||
case ENV_DAY_TIME:
|
||||
return new DayTimeEnvironment( this, value );
|
||||
case ENV_TIME_FROM_MIDNIGHT:
|
||||
return new TimeFromMidnightEnvironment( this, value );
|
||||
case ENV_WORLD_TIME:
|
||||
return new WorldTimeEnvironment( this, value );
|
||||
case ENV_CHUNK_TIME:
|
||||
return new ChunkTimeEnvironment( this, value );
|
||||
}
|
||||
|
||||
// The environment name was not recognized; try to provide some good feedback because this field is complicated
|
||||
final String[] environmentNames = {
|
||||
// Dimension-based
|
||||
ENV_DIMENSION_PROPERTY, ENV_DIMENSION_TYPE,
|
||||
// Biome-based
|
||||
ENV_TERRAIN_DEPTH, ENV_TERRAIN_SCALE, ENV_RAINFALL, ENV_BIOME_TEMPERATURE, ENV_TEMPERATURE, ENV_BIOME_CATEGORY, ENV_BIOME,
|
||||
// Position-based
|
||||
ENV_STRUCTURE, ENV_Y, ENV_Y_FROM_SEA, ENV_POSITION,
|
||||
// Time-based
|
||||
ENV_DIFFICULTY, ENV_SPECIAL_DIFFICULTY, ENV_WEATHER, ENV_MOON_BRIGHTNESS, ENV_MOON_PHASE, ENV_DAY_TIME,
|
||||
ENV_TIME_FROM_MIDNIGHT, ENV_WORLD_TIME, ENV_CHUNK_TIME
|
||||
};
|
||||
final AbstractEnvironment fallback = new YEnvironment( ComparisonOperator.LESS_THAN, 0 );
|
||||
SpecialMobs.LOG.warn( "Invalid environment '{}' for {} \"{}\"! Falling back to \"{}\". Environment name must be in the set [ {} ]. Invalid environment: {}",
|
||||
args[0], getClass(), getKey(), fallback, TomlHelper.literalList( (Object[]) environmentNames ), line );
|
||||
return fallback;
|
||||
}
|
||||
|
||||
|
||||
// Convenience methods
|
||||
|
||||
/** @return The value matching the given environment, or the default value if no matching environment is defined. */
|
||||
public double getOrElse( World world, @Nullable BlockPos pos, DoubleField defaultValue ) { return get().getOrElse( world, pos, defaultValue ); }
|
||||
|
||||
/** @return The value matching the given environment, or the default value if no matching environment is defined. */
|
||||
public double getOrElse( World world, @Nullable BlockPos pos, double defaultValue ) { return get().getOrElse( world, pos, defaultValue ); }
|
||||
|
||||
/** @return The value matching the given environment, or null if no matching environment is defined. */
|
||||
@Nullable
|
||||
public Double get( World world, @Nullable BlockPos pos ) { return get().get( world, pos ); }
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
package fathertoast.specialmobs.common.config.field;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Represents a config field with an object value.
|
||||
* <p>
|
||||
|
@ -16,7 +18,7 @@ public abstract class GenericField<T> extends AbstractConfigField {
|
|||
protected T value;
|
||||
|
||||
/** Creates a new field. */
|
||||
public GenericField( String key, T defaultValue, String... description ) {
|
||||
public GenericField( String key, T defaultValue, @Nullable String... description ) {
|
||||
super( key, description );
|
||||
valueDefault = defaultValue;
|
||||
}
|
||||
|
|
|
@ -23,12 +23,12 @@ public class IntField extends AbstractConfigField {
|
|||
private int value;
|
||||
|
||||
/** Creates a new field that accepts a common range of values. */
|
||||
public IntField( String key, int defaultValue, Range range, String... description ) {
|
||||
public IntField( String key, int defaultValue, Range range, @Nullable String... description ) {
|
||||
this( key, defaultValue, range.MIN, range.MAX, description );
|
||||
}
|
||||
|
||||
/** Creates a new field that accepts a specialized range of values. */
|
||||
public IntField( String key, int defaultValue, int min, int max, String... description ) {
|
||||
public IntField( String key, int defaultValue, int min, int max, @Nullable String... description ) {
|
||||
super( key, description );
|
||||
valueDefault = defaultValue;
|
||||
valueMin = min;
|
||||
|
|
|
@ -17,7 +17,7 @@ import javax.annotation.Nullable;
|
|||
public class LazyRegistryEntryListField<T extends IForgeRegistryEntry<T>> extends RegistryEntryListField<T> {
|
||||
|
||||
/** Creates a new field. */
|
||||
public LazyRegistryEntryListField( String key, RegistryEntryList<T> defaultValue, String... description ) {
|
||||
public LazyRegistryEntryListField( String key, RegistryEntryList<T> defaultValue, @Nullable String... description ) {
|
||||
super( key, defaultValue, description );
|
||||
}
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ public class RegistryEntryListField<T extends IForgeRegistryEntry<T>> extends Ge
|
|||
}
|
||||
|
||||
/** Creates a new field. */
|
||||
public RegistryEntryListField( String key, RegistryEntryList<T> defaultValue, String... description ) {
|
||||
public RegistryEntryListField( String key, RegistryEntryList<T> defaultValue, @Nullable String... description ) {
|
||||
super( key, defaultValue, description );
|
||||
}
|
||||
|
||||
|
@ -57,15 +57,18 @@ public class RegistryEntryListField<T extends IForgeRegistryEntry<T>> extends Ge
|
|||
value = new RegistryEntryList<>( this, valueDefault.getRegistry(), TomlHelper.parseStringList( raw ) );
|
||||
}
|
||||
|
||||
|
||||
// Convenience methods
|
||||
|
||||
/** @return The registry this list draws from. */
|
||||
public IForgeRegistry<T> getRegistry() { return value.getRegistry(); }
|
||||
public IForgeRegistry<T> getRegistry() { return get().getRegistry(); }
|
||||
|
||||
/** @return The entries in this list. */
|
||||
public Set<T> getEntries() { return value.getEntries(); }
|
||||
public Set<T> getEntries() { return get().getEntries(); }
|
||||
|
||||
/** @return Returns true if there are no entries in this list. */
|
||||
public boolean isEmpty() { return value.isEmpty(); }
|
||||
public boolean isEmpty() { return get().isEmpty(); }
|
||||
|
||||
/** @return Returns true if the entry is contained in this list. */
|
||||
public boolean contains( T entry ) { return value.contains( entry ); }
|
||||
public boolean contains( @Nullable T entry ) { return get().contains( entry ); }
|
||||
}
|
|
@ -14,13 +14,13 @@ public class ScaledDoubleField extends DoubleField {
|
|||
private double valueScaled;
|
||||
|
||||
/** Creates a new field that accepts a common range of values. */
|
||||
public ScaledDoubleField( String key, double defaultValue, double scale, Range range, String... description ) {
|
||||
public ScaledDoubleField( String key, double defaultValue, double scale, Range range, @Nullable String... description ) {
|
||||
super( key, defaultValue, range, description );
|
||||
SCALE = scale;
|
||||
}
|
||||
|
||||
/** Creates a new field that accepts a specialized range of values. */
|
||||
public ScaledDoubleField( String key, double defaultValue, double scale, double min, double max, String... description ) {
|
||||
public ScaledDoubleField( String key, double defaultValue, double scale, double min, double max, @Nullable String... description ) {
|
||||
super( key, defaultValue, min, max, description );
|
||||
SCALE = scale;
|
||||
}
|
||||
|
|
|
@ -11,12 +11,12 @@ public class SqrDoubleField extends DoubleField {
|
|||
private double valueSqr;
|
||||
|
||||
/** Creates a new field that accepts a common range of values. */
|
||||
public SqrDoubleField( String key, double defaultValue, Range range, String... description ) {
|
||||
public SqrDoubleField( String key, double defaultValue, Range range, @Nullable String... description ) {
|
||||
super( key, defaultValue, range, description );
|
||||
}
|
||||
|
||||
/** Creates a new field that accepts a specialized range of values. */
|
||||
public SqrDoubleField( String key, double defaultValue, double min, double max, String... description ) {
|
||||
public SqrDoubleField( String key, double defaultValue, double min, double max, @Nullable String... description ) {
|
||||
super( key, defaultValue, min, max, description );
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
@MethodsReturnNonnullByDefault
|
||||
@ParametersAreNonnullByDefault
|
||||
package fathertoast.specialmobs.common.config.field;
|
||||
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
|
@ -227,6 +227,30 @@ public class ToastConfigSpec {
|
|||
}
|
||||
}
|
||||
|
||||
/** Represents an appendix header comment. */
|
||||
private static class AppendixHeader extends Format {
|
||||
/** The appendix comment. */
|
||||
private final List<String> COMMENT;
|
||||
|
||||
/** Create a new header action that will insert the opening file comment. */
|
||||
private AppendixHeader( List<String> comment ) {
|
||||
COMMENT = comment;
|
||||
}
|
||||
|
||||
/** Called when the config is saved. */
|
||||
@Override
|
||||
public void write( ToastTomlWriter writer, CharacterOutput output ) {
|
||||
writer.decreaseIndentLevel();
|
||||
writer.writeNewLine( output );
|
||||
writer.writeNewLine( output );
|
||||
|
||||
writer.writeComment( "Appendix:", output );
|
||||
writer.writeComment( COMMENT, output );
|
||||
|
||||
writer.increaseIndentLevel();
|
||||
}
|
||||
}
|
||||
|
||||
/** Represents a category comment. */
|
||||
private static class Category extends Format {
|
||||
/** The category comment. */
|
||||
|
@ -355,6 +379,9 @@ public class ToastConfigSpec {
|
|||
/** @param comment The file comment to insert. */
|
||||
public void header( List<String> comment ) { ACTIONS.add( new Header( this, comment ) ); }
|
||||
|
||||
/** @param comment The appendix comment to insert. */
|
||||
public void appendixHeader( String... comment ) { ACTIONS.add( new AppendixHeader( TomlHelper.newComment( comment ) ) ); }
|
||||
|
||||
/** Inserts a detailed description of how to use the registry entry list field. */
|
||||
public void describeRegistryEntryList() { ACTIONS.add( new Comment( RegistryEntryListField.verboseDescription() ) ); }
|
||||
|
||||
|
@ -367,6 +394,12 @@ public class ToastConfigSpec {
|
|||
/** Inserts a detailed description of how to use the block list field. */
|
||||
public void describeBlockList() { ACTIONS.add( new Comment( BlockListField.verboseDescription() ) ); }
|
||||
|
||||
/** Inserts the first part of a detailed description of how to use the environment list field. Should go with the other field descriptions. */
|
||||
public void describeEnvironmentListPart1of2() { ACTIONS.add( new Comment( EnvironmentListField.verboseDescription() ) ); }
|
||||
|
||||
/** Inserts the second and last part of a detailed description of how to use the environment list field. Should go at the bottom of the file. */
|
||||
public void describeEnvironmentListPart2of2() { ACTIONS.add( new Comment( EnvironmentListField.environmentDescriptions() ) ); }
|
||||
|
||||
/**
|
||||
* @param name The category name.
|
||||
* @param comment The category comment to insert.
|
||||
|
|
|
@ -5,6 +5,7 @@ import com.electronwill.nightconfig.core.io.*;
|
|||
import fathertoast.specialmobs.common.config.field.AbstractConfigField;
|
||||
import fathertoast.specialmobs.common.core.SpecialMobs;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.Writer;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
@ -85,7 +86,7 @@ public class ToastTomlWriter implements ConfigWriter {
|
|||
}
|
||||
|
||||
/** Writes a literal array of single-line strings. */
|
||||
public void writeStringArray( List<String> list, CharacterOutput output ) {
|
||||
public void writeStringArray( @Nullable List<String> list, CharacterOutput output ) {
|
||||
if( list == null || list.isEmpty() ) {
|
||||
writeLine( "[]", output );
|
||||
return;
|
||||
|
|
|
@ -6,10 +6,12 @@ import fathertoast.specialmobs.common.config.field.DoubleField;
|
|||
import fathertoast.specialmobs.common.config.field.IntField;
|
||||
import fathertoast.specialmobs.common.config.util.ConfigUtil;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@SuppressWarnings( "unused" )
|
||||
public final class TomlHelper {
|
||||
private TomlHelper() { } // This is a static access only class that cannot be instantiated
|
||||
|
||||
|
@ -32,7 +34,7 @@ public final class TomlHelper {
|
|||
}
|
||||
|
||||
/** Attempts to convert a string value to a raw non-string toml literal. May or may not be accurate. */
|
||||
public static Object parseRaw( String value ) {
|
||||
public static Object parseRaw( @Nullable String value ) {
|
||||
// Note: It is very important here that the returned value is NOT a string
|
||||
|
||||
if( value != null && !"".equals( value ) ) {
|
||||
|
@ -56,9 +58,9 @@ public final class TomlHelper {
|
|||
}
|
||||
|
||||
/** Attempts to convert an object to a toml literal. May or may not be accurate. */
|
||||
public static String toLiteral( Object value ) {
|
||||
public static String toLiteral( @Nullable Object value ) {
|
||||
if( value == null ) {
|
||||
return "null";
|
||||
return "";
|
||||
}
|
||||
else if( value instanceof Enum<?> ) {
|
||||
return "\"" + ((Enum<?>) value).name().toLowerCase() + "\"";
|
||||
|
@ -66,21 +68,22 @@ public final class TomlHelper {
|
|||
else if( value instanceof String ) {
|
||||
return "\"" + value + "\"";
|
||||
}
|
||||
else if( value instanceof Double && ((Double) value).isInfinite() ) {
|
||||
// Toml infinite literals do not match java; these may also be unsupported in the current version
|
||||
return (Double) value > 0.0 ? "Inf" : "-Inf";
|
||||
}
|
||||
// Infinite values not supported
|
||||
//else if( value instanceof Double && ((Double) value).isInfinite() ) {
|
||||
// // Toml infinite literals do not match java
|
||||
// return (Double) value > 0.0 ? "Inf" : "-Inf";
|
||||
//}
|
||||
else {
|
||||
return value.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/** Attempts to convert an object array to a toml literal. May or may not be accurate. */
|
||||
public static String toLiteral( Object... values ) {
|
||||
public static String toLiteral( @Nullable Object... values ) {
|
||||
if( values == null ) {
|
||||
return "null";
|
||||
return "";
|
||||
}
|
||||
else if( values.length < 1 ) {
|
||||
if( values.length < 1 ) {
|
||||
return "[]";
|
||||
}
|
||||
else {
|
||||
|
@ -92,7 +95,7 @@ public final class TomlHelper {
|
|||
public static String literalList( Object... list ) { return literalList( Arrays.asList( list ) ); }
|
||||
|
||||
/** Attempts to convert an object list to a list of toml literals. May or may not be accurate. */
|
||||
public static String literalList( List<Object> list ) {
|
||||
public static String literalList( @Nullable List<Object> list ) {
|
||||
if( list == null || list.isEmpty() ) return "";
|
||||
StringBuilder literals = new StringBuilder();
|
||||
for( Object obj : list ) {
|
||||
|
@ -196,7 +199,7 @@ public final class TomlHelper {
|
|||
public static List<String> splitKey( String key ) { return StringUtils.split( key, '.' ); }
|
||||
|
||||
/** Combines a toml path into a key. */
|
||||
public static String mergePath( List<String> path ) {
|
||||
public static String mergePath( @Nullable List<String> path ) {
|
||||
if( path == null || path.isEmpty() ) return "";
|
||||
StringBuilder key = new StringBuilder();
|
||||
for( String subKey : path ) {
|
||||
|
@ -207,15 +210,13 @@ public final class TomlHelper {
|
|||
}
|
||||
|
||||
/** Convenience method for creating a list of single-line comments (no \n or \r). */
|
||||
public static ArrayList<String> newComment( String... lines ) {
|
||||
return new ArrayList<>( Arrays.asList( lines ) );
|
||||
}
|
||||
public static ArrayList<String> newComment( String... lines ) { return new ArrayList<>( Arrays.asList( lines ) ); }
|
||||
|
||||
/** Combines an array of objects as a comma-separated string. */
|
||||
public static String combineList( Object... list ) { return combineList( Arrays.asList( list ) ); }
|
||||
|
||||
/** Combines a list of objects as a comma-separated string. */
|
||||
public static String combineList( List<Object> list ) {
|
||||
public static String combineList( @Nullable List<Object> list ) {
|
||||
if( list == null || list.isEmpty() ) return "";
|
||||
StringBuilder key = new StringBuilder();
|
||||
for( Object obj : list ) {
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
@MethodsReturnNonnullByDefault
|
||||
@ParametersAreNonnullByDefault
|
||||
package fathertoast.specialmobs.common.config.file;
|
||||
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
|
@ -0,0 +1,7 @@
|
|||
@MethodsReturnNonnullByDefault
|
||||
@ParametersAreNonnullByDefault
|
||||
package fathertoast.specialmobs.common.config;
|
||||
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
|
@ -0,0 +1,35 @@
|
|||
package fathertoast.specialmobs.common.config.species;
|
||||
|
||||
import fathertoast.specialmobs.common.bestiary.MobFamily;
|
||||
import fathertoast.specialmobs.common.config.Config;
|
||||
import fathertoast.specialmobs.common.config.field.IntField;
|
||||
import fathertoast.specialmobs.common.config.file.ToastConfigSpec;
|
||||
import fathertoast.specialmobs.common.config.util.ConfigUtil;
|
||||
|
||||
public class DesiccatedSilverfishSpeciesConfig extends SilverfishSpeciesConfig {
|
||||
|
||||
public final Desiccated DESICCATED;
|
||||
|
||||
/** Builds the config spec that should be used for this config. */
|
||||
public DesiccatedSilverfishSpeciesConfig( MobFamily.Species<?> species, double spitChance, int minAbsorb, int maxAbsorb ) {
|
||||
super( species, spitChance );
|
||||
|
||||
DESICCATED = new Desiccated( SPEC, species, speciesName, minAbsorb, maxAbsorb );
|
||||
}
|
||||
|
||||
public static class Desiccated extends Config.AbstractCategory {
|
||||
|
||||
public final IntField.RandomRange absorbCount;
|
||||
|
||||
Desiccated( ToastConfigSpec parent, MobFamily.Species<?> species, String speciesName, int minAbsorb, int maxAbsorb ) {
|
||||
super( parent, ConfigUtil.camelCaseToLowerUnderscore( species.specialVariantName ),
|
||||
"Options specific to " + speciesName + "." );
|
||||
|
||||
absorbCount = new IntField.RandomRange(
|
||||
SPEC.define( new IntField( "water_absorbed.min", minAbsorb, IntField.Range.NON_NEGATIVE,
|
||||
"The minimum and maximum (inclusive) number of water blocks " + speciesName + " can absorb." ) ),
|
||||
SPEC.define( new IntField( "water_absorbed.max", maxAbsorb, IntField.Range.NON_NEGATIVE ) )
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -38,8 +38,6 @@ public class SpeciesConfig extends Config.AbstractConfig {
|
|||
super( FamilyConfig.dir( species.family ), fileName( species ),
|
||||
String.format( "This config contains options that apply only to the %s %s species.",
|
||||
variantName( species ), ConfigUtil.camelCaseToLowerSpace( species.family.name ) ) );
|
||||
SPEC.newLine();
|
||||
SPEC.comment( "See the main mod config for common terms and how to use special field types like Attribute List or Registry List." );
|
||||
|
||||
speciesName = variantName( species ) + " " + species.family.configName;
|
||||
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
@MethodsReturnNonnullByDefault
|
||||
@ParametersAreNonnullByDefault
|
||||
package fathertoast.specialmobs.common.config.species;
|
||||
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
|
@ -2,6 +2,7 @@ package fathertoast.specialmobs.common.config.util;
|
|||
|
||||
import fathertoast.specialmobs.common.config.field.AbstractConfigField;
|
||||
import fathertoast.specialmobs.common.core.SpecialMobs;
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.ai.attributes.Attribute;
|
||||
import net.minecraft.entity.ai.attributes.AttributeModifierMap;
|
||||
|
@ -10,12 +11,17 @@ import net.minecraft.entity.ai.attributes.ModifiableAttributeInstance;
|
|||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
/**
|
||||
* One attribute-operation-value entry in an attribute list. Uses a 'lazy' implementation so the attribute registry is
|
||||
* not polled until this entry is actually used.
|
||||
* <p>
|
||||
* See also {@link ConfigDrivenAttributeModifierMap}
|
||||
*/
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
@SuppressWarnings( "unused" )
|
||||
public class AttributeEntry {
|
||||
/** The field containing this entry. We save a reference to help improve error/warning reports. */
|
||||
|
@ -48,7 +54,7 @@ public class AttributeEntry {
|
|||
}
|
||||
|
||||
/** Creates an entry with the specified values. */
|
||||
public AttributeEntry( AbstractConfigField field, ResourceLocation regKey, boolean multiply, double value ) {
|
||||
public AttributeEntry( @Nullable AbstractConfigField field, @Nullable ResourceLocation regKey, boolean multiply, double value ) {
|
||||
FIELD = field;
|
||||
ATTRIBUTE_KEY = regKey;
|
||||
MULTIPLY = multiply;
|
||||
|
@ -95,7 +101,7 @@ public class AttributeEntry {
|
|||
}
|
||||
|
||||
/** Applies this attribute change to the attribute instance. Assumes that the instance is for this entry's target attribute. */
|
||||
private void apply( ModifiableAttributeInstance attributeInstance ) {
|
||||
private void apply( @Nullable ModifiableAttributeInstance attributeInstance ) {
|
||||
if( attributeInstance == null )
|
||||
throw new IllegalStateException( "Attempted to modify non-registered attribute " + ATTRIBUTE_KEY );
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import fathertoast.specialmobs.common.config.file.TomlHelper;
|
|||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.ai.attributes.AttributeModifierMap;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -33,7 +34,7 @@ public class AttributeList implements IStringArray {
|
|||
|
||||
/** @return Returns true if this object has the same value as another object. */
|
||||
@Override
|
||||
public boolean equals( Object other ) {
|
||||
public boolean equals( @Nullable Object other ) {
|
||||
if( !(other instanceof AttributeList) ) return false;
|
||||
// Compare by the string list view of the object
|
||||
return toStringList().equals( ((AttributeList) other).toStringList() );
|
||||
|
|
|
@ -32,7 +32,7 @@ public class BlockEntry implements Cloneable {
|
|||
this( block.getBlock() );
|
||||
|
||||
// Add all the properties present in the block state
|
||||
StateBuilder state = new StateBuilder();
|
||||
StateBuilder state = new StateBuilder( BLOCK );
|
||||
for( Property<? extends Comparable<?>> property : block.getProperties() ) {
|
||||
state.add( property, block.getValue( property ) );
|
||||
}
|
||||
|
@ -45,13 +45,8 @@ public class BlockEntry implements Cloneable {
|
|||
public BlockEntry( AbstractConfigField field, String line ) {
|
||||
// Parse the base block
|
||||
final String[] pair = line.split( "\\[", 2 );
|
||||
final ResourceLocation regKey = new ResourceLocation( pair[0] );
|
||||
if( !ForgeRegistries.BLOCKS.containsKey( regKey ) ) {
|
||||
BLOCK = Blocks.AIR;
|
||||
}
|
||||
else {
|
||||
BLOCK = ForgeRegistries.BLOCKS.getValue( regKey );
|
||||
}
|
||||
final Block block = ForgeRegistries.BLOCKS.getValue( new ResourceLocation( pair[0] ) );
|
||||
BLOCK = block == null ? Blocks.AIR : block;
|
||||
|
||||
// We are done constructing if the entry is invalid or does not specify block states
|
||||
if( BLOCK == Blocks.AIR || pair.length < 2 ) {
|
||||
|
@ -143,7 +138,7 @@ public class BlockEntry implements Cloneable {
|
|||
final StateContainer<Block, BlockState> stateContainer = block.getStateDefinition();
|
||||
|
||||
// Parse the state and build the matcher
|
||||
final StateBuilder builder = new StateBuilder();
|
||||
final StateBuilder builder = new StateBuilder( block );
|
||||
final String[] properties = stateString.split( "," );
|
||||
for( String combinedEntry : properties ) {
|
||||
// Parse an individual property key-value pair
|
||||
|
@ -271,9 +266,6 @@ public class BlockEntry implements Cloneable {
|
|||
/** Can be used for building default configs to make block entries with target states. */
|
||||
public StateBuilder( Block block ) { BLOCK = block; }
|
||||
|
||||
/** Used by block entries to build target states. Can not be built into a block entry when using this constructor. */
|
||||
private StateBuilder() { BLOCK = null; }
|
||||
|
||||
/** @return Returns true if this state builder has no properties set. */
|
||||
@SuppressWarnings( "BooleanMethodIsAlwaysInverted" )
|
||||
public boolean isEmpty() { return propertiesToMatch.isEmpty(); }
|
||||
|
@ -289,7 +281,7 @@ public class BlockEntry implements Cloneable {
|
|||
|
||||
/** @return Returns a block entry reflecting the current state of this builder. */
|
||||
public BlockEntry toBlockEntry() {
|
||||
BlockEntry target = new BlockEntry( BLOCK );
|
||||
final BlockEntry target = new BlockEntry( BLOCK );
|
||||
if( !isEmpty() ) {
|
||||
target.MATCHERS.add( toTargetState() );
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import net.minecraft.block.Blocks;
|
|||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
@ -61,13 +62,11 @@ public class BlockList implements IStringArray {
|
|||
|
||||
/** @return A string representation of this object. */
|
||||
@Override
|
||||
public String toString() {
|
||||
return TomlHelper.toLiteral( PRINT_LIST.toArray() );
|
||||
}
|
||||
public String toString() { return TomlHelper.toLiteral( PRINT_LIST.toArray() ); }
|
||||
|
||||
/** @return Returns true if this object has the same value as another object. */
|
||||
@Override
|
||||
public boolean equals( Object other ) {
|
||||
public boolean equals( @Nullable Object other ) {
|
||||
if( !(other instanceof BlockList) ) return false;
|
||||
// Compare by the string list view of the object
|
||||
return toStringList().equals( ((BlockList) other).toStringList() );
|
||||
|
@ -109,10 +108,9 @@ public class BlockList implements IStringArray {
|
|||
private void mergeFromNamespace( String namespace ) {
|
||||
for( ResourceLocation regKey : ForgeRegistries.BLOCKS.getKeys() ) {
|
||||
if( regKey.toString().startsWith( namespace ) ) {
|
||||
BlockEntry entry = new BlockEntry( ForgeRegistries.BLOCKS.getValue( regKey ) );
|
||||
if( entry.BLOCK != null && entry.BLOCK != Blocks.AIR ) {
|
||||
mergeFrom( entry );
|
||||
}
|
||||
final Block block = ForgeRegistries.BLOCKS.getValue( regKey );
|
||||
if( block != null && block != Blocks.AIR )
|
||||
mergeFrom( new BlockEntry( block ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,19 @@
|
|||
package fathertoast.specialmobs.common.config.util;
|
||||
|
||||
import com.electronwill.nightconfig.core.file.FileConfig;
|
||||
import fathertoast.specialmobs.common.core.SpecialMobs;
|
||||
import net.minecraftforge.eventbus.api.EventPriority;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.event.server.FMLServerAboutToStartEvent;
|
||||
import net.minecraftforge.fml.loading.FMLPaths;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public abstract class ConfigUtil {
|
||||
@Mod.EventBusSubscriber( modid = SpecialMobs.MOD_ID, bus = Mod.EventBusSubscriber.Bus.FORGE )
|
||||
public final class ConfigUtil {
|
||||
/** The current "version" of the dynamic registries. This is incremented each time dynamic registries are loaded. */
|
||||
public static byte DYNAMIC_REGISTRY_VERSION;
|
||||
|
||||
/** The plus or minus symbol (+/-). */
|
||||
public static final String PLUS_OR_MINUS = "\u00b1";
|
||||
|
@ -44,4 +52,12 @@ public abstract class ConfigUtil {
|
|||
|
||||
/** @return A string representation of the file from the game directory. */
|
||||
public static String toRelativePath( File gameFile ) { return FMLPaths.GAMEDIR.get().relativize( gameFile.toPath() ).toString(); }
|
||||
|
||||
/**
|
||||
* Called when a server (integrated or dedicated) is about to start.
|
||||
*
|
||||
* @param event The event data.
|
||||
*/
|
||||
@SubscribeEvent( priority = EventPriority.NORMAL )
|
||||
public static void onServerAboutToStart( FMLServerAboutToStartEvent event ) { DYNAMIC_REGISTRY_VERSION++; }
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
package fathertoast.specialmobs.common.config.util;
|
||||
|
||||
import fathertoast.specialmobs.common.config.field.AbstractConfigField;
|
||||
import fathertoast.specialmobs.common.config.field.EntityListField;
|
||||
import fathertoast.specialmobs.common.core.SpecialMobs;
|
||||
import net.minecraft.entity.Entity;
|
||||
|
@ -8,58 +9,84 @@ import net.minecraft.util.ResourceLocation;
|
|||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* One entity-value entry in an entity list.
|
||||
* One entity-value entry in an entity list. Uses a 'lazy' implementation so the entity type registry is
|
||||
* not polled until this entry is actually used.
|
||||
*/
|
||||
@SuppressWarnings( "unused" )
|
||||
public class EntityEntry {
|
||||
/** The entity type this entry is defined for. If this is null, then this entry will match any entity. */
|
||||
public final EntityType<? extends Entity> TYPE;
|
||||
/** The field containing this entry. We save a reference to help improve error/warning reports. */
|
||||
private final AbstractConfigField FIELD;
|
||||
|
||||
/** The registry key for this entry's entity type. */
|
||||
public final ResourceLocation ENTITY_KEY;
|
||||
/** True if this should check for instanceof the entity class (as opposed to equals). */
|
||||
public final boolean EXTEND;
|
||||
/** The values given to this entry. Null for comparison objects. */
|
||||
public final double[] VALUES;
|
||||
|
||||
/** The entity type this entry is defined for. If this is null, then this entry will match any entity. */
|
||||
private EntityType<? extends Entity> entityType;
|
||||
/** The class this entry is defined for. This is not assigned until a world has been loaded. */
|
||||
Class<? extends Entity> entityClass;
|
||||
|
||||
/** Creates an entry used to compare entity classes internally with the entries in an entity list. */
|
||||
EntityEntry( Entity entity ) {
|
||||
TYPE = entity.getType();
|
||||
FIELD = null;
|
||||
ENTITY_KEY = entity.getType().getRegistryName();
|
||||
EXTEND = false;
|
||||
VALUES = null;
|
||||
entityType = entity.getType();
|
||||
entityClass = entity.getClass();
|
||||
}
|
||||
|
||||
/** Creates an entry with the specified values that acts as a default matching all entity types. Used for creating default configs. */
|
||||
public EntityEntry( double... values ) {
|
||||
this( null, true, values );
|
||||
}
|
||||
public EntityEntry( double... values ) { this( null, true, values ); }
|
||||
|
||||
/** Creates an extendable entry with the specified values. Used for creating default configs. */
|
||||
public EntityEntry( EntityType<? extends Entity> entityType, double... values ) {
|
||||
this( entityType, true, values );
|
||||
}
|
||||
public EntityEntry( @Nullable EntityType<? extends Entity> type, double... values ) { this( type, true, values ); }
|
||||
|
||||
/** Creates an entry with the specified values. Used for creating default configs. */
|
||||
public EntityEntry( EntityType<? extends Entity> entityType, boolean extend, double... values ) {
|
||||
TYPE = entityType;
|
||||
public EntityEntry( @Nullable EntityType<? extends Entity> type, boolean extend, double... values ) {
|
||||
this( null, type == null ? null : type.getRegistryName(), extend, values );
|
||||
entityType = type;
|
||||
}
|
||||
|
||||
/** Creates an entry with the specified values. */
|
||||
public EntityEntry( @Nullable AbstractConfigField field, @Nullable ResourceLocation regKey, boolean extend, double... values ) {
|
||||
FIELD = field;
|
||||
ENTITY_KEY = regKey;
|
||||
EXTEND = extend;
|
||||
VALUES = values;
|
||||
}
|
||||
|
||||
/** @return Loads the entity type from registry. Returns true if successful. */
|
||||
private boolean validate() {
|
||||
if( entityType != null || ENTITY_KEY == null ) return true; // Null entity key means this is a default entry
|
||||
|
||||
if( !ForgeRegistries.ENTITIES.containsKey( ENTITY_KEY ) ) {
|
||||
SpecialMobs.LOG.warn( "Invalid entry for {} \"{}\"! Invalid entry: {}",
|
||||
FIELD.getClass(), FIELD.getKey(), ENTITY_KEY.toString() );
|
||||
return false;
|
||||
}
|
||||
entityType = ForgeRegistries.ENTITIES.getValue( ENTITY_KEY );
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Called on this entry before using it to check if the entity class has been determined, and loads the class if it has not been. */
|
||||
void checkClass( World world ) {
|
||||
if( TYPE != null && entityClass == null ) {
|
||||
if( validate() && entityType != null && entityClass == null ) {
|
||||
try {
|
||||
final Entity entity = TYPE.create( world );
|
||||
final Entity entity = entityType.create( world );
|
||||
if( entity != null ) {
|
||||
entityClass = entity.getClass();
|
||||
entity.remove();
|
||||
}
|
||||
}
|
||||
catch( Exception ex ) {
|
||||
SpecialMobs.LOG.warn( "Failed to load class of entity type {}!", TYPE );
|
||||
SpecialMobs.LOG.warn( "Failed to load class of entity type {}!", entityType );
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
@ -72,9 +99,11 @@ public class EntityEntry {
|
|||
* entries for the same class in a list.
|
||||
*/
|
||||
public boolean contains( EntityEntry entry ) {
|
||||
if( !validate() ) return false;
|
||||
|
||||
// Handle default entries
|
||||
if( TYPE == null ) return true;
|
||||
if( entry.TYPE == null ) return false;
|
||||
if( entityType == null ) return true;
|
||||
if( entry.entityType == null ) return false;
|
||||
// Same entity, but non-extendable is more specific
|
||||
if( entityClass == entry.entityClass ) return !entry.EXTEND;
|
||||
// Extendable entry, check if the other is for a subclass
|
||||
|
@ -91,8 +120,7 @@ public class EntityEntry {
|
|||
@Override
|
||||
public String toString() {
|
||||
// Start with the entity type registry key
|
||||
ResourceLocation resource = TYPE == null ? null : ForgeRegistries.ENTITIES.getKey( TYPE );
|
||||
StringBuilder str = new StringBuilder( resource == null ? EntityListField.REG_KEY_DEFAULT : resource.toString() );
|
||||
StringBuilder str = new StringBuilder( ENTITY_KEY == null ? EntityListField.REG_KEY_DEFAULT : ENTITY_KEY.toString() );
|
||||
// Insert "specific" prefix if not extendable
|
||||
if( !EXTEND ) {
|
||||
str.insert( 0, '~' );
|
||||
|
|
|
@ -5,6 +5,7 @@ import fathertoast.specialmobs.common.config.file.TomlHelper;
|
|||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -45,7 +46,7 @@ public class EntityList implements IStringArray {
|
|||
|
||||
/** @return Returns true if this object has the same value as another object. */
|
||||
@Override
|
||||
public boolean equals( Object other ) {
|
||||
public boolean equals( @Nullable Object other ) {
|
||||
if( !(other instanceof EntityList) ) return false;
|
||||
// Compare by the string list view of the object
|
||||
return toStringList().equals( ((EntityList) other).toStringList() );
|
||||
|
@ -63,7 +64,8 @@ public class EntityList implements IStringArray {
|
|||
}
|
||||
|
||||
/** @return True if the entity is contained in this list. */
|
||||
public boolean contains( Entity entity ) {
|
||||
public boolean contains( @Nullable Entity entity ) {
|
||||
if( entity == null ) return false;
|
||||
final EntityEntry targetEntry = new EntityEntry( entity );
|
||||
for( EntityEntry currentEntry : ENTRIES ) {
|
||||
currentEntry.checkClass( entity.level );
|
||||
|
@ -77,7 +79,9 @@ public class EntityList implements IStringArray {
|
|||
* @param entity The entity to retrieve values for.
|
||||
* @return The array of values of the best-match entry. Returns null if the entity is not contained in this entity list.
|
||||
*/
|
||||
public double[] getValues( Entity entity ) {
|
||||
@Nullable
|
||||
public double[] getValues( @Nullable Entity entity ) {
|
||||
if( entity == null ) return null;
|
||||
final EntityEntry targetEntry = new EntityEntry( entity );
|
||||
EntityEntry bestMatch = null;
|
||||
for( EntityEntry currentEntry : ENTRIES ) {
|
||||
|
@ -101,7 +105,7 @@ public class EntityList implements IStringArray {
|
|||
* @see #setSingleValue()
|
||||
* @see #setSinglePercent()
|
||||
*/
|
||||
public double getValue( Entity entity ) {
|
||||
public double getValue( @Nullable Entity entity ) {
|
||||
final double[] values = getValues( entity );
|
||||
return values == null || values.length < 1 ? 0.0 : values[0];
|
||||
}
|
||||
|
@ -112,7 +116,7 @@ public class EntityList implements IStringArray {
|
|||
* is not contained in this entity list or has no values specified. This should only be used for 'single percent' lists.
|
||||
* @see #setSinglePercent()
|
||||
*/
|
||||
public boolean rollChance( LivingEntity entity ) {
|
||||
public boolean rollChance( @Nullable LivingEntity entity ) {
|
||||
return ENTRIES.length > 0 && entity != null && entity.getRandom().nextDouble() < getValue( entity );
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,319 @@
|
|||
package fathertoast.specialmobs.common.config.util;
|
||||
|
||||
import fathertoast.specialmobs.common.config.util.environment.*;
|
||||
import fathertoast.specialmobs.common.config.util.environment.biome.*;
|
||||
import fathertoast.specialmobs.common.config.util.environment.dimension.DimensionPropertyEnvironment;
|
||||
import fathertoast.specialmobs.common.config.util.environment.dimension.DimensionTypeEnvironment;
|
||||
import fathertoast.specialmobs.common.config.util.environment.dimension.DimensionTypeGroupEnvironment;
|
||||
import fathertoast.specialmobs.common.config.util.environment.position.PositionEnvironment;
|
||||
import fathertoast.specialmobs.common.config.util.environment.position.StructureEnvironment;
|
||||
import fathertoast.specialmobs.common.config.util.environment.position.YEnvironment;
|
||||
import fathertoast.specialmobs.common.config.util.environment.position.YFromSeaEnvironment;
|
||||
import fathertoast.specialmobs.common.config.util.environment.time.*;
|
||||
import net.minecraft.util.RegistryKey;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.DimensionType;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.gen.feature.structure.Structure;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* One condition-value entry in an environment list. Uses a 'lazy' implementation so any needed registries are
|
||||
* not polled until this entry is actually used.
|
||||
*/
|
||||
@SuppressWarnings( "unused" )
|
||||
public class EnvironmentEntry {
|
||||
/** The value given to this entry. */
|
||||
public final double VALUE;
|
||||
/** The conditions that define this entry's environment. */
|
||||
private final AbstractEnvironment[] CONDITIONS;
|
||||
|
||||
/** Creates an entry with the specified values. */
|
||||
public EnvironmentEntry( double value, List<AbstractEnvironment> conditions ) { this( value, conditions.toArray( new AbstractEnvironment[0] ) ); }
|
||||
|
||||
/** Creates an entry with the specified values. */
|
||||
public EnvironmentEntry( double value, AbstractEnvironment... conditions ) {
|
||||
VALUE = value;
|
||||
CONDITIONS = conditions;
|
||||
}
|
||||
|
||||
/** @return Returns true if all this entry's conditions match the provided environment. */
|
||||
public boolean matches( World world, @Nullable BlockPos pos ) {
|
||||
for( AbstractEnvironment condition : CONDITIONS ) {
|
||||
if( !condition.matches( world, pos ) ) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The string representation of this environment entry, as it would appear in a config file.
|
||||
* <p>
|
||||
* Format is "value condition1 state1 & condition2 state2 & ...".
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
// Start with the value
|
||||
final StringBuilder str = new StringBuilder().append( VALUE ).append( ' ' );
|
||||
// List all conditions
|
||||
boolean first = true;
|
||||
for( AbstractEnvironment condition : CONDITIONS ) {
|
||||
if( first ) first = false;
|
||||
else str.append( " & " );
|
||||
str.append( condition );
|
||||
}
|
||||
return str.toString();
|
||||
}
|
||||
|
||||
|
||||
// Builder Implementation
|
||||
|
||||
/** Creates a new entry builder. The value is rounded to 2 decimal place precision. */
|
||||
public static Builder builder( float value ) { return new Builder( Math.round( value * 100.0 ) / 100.0 ); }
|
||||
|
||||
/** Creates a new entry builder. */
|
||||
public static Builder builder( double value ) { return new Builder( value ); }
|
||||
|
||||
/**
|
||||
* Builder class used to simplify creation of environment entries for default configs,
|
||||
* with shortcuts for the most commonly used environments.
|
||||
* <p>
|
||||
* Keep in mind that ALL conditions in an entry must be satisfied for it to be chosen.
|
||||
*/
|
||||
public static class Builder {
|
||||
private final double VALUE;
|
||||
private final ArrayList<AbstractEnvironment> CONDITIONS = new ArrayList<>();
|
||||
|
||||
private Builder( double value ) { VALUE = value; }
|
||||
|
||||
public EnvironmentEntry build() { return new EnvironmentEntry( VALUE, CONDITIONS ); }
|
||||
|
||||
public Builder in( AbstractEnvironment condition ) {
|
||||
CONDITIONS.add( condition );
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
// Dimension-based
|
||||
|
||||
/** Check if the dimension type causes water to instantly vaporize and has faster lava flow. */
|
||||
public Builder inUltraWarmDimension() { return inDimensionWithProperty( DimensionPropertyEnvironment.Value.ULTRAWARM, false ); }
|
||||
|
||||
/** Check if the dimension type causes water to instantly vaporize and has faster lava flow. */
|
||||
public Builder notInUltraWarmDimension() { return inDimensionWithProperty( DimensionPropertyEnvironment.Value.ULTRAWARM, true ); }
|
||||
|
||||
/** Check if the dimension type allows clocks, compasses, and beds to work. */
|
||||
public Builder inNaturalDimension() { return inDimensionWithProperty( DimensionPropertyEnvironment.Value.NATURAL, false ); }
|
||||
|
||||
/** Check if the dimension type allows clocks, compasses, and beds to work. */
|
||||
public Builder notInNaturalDimension() { return inDimensionWithProperty( DimensionPropertyEnvironment.Value.NATURAL, true ); }
|
||||
|
||||
private Builder inDimensionWithProperty( DimensionPropertyEnvironment.Value property, boolean invert ) {
|
||||
return in( new DimensionPropertyEnvironment( property, invert ) );
|
||||
}
|
||||
|
||||
public Builder inOverworld() { return inDimensionType( DimensionType.OVERWORLD_LOCATION, false ); }
|
||||
|
||||
public Builder notInOverworld() { return inDimensionType( DimensionType.OVERWORLD_LOCATION, true ); }
|
||||
|
||||
public Builder inNether() { return inDimensionType( DimensionType.NETHER_LOCATION, false ); }
|
||||
|
||||
public Builder notInNether() { return inDimensionType( DimensionType.NETHER_LOCATION, true ); }
|
||||
|
||||
public Builder inTheEnd() { return inDimensionType( DimensionType.END_LOCATION, false ); }
|
||||
|
||||
public Builder notInTheEnd() { return inDimensionType( DimensionType.END_LOCATION, true ); }
|
||||
|
||||
private Builder inDimensionType( RegistryKey<DimensionType> dimType, boolean invert ) { return in( new DimensionTypeEnvironment( dimType, invert ) ); }
|
||||
|
||||
/** Check if the dimension type is vanilla (registered with the "minecraft" namespace). */
|
||||
public Builder inVanillaDimension() { return in( new DimensionTypeGroupEnvironment( new ResourceLocation( "" ), false ) ); }
|
||||
|
||||
/** Check if the dimension type is vanilla (registered with the "minecraft" namespace). */
|
||||
public Builder notInVanillaDimension() { return in( new DimensionTypeGroupEnvironment( new ResourceLocation( "" ), true ) ); }
|
||||
|
||||
|
||||
// Biome-based
|
||||
|
||||
/** Check if the biome is a water or beach biome (depth at or below sea level). */
|
||||
public Builder inWaterBiome() { return isDepth( ComparisonOperator.LESS_OR_EQUAL, 0.0F ); }
|
||||
|
||||
/** Check if the biome is a water or beach biome (depth at or below sea level). */
|
||||
public Builder notInWaterBiome() { return isDepth( ComparisonOperator.LESS_OR_EQUAL.invert(), 0.0F ); }
|
||||
|
||||
/** Check if the biome has relatively high elevation. */
|
||||
public Builder inMountainBiome() { return isDepth( ComparisonOperator.GREATER_OR_EQUAL, 0.4F ); }
|
||||
|
||||
/** Check if the biome has relatively high elevation. */
|
||||
public Builder notInMountainBiome() { return isDepth( ComparisonOperator.GREATER_OR_EQUAL.invert(), 0.4F ); }
|
||||
|
||||
private Builder isDepth( ComparisonOperator op, float value ) { return in( new TerrainDepthEnvironment( op, value ) ); }
|
||||
|
||||
/** Check if the biome is relatively flat. */
|
||||
public Builder inFlatBiome() { return isScale( ComparisonOperator.LESS_OR_EQUAL, 0.1F ); }
|
||||
|
||||
/** Check if the biome is relatively flat. */
|
||||
public Builder notInFlatBiome() { return isScale( ComparisonOperator.LESS_OR_EQUAL.invert(), 0.1F ); }
|
||||
|
||||
/** Check if the biome is relatively hilly. */
|
||||
public Builder inHillyBiome() { return isScale( ComparisonOperator.GREATER_OR_EQUAL, 0.3F ); }
|
||||
|
||||
/** Check if the biome is relatively hilly. */
|
||||
public Builder notInHillyBiome() { return isScale( ComparisonOperator.GREATER_OR_EQUAL.invert(), 0.3F ); }
|
||||
|
||||
private Builder isScale( ComparisonOperator op, float value ) { return in( new TerrainScaleEnvironment( op, value ) ); }
|
||||
|
||||
/** Check if the biome has rain disabled. */
|
||||
public Builder inDryBiome() { return inAvgRainfall( ComparisonOperator.EQUAL_TO, 0.0F ); }
|
||||
|
||||
/** Check if the biome has rain disabled. */
|
||||
public Builder notInDryBiome() { return inAvgRainfall( ComparisonOperator.EQUAL_TO.invert(), 0.0F ); }
|
||||
|
||||
/** Check if the biome's humidity hinders fire spread. */
|
||||
public Builder inHumidBiome() { return inAvgRainfall( ComparisonOperator.GREATER_THAN, 0.85F ); }
|
||||
|
||||
/** Check if the biome's humidity hinders fire spread. */
|
||||
public Builder notInHumidBiome() { return inAvgRainfall( ComparisonOperator.GREATER_THAN.invert(), 0.85F ); }
|
||||
|
||||
private Builder inAvgRainfall( ComparisonOperator op, float value ) { return in( new RainfallEnvironment( op, value ) ); }
|
||||
|
||||
/** Check if the temperature is freezing. */
|
||||
public Builder isFreezing() { return in( new TemperatureEnvironment( true ) ); }
|
||||
|
||||
/** Check if the temperature is freezing. */
|
||||
public Builder isNotFreezing() { return in( new TemperatureEnvironment( false ) ); }
|
||||
|
||||
/** Check if the temperature is warm (disables snow golem trails). */
|
||||
public Builder isWarm() { return isTemperature( ComparisonOperator.GREATER_OR_EQUAL, 0.8F ); }
|
||||
|
||||
/** Check if the temperature is warm (disables snow golem trails). */
|
||||
public Builder isNotWarm() { return isTemperature( ComparisonOperator.GREATER_OR_EQUAL.invert(), 0.8F ); }
|
||||
|
||||
/** Check if the temperature is hot (causes snow golems to die). */
|
||||
public Builder isHot() { return isTemperature( ComparisonOperator.GREATER_THAN, 1.0F ); }
|
||||
|
||||
/** Check if the temperature is hot (causes snow golems to die). */
|
||||
public Builder isNotHot() { return isTemperature( ComparisonOperator.GREATER_THAN.invert(), 1.0F ); }
|
||||
|
||||
private Builder isTemperature( ComparisonOperator op, float value ) { return in( new TemperatureEnvironment( op, value ) ); }
|
||||
|
||||
/** Check if the biome belongs to a specific category. */
|
||||
public Builder inBiomeCategory( BiomeCategory category ) { return in( new BiomeCategoryEnvironment( category, false ) ); }
|
||||
|
||||
/** Check if the biome belongs to a specific category. */
|
||||
public Builder notInBiomeCategory( BiomeCategory category ) { return in( new BiomeCategoryEnvironment( category, true ) ); }
|
||||
|
||||
|
||||
// Position-based
|
||||
|
||||
/** Check if the position is inside a particular structure. See {@link Structure}. */
|
||||
public Builder inStructure( Structure<?> structure ) { return in( new StructureEnvironment( structure, false ) ); }
|
||||
|
||||
/** Check if the position is inside a particular structure. See {@link Structure}. */
|
||||
public Builder notInStructure( Structure<?> structure ) { return in( new StructureEnvironment( structure, true ) ); }
|
||||
|
||||
/** Check if diamond/redstone ore can generate at the position. */
|
||||
public Builder belowDiamondLevel() { return belowY( 15 ); } // TODO update ore-based logic in 1.18
|
||||
|
||||
/** Check if diamond/redstone ore can generate at the position. */
|
||||
public Builder aboveDiamondLevel() { return aboveY( 15 ); }
|
||||
|
||||
/** Check if gold/lapis ore can generate at the position. */
|
||||
public Builder belowGoldLevel() { return belowY( 33 ); }
|
||||
|
||||
/** Check if gold/lapis ore can generate at the position. */
|
||||
public Builder aboveGoldLevel() { return aboveY( 33 ); }
|
||||
|
||||
private Builder belowY( int y ) { return in( new YEnvironment( ComparisonOperator.LESS_OR_EQUAL, y ) ); }
|
||||
|
||||
private Builder aboveY( int y ) { return in( new YEnvironment( ComparisonOperator.LESS_OR_EQUAL.invert(), y ) ); }
|
||||
|
||||
/** Check if the position is above/below sea level. */
|
||||
public Builder belowSeaLevel() { return in( new YFromSeaEnvironment( ComparisonOperator.LESS_OR_EQUAL, 0 ) ); }
|
||||
|
||||
/** Check if the position is above/below sea level. */
|
||||
public Builder aboveSeaLevel() { return in( new YFromSeaEnvironment( ComparisonOperator.LESS_OR_EQUAL.invert(), 0 ) ); }
|
||||
|
||||
/** Check if the position is above/below the average sea floor. */
|
||||
public Builder belowSeaFloor() { return in( new YFromSeaEnvironment( ComparisonOperator.LESS_OR_EQUAL, -18 ) ); }
|
||||
|
||||
/** Check if the position is above/below the average sea floor. */
|
||||
public Builder aboveSeaFloor() { return in( new YFromSeaEnvironment( ComparisonOperator.LESS_OR_EQUAL.invert(), -18 ) ); }
|
||||
|
||||
/** Check if the position is above/below 'mountain level' - that is, high enough to die from falling to sea level. */
|
||||
public Builder aboveMountainLevel() { return in( new YFromSeaEnvironment( ComparisonOperator.GREATER_OR_EQUAL, 24 ) ); }
|
||||
|
||||
/** Check if the position is above/below 'mountain level' - that is, high enough to die from falling to sea level. */
|
||||
public Builder belowMountainLevel() { return in( new YFromSeaEnvironment( ComparisonOperator.GREATER_OR_EQUAL.invert(), 24 ) ); }
|
||||
|
||||
public Builder canSeeSky() { return inPositionWithState( PositionEnvironment.Value.CAN_SEE_SKY, false ); }
|
||||
|
||||
public Builder cannotSeeSky() { return inPositionWithState( PositionEnvironment.Value.CAN_SEE_SKY, true ); }
|
||||
|
||||
public Builder isNearVillage() { return inPositionWithState( PositionEnvironment.Value.IS_NEAR_VILLAGE, false ); }
|
||||
|
||||
public Builder isNotNearVillage() { return inPositionWithState( PositionEnvironment.Value.IS_NEAR_VILLAGE, true ); }
|
||||
|
||||
public Builder isNearRaid() { return inPositionWithState( PositionEnvironment.Value.IS_NEAR_RAID, false ); }
|
||||
|
||||
public Builder isNotNearRaid() { return inPositionWithState( PositionEnvironment.Value.IS_NEAR_RAID, true ); }
|
||||
|
||||
private Builder inPositionWithState( PositionEnvironment.Value state, boolean invert ) { return in( new PositionEnvironment( state, invert ) ); }
|
||||
|
||||
|
||||
// Time-based
|
||||
|
||||
/** Check if the special difficulty multiplier is above a threshold (0 - 1). */
|
||||
public Builder aboveDifficulty( float percent ) { return in( new SpecialDifficultyEnvironment( ComparisonOperator.GREATER_OR_EQUAL, percent ) ); }
|
||||
|
||||
/** Check if the special difficulty multiplier is above a threshold (0 - 1). */
|
||||
public Builder belowDifficulty( float percent ) { return in( new SpecialDifficultyEnvironment( ComparisonOperator.GREATER_OR_EQUAL.invert(), percent ) ); }
|
||||
|
||||
public Builder isRaining() { return inWeather( WeatherEnvironment.Value.RAIN, false ); } // same as "is not clear"
|
||||
|
||||
public Builder isNotRaining() { return inWeather( WeatherEnvironment.Value.RAIN, true ); } // same as "is clear"
|
||||
|
||||
public Builder isThundering() { return inWeather( WeatherEnvironment.Value.THUNDER, false ); }
|
||||
|
||||
public Builder isNotThundering() { return inWeather( WeatherEnvironment.Value.THUNDER, true ); }
|
||||
|
||||
private Builder inWeather( WeatherEnvironment.Value weather, boolean invert ) { return in( new WeatherEnvironment( weather, invert ) ); }
|
||||
|
||||
public Builder atMaxMoonLight() { return in( new MoonPhaseEnvironment( MoonPhaseEnvironment.Value.FULL, false ) ); }
|
||||
|
||||
public Builder aboveHalfMoonLight() { return fromHalfMoonLight( ComparisonOperator.GREATER_THAN ); }
|
||||
|
||||
public Builder atHalfMoonLight() { return fromHalfMoonLight( ComparisonOperator.EQUAL_TO ); }
|
||||
|
||||
public Builder belowHalfMoonLight() { return fromHalfMoonLight( ComparisonOperator.LESS_THAN ); }
|
||||
|
||||
public Builder atNoMoonLight() { return in( new MoonPhaseEnvironment( MoonPhaseEnvironment.Value.NEW, false ) ); }
|
||||
|
||||
private Builder fromHalfMoonLight( ComparisonOperator op ) { return in( new MoonBrightnessEnvironment( op, 0.5F ) ); }
|
||||
|
||||
public Builder isNight() { return in( new DayTimeEnvironment( DayTimeEnvironment.Value.NIGHT, false ) ); }
|
||||
|
||||
public Builder isDay() { return in( new DayTimeEnvironment( DayTimeEnvironment.Value.DAY, false ) ); }
|
||||
|
||||
/** Check if the time is during a quarter of the night centered on midnight. */
|
||||
public Builder isNearMidnight() { return in( new TimeFromMidnightEnvironment( ComparisonOperator.LESS_OR_EQUAL, 1_500 ) ); }
|
||||
|
||||
/** Check if the time is during a quarter of the night centered on midnight. */
|
||||
public Builder isNotNearMidnight() { return in( new TimeFromMidnightEnvironment( ComparisonOperator.LESS_OR_EQUAL.invert(), 1_500 ) ); }
|
||||
|
||||
/** Check if the world time is after a certain number of days. */
|
||||
public Builder afterDays( int days ) { return in( new WorldTimeEnvironment( ComparisonOperator.GREATER_OR_EQUAL, 24_000L * days ) ); }
|
||||
|
||||
/** Check if the world time is after a certain number of days. */
|
||||
public Builder beforeDays( int days ) { return in( new WorldTimeEnvironment( ComparisonOperator.GREATER_OR_EQUAL.invert(), 24_000L * days ) ); }
|
||||
|
||||
/** Check if the chunk inhabited time is after a certain number of days. */
|
||||
public Builder afterDaysInChunk( int days ) { return in( new ChunkTimeEnvironment( ComparisonOperator.GREATER_OR_EQUAL, 24_000L * days ) ); }
|
||||
|
||||
/** Check if the chunk inhabited time is after a certain number of days. */
|
||||
public Builder beforeDaysInChunk( int days ) { return in( new ChunkTimeEnvironment( ComparisonOperator.GREATER_OR_EQUAL.invert(), 24_000L * days ) ); }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
package fathertoast.specialmobs.common.config.util;
|
||||
|
||||
import fathertoast.specialmobs.common.config.field.DoubleField;
|
||||
import fathertoast.specialmobs.common.config.field.IStringArray;
|
||||
import fathertoast.specialmobs.common.config.file.TomlHelper;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A list of condition-value entries used to link one number to specific environments.
|
||||
*/
|
||||
@SuppressWarnings( { "unused", "SameParameterValue" } )
|
||||
public class EnvironmentList implements IStringArray {
|
||||
/** The condition-value entries in this list. */
|
||||
private final EnvironmentEntry[] ENTRIES;
|
||||
|
||||
/** The minimum value accepted for entry values in this list. */
|
||||
private double minValue = Double.NEGATIVE_INFINITY;
|
||||
/** The maximum value accepted for entry values in this list. */
|
||||
private double maxValue = Double.POSITIVE_INFINITY;
|
||||
|
||||
/**
|
||||
* Create a new environment list from a list of entries.
|
||||
* <p>
|
||||
* By default, environment list value(s) can be any numerical double.
|
||||
* This can be changed with helper methods that alter values' bounds and return 'this'.
|
||||
*/
|
||||
public EnvironmentList( List<EnvironmentEntry> entries ) { this( entries.toArray( new EnvironmentEntry[0] ) ); }
|
||||
|
||||
/**
|
||||
* Create a new environment list from an array of entries. Used for creating default configs.
|
||||
* <p>
|
||||
* By default, environment list value(s) can be any numerical double.
|
||||
* This can be changed with helper methods that alter values' bounds and return 'this'.
|
||||
*/
|
||||
public EnvironmentList( EnvironmentEntry... entries ) { ENTRIES = entries; }
|
||||
|
||||
/** @return A string representation of this object. */
|
||||
@Override
|
||||
public String toString() { return TomlHelper.toLiteral( toStringList().toArray() ); }
|
||||
|
||||
/** @return Returns true if this object has the same value as another object. */
|
||||
@Override
|
||||
public boolean equals( @Nullable Object other ) {
|
||||
if( !(other instanceof EnvironmentList) ) return false;
|
||||
// Compare by the string list view of the object
|
||||
return toStringList().equals( ((EnvironmentList) other).toStringList() );
|
||||
}
|
||||
|
||||
/** @return A list of strings that will represent this object when written to a toml file. */
|
||||
@Override
|
||||
public List<String> toStringList() {
|
||||
// Create a list of the entries in string format
|
||||
final List<String> list = new ArrayList<>( ENTRIES.length );
|
||||
for( EnvironmentEntry entry : ENTRIES ) {
|
||||
list.add( entry.toString() );
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/** @return The value matching the given environment, or the default value if no matching environment is defined. */
|
||||
public double getOrElse( World world, @Nullable BlockPos pos, DoubleField defaultValue ) {
|
||||
return getOrElse( world, pos, defaultValue.get() );
|
||||
}
|
||||
|
||||
/** @return The value matching the given environment, or the default value if no matching environment is defined. */
|
||||
public double getOrElse( World world, @Nullable BlockPos pos, double defaultValue ) {
|
||||
final Double value = get( world, pos );
|
||||
return value == null ? defaultValue : value;
|
||||
}
|
||||
|
||||
/** @return The value matching the given environment, or null if no matching environment is defined. */
|
||||
@Nullable
|
||||
public Double get( World world, @Nullable BlockPos pos ) {
|
||||
for( EnvironmentEntry entry : ENTRIES ) {
|
||||
if( entry.matches( world, pos ) ) return entry.VALUE;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Bounds entry values in this list to the specified range. */
|
||||
public EnvironmentList setRange( DoubleField.Range range ) { return setRange( range.MIN, range.MAX ); }
|
||||
|
||||
/** Bounds entry values in this list to the specified limits, inclusive. */
|
||||
public EnvironmentList setRange( double min, double max ) {
|
||||
minValue = min;
|
||||
maxValue = max;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** @return The minimum value that can be given to entry values. */
|
||||
public double getMinValue() { return minValue; }
|
||||
|
||||
/** @return The maximum value that can be given to entry values. */
|
||||
public double getMaxValue() { return maxValue; }
|
||||
}
|
|
@ -8,6 +8,7 @@ import net.minecraft.util.ResourceLocation;
|
|||
import net.minecraftforge.registries.IForgeRegistry;
|
||||
import net.minecraftforge.registries.IForgeRegistryEntry;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
|
@ -25,9 +26,7 @@ public class RegistryEntryList<T extends IForgeRegistryEntry<T>> implements IStr
|
|||
/** The list used to write back to file. */
|
||||
protected final List<String> PRINT_LIST = new ArrayList<>();
|
||||
|
||||
protected RegistryEntryList( IForgeRegistry<T> registry ) {
|
||||
REGISTRY = registry;
|
||||
}
|
||||
protected RegistryEntryList( IForgeRegistry<T> registry ) { REGISTRY = registry; }
|
||||
|
||||
/**
|
||||
* Create a new registry entry list from an array of entries. Used for creating default configs.
|
||||
|
@ -79,13 +78,11 @@ public class RegistryEntryList<T extends IForgeRegistryEntry<T>> implements IStr
|
|||
|
||||
/** @return A string representation of this object. */
|
||||
@Override
|
||||
public String toString() {
|
||||
return TomlHelper.toLiteral( PRINT_LIST.toArray() );
|
||||
}
|
||||
public String toString() { return TomlHelper.toLiteral( PRINT_LIST.toArray() ); }
|
||||
|
||||
/** @return Returns true if this object has the same value as another object. */
|
||||
@Override
|
||||
public boolean equals( Object other ) {
|
||||
public boolean equals( @Nullable Object other ) {
|
||||
if( !(other instanceof RegistryEntryList) ) return false;
|
||||
// Compare by the registries used and string list view of the object
|
||||
return getRegistry() == ((RegistryEntryList<?>) other).getRegistry() &&
|
||||
|
@ -100,7 +97,7 @@ public class RegistryEntryList<T extends IForgeRegistryEntry<T>> implements IStr
|
|||
public boolean isEmpty() { return UNDERLYING_SET.isEmpty(); }
|
||||
|
||||
/** @return Returns true if the entry is contained in this list. */
|
||||
public boolean contains( T entry ) { return UNDERLYING_SET.contains( entry ); }
|
||||
public boolean contains( @Nullable T entry ) { return UNDERLYING_SET.contains( entry ); }
|
||||
|
||||
/** @return Adds the registry entry if it exists and isn't already present, returns true if successful. */
|
||||
protected boolean mergeFrom( ResourceLocation regKey ) {
|
||||
|
|
|
@ -13,10 +13,8 @@ import java.util.*;
|
|||
* <p>
|
||||
* Creates a config field for each item so weights can be defined by the user.
|
||||
*/
|
||||
@SuppressWarnings( "unused" )
|
||||
public class WeightedList<T extends WeightedList.Value> {
|
||||
/** The spec used by this config that defines the file's format. */
|
||||
protected final ToastConfigSpec SPEC;
|
||||
|
||||
/** The weighted entries in this list. */
|
||||
private final List<Entry<T>> ENTRIES;
|
||||
/** The total weight of all entries in this list. */
|
||||
|
@ -25,20 +23,20 @@ public class WeightedList<T extends WeightedList.Value> {
|
|||
/**
|
||||
* Creates a new weighted list config option and registers it and any needed definitions with the spec.
|
||||
*/
|
||||
public WeightedList( ToastConfigSpec parent, String key, T[] values, String... description ) {
|
||||
this( parent, key, Arrays.asList( values ), description );
|
||||
public WeightedList( ToastConfigSpec SPEC, String key, T[] values, @Nullable String... description ) {
|
||||
this( SPEC, key, Arrays.asList( values ), description );
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new weighted list config option and registers it and any needed definitions with the spec.
|
||||
*/
|
||||
public WeightedList( ToastConfigSpec parent, String key, Iterable<T> values, String... description ) {
|
||||
SPEC = parent;
|
||||
|
||||
public WeightedList( ToastConfigSpec SPEC, String key, Iterable<T> values, @Nullable String... description ) {
|
||||
final IntField.Range fieldRange = IntField.Range.NON_NEGATIVE;
|
||||
List<String> comment = TomlHelper.newComment( description );
|
||||
comment.add( TomlHelper.multiFieldInfo( fieldRange ) );
|
||||
SPEC.comment( comment );
|
||||
if( description != null ) {
|
||||
List<String> comment = TomlHelper.newComment( description );
|
||||
comment.add( TomlHelper.multiFieldInfo( fieldRange ) );
|
||||
SPEC.comment( comment );
|
||||
}
|
||||
|
||||
// Define each value's weight field and connect the value to its weight in an entry
|
||||
List<Entry<T>> list = new ArrayList<>();
|
||||
|
@ -110,6 +108,7 @@ public class WeightedList<T extends WeightedList.Value> {
|
|||
default int getDefaultWeight() { return 1; }
|
||||
|
||||
/** @return Returns the comment for this object. */
|
||||
@Nullable
|
||||
default String[] getComment() { return null; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package fathertoast.specialmobs.common.config.util.environment;
|
||||
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public abstract class AbstractEnvironment {
|
||||
/** @return The string representation of this environment, as it would appear in a config file. */
|
||||
@Override
|
||||
public final String toString() { return name() + " " + value(); }
|
||||
|
||||
/** @return The string name of this environment, as it would appear in a config file. */
|
||||
public abstract String name();
|
||||
|
||||
/** @return The string value of this environment, as it would appear in a config file. */
|
||||
public abstract String value();
|
||||
|
||||
/** @return Returns true if this environment matches the provided environment. */
|
||||
public abstract boolean matches( World world, @Nullable BlockPos pos );
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
package fathertoast.specialmobs.common.config.util.environment;
|
||||
|
||||
import fathertoast.specialmobs.common.config.field.AbstractConfigField;
|
||||
import fathertoast.specialmobs.common.config.file.TomlHelper;
|
||||
import fathertoast.specialmobs.common.core.SpecialMobs;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public abstract class CompareFloatEnvironment extends AbstractEnvironment {
|
||||
/** How the actual value is compared to this environment's value. */
|
||||
public final ComparisonOperator COMPARATOR;
|
||||
/** The value for this environment. */
|
||||
public final float VALUE;
|
||||
|
||||
public CompareFloatEnvironment( ComparisonOperator op, float value ) {
|
||||
COMPARATOR = op;
|
||||
VALUE = value;
|
||||
}
|
||||
|
||||
public CompareFloatEnvironment( AbstractConfigField field, String line ) {
|
||||
if( line.isEmpty() ) {
|
||||
COMPARATOR = ComparisonOperator.LESS_THAN;
|
||||
VALUE = 0.0F;
|
||||
SpecialMobs.LOG.warn( "Invalid entry for {} \"{}\"! Not defined. Defaulting to \"{}\". Invalid entry: {}",
|
||||
field.getClass(), field.getKey(), value(), line );
|
||||
}
|
||||
else {
|
||||
final ComparisonOperator op = ComparisonOperator.parse( line );
|
||||
if( op == null ) {
|
||||
COMPARATOR = ComparisonOperator.LESS_THAN;
|
||||
SpecialMobs.LOG.warn( "Invalid entry for {} \"{}\"! Comparison not defined (must be in the set [ {} ]). Defaulting to \"{}\". Invalid entry: {}",
|
||||
field.getClass(), field.getKey(), TomlHelper.literalList( (Object[]) ComparisonOperator.values() ), COMPARATOR, line );
|
||||
}
|
||||
else COMPARATOR = op;
|
||||
VALUE = parseValue( field, line, line.substring( COMPARATOR.toString().length() ).trim() );
|
||||
}
|
||||
}
|
||||
|
||||
/** @return Parses the value and returns a valid result. */
|
||||
private float parseValue( AbstractConfigField field, String line, String arg ) {
|
||||
// Try to parse the value
|
||||
float value;
|
||||
try {
|
||||
value = Float.parseFloat( arg );
|
||||
}
|
||||
catch( NumberFormatException ex ) {
|
||||
SpecialMobs.LOG.warn( "Invalid entry for {} \"{}\"! Value not defined (must be a float). Defaulting to '0'. Invalid entry: {}",
|
||||
field.getClass(), field.getKey(), line );
|
||||
value = 0.0F;
|
||||
}
|
||||
// Verify value is within range
|
||||
if( value < getMinValue() ) {
|
||||
SpecialMobs.LOG.warn( "Value for {} \"{}\" is below the minimum ({})! Clamping value. Invalid value: {}",
|
||||
field.getClass(), field.getKey(), getMinValue(), value );
|
||||
value = getMinValue();
|
||||
}
|
||||
else if( value > getMaxValue() ) {
|
||||
SpecialMobs.LOG.warn( "Value for {} \"{}\" is above the maximum ({})! Clamping value. Invalid value: {}",
|
||||
field.getClass(), field.getKey(), getMaxValue(), value );
|
||||
value = getMaxValue();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/** @return The minimum value that can be given to the value. */
|
||||
protected float getMinValue() { return Float.NEGATIVE_INFINITY; }
|
||||
|
||||
/** @return The maximum value that can be given to the value. */
|
||||
protected float getMaxValue() { return Float.POSITIVE_INFINITY; }
|
||||
|
||||
/** @return The string value of this environment, as it would appear in a config file. */
|
||||
@Override
|
||||
public String value() { return COMPARATOR + " " + VALUE; }
|
||||
|
||||
/** @return Returns true if this environment matches the provided environment. */
|
||||
@Override
|
||||
public boolean matches( World world, @Nullable BlockPos pos ) {
|
||||
final float actual = getActual( world, pos );
|
||||
return !Float.isNaN( actual ) && COMPARATOR.apply( actual, VALUE );
|
||||
}
|
||||
|
||||
/** @return Returns the actual value to compare, or Float.NaN if there isn't enough information. */
|
||||
public abstract float getActual( World world, @Nullable BlockPos pos );
|
||||
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
package fathertoast.specialmobs.common.config.util.environment;
|
||||
|
||||
import fathertoast.specialmobs.common.config.field.AbstractConfigField;
|
||||
import fathertoast.specialmobs.common.config.file.TomlHelper;
|
||||
import fathertoast.specialmobs.common.core.SpecialMobs;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public abstract class CompareIntEnvironment extends AbstractEnvironment {
|
||||
/** How the actual value is compared to this environment's value. */
|
||||
public final ComparisonOperator COMPARATOR;
|
||||
/** The value for this environment. */
|
||||
public final int VALUE;
|
||||
|
||||
public CompareIntEnvironment( ComparisonOperator op, int value ) {
|
||||
COMPARATOR = op;
|
||||
VALUE = value;
|
||||
}
|
||||
|
||||
public CompareIntEnvironment( AbstractConfigField field, String line ) {
|
||||
if( line.isEmpty() ) {
|
||||
COMPARATOR = ComparisonOperator.LESS_THAN;
|
||||
VALUE = 0;
|
||||
SpecialMobs.LOG.warn( "Invalid entry for {} \"{}\"! Not defined. Defaulting to \"{}\". Invalid entry: {}",
|
||||
field.getClass(), field.getKey(), value(), line );
|
||||
}
|
||||
else {
|
||||
final ComparisonOperator op = ComparisonOperator.parse( line );
|
||||
if( op == null ) {
|
||||
COMPARATOR = ComparisonOperator.LESS_THAN;
|
||||
SpecialMobs.LOG.warn( "Invalid entry for {} \"{}\"! Comparison not defined (must be in the set [ {} ]). Defaulting to \"{}\". Invalid entry: {}",
|
||||
field.getClass(), field.getKey(), TomlHelper.literalList( (Object[]) ComparisonOperator.values() ), COMPARATOR, line );
|
||||
}
|
||||
else COMPARATOR = op;
|
||||
VALUE = parseValue( field, line, line.substring( COMPARATOR.toString().length() ).trim() );
|
||||
}
|
||||
}
|
||||
|
||||
/** @return Parses the value and returns a valid result. */
|
||||
private int parseValue( AbstractConfigField field, String line, String arg ) {
|
||||
// Try to parse the value
|
||||
int value;
|
||||
try {
|
||||
value = Integer.parseInt( arg );
|
||||
}
|
||||
catch( NumberFormatException ex ) {
|
||||
SpecialMobs.LOG.warn( "Invalid entry for {} \"{}\"! Value not defined (must be an integer). Defaulting to '0'. Invalid entry: {}",
|
||||
field.getClass(), field.getKey(), line );
|
||||
value = 0;
|
||||
}
|
||||
// Verify value is within range
|
||||
if( value < getMinValue() ) {
|
||||
SpecialMobs.LOG.warn( "Value for {} \"{}\" is below the minimum ({})! Clamping value. Invalid value: {}",
|
||||
field.getClass(), field.getKey(), getMinValue(), value );
|
||||
value = getMinValue();
|
||||
}
|
||||
else if( value > getMaxValue() ) {
|
||||
SpecialMobs.LOG.warn( "Value for {} \"{}\" is above the maximum ({})! Clamping value. Invalid value: {}",
|
||||
field.getClass(), field.getKey(), getMaxValue(), value );
|
||||
value = getMaxValue();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/** @return The minimum value that can be given to the value. */
|
||||
protected int getMinValue() { return Integer.MIN_VALUE; }
|
||||
|
||||
/** @return The maximum value that can be given to the value. */
|
||||
protected int getMaxValue() { return Integer.MAX_VALUE; }
|
||||
|
||||
/** @return The string value of this environment, as it would appear in a config file. */
|
||||
@Override
|
||||
public String value() { return COMPARATOR + " " + VALUE; }
|
||||
|
||||
/** @return Returns true if this environment matches the provided environment. */
|
||||
@Override
|
||||
public boolean matches( World world, @Nullable BlockPos pos ) {
|
||||
final Integer actual = getActual( world, pos );
|
||||
return actual != null && COMPARATOR.apply( actual, VALUE );
|
||||
}
|
||||
|
||||
/** @return Returns the actual value to compare, or null if there isn't enough information. */
|
||||
@Nullable
|
||||
public abstract Integer getActual( World world, @Nullable BlockPos pos );
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
package fathertoast.specialmobs.common.config.util.environment;
|
||||
|
||||
import fathertoast.specialmobs.common.config.field.AbstractConfigField;
|
||||
import fathertoast.specialmobs.common.config.file.TomlHelper;
|
||||
import fathertoast.specialmobs.common.core.SpecialMobs;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public abstract class CompareLongEnvironment extends AbstractEnvironment {
|
||||
/** How the actual value is compared to this environment's value. */
|
||||
public final ComparisonOperator COMPARATOR;
|
||||
/** The value for this environment. */
|
||||
public final long VALUE;
|
||||
|
||||
public CompareLongEnvironment( ComparisonOperator op, long value ) {
|
||||
COMPARATOR = op;
|
||||
VALUE = value;
|
||||
}
|
||||
|
||||
public CompareLongEnvironment( AbstractConfigField field, String line ) {
|
||||
if( line.isEmpty() ) {
|
||||
COMPARATOR = ComparisonOperator.LESS_THAN;
|
||||
VALUE = 0L;
|
||||
SpecialMobs.LOG.warn( "Invalid entry for {} \"{}\"! Not defined. Defaulting to \"{}\". Invalid entry: {}",
|
||||
field.getClass(), field.getKey(), value(), line );
|
||||
}
|
||||
else {
|
||||
final ComparisonOperator op = ComparisonOperator.parse( line );
|
||||
if( op == null ) {
|
||||
COMPARATOR = ComparisonOperator.LESS_THAN;
|
||||
SpecialMobs.LOG.warn( "Invalid entry for {} \"{}\"! Comparison not defined (must be in the set [ {} ]). Defaulting to \"{}\". Invalid entry: {}",
|
||||
field.getClass(), field.getKey(), TomlHelper.literalList( (Object[]) ComparisonOperator.values() ), COMPARATOR, line );
|
||||
}
|
||||
else COMPARATOR = op;
|
||||
VALUE = parseValue( field, line, line.substring( COMPARATOR.toString().length() ).trim() );
|
||||
}
|
||||
}
|
||||
|
||||
/** @return Parses the value and returns a valid result. */
|
||||
private long parseValue( AbstractConfigField field, String line, String arg ) {
|
||||
// Try to parse the value
|
||||
long value;
|
||||
try {
|
||||
value = Long.parseLong( arg );
|
||||
}
|
||||
catch( NumberFormatException ex ) {
|
||||
SpecialMobs.LOG.warn( "Invalid entry for {} \"{}\"! Value not defined (must be a long). Defaulting to '0'. Invalid entry: {}",
|
||||
field.getClass(), field.getKey(), line );
|
||||
value = 0;
|
||||
}
|
||||
// Verify value is within range
|
||||
if( value < getMinValue() ) {
|
||||
SpecialMobs.LOG.warn( "Value for {} \"{}\" is below the minimum ({})! Clamping value. Invalid value: {}",
|
||||
field.getClass(), field.getKey(), getMinValue(), value );
|
||||
value = getMinValue();
|
||||
}
|
||||
else if( value > getMaxValue() ) {
|
||||
SpecialMobs.LOG.warn( "Value for {} \"{}\" is above the maximum ({})! Clamping value. Invalid value: {}",
|
||||
field.getClass(), field.getKey(), getMaxValue(), value );
|
||||
value = getMaxValue();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/** @return The minimum value that can be given to the value. */
|
||||
protected long getMinValue() { return Long.MIN_VALUE; }
|
||||
|
||||
/** @return The maximum value that can be given to the value. */
|
||||
protected long getMaxValue() { return Long.MAX_VALUE; }
|
||||
|
||||
/** @return The string value of this environment, as it would appear in a config file. */
|
||||
@Override
|
||||
public String value() { return COMPARATOR + " " + VALUE; }
|
||||
|
||||
/** @return Returns true if this environment matches the provided environment. */
|
||||
@Override
|
||||
public boolean matches( World world, @Nullable BlockPos pos ) {
|
||||
final Long actual = getActual( world, pos );
|
||||
return actual != null && COMPARATOR.apply( actual, VALUE );
|
||||
}
|
||||
|
||||
/** @return Returns the actual value to compare, or null if there isn't enough information. */
|
||||
@Nullable
|
||||
public abstract Long getActual( World world, @Nullable BlockPos pos );
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
package fathertoast.specialmobs.common.config.util.environment;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public enum ComparisonOperator {
|
||||
NOT_EQUAL_TO( "!=" ), LESS_OR_EQUAL( "<=" ), GREATER_OR_EQUAL( ">=" ),
|
||||
EQUAL_TO( "=" ), LESS_THAN( "<" ), GREATER_THAN( ">" );
|
||||
|
||||
private final String LITERAL;
|
||||
|
||||
ComparisonOperator( String str ) { LITERAL = str; }
|
||||
|
||||
@Override
|
||||
public String toString() { return LITERAL; }
|
||||
|
||||
/** @return A convenience method that returns the opposite comparison operator only if the passed value is true. */
|
||||
public ComparisonOperator invert( boolean invert ) { return invert ? invert() : this; }
|
||||
|
||||
/** @return The opposite comparison operator. */
|
||||
public ComparisonOperator invert() {
|
||||
switch( this ) {
|
||||
case LESS_THAN: return GREATER_OR_EQUAL;
|
||||
case LESS_OR_EQUAL: return GREATER_THAN;
|
||||
case GREATER_THAN: return LESS_OR_EQUAL;
|
||||
case GREATER_OR_EQUAL: return LESS_THAN;
|
||||
case EQUAL_TO: return NOT_EQUAL_TO;
|
||||
case NOT_EQUAL_TO: return EQUAL_TO;
|
||||
}
|
||||
throw new IllegalStateException( "Inversion implementation is invalid! :(" );
|
||||
}
|
||||
|
||||
public boolean apply( float first, float second ) {
|
||||
switch( this ) {
|
||||
case LESS_THAN: return first < second;
|
||||
case LESS_OR_EQUAL: return first <= second;
|
||||
case GREATER_THAN: return first > second;
|
||||
case GREATER_OR_EQUAL: return first >= second;
|
||||
case EQUAL_TO: return first == second;
|
||||
case NOT_EQUAL_TO: return first != second;
|
||||
}
|
||||
throw new IllegalStateException( "Float comparison implementation is invalid! :(" );
|
||||
}
|
||||
|
||||
public boolean apply( int first, int second ) {
|
||||
switch( this ) {
|
||||
case LESS_THAN: return first < second;
|
||||
case LESS_OR_EQUAL: return first <= second;
|
||||
case GREATER_THAN: return first > second;
|
||||
case GREATER_OR_EQUAL: return first >= second;
|
||||
case EQUAL_TO: return first == second;
|
||||
case NOT_EQUAL_TO: return first != second;
|
||||
}
|
||||
throw new IllegalStateException( "Integer comparison implementation is invalid! :(" );
|
||||
}
|
||||
|
||||
public boolean apply( long first, long second ) {
|
||||
switch( this ) {
|
||||
case LESS_THAN: return first < second;
|
||||
case LESS_OR_EQUAL: return first <= second;
|
||||
case GREATER_THAN: return first > second;
|
||||
case GREATER_OR_EQUAL: return first >= second;
|
||||
case EQUAL_TO: return first == second;
|
||||
case NOT_EQUAL_TO: return first != second;
|
||||
}
|
||||
throw new IllegalStateException( "Long comparison implementation is invalid! :(" );
|
||||
}
|
||||
|
||||
/** @return The operator described by a given string, or null if invalid. */
|
||||
@Nullable
|
||||
public static ComparisonOperator parse( String op ) {
|
||||
for( ComparisonOperator operator : values() ) {
|
||||
if( op.startsWith( operator.LITERAL ) ) return operator;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
package fathertoast.specialmobs.common.config.util.environment;
|
||||
|
||||
import fathertoast.specialmobs.common.config.field.AbstractConfigField;
|
||||
import fathertoast.specialmobs.common.config.util.ConfigUtil;
|
||||
import fathertoast.specialmobs.common.core.SpecialMobs;
|
||||
import net.minecraft.util.RegistryKey;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.registry.Registry;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.server.ServerWorld;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Dynamic registries are contained in {@link net.minecraft.util.registry.DynamicRegistries}
|
||||
*/
|
||||
public abstract class DynamicRegistryEnvironment<T> extends AbstractEnvironment {
|
||||
/** The field containing this entry. We save a reference to help improve error/warning reports. */
|
||||
private final AbstractConfigField FIELD;
|
||||
|
||||
/** If true, the condition is inverted. */
|
||||
protected final boolean INVERT;
|
||||
/** The registry key for this environment. */
|
||||
private final ResourceLocation REGISTRY_KEY;
|
||||
|
||||
private T registryEntry;
|
||||
/** The value of ConfigUtil#DYNAMIC_REGISTRY_VERSION at the time of last poll. */
|
||||
private byte version = -1;
|
||||
|
||||
public DynamicRegistryEnvironment( ResourceLocation regKey, boolean invert ) {
|
||||
FIELD = null;
|
||||
INVERT = invert;
|
||||
REGISTRY_KEY = regKey;
|
||||
}
|
||||
|
||||
public DynamicRegistryEnvironment( AbstractConfigField field, String line ) {
|
||||
FIELD = field;
|
||||
INVERT = line.startsWith( "!" );
|
||||
REGISTRY_KEY = new ResourceLocation( INVERT ? line.substring( 1 ) : line );
|
||||
}
|
||||
|
||||
/** @return The string value of this environment, as it would appear in a config file. */
|
||||
@Override
|
||||
public final String value() { return (INVERT ? "!" : "") + REGISTRY_KEY.toString(); }
|
||||
|
||||
/** @return The registry used. */
|
||||
public abstract RegistryKey<Registry<T>> getRegistry();
|
||||
|
||||
/** @return Returns true if this environment matches the provided environment. */
|
||||
@Override
|
||||
public final boolean matches( World world, @Nullable BlockPos pos ) {
|
||||
if( world instanceof ServerWorld )
|
||||
return matches( (ServerWorld) world, pos ); // These don't work on the client :(
|
||||
return INVERT;
|
||||
}
|
||||
|
||||
/** @return Returns true if this environment matches the provided environment. */
|
||||
public abstract boolean matches( ServerWorld world, @Nullable BlockPos pos );
|
||||
|
||||
/** @return The target registry object. */
|
||||
@Nullable
|
||||
public final T getRegistryEntry( ServerWorld world ) {
|
||||
if( version != ConfigUtil.DYNAMIC_REGISTRY_VERSION ) {
|
||||
version = ConfigUtil.DYNAMIC_REGISTRY_VERSION;
|
||||
|
||||
final Registry<T> registry = world.getServer().registryAccess().registryOrThrow( getRegistry() );
|
||||
registryEntry = registry.get( REGISTRY_KEY );
|
||||
if( registryEntry == null ) {
|
||||
SpecialMobs.LOG.info( "Missing entry for {} \"{}\"! Not present in registry \"{}\". Missing entry: {}",
|
||||
FIELD.getClass(), FIELD.getKey(), getRegistry().getRegistryName(), REGISTRY_KEY );
|
||||
}
|
||||
}
|
||||
return registryEntry;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
package fathertoast.specialmobs.common.config.util.environment;
|
||||
|
||||
import fathertoast.specialmobs.common.config.field.AbstractConfigField;
|
||||
import fathertoast.specialmobs.common.config.util.ConfigUtil;
|
||||
import fathertoast.specialmobs.common.core.SpecialMobs;
|
||||
import net.minecraft.util.RegistryKey;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.registry.Registry;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.server.ServerWorld;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Dynamic registries are contained in {@link net.minecraft.util.registry.DynamicRegistries}
|
||||
*/
|
||||
public abstract class DynamicRegistryGroupEnvironment<T> extends AbstractEnvironment {
|
||||
/** The field containing this entry. We save a reference to help improve error/warning reports. */
|
||||
private final AbstractConfigField FIELD;
|
||||
|
||||
/** If true, the condition is inverted. */
|
||||
protected final boolean INVERT;
|
||||
/** The namespace for this environment. */
|
||||
private final String NAMESPACE;
|
||||
|
||||
private List<T> registryEntries;
|
||||
/** The value of ConfigUtil#DYNAMIC_REGISTRY_VERSION at the time of last poll. */
|
||||
private byte version = -1;
|
||||
|
||||
public DynamicRegistryGroupEnvironment( ResourceLocation regKey, boolean invert ) {
|
||||
FIELD = null;
|
||||
INVERT = invert;
|
||||
NAMESPACE = regKey.toString();
|
||||
}
|
||||
|
||||
public DynamicRegistryGroupEnvironment( AbstractConfigField field, String line ) {
|
||||
FIELD = field;
|
||||
INVERT = line.startsWith( "!" );
|
||||
NAMESPACE = line.substring( INVERT ? 1 : 0, line.length() - 1 );
|
||||
}
|
||||
|
||||
/** @return The string value of this environment, as it would appear in a config file. */
|
||||
@Override
|
||||
public final String value() { return (INVERT ? "!" : "") + NAMESPACE + "*"; }
|
||||
|
||||
/** @return The registry used. */
|
||||
public abstract RegistryKey<Registry<T>> getRegistry();
|
||||
|
||||
/** @return Returns true if this environment matches the provided environment. */
|
||||
@Override
|
||||
public final boolean matches( World world, @Nullable BlockPos pos ) {
|
||||
if( world instanceof ServerWorld )
|
||||
return matches( (ServerWorld) world, pos ); // These don't work on the client :(
|
||||
return INVERT;
|
||||
}
|
||||
|
||||
/** @return Returns true if this environment matches the provided environment. */
|
||||
public abstract boolean matches( ServerWorld world, @Nullable BlockPos pos );
|
||||
|
||||
/** @return The target registry object. */
|
||||
protected final List<T> getRegistryEntries( ServerWorld world ) {
|
||||
if( version != ConfigUtil.DYNAMIC_REGISTRY_VERSION ) {
|
||||
version = ConfigUtil.DYNAMIC_REGISTRY_VERSION;
|
||||
|
||||
registryEntries = new ArrayList<>();
|
||||
final Registry<T> registry = world.getServer().registryAccess().registryOrThrow( getRegistry() );
|
||||
for( ResourceLocation regKey : registry.keySet() ) {
|
||||
if( regKey.toString().startsWith( NAMESPACE ) ) {
|
||||
final T entry = registry.get( regKey );
|
||||
if( entry != null ) registryEntries.add( entry );
|
||||
}
|
||||
}
|
||||
if( registryEntries.isEmpty() ) {
|
||||
SpecialMobs.LOG.info( "Namespace entry for {} \"{}\" did not match anything in registry \"{}\"! Questionable entry: {}",
|
||||
FIELD == null ? "DEFAULT" : FIELD.getClass(), FIELD == null ? "DEFAULT" : FIELD.getKey(), getRegistry().getRegistryName(), NAMESPACE );
|
||||
}
|
||||
registryEntries = Collections.unmodifiableList( registryEntries );
|
||||
}
|
||||
return registryEntries;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package fathertoast.specialmobs.common.config.util.environment;
|
||||
|
||||
import fathertoast.specialmobs.common.config.field.AbstractConfigField;
|
||||
import fathertoast.specialmobs.common.config.file.TomlHelper;
|
||||
import fathertoast.specialmobs.common.core.SpecialMobs;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
public abstract class EnumEnvironment<T extends Enum<T>> extends AbstractEnvironment {
|
||||
/** If true, the condition is inverted. */
|
||||
protected final boolean INVERT;
|
||||
/** The enum value for this environment. */
|
||||
protected final T VALUE;
|
||||
|
||||
public EnumEnvironment( T value, boolean invert ) {
|
||||
INVERT = invert;
|
||||
VALUE = value;
|
||||
}
|
||||
|
||||
public EnumEnvironment( AbstractConfigField field, String line, T[] validValues ) {
|
||||
INVERT = line.startsWith( "!" );
|
||||
VALUE = parseValue( field, line, validValues, INVERT ? line.substring( 1 ) : line );
|
||||
}
|
||||
|
||||
/** @return Attempts to parse the string literal as one of the valid values and returns it, or null if invalid. */
|
||||
private T parseValue( AbstractConfigField field, String line, T[] validValues, String name ) {
|
||||
for( T value : validValues ) {
|
||||
if( value.name().equalsIgnoreCase( name ) ) return value;
|
||||
}
|
||||
// Value cannot be parsed
|
||||
SpecialMobs.LOG.warn( "Invalid entry for {} \"{}\"! Value not defined (must be in the set [ {} ]). Defaulting to {}. Invalid entry: {}",
|
||||
field.getClass(), field.getKey(), TomlHelper.literalList( (Object[]) validValues ), TomlHelper.toLiteral(), line );
|
||||
return validValues[0];
|
||||
}
|
||||
|
||||
/** @return The string value of this environment, as it would appear in a config file. */
|
||||
@Override
|
||||
public final String value() { return (INVERT ? "!" : "") + VALUE.name().toLowerCase( Locale.ROOT ); }
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
package fathertoast.specialmobs.common.config.util.environment;
|
||||
|
||||
import fathertoast.specialmobs.common.config.field.AbstractConfigField;
|
||||
import fathertoast.specialmobs.common.core.SpecialMobs;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.registries.IForgeRegistry;
|
||||
import net.minecraftforge.registries.IForgeRegistryEntry;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Registries are contained in {@link net.minecraftforge.registries.ForgeRegistries}
|
||||
*/
|
||||
public abstract class RegistryEnvironment<T extends IForgeRegistryEntry<T>> extends AbstractEnvironment {
|
||||
/** The field containing this entry. We save a reference to help improve error/warning reports. */
|
||||
private final AbstractConfigField FIELD;
|
||||
|
||||
/** If true, the condition is inverted. */
|
||||
protected final boolean INVERT;
|
||||
/** The registry key for this environment. */
|
||||
private final ResourceLocation REGISTRY_KEY;
|
||||
|
||||
private T registryEntry;
|
||||
|
||||
public RegistryEnvironment( T regEntry, boolean invert ) {
|
||||
FIELD = null;
|
||||
INVERT = invert;
|
||||
REGISTRY_KEY = regEntry.getRegistryName();
|
||||
registryEntry = regEntry;
|
||||
}
|
||||
|
||||
public RegistryEnvironment( AbstractConfigField field, String line ) {
|
||||
FIELD = field;
|
||||
INVERT = line.startsWith( "!" );
|
||||
REGISTRY_KEY = new ResourceLocation( INVERT ? line.substring( 1 ) : line );
|
||||
}
|
||||
|
||||
/** @return The string value of this environment, as it would appear in a config file. */
|
||||
@Override
|
||||
public final String value() { return (INVERT ? "!" : "") + REGISTRY_KEY.toString(); }
|
||||
|
||||
/** @return The registry used. */
|
||||
public abstract IForgeRegistry<T> getRegistry();
|
||||
|
||||
/** @return The registry entry. */
|
||||
@Nullable
|
||||
protected final T getRegistryEntry() {
|
||||
if( registryEntry == null ) {
|
||||
if( !getRegistry().containsKey( REGISTRY_KEY ) ) {
|
||||
SpecialMobs.LOG.warn( "Invalid entry for {} \"{}\"! Not present in registry \"{}\". Invalid entry: {}",
|
||||
FIELD.getClass(), FIELD.getKey(), getRegistry().getRegistryName(), REGISTRY_KEY );
|
||||
}
|
||||
registryEntry = getRegistry().getValue( REGISTRY_KEY );
|
||||
}
|
||||
return registryEntry;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
package fathertoast.specialmobs.common.config.util.environment;
|
||||
|
||||
import fathertoast.specialmobs.common.config.field.AbstractConfigField;
|
||||
import fathertoast.specialmobs.common.core.SpecialMobs;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.registries.IForgeRegistry;
|
||||
import net.minecraftforge.registries.IForgeRegistryEntry;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Registries are contained in {@link net.minecraftforge.registries.ForgeRegistries}
|
||||
*/
|
||||
public abstract class RegistryGroupEnvironment<T extends IForgeRegistryEntry<T>> extends AbstractEnvironment {
|
||||
/** The field containing this entry. We save a reference to help improve error/warning reports. */
|
||||
private final AbstractConfigField FIELD;
|
||||
|
||||
/** If true, the condition is inverted. */
|
||||
protected final boolean INVERT;
|
||||
/** The namespace for this environment. */
|
||||
private final String NAMESPACE;
|
||||
|
||||
private List<T> registryEntries;
|
||||
|
||||
public RegistryGroupEnvironment( T regEntry, boolean invert ) {
|
||||
//noinspection ConstantConditions
|
||||
this( regEntry.getRegistryName(), invert );
|
||||
}
|
||||
|
||||
public RegistryGroupEnvironment( ResourceLocation regKey, boolean invert ) {
|
||||
FIELD = null;
|
||||
INVERT = invert;
|
||||
NAMESPACE = regKey.toString();
|
||||
}
|
||||
|
||||
public RegistryGroupEnvironment( AbstractConfigField field, String line ) {
|
||||
FIELD = field;
|
||||
INVERT = line.startsWith( "!" );
|
||||
NAMESPACE = line.substring( INVERT ? 1 : 0, line.length() - 1 );
|
||||
}
|
||||
|
||||
/** @return The string value of this environment, as it would appear in a config file. */
|
||||
@Override
|
||||
public final String value() { return (INVERT ? "!" : "") + NAMESPACE + "*"; }
|
||||
|
||||
/** @return The registry used. */
|
||||
public abstract IForgeRegistry<T> getRegistry();
|
||||
|
||||
/** @return The registry entries. */
|
||||
protected final List<T> getRegistryEntries() {
|
||||
if( registryEntries == null ) {
|
||||
registryEntries = new ArrayList<>();
|
||||
for( ResourceLocation regKey : getRegistry().getKeys() ) {
|
||||
if( regKey.toString().startsWith( NAMESPACE ) ) {
|
||||
final T entry = getRegistry().getValue( regKey );
|
||||
if( entry != null ) registryEntries.add( entry );
|
||||
}
|
||||
}
|
||||
if( registryEntries.isEmpty() ) {
|
||||
SpecialMobs.LOG.warn( "Namespace entry for {} \"{}\" did not match anything in registry \"{}\"! Questionable entry: {}",
|
||||
FIELD == null ? "DEFAULT" : FIELD.getClass(), FIELD == null ? "DEFAULT" : FIELD.getKey(), getRegistry().getRegistryName(), NAMESPACE );
|
||||
}
|
||||
registryEntries = Collections.unmodifiableList( registryEntries );
|
||||
}
|
||||
return registryEntries;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package fathertoast.specialmobs.common.config.util.environment.biome;
|
||||
|
||||
import net.minecraft.world.biome.Biome;
|
||||
|
||||
/**
|
||||
* Used to wrap the vanilla enum Biome.Category so that it can be safely used in configs.
|
||||
* The declared names should match the string passed into vanilla enums' constructors so that both enums serialize identically.
|
||||
*/
|
||||
public enum BiomeCategory {
|
||||
NONE( Biome.Category.NONE ),
|
||||
TAIGA( Biome.Category.TAIGA ),
|
||||
EXTREME_HILLS( Biome.Category.EXTREME_HILLS ),
|
||||
JUNGLE( Biome.Category.JUNGLE ),
|
||||
MESA( Biome.Category.MESA ),
|
||||
PLAINS( Biome.Category.PLAINS ),
|
||||
SAVANNA( Biome.Category.SAVANNA ),
|
||||
ICY( Biome.Category.ICY ),
|
||||
THE_END( Biome.Category.THEEND ),
|
||||
BEACH( Biome.Category.BEACH ),
|
||||
FOREST( Biome.Category.FOREST ),
|
||||
OCEAN( Biome.Category.OCEAN ),
|
||||
DESERT( Biome.Category.DESERT ),
|
||||
RIVER( Biome.Category.RIVER ),
|
||||
SWAMP( Biome.Category.SWAMP ),
|
||||
MUSHROOM( Biome.Category.MUSHROOM ),
|
||||
NETHER( Biome.Category.NETHER );
|
||||
|
||||
public final Biome.Category BASE;
|
||||
|
||||
BiomeCategory( Biome.Category base ) { BASE = base; }
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package fathertoast.specialmobs.common.config.util.environment.biome;
|
||||
|
||||
import fathertoast.specialmobs.common.config.field.AbstractConfigField;
|
||||
import fathertoast.specialmobs.common.config.field.EnvironmentListField;
|
||||
import fathertoast.specialmobs.common.config.util.environment.EnumEnvironment;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class BiomeCategoryEnvironment extends EnumEnvironment<BiomeCategory> {
|
||||
|
||||
public BiomeCategoryEnvironment( BiomeCategory value, boolean invert ) { super( value, invert ); }
|
||||
|
||||
public BiomeCategoryEnvironment( AbstractConfigField field, String line ) { super( field, line, BiomeCategory.values() ); }
|
||||
|
||||
/** @return The string name of this environment, as it would appear in a config file. */
|
||||
@Override
|
||||
public String name() { return EnvironmentListField.ENV_BIOME_CATEGORY; }
|
||||
|
||||
/** @return Returns true if this environment matches the provided environment. */
|
||||
@Override
|
||||
public boolean matches( World world, @Nullable BlockPos pos ) {
|
||||
return (pos != null && VALUE.BASE.equals( world.getBiome( pos ).getBiomeCategory() )) != INVERT;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package fathertoast.specialmobs.common.config.util.environment.biome;
|
||||
|
||||
import fathertoast.specialmobs.common.config.field.AbstractConfigField;
|
||||
import fathertoast.specialmobs.common.config.field.EnvironmentListField;
|
||||
import fathertoast.specialmobs.common.config.util.environment.DynamicRegistryEnvironment;
|
||||
import net.minecraft.util.RegistryKey;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.registry.Registry;
|
||||
import net.minecraft.world.biome.Biome;
|
||||
import net.minecraft.world.server.ServerWorld;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class BiomeEnvironment extends DynamicRegistryEnvironment<Biome> {
|
||||
|
||||
public BiomeEnvironment( RegistryKey<Biome> biome, boolean invert ) { super( biome.getRegistryName(), invert ); }
|
||||
|
||||
public BiomeEnvironment( AbstractConfigField field, String line ) { super( field, line ); }
|
||||
|
||||
/** @return The string name of this environment, as it would appear in a config file. */
|
||||
@Override
|
||||
public String name() { return EnvironmentListField.ENV_BIOME; }
|
||||
|
||||
/** @return The registry used. */
|
||||
@Override
|
||||
public RegistryKey<Registry<Biome>> getRegistry() { return Registry.BIOME_REGISTRY; }
|
||||
|
||||
/** @return Returns true if this environment matches the provided environment. */
|
||||
@Override
|
||||
public boolean matches( ServerWorld world, @Nullable BlockPos pos ) {
|
||||
final Biome entry = getRegistryEntry( world );
|
||||
return (entry != null && pos != null && entry.equals( world.getBiome( pos ) )) != INVERT;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package fathertoast.specialmobs.common.config.util.environment.biome;
|
||||
|
||||
import fathertoast.specialmobs.common.config.field.AbstractConfigField;
|
||||
import fathertoast.specialmobs.common.config.field.EnvironmentListField;
|
||||
import fathertoast.specialmobs.common.config.util.environment.DynamicRegistryGroupEnvironment;
|
||||
import net.minecraft.util.RegistryKey;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.registry.Registry;
|
||||
import net.minecraft.world.biome.Biome;
|
||||
import net.minecraft.world.server.ServerWorld;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.List;
|
||||
|
||||
public class BiomeGroupEnvironment extends DynamicRegistryGroupEnvironment<Biome> {
|
||||
|
||||
public BiomeGroupEnvironment( RegistryKey<Biome> biome, boolean invert ) { this( biome.getRegistryName(), invert ); }
|
||||
|
||||
public BiomeGroupEnvironment( ResourceLocation regKey, boolean invert ) { super( regKey, invert ); }
|
||||
|
||||
public BiomeGroupEnvironment( AbstractConfigField field, String line ) { super( field, line ); }
|
||||
|
||||
/** @return The string name of this environment, as it would appear in a config file. */
|
||||
@Override
|
||||
public String name() { return EnvironmentListField.ENV_BIOME; }
|
||||
|
||||
/** @return The registry used. */
|
||||
@Override
|
||||
public RegistryKey<Registry<Biome>> getRegistry() { return Registry.BIOME_REGISTRY; }
|
||||
|
||||
/** @return Returns true if this environment matches the provided environment. */
|
||||
@Override
|
||||
public final boolean matches( ServerWorld world, @Nullable BlockPos pos ) {
|
||||
final Biome target = pos == null ? null : world.getBiome( pos );
|
||||
if( target != null ) {
|
||||
final List<Biome> entries = getRegistryEntries( world );
|
||||
for( Biome entry : entries ) {
|
||||
if( entry.equals( target ) ) return !INVERT;
|
||||
}
|
||||
}
|
||||
return INVERT;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package fathertoast.specialmobs.common.config.util.environment.biome;
|
||||
|
||||
import fathertoast.specialmobs.common.config.field.AbstractConfigField;
|
||||
import fathertoast.specialmobs.common.config.field.EnvironmentListField;
|
||||
import fathertoast.specialmobs.common.config.util.environment.ComparisonOperator;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class BiomeTemperatureEnvironment extends TemperatureEnvironment {
|
||||
|
||||
public BiomeTemperatureEnvironment( boolean freezing ) { super( freezing ); }
|
||||
|
||||
public BiomeTemperatureEnvironment( ComparisonOperator op, float value ) { super( op, value ); }
|
||||
|
||||
public BiomeTemperatureEnvironment( AbstractConfigField field, String line ) { super( field, line ); }
|
||||
|
||||
/** @return The string name of this environment, as it would appear in a config file. */
|
||||
@Override
|
||||
public String name() { return EnvironmentListField.ENV_BIOME_TEMPERATURE; }
|
||||
|
||||
/** @return Returns the actual value to compare, or Float.NaN if there isn't enough information. */
|
||||
@Override
|
||||
public float getActual( World world, @Nullable BlockPos pos ) {
|
||||
return pos == null ? Float.NaN : world.getBiome( pos ).getBaseTemperature();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package fathertoast.specialmobs.common.config.util.environment.biome;
|
||||
|
||||
import fathertoast.specialmobs.common.config.field.AbstractConfigField;
|
||||
import fathertoast.specialmobs.common.config.field.EnvironmentListField;
|
||||
import fathertoast.specialmobs.common.config.util.environment.CompareFloatEnvironment;
|
||||
import fathertoast.specialmobs.common.config.util.environment.ComparisonOperator;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.biome.Biome;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class RainfallEnvironment extends CompareFloatEnvironment {
|
||||
|
||||
public RainfallEnvironment( ComparisonOperator op, float value ) { super( op, value ); }
|
||||
|
||||
public RainfallEnvironment( AbstractConfigField field, String line ) { super( field, line ); }
|
||||
|
||||
/** @return The string name of this environment, as it would appear in a config file. */
|
||||
@Override
|
||||
public String name() { return EnvironmentListField.ENV_RAINFALL; }
|
||||
|
||||
/** @return Returns true if this environment matches the provided environment. */
|
||||
@Override
|
||||
public boolean matches( World world, @Nullable BlockPos pos ) {
|
||||
// Handle the special case of no rainfall
|
||||
if( COMPARATOR == ComparisonOperator.EQUAL_TO && VALUE == 0.0F )
|
||||
return pos != null && world.getBiome( pos ).getPrecipitation() == Biome.RainType.NONE;
|
||||
if( COMPARATOR == ComparisonOperator.NOT_EQUAL_TO && VALUE == 0.0F )
|
||||
return pos != null && world.getBiome( pos ).getPrecipitation() != Biome.RainType.NONE;
|
||||
return super.matches( world, pos );
|
||||
}
|
||||
|
||||
/** @return Returns the actual value to compare, or Float.NaN if there isn't enough information. */
|
||||
@Override
|
||||
public float getActual( World world, @Nullable BlockPos pos ) {
|
||||
return pos == null ? Float.NaN : world.getBiome( pos ).getDownfall();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package fathertoast.specialmobs.common.config.util.environment.biome;
|
||||
|
||||
import fathertoast.specialmobs.common.config.field.AbstractConfigField;
|
||||
import fathertoast.specialmobs.common.config.field.EnvironmentListField;
|
||||
import fathertoast.specialmobs.common.config.util.environment.CompareFloatEnvironment;
|
||||
import fathertoast.specialmobs.common.config.util.environment.ComparisonOperator;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class TemperatureEnvironment extends CompareFloatEnvironment {
|
||||
|
||||
public static final String FREEZING = "freezing";
|
||||
public static final float FREEZING_POINT = 0.15F;
|
||||
|
||||
public static String handleTempInput( String line ) {
|
||||
if( line.equalsIgnoreCase( FREEZING ) )
|
||||
return ComparisonOperator.LESS_THAN + " " + FREEZING_POINT;
|
||||
if( line.equalsIgnoreCase( "!" + FREEZING ) )
|
||||
return ComparisonOperator.LESS_THAN.invert() + " " + FREEZING_POINT;
|
||||
return line;
|
||||
}
|
||||
|
||||
public TemperatureEnvironment( boolean freezing ) {
|
||||
this( ComparisonOperator.LESS_THAN.invert( !freezing ), FREEZING_POINT );
|
||||
}
|
||||
|
||||
public TemperatureEnvironment( ComparisonOperator op, float value ) { super( op, value ); }
|
||||
|
||||
public TemperatureEnvironment( AbstractConfigField field, String line ) { super( field, handleTempInput( line ) ); }
|
||||
|
||||
/** @return The string name of this environment, as it would appear in a config file. */
|
||||
@Override
|
||||
public String name() { return EnvironmentListField.ENV_TEMPERATURE; }
|
||||
|
||||
/** @return The string value of this environment, as it would appear in a config file. */
|
||||
@Override
|
||||
public String value() {
|
||||
if( COMPARATOR == ComparisonOperator.LESS_THAN && VALUE == FREEZING_POINT ) return FREEZING;
|
||||
if( COMPARATOR == ComparisonOperator.LESS_THAN.invert() && VALUE == FREEZING_POINT ) return "!" + FREEZING;
|
||||
return super.value();
|
||||
}
|
||||
|
||||
/** @return Returns the actual value to compare, or Float.NaN if there isn't enough information. */
|
||||
@Override
|
||||
public float getActual( World world, @Nullable BlockPos pos ) {
|
||||
return pos == null ? Float.NaN : world.getBiome( pos ).getTemperature( pos );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package fathertoast.specialmobs.common.config.util.environment.biome;
|
||||
|
||||
import fathertoast.specialmobs.common.config.field.AbstractConfigField;
|
||||
import fathertoast.specialmobs.common.config.field.EnvironmentListField;
|
||||
import fathertoast.specialmobs.common.config.util.environment.CompareFloatEnvironment;
|
||||
import fathertoast.specialmobs.common.config.util.environment.ComparisonOperator;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class TerrainDepthEnvironment extends CompareFloatEnvironment {
|
||||
|
||||
public TerrainDepthEnvironment( ComparisonOperator op, float value ) { super( op, value ); }
|
||||
|
||||
public TerrainDepthEnvironment( AbstractConfigField field, String line ) { super( field, line ); }
|
||||
|
||||
/** @return The string name of this environment, as it would appear in a config file. */
|
||||
@Override
|
||||
public String name() { return EnvironmentListField.ENV_TERRAIN_DEPTH; }
|
||||
|
||||
/** @return Returns the actual value to compare, or Float.NaN if there isn't enough information. */
|
||||
@Override
|
||||
public float getActual( World world, @Nullable BlockPos pos ) {
|
||||
return pos == null ? Float.NaN : world.getBiome( pos ).getDepth();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package fathertoast.specialmobs.common.config.util.environment.biome;
|
||||
|
||||
import fathertoast.specialmobs.common.config.field.AbstractConfigField;
|
||||
import fathertoast.specialmobs.common.config.field.EnvironmentListField;
|
||||
import fathertoast.specialmobs.common.config.util.environment.CompareFloatEnvironment;
|
||||
import fathertoast.specialmobs.common.config.util.environment.ComparisonOperator;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class TerrainScaleEnvironment extends CompareFloatEnvironment {
|
||||
|
||||
public TerrainScaleEnvironment( ComparisonOperator op, float value ) { super( op, value ); }
|
||||
|
||||
public TerrainScaleEnvironment( AbstractConfigField field, String line ) { super( field, line ); }
|
||||
|
||||
/** @return The string name of this environment, as it would appear in a config file. */
|
||||
@Override
|
||||
public String name() { return EnvironmentListField.ENV_TERRAIN_SCALE; }
|
||||
|
||||
/** @return Returns the actual value to compare, or Float.NaN if there isn't enough information. */
|
||||
@Override
|
||||
public float getActual( World world, @Nullable BlockPos pos ) {
|
||||
return pos == null ? Float.NaN : world.getBiome( pos ).getScale();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
@MethodsReturnNonnullByDefault
|
||||
@ParametersAreNonnullByDefault
|
||||
package fathertoast.specialmobs.common.config.util.environment.biome;
|
||||
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
|
@ -0,0 +1,49 @@
|
|||
package fathertoast.specialmobs.common.config.util.environment.dimension;
|
||||
|
||||
import fathertoast.specialmobs.common.config.field.AbstractConfigField;
|
||||
import fathertoast.specialmobs.common.config.field.EnvironmentListField;
|
||||
import fathertoast.specialmobs.common.config.util.environment.EnumEnvironment;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.DimensionType;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class DimensionPropertyEnvironment extends EnumEnvironment<DimensionPropertyEnvironment.Value> {
|
||||
/**
|
||||
* Represents all boolean values defined by dimension type, named to match data pack format.
|
||||
*
|
||||
* @see <a href="https://minecraft.fandom.com/wiki/Custom_dimension#Syntax">Data pack format (Minecraft Wiki)</a>
|
||||
*/
|
||||
public enum Value {
|
||||
@SuppressWarnings( "SpellCheckingInspection" )
|
||||
ULTRAWARM( DimensionType::ultraWarm ),
|
||||
NATURAL( DimensionType::natural ),
|
||||
HAS_SKYLIGHT( DimensionType::hasSkyLight ),
|
||||
HAS_CEILING( DimensionType::hasCeiling ),
|
||||
FIXED_TIME( DimensionType::hasFixedTime ),
|
||||
PIGLIN_SAFE( DimensionType::piglinSafe ),
|
||||
BED_WORKS( DimensionType::bedWorks ),
|
||||
RESPAWN_ANCHOR_WORKS( DimensionType::respawnAnchorWorks ),
|
||||
HAS_RAIDS( DimensionType::hasRaids );
|
||||
|
||||
private final Function<DimensionType, Boolean> SUPPLIER;
|
||||
|
||||
Value( Function<DimensionType, Boolean> supplier ) { SUPPLIER = supplier; }
|
||||
|
||||
public boolean of( DimensionType dimType ) { return SUPPLIER.apply( dimType ); }
|
||||
}
|
||||
|
||||
public DimensionPropertyEnvironment( Value value, boolean invert ) { super( value, invert ); }
|
||||
|
||||
public DimensionPropertyEnvironment( AbstractConfigField field, String line ) { super( field, line, Value.values() ); }
|
||||
|
||||
/** @return The string name of this environment, as it would appear in a config file. */
|
||||
@Override
|
||||
public String name() { return EnvironmentListField.ENV_DIMENSION_PROPERTY; }
|
||||
|
||||
/** @return Returns true if this environment matches the provided environment. */
|
||||
@Override
|
||||
public boolean matches( World world, @Nullable BlockPos pos ) { return VALUE.of( world.dimensionType() ) != INVERT; }
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package fathertoast.specialmobs.common.config.util.environment.dimension;
|
||||
|
||||
import fathertoast.specialmobs.common.config.field.AbstractConfigField;
|
||||
import fathertoast.specialmobs.common.config.field.EnvironmentListField;
|
||||
import fathertoast.specialmobs.common.config.util.environment.DynamicRegistryEnvironment;
|
||||
import net.minecraft.util.RegistryKey;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.registry.Registry;
|
||||
import net.minecraft.world.DimensionType;
|
||||
import net.minecraft.world.server.ServerWorld;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class DimensionTypeEnvironment extends DynamicRegistryEnvironment<DimensionType> {
|
||||
|
||||
public DimensionTypeEnvironment( RegistryKey<DimensionType> dimType, boolean invert ) { super( dimType.getRegistryName(), invert ); }
|
||||
|
||||
public DimensionTypeEnvironment( AbstractConfigField field, String line ) { super( field, line ); }
|
||||
|
||||
/** @return The string name of this environment, as it would appear in a config file. */
|
||||
@Override
|
||||
public String name() { return EnvironmentListField.ENV_DIMENSION_TYPE; }
|
||||
|
||||
/** @return The registry used. */
|
||||
@Override
|
||||
public RegistryKey<Registry<DimensionType>> getRegistry() { return Registry.DIMENSION_TYPE_REGISTRY; }
|
||||
|
||||
/** @return Returns true if this environment matches the provided environment. */
|
||||
@Override
|
||||
public boolean matches( ServerWorld world, @Nullable BlockPos pos ) {
|
||||
final DimensionType entry = getRegistryEntry( world );
|
||||
return (entry != null && entry.equals( world.dimensionType() )) != INVERT;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package fathertoast.specialmobs.common.config.util.environment.dimension;
|
||||
|
||||
import fathertoast.specialmobs.common.config.field.AbstractConfigField;
|
||||
import fathertoast.specialmobs.common.config.field.EnvironmentListField;
|
||||
import fathertoast.specialmobs.common.config.util.environment.DynamicRegistryGroupEnvironment;
|
||||
import net.minecraft.util.RegistryKey;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.registry.Registry;
|
||||
import net.minecraft.world.DimensionType;
|
||||
import net.minecraft.world.server.ServerWorld;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.List;
|
||||
|
||||
public class DimensionTypeGroupEnvironment extends DynamicRegistryGroupEnvironment<DimensionType> {
|
||||
|
||||
public DimensionTypeGroupEnvironment( RegistryKey<DimensionType> dimType, boolean invert ) { this( dimType.getRegistryName(), invert ); }
|
||||
|
||||
public DimensionTypeGroupEnvironment( ResourceLocation regKey, boolean invert ) { super( regKey, invert ); }
|
||||
|
||||
public DimensionTypeGroupEnvironment( AbstractConfigField field, String line ) { super( field, line ); }
|
||||
|
||||
/** @return The string name of this environment, as it would appear in a config file. */
|
||||
@Override
|
||||
public String name() { return EnvironmentListField.ENV_DIMENSION_TYPE; }
|
||||
|
||||
/** @return The registry used. */
|
||||
@Override
|
||||
public RegistryKey<Registry<DimensionType>> getRegistry() { return Registry.DIMENSION_TYPE_REGISTRY; }
|
||||
|
||||
/** @return Returns true if this environment matches the provided environment. */
|
||||
@Override
|
||||
public final boolean matches( ServerWorld world, @Nullable BlockPos pos ) {
|
||||
final DimensionType target = world.dimensionType();
|
||||
final List<DimensionType> entries = getRegistryEntries( world );
|
||||
for( DimensionType entry : entries ) {
|
||||
if( entry.equals( target ) ) return !INVERT;
|
||||
}
|
||||
return INVERT;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
@MethodsReturnNonnullByDefault
|
||||
@ParametersAreNonnullByDefault
|
||||
package fathertoast.specialmobs.common.config.util.environment.dimension;
|
||||
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
|
@ -0,0 +1,7 @@
|
|||
@MethodsReturnNonnullByDefault
|
||||
@ParametersAreNonnullByDefault
|
||||
package fathertoast.specialmobs.common.config.util.environment;
|
||||
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
|
@ -0,0 +1,45 @@
|
|||
package fathertoast.specialmobs.common.config.util.environment.position;
|
||||
|
||||
import fathertoast.specialmobs.common.config.field.AbstractConfigField;
|
||||
import fathertoast.specialmobs.common.config.field.EnvironmentListField;
|
||||
import fathertoast.specialmobs.common.config.util.environment.EnumEnvironment;
|
||||
import net.minecraft.tags.FluidTags;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.server.ServerWorld;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
public class PositionEnvironment extends EnumEnvironment<PositionEnvironment.Value> {
|
||||
|
||||
public enum Value {
|
||||
CAN_SEE_SKY( ( world, pos ) -> pos != null && world.canSeeSky( pos ) ),
|
||||
IS_IN_VILLAGE( ( world, pos ) -> pos != null && world instanceof ServerWorld && ((ServerWorld) world).isVillage( pos ) ),
|
||||
IS_NEAR_VILLAGE( ( world, pos ) -> pos != null && world instanceof ServerWorld &&
|
||||
((ServerWorld) world).isCloseToVillage( pos, 3 ) ),
|
||||
IS_NEAR_RAID( ( world, pos ) -> pos != null && world instanceof ServerWorld && ((ServerWorld) world).isRaided( pos ) ),
|
||||
IS_IN_WATER( ( world, pos ) -> pos != null && world.getFluidState( pos ).is( FluidTags.WATER ) ),
|
||||
IS_IN_LAVA( ( world, pos ) -> pos != null && world.getFluidState( pos ).is( FluidTags.LAVA ) ),
|
||||
IS_IN_FLUID( ( world, pos ) -> pos != null && !world.getFluidState( pos ).isEmpty() ),
|
||||
HAS_REDSTONE_POWER( ( world, pos ) -> pos != null && world.getDirectSignalTo( pos ) > 0 );
|
||||
|
||||
private final BiFunction<World, BlockPos, Boolean> SUPPLIER;
|
||||
|
||||
Value( BiFunction<World, BlockPos, Boolean> supplier ) { SUPPLIER = supplier; }
|
||||
|
||||
public boolean of( World world, @Nullable BlockPos pos ) { return SUPPLIER.apply( world, pos ); }
|
||||
}
|
||||
|
||||
public PositionEnvironment( Value value, boolean invert ) { super( value, invert ); }
|
||||
|
||||
public PositionEnvironment( AbstractConfigField field, String line ) { super( field, line, Value.values() ); }
|
||||
|
||||
/** @return The string name of this environment, as it would appear in a config file. */
|
||||
@Override
|
||||
public String name() { return EnvironmentListField.ENV_POSITION; }
|
||||
|
||||
/** @return Returns true if this environment matches the provided environment. */
|
||||
@Override
|
||||
public boolean matches( World world, @Nullable BlockPos pos ) { return VALUE.of( world, pos ) != INVERT; }
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package fathertoast.specialmobs.common.config.util.environment.position;
|
||||
|
||||
import fathertoast.specialmobs.common.config.field.AbstractConfigField;
|
||||
import fathertoast.specialmobs.common.config.field.EnvironmentListField;
|
||||
import fathertoast.specialmobs.common.config.util.environment.RegistryEnvironment;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.gen.feature.structure.Structure;
|
||||
import net.minecraft.world.server.ServerWorld;
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
import net.minecraftforge.registries.IForgeRegistry;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class StructureEnvironment extends RegistryEnvironment<Structure<?>> {
|
||||
|
||||
public StructureEnvironment( Structure<?> structure, boolean invert ) { super( structure, invert ); }
|
||||
|
||||
public StructureEnvironment( AbstractConfigField field, String line ) { super( field, line ); }
|
||||
|
||||
/** @return The string name of this environment, as it would appear in a config file. */
|
||||
@Override
|
||||
public String name() { return EnvironmentListField.ENV_STRUCTURE; }
|
||||
|
||||
/** @return The registry used. */
|
||||
@Override
|
||||
public IForgeRegistry<Structure<?>> getRegistry() { return ForgeRegistries.STRUCTURE_FEATURES; }
|
||||
|
||||
/** @return Returns true if this environment matches the provided environment. */
|
||||
@Override
|
||||
public boolean matches( World world, @Nullable BlockPos pos ) {
|
||||
final Structure<?> entry = getRegistryEntry();
|
||||
return (entry != null && pos != null && world instanceof ServerWorld &&
|
||||
((ServerWorld) world).structureFeatureManager().getStructureAt( pos, false, entry ).isValid()) != INVERT;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
package fathertoast.specialmobs.common.config.util.environment.position;
|
||||
|
||||
import fathertoast.specialmobs.common.config.field.AbstractConfigField;
|
||||
import fathertoast.specialmobs.common.config.field.EnvironmentListField;
|
||||
import fathertoast.specialmobs.common.config.util.environment.RegistryGroupEnvironment;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.gen.feature.structure.Structure;
|
||||
import net.minecraft.world.gen.feature.structure.StructureManager;
|
||||
import net.minecraft.world.server.ServerWorld;
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
import net.minecraftforge.registries.IForgeRegistry;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.List;
|
||||
|
||||
public class StructureGroupEnvironment extends RegistryGroupEnvironment<Structure<?>> {
|
||||
|
||||
public StructureGroupEnvironment( Structure<?> structure, boolean invert ) { super( structure, invert ); }
|
||||
|
||||
public StructureGroupEnvironment( ResourceLocation regKey, boolean invert ) { super( regKey, invert ); }
|
||||
|
||||
public StructureGroupEnvironment( AbstractConfigField field, String line ) { super( field, line ); }
|
||||
|
||||
/** @return The string name of this environment, as it would appear in a config file. */
|
||||
@Override
|
||||
public String name() { return EnvironmentListField.ENV_STRUCTURE; }
|
||||
|
||||
/** @return The registry used. */
|
||||
@Override
|
||||
public IForgeRegistry<Structure<?>> getRegistry() { return ForgeRegistries.STRUCTURE_FEATURES; }
|
||||
|
||||
/** @return Returns true if this environment matches the provided environment. */
|
||||
@Override
|
||||
public final boolean matches( World world, @Nullable BlockPos pos ) {
|
||||
final StructureManager structureManager = pos != null && world instanceof ServerWorld ?
|
||||
((ServerWorld) world).structureFeatureManager() : null;
|
||||
if( structureManager != null ) {
|
||||
final List<Structure<?>> entries = getRegistryEntries();
|
||||
for( Structure<?> entry : entries ) {
|
||||
if( structureManager.getStructureAt( pos, false, entry ).isValid() ) return !INVERT;
|
||||
}
|
||||
}
|
||||
return INVERT;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package fathertoast.specialmobs.common.config.util.environment.position;
|
||||
|
||||
import fathertoast.specialmobs.common.config.field.AbstractConfigField;
|
||||
import fathertoast.specialmobs.common.config.field.EnvironmentListField;
|
||||
import fathertoast.specialmobs.common.config.util.environment.CompareIntEnvironment;
|
||||
import fathertoast.specialmobs.common.config.util.environment.ComparisonOperator;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class YEnvironment extends CompareIntEnvironment {
|
||||
|
||||
public YEnvironment( ComparisonOperator op, int value ) { super( op, value ); }
|
||||
|
||||
public YEnvironment( AbstractConfigField field, String line ) { super( field, line ); }
|
||||
|
||||
/** @return The string name of this environment, as it would appear in a config file. */
|
||||
@Override
|
||||
public String name() { return EnvironmentListField.ENV_Y; }
|
||||
|
||||
/** @return Returns the actual value to compare, or null if there isn't enough information. */
|
||||
@Override
|
||||
public Integer getActual( World world, @Nullable BlockPos pos ) { return pos == null ? null : pos.getY(); }
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package fathertoast.specialmobs.common.config.util.environment.position;
|
||||
|
||||
import fathertoast.specialmobs.common.config.field.AbstractConfigField;
|
||||
import fathertoast.specialmobs.common.config.field.EnvironmentListField;
|
||||
import fathertoast.specialmobs.common.config.util.environment.CompareIntEnvironment;
|
||||
import fathertoast.specialmobs.common.config.util.environment.ComparisonOperator;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class YFromSeaEnvironment extends CompareIntEnvironment {
|
||||
|
||||
public YFromSeaEnvironment( ComparisonOperator op, int value ) { super( op, value ); }
|
||||
|
||||
public YFromSeaEnvironment( AbstractConfigField field, String line ) { super( field, line ); }
|
||||
|
||||
/** @return The string name of this environment, as it would appear in a config file. */
|
||||
@Override
|
||||
public String name() { return EnvironmentListField.ENV_Y_FROM_SEA; }
|
||||
|
||||
/** @return Returns the actual value to compare, or null if there isn't enough information. */
|
||||
@Override
|
||||
public Integer getActual( World world, @Nullable BlockPos pos ) { return pos == null ? null : pos.getY() - world.getSeaLevel(); }
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
@MethodsReturnNonnullByDefault
|
||||
@ParametersAreNonnullByDefault
|
||||
package fathertoast.specialmobs.common.config.util.environment.position;
|
||||
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue