Merge branch '1.20.1' into 1.20.2

This commit is contained in:
Sollace 2024-03-20 21:41:51 +00:00
commit c608a33aea
No known key found for this signature in database
GPG key ID: E52FACE7B5C773DB
1296 changed files with 3436 additions and 16506 deletions

1
.gitignore vendored
View file

@ -3,6 +3,7 @@
bin/
build/
run/
generated/
.classpath
.project
*.launch

View file

@ -27,7 +27,18 @@ archivesBaseName = project.name
loom {
mixin.defaultRefmapName = 'unicopia.mixin.refmap.json'
accessWidenerPath = file('src/main/resources/unicopia.aw')
runs {
datagen {
server()
name "Data Generation"
vmArg "-Dfabric-api.datagen"
vmArg "-Dfabric-api.datagen.modid=unicopia"
vmArg "-Dfabric-api.datagen.output-dir=${file("src/main/generated")}"
runDir "build/datagen"
}
}
}
//assemble.dependsOn(runDatagen)
reckon {
scopeFromProp()
@ -98,6 +109,14 @@ dependencies {
}
}
sourceSets {
main {
resources {
srcDirs += [ "src/main/generated" ]
}
}
}
processResources {
inputs.property "version", project.version.toString()

View file

@ -35,11 +35,13 @@ public interface EquinePredicates {
Predicate<Entity> IS_CASTER = e -> !e.isRemoved() && (e instanceof Caster || IS_PLAYER.test(e));
Predicate<Entity> IS_PLACED_SPELL = e -> e instanceof Caster && !e.isRemoved();
Predicate<Entity> IS_MAGIC_IMMUNE = e -> (e instanceof MagicImmune || !(e instanceof LivingEntity))
Predicate<Entity> IS_MAGIC_IMMUNE = EntityPredicates.VALID_ENTITY.negate()
.or(EntityPredicates.EXCEPT_CREATIVE_OR_SPECTATOR.negate()
.or(e -> (e instanceof MagicImmune || !(e instanceof LivingEntity))
&& !(e instanceof ItemEntity)
&& !(e instanceof ExperienceOrbEntity)
&& !(e instanceof BoatEntity)
&& !(e instanceof ProjectileEntity);
&& !(e instanceof ProjectileEntity)));
Predicate<Entity> EXCEPT_MAGIC_IMMUNE = IS_MAGIC_IMMUNE.negate();
Predicate<Entity> VALID_LIVING_AND_NOT_MAGIC_IMMUNE = EntityPredicates.VALID_LIVING_ENTITY.and(EXCEPT_MAGIC_IMMUNE);

View file

@ -0,0 +1,38 @@
package com.minelittlepony.unicopia;
import net.minecraft.block.Block;
import net.minecraft.item.Item;
import net.minecraft.registry.RegistryKeys;
import net.minecraft.registry.tag.TagKey;
import net.minecraft.util.Identifier;
public interface UConventionalTags {
TagKey<Item> APPLES = item("apples");
TagKey<Item> ACORNS = item("acorns");
TagKey<Item> PINECONES = item("pinecones");
TagKey<Item> PINEAPPLES = item("pineapples");
TagKey<Item> BANANAS = item("bananas");
TagKey<Item> STICKS = item("sticks");
TagKey<Item> SEEDS = item("seeds");
TagKey<Item> GRAIN = item("grain");
TagKey<Item> NUTS = item("nuts");
TagKey<Item> MUSHROOMS = item("mushrooms");
TagKey<Item> MUFFINS = item("muffins");
TagKey<Item> MANGOES = item("mangoes");
TagKey<Item> OEATMEALS = item("oatmeals");
TagKey<Item> FRUITS = item("fruits");
TagKey<Item> COOKED_FISH = item("cooked_fish");
TagKey<Item> CROPS_PEANUTS = item("crops/peanuts");
TagKey<Item> TOOL_KNIVES = item("tools/knives");
static TagKey<Item> item(String name) {
return TagKey.of(RegistryKeys.ITEM, new Identifier("c", name));
}
static TagKey<Block> block(String name) {
return TagKey.of(RegistryKeys.BLOCK, new Identifier("c", name));
}
}

View file

@ -12,7 +12,7 @@ import static net.minecraft.sound.SoundEvents.*;
public interface USounds {
SoundEvent ENTITY_GENERIC_BUTTER_FINGERS = BLOCK_HONEY_BLOCK_SLIDE;
SoundEvent ENTITY_PLAYER_CORRUPTION = PARTICLE_SOUL_ESCAPE;
SoundEvent ENTITY_PLAYER_CORRUPTION = register("entity.player.corrupt");
SoundEvent ENTITY_PLAYER_BATPONY_SCREECH = register("entity.player.batpony.screech");
SoundEvent ENTITY_PLAYER_HIPPOGRIFF_SCREECH = register("entity.player.hippogriff.screech");
SoundEvent ENTITY_PLAYER_HIPPOGRIFF_PECK = ENTITY_CHICKEN_STEP;

View file

@ -11,7 +11,6 @@ import net.minecraft.util.Identifier;
import net.minecraft.world.dimension.DimensionType;
public interface UTags {
TagKey<Item> APPLES = item("apples");
TagKey<Item> FRESH_APPLES = item("fresh_apples");
TagKey<Item> FALLS_SLOWLY = item("falls_slowly");
@ -27,16 +26,19 @@ public interface UTags {
TagKey<Item> IS_DELIVERED_AGGRESSIVELY = item("is_delivered_aggressively");
TagKey<Item> FLOATS_ON_CLOUDS = item("floats_on_clouds");
TagKey<Item> COOLS_OFF_KIRINS = item("cools_off_kirins");
TagKey<Item> LOOT_BUG_HIGH_VALUE_DROPS = item("loot_bug_high_value_drops");
TagKey<Item> SHELLS = item("food_types/shells");
TagKey<Item> POLEARMS = item("polearms");
TagKey<Item> HORSE_SHOES = item("horse_shoes");
TagKey<Item> APPLE_SEEDS = item("apple_seeds");
TagKey<Item> ACORNS = item("acorns");
TagKey<Item> BASKETS = item("baskets");
TagKey<Item> BADGES = item("badges");
TagKey<Item> BED_SHEETS = item("bed_sheets");
TagKey<Item> CLOUD_JARS = item("cloud_jars");
TagKey<Block> GLASS_PANES = block("glass_panes");
TagKey<Block> GLASS_BLOCKS = block("glass_blocks");
TagKey<Block> FRAGILE = block("fragile");
TagKey<Block> INTERESTING = block("interesting");
TagKey<Block> CATAPULT_IMMUNE = block("catapult_immune");
@ -57,6 +59,28 @@ public interface UTags {
TagKey<DimensionType> HAS_NO_ATMOSPHERE = dimension("has_no_atmosphere");
interface Items {
TagKey<Item> ZAP_LOGS = item("zap_logs");
TagKey<Item> WAXED_ZAP_LOGS = item("waxed_zap_logs");
TagKey<Item> PALM_LOGS = item("palm_logs");
TagKey<Item> CLOUD_BEDS = item("cloud_beds");
TagKey<Item> CLOUD_SLABS = item("cloud_slabs");
TagKey<Item> CLOUD_STAIRS = item("cloud_stairs");
TagKey<Item> CLOUD_BLOCKS = item("cloud_blocks");
TagKey<Item> CHITIN_BLOCKS = item("chitin_blocks");
}
interface Blocks {
TagKey<Block> ZAP_LOGS = block("zap_logs");
TagKey<Block> WAXED_ZAP_LOGS = block("waxed_zap_logs");
TagKey<Block> PALM_LOGS = block("palm_logs");
TagKey<Block> CLOUD_BEDS = block("cloud_beds");
TagKey<Block> CLOUD_SLABS = block("cloud_slabs");
TagKey<Block> CLOUD_STAIRS = block("cloud_stairs");
TagKey<Block> CLOUD_BLOCKS = block("cloud_blocks");
TagKey<Block> CHITIN_BLOCKS = block("chitin_blocks");
}
static TagKey<Item> item(String name) {
return TagKey.of(RegistryKeys.ITEM, Unicopia.id(name));
}

View file

@ -19,7 +19,7 @@ public class TimeChangeAbility implements Ability<Rot> {
@Override
public boolean canUse(Race.Composite race) {
return Ability.super.canUse(race) || race.pseudo() == Race.UNICORN;
return canUse(race.physical()) || race.pseudo() == Race.UNICORN;
}
@Override

View file

@ -37,7 +37,7 @@ public class UnicornCastingAbility extends AbstractSpellCastingAbility {
@Override
public int getWarmupTime(Pony player) {
return 20;
return (int)(20 - Math.min(17F, player.getLevel().get() * 0.75F));
}
@Override

View file

@ -16,6 +16,9 @@ import com.minelittlepony.unicopia.particle.MagicParticleEffect;
import com.minelittlepony.unicopia.util.Trace;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.LeavesBlock;
import net.minecraft.block.PowderSnowBlock;
import net.minecraft.block.ShapeContext;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.PlayerEntity;
@ -48,12 +51,12 @@ public class UnicornTeleportAbility implements Ability<Pos> {
@Override
public int getWarmupTime(Pony player) {
return 20;
return (int)(20 - Math.min(17F, player.getLevel().get() * 0.75F));
}
@Override
public int getCooldownTime(Pony player) {
return 50;
return (int)(50 - Math.min(45F, player.getLevel().get() * 0.75F));
}
@Override
@ -78,8 +81,7 @@ public class UnicornTeleportAbility implements Ability<Pos> {
return Optional.empty();
}
int maxDistance = player.asEntity().isCreative() ? 1000 : 100;
int maxDistance = (int)((player.asEntity().isCreative() ? 1000 : 100) + (player.getLevel().get() * 0.25F));
World w = player.asWorld();
@ -87,10 +89,16 @@ public class UnicornTeleportAbility implements Ability<Pos> {
return trace.getBlockOrEntityPos().map(pos -> {
final BlockPos originalPos = pos;
boolean airAbove = enterable(w, pos.up()) && enterable(w, pos.up(2));
boolean originalPosHasSupport = exception(w, pos, player.asEntity());
boolean originalPosValid = enterable(w, pos.up()) && enterable(w, pos.up(2));
if (exception(w, pos, player.asEntity())) {
if (w.getBlockState(pos).isOf(Blocks.POWDER_SNOW) && !PowderSnowBlock.canWalkOnPowderSnow(player.asEntity())) {
return null;
}
if (originalPosHasSupport) {
final BlockPos p = pos;
// offset to adjacent
pos = trace.getSide().map(sideHit -> {
if (player.asEntity().isSneaking()) {
sideHit = sideHit.getOpposite();
@ -100,15 +108,19 @@ public class UnicornTeleportAbility implements Ability<Pos> {
}).orElse(pos);
}
if (enterable(w, pos.down())) {
pos = pos.down();
if (enterable(w, pos.down())) {
if (!airAbove) {
return null;
if (pos.getX() != originalPos.getX() || pos.getZ() != originalPos.getZ()) {
// check support
int steps = 0;
while (enterable(w, pos.down())) {
pos = pos.down();
if (++steps > 2) {
if (originalPosValid) {
pos = originalPos.up();
break;
} else {
return null;
}
}
pos = originalPos.up(2);
}
}
@ -162,11 +174,17 @@ public class UnicornTeleportAbility implements Ability<Pos> {
participant.getZ() - Math.floor(participant.getZ())
);
Vec3d dest = destination.vec().add(offset);
dest = new Vec3d(dest.x, getTargetYPosition(participant.getEntityWorld(), BlockPos.ofFloored(dest), ShapeContext.of(participant)), dest.z);
double yPos = getTargetYPosition(participant.getEntityWorld(), destination.pos(), ShapeContext.of(participant));
Vec3d dest = new Vec3d(
destination.x() + offset.getX(),
yPos,
destination.z() + offset.getZ()
);
participant.teleport(dest.x, dest.y, dest.z);
if (participant.getWorld().getBlockCollisions(participant, participant.getBoundingBox()).iterator().hasNext()) {
dest = destination.vec();
participant.teleport(dest.x, participant.getY(), dest.z);
}
teleporter.subtractEnergyCost(distance);
participant.fallDistance /= distance;
@ -183,7 +201,10 @@ public class UnicornTeleportAbility implements Ability<Pos> {
private boolean enterable(World w, BlockPos pos) {
BlockState state = w.getBlockState(pos);
return w.isAir(pos) || !state.isOpaque();
if (StatePredicate.isFluid(state) || state.getBlock() instanceof LeavesBlock) {
return false;
}
return w.isAir(pos) || !state.isOpaque() || !state.shouldSuffocate(w, pos);
}
private boolean exception(World w, BlockPos pos, PlayerEntity player) {

View file

@ -3,6 +3,7 @@ package com.minelittlepony.unicopia.ability.magic;
import java.util.UUID;
import java.util.function.Predicate;
import com.minelittlepony.unicopia.Affinity;
import com.minelittlepony.unicopia.ability.magic.spell.*;
import com.minelittlepony.unicopia.ability.magic.spell.effect.MimicSpell;
import com.minelittlepony.unicopia.ability.magic.spell.effect.ShieldSpell;
@ -21,6 +22,8 @@ public interface SpellPredicate<T extends Spell> extends Predicate<Spell> {
SpellPredicate<?> IS_NOT_PLACED = IS_PLACED.negate();
SpellPredicate<?> IS_VISIBLE = spell -> spell != null && !spell.isHidden();
SpellPredicate<?> IS_CORRUPTING = spell -> spell.getAffinity() == Affinity.BAD;
default <Q extends Spell> SpellPredicate<Q> and(SpellPredicate<Q> predicate) {
SpellPredicate<T> self = this;
return s -> self.test(s) && predicate.test(s);

View file

@ -9,7 +9,6 @@ import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.spell.effect.*;
import com.minelittlepony.unicopia.entity.damage.UDamageTypes;
import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.item.FriendshipBraceletItem;
import com.minelittlepony.unicopia.particle.OrientedBillboardParticleEffect;
import com.minelittlepony.unicopia.particle.ParticleSpawner;
import com.minelittlepony.unicopia.particle.TargetBoundParticleEffect;
@ -60,9 +59,7 @@ public class RainboomAbilitySpell extends AbstractSpell {
}
}
source.findAllEntitiesInRange(RADIUS)
.filter(e -> !FriendshipBraceletItem.isComrade(source, e))
.forEach(e -> {
source.findAllEntitiesInRange(RADIUS, e -> !source.isOwnerOrFriend(e)).forEach(e -> {
e.damage(source.damageOf(UDamageTypes.RAINBOOM, source), 6);
});
EFFECT_RANGE.translate(source.getOrigin()).getBlockPositions().forEach(pos -> {

View file

@ -7,11 +7,7 @@ import java.util.Optional;
import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType;
import com.minelittlepony.unicopia.entity.mob.UEntities;
import com.minelittlepony.unicopia.item.UItems;
import com.minelittlepony.unicopia.projectile.MagicProjectileEntity;
import net.minecraft.entity.Entity;
import com.minelittlepony.unicopia.projectile.MagicBeamEntity;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.world.World;
@ -43,7 +39,7 @@ public final class ThrowableSpell extends AbstractDelegatingSpell {
*
* Returns the resulting projectile entity for customization (or null if on the client).
*/
public Optional<MagicProjectileEntity> throwProjectile(Caster<?> caster) {
public Optional<MagicBeamEntity> throwProjectile(Caster<?> caster) {
return throwProjectile(caster, 1);
}
@ -52,33 +48,23 @@ public final class ThrowableSpell extends AbstractDelegatingSpell {
*
* Returns the resulting projectile entity for customization (or null if on the client).
*/
public Optional<MagicProjectileEntity> throwProjectile(Caster<?> caster, float divergance) {
public Optional<MagicBeamEntity> throwProjectile(Caster<?> caster, float divergance) {
World world = caster.asWorld();
Entity entity = caster.asEntity();
caster.playSound(USounds.SPELL_CAST_SHOOT, 0.7F, 0.4F / (world.random.nextFloat() * 0.4F + 0.8F));
if (caster.isClient()) {
return Optional.empty();
}
Spell s = spell.get().prepareForCast(caster, CastingMethod.STORED);
if (s == null) {
return Optional.empty();
}
return Optional.ofNullable(spell.get().prepareForCast(caster, CastingMethod.STORED)).map(s -> {
MagicBeamEntity projectile = new MagicBeamEntity(world, caster.asEntity(), divergance, s);
MagicProjectileEntity projectile = UEntities.MAGIC_BEAM.create(world);
projectile.setPosition(entity.getX(), entity.getEyeY() - 0.1F, entity.getZ());
projectile.setOwner(entity);
projectile.setItem(UItems.GEMSTONE.getDefaultStack(spell.get().getType()));
s.apply(projectile);
projectile.setVelocity(entity, entity.getPitch(), entity.getYaw(), 0, 1.5F, divergance);
projectile.setNoGravity(true);
configureProjectile(projectile, caster);
world.spawnEntity(projectile);
configureProjectile(projectile, caster);
world.spawnEntity(projectile);
return Optional.of(projectile);
return projectile;
});
}
@Override

View file

@ -10,6 +10,7 @@ import com.minelittlepony.unicopia.ability.magic.spell.Situation;
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
import com.minelittlepony.unicopia.mixin.MixinFallingBlockEntity;
import com.minelittlepony.unicopia.projectile.MagicBeamEntity;
import com.minelittlepony.unicopia.projectile.MagicProjectileEntity;
import com.minelittlepony.unicopia.projectile.ProjectileDelegate;
@ -42,15 +43,15 @@ public class CatapultSpell extends AbstractSpell implements ProjectileDelegate.B
@Override
public void onImpact(MagicProjectileEntity projectile, BlockHitResult hit) {
if (!projectile.isClient() && projectile.canModifyAt(hit.getBlockPos())) {
createBlockEntity(projectile.getWorld(), hit.getBlockPos(), e -> apply(projectile, e));
if (!projectile.isClient() && projectile instanceof MagicBeamEntity source && source.canModifyAt(hit.getBlockPos())) {
createBlockEntity(projectile.getWorld(), hit.getBlockPos(), e -> apply(source, e));
}
}
@Override
public void onImpact(MagicProjectileEntity projectile, EntityHitResult hit) {
if (!projectile.isClient()) {
apply(projectile, hit.getEntity());
if (!projectile.isClient() && projectile instanceof MagicBeamEntity source) {
apply(source, hit.getEntity());
}
}

View file

@ -16,6 +16,7 @@ import com.minelittlepony.unicopia.particle.FollowingParticleEffect;
import com.minelittlepony.unicopia.particle.LightningBoltParticleEffect;
import com.minelittlepony.unicopia.particle.ParticleUtils;
import com.minelittlepony.unicopia.particle.UParticles;
import com.minelittlepony.unicopia.projectile.MagicBeamEntity;
import com.minelittlepony.unicopia.projectile.MagicProjectileEntity;
import com.minelittlepony.unicopia.projectile.ProjectileDelegate;
import com.minelittlepony.unicopia.util.shape.Sphere;
@ -55,10 +56,10 @@ public class DarkVortexSpell extends AttractiveSpell implements ProjectileDelega
@Override
public void onImpact(MagicProjectileEntity projectile, BlockHitResult hit) {
if (!projectile.isClient()) {
if (!projectile.isClient() && projectile instanceof MagicBeamEntity source) {
BlockPos pos = hit.getBlockPos();
projectile.getWorld().createExplosion(projectile, pos.getX(), pos.getY(), pos.getZ(), 3, ExplosionSourceType.NONE);
toPlaceable().tick(projectile, Situation.BODY);
toPlaceable().tick(source, Situation.BODY);
}
}

View file

@ -5,6 +5,7 @@ import com.minelittlepony.unicopia.ability.magic.spell.*;
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
import com.minelittlepony.unicopia.particle.LightningBoltParticleEffect;
import com.minelittlepony.unicopia.projectile.MagicBeamEntity;
import com.minelittlepony.unicopia.projectile.MagicProjectileEntity;
import com.minelittlepony.unicopia.projectile.ProjectileDelegate;
@ -48,6 +49,8 @@ public class DispellEvilSpell extends AbstractSpell implements ProjectileDelegat
@Override
public void onImpact(MagicProjectileEntity projectile) {
tick(projectile, Situation.GROUND);
if (projectile instanceof MagicBeamEntity source) {
tick(source, Situation.GROUND);
}
}
}

View file

@ -45,13 +45,11 @@ public class FireBoltSpell extends AbstractSpell implements HomingSpell,
@Override
public boolean tick(Caster<?> caster, Situation situation) {
if (situation == Situation.PROJECTILE) {
if (caster instanceof MagicProjectileEntity && getTraits().get(Trait.FOCUS) >= 50) {
if (caster instanceof MagicProjectileEntity projectile && getTraits().get(Trait.FOCUS) >= 50) {
caster.findAllEntitiesInRange(
getTraits().get(Trait.FOCUS) - 49,
EntityPredicates.VALID_LIVING_ENTITY.and(TargetSelecter.validTarget(this, caster))
).findFirst().ifPresent(target -> {
((MagicProjectileEntity)caster).setHomingTarget(target);
});
).findFirst().ifPresent(target -> projectile.setHomingTarget(target));
}
return true;

View file

@ -12,6 +12,7 @@ import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
import com.minelittlepony.unicopia.entity.Creature;
import com.minelittlepony.unicopia.entity.EntityReference;
import com.minelittlepony.unicopia.entity.Equine;
import com.minelittlepony.unicopia.projectile.MagicBeamEntity;
import com.minelittlepony.unicopia.projectile.MagicProjectileEntity;
import com.minelittlepony.unicopia.projectile.ProjectileDelegate;
import com.minelittlepony.unicopia.util.Weighted;
@ -231,9 +232,10 @@ public class NecromancySpell extends AbstractAreaEffectSpell implements Projecti
}
@Override
public void onImpact(MagicProjectileEntity source, BlockHitResult hit) {
// source.asWorld().createExplosion(source, hit.getPos().x, hit.getPos().y, hit.getPos().z, 3, ExplosionSourceType.MOB);
public void onImpact(MagicProjectileEntity projectile, BlockHitResult hit) {
if (!(projectile instanceof MagicBeamEntity source)) {
return;
}
Shape affectRegion = new Sphere(false, 3);

View file

@ -12,7 +12,6 @@ import com.minelittlepony.unicopia.ability.magic.Affine;
import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.spell.Spell;
import net.minecraft.entity.Entity;
import net.minecraft.predicate.entity.EntityPredicates;
public class TargetSelecter {
private final Map<UUID, Target> targets = new TreeMap<>();
@ -46,7 +45,6 @@ public class TargetSelecter {
public Stream<Entity> getEntities(Caster<?> source, double radius) {
targets.values().removeIf(Target::tick);
return source.findAllEntitiesInRange(radius)
.filter(EntityPredicates.VALID_ENTITY)
.filter(EquinePredicates.EXCEPT_MAGIC_IMMUNE)
.filter(entity -> entity != source.asEntity() && checkAlliegance(spell, source, entity) && filter.test(source, entity))
.map(i -> {

View file

@ -50,7 +50,7 @@ public class EdibleBlock extends HayBlock {
static final BooleanProperty BOTTOM_SOUTH_WEST = BooleanProperty.of("bottom_south_west");
// [up/down][north/south][west/east]
private static final BooleanProperty[] SEGMENTS = {
public static final BooleanProperty[] SEGMENTS = {
BOTTOM_NORTH_WEST,
BOTTOM_NORTH_EAST,
BOTTOM_SOUTH_WEST,

View file

@ -24,9 +24,9 @@ import net.minecraft.util.math.random.Random;
import net.minecraft.world.*;
import net.minecraft.world.event.GameEvent;
public class FruitBearingBlock extends LeavesBlock implements TintedBlock, Buckable {
public class FruitBearingBlock extends LeavesBlock implements TintedBlock, Buckable, Fertilizable {
public static final IntProperty AGE = Properties.AGE_25;
public static final int WITHER_AGE = 15;
public static final int MAX_AGE = 25;
public static final EnumProperty<Stage> STAGE = EnumProperty.of("stage", Stage.class);
private final Supplier<Block> fruit;
@ -41,7 +41,7 @@ public class FruitBearingBlock extends LeavesBlock implements TintedBlock, Bucka
.allowsSpawning(BlockConstructionUtils::canSpawnOnLeaves)
.suffocates(BlockConstructionUtils::never)
.blockVision(BlockConstructionUtils::never));
setDefaultState(getDefaultState().with(STAGE, Stage.IDLE));
setDefaultState(getDefaultState().with(AGE, 0).with(STAGE, Stage.IDLE));
this.overlay = overlay;
this.fruit = fruit;
this.rottenFruitSupplier = rottenFruitSupplier;
@ -76,51 +76,81 @@ public class FruitBearingBlock extends LeavesBlock implements TintedBlock, Bucka
}
if (world.getBaseLightLevel(pos, 0) > 8) {
BlockSoundGroup group = getSoundGroup(state);
int steps = FertilizableUtil.getGrowthSteps(world, pos, state, random);
while (steps-- > 0) {
if (!shouldAdvance(random)) {
continue;
}
if (state.get(STAGE) == Stage.FRUITING) {
state = state.cycle(AGE);
if (state.get(AGE) > 20) {
state = state.with(AGE, 0).cycle(STAGE);
}
} else {
state = state.with(AGE, 0).cycle(STAGE);
}
world.setBlockState(pos, state, Block.NOTIFY_ALL);
state = cycleStage(state);
BlockPos fruitPosition = pos.down();
Stage stage = state.get(STAGE);
if (stage == Stage.FRUITING && isPositionValidForFruit(state, pos)) {
if (world.isAir(fruitPosition)) {
world.setBlockState(fruitPosition, getPlacedFruitState(random), Block.NOTIFY_ALL);
}
}
BlockState fruitState = world.getBlockState(fruitPosition);
if (stage == Stage.WITHERING && fruitState.isOf(fruit.get())) {
if (world.random.nextInt(2) == 0) {
Block.dropStack(world, fruitPosition, rottenFruitSupplier.get());
} else {
Block.dropStacks(fruitState, world, fruitPosition, fruitState.hasBlockEntity() ? world.getBlockEntity(fruitPosition) : null, null, ItemStack.EMPTY);
switch (state.get(STAGE)) {
case WITHERING:
wither(state, world, pos, fruitPosition, world.getBlockState(fruitPosition));
case BEARING:
if (!fruitState.isOf(fruit.get())) {
state = withStage(state, Stage.IDLE);
}
break;
case FRUITING: {
if (!isPositionValidForFruit(state, pos)) {
state = withStage(state, Stage.IDLE);
} else {
state = grow(state, world, pos, fruitPosition, fruitState, random);
}
break;
}
if (world.removeBlock(fruitPosition, false)) {
world.emitGameEvent(GameEvent.BLOCK_DESTROY, pos, GameEvent.Emitter.of(fruitState));
}
world.playSound(null, pos, USounds.ITEM_APPLE_ROT, SoundCategory.BLOCKS, group.getVolume(), group.getPitch());
default:
}
world.setBlockState(pos, state, Block.NOTIFY_ALL);
}
}
}
protected BlockState withStage(BlockState state, Stage stage) {
return state.with(AGE, 0).with(STAGE, stage);
}
private BlockState cycleStage(BlockState state) {
state = state.cycle(AGE);
if (state.get(AGE) == 0) {
state = state.cycle(STAGE);
}
return state;
}
protected BlockState grow(BlockState state, World world, BlockPos pos, BlockPos fruitPosition, BlockState fruitState, Random random) {
if (world.isAir(fruitPosition)) {
world.setBlockState(fruitPosition, getPlacedFruitState(random), Block.NOTIFY_ALL);
return withStage(state, Stage.BEARING);
}
if (!fruitState.isOf(fruit.get())) {
return withStage(state, Stage.IDLE);
}
return state;
}
protected void wither(BlockState state, World world, BlockPos pos, BlockPos fruitPosition, BlockState fruitState) {
if (!fruitState.isOf(fruit.get())) {
if (world.random.nextInt(2) == 0) {
Block.dropStack(world, fruitPosition, rottenFruitSupplier.get());
} else {
Block.dropStacks(fruitState, world, fruitPosition, fruitState.hasBlockEntity() ? world.getBlockEntity(fruitPosition) : null, null, ItemStack.EMPTY);
}
if (world.removeBlock(fruitPosition, false)) {
world.emitGameEvent(GameEvent.BLOCK_DESTROY, pos, GameEvent.Emitter.of(fruitState));
}
BlockSoundGroup group = getSoundGroup(state);
world.playSound(null, pos, USounds.ITEM_APPLE_ROT, SoundCategory.BLOCKS, group.getVolume(), group.getPitch());
}
}
@Override
public List<ItemStack> onBucked(ServerWorld world, BlockState state, BlockPos pos) {
world.setBlockState(pos, state.with(STAGE, Stage.IDLE).with(AGE, 0));
@ -142,18 +172,42 @@ public class FruitBearingBlock extends LeavesBlock implements TintedBlock, Bucka
return state.getRenderingSeed(pos) % 3 == 1;
}
@Override
public boolean isFertilizable(WorldView world, BlockPos pos, BlockState state) {
return switch (state.get(STAGE)) {
case FLOWERING -> world.isAir(pos.down());
default -> !world.getBlockState(pos.down()).isOf(fruit.get());
};
}
@Override
public boolean canGrow(World world, Random random, BlockPos pos, BlockState state) {
return isFertilizable(world, pos, state);
}
@Override
public void grow(ServerWorld world, Random random, BlockPos pos, BlockState state) {
state = state.cycle(AGE);
if (state.get(AGE) == 0) {
state = state.with(STAGE, switch (state.get(STAGE)) {
case IDLE -> Stage.FLOWERING;
case FLOWERING -> Stage.FRUITING;
default -> Stage.FLOWERING;
});
}
if (state.get(STAGE) == Stage.FRUITING && state.get(AGE) == 0) {
state = grow(state, world, pos, pos.down(), world.getBlockState(pos.down()), random);
}
world.setBlockState(pos, state);
}
public enum Stage implements StringIdentifiable {
IDLE,
FLOWERING,
FRUITING,
BEARING,
WITHERING;
private static final Stage[] VALUES = values();
public Stage getNext() {
return VALUES[(ordinal() + 1) % VALUES.length];
}
@Override
public String asString() {
return name().toLowerCase(Locale.ROOT);

View file

@ -74,6 +74,18 @@ public class FruitBlock extends Block implements Buckable {
}
}
@Deprecated
@Override
public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean moved) {
super.onStateReplaced(state, world, pos, newState, moved);
if (!newState.isOf(state.getBlock())) {
BlockState leaves = world.getBlockState(pos.up());
if (leaves.contains(FruitBearingBlock.STAGE)) {
world.setBlockState(pos.up(), leaves.withIfExists(FruitBearingBlock.AGE, 0).with(FruitBearingBlock.STAGE, FruitBearingBlock.Stage.IDLE));
}
}
}
protected boolean canAttachTo(BlockState state) {
return state.isOf(stem);
}

View file

@ -65,6 +65,11 @@ public class SegmentedCropBlock extends CropBlock implements SegmentedBlock {
this.progressionAge = progressionAge;
}
@Override
public IntProperty getAgeProperty() {
return super.getAgeProperty();
}
public SegmentedCropBlock createNext(int progressionAge) {
SegmentedCropBlock next = create(getMaxAge() - this.progressionAge, progressionAge, Settings.copy(this), seeds, () -> this, null);
nextSegmentSupplier = () -> next;

View file

@ -40,7 +40,7 @@ import net.minecraft.world.WorldAccess;
import net.minecraft.world.WorldView;
public class SlimePustuleBlock extends Block {
private static final EnumProperty<Shape> SHAPE = EnumProperty.of("shape", Shape.class);
public static final EnumProperty<Shape> SHAPE = EnumProperty.of("shape", Shape.class);
private static final BooleanProperty POWERED = Properties.POWERED;
private static final Direction[] DIRECTIONS = Arrays.stream(Direction.values())
.filter(direction -> direction != Direction.UP)

View file

@ -32,9 +32,9 @@ public class ThornBlock extends ConnectingBlock implements EarthPonyGrowAbility.
static final Collection<BooleanProperty> PROPERTIES = FACING_PROPERTIES.values();
static final DirectionProperty FACING = Properties.FACING;
static final int MAX_DISTANCE = 25;
static final int MAX_AGE = 4;
static final int MAX_AGE = Properties.AGE_4_MAX;
static final IntProperty DISTANCE = IntProperty.of("distance", 0, MAX_DISTANCE);
static final IntProperty AGE = IntProperty.of("age", 0, MAX_AGE);
static final IntProperty AGE = Properties.AGE_4;
private final Supplier<Block> bud;

View file

@ -175,7 +175,7 @@ public interface UBlocks {
SegmentedCropBlock OATS_CROWN = register("oats_crown", OATS_STEM.createNext(5));
Block PLUNDER_VINE = register("plunder_vine", new ThornBlock(Settings.create().mapColor(MapColor.DARK_CRIMSON).hardness(1).ticksRandomly().sounds(BlockSoundGroup.WOOD).pistonBehavior(PistonBehavior.DESTROY), () -> UBlocks.PLUNDER_VINE_BUD));
Block PLUNDER_VINE_BUD = register("plunder_vine_bud", new ThornBudBlock(Settings.create().mapColor(MapColor.DARK_CRIMSON).hardness(1).nonOpaque().ticksRandomly().sounds(BlockSoundGroup.GRASS).pistonBehavior(PistonBehavior.DESTROY), PLUNDER_VINE.getDefaultState()));
Block PLUNDER_VINE_BUD = register("plunder_vine_bud", new ThornBudBlock(Settings.create().mapColor(MapColor.DARK_CRIMSON).hardness(1).nonOpaque().ticksRandomly().noCollision().sounds(BlockSoundGroup.GRASS).pistonBehavior(PistonBehavior.DESTROY), PLUNDER_VINE.getDefaultState()));
CuringJokeBlock CURING_JOKE = register("curing_joke", new CuringJokeBlock(UEffects.BUTTER_FINGERS, 7, AbstractBlock.Settings.create().mapColor(MapColor.PALE_PURPLE).noCollision().breakInstantly().sounds(BlockSoundGroup.GRASS).offset(AbstractBlock.OffsetType.XZ).pistonBehavior(PistonBehavior.DESTROY)));
Block GOLD_ROOT = register("gold_root", new CarrotsBlock(AbstractBlock.Settings.create().mapColor(MapColor.GOLD).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.CROP).pistonBehavior(PistonBehavior.DESTROY)) {
@Override

View file

@ -12,6 +12,7 @@ import net.minecraft.block.ShapeContext;
import net.minecraft.item.ItemPlacementContext;
import net.minecraft.state.StateManager;
import net.minecraft.state.property.BooleanProperty;
import net.minecraft.state.property.Properties;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.util.shape.VoxelShape;
@ -20,8 +21,8 @@ import net.minecraft.world.BlockView;
import net.minecraft.world.WorldAccess;
public class CloudPillarBlock extends CloudBlock {
private static final BooleanProperty NORTH = BooleanProperty.of("north");
private static final BooleanProperty SOUTH = BooleanProperty.of("south");
private static final BooleanProperty NORTH = Properties.NORTH;
private static final BooleanProperty SOUTH = Properties.SOUTH;
private static final Map<Direction, BooleanProperty> DIRECTION_PROPERTIES = Map.of(
Direction.UP, NORTH,
Direction.DOWN, SOUTH

View file

@ -52,6 +52,7 @@ import net.minecraft.client.item.ModelPredicateProviderRegistry;
import net.minecraft.client.particle.Particle;
import net.minecraft.client.particle.SpriteProvider;
import net.minecraft.client.render.*;
import net.minecraft.client.render.VertexConsumerProvider.Immediate;
import net.minecraft.client.render.block.entity.BlockEntityRendererFactories;
import net.minecraft.client.render.entity.FlyingItemEntityRenderer;
import net.minecraft.client.render.item.ItemRenderer;
@ -210,7 +211,6 @@ public interface URenderers {
matrices.translate(0, 0.06, 0);
}
// GUI, FIXED, NONE - translate(0, 0, 0)
//matrices.scale(0.5F, 0.5F, 0.5F);
float scale = 0.5F;
matrices.scale(scale, scale, scale);
@ -219,11 +219,16 @@ public interface URenderers {
renderer.renderItem(appearance, mode, light, overlay, matrices, immediate, world, 0);
matrices.pop();
}
renderer.renderItem(item.createAppearanceStack(stack, UItems.EMPTY_JAR), mode, light, OverlayTexture.DEFAULT_UV, matrices, vertices, world, 0);
renderer.renderItem(UItems.EMPTY_JAR.getDefaultStack(), mode, light, overlay, matrices, vertices, world, 0);
if (mode == ModelTransformationMode.GUI) {
if (vertices instanceof Immediate i) {
i.draw();
}
DiffuseLighting.enableGuiDepthLighting();
}
matrices.push();
}

View file

@ -163,15 +163,15 @@ public class DismissSpellScreen extends GameGui {
@Override
public void render(DrawContext context, int mouseX, int mouseY, float tickDelta) {
MatrixStack matrices = context.getMatrices();
copy.set(x, y, z, w);
copy.mul(matrices.peek().getPositionMatrix());
var type = actualSpell.getType().withTraits(actualSpell.getTraits());
DrawableUtil.drawLine(matrices, 0, 0, (int)x, (int)y, 0xFFAAFF99);
copy.set(mouseX - width * 0.5F - x * 0.5F, mouseY - height * 0.5F - y * 0.5F, 0, 0);
DrawableUtil.drawLine(matrices, 0, 0, (int)x, (int)y, actualSpell.getAffinity().getColor().getColorValue());
DrawableUtil.renderItemIcon(context, actualSpell.isDead() ? UItems.BOTCHED_GEM.getDefaultStack() : type.getDefaultStack(),
copy.x - 8 + copy.z / 20F,
copy.y - 8 + copy.z / 20F,
x - 8 - copy.x * 0.2F,
y - 8 - copy.y * 0.2F,
1
);

View file

@ -5,6 +5,7 @@ import java.util.List;
import com.minelittlepony.common.client.gui.IViewRoot;
import com.minelittlepony.common.client.gui.dimension.Bounds;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.ability.magic.SpellPredicate;
import com.minelittlepony.unicopia.client.gui.*;
import com.minelittlepony.unicopia.entity.player.*;
import com.minelittlepony.unicopia.util.ColorHelper;
@ -43,7 +44,7 @@ public class SpellbookProfilePageContent implements SpellbookChapterList.Content
.setTooltip(() -> List.of(
Text.literal(String.format("Level %d ", pony.getLevel().get() + 1)).append(pony.getSpecies().getDisplayName()).formatted(pony.getSpecies().getAffinity().getColor()),
Text.literal(String.format("Mana: %d%%", (int)(pony.getMagicalReserves().getMana().getPercentFill() * 100))),
Text.literal(String.format("Corruption: %d%%", (int)(pony.getCorruption().getScaled(100)))),
Text.literal(String.format("Corruption: %s%d%%", pony.getCorruptionhandler().hasCorruptingMagic() ? "^" : "", (int)(pony.getCorruption().getScaled(100)))),
Text.literal(String.format("Experience: %d", (int)(pony.getMagicalReserves().getXp().getPercentFill() * 100))),
Text.literal(String.format("Next level in: %dxp", 100 - (int)(pony.getMagicalReserves().getXp().getPercentFill() * 100)))
));
@ -108,7 +109,11 @@ public class SpellbookProfilePageContent implements SpellbookChapterList.Content
int alpha = (int)(alphaF * 0x10) & 0xFF;
int color = 0x10404000 | alpha;
int xpColor = 0xAA0040FF | ((int)((0.3F + 0.7F * xpPercentage) * 0xFF) & 0xFF) << 16;
int manaColor = 0xFF00F040 | (int)((0.3F + 0.7F * alphaF) * 0x40) << 16;
int manaColor = 0xFF00F040;
if (pony.getSpellSlot().get(SpellPredicate.IS_CORRUPTING, false).isPresent()) {
manaColor = ColorHelper.lerp(Math.abs(MathHelper.sin(pony.asEntity().age / 15F)), manaColor, 0xFF0030F0);
}
manaColor |= (int)((0.3F + 0.7F * alphaF) * 0x40) << 16;
DrawableUtil.drawArc(matrices, 0, radius + 24, 0, DrawableUtil.TAU, color, false);
DrawableUtil.drawArc(matrices, radius / 3, radius + 6, 0, DrawableUtil.TAU, color, false);

View file

@ -1,14 +1,38 @@
package com.minelittlepony.unicopia.client.render;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Function;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.*;
import net.minecraft.client.render.VertexConsumerProvider.Immediate;
import net.minecraft.screen.PlayerScreenHandler;
import net.minecraft.util.Identifier;
public interface RenderLayerUtil {
Identifier SHADOW_TEXTURE = new Identifier("textures/misc/shadow.png");
static Optional<Identifier> getTexture(RenderLayer layer) {
if (layer instanceof RenderLayer.MultiPhase multiphase) {
return multiphase.getPhases().texture.getId();
}
return Optional.empty();
}
static void createUnionBuffer(Consumer<VertexConsumerProvider> action, VertexConsumerProvider vertices, Function<Identifier, RenderLayer> overlayFunction) {
Immediate immediate = MinecraftClient.getInstance().getBufferBuilders().getEffectVertexConsumers();
action.accept(layer -> {
Identifier texture = RenderLayerUtil.getTexture(layer).orElse(null);
if (texture == null || texture.equals(SHADOW_TEXTURE) || texture.equals(PlayerScreenHandler.BLOCK_ATLAS_TEXTURE)) {
return vertices.getBuffer(layer);
}
return VertexConsumers.union(
vertices.getBuffer(layer),
immediate.getBuffer(overlayFunction.apply(texture))
);
});
immediate.draw();
}
}

View file

@ -1,8 +1,6 @@
package com.minelittlepony.unicopia.client.render;
import java.util.Optional;
import com.minelittlepony.client.util.render.RenderLayerUtil;
import com.minelittlepony.unicopia.EquinePredicates;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.Unicopia;
@ -14,6 +12,7 @@ import com.minelittlepony.unicopia.entity.ItemImpl;
import com.minelittlepony.unicopia.entity.Living;
import com.minelittlepony.unicopia.entity.duck.LavaAffine;
import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.util.ColorHelper;
import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.MinecraftClient;
@ -24,14 +23,13 @@ import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.*;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.vehicle.BoatEntity;
import net.minecraft.screen.PlayerScreenHandler;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.*;
import net.minecraft.util.math.RotationAxis;
import net.minecraft.util.math.Vec3d;
public class WorldRenderDelegate {
public static final WorldRenderDelegate INSTANCE = new WorldRenderDelegate();
private static final Optional<Vec3d> RED_SKY_COLOR = Optional.of(new Vec3d(1, 0, 0));
private static final Identifier SHADOW_TEXTURE = new Identifier("textures/misc/shadow.png");
private final EntityReplacementManager disguiseLookup = new EntityReplacementManager();
private final EntityDisguiseRenderer disguiseRenderer = new EntityDisguiseRenderer(this);
@ -72,23 +70,10 @@ public class WorldRenderDelegate {
if (MinecraftClient.getInstance().getResourceManager().getResource(frostingTexture).isPresent()) {
recurseFrosting = true;
Immediate immediate = MinecraftClient.getInstance().getBufferBuilders().getEffectVertexConsumers();
client.getEntityRenderDispatcher().render(entity, x, y, z, yaw, tickDelta, matrices, layer -> {
Identifier texture = RenderLayerUtil.getTexture(layer).orElse(null);
if (texture == null || texture.equals(SHADOW_TEXTURE)) {
return vertices.getBuffer(layer);
}
return VertexConsumers.union(
vertices.getBuffer(layer),
immediate.getBuffer(RenderLayers.getEntityTranslucent(frostingTexture))
);
}, light);
RenderLayerUtil.createUnionBuffer(c -> {
client.getEntityRenderDispatcher().render(entity, x, y, z, yaw, tickDelta, matrices, c, light);
}, vertices, texture -> RenderLayers.getEntityTranslucent(frostingTexture));
recurseFrosting = false;
immediate.draw();
return true;
}
}
@ -146,16 +131,9 @@ public class WorldRenderDelegate {
if (!recurseMinion && pony instanceof Creature creature && creature.isMinion()) {
try {
recurseMinion = true;
client.getEntityRenderDispatcher().render(creature.asEntity(), x, y, z, yaw, tickDelta, matrices, layer -> {
return RenderLayerUtil.getTexture(layer)
.filter(texture -> texture != PlayerScreenHandler.BLOCK_ATLAS_TEXTURE)
.map(texture -> {
return VertexConsumers.union(
vertices.getBuffer(layer),
vertices.getBuffer(RenderLayers.getMagicColored(texture, creature.isDiscorded() ? 0xCCFF0000 : 0xCC0000FF))
);
}).orElseGet(() -> vertices.getBuffer(layer));
}, light);
RenderLayerUtil.createUnionBuffer(c -> {
client.getEntityRenderDispatcher().render(creature.asEntity(), x, y, z, yaw, tickDelta, matrices, c, light);
}, vertices, texture -> RenderLayers.getMagicColored(texture, creature.isDiscorded() ? 0x33FF0000 : ColorHelper.getRainbowColor(creature.asEntity(), 25, 1) )); // 0x8800AA00
return true;
} catch (Throwable t) {
Unicopia.LOGGER.error("Error whilst rendering minion", t);

View file

@ -1,8 +1,7 @@
package com.minelittlepony.unicopia.client.render.entity;
import com.minelittlepony.unicopia.client.render.RenderLayers;
import com.minelittlepony.unicopia.projectile.MagicProjectileEntity;
import com.minelittlepony.unicopia.projectile.MagicBeamEntity;
import net.minecraft.client.model.Dilation;
import net.minecraft.client.model.ModelData;
import net.minecraft.client.model.ModelPart;
@ -23,7 +22,7 @@ import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
public class MagicBeamEntityRenderer extends EntityRenderer<MagicProjectileEntity> {
public class MagicBeamEntityRenderer extends EntityRenderer<MagicBeamEntity> {
private final Model model;
public MagicBeamEntityRenderer(EntityRendererFactory.Context ctx) {
@ -32,17 +31,17 @@ public class MagicBeamEntityRenderer extends EntityRenderer<MagicProjectileEntit
}
@Override
public Identifier getTexture(MagicProjectileEntity entity) {
public Identifier getTexture(MagicBeamEntity entity) {
return PlayerScreenHandler.BLOCK_ATLAS_TEXTURE;
}
@Override
protected int getBlockLight(MagicProjectileEntity entity, BlockPos pos) {
protected int getBlockLight(MagicBeamEntity entity, BlockPos pos) {
return 15;
}
@Override
public void render(MagicProjectileEntity entity, float yaw, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light) {
public void render(MagicBeamEntity entity, float yaw, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light) {
if (entity.age < 2 && dispatcher.camera.getFocusedEntity().squaredDistanceTo(entity) < 8) {
return;
}
@ -68,7 +67,7 @@ public class MagicBeamEntityRenderer extends EntityRenderer<MagicProjectileEntit
super.render(entity, yaw, tickDelta, matrices, vertexConsumers, light);
}
public class Model extends EntityModel<MagicProjectileEntity> {
public class Model extends EntityModel<MagicBeamEntity> {
private final ModelPart part;
@ -89,7 +88,7 @@ public class MagicBeamEntityRenderer extends EntityRenderer<MagicProjectileEntit
}
@Override
public void setAngles(MagicProjectileEntity entity, float limbAngle, float limbDistance, float customAngle, float headYaw, float headPitch) {
public void setAngles(MagicBeamEntity entity, float limbAngle, float limbDistance, float customAngle, float headYaw, float headPitch) {
part.pitch = headPitch;
part.yaw = headYaw;
}

View file

@ -1,18 +1,11 @@
package com.minelittlepony.unicopia.compat.ad_astra;
import com.minelittlepony.unicopia.mixin.ad_astra.MixinOxygenUtils;
import net.minecraft.entity.Entity;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.entity.LivingEntity;
import net.minecraft.world.World;
public final class OxygenUtils {
public static OxygenApi API = entity -> false;
public interface OxygenUtils {
boolean MOD_LOADED = FabricLoader.getInstance().isModLoaded("ad_astra");
static boolean entityHasOxygen(World world, LivingEntity entity) {
if (MOD_LOADED) {
return MixinOxygenUtils.entityHasOxygen(world, entity);
}
return false;
public interface OxygenApi {
boolean hasOxygen(Entity entity);
}
}

View file

@ -30,7 +30,7 @@ public interface TrinketsDelegate {
TrinketsDelegate EMPTY = new TrinketsDelegate() {};
static TrinketsDelegate getInstance(@Nullable LivingEntity entity) {
if (!(entity instanceof PlayerEntity && hasTrinkets())) {
if (!hasTrinkets() || (entity != null && !(entity instanceof PlayerEntity))) {
return EMPTY;
}
return TrinketsDelegateImpl.INSTANCE;

View file

@ -3,6 +3,8 @@ package com.minelittlepony.unicopia.compat.trinkets;
import java.util.UUID;
import com.google.common.collect.Multimap;
import com.minelittlepony.unicopia.entity.ItemTracker;
import com.minelittlepony.unicopia.entity.Living;
import com.minelittlepony.unicopia.item.FriendshipBraceletItem;
import com.minelittlepony.unicopia.item.WearableItem;
@ -30,6 +32,17 @@ public class UnicopiaTrinket implements Trinket {
return;
}
if (!(stack.getItem() instanceof ItemTracker.Trackable) && stack.getItem() instanceof Equipment q) {
entity.playSound(q.getEquipSound(), 1, 1);
}
}
@Override
public void onUnequip(ItemStack stack, SlotReference slot, LivingEntity entity) {
if (stack.getItem() instanceof ItemTracker.Trackable t) {
Living<?> l = Living.living(entity);
t.onUnequipped(l, l.getArmour().forceRemove(t));
}
if (stack.getItem() instanceof Equipment q) {
entity.playSound(q.getEquipSound(), 1, 1);
}

View file

@ -0,0 +1,38 @@
package com.minelittlepony.unicopia.datagen;
import java.util.HashMap;
import java.util.concurrent.CompletableFuture;
import java.util.function.BiConsumer;
import java.util.function.Supplier;
import com.google.common.base.Preconditions;
import com.google.gson.JsonElement;
import net.minecraft.data.DataOutput.PathResolver;
import net.minecraft.data.DataProvider;
import net.minecraft.data.DataWriter;
import net.minecraft.util.Identifier;
public class DataCollector {
private final HashMap<Identifier, Supplier<JsonElement>> values = new HashMap<>();
private final PathResolver resolver;
public DataCollector(PathResolver resolver) {
this.resolver = resolver;
}
public BiConsumer<Identifier, Supplier<JsonElement>> prime() {
values.clear();
return (Identifier id, Supplier<JsonElement> value) ->
Preconditions.checkState(values.put(id, value) == null, "Duplicate model definition for " + id);
}
public CompletableFuture<?> upload(DataWriter cache) {
return CompletableFuture.allOf(values.entrySet()
.stream()
.map(entry -> DataProvider.writeToPath(cache, entry.getValue().get(), resolver.resolveJson(entry.getKey())))
.toArray(CompletableFuture[]::new)
);
}
}

View file

@ -0,0 +1,51 @@
package com.minelittlepony.unicopia.datagen;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import com.minelittlepony.unicopia.datagen.providers.SeasonsGrowthRatesProvider;
import com.minelittlepony.unicopia.datagen.providers.UBlockTagProvider;
import com.minelittlepony.unicopia.datagen.providers.UItemTagProvider;
import com.minelittlepony.unicopia.datagen.providers.UModelProvider;
import com.minelittlepony.unicopia.datagen.providers.URecipeProvider;
import com.minelittlepony.unicopia.datagen.providers.loot.UBlockAdditionsLootTableProvider;
import com.minelittlepony.unicopia.datagen.providers.loot.UBlockLootTableProvider;
import com.minelittlepony.unicopia.datagen.providers.loot.UChestAdditionsLootTableProvider;
import com.minelittlepony.unicopia.server.world.UWorldGen;
import net.fabricmc.fabric.api.datagen.v1.DataGeneratorEntrypoint;
import net.fabricmc.fabric.api.datagen.v1.FabricDataGenerator;
import net.minecraft.registry.RegistryBuilder;
import net.minecraft.registry.RegistryEntryLookup;
import net.minecraft.registry.RegistryKeys;
import net.minecraft.world.biome.OverworldBiomeCreator;
import net.minecraft.world.gen.carver.ConfiguredCarver;
import net.minecraft.world.gen.feature.PlacedFeature;
public class Datagen implements DataGeneratorEntrypoint {
public static final Logger LOGGER = LogManager.getLogger();
@Override
public void onInitializeDataGenerator(FabricDataGenerator fabricDataGenerator) {
final FabricDataGenerator.Pack pack = fabricDataGenerator.createPack();
UBlockTagProvider blockTags = pack.addProvider(UBlockTagProvider::new);
pack.addProvider((output, registries) -> new UItemTagProvider(output, registries, blockTags));
pack.addProvider(UModelProvider::new);
pack.addProvider(URecipeProvider::new);
pack.addProvider(UBlockLootTableProvider::new);
pack.addProvider(UBlockAdditionsLootTableProvider::new);
pack.addProvider(UChestAdditionsLootTableProvider::new);
pack.addProvider(SeasonsGrowthRatesProvider::new);
}
@Override
public void buildRegistry(RegistryBuilder builder) {
builder.addRegistry(RegistryKeys.BIOME, registerable -> {
RegistryEntryLookup<PlacedFeature> placedFeatureLookup = registerable.getRegistryLookup(RegistryKeys.PLACED_FEATURE);
RegistryEntryLookup<ConfiguredCarver<?>> carverLookup = registerable.getRegistryLookup(RegistryKeys.CONFIGURED_CARVER);
registerable.register(UWorldGen.SWEET_APPLE_ORCHARD, OverworldBiomeCreator.createNormalForest(placedFeatureLookup, carverLookup, false, false, false));
});
}
}

View file

@ -0,0 +1,21 @@
package com.minelittlepony.unicopia.datagen;
import com.minelittlepony.unicopia.item.UItems;
import net.minecraft.item.Item;
public interface ItemFamilies {
Item[] MUSIC_DISCS = {
UItems.MUSIC_DISC_CRUSADE, UItems.MUSIC_DISC_FUNK, UItems.MUSIC_DISC_PET, UItems.MUSIC_DISC_POPULAR
};
Item[] POLEARMS = {
UItems.WOODEN_POLEARM, UItems.STONE_POLEARM, UItems.IRON_POLEARM, UItems.GOLDEN_POLEARM, UItems.DIAMOND_POLEARM, UItems.NETHERITE_POLEARM
};
Item[] HORSE_SHOES = {
UItems.IRON_HORSE_SHOE, UItems.GOLDEN_HORSE_SHOE, UItems.COPPER_HORSE_SHOE, UItems.NETHERITE_HORSE_SHOE
};
Item[] BASKETS = {
UItems.ACACIA_BASKET, UItems.BAMBOO_BASKET, UItems.BIRCH_BASKET, UItems.CHERRY_BASKET, UItems.DARK_OAK_BASKET,
UItems.JUNGLE_BASKET, UItems.MANGROVE_BASKET, UItems.OAK_BASKET, UItems.PALM_BASKET, UItems.SPRUCE_BASKET
};
}

View file

@ -0,0 +1,22 @@
package com.minelittlepony.unicopia.datagen;
import com.minelittlepony.unicopia.block.UBlocks;
import net.minecraft.data.family.BlockFamily;
public interface UBlockFamilies {
BlockFamily PALM = new BlockFamily.Builder(UBlocks.PALM_PLANKS)
.slab(UBlocks.PALM_SLAB).stairs(UBlocks.PALM_STAIRS).fence(UBlocks.PALM_FENCE).fenceGate(UBlocks.PALM_FENCE_GATE)
.button(UBlocks.PALM_BUTTON).pressurePlate(UBlocks.PALM_PRESSURE_PLATE).sign(UBlocks.PALM_SIGN, UBlocks.PALM_WALL_SIGN)
.door(UBlocks.PALM_DOOR).trapdoor(UBlocks.PALM_TRAPDOOR)
.group("wooden").unlockCriterionName("has_planks")
.build();
BlockFamily ZAP = new BlockFamily.Builder(UBlocks.ZAP_PLANKS)
.slab(UBlocks.ZAP_SLAB).stairs(UBlocks.ZAP_STAIRS).fence(UBlocks.ZAP_FENCE).fenceGate(UBlocks.ZAP_FENCE_GATE)
.group("wooden").unlockCriterionName("has_planks")
.build();
BlockFamily WAXED_ZAP = new BlockFamily.Builder(UBlocks.WAXED_ZAP_PLANKS)
.slab(UBlocks.WAXED_ZAP_SLAB).stairs(UBlocks.WAXED_ZAP_STAIRS).fence(UBlocks.WAXED_ZAP_FENCE).fenceGate(UBlocks.WAXED_ZAP_FENCE_GATE)
.group("wooden").unlockCriterionName("has_planks")
.build();
}

View file

@ -0,0 +1,90 @@
package com.minelittlepony.unicopia.datagen.providers;
import java.util.Arrays;
import java.util.Optional;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import com.google.gson.JsonElement;
import com.minelittlepony.unicopia.Unicopia;
import net.minecraft.block.Block;
import net.minecraft.data.client.Model;
import net.minecraft.data.client.ModelIds;
import net.minecraft.data.client.Models;
import net.minecraft.data.client.TextureKey;
import net.minecraft.data.client.TextureMap;
import net.minecraft.data.client.TexturedModel;
import net.minecraft.data.client.VariantSettings;
import net.minecraft.util.Identifier;
import net.minecraft.util.Pair;
public interface BlockModels {
TextureKey SHELL = TextureKey.of("shell");
TextureKey STEP = TextureKey.of("step");
Model FRUIT = block("fruit", TextureKey.CROSS);
Model STRAIGHT_STAIRS = block("seethrough_stairs", TextureKey.BOTTOM, TextureKey.TOP, TextureKey.SIDE, STEP);
Model INNER_STAIRS = block("inner_seethrough_stairs", "_inner", TextureKey.BOTTOM, TextureKey.TOP, TextureKey.SIDE, STEP);
Model OUTER_STAIRS = block("outer_seethrough_stairs", "_outer", TextureKey.BOTTOM, TextureKey.TOP, TextureKey.SIDE, STEP);
Model DOOR_LEFT = block("door_left", TextureKey.BOTTOM, TextureKey.TOP);
Model DOOR_RIGHT = block("door_right", TextureKey.BOTTOM, TextureKey.TOP);
Model TEMPLATE_PILLAR = block("template_pillar", TextureKey.SIDE);
Model TEMPLATE_PILLAR_END = block("template_pillar_end", "_end", TextureKey.BOTTOM, TextureKey.TOP, TextureKey.END);
Factory CROP = Factory.of(TextureMap::crop, Models.CROP);
Factory CUBE_ALL = Factory.of(TextureMap::all, Models.CUBE_ALL);
TexturedModel.Factory SPIKES = TexturedModel.makeFactory(b -> TextureMap.crop(ModelIds.getBlockModelId(b)), Models.CROP);
String[] FLATTENED_MODEL_SUFFEXES = {"xyz", "yz", "xy", "y", "xz", "z", "x", "full"};
String[] FLATTENED_MODEL_SUFFEXES_ROT = {"xyz", "xy", "yz", "y", "xz", "x", "z", "full"};
VariantSettings.Rotation[] FLATTENED_MODEL_ROTATIONS = {
VariantSettings.Rotation.R0, VariantSettings.Rotation.R270, VariantSettings.Rotation.R90, VariantSettings.Rotation.R180,
VariantSettings.Rotation.R270, VariantSettings.Rotation.R180, VariantSettings.Rotation.R0, VariantSettings.Rotation.R90
};
Model[] FLATTENED_MODELS = Arrays.stream(FLATTENED_MODEL_SUFFEXES)
.map(variant -> block("flattened_corner_" + variant, "_corner_" + variant, TextureKey.ALL))
.toArray(Model[]::new);
Model[] SHELL_MODELS = IntStream.range(1, 5)
.mapToObj(i -> block("template_shell_" + i, "_" + i, SHELL))
.toArray(Model[]::new);
Model[] PIE_MODELS = Stream.of("_full", "_elbow", "_straight", "_corner")
.map(variant -> block("pie" + variant, variant, TextureKey.TOP, TextureKey.BOTTOM, TextureKey.SIDE, TextureKey.INSIDE))
.toArray(Model[]::new);
@SuppressWarnings("unchecked")
Pair<Model, String>[] BALE_MODELS = Stream.of("bnw", "bne", "bsw", "bse", "tnw", "tne", "tsw", "tse")
.map(suffex -> new Pair<>(block("template_bale_" + suffex, "_" + suffex, TextureKey.TOP, TextureKey.SIDE), "_" + suffex))
.toArray(Pair[]::new);
static Model block(String parent, TextureKey ... requiredTextureKeys) {
return new Model(Optional.of(Unicopia.id("block/" + parent)), Optional.empty(), requiredTextureKeys);
}
static Model block(String parent, String variant, TextureKey ... requiredTextureKeys) {
return new Model(Optional.of(Unicopia.id("block/" + parent)), Optional.of(variant), requiredTextureKeys);
}
static Model block(Identifier parent, TextureKey ... requiredTextureKeys) {
return new Model(Optional.of(parent.withPrefixedPath("block/")), Optional.empty(), requiredTextureKeys);
}
static Model block(Identifier parent, String variant, TextureKey ... requiredTextureKeys) {
return new Model(Optional.of(parent.withPrefixedPath("block/")), Optional.of(variant), requiredTextureKeys);
}
public interface Factory {
static Factory of(Function<Identifier, TextureMap> textureFunc, Model model) {
return (block, suffix) -> TexturedModel.makeFactory(b -> textureFunc.apply(ModelIds.getBlockSubModelId(b, suffix)), model).get(block);
}
TexturedModel get(Block block, String suffix);
default Identifier upload(Block block, String suffix, BiConsumer<Identifier, Supplier<JsonElement>> writer) {
return get(block, suffix).upload(block, suffix, writer);
}
}
}

View file

@ -0,0 +1,28 @@
package com.minelittlepony.unicopia.datagen.providers;
import net.minecraft.data.client.VariantSettings;
import net.minecraft.data.client.VariantSettings.Rotation;
import net.minecraft.util.math.Direction;
import static net.minecraft.util.math.Direction.*;
public class BlockRotation {
private static final Rotation[] ROTATIONS = Rotation.values();
public static final Direction[] DIRECTIONS = { EAST, SOUTH, WEST, NORTH };
public static VariantSettings.Rotation cycle(Rotation rotation, int steps) {
int index = rotation.ordinal() + steps;
while (index < 0) {
index += ROTATIONS.length;
}
return ROTATIONS[index % ROTATIONS.length];
}
public static Rotation next(Rotation rotation) {
return cycle(rotation, 1);
}
public static Rotation previous(Rotation rotation) {
return cycle(rotation, -1);
}
}

View file

@ -0,0 +1,33 @@
package com.minelittlepony.unicopia.datagen.providers;
import java.util.List;
import java.util.function.UnaryOperator;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import net.minecraft.block.Block;
import net.minecraft.data.client.BlockStateModelGenerator;
import net.minecraft.data.client.ModelIds;
import net.minecraft.data.client.MultipartBlockStateSupplier;
import net.minecraft.data.client.VariantSettings;
import net.minecraft.util.Identifier;
final class FireModels {
static void registerSoulFire(BlockStateModelGenerator modelGenerator, Block fire, Block texture) {
List<Identifier> floorModels = getFireModels(modelGenerator, texture, "_floor").toList();
List<Identifier> sideModels = Stream.concat(
getFireModels(modelGenerator, texture, "_side"),
getFireModels(modelGenerator, texture, "_side_alt")
).toList();
modelGenerator.blockStateCollector.accept(MultipartBlockStateSupplier.create(fire)
.with(BlockStateModelGenerator.buildBlockStateVariants(floorModels, UnaryOperator.identity()))
.with(BlockStateModelGenerator.buildBlockStateVariants(sideModels, UnaryOperator.identity()))
.with(BlockStateModelGenerator.buildBlockStateVariants(sideModels, blockStateVariant -> blockStateVariant.put(VariantSettings.Y, VariantSettings.Rotation.R90)))
.with(BlockStateModelGenerator.buildBlockStateVariants(sideModels, blockStateVariant -> blockStateVariant.put(VariantSettings.Y, VariantSettings.Rotation.R180)))
.with(BlockStateModelGenerator.buildBlockStateVariants(sideModels, blockStateVariant -> blockStateVariant.put(VariantSettings.Y, VariantSettings.Rotation.R270))));
}
private static Stream<Identifier> getFireModels(BlockStateModelGenerator modelGenerator, Block texture, String midfix) {
return IntStream.range(0, 2).mapToObj(i -> ModelIds.getBlockSubModelId(texture, midfix + i));
}
}

View file

@ -0,0 +1,78 @@
package com.minelittlepony.unicopia.datagen.providers;
import java.util.Locale;
import java.util.Optional;
import com.google.common.base.Strings;
import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.entity.mob.ButterflyEntity;
import net.minecraft.data.client.ItemModelGenerator;
import net.minecraft.data.client.Model;
import net.minecraft.data.client.ModelIds;
import net.minecraft.data.client.TextureKey;
import net.minecraft.data.client.TextureMap;
import net.minecraft.item.Item;
import net.minecraft.registry.Registries;
import net.minecraft.util.Identifier;
interface ItemModels {
Model GENERATED = net.minecraft.data.client.Models.GENERATED;
Model CHEST = item(new Identifier("chest"), TextureKey.PARTICLE);
Model BUILTIN_ENTITY = new Model(Optional.of(new Identifier("builtin/entity")), Optional.empty());
Model TEMPLATE_AMULET = item("template_amulet", TextureKey.LAYER0);
Model TEMPLATE_EYEWEAR = item("template_eyewear", TextureKey.LAYER0);
Model TEMPLATE_SPAWN_EGG = item(new Identifier("template_spawn_egg"));
Model TEMPLATE_MUG = item("template_mug", TextureKey.LAYER0);
Model TEMPLATE_PILLAR = item("template_pillar", TextureKey.TOP, TextureKey.BOTTOM, TextureKey.SIDE, TextureKey.END);
Model HANDHELD_STAFF = item("handheld_staff", TextureKey.LAYER0);
Model TRIDENT_THROWING = item(new Identifier("trident_throwing"), TextureKey.LAYER0);
Model TRIDENT_IN_HAND = item(new Identifier("trident_in_hand"), TextureKey.LAYER0);
static Model item(String parent, TextureKey ... requiredTextureKeys) {
return new Model(Optional.of(Unicopia.id("item/" + parent)), Optional.empty(), requiredTextureKeys);
}
static Model item(Identifier parent, TextureKey ... requiredTextureKeys) {
return new Model(Optional.of(parent.withPrefixedPath("item/")), Optional.empty(), requiredTextureKeys);
}
static void register(ItemModelGenerator itemModelGenerator, Item... items) {
register(itemModelGenerator, GENERATED, items);
}
static void register(ItemModelGenerator itemModelGenerator, Model model, Item... items) {
for (Item item : items) {
itemModelGenerator.register(item, model);
}
}
static void registerPolearm(ItemModelGenerator itemModelGenerator, Item item) {
TextureMap textures = TextureMap.layer0(TextureMap.getId(item));
GENERATED.upload(ModelIds.getItemSubModelId(item, "_in_inventory"), textures, itemModelGenerator.writer);
ModelOverrides.of(TRIDENT_IN_HAND)
.addOverride("throwing", 1, generator -> TRIDENT_THROWING.upload(ModelIds.getItemSubModelId(item, "_throwing"), textures, itemModelGenerator.writer))
.upload(ModelIds.getItemModelId(item), textures, itemModelGenerator);
}
static void registerButterfly(ItemModelGenerator itemModelGenerator, Item item) {
float step = 1F / ButterflyEntity.Variant.VALUES.length;
ModelOverrides.of(GENERATED).addUniform("variant", step, 1 - step, step, (i, value) -> {
String name = ButterflyEntity.Variant.byId(i + 1).name().toLowerCase(Locale.ROOT);
Identifier subModelId = Registries.ITEM.getId(item).withPath(p -> "item/" + name + "_" + p);
return GENERATED.upload(subModelId, TextureMap.layer0(subModelId), itemModelGenerator.writer);
}).upload(item, itemModelGenerator);
}
static void registerSpectralBlock(ItemModelGenerator itemModelGenerator, Item item) {
final float step = 0.025F;
String[] suffexes = { "", "_greening", "_flowering", "_fruiting", "_ripe", "" };
ModelOverrides.of(GENERATED).addUniform("unicopia:zap_cycle", 0, 1, step, (index, value) -> {
if (value < 0.0001 || value > 0.999F) {
return ModelIds.getItemModelId(item);
}
Identifier subModelId = ModelIds.getItemSubModelId(item, suffexes[index / 8] + "_" + Strings.padStart((index % 8) * 5 + "", 2, '0'));
return GENERATED.upload(subModelId, TextureMap.layer0(subModelId), itemModelGenerator.writer);
}).upload(item, "_00", itemModelGenerator);
}
}

View file

@ -0,0 +1,107 @@
package com.minelittlepony.unicopia.datagen.providers;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import net.minecraft.data.client.ItemModelGenerator;
import net.minecraft.data.client.Model;
import net.minecraft.data.client.ModelIds;
import net.minecraft.data.client.TextureMap;
import net.minecraft.item.Item;
import net.minecraft.util.Identifier;
import net.minecraft.util.Pair;
import net.minecraft.util.Util;
public final class ModelOverrides {
private final Model model;
private final List<Override> overrides = new ArrayList<>();
public static ModelOverrides of(Model model) {
return new ModelOverrides(model);
}
private ModelOverrides(Model model) {
this.model = model;
}
public ModelOverrides addUniform(String key, int from, int to, Identifier model) {
float step = 1F / to;
for (int index = from; index <= to; index++) {
addOverride(model.withSuffixedPath("_" + index), key, index * step);
}
return this;
}
public ModelOverrides addUniform(String key, float from, float to, float step, ModelVariantSupplier childModelSupplier) {
int index = 0;
for (float value = from; value <= to; value += step) {
final int capture = index++;
final float capture2 = value;
addOverride(key, value, generator -> {
return childModelSupplier.upload(capture, capture2);
});
}
return this;
}
public ModelOverrides addOverride(Identifier modelId, String key, float value) {
return addOverride(modelId, TextureMap.layer0(modelId), key, value);
}
public ModelOverrides addOverride(Identifier modelId, TextureMap textures, String key, float value) {
return addOverride(key, value, generator -> model.upload(modelId, textures, generator.writer));
}
public ModelOverrides addOverride(String key, float value, Function<ItemModelGenerator, Identifier> generator) {
return addOverride(Map.of(key, value), generator);
}
public ModelOverrides addOverride(Map<String, Float> predicate, Function<ItemModelGenerator, Identifier> generator) {
overrides.add(new Override(predicate, generator));
return this;
}
public Identifier upload(Item item, ItemModelGenerator generator) {
return upload(item, "", generator);
}
public Identifier upload(Item item, String suffex, ItemModelGenerator generator) {
return upload(ModelIds.getItemModelId(item), TextureMap.layer0(ModelIds.getItemSubModelId(item, suffex)), generator);
}
public Identifier upload(Identifier id, TextureMap textures, ItemModelGenerator generator) {
List<Pair<Identifier, Map<String, Float>>> overrides = this.overrides.stream()
.map(override -> new Pair<>(override.model().apply(generator), override.predicate()))
.toList();
return model.upload(id, textures, (a, jsonSupplier) -> {
generator.writer.accept(a, () -> Util.make(jsonSupplier.get(), json -> {
json.getAsJsonObject().add("overrides", Util.make(new JsonArray(), array -> {
overrides.forEach(override -> {
array.add(writeOverride(override.getLeft(), override.getRight(), new JsonObject()));
});
}));
}));
});
}
private JsonObject writeOverride(Identifier model, Map<String, Float> predicate, JsonObject json) {
json.addProperty("model", model.toString());
json.add("predicate", Util.make(new JsonObject(), output -> {
predicate.forEach(output::addProperty);
}));
return json;
}
private record Override(Map<String, Float> predicate, Function<ItemModelGenerator, Identifier> model) {
}
public interface ModelVariantSupplier {
Identifier upload(int index, float value);
}
}

View file

@ -0,0 +1,93 @@
package com.minelittlepony.unicopia.datagen.providers;
import java.util.concurrent.CompletableFuture;
import java.util.function.BiConsumer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.minelittlepony.unicopia.block.UBlocks;
import com.minelittlepony.unicopia.datagen.DataCollector;
import com.minelittlepony.unicopia.server.world.UTreeGen;
import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
import net.minecraft.block.Block;
import net.minecraft.data.DataOutput;
import net.minecraft.data.DataOutput.PathResolver;
import net.minecraft.registry.Registries;
import net.minecraft.data.DataProvider;
import net.minecraft.data.DataWriter;
public class SeasonsGrowthRatesProvider implements DataProvider {
private final PathResolver pathResolver;
public SeasonsGrowthRatesProvider(FabricDataOutput output) {
this.pathResolver = output.getResolver(DataOutput.OutputType.DATA_PACK, "seasons/crop");
}
@Override
public String getName() {
return "Seasons Growth Rates";
}
@Override
public CompletableFuture<?> run(DataWriter writer) {
DataCollector collectedData = new DataCollector(pathResolver);
var exporter = collectedData.prime();
generate((block, crop) -> {
exporter.accept(Registries.BLOCK.getId(block), crop::toJson);
});
return collectedData.upload(writer);
}
private void generate(BiConsumer<Block, Crop> exporter) {
Crop greenApple = new Crop(0.5F, 0.6F, 1, 0);
exporter.accept(UBlocks.GREEN_APPLE_LEAVES, greenApple);
exporter.accept(UBlocks.GREEN_APPLE_SPROUT, greenApple);
exporter.accept(UTreeGen.GREEN_APPLE_TREE.sapling().get(), greenApple);
Crop sourApple = new Crop(0.25F, 0.5F, 1, 0.5F);
exporter.accept(UBlocks.SOUR_APPLE_LEAVES, sourApple);
exporter.accept(UBlocks.SOUR_APPLE_SPROUT, sourApple);
exporter.accept(UTreeGen.SOUR_APPLE_TREE.sapling().get(), sourApple);
Crop sweetApple = new Crop(1, 1, 0.6F, 0);
exporter.accept(UBlocks.SWEET_APPLE_LEAVES, sweetApple);
exporter.accept(UBlocks.SWEET_APPLE_SPROUT, sweetApple);
exporter.accept(UTreeGen.SWEET_APPLE_TREE.sapling().get(), sweetApple);
Crop goldenOak = new Crop(1.5F, 1.4F, 0.6F, 0);
exporter.accept(UBlocks.GOLDEN_OAK_LEAVES, goldenOak);
exporter.accept(UBlocks.GOLDEN_OAK_SPROUT, goldenOak);
exporter.accept(UTreeGen.GOLDEN_APPLE_TREE.sapling().get(), goldenOak);
Crop palm = new Crop(1.1F, 0.9F, 0.2F, 0);
exporter.accept(UBlocks.PALM_LEAVES, palm);
exporter.accept(UBlocks.BANANAS, palm);
exporter.accept(UTreeGen.BANANA_TREE.sapling().get(), palm);
Crop mango = new Crop(1, 1.6F, 0.5F, 0);
exporter.accept(UBlocks.MANGO_LEAVES, mango);
exporter.accept(UTreeGen.MANGO_TREE.sapling().get(), mango);
Crop oats = new Crop(0.6F, 1, 1, 0);
exporter.accept(UBlocks.OATS_CROWN, oats);
exporter.accept(UBlocks.OATS_STEM, oats);
exporter.accept(UBlocks.OATS, oats);
exporter.accept(UBlocks.ROCKS, new Crop(1, 1, 1, 1));
exporter.accept(UBlocks.PINEAPPLE, palm);
}
record Crop(float spring, float summer, float fall, float winter) {
JsonElement toJson() {
JsonObject json = new JsonObject();
json.addProperty("spring", spring);
json.addProperty("summer", summer);
json.addProperty("winter", winter);
json.addProperty("fall", fall);
return json;
}
}
}

View file

@ -0,0 +1,51 @@
package com.minelittlepony.unicopia.datagen.providers;
import java.util.function.BiConsumer;
import java.util.function.Supplier;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.minelittlepony.unicopia.block.UBlocks;
import com.minelittlepony.unicopia.item.UItems;
import net.minecraft.data.client.BlockStateModelGenerator;
import net.minecraft.util.Identifier;
public class SeasonsModelGenerator extends UBlockStateModelGenerator {
private static final String[] SEASONS = { "fall", "summer", "winter" };
public SeasonsModelGenerator(BlockStateModelGenerator modelGenerator, BiConsumer<Identifier, Supplier<JsonElement>> seasonsModelConsumer) {
super(modelGenerator.blockStateCollector, (id, jsonSupplier) -> {
modelGenerator.modelCollector.accept(id, jsonSupplier);
seasonsModelConsumer.accept(id, () -> {
JsonObject textures = jsonSupplier.get().getAsJsonObject().getAsJsonObject("textures");
JsonObject seasonTextures = new JsonObject();
for (String season : SEASONS) {
seasonTextures.add(season, createTextures(season, textures));
}
JsonObject model = new JsonObject();
model.add("textures", seasonTextures);
return model;
});
}, modelGenerator::excludeFromSimpleItemModelGeneration);
}
private static JsonObject createTextures(String season, JsonObject input) {
JsonObject textures = new JsonObject();
input.entrySet().forEach(entry -> {
textures.addProperty(entry.getKey(), new Identifier(entry.getValue().getAsString()).withPath(path -> path.replace("/", "/seasons/" + season + "/")).toString());
});
return textures;
}
@Override
public void register() {
registerWithStages(UBlocks.OATS, UBlocks.OATS.getAgeProperty(), BlockModels.CROP, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11);
registerWithStages(UBlocks.OATS_STEM, UBlocks.OATS_STEM.getAgeProperty(), BlockModels.CROP, 0, 1, 2, 3, 4, 5, 6);
registerWithStages(UBlocks.OATS_CROWN, UBlocks.OATS_CROWN.getAgeProperty(), BlockModels.CROP, 0, 1);
registerItemModel(UItems.OATS);
registerItemModel(UItems.OAT_SEEDS);
}
}

View file

@ -0,0 +1,524 @@
package com.minelittlepony.unicopia.datagen.providers;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Supplier;
import com.google.gson.JsonElement;
import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.block.EdibleBlock;
import com.minelittlepony.unicopia.block.FruitBearingBlock;
import com.minelittlepony.unicopia.block.PieBlock;
import com.minelittlepony.unicopia.block.PileBlock;
import com.minelittlepony.unicopia.block.ShellsBlock;
import com.minelittlepony.unicopia.block.SlimePustuleBlock;
import com.minelittlepony.unicopia.block.UBlocks;
import com.minelittlepony.unicopia.block.zap.ZapAppleLeavesBlock;
import com.minelittlepony.unicopia.datagen.UBlockFamilies;
import com.minelittlepony.unicopia.server.world.Tree;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import net.minecraft.block.Block;
import net.minecraft.block.Blocks;
import net.minecraft.block.ConnectingBlock;
import net.minecraft.block.enums.DoorHinge;
import net.minecraft.block.enums.DoubleBlockHalf;
import net.minecraft.data.client.BlockStateModelGenerator;
import net.minecraft.data.client.BlockStateSupplier;
import net.minecraft.data.client.BlockStateVariant;
import net.minecraft.data.client.BlockStateVariantMap;
import net.minecraft.data.client.Model;
import net.minecraft.data.client.ModelIds;
import net.minecraft.data.client.Models;
import net.minecraft.data.client.MultipartBlockStateSupplier;
import net.minecraft.data.client.TextureMap;
import net.minecraft.data.client.TexturedModel;
import net.minecraft.data.client.VariantsBlockStateSupplier;
import net.minecraft.data.client.When;
import net.minecraft.item.Item;
import net.minecraft.item.Items;
import net.minecraft.registry.Registries;
import net.minecraft.registry.Registry;
import net.minecraft.state.property.BooleanProperty;
import net.minecraft.state.property.EnumProperty;
import net.minecraft.state.property.Properties;
import net.minecraft.state.property.Property;
import net.minecraft.util.Identifier;
import net.minecraft.util.Pair;
import net.minecraft.util.StringIdentifiable;
import net.minecraft.util.math.Direction;
import static net.minecraft.data.client.TextureKey.*;
import static net.minecraft.data.client.VariantSettings.*;
import static net.minecraft.data.client.VariantSettings.Rotation.*;
public class UBlockStateModelGenerator extends BlockStateModelGenerator {
static final Identifier AIR_BLOCK_ID = new Identifier("block/air");
static final Identifier AIR_ITEM_ID = new Identifier("item/air");
static UBlockStateModelGenerator create(BlockStateModelGenerator modelGenerator) {
return new UBlockStateModelGenerator(modelGenerator.blockStateCollector, modelGenerator.modelCollector, modelGenerator::excludeFromSimpleItemModelGeneration);
}
protected UBlockStateModelGenerator(BlockStateModelGenerator modelGenerator) {
this(modelGenerator.blockStateCollector, modelGenerator.modelCollector, modelGenerator::excludeFromSimpleItemModelGeneration);
}
public UBlockStateModelGenerator(
Consumer<BlockStateSupplier> blockStateCollector,
BiConsumer<Identifier, Supplier<JsonElement>> modelCollector,
Consumer<Block> simpleItemModelExemptionCollector) {
super(blockStateCollector, (id, jsonSupplier) -> {
if (AIR_BLOCK_ID.equals(id) || AIR_ITEM_ID.equals(id)) {
throw new IllegalStateException("Registered air id for block model: " + jsonSupplier.get().toString());
}
modelCollector.accept(id, jsonSupplier);
}, item -> simpleItemModelExemptionCollector.accept(Block.getBlockFromItem(item)));
}
@Override
public void register() {
for (int i = 0; i < Models.STEM_GROWTH_STAGES.length; i++) {
Models.STEM_GROWTH_STAGES[i].upload(Unicopia.id("block/apple_sprout_stage" + i), TextureMap.stem(Blocks.MELON_STEM), modelCollector);
}
// handmade
registerAll((g, block) -> g.registerParentedItemModel(block, ModelIds.getBlockModelId(block)), UBlocks.SHAPING_BENCH, UBlocks.SURFACE_CHITIN);
registerAll(UBlockStateModelGenerator::registerSimpleState, UBlocks.SHAPING_BENCH, UBlocks.BANANAS);
// doors
registerAll(UBlockStateModelGenerator::registerStableDoor, UBlocks.STABLE_DOOR, UBlocks.DARK_OAK_DOOR, UBlocks.CRYSTAL_DOOR, UBlocks.CLOUD_DOOR);
// cloud blocks
createCustomTexturePool(UBlocks.CLOUD, TexturedModel.CUBE_ALL).same(UBlocks.UNSTABLE_CLOUD).slab(UBlocks.CLOUD_SLAB).stairs(UBlocks.CLOUD_STAIRS);
createCustomTexturePool(UBlocks.ETCHED_CLOUD, TexturedModel.CUBE_ALL).slab(UBlocks.ETCHED_CLOUD_SLAB).stairs(UBlocks.ETCHED_CLOUD_STAIRS);
createCustomTexturePool(UBlocks.DENSE_CLOUD, TexturedModel.CUBE_ALL).slab(UBlocks.DENSE_CLOUD_SLAB).stairs(UBlocks.DENSE_CLOUD_STAIRS);
createCustomTexturePool(UBlocks.CLOUD_PLANKS, TexturedModel.CUBE_ALL).slab(UBlocks.CLOUD_PLANK_SLAB).stairs(UBlocks.CLOUD_PLANK_STAIRS);
createCustomTexturePool(UBlocks.CLOUD_BRICKS, TexturedModel.CUBE_ALL).slab(UBlocks.CLOUD_BRICK_SLAB).stairs(UBlocks.CLOUD_BRICK_STAIRS);
createTwoStepTexturePool(UBlocks.SOGGY_CLOUD, TexturedModel.CUBE_BOTTOM_TOP.andThen(textures -> textures.put(BOTTOM, ModelIds.getBlockModelId(UBlocks.CLOUD)))).slab(UBlocks.SOGGY_CLOUD_SLAB).stairs(UBlocks.SOGGY_CLOUD_STAIRS);
registerRotated(UBlocks.CARVED_CLOUD, TexturedModel.CUBE_COLUMN);
registerPillar(UBlocks.CLOUD_PILLAR);
registerAll(UBlockStateModelGenerator::registerCompactedBlock, UBlocks.COMPACTED_CLOUD, UBlocks.COMPACTED_CLOUD_BRICKS, UBlocks.COMPACTED_CLOUD_PLANKS, UBlocks.COMPACTED_DENSE_CLOUD, UBlocks.COMPACTED_ETCHED_CLOUD);
registerChest(UBlocks.CLOUD_CHEST, UBlocks.CLOUD);
registerFancyBed(UBlocks.CLOUD_BED, UBlocks.CLOUD);
registerFancyBed(UBlocks.CLOTH_BED, Blocks.SPRUCE_PLANKS);
// chitin blocks
registerTopsoil(UBlocks.SURFACE_CHITIN, UBlocks.CHITIN);
registerHollow(UBlocks.CHITIN);
registerCubeAllModelTexturePool(UBlocks.CHISELLED_CHITIN).stairs(UBlocks.CHISELLED_CHITIN_STAIRS).slab(UBlocks.CHISELLED_CHITIN_SLAB);
registerHiveBlock(UBlocks.HIVE);
registerRotated(UBlocks.CHITIN_SPIKES, BlockModels.SPIKES);
registerHull(UBlocks.CHISELLED_CHITIN_HULL, UBlocks.CHITIN, UBlocks.CHISELLED_CHITIN);
registerParentedItemModel(UBlocks.SLIME_PUSTULE, ModelIds.getBlockSubModelId(UBlocks.SLIME_PUSTULE, "_pod"));
blockStateCollector.accept(VariantsBlockStateSupplier.create(UBlocks.SLIME_PUSTULE)
.coordinate(BlockStateVariantMap.create(SlimePustuleBlock.SHAPE)
.register(state -> BlockStateVariant.create().put(MODEL, ModelIds.getBlockSubModelId(UBlocks.SLIME_PUSTULE, "_" + state.asString())))));
registerPie(UBlocks.APPLE_PIE);
// palm wood
registerLog(UBlocks.PALM_LOG).log(UBlocks.PALM_LOG).wood(UBlocks.PALM_WOOD);
registerLog(UBlocks.STRIPPED_PALM_LOG).log(UBlocks.STRIPPED_PALM_LOG).wood(UBlocks.STRIPPED_PALM_WOOD);
registerCubeAllModelTexturePool(UBlocks.PALM_PLANKS).family(UBlockFamilies.PALM);
registerHangingSign(UBlocks.STRIPPED_PALM_LOG, UBlocks.PALM_HANGING_SIGN, UBlocks.PALM_WALL_HANGING_SIGN);
registerSimpleCubeAll(UBlocks.PALM_LEAVES);
// zap wood
registerLog(UBlocks.ZAP_LOG)
.log(UBlocks.ZAP_LOG).wood(UBlocks.ZAP_WOOD)
.log(UBlocks.WAXED_ZAP_LOG).wood(UBlocks.WAXED_ZAP_WOOD);
registerLog(UBlocks.STRIPPED_ZAP_LOG)
.log(UBlocks.STRIPPED_ZAP_LOG).wood(UBlocks.STRIPPED_ZAP_WOOD)
.log(UBlocks.WAXED_STRIPPED_ZAP_LOG).wood(UBlocks.WAXED_STRIPPED_ZAP_WOOD);
registerCubeAllModelTexturePool(UBlocks.ZAP_PLANKS).family(UBlockFamilies.ZAP).same(UBlocks.WAXED_ZAP_PLANKS).family(UBlockFamilies.WAXED_ZAP);
registerZapLeaves(UBlocks.ZAP_LEAVES);
registerSingleton(UBlocks.FLOWERING_ZAP_LEAVES, TexturedModel.LEAVES);
registerStateWithModelReference(UBlocks.ZAP_LEAVES_PLACEHOLDER, Blocks.AIR);
// golden oak wood
registerSimpleCubeAll(UBlocks.GOLDEN_OAK_LEAVES);
registerLog(UBlocks.GOLDEN_OAK_LOG).log(UBlocks.GOLDEN_OAK_LOG);
// plants
Tree.REGISTRY.stream().filter(tree -> tree.sapling().isPresent()).forEach(tree -> registerFlowerPotPlant(tree.sapling().get(), tree.pot().get(), TintType.NOT_TINTED));
registerTintableCross(UBlocks.CURING_JOKE, TintType.NOT_TINTED);
registerWithStages(UBlocks.GOLD_ROOT, Properties.AGE_7, BlockModels.CROP, 0, 0, 1, 1, 2, 2, 2, 3);
registerTallCrop(UBlocks.PINEAPPLE, Properties.AGE_7, Properties.BLOCK_HALF,
new int[] { 0, 1, 2, 3, 4, 5, 5, 6 },
new int[] { 0, 0, 1, 2, 3, 4, 5, 6 }
);
registerPlunderVine(UBlocks.PLUNDER_VINE, UBlocks.PLUNDER_VINE_BUD);
// leaves
registerAll(UBlockStateModelGenerator::registerFloweringLeaves, UBlocks.GREEN_APPLE_LEAVES, UBlocks.SOUR_APPLE_LEAVES, UBlocks.SWEET_APPLE_LEAVES);
registerAll(UBlockStateModelGenerator::registerSprout, UBlocks.GREEN_APPLE_SPROUT, UBlocks.SOUR_APPLE_SPROUT, UBlocks.SWEET_APPLE_SPROUT, UBlocks.GOLDEN_OAK_SPROUT);
registerStateWithModelReference(UBlocks.MANGO_LEAVES, Blocks.JUNGLE_LEAVES);
registerParentedItemModel(UBlocks.MANGO_LEAVES, ModelIds.getBlockModelId(Blocks.JUNGLE_LEAVES));
// fruit
UModelProvider.FRUITS.forEach((block, item) -> registerSingleton(block, TextureMap.cross(ModelIds.getItemModelId(item)), BlockModels.FRUIT));
// bales
registerAll((g, block) -> g.registerBale(Unicopia.id(block.getLeft().getPath().replace("bale", "block")), block.getLeft(), block.getRight()),
new Pair<>(new Identifier("hay_block"), "_top"),
new Pair<>(new Identifier("farmersdelight", "rice_bale"), "_top"),
new Pair<>(new Identifier("farmersdelight", "straw_bale"), "_end")
);
// shells
registerAll(UBlockStateModelGenerator::registerShell, UBlocks.CLAM_SHELL, UBlocks.TURRET_SHELL, UBlocks.SCALLOP_SHELL);
// other
registerBuiltinWithParticle(UBlocks.WEATHER_VANE, UBlocks.WEATHER_VANE.asItem());
registerWithStages(UBlocks.FROSTED_OBSIDIAN, Properties.AGE_3, BlockModels.CUBE_ALL, 0, 1, 2, 3);
registerWithStagesBuiltinModels(UBlocks.ROCKS, Properties.AGE_7, 0, 1, 2, 3, 4, 5, 6, 7);
registerWithStagesBuiltinModels(UBlocks.MYSTERIOUS_EGG, PileBlock.COUNT, 1, 2, 3);
excludeFromSimpleItemModelGeneration(UBlocks.MYSTERIOUS_EGG);
FireModels.registerSoulFire(this, UBlocks.SPECTRAL_FIRE, Blocks.SOUL_FIRE);
}
@SafeVarargs
public final <T> UBlockStateModelGenerator registerAll(BiConsumer<? super UBlockStateModelGenerator, T> register, T... blocks) {
for (T block : blocks) {
register.accept(this, block);
}
return this;
}
@Override
public void registerParentedItemModel(Block block, Identifier parentModelId) {
Item item = block.asItem();
if (item != Items.AIR) {
registerParentedItemModel(item, parentModelId);
}
}
public BlockTexturePool createCustomTexturePool(Block block, TexturedModel.Factory modelFactory) {
final TexturedModel texturedModel = modelFactory.get(block);
final TextureMap textures = texturedModel.getTextures();
return (new BlockTexturePool(textures) {
@Override
public BlockTexturePool stairs(Block block) {
TextureMap textMap = textures.copyAndAdd(BlockModels.STEP, textures.getTexture(SIDE));
Identifier inner = BlockModels.INNER_STAIRS.upload(block, textMap, modelCollector);
Identifier straight = BlockModels.STRAIGHT_STAIRS.upload(block, textMap, modelCollector);
Identifier outer = BlockModels.OUTER_STAIRS.upload(block, textMap, modelCollector);
blockStateCollector.accept(BlockStateModelGenerator.createStairsBlockState(block, inner, straight, outer));
registerParentedItemModel(block, straight);
return this;
}
}).base(block, texturedModel.getModel());
}
public BlockTexturePool createTwoStepTexturePool(Block block, TexturedModel.Factory modelFactory) {
final TexturedModel texturedModel = modelFactory.get(block);
final TextureMap textures = texturedModel.getTextures();
final Identifier baseModelId = ModelIds.getBlockModelId(block);
final Identifier twoStepTexture = ModelIds.getBlockSubModelId(block, "_slab_side");
return (new BlockTexturePool(textures) {
@Override
public BlockTexturePool stairs(Block block) {
TextureMap textMap = textures.copyAndAdd(BlockModels.STEP, twoStepTexture);
Identifier inner = BlockModels.INNER_STAIRS.upload(block, textMap, modelCollector);
Identifier straight = BlockModels.STRAIGHT_STAIRS.upload(block, textMap, modelCollector);
Identifier outer = BlockModels.OUTER_STAIRS.upload(block, textMap, modelCollector);
blockStateCollector.accept(BlockStateModelGenerator.createStairsBlockState(block, inner, straight, outer));
registerParentedItemModel(block, straight);
return this;
}
@Override
public BlockTexturePool slab(Block block) {
TextureMap textMap = textures.copyAndAdd(SIDE, twoStepTexture);
Identifier lower = Models.SLAB.upload(block, textMap, modelCollector);
Identifier upper = Models.SLAB_TOP.upload(block, textMap, modelCollector);
blockStateCollector.accept(BlockStateModelGenerator.createSlabBlockState(block, lower, upper, baseModelId));
registerParentedItemModel(block, lower);
return this;
}
}).base(block, texturedModel.getModel());
}
public void registerTopsoil(Block block, Block dirt) {
TexturedModel model = TexturedModel.CUBE_BOTTOM_TOP.get(dirt);
registerTopSoil(block,
model.upload(block, modelCollector),
BlockStateVariant.create().put(MODEL, Models.CUBE_BOTTOM_TOP.upload(dirt, "_snow", model.getTextures()
.copyAndAdd(SIDE, ModelIds.getBlockSubModelId(dirt, "_side_snow_covered")
), modelCollector))
);
}
public void registerHollow(Block block) {
Identifier outside = ModelIds.getBlockModelId(UBlocks.CHITIN);
Identifier inside = ModelIds.getBlockSubModelId(UBlocks.CHITIN, "_bottom");
registerSingleton(UBlocks.CHITIN, new TextureMap()
.put(SIDE, outside)
.put(TOP, outside)
.put(BOTTOM, inside), Models.CUBE_BOTTOM_TOP);
}
public void registerRotated(Block block, TexturedModel.Factory modelFactory) {
Identifier modelId = modelFactory.get(block).upload(block, modelCollector);
blockStateCollector.accept(VariantsBlockStateSupplier.create(block, BlockStateVariant.create()
.put(MODEL, modelId))
.coordinate(createUpDefaultFacingVariantMap()));
}
public void registerPlunderVine(Block plant, Block bud) {
var rotationVariants = BlockStateVariantMap.create(Properties.FACING);
createDownDefaultFacingVariantMap(rotationVariants::register);
blockStateCollector.accept(VariantsBlockStateSupplier.create(bud, BlockStateVariant.create()
.put(MODEL, ModelIds.getBlockModelId(bud)))
.coordinate(rotationVariants));
var supplier = MultipartBlockStateSupplier.create(plant);
String[] stages = { "", "_2", "_3", "_4", "_4"};
Properties.AGE_4.getValues().forEach(age -> {
Identifier modelId = ModelIds.getBlockSubModelId(plant, "_branch" + stages[age]);
createDownDefaultFacingVariantMap((direction, variant) -> {
supplier.with(When.create().set(Properties.AGE_4, age).set(ConnectingBlock.FACING_PROPERTIES.get(direction), true), variant.put(MODEL, modelId));
});
});
blockStateCollector.accept(supplier);
registerParentedItemModel(bud, ModelIds.getBlockModelId(bud));
}
public final void createDownDefaultFacingVariantMap(BiConsumer<Direction, BlockStateVariant> builder) {
builder.accept(Direction.DOWN, BlockStateVariant.create());
builder.accept(Direction.UP, BlockStateVariant.create().put(X, R180));
builder.accept(Direction.SOUTH, BlockStateVariant.create().put(X, R90));
builder.accept(Direction.NORTH, BlockStateVariant.create().put(X, R90).put(Y, R180));
builder.accept(Direction.EAST, BlockStateVariant.create().put(X, R90).put(Y, R270));
builder.accept(Direction.WEST, BlockStateVariant.create().put(X, R90).put(Y, R90));
}
public void registerCompactedBlock(Block block) {
for (Model model : BlockModels.FLATTENED_MODELS) {
model.upload(block, TextureMap.all(ModelIds.getBlockModelId(block).withPath(p -> p.replace("compacted_", ""))), modelCollector);
}
MultipartBlockStateSupplier supplier = MultipartBlockStateSupplier.create(block);
for (byte i = 0; i < BlockModels.FLATTENED_MODEL_ROTATIONS.length; i++) {
final BooleanProperty yAxis = (i & 0b100) == 0 ? Properties.DOWN : Properties.UP;
final BooleanProperty xAxis = (i & 0b010) == 0 ? Properties.NORTH: Properties.SOUTH;
final BooleanProperty zAxis = (i & 0b001) == 0 ? Properties.EAST : Properties.WEST;
final Rotation xRot = yAxis == Properties.DOWN ? R0 : R180;
final Rotation yRot = BlockModels.FLATTENED_MODEL_ROTATIONS[i];
final String[] suffexes = yRot.ordinal() % 2 == 0 ? BlockModels.FLATTENED_MODEL_SUFFEXES : BlockModels.FLATTENED_MODEL_SUFFEXES_ROT;
for (byte v = 0; v < suffexes.length; v++) {
supplier.with(When.create()
.set(yAxis, (v & 0b100) != 0)
.set(xAxis, (v & 0b010) != 0)
.set(zAxis, (v & 0b001) != 0), BlockStateVariant.create()
.put(MODEL, ModelIds.getBlockSubModelId(block, "_corner_" + suffexes[v]))
.put(UVLOCK, true)
.put(X, xRot)
.put(Y, yRot)
);
}
}
blockStateCollector.accept(supplier);
}
public void registerChest(Block chest, Block particleSource) {
registerBuiltin(ModelIds.getBlockModelId(chest), particleSource).includeWithoutItem(chest);
ItemModels.CHEST.upload(ModelIds.getItemModelId(chest.asItem()), TextureMap.particle(particleSource), modelCollector);
}
public void registerFancyBed(Block bed, Block particleSource) {
registerBuiltinWithParticle(bed, ModelIds.getBlockModelId(particleSource));
super.registerBed(bed, particleSource);
}
public void registerStableDoor(Block door) {
TextureMap topTextures = TextureMap.topBottom(door);
TextureMap bottomTextures = topTextures.copyAndAdd(TOP, topTextures.getTexture(BOTTOM));
registerItemModel(door.asItem());
var variants = BlockStateVariantMap.create(Properties.HORIZONTAL_FACING, Properties.DOUBLE_BLOCK_HALF, Properties.DOOR_HINGE, Properties.OPEN);
fillStableDoorVariantMap(variants, DoubleBlockHalf.LOWER,
BlockModels.DOOR_LEFT.upload(door, "_bottom_left", bottomTextures, modelCollector),
BlockModels.DOOR_RIGHT.upload(door, "_bottom_right", bottomTextures, modelCollector)
);
fillStableDoorVariantMap(variants, DoubleBlockHalf.UPPER,
BlockModels.DOOR_LEFT.upload(door, "_top_left", topTextures, modelCollector),
BlockModels.DOOR_RIGHT.upload(door, "_top_right", topTextures, modelCollector)
);
blockStateCollector.accept(VariantsBlockStateSupplier.create(door).coordinate(variants));
}
public static void fillStableDoorVariantMap(
BlockStateVariantMap.QuadrupleProperty<Direction, DoubleBlockHalf, DoorHinge, Boolean> variantMap,
DoubleBlockHalf targetHalf, Identifier leftModelId, Identifier rightModelId) {
fillStableDoorVariantMap(variantMap, targetHalf, DoorHinge.LEFT, false, R0, leftModelId);
fillStableDoorVariantMap(variantMap, targetHalf, DoorHinge.RIGHT, false, R0, rightModelId);
fillStableDoorVariantMap(variantMap, targetHalf, DoorHinge.LEFT, true, R90, rightModelId);
fillStableDoorVariantMap(variantMap, targetHalf, DoorHinge.RIGHT, true, R270, leftModelId);
}
public static void fillStableDoorVariantMap(
BlockStateVariantMap.QuadrupleProperty<Direction, DoubleBlockHalf, DoorHinge, Boolean> variantMap,
DoubleBlockHalf targetHalf,
DoorHinge hinge, boolean open, Rotation rotation,
Identifier modelId) {
for (int i = 0; i < BlockRotation.DIRECTIONS.length; i++) {
variantMap.register(BlockRotation.DIRECTIONS[i], targetHalf, hinge, open, BlockStateVariant.create()
.put(MODEL, modelId)
.put(Y, BlockRotation.cycle(rotation, i))
);
}
}
public void registerPillar(Block pillar) {
TextureMap textures = new TextureMap()
.put(SIDE, ModelIds.getBlockSubModelId(pillar, "_side"))
.put(TOP, ModelIds.getBlockSubModelId(pillar, "_lip"))
.put(BOTTOM, ModelIds.getBlockSubModelId(pillar, "_end"))
.put(END, ModelIds.getBlockSubModelId(pillar, "_side_end"));
Identifier middle = BlockModels.TEMPLATE_PILLAR.upload(pillar, textures, modelCollector);
Identifier end = BlockModels.TEMPLATE_PILLAR_END.upload(pillar, textures, modelCollector);
blockStateCollector.accept(MultipartBlockStateSupplier.create(pillar)
.with(BlockStateVariant.create().put(MODEL, middle))
.with(When.create().set(Properties.NORTH, false), BlockStateVariant.create().put(MODEL, end).put(UVLOCK, true).put(X, R180))
.with(When.create().set(Properties.SOUTH, false), BlockStateVariant.create().put(MODEL, end))
);
ItemModels.TEMPLATE_PILLAR.upload(ModelIds.getItemModelId(pillar.asItem()), textures, modelCollector);
}
public void registerHiveBlock(Block hive) {
Identifier core = ModelIds.getBlockSubModelId(hive, "_core");
Identifier side = ModelIds.getBlockSubModelId(hive, "_side");
blockStateCollector.accept(MultipartBlockStateSupplier.create(hive)
.with(BlockStateVariant.create().put(MODEL, core))
.with(When.create().set(Properties.NORTH, true), BlockStateVariant.create().put(MODEL, side).put(UVLOCK, true))
.with(When.create().set(Properties.EAST, true), BlockStateVariant.create().put(MODEL, side).put(UVLOCK, true).put(Y, R90))
.with(When.create().set(Properties.SOUTH, true), BlockStateVariant.create().put(MODEL, side).put(UVLOCK, true).put(Y, R180))
.with(When.create().set(Properties.WEST, true), BlockStateVariant.create().put(MODEL, side).put(UVLOCK, true).put(Y, R270))
.with(When.create().set(Properties.DOWN, true), BlockStateVariant.create().put(MODEL, side).put(UVLOCK, true).put(X, R90))
.with(When.create().set(Properties.UP, true), BlockStateVariant.create().put(MODEL, side).put(UVLOCK, true).put(X, R270)));
Models.CUBE_ALL.upload(ModelIds.getItemModelId(hive.asItem()), TextureMap.all(ModelIds.getBlockSubModelId(hive, "_side")), modelCollector);
}
public void registerBale(Identifier blockId, Identifier baseBlockId, String endSuffex) {
Identifier top = baseBlockId.withPath(p -> "block/" + p + endSuffex);
Identifier side = baseBlockId.withPath(p -> "block/" + p + "_side");
TextureMap textures = new TextureMap().put(TOP, top).put(SIDE, side);
MultipartBlockStateSupplier supplier = MultipartBlockStateSupplier.create(Registries.BLOCK.getOrEmpty(blockId).orElseGet(() -> {
return Registry.register(Registries.BLOCK, blockId, new EdibleBlock(blockId, blockId, false));
}));
Map<Integer, Identifier> uploadedModels = new HashMap<>();
for (Direction.Axis axis : Direction.Axis.VALUES) {
for (int i = 0; i < EdibleBlock.SEGMENTS.length; i++) {
BooleanProperty segment = EdibleBlock.SEGMENTS[i];
segment.getName();
supplier.with(When.create().set(EdibleBlock.AXIS, axis).set(segment, true), BlockStateVariant.create()
.put(MODEL, uploadedModels.computeIfAbsent(i, ii -> {
return BlockModels.BALE_MODELS[ii].getLeft().upload(blockId.withPath(p -> "block/" + p + BlockModels.BALE_MODELS[ii].getRight()), textures, modelCollector);
}))
.put(X, axis == Direction.Axis.Y ? R0 : R90)
.put(Y, axis == Direction.Axis.X ? R90 : R0)
);
}
}
blockStateCollector.accept(supplier);
}
public void registerWithStages(Block crop, Property<Integer> ageProperty, BlockModels.Factory modelFactory, int ... stages) {
if (ageProperty.getValues().size() != stages.length) {
throw new IllegalArgumentException();
}
int offset = ageProperty.getValues().iterator().next();
Int2ObjectOpenHashMap<Identifier> uploadedModels = new Int2ObjectOpenHashMap<>();
blockStateCollector.accept(VariantsBlockStateSupplier.create(crop)
.coordinate(BlockStateVariantMap.create(ageProperty)
.register(age -> BlockStateVariant.create().put(MODEL, uploadedModels.computeIfAbsent(stages[age - offset], stage -> {
return modelFactory.upload(crop, "_stage" + stage, modelCollector);
})))));
}
public void registerWithStagesBuiltinModels(Block crop, Property<Integer> ageProperty, int ... stages) {
if (ageProperty.getValues().size() != stages.length) {
throw new IllegalArgumentException();
}
int offset = ageProperty.getValues().iterator().next();
blockStateCollector.accept(VariantsBlockStateSupplier.create(crop)
.coordinate(BlockStateVariantMap.create(ageProperty)
.register(age -> BlockStateVariant.create().put(MODEL, ModelIds.getBlockSubModelId(crop, "_stage" + stages[age - offset])))));
}
public <T extends Enum<T> & StringIdentifiable> void registerTallCrop(Block crop,
Property<Integer> ageProperty,
EnumProperty<T> partProperty,
int[] ... ageTextureIndices) {
Map<String, Identifier> uploadedModels = new HashMap<>();
blockStateCollector.accept(VariantsBlockStateSupplier.create(crop).coordinate(BlockStateVariantMap.create(partProperty, ageProperty).register((part, age) -> {
int i = ageTextureIndices[part.ordinal()][age];
Identifier identifier = uploadedModels.computeIfAbsent("_" + part.asString() + "_stage" + i, variant -> createSubModel(crop, variant, Models.CROSS, TextureMap::cross));
return BlockStateVariant.create().put(MODEL, identifier);
})));
}
public void registerPie(Block pie) {
TextureMap textures = new TextureMap()
.put(TOP, ModelIds.getBlockSubModelId(pie, "_top"))
.put(BOTTOM, ModelIds.getBlockSubModelId(pie, "_bottom"))
.put(SIDE, ModelIds.getBlockSubModelId(pie, "_side"))
.put(INSIDE, ModelIds.getBlockSubModelId(pie, "_inside"));
TextureMap stompedTextures = textures.copyAndAdd(TOP, ModelIds.getBlockSubModelId(pie, "_top_stomped"));
blockStateCollector.accept(VariantsBlockStateSupplier.create(pie).coordinate(BlockStateVariantMap.create(PieBlock.BITES, PieBlock.STOMPED).register((bites, stomped) -> {
return BlockStateVariant.create().put(MODEL, BlockModels.PIE_MODELS[bites].upload(pie, (stomped ? "_stomped" : ""), stomped ? stompedTextures : textures, modelCollector));
})));
}
public void registerFloweringLeaves(Block block) {
Identifier baseModel = TexturedModel.LEAVES.upload(block, modelCollector);
Identifier floweringModel = Models.CUBE_ALL.upload(block, "_flowering", TextureMap.of(ALL, ModelIds.getBlockSubModelId(block, "_flowering")), modelCollector);
blockStateCollector.accept(MultipartBlockStateSupplier.create(block)
.with(BlockStateVariant.create().put(MODEL, baseModel))
.with(When.create().set(FruitBearingBlock.STAGE, FruitBearingBlock.Stage.FLOWERING), BlockStateVariant.create().put(MODEL, floweringModel)));
}
public void registerZapLeaves(Block block) {
Identifier baseModel = TexturedModel.LEAVES.upload(block, modelCollector);
Identifier floweringModel = Registries.BLOCK.getId(block).withPrefixedPath("block/flowering_");
Identifier airModel = ModelIds.getBlockModelId(Blocks.AIR);
blockStateCollector.accept(VariantsBlockStateSupplier.create(block)
.coordinate(BlockStateVariantMap.create(ZapAppleLeavesBlock.STAGE)
.register(stage -> BlockStateVariant.create()
.put(MODEL, switch (stage) {
case HIBERNATING -> airModel;
case FLOWERING -> floweringModel;
default -> baseModel;
}))));
}
public void registerSprout(Block sprout) {
blockStateCollector.accept(VariantsBlockStateSupplier.create(sprout)
.coordinate(BlockStateVariantMap.create(Properties.AGE_7)
.register(age -> BlockStateVariant.create()
.put(MODEL, Unicopia.id("block/apple_sprout_stage" + age)))));
}
public void registerShell(Block shell) {
blockStateCollector.accept(VariantsBlockStateSupplier.create(shell)
.coordinate(BlockStateVariantMap.create(ShellsBlock.COUNT)
.register(count -> BlockStateVariant.create()
.put(MODEL, BlockModels.SHELL_MODELS[count - 1].upload(shell, TextureMap.of(BlockModels.SHELL, Registries.BLOCK.getId(shell).withPrefixedPath("item/")), modelCollector)))));
}
public void registerHull(Block block, Block core, Block shell) {
blockStateCollector.accept(VariantsBlockStateSupplier.create(
block,
BlockStateVariant.create().put(MODEL, Models.CUBE_BOTTOM_TOP.upload(block, new TextureMap()
.put(BOTTOM, ModelIds.getBlockModelId(core))
.put(TOP, ModelIds.getBlockModelId(shell))
.put(SIDE, ModelIds.getBlockSubModelId(shell, "_half")), modelCollector))
).coordinate(createUpDefaultFacingVariantMap()));
}
}

View file

@ -0,0 +1,204 @@
package com.minelittlepony.unicopia.datagen.providers;
import java.util.concurrent.CompletableFuture;
import com.minelittlepony.unicopia.UTags;
import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.block.UBlocks;
import com.minelittlepony.unicopia.server.world.Tree;
import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricTagProvider;
import net.fabricmc.fabric.api.tag.convention.v1.ConventionalBlockTags;
import net.minecraft.block.Block;
import net.minecraft.block.Blocks;
import net.minecraft.registry.RegistryKeys;
import net.minecraft.registry.RegistryWrapper;
import net.minecraft.registry.RegistryWrapper.WrapperLookup;
import net.minecraft.registry.tag.BlockTags;
import net.minecraft.registry.tag.TagBuilder;
import net.minecraft.registry.tag.TagKey;
import net.minecraft.util.Identifier;
public class UBlockTagProvider extends FabricTagProvider.BlockTagProvider {
public UBlockTagProvider(FabricDataOutput output, CompletableFuture<RegistryWrapper.WrapperLookup> registriesFuture) {
super(output, registriesFuture);
}
@Override
protected TagBuilder getTagBuilder(TagKey<Block> tag) {
return super.getTagBuilder(tag);
}
@Override
protected void configure(WrapperLookup registries) {
Block[] crops = {
UBlocks.OATS, UBlocks.OATS_STEM, UBlocks.OATS_CROWN,
UBlocks.ROCKS, UBlocks.PINEAPPLE,
UBlocks.SWEET_APPLE_SPROUT, UBlocks.GREEN_APPLE_SPROUT, UBlocks.SWEET_APPLE_SPROUT,
UBlocks.GOLDEN_OAK_SPROUT
};
getOrCreateTagBuilder(UTags.CATAPULT_IMMUNE).add(Blocks.BEDROCK).forceAddTag(BlockTags.DOORS).forceAddTag(BlockTags.TRAPDOORS);
getOrCreateTagBuilder(BlockTags.CROPS).add(crops);
getOrCreateTagBuilder(BlockTags.BEE_GROWABLES).add(crops);
getOrCreateTagBuilder(BlockTags.MAINTAINS_FARMLAND).add(crops);
getOrCreateTagBuilder(BlockTags.NEEDS_DIAMOND_TOOL).add(UBlocks.FROSTED_OBSIDIAN);
getOrCreateTagBuilder(BlockTags.PICKAXE_MINEABLE).add(UBlocks.ROCKS, UBlocks.FROSTED_OBSIDIAN, UBlocks.WEATHER_VANE);
getOrCreateTagBuilder(BlockTags.DRAGON_IMMUNE).add(UBlocks.FROSTED_OBSIDIAN, UBlocks.GOLDEN_OAK_LOG, UBlocks.GOLDEN_OAK_LEAVES);
getOrCreateTagBuilder(BlockTags.FIRE).add(UBlocks.SPECTRAL_FIRE);
getOrCreateTagBuilder(BlockTags.HOE_MINEABLE).add(UBlocks.HAY_BLOCK).addOptional(Unicopia.id("rice_block")).addOptional(Unicopia.id("straw_block"));
addZapWoodset();
addPalmWoodset();
addCloudBlocksets();
addChitinBlocksets();
addFruitTrees();
getOrCreateTagBuilder(UTags.CRYSTAL_HEART_BASE).add(
Blocks.DIAMOND_BLOCK,
Blocks.QUARTZ_BLOCK, Blocks.QUARTZ_BRICKS, Blocks.QUARTZ_SLAB, Blocks.QUARTZ_STAIRS, Blocks.QUARTZ_PILLAR,
Blocks.SMOOTH_QUARTZ, Blocks.SMOOTH_QUARTZ_SLAB, Blocks.SMOOTH_QUARTZ_STAIRS, Blocks.CHISELED_QUARTZ_BLOCK,
Blocks.AMETHYST_BLOCK, Blocks.NETHERITE_BLOCK, Blocks.EMERALD_BLOCK
);
getOrCreateTagBuilder(UTags.CRYSTAL_HEART_ORNAMENT).add(Blocks.END_ROD);
getOrCreateTagBuilder(UTags.FRAGILE)
.forceAddTag(ConventionalBlockTags.GLASS_BLOCKS)
.forceAddTag(ConventionalBlockTags.GLASS_PANES)
.add(Blocks.VINE, Blocks.LILY_PAD);
getOrCreateTagBuilder(UTags.INTERESTING).add(
Blocks.SEA_LANTERN, Blocks.ENDER_CHEST, Blocks.END_PORTAL_FRAME,
Blocks.JUKEBOX, Blocks.SPAWNER
).forceAddTag(ConventionalBlockTags.ORES);
getOrCreateTagBuilder(UTags.KICKS_UP_DUST).forceAddTag(BlockTags.SAND).add(
Blocks.SUSPICIOUS_SAND,
Blocks.GRAVEL, Blocks.SUSPICIOUS_GRAVEL
).forceAddTag(TagKey.of(RegistryKeys.BLOCK, new Identifier("c", "concrete_powders")));
getOrCreateTagBuilder(UTags.UNAFFECTED_BY_GROW_ABILITY).add(Blocks.GRASS_BLOCK);
}
private void addFruitTrees() {
Block[] leaves = {
UBlocks.GREEN_APPLE_LEAVES, UBlocks.SWEET_APPLE_LEAVES, UBlocks.SOUR_APPLE_LEAVES,
UBlocks.GOLDEN_OAK_LEAVES, UBlocks.MANGO_LEAVES
};
getOrCreateTagBuilder(BlockTags.LEAVES).add(leaves);
getOrCreateTagBuilder(BlockTags.HOE_MINEABLE).add(leaves);
Block[] burnableLogs = { UBlocks.GOLDEN_OAK_LOG };
getOrCreateTagBuilder(BlockTags.LOGS).add(burnableLogs);
getOrCreateTagBuilder(BlockTags.LOGS_THAT_BURN).add(burnableLogs);
var saplings = Tree.REGISTRY.stream().flatMap(tree -> tree.sapling().stream()).toArray(Block[]::new);
getOrCreateTagBuilder(BlockTags.SAPLINGS).add(saplings);
getOrCreateTagBuilder(BlockTags.MAINTAINS_FARMLAND).add(saplings);
getOrCreateTagBuilder(BlockTags.GUARDED_BY_PIGLINS).add(UBlocks.GOLDEN_OAK_LEAVES, UBlocks.GOLDEN_OAK_LOG, UBlocks.GOLDEN_OAK_SPROUT, UBlocks.GOLDEN_APPLE);
}
private void addZapWoodset() {
getOrCreateTagBuilder(BlockTags.LEAVES).add(UBlocks.ZAP_LEAVES, UBlocks.FLOWERING_ZAP_LEAVES);
getOrCreateTagBuilder(UTags.POLEARM_MINEABLE).add(
UBlocks.ZAP_LEAVES, UBlocks.FLOWERING_ZAP_LEAVES,
UBlocks.ZAP_PLANKS,
UBlocks.ZAP_LOG, UBlocks.ZAP_WOOD, UBlocks.STRIPPED_ZAP_LOG, UBlocks.STRIPPED_ZAP_WOOD,
UBlocks.ZAP_FENCE_GATE, UBlocks.ZAP_FENCE,
UBlocks.ZAP_SLAB,
UBlocks.ZAP_STAIRS
);
getOrCreateTagBuilder(UTags.Blocks.ZAP_LOGS).add(UBlocks.ZAP_LOG, UBlocks.ZAP_WOOD, UBlocks.STRIPPED_ZAP_LOG, UBlocks.STRIPPED_ZAP_WOOD);
getOrCreateTagBuilder(UTags.Blocks.WAXED_ZAP_LOGS).add(UBlocks.WAXED_ZAP_LOG, UBlocks.WAXED_ZAP_WOOD, UBlocks.WAXED_STRIPPED_ZAP_LOG, UBlocks.WAXED_STRIPPED_ZAP_WOOD);
getOrCreateTagBuilder(BlockTags.LOGS).forceAddTag(UTags.Blocks.ZAP_LOGS).forceAddTag(UTags.Blocks.WAXED_ZAP_LOGS);
getOrCreateTagBuilder(BlockTags.LOGS_THAT_BURN).forceAddTag(UTags.Blocks.ZAP_LOGS);
getOrCreateTagBuilder(BlockTags.PLANKS).add(UBlocks.ZAP_PLANKS, UBlocks.WAXED_ZAP_PLANKS);
//getOrCreateTagBuilder(BlockTags.WOODEN_BUTTONS).add(UBlocks.ZAP_BUTTON);
//getOrCreateTagBuilder(BlockTags.WOODEN_DOORS).add(UBlocks.ZAP_DOOR);
getOrCreateTagBuilder(BlockTags.FENCE_GATES).add(UBlocks.ZAP_FENCE_GATE, UBlocks.WAXED_ZAP_FENCE_GATE);
getOrCreateTagBuilder(BlockTags.WOODEN_FENCES).add(UBlocks.ZAP_FENCE, UBlocks.WAXED_ZAP_FENCE);
//getOrCreateTagBuilder(BlockTags.PRESSURE_PLATES).add(UBlocks.ZAP_PRESSURE_PLATE);
//getOrCreateTagBuilder(BlockTags.WOODEN_PRESSURE_PLATES).add(UBlocks.ZAP_PRESSURE_PLATE);
getOrCreateTagBuilder(BlockTags.SLABS).add(UBlocks.ZAP_SLAB, UBlocks.WAXED_ZAP_SLAB);
getOrCreateTagBuilder(BlockTags.WOODEN_SLABS).add(UBlocks.ZAP_SLAB, UBlocks.WAXED_ZAP_SLAB);
getOrCreateTagBuilder(BlockTags.STAIRS).add(UBlocks.ZAP_STAIRS, UBlocks.WAXED_ZAP_STAIRS);
getOrCreateTagBuilder(BlockTags.WOODEN_STAIRS).add(UBlocks.ZAP_STAIRS, UBlocks.WAXED_ZAP_STAIRS);
//getOrCreateTagBuilder(BlockTags.TRAPDOORS).add(UBlocks.ZAP_TRAPDOOR);
//getOrCreateTagBuilder(BlockTags.WOODEN_TRAPDOORS).add(UBlocks.ZAP_TRAPDOOR);
}
private void addPalmWoodset() {
getOrCreateTagBuilder(BlockTags.LEAVES).add(UBlocks.PALM_LEAVES);
getOrCreateTagBuilder(BlockTags.HOE_MINEABLE).add(UBlocks.PALM_LEAVES);
getOrCreateTagBuilder(UTags.Blocks.PALM_LOGS).add(UBlocks.PALM_LOG, UBlocks.PALM_WOOD, UBlocks.STRIPPED_PALM_LOG, UBlocks.STRIPPED_PALM_WOOD);
getOrCreateTagBuilder(BlockTags.LOGS).forceAddTag(UTags.Blocks.PALM_LOGS);
getOrCreateTagBuilder(BlockTags.LOGS_THAT_BURN).forceAddTag(UTags.Blocks.PALM_LOGS);
getOrCreateTagBuilder(BlockTags.PLANKS).add(UBlocks.PALM_PLANKS);
addSign(UBlocks.PALM_SIGN, UBlocks.PALM_WALL_SIGN, UBlocks.PALM_HANGING_SIGN, UBlocks.PALM_WALL_HANGING_SIGN);
getOrCreateTagBuilder(BlockTags.WOODEN_BUTTONS).add(UBlocks.PALM_BUTTON);
getOrCreateTagBuilder(BlockTags.WOODEN_DOORS).add(UBlocks.PALM_DOOR);
getOrCreateTagBuilder(BlockTags.FENCE_GATES).add(UBlocks.PALM_FENCE_GATE);
getOrCreateTagBuilder(BlockTags.WOODEN_FENCES).add(UBlocks.PALM_FENCE);
getOrCreateTagBuilder(BlockTags.PRESSURE_PLATES).add(UBlocks.PALM_PRESSURE_PLATE);
getOrCreateTagBuilder(BlockTags.WOODEN_PRESSURE_PLATES).add(UBlocks.PALM_PRESSURE_PLATE);
getOrCreateTagBuilder(BlockTags.SLABS).add(UBlocks.PALM_SLAB);
getOrCreateTagBuilder(BlockTags.WOODEN_SLABS).add(UBlocks.PALM_SLAB);
getOrCreateTagBuilder(BlockTags.STAIRS).add(UBlocks.PALM_STAIRS);
getOrCreateTagBuilder(BlockTags.WOODEN_STAIRS).add(UBlocks.PALM_STAIRS);
getOrCreateTagBuilder(BlockTags.TRAPDOORS).add(UBlocks.PALM_TRAPDOOR);
getOrCreateTagBuilder(BlockTags.WOODEN_TRAPDOORS).add(UBlocks.PALM_TRAPDOOR);
}
private void addCloudBlocksets() {
getOrCreateTagBuilder(BlockTags.PICKAXE_MINEABLE).add(
UBlocks.CLOUD_BRICKS, UBlocks.CLOUD_BRICK_SLAB, UBlocks.CLOUD_BRICK_STAIRS, UBlocks.COMPACTED_CLOUD_BRICKS, UBlocks.CARVED_CLOUD
);
getOrCreateTagBuilder(BlockTags.AXE_MINEABLE).add(
UBlocks.CLOUD_PLANKS, UBlocks.CLOUD_PLANK_SLAB, UBlocks.CLOUD_PLANK_STAIRS, UBlocks.COMPACTED_CLOUD_PLANKS
);
getOrCreateTagBuilder(UTags.Blocks.CLOUD_BEDS).add(UBlocks.CLOUD_BED);
getOrCreateTagBuilder(UTags.Blocks.CLOUD_SLABS).add(
UBlocks.CLOUD_SLAB, UBlocks.SOGGY_CLOUD_SLAB, UBlocks.DENSE_CLOUD_SLAB, UBlocks.ETCHED_CLOUD_SLAB,
UBlocks.CLOUD_PLANK_SLAB, UBlocks.CLOUD_BRICK_SLAB
);
getOrCreateTagBuilder(UTags.Blocks.CLOUD_STAIRS).add(
UBlocks.CLOUD_STAIRS, UBlocks.SOGGY_CLOUD_STAIRS, UBlocks.DENSE_CLOUD_STAIRS, UBlocks.ETCHED_CLOUD_STAIRS,
UBlocks.CLOUD_PLANK_STAIRS, UBlocks.CLOUD_BRICK_STAIRS
);
getOrCreateTagBuilder(UTags.Blocks.CLOUD_BLOCKS).add(
UBlocks.CLOUD, UBlocks.CLOUD_PLANKS, UBlocks.CLOUD_BRICKS, UBlocks.DENSE_CLOUD,
UBlocks.ETCHED_CLOUD, UBlocks.CARVED_CLOUD, UBlocks.CLOUD_PILLAR,
UBlocks.COMPACTED_CLOUD, UBlocks.COMPACTED_CLOUD_PLANKS, UBlocks.COMPACTED_CLOUD_BRICKS,
UBlocks.UNSTABLE_CLOUD, UBlocks.SOGGY_CLOUD, UBlocks.SHAPING_BENCH
);
}
private void addChitinBlocksets() {
getOrCreateTagBuilder(UTags.Blocks.CHITIN_BLOCKS).add(
UBlocks.CHITIN, UBlocks.SURFACE_CHITIN,
UBlocks.CHISELLED_CHITIN, UBlocks.CHISELLED_CHITIN_HULL, UBlocks.CHISELLED_CHITIN_SLAB, UBlocks.CHISELLED_CHITIN_STAIRS,
UBlocks.CHITIN_SPIKES
);
getOrCreateTagBuilder(BlockTags.PICKAXE_MINEABLE).add(
UBlocks.CHITIN_SPIKES,
UBlocks.CHISELLED_CHITIN, UBlocks.CHISELLED_CHITIN_HULL, UBlocks.CHISELLED_CHITIN_SLAB, UBlocks.CHISELLED_CHITIN_STAIRS
);
getOrCreateTagBuilder(BlockTags.SHOVEL_MINEABLE).add(UBlocks.CHITIN, UBlocks.SURFACE_CHITIN);
}
private void addSign(Block standing, Block wall, Block hanging, Block wallHanging) {
getOrCreateTagBuilder(BlockTags.STANDING_SIGNS).add(standing);
getOrCreateTagBuilder(BlockTags.WALL_SIGNS).add(wall);
getOrCreateTagBuilder(BlockTags.CEILING_HANGING_SIGNS).add(hanging);
getOrCreateTagBuilder(BlockTags.WALL_HANGING_SIGNS).add(wallHanging);
}
}

View file

@ -0,0 +1,189 @@
package com.minelittlepony.unicopia.datagen.providers;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.UConventionalTags;
import com.minelittlepony.unicopia.UTags;
import com.minelittlepony.unicopia.block.UBlocks;
import com.minelittlepony.unicopia.datagen.Datagen;
import com.minelittlepony.unicopia.datagen.ItemFamilies;
import com.minelittlepony.unicopia.item.BedsheetsItem;
import com.minelittlepony.unicopia.item.UItems;
import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricTagProvider;
import net.fabricmc.fabric.api.tag.convention.v1.ConventionalItemTags;
import net.minecraft.block.Block;
import net.minecraft.item.Item;
import net.minecraft.item.Items;
import net.minecraft.registry.Registries;
import net.minecraft.registry.RegistryKeys;
import net.minecraft.registry.RegistryWrapper;
import net.minecraft.registry.RegistryWrapper.WrapperLookup;
import net.minecraft.registry.tag.BlockTags;
import net.minecraft.registry.tag.ItemTags;
import net.minecraft.registry.tag.TagBuilder;
import net.minecraft.registry.tag.TagKey;
import net.minecraft.util.Identifier;
public class UItemTagProvider extends FabricTagProvider.ItemTagProvider {
private final UBlockTagProvider blockTagProvider;
public UItemTagProvider(FabricDataOutput output, CompletableFuture<RegistryWrapper.WrapperLookup> registriesFuture, UBlockTagProvider blockTagProvider) {
super(output, registriesFuture, blockTagProvider);
this.blockTagProvider = blockTagProvider;
}
@Override
public void copy(TagKey<Block> blockTag, TagKey<Item> itemTag) {
TagBuilder blockTagBuilder = Objects.requireNonNull(blockTagProvider, "Pass Block tag provider via constructor to use copy").getTagBuilder(blockTag);
TagBuilder itemTagBuilder = getTagBuilder(itemTag);
blockTagBuilder.build().forEach(entry -> {
if (entry.canAdd(Registries.ITEM::containsId, tagId -> getTagBuilder(TagKey.of(RegistryKeys.ITEM, tagId)) != null)) {
itemTagBuilder.add(entry);
} else {
Datagen.LOGGER.warn("Cannot copy missing entry {} to item tag {}", entry, itemTag.id());
}
});
}
@Override
protected void configure(WrapperLookup arg) {
copyBlockTags();
exportConventionalTags();
getOrCreateTagBuilder(ItemTags.BOOKSHELF_BOOKS).add(UItems.SPELLBOOK);
getOrCreateTagBuilder(ItemTags.BEDS).add(UItems.CLOTH_BED, UItems.CLOUD_BED);
getOrCreateTagBuilder(ItemTags.CHEST_BOATS).add(UItems.PALM_CHEST_BOAT);
getOrCreateTagBuilder(ItemTags.BOATS).add(UItems.PALM_BOAT);
getOrCreateTagBuilder(ItemTags.MUSIC_DISCS).add(ItemFamilies.MUSIC_DISCS);
getOrCreateTagBuilder(ItemTags.CREEPER_DROP_MUSIC_DISCS).add(UItems.MUSIC_DISC_CRUSADE, UItems.MUSIC_DISC_FUNK, UItems.MUSIC_DISC_PET, UItems.MUSIC_DISC_POPULAR);
getOrCreateTagBuilder(ItemTags.SIGNS).add(UBlocks.PALM_SIGN.asItem());
getOrCreateTagBuilder(ItemTags.HANGING_SIGNS).add(UBlocks.PALM_HANGING_SIGN.asItem());
getOrCreateTagBuilder(UTags.HORSE_SHOES).add(ItemFamilies.HORSE_SHOES);
getOrCreateTagBuilder(UTags.POLEARMS).add(ItemFamilies.POLEARMS);
getOrCreateTagBuilder(ItemTags.TOOLS).addTag(UTags.HORSE_SHOES).addTag(UTags.POLEARMS);
getOrCreateTagBuilder(UTags.BASKETS).add(ItemFamilies.BASKETS);
getOrCreateTagBuilder(UTags.BADGES).add(Race.REGISTRY.stream()
.map(race -> race.getId().withPath(p -> p + "_badge"))
.flatMap(id -> Registries.ITEM.getOrEmpty(id).stream())
.toArray(Item[]::new));
getOrCreateTagBuilder(UTags.BED_SHEETS).add(BedsheetsItem.ITEMS.values().stream().toArray(Item[]::new));
getOrCreateTagBuilder(UTags.APPLE_SEEDS).add(UItems.GREEN_APPLE_SEEDS, UItems.SWEET_APPLE_SEEDS, UItems.SOUR_APPLE_SEEDS);
getOrCreateTagBuilder(UTags.MAGIC_FEATHERS).add(UItems.PEGASUS_FEATHER, UItems.GRYPHON_FEATHER);
getOrCreateTagBuilder(UTags.FRESH_APPLES).add(Items.APPLE, UItems.GREEN_APPLE, UItems.SWEET_APPLE, UItems.SOUR_APPLE);
getOrCreateTagBuilder(UTags.CLOUD_JARS).add(UItems.RAIN_CLOUD_JAR, UItems.STORM_CLOUD_JAR);
getOrCreateTagBuilder(UTags.PIES).add(UItems.APPLE_PIE, UItems.APPLE_PIE_HOOF);
// technical tags
getOrCreateTagBuilder(ItemTags.VILLAGER_PLANTABLE_SEEDS).addTag(UTags.APPLE_SEEDS);
getOrCreateTagBuilder(UTags.CAN_CUT_PIE).forceAddTag(ConventionalItemTags.SHEARS).addOptionalTag(UConventionalTags.TOOL_KNIVES);
getOrCreateTagBuilder(UTags.COOLS_OFF_KIRINS).add(Items.MELON_SLICE, UItems.JUICE).forceAddTag(ConventionalItemTags.WATER_BUCKETS);
getOrCreateTagBuilder(UTags.FALLS_SLOWLY).add(Items.FEATHER, UItems.CLOUD_LUMP).forceAddTag(UTags.MAGIC_FEATHERS);
getOrCreateTagBuilder(UTags.IS_DELIVERED_AGGRESSIVELY).forceAddTag(ItemTags.ANVIL);
getOrCreateTagBuilder(UTags.SPOOKED_MOB_DROPS).add(Items.BRICK);
getOrCreateTagBuilder(UTags.SHADES).add(
Items.CARVED_PUMPKIN, Items.SKELETON_SKULL, Items.WITHER_SKELETON_SKULL, Items.PLAYER_HEAD,
Items.ZOMBIE_HEAD, Items.CREEPER_HEAD, Items.DRAGON_HEAD, Items.PIGLIN_HEAD,
UItems.SUNGLASSES
);
getOrCreateTagBuilder(UTags.FLOATS_ON_CLOUDS)
.forceAddTag(UTags.Items.CLOUD_BEDS)
.forceAddTag(UTags.Items.CLOUD_SLABS)
.forceAddTag(UTags.Items.CLOUD_STAIRS)
.forceAddTag(UTags.Items.CLOUD_BLOCKS)
.add(UItems.CLOUD_LUMP);
getOrCreateTagBuilder(UTags.HAS_NO_TRAITS).add(
Items.AIR, Items.SPAWNER, Items.STRUCTURE_VOID, Items.STRUCTURE_BLOCK,
Items.COMMAND_BLOCK, Items.CHAIN_COMMAND_BLOCK, Items.REPEATING_COMMAND_BLOCK,
Items.LIGHT, Items.JIGSAW, Items.BARRIER, Items.BEDROCK, Items.END_PORTAL_FRAME,
Items.DEBUG_STICK, Items.COMMAND_BLOCK_MINECART,
UItems.PLUNDER_VINE
).forceAddTag(UTags.BADGES);
getOrCreateTagBuilder(UTags.LOOT_BUG_HIGH_VALUE_DROPS).add(
Items.DIAMOND, Items.GOLDEN_APPLE, Items.GOLDEN_CARROT,
Items.GOLDEN_HELMET, Items.GOLDEN_BOOTS, Items.GOLDEN_LEGGINGS, Items.GOLDEN_CHESTPLATE,
Items.GOLDEN_HORSE_ARMOR,
Items.GOLDEN_PICKAXE, Items.GOLDEN_SHOVEL, Items.GOLDEN_AXE, Items.GOLDEN_SWORD, Items.GOLDEN_HOE,
UItems.GOLDEN_HORSE_SHOE, UItems.GOLDEN_POLEARM, UItems.GOLDEN_FEATHER, UItems.GOLDEN_WING,
UItems.GOLDEN_OAK_SEEDS
).forceAddTag(ConventionalItemTags.NUGGETS)
.forceAddTag(ConventionalItemTags.GOLD_INGOTS).forceAddTag(ConventionalItemTags.RAW_GOLD_ORES).forceAddTag(ConventionalItemTags.RAW_GOLD_BLOCKS)
.addOptionalTag(new Identifier("farmersdelight:golden_knife"));
exportFarmersDelightItems();
}
private void copyBlockTags() {
copy(BlockTags.LEAVES, ItemTags.LEAVES);
copy(BlockTags.LOGS_THAT_BURN, ItemTags.LOGS_THAT_BURN);
copy(BlockTags.LOGS, ItemTags.LOGS);
copy(BlockTags.PLANKS, ItemTags.PLANKS);
copy(BlockTags.WOODEN_BUTTONS, ItemTags.WOODEN_BUTTONS);
copy(BlockTags.WOODEN_DOORS, ItemTags.WOODEN_DOORS);
copy(BlockTags.FENCE_GATES, ItemTags.FENCE_GATES);
copy(BlockTags.WOODEN_FENCES, ItemTags.WOODEN_FENCES);
copy(BlockTags.WOODEN_PRESSURE_PLATES, ItemTags.WOODEN_PRESSURE_PLATES);
copy(BlockTags.SLABS, ItemTags.SLABS);
copy(BlockTags.WOODEN_SLABS, ItemTags.WOODEN_SLABS);
copy(BlockTags.STAIRS, ItemTags.STAIRS);
copy(BlockTags.WOODEN_STAIRS, ItemTags.WOODEN_STAIRS);
copy(BlockTags.TRAPDOORS, ItemTags.TRAPDOORS);
copy(BlockTags.WOODEN_TRAPDOORS, ItemTags.WOODEN_TRAPDOORS);
copy(BlockTags.SAPLINGS, ItemTags.SAPLINGS);
copy(UTags.Blocks.ZAP_LOGS, UTags.Items.ZAP_LOGS);
copy(UTags.Blocks.WAXED_ZAP_LOGS, UTags.Items.WAXED_ZAP_LOGS);
copy(UTags.Blocks.PALM_LOGS, UTags.Items.PALM_LOGS);
copy(UTags.Blocks.CLOUD_BEDS, UTags.Items.CLOUD_BEDS);
copy(UTags.Blocks.CLOUD_SLABS, UTags.Items.CLOUD_SLABS);
copy(UTags.Blocks.CLOUD_STAIRS, UTags.Items.CLOUD_STAIRS);
copy(UTags.Blocks.CLOUD_BLOCKS, UTags.Items.CLOUD_BLOCKS);
copy(UTags.Blocks.CHITIN_BLOCKS, UTags.Items.CHITIN_BLOCKS);
}
private void exportConventionalTags() {
getOrCreateTagBuilder(UConventionalTags.ACORNS).add(UItems.ACORN);
getOrCreateTagBuilder(UConventionalTags.APPLES)
.add(Items.APPLE, Items.GOLDEN_APPLE, Items.ENCHANTED_GOLDEN_APPLE, UItems.ROTTEN_APPLE)
.forceAddTag(UTags.FRESH_APPLES)
.addOptionalTag(new Identifier("c", "pyrite_apples")) // no idea which mod add pyrite apples
;
getOrCreateTagBuilder(UConventionalTags.BANANAS).add(UItems.BANANA);
getOrCreateTagBuilder(UConventionalTags.COOKED_FISH).add(Items.COOKED_COD, Items.COOKED_SALMON);
getOrCreateTagBuilder(UConventionalTags.STICKS).add(Items.STICK);
getOrCreateTagBuilder(UConventionalTags.PINECONES).add(UItems.PINECONE);
getOrCreateTagBuilder(UConventionalTags.PINEAPPLES).add(UItems.PINEAPPLE);
getOrCreateTagBuilder(UConventionalTags.MANGOES).add(UItems.MANGO);
getOrCreateTagBuilder(UConventionalTags.MUSHROOMS).add(Items.RED_MUSHROOM, Items.BROWN_MUSHROOM);
getOrCreateTagBuilder(UConventionalTags.MUFFINS).add(UItems.MUFFIN);
getOrCreateTagBuilder(UConventionalTags.SEEDS).add(Items.BEETROOT_SEEDS, Items.MELON_SEEDS, Items.PUMPKIN_SEEDS, Items.TORCHFLOWER_SEEDS, Items.WHEAT_SEEDS)
.add(UItems.OAT_SEEDS)
.forceAddTag(UTags.APPLE_SEEDS);
getOrCreateTagBuilder(UConventionalTags.OEATMEALS).add(UItems.OATMEAL);
getOrCreateTagBuilder(UConventionalTags.GRAIN).add(Items.WHEAT, UItems.OATS);
getOrCreateTagBuilder(UConventionalTags.NUTS).addOptionalTag(UConventionalTags.CROPS_PEANUTS);
getOrCreateTagBuilder(UConventionalTags.FRUITS)
.forceAddTag(UConventionalTags.MANGOES)
.forceAddTag(UConventionalTags.PINEAPPLES)
.forceAddTag(UConventionalTags.APPLES)
.forceAddTag(UConventionalTags.BANANAS);
}
private void exportFarmersDelightItems() {
getOrCreateTagBuilder(UTags.COOLS_OFF_KIRINS)
.addOptional(new Identifier("farmersdelight:melon_popsicle"))
.addOptional(new Identifier("farmersdelight:melon_juice"));
getOrCreateTagBuilder(TagKey.of(RegistryKeys.ITEM, new Identifier("farmersdelight:cabbage_roll_ingredients"))).add(UItems.OATS, UItems.ROCK, UItems.WHEAT_WORMS);
getOrCreateTagBuilder(TagKey.of(RegistryKeys.ITEM, new Identifier("farmersdelight:comfort_foods"))).add(UItems.OATMEAL, UItems.ROCK_STEW, UItems.MUFFIN);
}
}

View file

@ -0,0 +1,137 @@
package com.minelittlepony.unicopia.datagen.providers;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.block.UBlocks;
import com.minelittlepony.unicopia.datagen.DataCollector;
import com.minelittlepony.unicopia.item.BedsheetsItem;
import com.minelittlepony.unicopia.item.UItems;
import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricModelProvider;
import net.minecraft.block.Block;
import net.minecraft.data.DataOutput;
import net.minecraft.data.DataWriter;
import net.minecraft.data.client.BlockStateModelGenerator;
import net.minecraft.item.Item;
import net.minecraft.item.Items;
import net.minecraft.registry.Registries;
import net.minecraft.data.client.ItemModelGenerator;
import net.minecraft.data.client.ModelIds;
import net.minecraft.data.client.TextureKey;
import net.minecraft.data.client.TextureMap;
public class UModelProvider extends FabricModelProvider {
public static final Map<Block, Item> FRUITS = Map.of(UBlocks.GREEN_APPLE, UItems.GREEN_APPLE,
UBlocks.GOLDEN_APPLE, Items.GOLDEN_APPLE,
UBlocks.MANGO, UItems.MANGO,
UBlocks.SOUR_APPLE, UItems.SOUR_APPLE,
UBlocks.SWEET_APPLE, UItems.SWEET_APPLE,
UBlocks.ZAP_APPLE, UItems.ZAP_APPLE,
UBlocks.ZAP_BULB, UItems.ZAP_BULB
);
private final DataCollector seasonsModels;
public UModelProvider(FabricDataOutput output) {
super(output);
seasonsModels = new DataCollector(output.getResolver(DataOutput.OutputType.RESOURCE_PACK, "seasons/models"));
}
@Override
public void generateBlockStateModels(BlockStateModelGenerator modelGenerator0) {
UBlockStateModelGenerator.create(modelGenerator0).register();
new SeasonsModelGenerator(modelGenerator0, seasonsModels.prime()).register();
}
@Override
public CompletableFuture<?> run(DataWriter writer) {
return CompletableFuture.allOf(
super.run(writer),
seasonsModels.upload(writer)
);
}
@Override
public void generateItemModels(ItemModelGenerator itemModelGenerator) {
ItemModels.register(itemModelGenerator,
UItems.ACORN, UItems.APPLE_PIE_HOOF, UItems.APPLE_PIE_SLICE, UItems.APPLE_PIE,
UItems.BANANA, UItems.BOTCHED_GEM, UItems.BROKEN_SUNGLASSES, UItems.BURNED_JUICE, UItems.BURNED_TOAST,
UItems.CARAPACE, UItems.CLAM_SHELL, UItems.COOKED_ZAP_APPLE, UItems.CLOUD_LUMP, UItems.CRISPY_HAY_FRIES, UItems.CRYSTAL_HEART, UItems.CRYSTAL_SHARD,
UItems.DAFFODIL_DAISY_SANDWICH, UItems.DRAGON_BREATH_SCROLL,
UItems.EMPTY_JAR,
UItems.FRIENDSHIP_BRACELET,
UItems.GIANT_BALLOON, UItems.GOLDEN_FEATHER, UItems.GOLDEN_OAK_SEEDS, UItems.GOLDEN_WING, UItems.GREEN_APPLE_SEEDS, UItems.GREEN_APPLE, UItems.GROGARS_BELL,
UItems.GRYPHON_FEATHER,
UItems.HAY_BURGER, UItems.HAY_FRIES, UItems.HORSE_SHOE_FRIES,
UItems.IMPORTED_OATS,
UItems.JAM_TOAST, UItems.JUICE,
UItems.LIGHTNING_JAR,
UItems.MANGO, UItems.MUFFIN,
UItems.OATMEAL,
UItems.PEBBLES, UItems.PEGASUS_FEATHER, UItems.PINECONE, UItems.PINEAPPLE_CROWN,
UItems.RAIN_CLOUD_JAR, UItems.ROCK_STEW, UItems.ROCK, UItems.ROTTEN_APPLE,
UItems.SALT_CUBE, UItems.SCALLOP_SHELL, UItems.SHELLY, UItems.SOUR_APPLE_SEEDS, UItems.SOUR_APPLE, UItems.SPELLBOOK, UItems.STORM_CLOUD_JAR,
UItems.SWEET_APPLE_SEEDS, UItems.SWEET_APPLE,
UItems.TOAST, UItems.TOM, UItems.TURRET_SHELL,
UItems.WEIRD_ROCK, UItems.WHEAT_WORMS, UBlocks.WEATHER_VANE.asItem(),
UItems.ZAP_APPLE_JAM_JAR, UItems.ZAP_APPLE, UItems.ZAP_BULB,
// discs
UItems.MUSIC_DISC_CRUSADE, UItems.MUSIC_DISC_FUNK, UItems.MUSIC_DISC_PET, UItems.MUSIC_DISC_POPULAR,
// baskets
UItems.ACACIA_BASKET, UItems.BAMBOO_BASKET, UItems.BIRCH_BASKET, UItems.CHERRY_BASKET,
UItems.DARK_OAK_BASKET, UItems.JUNGLE_BASKET, UItems.MANGROVE_BASKET, UItems.OAK_BASKET, UItems.SPRUCE_BASKET,
UItems.PALM_BASKET,
// boats
UItems.PALM_BOAT, UItems.PALM_CHEST_BOAT,
// horseshoes
UItems.COPPER_HORSE_SHOE, UItems.GOLDEN_HORSE_SHOE, UItems.IRON_HORSE_SHOE, UItems.NETHERITE_HORSE_SHOE
);
// spawn eggs
ItemModels.register(itemModelGenerator, ItemModels.TEMPLATE_SPAWN_EGG, UItems.BUTTERFLY_SPAWN_EGG, UItems.LOOT_BUG_SPAWN_EGG);
// amulets
ItemModels.register(itemModelGenerator, ItemModels.TEMPLATE_AMULET, UItems.ALICORN_AMULET, UItems.BROKEN_ALICORN_AMULET, UItems.PEARL_NECKLACE, UItems.PEGASUS_AMULET, UItems.UNICORN_AMULET);
// mugs
ItemModels.register(itemModelGenerator, ItemModels.TEMPLATE_MUG, UItems.CIDER, UItems.LOVE_BOTTLE, UItems.LOVE_BUCKET, UItems.LOVE_MUG, UItems.MUG);
// jars
ItemModels.register(itemModelGenerator, ItemModels.BUILTIN_ENTITY, UItems.FILLED_JAR);
// eyewear
ItemModels.register(itemModelGenerator, ItemModels.TEMPLATE_EYEWEAR, UItems.SUNGLASSES);
// staffs
ItemModels.register(itemModelGenerator, ItemModels.HANDHELD_STAFF, UItems.MEADOWBROOKS_STAFF);
ItemModels.item("handheld_staff", TextureKey.LAYER0, TextureKey.LAYER1).upload(ModelIds.getItemModelId(UItems.MAGIC_STAFF), new TextureMap()
.put(TextureKey.LAYER0, ModelIds.getItemSubModelId(UItems.MAGIC_STAFF, "_base"))
.put(TextureKey.LAYER1, ModelIds.getItemSubModelId(UItems.MAGIC_STAFF, "_magic")), itemModelGenerator.writer);
// polearms
List.of(UItems.DIAMOND_POLEARM, UItems.GOLDEN_POLEARM, UItems.NETHERITE_POLEARM, UItems.STONE_POLEARM, UItems.WOODEN_POLEARM, UItems.IRON_POLEARM).forEach(item -> ItemModels.registerPolearm(itemModelGenerator, item));
// sheets
ItemModels.register(itemModelGenerator, BedsheetsItem.ITEMS.values().stream().toArray(Item[]::new));
// badges
ItemModels.register(itemModelGenerator, Race.REGISTRY.stream()
.map(race -> race.getId().withPath(p -> p + "_badge"))
.flatMap(id -> Registries.ITEM.getOrEmpty(id).stream())
.toArray(Item[]::new));
// butterflies
ItemModels.registerButterfly(itemModelGenerator, UItems.BUTTERFLY);
ItemModels.registerSpectralBlock(itemModelGenerator, UItems.SPECTRAL_CLOCK);
ModelOverrides.of(ItemModels.GENERATED)
.addUniform("count", 2, 16, ModelIds.getItemModelId(UItems.ROCK_CANDY))
.upload(UItems.ROCK_CANDY, itemModelGenerator);
List.of(UItems.PINEAPPLE, UItems.CANDIED_APPLE).forEach(item -> {
ModelOverrides.of(ItemModels.GENERATED)
.addOverride(ModelIds.getItemSubModelId(item, "_bite1"), "damage", 0.3F)
.addOverride(ModelIds.getItemSubModelId(item, "_bite2"), "damage", 0.6F)
.upload(item, itemModelGenerator);
});
// gemstone
ModelOverrides.of(ItemModels.GENERATED)
.addOverride(ModelIds.getItemSubModelId(UItems.GEMSTONE, "_pure"), "affinity", 0)
.addOverride(ModelIds.getItemSubModelId(UItems.GEMSTONE, "_corrupted"), "affinity", 1)
.upload(UItems.GEMSTONE, itemModelGenerator);
}
}

View file

@ -0,0 +1,87 @@
package com.minelittlepony.unicopia.datagen.providers;
import java.util.Arrays;
import java.util.NoSuchElementException;
import com.minelittlepony.unicopia.UTags;
import com.minelittlepony.unicopia.block.UBlocks;
import com.minelittlepony.unicopia.datagen.ItemFamilies;
import com.minelittlepony.unicopia.datagen.UBlockFamilies;
import com.minelittlepony.unicopia.item.UItems;
import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
import net.minecraft.block.Block;
import net.minecraft.data.server.recipe.RecipeExporter;
import net.minecraft.data.server.recipe.RecipeProvider;
import net.minecraft.data.server.recipe.ShapedRecipeJsonBuilder;
import net.minecraft.data.server.recipe.ShapelessRecipeJsonBuilder;
import net.minecraft.data.server.recipe.VanillaRecipeProvider;
import net.minecraft.item.Item;
import net.minecraft.item.ItemConvertible;
import net.minecraft.item.Items;
import net.minecraft.recipe.book.RecipeCategory;
import net.minecraft.registry.Registries;
import net.minecraft.util.Identifier;
public class URecipeProvider extends FabricRecipeProvider {
public URecipeProvider(FabricDataOutput output) {
super(output);
}
@Override
public void generate(RecipeExporter exporter) {
Arrays.stream(ItemFamilies.BASKETS).forEach(basket -> {
offerBasketRecipe(exporter, basket, getMaterial(basket, "_basket", "_planks"));
});
offerBoatRecipe(exporter, UItems.PALM_BOAT, UBlocks.PALM_PLANKS);
offerChestBoatRecipe(exporter, UItems.PALM_CHEST_BOAT, UItems.PALM_BOAT);
offerHangingSignRecipe(exporter, UBlocks.PALM_HANGING_SIGN, UBlocks.PALM_PLANKS);
offerPlanksRecipe(exporter, UBlocks.PALM_PLANKS, UTags.Items.PALM_LOGS, 4);
offerPlanksRecipe(exporter, UBlocks.ZAP_PLANKS, UTags.Items.ZAP_LOGS, 4);
offerPlanksRecipe(exporter, UBlocks.WAXED_ZAP_PLANKS, UTags.Items.WAXED_ZAP_LOGS, 4);
offerBarkBlockRecipe(exporter, UBlocks.PALM_WOOD, UBlocks.PALM_LOG);
offerBarkBlockRecipe(exporter, UBlocks.ZAP_WOOD, UBlocks.ZAP_LOG);
offerBarkBlockRecipe(exporter, UBlocks.WAXED_ZAP_WOOD, UBlocks.WAXED_ZAP_LOG);
generateFamily(exporter, UBlockFamilies.PALM);
generateFamily(exporter, UBlockFamilies.ZAP);
generateFamily(exporter, UBlockFamilies.WAXED_ZAP);
offerWaxingRecipes(exporter);
}
private static Item getMaterial(Item output, String toStrip, String suffex) {
Identifier id = Registries.ITEM.getId(output).withPath(p -> p.replace(toStrip, "") + suffex);
return Registries.ITEM.getOrEmpty(id)
.or(() -> Registries.ITEM.getOrEmpty(new Identifier(Identifier.DEFAULT_NAMESPACE, id.getPath())))
.orElseThrow(() -> new NoSuchElementException("No item with id " + id));
}
public static void offerBasketRecipe(RecipeExporter exporter, ItemConvertible output, ItemConvertible input) {
ShapedRecipeJsonBuilder.create(RecipeCategory.TRANSPORTATION, output)
.input(Character.valueOf('#'), input)
.pattern("# #")
.pattern("# #")
.pattern("###")
.group("basket")
.criterion(VanillaRecipeProvider.hasItem(input), VanillaRecipeProvider.conditionsFromItem(input))
.offerTo(exporter);
}
public static void offerWaxingRecipes(RecipeExporter exporter) {
UBlockFamilies.WAXED_ZAP.getVariants().forEach((variant, output) -> {
Block input = UBlockFamilies.ZAP.getVariant(variant);
offerWaxingRecipe(exporter, output, input);
});
offerWaxingRecipe(exporter, UBlocks.WAXED_ZAP_PLANKS, UBlocks.ZAP_PLANKS);
offerWaxingRecipe(exporter, UBlocks.WAXED_ZAP_WOOD, UBlocks.ZAP_WOOD);
}
public static void offerWaxingRecipe(RecipeExporter exporter, ItemConvertible output, ItemConvertible input) {
ShapelessRecipeJsonBuilder.create(RecipeCategory.BUILDING_BLOCKS, output)
.input(input)
.input(Items.HONEYCOMB).group(RecipeProvider.getItemPath(output))
.criterion(RecipeProvider.hasItem(input), RecipeProvider.conditionsFromItem(input))
.offerTo(exporter, RecipeProvider.convertBetween(output, Items.HONEYCOMB));
}
}

View file

@ -0,0 +1,126 @@
package com.minelittlepony.unicopia.datagen.providers.loot;
import java.util.function.Function;
import com.minelittlepony.unicopia.item.UItems;
import com.minelittlepony.unicopia.item.enchantment.UEnchantments;
import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricBlockLootTableProvider;
import net.minecraft.block.Block;
import net.minecraft.block.Blocks;
import net.minecraft.data.server.loottable.BlockLootTableGenerator;
import net.minecraft.enchantment.Enchantments;
import net.minecraft.loot.LootPool;
import net.minecraft.loot.LootTable;
import net.minecraft.loot.condition.LootCondition;
import net.minecraft.loot.condition.MatchToolLootCondition;
import net.minecraft.loot.condition.RandomChanceLootCondition;
import net.minecraft.loot.condition.TableBonusLootCondition;
import net.minecraft.loot.entry.ItemEntry;
import net.minecraft.loot.entry.LootPoolEntry;
import net.minecraft.loot.function.ApplyBonusLootFunction;
import net.minecraft.loot.function.SetCountLootFunction;
import net.minecraft.loot.provider.number.ConstantLootNumberProvider;
import net.minecraft.loot.provider.number.UniformLootNumberProvider;
import net.minecraft.predicate.NumberRange;
import net.minecraft.predicate.item.EnchantmentPredicate;
import net.minecraft.predicate.item.ItemPredicate;
import net.minecraft.util.Identifier;
public class UBlockAdditionsLootTableProvider extends FabricBlockLootTableProvider {
public static final LootCondition.Builder WITH_GEM_FINDER = MatchToolLootCondition.builder(ItemPredicate.Builder.create().enchantment(new EnchantmentPredicate(UEnchantments.GEM_FINDER, NumberRange.IntRange.atLeast(1))));
public static final LootCondition.Builder WITHOUT_SILK_TOUCH_AND_GEM_FINDER = WITHOUT_SILK_TOUCH.and(WITH_GEM_FINDER);
public static final float[] GEMSTONES_FORTUNE_CHANCE = { 0.1F, 0.14285715F, 0.25F, 1F };
public UBlockAdditionsLootTableProvider(FabricDataOutput dataOutput) {
super(dataOutput);
}
@Override
public String getName() {
return "Block Loot Table Additions";
}
@Override
public void generate() {
addVanillaDrop(Blocks.STONE, this::gemstoneDrops);
addVanillaDrop(Blocks.DIRT, block -> gemstoneAndWormDrops(block, 2, 0.05F, 0.052222223F, 0.055F, 0.066666665F, 0.1F));
addVanillaDrop(Blocks.COARSE_DIRT, block -> gemstoneAndWormDrops(block, 2, 0.05F, 0.052222223F, 0.055F, 0.066666665F, 0.1F));
addVanillaDrop(Blocks.GRASS_BLOCK, block -> gemstoneAndWormDrops(block, 2, 0.05F, 0.052222223F, 0.055F, 0.066666665F, 0.1F));
addVanillaDrop(Blocks.GRASS, block -> wormDrops(block, 2, 0.05F, 0.052222223F, 0.055F, 0.066666665F, 0.1F));
addVanillaDrop(Blocks.MYCELIUM, block -> wormDrops(block, 3, 0.06F, 0.062222223F, 0.065F, 0.077777776F, 0.2F));
addVanillaDrop(Blocks.PODZOL, block -> wormDrops(block, 4, 0.06F, 0.062222223F, 0.065F, 0.077777776F, 0.2F));
addVanillaDrop(Blocks.DIAMOND_ORE, this::crystalShardDrops);
addVanillaDrop(Blocks.DEEPSLATE_DIAMOND_ORE, this::crystalShardDrops);
}
private void addVanillaDrop(Block block, Function<Block, LootTable.Builder> lootTableFunction) {
lootTables.put(new Identifier("unicopiamc", block.getLootTableId().getPath()), lootTableFunction.apply(block));
}
public LootTable.Builder wormDrops(Block block, int max, float...chance) {
return LootTable.builder()
.pool(LootPool.builder()
.rolls(ConstantLootNumberProvider.create(1))
.conditionally(WITHOUT_SILK_TOUCH)
.with(wheatwormDrops(block, max, chance))
);
}
public LootTable.Builder gemstoneAndWormDrops(Block block, int max, float...chance) {
return LootTable.builder()
.pool(LootPool.builder()
.rolls(ConstantLootNumberProvider.create(1))
.conditionally(WITHOUT_SILK_TOUCH)
.with(gemstoneDrops(block, 0.1F))
.with(wheatwormDrops(block, max, chance))
);
}
public LootTable.Builder gemstoneDrops(Block block) {
return LootTable.builder()
.pool(LootPool.builder()
.rolls(ConstantLootNumberProvider.create(1))
.conditionally(WITHOUT_SILK_TOUCH)
.with(gemstoneDrops(block, 0.1F))
);
}
public LootTable.Builder crystalShardDrops(Block block) {
return LootTable.builder()
.pool(LootPool.builder()
.rolls(ConstantLootNumberProvider.create(1))
.conditionally(WITHOUT_SILK_TOUCH)
.with(applyExplosionDecay(block, ItemEntry.builder(UItems.CRYSTAL_SHARD)
.apply(SetCountLootFunction.builder(UniformLootNumberProvider.create(1, 2)))
.apply(ApplyBonusLootFunction.oreDrops(Enchantments.FORTUNE))
)
.conditionally(RandomChanceLootCondition.builder(0.25F))
)
);
}
public LootPoolEntry.Builder<?> gemstoneDrops(Block block, float chance) {
return applyExplosionDecay(block, ItemEntry.builder(UItems.GEMSTONE)
.apply(SetCountLootFunction.builder(UniformLootNumberProvider.create(1, 2)))
)
.conditionally(WITH_GEM_FINDER)
.conditionally(RandomChanceLootCondition.builder(0.1F))
.conditionally(TableBonusLootCondition.builder(Enchantments.FORTUNE, GEMSTONES_FORTUNE_CHANCE));
}
public LootPoolEntry.Builder<?> wheatwormDrops(Block block, int max, float...chance) {
return applyExplosionDecay(block, ItemEntry.builder(UItems.WHEAT_WORMS)
.apply(SetCountLootFunction.builder(UniformLootNumberProvider.create(1, max)))
)
.conditionally(TableBonusLootCondition.builder(Enchantments.FORTUNE, chance));
}
public static LootTable.Builder dropsWithGemfinding(Block drop, LootPoolEntry.Builder<?> child) {
return BlockLootTableGenerator.drops(drop, WITHOUT_SILK_TOUCH_AND_GEM_FINDER, child);
}
}

View file

@ -0,0 +1,132 @@
package com.minelittlepony.unicopia.datagen.providers.loot;
import java.util.List;
import com.minelittlepony.unicopia.block.UBlocks;
import com.minelittlepony.unicopia.datagen.providers.UModelProvider;
import com.minelittlepony.unicopia.item.UItems;
import com.minelittlepony.unicopia.server.world.Tree;
import com.minelittlepony.unicopia.server.world.UTreeGen;
import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricBlockLootTableProvider;
import net.minecraft.block.BedBlock;
import net.minecraft.block.Block;
import net.minecraft.block.Blocks;
import net.minecraft.block.enums.BedPart;
import net.minecraft.enchantment.Enchantments;
import net.minecraft.item.Items;
import net.minecraft.loot.LootPool;
import net.minecraft.loot.LootTable;
import net.minecraft.loot.condition.TableBonusLootCondition;
import net.minecraft.loot.entry.ItemEntry;
import net.minecraft.loot.function.SetCountLootFunction;
import net.minecraft.loot.provider.number.ConstantLootNumberProvider;
import net.minecraft.loot.provider.number.UniformLootNumberProvider;
public class UBlockLootTableProvider extends FabricBlockLootTableProvider {
public UBlockLootTableProvider(FabricDataOutput output) {
super(output);
}
@Override
public void generate() {
// simple drops
List.of(
UBlocks.CARVED_CLOUD, UBlocks.UNSTABLE_CLOUD,
UBlocks.CHISELLED_CHITIN_STAIRS, UBlocks.CHISELLED_CHITIN,
UBlocks.CLOUD_BRICK_STAIRS, UBlocks.CLOUD_BRICKS,
UBlocks.CLOUD_PLANK_STAIRS, UBlocks.CLOUD_PLANKS,
UBlocks.CURING_JOKE,
UBlocks.GOLDEN_OAK_LOG,
UBlocks.HIVE,
UBlocks.PALM_BUTTON, UBlocks.PALM_FENCE_GATE, UBlocks.PALM_FENCE, UBlocks.PALM_LOG, UBlocks.PALM_PLANKS,
UBlocks.PALM_PRESSURE_PLATE, UBlocks.PALM_SIGN, UBlocks.PALM_HANGING_SIGN, UBlocks.PALM_STAIRS, UBlocks.PALM_TRAPDOOR, UBlocks.PALM_WOOD,
UBlocks.STRIPPED_PALM_LOG, UBlocks.STRIPPED_PALM_WOOD,
UBlocks.STRIPPED_ZAP_LOG, UBlocks.STRIPPED_ZAP_WOOD,
UBlocks.WAXED_STRIPPED_ZAP_LOG, UBlocks.WAXED_STRIPPED_ZAP_WOOD,
UBlocks.WAXED_ZAP_FENCE_GATE, UBlocks.WAXED_ZAP_FENCE,
UBlocks.WAXED_ZAP_LOG, UBlocks.WAXED_ZAP_PLANKS, UBlocks.WAXED_ZAP_STAIRS, UBlocks.WAXED_ZAP_WOOD,
UBlocks.WEATHER_VANE,
UBlocks.ZAP_FENCE_GATE, UBlocks.ZAP_FENCE,
UBlocks.ZAP_LOG, UBlocks.ZAP_PLANKS, UBlocks.ZAP_STAIRS, UBlocks.ZAP_WOOD
).forEach(this::addDrop);
// slabs
List.of(
UBlocks.CHISELLED_CHITIN_SLAB, UBlocks.CLOUD_BRICK_SLAB,
UBlocks.CLOUD_PLANK_SLAB, UBlocks.PALM_SLAB, UBlocks.ZAP_SLAB, UBlocks.WAXED_ZAP_SLAB
).forEach(slab -> addDrop(slab, this::slabDrops));
// fruit
UModelProvider.FRUITS.forEach((block, drop) -> {
if (block != UBlocks.GOLDEN_APPLE) {
addDrop(block, drop);
}
});
List.of(UBlocks.GREEN_APPLE_LEAVES, UBlocks.SOUR_APPLE_LEAVES, UBlocks.SWEET_APPLE_LEAVES, UBlocks.GOLDEN_OAK_LEAVES).forEach(block -> addDrop(block, this::fruitLeavesDrops));
addDrop(UBlocks.MANGO_LEAVES, block -> leavesDrops(block, UTreeGen.MANGO_TREE.sapling().get(), 0.025F, 0.027777778F, 0.03125F, 0.041666668F, 0.1F)); // same chance as jungle
addDrop(UBlocks.ZAP_LEAVES, block -> leavesDrops(block, UTreeGen.ZAP_APPLE_TREE.sapling().get(), SAPLING_DROP_CHANCE));
addDrop(UBlocks.FLOWERING_ZAP_LEAVES, block -> leavesDrops(block, UTreeGen.ZAP_APPLE_TREE.sapling().get(), SAPLING_DROP_CHANCE));
addDrop(UBlocks.PALM_LEAVES, block -> leavesDrops(block, UTreeGen.BANANA_TREE.sapling().get(), SAPLING_DROP_CHANCE));
Tree.REGISTRY.forEach(tree -> {
tree.sapling().ifPresent(this::addDrop);
tree.pot().ifPresent(this::addPottedPlantDrops);
});
// doors
List.of(
UBlocks.CLOUD_DOOR, UBlocks.CRYSTAL_DOOR,
UBlocks.DARK_OAK_DOOR, UBlocks.PALM_DOOR, UBlocks.STABLE_DOOR
).forEach(door -> addDrop(door, this::doorDrops));
//beds
List.of(
UBlocks.CLOUD_BED, UBlocks.CLOTH_BED
).forEach(bed -> addDrop(bed, b -> dropsWithProperty(b, BedBlock.PART, BedPart.HEAD)));
addDrop(UBlocks.CHITIN_SPIKES, drops(UBlocks.CHITIN_SPIKES, UItems.CARAPACE, ConstantLootNumberProvider.create(6)));
addDrop(UBlocks.CHITIN, drops(UBlocks.CHITIN, UItems.CARAPACE, ConstantLootNumberProvider.create(9)));
addDrop(UBlocks.SURFACE_CHITIN, drops(UBlocks.SURFACE_CHITIN, UItems.CARAPACE, ConstantLootNumberProvider.create(9)));
addDrop(UBlocks.CLOUD, drops(UBlocks.CLOUD, UItems.CLOUD_LUMP, ConstantLootNumberProvider.create(4)));
addDrop(UBlocks.CLOUD_STAIRS, drops(UBlocks.CLOUD_STAIRS, UItems.CLOUD_LUMP, ConstantLootNumberProvider.create(6)));
addDrop(UBlocks.SOGGY_CLOUD, drops(UBlocks.CLOUD, UItems.CLOUD_LUMP, ConstantLootNumberProvider.create(4)));
addDrop(UBlocks.SOGGY_CLOUD_STAIRS, drops(UBlocks.CLOUD_STAIRS, UItems.CLOUD_LUMP, ConstantLootNumberProvider.create(6)));
addDrop(UBlocks.DENSE_CLOUD, drops(UBlocks.DENSE_CLOUD, UItems.CLOUD_LUMP, ConstantLootNumberProvider.create(9)));
addDrop(UBlocks.DENSE_CLOUD_STAIRS, drops(UBlocks.DENSE_CLOUD_STAIRS, UItems.CLOUD_LUMP, ConstantLootNumberProvider.create(13)));
addDrop(UBlocks.ETCHED_CLOUD, drops(UBlocks.ETCHED_CLOUD, UItems.CLOUD_LUMP, ConstantLootNumberProvider.create(9)));
addDrop(UBlocks.ETCHED_CLOUD_STAIRS, drops(UBlocks.ETCHED_CLOUD_STAIRS, UItems.CLOUD_LUMP, ConstantLootNumberProvider.create(13)));
addDrop(UBlocks.CLOUD_PILLAR, drops(UBlocks.CLOUD_PILLAR, UBlocks.CLOUD, ConstantLootNumberProvider.create(6)));
addDrop(UBlocks.FROSTED_OBSIDIAN, Blocks.OBSIDIAN);
}
private LootTable.Builder fruitLeavesDrops(Block leaves) {
return LootTable.builder()
.pool(LootPool.builder()
.rolls(ConstantLootNumberProvider.create(1))
.with(ItemEntry.builder(leaves).conditionally(WITH_SILK_TOUCH_OR_SHEARS))
)
.pool(LootPool.builder()
.rolls(ConstantLootNumberProvider.create(1))
.conditionally(WITHOUT_SILK_TOUCH_NOR_SHEARS)
.with(
applyExplosionDecay(leaves, ItemEntry.builder(Items.STICK)
.apply(SetCountLootFunction.builder(UniformLootNumberProvider.create(1, 2)))
)
.conditionally(TableBonusLootCondition.builder(Enchantments.FORTUNE, LEAVES_STICK_DROP_CHANCE))
)
);
}
}

View file

@ -0,0 +1,138 @@
package com.minelittlepony.unicopia.datagen.providers.loot;
import java.util.function.BiConsumer;
import com.minelittlepony.unicopia.UTags;
import com.minelittlepony.unicopia.item.UItems;
import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
import net.fabricmc.fabric.api.datagen.v1.provider.SimpleFabricLootTableProvider;
import net.minecraft.loot.LootTable.Builder;
import net.minecraft.loot.LootPool;
import net.minecraft.loot.LootTable;
import net.minecraft.loot.LootTables;
import net.minecraft.loot.context.LootContextTypes;
import net.minecraft.loot.entry.ItemEntry;
import net.minecraft.loot.entry.TagEntry;
import net.minecraft.loot.function.SetCountLootFunction;
import net.minecraft.loot.provider.number.UniformLootNumberProvider;
import net.minecraft.util.Identifier;
public class UChestAdditionsLootTableProvider extends SimpleFabricLootTableProvider {
public UChestAdditionsLootTableProvider(FabricDataOutput dataOutput) {
super(dataOutput, LootContextTypes.CHEST);
}
@Override
public void accept(BiConsumer<Identifier, Builder> exporter) {
acceptAdditions((id, builder) -> exporter.accept(new Identifier("unicopiamc", id.getPath()), builder));
}
public void acceptAdditions(BiConsumer<Identifier, Builder> exporter) {
exporter.accept(LootTables.ABANDONED_MINESHAFT_CHEST, LootTable.builder().pool(LootPool.builder()
.rolls(UniformLootNumberProvider.create(2, 4))
.with(ItemEntry.builder(UItems.GRYPHON_FEATHER).weight(2).apply(SetCountLootFunction.builder(UniformLootNumberProvider.create(1, 4))))
));
exporter.accept(LootTables.WOODLAND_MANSION_CHEST, LootTable.builder().pool(LootPool.builder()
.rolls(UniformLootNumberProvider.create(2, 4))
.with(ItemEntry.builder(UItems.GRYPHON_FEATHER).weight(10).apply(SetCountLootFunction.builder(UniformLootNumberProvider.create(1, 7))))
.with(ItemEntry.builder(UItems.GOLDEN_WING).weight(1).apply(SetCountLootFunction.builder(UniformLootNumberProvider.create(1, 2))))
.with(TagEntry.expandBuilder(UTags.FRESH_APPLES).weight(1).apply(SetCountLootFunction.builder(UniformLootNumberProvider.create(2, 5))))
));
exporter.accept(LootTables.VILLAGE_FLETCHER_CHEST, LootTable.builder().pool(LootPool.builder()
.rolls(UniformLootNumberProvider.create(2, 4))
.with(ItemEntry.builder(UItems.GRYPHON_FEATHER).weight(10).apply(SetCountLootFunction.builder(UniformLootNumberProvider.create(1, 2))))
.with(ItemEntry.builder(UItems.PEGASUS_FEATHER).weight(1).apply(SetCountLootFunction.builder(UniformLootNumberProvider.create(1, 2))))
));
exporter.accept(LootTables.VILLAGE_PLAINS_CHEST, LootTable.builder().pool(LootPool.builder()
.rolls(UniformLootNumberProvider.create(3, 4))
.with(TagEntry.expandBuilder(UTags.FRESH_APPLES).weight(1))
.with(TagEntry.expandBuilder(UTags.APPLE_SEEDS).weight(1))
));
exporter.accept(LootTables.ANCIENT_CITY_CHEST, LootTable.builder().pool(LootPool.builder()
.rolls(UniformLootNumberProvider.create(0, 1))
.with(ItemEntry.builder(UItems.GROGARS_BELL).weight(1))
));
exporter.accept(LootTables.BURIED_TREASURE_CHEST, LootTable.builder().pool(LootPool.builder()
.rolls(UniformLootNumberProvider.create(1, 4))
.with(ItemEntry.builder(UItems.PEARL_NECKLACE).weight(1))
.with(TagEntry.expandBuilder(UTags.item("food_types/shells")).weight(3))
));
exporter.accept(LootTables.SHIPWRECK_SUPPLY_CHEST, LootTable.builder().pool(LootPool.builder()
.rolls(UniformLootNumberProvider.create(1, 6))
.with(TagEntry.expandBuilder(UTags.SHELLS).weight(3))
));
exporter.accept(LootTables.SHIPWRECK_TREASURE_CHEST, LootTable.builder().pool(LootPool.builder()
.rolls(UniformLootNumberProvider.create(1, 4))
.with(ItemEntry.builder(UItems.PEARL_NECKLACE).weight(1))
.with(TagEntry.expandBuilder(UTags.SHELLS).weight(3))
));
exporter.accept(LootTables.UNDERWATER_RUIN_BIG_CHEST, LootTable.builder().pool(LootPool.builder()
.rolls(UniformLootNumberProvider.create(1, 2))
.with(ItemEntry.builder(UItems.PEARL_NECKLACE).weight(1))
.with(ItemEntry.builder(UItems.SHELLY).weight(4))
.with(TagEntry.expandBuilder(UTags.SHELLS).weight(8))
));
exporter.accept(LootTables.UNDERWATER_RUIN_SMALL_CHEST, LootTable.builder().pool(LootPool.builder()
.rolls(UniformLootNumberProvider.create(1, 4))
.with(TagEntry.expandBuilder(UTags.SHELLS).weight(1))
));
exporter.accept(LootTables.DESERT_WELL_ARCHAEOLOGY, LootTable.builder().pool(LootPool.builder()
.rolls(UniformLootNumberProvider.create(1, 4))
.with(ItemEntry.builder(UItems.WEIRD_ROCK).weight(2))
.with(ItemEntry.builder(UItems.ROCK).weight(1))
.with(ItemEntry.builder(UItems.TOM).weight(1))
.with(ItemEntry.builder(UItems.ROCK_STEW).weight(1))
.with(ItemEntry.builder(UItems.PEBBLES).weight(1))
.with(ItemEntry.builder(UItems.SHELLY).weight(1))
.with(TagEntry.expandBuilder(UTags.SHELLS).weight(1))
.with(ItemEntry.builder(UItems.PEARL_NECKLACE).weight(1))
));
exporter.accept(LootTables.TRAIL_RUINS_COMMON_ARCHAEOLOGY, LootTable.builder().pool(LootPool.builder()
.rolls(UniformLootNumberProvider.create(1, 4))
.with(ItemEntry.builder(UItems.MEADOWBROOKS_STAFF).weight(2))
.with(ItemEntry.builder(UItems.BOTCHED_GEM).weight(3))
.with(ItemEntry.builder(UItems.PEGASUS_FEATHER).weight(1))
));
exporter.accept(LootTables.TRAIL_RUINS_RARE_ARCHAEOLOGY, LootTable.builder().pool(LootPool.builder()
.rolls(UniformLootNumberProvider.create(1, 4))
.with(ItemEntry.builder(UItems.BROKEN_SUNGLASSES).weight(2))
.with(ItemEntry.builder(UItems.EMPTY_JAR).weight(2))
.with(ItemEntry.builder(UItems.MUSIC_DISC_CRUSADE).weight(1))
));
exporter.accept(LootTables.OCEAN_RUIN_WARM_ARCHAEOLOGY, LootTable.builder().pool(LootPool.builder()
.rolls(UniformLootNumberProvider.create(1, 4))
.with(TagEntry.expandBuilder(UTags.SHELLS).weight(1))
.with(ItemEntry.builder(UItems.PEARL_NECKLACE).weight(1))
));
exporter.accept(LootTables.FISHING_GAMEPLAY, LootTable.builder().pool(LootPool.builder()
.rolls(UniformLootNumberProvider.create(1, 4))
.with(TagEntry.expandBuilder(UTags.SHELLS).weight(2))
));
exporter.accept(LootTables.FISHING_JUNK_GAMEPLAY, LootTable.builder().pool(LootPool.builder()
.rolls(UniformLootNumberProvider.create(1, 4))
.with(ItemEntry.builder(UItems.BROKEN_SUNGLASSES).weight(2))
.with(ItemEntry.builder(UItems.WHEAT_WORMS).weight(2))
.with(ItemEntry.builder(UItems.BOTCHED_GEM).weight(4))
));
exporter.accept(LootTables.FISHING_TREASURE_GAMEPLAY, LootTable.builder().pool(LootPool.builder()
.rolls(UniformLootNumberProvider.create(1, 4))
.with(ItemEntry.builder(UItems.PEARL_NECKLACE).weight(1))
.with(ItemEntry.builder(UItems.SHELLY).weight(1))
));
exporter.accept(LootTables.HERO_OF_THE_VILLAGE_FISHERMAN_GIFT_GAMEPLAY, LootTable.builder().pool(LootPool.builder()
.rolls(UniformLootNumberProvider.create(1, 4))
.with(ItemEntry.builder(UItems.PEARL_NECKLACE).weight(1))
.with(ItemEntry.builder(UItems.SHELLY).weight(1))
));
}
}

View file

@ -80,8 +80,11 @@ public record DietProfile(
return null;
}
float hunger = food.getHunger() * ratios.getFirst();
int baseline = (int)hunger;
return FoodAttributes.copy(food)
.hunger(Math.max(1, (int)(food.getHunger() * ratios.getFirst())))
.hunger(Math.max(1, (hunger - baseline) >= 0.5F ? baseline + 1 : baseline))
.saturationModifier(food.getSaturationModifier() * ratios.getSecond())
.build();
}

View file

@ -49,7 +49,7 @@ public record Effect(
});
if (tooltip.size() == size) {
if (stack.isFood()) {
tooltip.add(Text.literal(" ").append(Text.translatable("tag.unicopia.food_types.fruits_and_vegetables")).formatted(Formatting.GRAY));
tooltip.add(Text.literal(" ").append(Text.translatable("tag.unicopia.food_types.misc")).formatted(Formatting.GRAY));
} else if (stack.getUseAction() == UseAction.DRINK) {
tooltip.add(Text.literal(" ").append(Text.translatable("tag.unicopia.food_types.drinks")).formatted(Formatting.GRAY));
}

View file

@ -82,6 +82,15 @@ public class PonyDiets implements DietView {
tooltip.add(Text.translatable("unicopia.diet.information").formatted(Formatting.DARK_PURPLE));
getEffects(stack, pony).appendTooltip(stack, tooltip, context);
/*for (Race race : Race.REGISTRY) {
var diet = diets.get(race);
if (diet != null) {
tooltip.add(race.getDisplayName());
diet.appendTooltip(stack, user, tooltip, context);
}
}*/
getDiet(pony).appendTooltip(stack, user, tooltip, context);
}
}

View file

@ -4,6 +4,8 @@ import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Stream;
import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.compat.trinkets.TrinketsDelegate;
import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.util.*;
@ -67,19 +69,23 @@ public class ItemTracker implements NbtSerialisable, Copyable<ItemTracker>, Tick
@Override
public void tick() {
update(living, living.getArmourStacks());
update(living.getArmourStacks());
}
private void update(Living<?> living, Stream<ItemStack> stacks) {
private void update(Stream<ItemStack> stacks) {
final Set<Trackable> found = new HashSet<>();
final Set<ItemStack> foundStacks = new HashSet<>();
stacks.forEach(stack -> {
if (stack.getItem() instanceof Trackable trackable) {
items.compute(trackable, (item, prev) -> prev == null ? 1 : prev + 1);
if (items.compute(trackable, (item, prev) -> prev == null ? 1 : prev + 1) == 1) {
trackable.onEquipped(this.living);
}
found.add(trackable);
foundStacks.add(stack);
}
});
items.entrySet().removeIf(e -> {
if (!found.contains(e.getKey())) {
e.getKey().onUnequipped(living, e.getValue());
@ -90,13 +96,16 @@ public class ItemTracker implements NbtSerialisable, Copyable<ItemTracker>, Tick
if (!(living instanceof Pony)) {
foundStacks.forEach(stack -> {
if (getTicks((Trackable)stack.getItem()) == 1) {
stack.inventoryTick(living.asWorld(), living.asEntity(), 0, false);
}
stack.inventoryTick(living.asWorld(), living.asEntity(), 0, false);
});
}
}
public long forceRemove(Trackable charm) {
@Nullable Long time = items.remove(charm);
return time == null ? 0 : time;
}
public long getTicks(Trackable charm) {
return items.getOrDefault(charm.asItem(), 0L);
}

View file

@ -23,6 +23,7 @@ import com.minelittlepony.unicopia.entity.behaviour.Guest;
import com.minelittlepony.unicopia.entity.collision.MultiBoundingBoxEntity;
import com.minelittlepony.unicopia.entity.damage.MagicalDamageSource;
import com.minelittlepony.unicopia.entity.duck.LivingEntityDuck;
import com.minelittlepony.unicopia.entity.effect.CorruptInfluenceStatusEffect;
import com.minelittlepony.unicopia.entity.effect.EffectUtils;
import com.minelittlepony.unicopia.entity.effect.UEffects;
import com.minelittlepony.unicopia.entity.player.Pony;
@ -49,6 +50,7 @@ import net.minecraft.entity.attribute.EntityAttributeModifier;
import net.minecraft.entity.damage.DamageSource;
import net.minecraft.entity.damage.DamageTypes;
import net.minecraft.entity.data.*;
import net.minecraft.entity.mob.HostileEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.projectile.ProjectileEntity;
import net.minecraft.item.BlockItem;
@ -519,6 +521,10 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
}
}
if (entity instanceof HostileEntity mob && mob.hasStatusEffect(UEffects.CORRUPT_INFLUENCE) && mob.getRandom().nextInt(4) == 0) {
CorruptInfluenceStatusEffect.reproduce(mob);
}
return Optional.empty();
}

View file

@ -1,5 +1,7 @@
package com.minelittlepony.unicopia.entity.effect;
import java.util.UUID;
import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.Owned;
@ -13,6 +15,8 @@ import net.minecraft.entity.attribute.EntityAttributeModifier;
import net.minecraft.entity.attribute.EntityAttributes;
import net.minecraft.entity.effect.StatusEffect;
import net.minecraft.entity.effect.StatusEffectCategory;
import net.minecraft.entity.effect.StatusEffectInstance;
import net.minecraft.entity.effect.StatusEffects;
import net.minecraft.entity.mob.HostileEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.world.WorldEvents;
@ -24,7 +28,6 @@ public class CorruptInfluenceStatusEffect extends StatusEffect {
addAttributeModifier(EntityAttributes.GENERIC_ATTACK_SPEED, "6D706448-6A60-4F59-BE8A-C23A6DD2C7A9", 10, EntityAttributeModifier.Operation.ADDITION);
}
@SuppressWarnings("unchecked")
@Override
public void applyUpdateEffect(LivingEntity entity, int amplifier) {
@ -32,7 +35,7 @@ public class CorruptInfluenceStatusEffect extends StatusEffect {
return;
}
if (entity instanceof HostileEntity) {
if (entity instanceof HostileEntity mob) {
int nearby = entity.getWorld().getOtherEntities(entity, entity.getBoundingBox().expand(40), i -> i.getType() == entity.getType()).size();
@ -48,25 +51,12 @@ public class CorruptInfluenceStatusEffect extends StatusEffect {
return;
}
HostileEntity mob = (HostileEntity)entity;
reproduce(mob);
HostileEntity clone = (HostileEntity)mob.getType().create(mob.getWorld());
clone.copyPositionAndRotation(entity);
Equine.of(clone).ifPresent(eq -> {
if (eq instanceof Owned.Mutable) {
((Owned.Mutable<Entity>)eq).setMaster(mob);
}
});
mob.getWorld().spawnEntity(clone);
if (!mob.isSilent()) {
mob.getWorld().syncWorldEvent((PlayerEntity)null, WorldEvents.ZOMBIE_INFECTS_VILLAGER, mob.getBlockPos(), 0);
}
} else if (entity.age % 2000 == 0) {
entity.damage(Living.living(entity).damageOf(UDamageTypes.ALICORN_AMULET), 2);
}
}
@Override
@ -78,4 +68,31 @@ public class CorruptInfluenceStatusEffect extends StatusEffect {
public boolean canApplyUpdateEffect(int duration, int amplifier) {
return duration > 0;
}
public static void reproduce(HostileEntity mob) {
HostileEntity clone = (HostileEntity)mob.getType().create(mob.getWorld());
clone.copyPositionAndRotation(mob);
clone.takeKnockback(0.1, 0.5, 0.5);
mob.takeKnockback(0.1, -0.5, -0.5);
if (mob.getRandom().nextInt(4) != 0) {
mob.clearStatusEffects();
} else {
if (clone.getAttributes().hasAttribute(EntityAttributes.GENERIC_MAX_HEALTH)) {
float maxHealthDifference = mob.getMaxHealth() - clone.getMaxHealth();
clone.addStatusEffect(new StatusEffectInstance(StatusEffects.STRENGTH, 900000, 2));
clone.getAttributeInstance(EntityAttributes.GENERIC_MAX_HEALTH)
.addPersistentModifier(new EntityAttributeModifier(UUID.randomUUID(), "Corruption Strength Modifier", maxHealthDifference + 1, EntityAttributeModifier.Operation.ADDITION));
}
if (clone.getAttributes().hasAttribute(EntityAttributes.GENERIC_ATTACK_DAMAGE)) {
clone.getAttributeInstance(EntityAttributes.GENERIC_ATTACK_DAMAGE)
.addPersistentModifier(new EntityAttributeModifier(UUID.randomUUID(), "Corruption Damage Modifier", mob.getAttributeValue(EntityAttributes.GENERIC_ATTACK_DAMAGE) + 1, EntityAttributeModifier.Operation.ADDITION));
}
}
mob.getWorld().spawnEntity(clone);
if (!mob.isSilent()) {
mob.getWorld().syncWorldEvent((PlayerEntity)null, WorldEvents.ZOMBIE_INFECTS_VILLAGER, mob.getBlockPos(), 0);
}
}
}

View file

@ -10,8 +10,16 @@ import net.minecraft.registry.Registries;
public interface UEffects {
StatusEffect FOOD_POISONING = register("food_poisoning", new FoodPoisoningStatusEffect(3484199));
StatusEffect SUN_BLINDNESS = register("sun_blindness", new SunBlindnessStatusEffect(0x886F0F));
/**
* Status effect emitted by players with a high level of corruption.
* When affecting an entity, will give them a random chance to reproduce or duplicate themselves when they die.
*/
StatusEffect CORRUPT_INFLUENCE = register("corrupt_influence", new CorruptInfluenceStatusEffect(0x00FF00));
StatusEffect PARALYSIS = register("paralysis", new StatusEffect(StatusEffectCategory.HARMFUL, 0) {});
/**
* Side-effect of wearing the alicorn amulet.
* Causes the player to lose grip on whatever item they're holding.
*/
StatusEffect BUTTER_FINGERS = register("butter_fingers", new ButterfingersStatusEffect(0x888800));
private static StatusEffect register(String name, StatusEffect effect) {

View file

@ -386,12 +386,13 @@ public class ButterflyEntity extends AmbientEntity {
public static final Variant[] VALUES = Variant.values();
private static final Map<String, Variant> REGISTRY = Arrays.stream(VALUES).collect(Collectors.toMap(a -> a.name().toLowerCase(Locale.ROOT), Function.identity()));
private final Identifier skin = Unicopia.id("textures/entity/butterfly/" + name().toLowerCase() + ".png");
private final Identifier skin = Unicopia.id("textures/entity/butterfly/" + name().toLowerCase(Locale.ROOT) + ".png");
public Identifier getSkin() {
return skin;
}
static Variant byId(int index) {
public static Variant byId(int index) {
return VALUES[Math.max(0, index) % VALUES.length];
}

View file

@ -4,6 +4,7 @@ import java.util.function.Predicate;
import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.entity.behaviour.EntityBehaviour;
import com.minelittlepony.unicopia.projectile.MagicBeamEntity;
import com.minelittlepony.unicopia.projectile.MagicProjectileEntity;
import com.minelittlepony.unicopia.projectile.PhysicsBodyProjectileEntity;
@ -32,7 +33,7 @@ public interface UEntities {
.trackRangeBlocks(100)
.trackedUpdateRate(2)
.dimensions(EntityDimensions.fixed(0.25F, 0.25F)));
EntityType<MagicProjectileEntity> MAGIC_BEAM = register("magic_beam", FabricEntityTypeBuilder.<MagicProjectileEntity>create(SpawnGroup.MISC, MagicProjectileEntity::new)
EntityType<MagicBeamEntity> MAGIC_BEAM = register("magic_beam", FabricEntityTypeBuilder.<MagicBeamEntity>create(SpawnGroup.MISC, MagicBeamEntity::new)
.trackRangeBlocks(100)
.trackedUpdateRate(2)
.dimensions(EntityDimensions.fixed(0.25F, 0.25F)));

View file

@ -0,0 +1,84 @@
package com.minelittlepony.unicopia.entity.player;
import com.minelittlepony.unicopia.InteractionManager;
import com.minelittlepony.unicopia.ability.magic.SpellPredicate;
import com.minelittlepony.unicopia.entity.ItemTracker;
import com.minelittlepony.unicopia.entity.effect.UEffects;
import com.minelittlepony.unicopia.item.UItems;
import com.minelittlepony.unicopia.util.Tickable;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.effect.StatusEffectInstance;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.particle.ParticleTypes;
import net.minecraft.util.math.random.Random;
public class CorruptionHandler implements Tickable {
private final Pony pony;
public CorruptionHandler(Pony pony) {
this.pony = pony;
}
public boolean hasCorruptingMagic() {
return pony.getSpellSlot().get(SpellPredicate.IS_CORRUPTING, false).isPresent() || UItems.ALICORN_AMULET.isApplicable(pony.asEntity());
}
@Override
public void tick() {
if (pony.isClient() || pony.asEntity().age % 5 != 0) {
return;
}
PlayerEntity entity = pony.asEntity();
Random random = pony.asEntity().getRandom();
if (!UItems.ALICORN_AMULET.isApplicable(entity)) {
if (entity.age % (10 * ItemTracker.SECONDS) == 0) {
if (random.nextInt(100) == 0) {
pony.getCorruption().add(-1);
pony.setDirty();
}
if (entity.getHealth() >= entity.getMaxHealth() - 1 && !entity.getHungerManager().isNotFull()) {
pony.getCorruption().add(-random.nextInt(4));
pony.setDirty();
}
}
}
if (pony.asEntity().age % 100 == 0 && hasCorruptingMagic()) {
pony.getCorruption().add(random.nextInt(4));
}
float corruptionPercentage = pony.getCorruption().getScaled(1);
if (corruptionPercentage > 0.5F && random.nextFloat() < corruptionPercentage - 0.25F) {
pony.findAllEntitiesInRange(10, e -> e instanceof LivingEntity && !((LivingEntity)e).hasStatusEffect(UEffects.CORRUPT_INFLUENCE)).forEach(e -> {
((LivingEntity)e).addStatusEffect(new StatusEffectInstance(UEffects.CORRUPT_INFLUENCE, 100, 1));
recover(10);
});
}
if (corruptionPercentage > 0.25F && random.nextInt(200) == 0) {
if (!pony.asEntity().hasStatusEffect(UEffects.BUTTER_FINGERS)) {
pony.asEntity().addStatusEffect(new StatusEffectInstance(UEffects.BUTTER_FINGERS, 2100, 1));
recover(25);
}
}
if (random.nextFloat() < corruptionPercentage) {
pony.spawnParticles(ParticleTypes.ASH, 10);
}
}
private void recover(float percentage) {
pony.getCorruption().set((int)(pony.getCorruption().get() * (1 - percentage)));
InteractionManager.INSTANCE.playLoopingSound(pony.asEntity(), InteractionManager.SOUND_HEART_BEAT, 0);
MagicReserves reserves = pony.getMagicalReserves();
reserves.getExertion().addPercent(10);
reserves.getEnergy().add(10);
pony.setDirty();
}
}

View file

@ -29,6 +29,7 @@ import com.minelittlepony.unicopia.server.world.UGameRules;
import com.minelittlepony.unicopia.server.world.WeatherConditions;
import com.minelittlepony.unicopia.util.*;
import net.fabricmc.fabric.api.tag.convention.v1.ConventionalBlockTags;
import net.minecraft.block.*;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.EntityPose;
@ -195,7 +196,7 @@ public class PlayerPhysics extends EntityPhysics<PlayerEntity> implements Tickab
if ((RegistryUtils.isIn(entity.getWorld(), dimension, RegistryKeys.DIMENSION_TYPE, UTags.HAS_NO_ATMOSPHERE)
|| Unicopia.getConfig().dimensionsWithoutAtmosphere.get().contains(RegistryUtils.getId(entity.getWorld(), dimension, RegistryKeys.DIMENSION_TYPE).toString()))
&& !OxygenUtils.entityHasOxygen(entity.getWorld(), entity)) {
&& !OxygenUtils.API.hasOxygen(entity)) {
return FlightType.NONE;
}
@ -252,6 +253,10 @@ public class PlayerPhysics extends EntityPhysics<PlayerEntity> implements Tickab
final MutableVector velocity = new MutableVector(entity.getVelocity());
if (isGravityNegative()) {
velocity.y *= -1;
}
if (isGravityNegative() && !entity.isSneaking() && entity.isInSneakingPose()) {
float currentHeight = entity.getDimensions(entity.getPose()).height;
float sneakingHeight = entity.getDimensions(EntityPose.STANDING).height;
@ -343,7 +348,7 @@ public class PlayerPhysics extends EntityPhysics<PlayerEntity> implements Tickab
}
if (((LivingEntityDuck)entity).isJumping()) {
velocity.y -= 0.2F * getGravitySignum();
velocity.y -= 0.2F;
velocity.y /= 2F;
}
@ -391,6 +396,10 @@ public class PlayerPhysics extends EntityPhysics<PlayerEntity> implements Tickab
velocity.z /= heavyness;
}
if (isGravityNegative()) {
velocity.y *= -1;
}
entity.setVelocity(velocity.toImmutable());
if (isFlying() && !entity.isFallFlying() && !pony.getAcrobatics().isHanging() && pony.isClient()) {
@ -448,7 +457,7 @@ public class PlayerPhysics extends EntityPhysics<PlayerEntity> implements Tickab
}
}
velocity.y -= 0.02 * getGravitySignum();
velocity.y -= 0.02;
velocity.x *= 0.9896;
velocity.z *= 0.9896;
}
@ -541,7 +550,7 @@ public class PlayerPhysics extends EntityPhysics<PlayerEntity> implements Tickab
boolean takeOffCondition =
(horMotion > 0.05 || motion > 0.05)
&& pony.getJumpingHeuristic().hasChanged(Heuristic.TWICE);
boolean fallingTakeOffCondition = !entity.isOnGround() && velocity.y < -1.6 * getGravitySignum() && entity.fallDistance > 1;
boolean fallingTakeOffCondition = !entity.isOnGround() && velocity.y < -1.6 && entity.fallDistance > 1;
if ((takeOffCondition || fallingTakeOffCondition) && !pony.getAcrobatics().isHanging() && !isCancelled) {
initiateTakeoff(velocity);
@ -551,9 +560,7 @@ public class PlayerPhysics extends EntityPhysics<PlayerEntity> implements Tickab
private void initiateTakeoff(MutableVector velocity) {
startFlying(false);
if (!isGravityNegative()) {
velocity.y += getHorizontalMotion() + 0.3;
}
velocity.y += getHorizontalMotion() + 0.3;
applyThrust(velocity);
velocity.x *= 0.2;
@ -635,6 +642,9 @@ public class PlayerPhysics extends EntityPhysics<PlayerEntity> implements Tickab
} else {
float targetUpdraft = (float)WeatherConditions.getUpdraft(new BlockPos.Mutable().set(entity.getBlockPos()), entity.getWorld()) / 3F;
targetUpdraft *= 1 + motion;
if (isGravityNegative()) {
targetUpdraft *= -1;
}
this.updraft.update(targetUpdraft, targetUpdraft > this.updraft.getTarget() ? 30_000 : 3000);
double updraft = this.updraft.getValue();
velocity.y += updraft;
@ -647,7 +657,7 @@ public class PlayerPhysics extends EntityPhysics<PlayerEntity> implements Tickab
descentRate *= 0.8F;
}
velocity.y -= descentRate * getGravityModifier();
velocity.y -= descentRate;
}
private void applyThrust(MutableVector velocity) {
@ -695,7 +705,7 @@ public class PlayerPhysics extends EntityPhysics<PlayerEntity> implements Tickab
} else {
velocity.x += direction.x * 1.3F;
velocity.z += direction.z * 1.3F;
velocity.y += ((direction.y * 2.45 + Math.abs(direction.y) * 10)) * getGravitySignum();// - heavyness / 5F
velocity.y += ((direction.y * 2.45 + Math.abs(direction.y) * 10));// - heavyness / 5F
}
if (velocity.y < 0 && hovering) {
@ -759,9 +769,9 @@ public class PlayerPhysics extends EntityPhysics<PlayerEntity> implements Tickab
entity.addVelocity(orientation.x, orientation.y, orientation.z);
boolean isEarthPonySmash = pony.getObservedSpecies().canUseEarth() && !isFlying();
int damage = TraceHelper.findBlocks(entity, speed + 4, 1, state -> (isEarthPonySmash && !state.isAir()) || state.isIn(UTags.GLASS_PANES)).stream()
int damage = TraceHelper.findBlocks(entity, speed + 4, 1, state -> (isEarthPonySmash && !state.isAir()) || state.isIn(ConventionalBlockTags.GLASS_PANES)).stream()
.flatMap(pos -> BlockPos.streamOutwards(pos, 2, 2, 2))
.filter(pos -> (isEarthPonySmash && !entity.getWorld().isAir(pos)) || entity.getWorld().getBlockState(pos).isIn(UTags.GLASS_PANES))
.filter(pos -> (isEarthPonySmash && !entity.getWorld().isAir(pos)) || entity.getWorld().getBlockState(pos).isIn(ConventionalBlockTags.GLASS_PANES))
.reduce(0, (u, pos) -> {
if (pony.canModifyAt(pos, ModificationType.PHYSICAL)) {
if (isEarthPonySmash) {

View file

@ -92,6 +92,7 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
private final PlayerCamera camera = new PlayerCamera(this);
private final TraitDiscovery discoveries = new TraitDiscovery(this);
private final Acrobatics acrobatics = new Acrobatics(this);
private final CorruptionHandler corruptionHandler = new CorruptionHandler(this);
private final Map<String, Integer> advancementProgress = new HashMap<>();
@ -129,6 +130,7 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
addTicker(this::updateBatPonyAbilities);
addTicker(this::updateCorruptionDecay);
addTicker(new PlayerAttributes(this));
addTicker(corruptionHandler);
}
@Override
@ -289,6 +291,10 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
return corruption;
}
public CorruptionHandler getCorruptionhandler() {
return corruptionHandler;
}
public boolean canUseSuperMove() {
return entity.isCreative() || getMagicalReserves().getCharge().get() >= getMagicalReserves().getCharge().getMax();
}
@ -572,24 +578,7 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
}
private void updateCorruptionDecay() {
if (!isClient() && !UItems.ALICORN_AMULET.isApplicable(entity)) {
if (entity.age % (10 * ItemTracker.SECONDS) == 0) {
if (entity.getWorld().random.nextInt(100) == 0) {
corruption.add(-1);
setDirty();
}
if (entity.getHealth() >= entity.getMaxHealth() - 1 && !entity.getHungerManager().isNotFull()) {
corruption.add(-entity.getWorld().random.nextInt(4));
setDirty();
}
}
if (entity.hurtTime == 1 && getCompositeRace().physical().canCast()) {
corruption.add(1);
setDirty();
}
}
}
@Override
@ -789,6 +778,12 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
@Override
public boolean subtractEnergyCost(double foodSubtract) {
if (getSpellSlot().get(SpellPredicate.IS_CORRUPTING, false).isPresent()) {
int corruptionTaken = (int)(foodSubtract * (AmuletSelectors.ALICORN_AMULET.test(entity) ? 0.9F : 0.5F));
foodSubtract -= corruptionTaken;
getCorruption().add(corruptionTaken);
}
List<Pony> partyMembers = FriendshipBraceletItem.getPartyMembers(this, 10).toList();
if (!partyMembers.isEmpty()) {
@ -956,10 +951,10 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
@Override
public void onSpellSet(@Nullable Spell spell) {
if (spell != null) {
if (spell.getAffinity() == Affinity.BAD && entity.getWorld().random.nextInt(120) == 0) {
getCorruption().add(1);
if (spell.getAffinity() == Affinity.BAD && entity.getWorld().random.nextInt(20) == 0) {
getCorruption().add(entity.getRandom().nextBetween(1, 10));
}
getCorruption().add((int)spell.getTraits().getCorruption());
getCorruption().add((int)spell.getTraits().getCorruption() * 10);
setDirty();
}
}

View file

@ -134,7 +134,7 @@ public class AlicornAmuletItem extends AmuletItem implements ItemTracker.Trackab
@Override
public void onEquipped(Living<?> wearer) {
wearer.playSound(USounds.ITEM_ALICORN_AMULET_CURSE, 3, 1);
wearer.playSound(USounds.ITEM_ALICORN_AMULET_CURSE, 0.5F, 1);
}
@Override
@ -234,7 +234,7 @@ public class AlicornAmuletItem extends AmuletItem implements ItemTracker.Trackab
// butterfingers effects
if (daysAttached >= 2) {
if (pony.asWorld().random.nextInt(200) == 0 && !pony.asEntity().hasStatusEffect(UEffects.BUTTER_FINGERS)) {
pony.asEntity().addStatusEffect(new StatusEffectInstance(UEffects.CORRUPT_INFLUENCE, 2100, 1));
pony.asEntity().addStatusEffect(new StatusEffectInstance(UEffects.BUTTER_FINGERS, 2100, 1));
}
pony.findAllEntitiesInRange(10, e -> e instanceof LivingEntity && !((LivingEntity)e).hasStatusEffect(UEffects.CORRUPT_INFLUENCE)).forEach(e -> {

View file

@ -68,7 +68,7 @@ public class AmuletItem extends WearableItem implements ChargeableItem {
@Override
public EquipmentSlot getSlotType(ItemStack stack) {
return EquipmentSlot.CHEST;
return TrinketsDelegate.hasTrinkets() ? EquipmentSlot.OFFHAND : EquipmentSlot.CHEST;
}
@Override

View file

@ -18,7 +18,7 @@ import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
public class BedsheetsItem extends Item {
private static final Map<CloudBedBlock.SheetPattern, Item> ITEMS = new HashMap<>();
public static final Map<CloudBedBlock.SheetPattern, Item> ITEMS = new HashMap<>();
private final CloudBedBlock.SheetPattern pattern;

View file

@ -57,7 +57,7 @@ public class BellItem extends Item implements ChargeableItem {
public ActionResult useOnEntity(ItemStack stack, PlayerEntity player, LivingEntity target, Hand hand) {
player.setCurrentHand(hand);
Pony pony = Pony.of(player);
pony.getCorruption().add(1);
pony.getCorruption().add(1 + player.getRandom().nextBetween(1, 10));
pony.playSound(USounds.ITEM_GROGAR_BELL_USE, 0.4F, 0.2F);
Living<?> targetLiving = target instanceof MobEntity || target instanceof PlayerEntity ? Living.getOrEmpty(target)
.filter(living -> !(living instanceof Creature c && c.isDiscorded()))
@ -79,7 +79,7 @@ public class BellItem extends Item implements ChargeableItem {
if (hasCharge(stack)) {
pony.playSound(USounds.ITEM_GROGAR_BELL_CHARGE, 0.6F, 1);
pony.getCorruption().add(1);
pony.getCorruption().add(player.getRandom().nextBetween(1, 10));
if (offhandStack.getItem() instanceof ChargeableItem chargeable) {
float maxChargeBy = chargeable.getMaxCharge() - ChargeableItem.getEnergy(offhandStack);
float energyTransferred = Math.min(ChargeableItem.getEnergy(stack), maxChargeBy);

View file

@ -177,7 +177,7 @@ public interface UItems {
Item GREEN_BED_SHEETS = register(CloudBedBlock.SheetPattern.GREEN);
Item CYAN_BED_SHEETS = register(CloudBedBlock.SheetPattern.CYAN);
Item LIGHT_BLUE_BED_SHEETS = register(CloudBedBlock.SheetPattern.LIGHT_BLUE);
Item BLUE_SHEETS = register(CloudBedBlock.SheetPattern.BLUE);
Item BLUE_BED_SHEETS = register(CloudBedBlock.SheetPattern.BLUE);
Item PURPLE_BED_SHEETS = register(CloudBedBlock.SheetPattern.PURPLE);
Item MAGENTA_BED_SHEETS = register(CloudBedBlock.SheetPattern.MAGENTA);
Item PINK_BED_SHEETS = register(CloudBedBlock.SheetPattern.PINK);

View file

@ -54,11 +54,17 @@ public interface URecipes {
LootTable table = manager.getLootTable(modId);
if (table != LootTable.EMPTY) {
supplier.modifyPools(poolBuilder -> {
if (id.getPath().startsWith("blocks/")) {
for (var pool : table.pools) {
poolBuilder.with(pool.entries);
supplier.pool(pool);
}
});
} else {
supplier.modifyPools(poolBuilder -> {
for (var pool : table.pools) {
poolBuilder.with(pool.entries);
}
});
}
}
});
}

View file

@ -2,7 +2,7 @@ package com.minelittlepony.unicopia.item;
import java.util.List;
import com.minelittlepony.unicopia.UTags;
import com.minelittlepony.unicopia.UConventionalTags;
import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.advancement.UCriteria;
import com.minelittlepony.unicopia.entity.Living;
@ -103,7 +103,7 @@ public class ZapAppleItem extends Item implements ChameleonItem, MultiItem {
public List<ItemStack> getDefaultStacks() {
return Unicopia.SIDE.getPony().map(Pony::asWorld)
.stream()
.flatMap(world -> RegistryUtils.valuesForTag(world, UTags.APPLES))
.flatMap(world -> RegistryUtils.valuesForTag(world, UConventionalTags.APPLES))
.filter(a -> a != this).map(item -> {
ItemStack stack = new ItemStack(this);
stack.getOrCreateNbt().putString("appearance", Registries.ITEM.getId(item).toString());

View file

@ -59,7 +59,7 @@ public class SimpleEnchantment extends Enchantment {
@Override
public final boolean isAvailableForRandomSelection() {
return options.looted;
return options.table;
}
public static class Data {
@ -77,8 +77,8 @@ public class SimpleEnchantment extends Enchantment {
public static class Options {
private boolean cursed;
private boolean treasured;
private boolean traded = true;
private boolean looted = true;
private boolean traded;
private boolean table;
private Rarity rarity;
private int maxLevel = 1;
private EquipmentSlot[] slots;
@ -102,6 +102,9 @@ public class SimpleEnchantment extends Enchantment {
this.target = target;
}
/**
* Sets the enchantment to apply to all items.
*/
public Options ignoreTarget() {
allItems = true;
return this;
@ -128,8 +131,7 @@ public class SimpleEnchantment extends Enchantment {
}
/**
* Treasure enchantments only generate in loot tables with high-value items or by trading with villagers.
* They do not appear in the enchanting table.
* Whether this enchantment should be limited to high value trades or leveled up enchanting table offers.
*/
public Options treasure() {
treasured = true;
@ -137,25 +139,24 @@ public class SimpleEnchantment extends Enchantment {
}
/**
* Loot-Only enchantments do not appear in villager trades.
* They may still appear in loot table generation and can be found in the enchanting table.
* Set whether this enchantment should appear in villager trades.
*/
public Options lootedOnly() {
traded = false;
looted = true;
public Options traded() {
this.traded = true;
return this;
}
/**
* Trade-Only enchantments are excluded from loot table generation and do not appear in the enchanting table.
* They can only be found by trading with villagers.
* Sets whether the enchantment should appear in enchanting table draws.
*/
public Options tradedOnly() {
looted = false;
traded = true;
public Options table() {
this.table = true;
return this;
}
/**
* Sets the maximum level for the enchantment.
*/
public Options maxLevel(int level) {
maxLevel = level;
return this;

View file

@ -24,18 +24,30 @@ public interface UEnchantments {
/**
* Makes a sound when there are interesting blocks in your area.
*
* Appears in:
* - Trades
* - Enchanting Table
*/
Enchantment GEM_FINDER = register("gem_finder", new GemFindingEnchantment(Options.create(EnchantmentTarget.DIGGER, UEnchantmentValidSlots.HANDS).rarity(Rarity.RARE).maxLevel(3).treasure()));
Enchantment GEM_FINDER = register("gem_finder", new GemFindingEnchantment(Options.create(EnchantmentTarget.DIGGER, UEnchantmentValidSlots.HANDS).rarity(Rarity.RARE).maxLevel(3).treasure().traded().table()));
/**
* Protects against wall collisions and earth pony attacks!
*
* Appears in:
* - Trades
* - Enchanting Table
*/
Enchantment PADDED = register("padded", new SimpleEnchantment(Options.armor().rarity(Rarity.UNCOMMON).maxLevel(3)));
Enchantment PADDED = register("padded", new SimpleEnchantment(Options.armor().rarity(Rarity.UNCOMMON).maxLevel(3).traded().table()));
/**
* Heavy players move more slowly but are less likely to be flung around wildly.
*
* Appears in:
* - Trades
* - Enchanting Table
*/
Enchantment HEAVY = register("heavy", new AttributedEnchantment(Options.armor().rarity(Rarity.RARE).maxLevel(4)))
Enchantment HEAVY = register("heavy", new AttributedEnchantment(Options.armor().rarity(Rarity.RARE).maxLevel(4).traded().table()))
.addModifier(EntityAttributes.GENERIC_MOVEMENT_SPEED, (user, level) -> {
return new EntityAttributeModifier(UUID.fromString("a3d5a94f-4c40-48f6-a343-558502a13e10"), "Heavyness", (1 - level/(float)10) - 1, Operation.MULTIPLY_TOTAL);
});
@ -44,13 +56,20 @@ public interface UEnchantments {
* It's dangerous to go alone, take this!
*
* Weapons will become stronger the more allies you have around.
*
* Appears in:
* - Trades
* - Enchanting Table
*/
Enchantment HERDS = register("herds", new CollaboratorEnchantment(Options.create(EnchantmentTarget.WEAPON, EquipmentSlot.MAINHAND).rarity(Rarity.RARE).maxLevel(3)));
Enchantment HERDS = register("herds", new CollaboratorEnchantment(Options.create(EnchantmentTarget.WEAPON, EquipmentSlot.MAINHAND).rarity(Rarity.RARE).maxLevel(3).treasure().traded().table()));
/**
* Alters gravity
*
* Appears in:
* - Trades
*/
Enchantment REPULSION = register("repulsion", new AttributedEnchantment(Options.create(EnchantmentTarget.ARMOR_FEET, EquipmentSlot.FEET).rarity(Rarity.VERY_RARE).maxLevel(3)))
Enchantment REPULSION = register("repulsion", new AttributedEnchantment(Options.create(EnchantmentTarget.ARMOR_FEET, EquipmentSlot.FEET).rarity(Rarity.VERY_RARE).maxLevel(3).treasure().traded()))
.addModifier(UEntityAttributes.ENTITY_GRAVITY_MODIFIER, (user, level) -> {
return new EntityAttributeModifier(UUID.fromString("1734bbd6-1916-4124-b710-5450ea70fbdb"), "Anti Grav", (0.5F - (0.375 * (level - 1))) - 1, Operation.MULTIPLY_TOTAL);
});
@ -60,35 +79,52 @@ public interface UEnchantments {
*
* Mobs really want your candy. You'd better give it to them.
*/
Enchantment WANT_IT_NEED_IT = register("want_it_need_it", new WantItNeedItEnchantment(Options.allItems().rarity(Rarity.VERY_RARE).curse().treasure()));
Enchantment WANT_IT_NEED_IT = register("want_it_need_it", new WantItNeedItEnchantment(Options.allItems().rarity(Rarity.VERY_RARE).curse().treasure().traded()));
/**
* Hahaha geddit?
*
* Random things happen.
*
* Appears in:
* - Trades
*/
PoisonedJokeEnchantment POISONED_JOKE = register("poisoned_joke", new PoisonedJokeEnchantment(Options.allItems().rarity(Rarity.VERY_RARE).curse().tradedOnly()));
PoisonedJokeEnchantment POISONED_JOKE = register("poisoned_joke", new PoisonedJokeEnchantment(Options.allItems().rarity(Rarity.VERY_RARE).curse().traded()));
/**
* Who doesn't like a good freakout?
*
* Appears in:
* - Trades
*/
Enchantment STRESSED = register("stressed", new StressfulEnchantment(Options.allItems().rarity(Rarity.VERY_RARE).curse().treasure().maxLevel(3)));
Enchantment STRESSED = register("stressed", new StressfulEnchantment(Options.allItems().rarity(Rarity.VERY_RARE).curse().treasure().traded().maxLevel(3)));
/**
* This item just wants to be held.
*
* Appears in:
* - Trades
* - Enchanting Table
*/
Enchantment CLINGY = register("clingy", new SimpleEnchantment(Options.allItems().rarity(Rarity.VERY_RARE).curse().maxLevel(6)));
Enchantment CLINGY = register("clingy", new SimpleEnchantment(Options.allItems().rarity(Rarity.VERY_RARE).maxLevel(6).traded().table().treasure()));
/**
* Items with loyalty are kept after death.
* Only works if they don't also have curse of binding.
*
* Appears in:
* - Enchanting Table
*/
Enchantment HEART_BOUND = register("heart_bound", new SimpleEnchantment(Options.create(EnchantmentTarget.VANISHABLE, UEnchantmentValidSlots.ANY).rarity(Rarity.UNCOMMON).maxLevel(5)));
Enchantment HEART_BOUND = register("heart_bound", new SimpleEnchantment(Options.create(EnchantmentTarget.VANISHABLE, UEnchantmentValidSlots.ANY).rarity(Rarity.UNCOMMON).maxLevel(5).treasure().table()));
/**
* Consumes drops whilst mining and produces experience instead
*
* Appears in:
* - Trades
* - Enchanting Table
*/
Enchantment CONSUMPTION = register("consumption", new ConsumptionEnchantment(Options.create(EnchantmentTarget.DIGGER, UEnchantmentValidSlots.HANDS).rarity(Rarity.VERY_RARE)));
Enchantment CONSUMPTION = register("consumption", new ConsumptionEnchantment(Options.create(EnchantmentTarget.DIGGER, UEnchantmentValidSlots.HANDS).rarity(Rarity.VERY_RARE).treasure().table().traded()));
static void bootstrap() { }

View file

@ -1,20 +1,30 @@
package com.minelittlepony.unicopia.mixin.ad_astra;
import org.spongepowered.asm.mixin.Dynamic;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Pseudo;
import org.spongepowered.asm.mixin.gen.Invoker;
import org.spongepowered.asm.mixin.gen.Accessor;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Coerce;
import org.spongepowered.asm.mixin.injection.Inject;
import net.minecraft.entity.LivingEntity;
import net.minecraft.world.World;
import com.minelittlepony.unicopia.compat.ad_astra.OxygenUtils;
@Pseudo
@Mixin(
targets = { "earth.terrarium.ad_astra.common.util.OxygenUtils" },
targets = { "earth.terrarium.adastra.api.systems.OxygenApi" },
remap = false
)
public interface MixinOxygenUtils {
@Invoker("entityHasOxygen")
static boolean entityHasOxygen(World world, LivingEntity entity) {
return true;
public interface MixinOxygenUtils extends OxygenUtils.OxygenApi {
@Accessor("API")
@Coerce
static Object getAPI() {
throw new AbstractMethodError("stub");
}
@Dynamic("Compiler-generated class-init() method")
@Inject(method = "<clinit>()V", at = @At("RETURN"), remap = false)
private static void classInit() {
OxygenUtils.API = (OxygenUtils.OxygenApi)getAPI();
}
}

View file

@ -19,7 +19,6 @@ public interface Channel {
C2SPacketType<MsgPlayerFlightControlsInput> FLIGHT_CONTROLS_INPUT = SimpleNetworking.clientToServer(Unicopia.id("flight_controls"), MsgPlayerFlightControlsInput::new);
S2CPacketType<MsgPlayerCapabilities> SERVER_PLAYER_CAPABILITIES = SimpleNetworking.serverToClient(Unicopia.id("player_capabilities"), MsgPlayerCapabilities::new);
S2CPacketType<MsgSpawnProjectile> SERVER_SPAWN_PROJECTILE = SimpleNetworking.serverToClient(Unicopia.id("projectile_entity"), MsgSpawnProjectile::new);
S2CPacketType<MsgBlockDestruction> SERVER_BLOCK_DESTRUCTION = SimpleNetworking.serverToClient(Unicopia.id("block_destruction"), MsgBlockDestruction::new);
S2CPacketType<MsgCancelPlayerAbility> CANCEL_PLAYER_ABILITY = SimpleNetworking.serverToClient(Unicopia.id("player_ability_cancel"), MsgCancelPlayerAbility::read);
S2CPacketType<MsgCasterLookRequest> SERVER_REQUEST_PLAYER_LOOK = SimpleNetworking.serverToClient(Unicopia.id("request_player_look"), MsgCasterLookRequest::new);

View file

@ -2,8 +2,6 @@ package com.minelittlepony.unicopia.network.handler;
import java.util.Map;
import com.minelittlepony.unicopia.InteractionManager;
import com.minelittlepony.unicopia.Owned;
import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.ability.data.Rot;
import com.minelittlepony.unicopia.ability.data.tree.TreeTypes;
@ -16,14 +14,11 @@ import com.minelittlepony.unicopia.client.gui.TribeSelectionScreen;
import com.minelittlepony.unicopia.client.gui.spellbook.ClientChapters;
import com.minelittlepony.unicopia.client.gui.spellbook.SpellbookChapterList.Chapter;
import com.minelittlepony.unicopia.diet.PonyDiets;
import com.minelittlepony.unicopia.entity.mob.UEntities;
import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.network.*;
import com.minelittlepony.unicopia.network.MsgCasterLookRequest.Reply;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.Identifier;
@ -32,7 +27,6 @@ public class ClientNetworkHandlerImpl {
public ClientNetworkHandlerImpl() {
Channel.SERVER_SELECT_TRIBE.receiver().addPersistentListener(this::handleTribeScreen);
Channel.SERVER_SPAWN_PROJECTILE.receiver().addPersistentListener(this::handleSpawnProjectile);
Channel.SERVER_BLOCK_DESTRUCTION.receiver().addPersistentListener(this::handleBlockDestruction);
Channel.CANCEL_PLAYER_ABILITY.receiver().addPersistentListener(this::handleCancelAbility);
Channel.UNLOCK_TRAITS.receiver().addPersistentListener(this::handleUnlockTraits);
@ -47,31 +41,6 @@ public class ClientNetworkHandlerImpl {
client.setScreen(new TribeSelectionScreen(packet.availableRaces(), packet.serverMessage()));
}
@SuppressWarnings("unchecked")
private void handleSpawnProjectile(PlayerEntity sender, MsgSpawnProjectile packet) {
ClientWorld world = client.world;
Entity entity = packet.getEntityType().create(world);
entity.updateTrackedPosition(packet.getX(), packet.getY(), packet.getZ());
entity.refreshPositionAfterTeleport(packet.getX(), packet.getY(), packet.getZ());
entity.setVelocity(packet.getVelocityX(), packet.getVelocityY(), packet.getVelocityZ());
entity.setPitch(packet.getPitch() * 360 / 256F);
entity.setYaw(packet.getYaw() * 360 / 256F);
entity.setId(packet.getId());
entity.setUuid(packet.getUuid());
if (entity instanceof Owned.Mutable) {
((Owned.Mutable<Entity>) entity).setMaster(world.getEntityById(packet.getEntityData()));
}
if (entity.getType() == UEntities.MAGIC_BEAM) {
InteractionManager.instance().playLoopingSound(entity, InteractionManager.SOUND_MAGIC_BEAM, entity.getId());
}
entity.onSpawnPacket(packet);
world.addEntity(entity);
}
private void handleBlockDestruction(PlayerEntity sender, MsgBlockDestruction packet) {
ClientBlockDestructionManager destr = ((ClientBlockDestructionManager.Source)client.worldRenderer).getDestructionManager();

View file

@ -0,0 +1,171 @@
package com.minelittlepony.unicopia.projectile;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Function;
import com.minelittlepony.unicopia.Affinity;
import com.minelittlepony.unicopia.InteractionManager;
import com.minelittlepony.unicopia.ability.magic.Affine;
import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.Levelled;
import com.minelittlepony.unicopia.ability.magic.SpellContainer;
import com.minelittlepony.unicopia.ability.magic.SpellContainer.Operation;
import com.minelittlepony.unicopia.ability.magic.spell.Situation;
import com.minelittlepony.unicopia.ability.magic.spell.Spell;
import com.minelittlepony.unicopia.block.state.StatePredicate;
import com.minelittlepony.unicopia.entity.EntityPhysics;
import com.minelittlepony.unicopia.entity.MagicImmune;
import com.minelittlepony.unicopia.entity.Physics;
import com.minelittlepony.unicopia.entity.mob.UEntities;
import com.minelittlepony.unicopia.network.datasync.EffectSync;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.data.DataTracker;
import net.minecraft.entity.data.TrackedData;
import net.minecraft.entity.data.TrackedDataHandlerRegistry;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.network.packet.s2c.play.EntitySpawnS2CPacket;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
public class MagicBeamEntity extends MagicProjectileEntity implements Caster<MagicBeamEntity>, MagicImmune {
private static final TrackedData<Float> GRAVITY = DataTracker.registerData(MagicBeamEntity.class, TrackedDataHandlerRegistry.FLOAT);
private static final TrackedData<Boolean> HYDROPHOBIC = DataTracker.registerData(MagicBeamEntity.class, TrackedDataHandlerRegistry.BOOLEAN);
private static final TrackedData<NbtCompound> EFFECT = DataTracker.registerData(MagicBeamEntity.class, TrackedDataHandlerRegistry.NBT_COMPOUND);
private final EffectSync effectDelegate = new EffectSync(this, EFFECT);
private final EntityPhysics<MagicProjectileEntity> physics = new EntityPhysics<>(this, GRAVITY);
public MagicBeamEntity(EntityType<MagicBeamEntity> type, World world) {
super(type, world);
}
public MagicBeamEntity(World world, Entity owner, float divergance, Spell spell) {
super(UEntities.MAGIC_BEAM, world);
setPosition(owner.getX(), owner.getEyeY() - 0.1F, owner.getZ());
setOwner(owner);
setVelocity(owner, owner.getPitch(), owner.getYaw(), 0, 1.5F, divergance);
setNoGravity(true);
spell.apply(this);
}
@Override
protected void initDataTracker() {
super.initDataTracker();
getDataTracker().startTracking(GRAVITY, 1F);
getDataTracker().startTracking(HYDROPHOBIC, false);
getDataTracker().startTracking(EFFECT, new NbtCompound());
}
@Override
public void tick() {
super.tick();
if (getOwner() != null) {
effectDelegate.tick(Situation.PROJECTILE);
}
if (getHydrophobic()) {
if (StatePredicate.isFluid(getWorld().getBlockState(getBlockPos()))) {
Vec3d vel = getVelocity();
double velY = vel.y;
velY *= -1;
if (!hasNoGravity()) {
velY += 0.16;
}
setVelocity(new Vec3d(vel.x, velY, vel.z));
}
}
}
public void setHydrophobic() {
getDataTracker().set(HYDROPHOBIC, true);
}
public boolean getHydrophobic() {
return getDataTracker().get(HYDROPHOBIC);
}
@Override
public MagicBeamEntity asEntity() {
return this;
}
@Override
public LevelStore getLevel() {
return getMasterReference().getTarget().map(target -> target.level()).orElse(Levelled.EMPTY);
}
@Override
public LevelStore getCorruption() {
return getMasterReference().getTarget().map(target -> target.corruption()).orElse(Levelled.EMPTY);
}
@Override
public Physics getPhysics() {
return physics;
}
@Override
public Affinity getAffinity() {
return getSpellSlot().get(true).map(Affine::getAffinity).orElse(Affinity.NEUTRAL);
}
@Override
public SpellContainer getSpellSlot() {
return effectDelegate;
}
@Override
public boolean subtractEnergyCost(double amount) {
return Caster.of(getMaster()).filter(c -> c.subtractEnergyCost(amount)).isPresent();
}
@Override
public void onSpawnPacket(EntitySpawnS2CPacket packet) {
super.onSpawnPacket(packet);
InteractionManager.instance().playLoopingSound(this, InteractionManager.SOUND_MAGIC_BEAM, getId());
}
@Override
public void remove(RemovalReason reason) {
super.remove(reason);
getSpellSlot().clear();
}
@Override
protected <T extends ProjectileDelegate> void forEachDelegates(Consumer<T> consumer, Function<Object, T> predicate) {
effectDelegate.tick(spell -> {
Optional.ofNullable(predicate.apply(spell)).ifPresent(consumer);
return Operation.SKIP;
});
super.forEachDelegates(consumer, predicate);
}
@Override
public void readCustomDataFromNbt(NbtCompound compound) {
super.readCustomDataFromNbt(compound);
getDataTracker().set(HYDROPHOBIC, compound.getBoolean("hydrophobic"));
physics.fromNBT(compound);
if (compound.contains("effect")) {
getSpellSlot().put(Spell.readNbt(compound.getCompound("effect")));
}
}
@Override
public void writeCustomDataToNbt(NbtCompound compound) {
super.writeCustomDataToNbt(compound);
compound.putBoolean("hydrophobic", getHydrophobic());
physics.toNBT(compound);
getSpellSlot().get(true).ifPresent(effect -> {
compound.put("effect", Spell.writeNbt(effect));
});
}
}

View file

@ -6,28 +6,12 @@ import java.util.function.Function;
import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.Affinity;
import com.minelittlepony.unicopia.EquinePredicates;
import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.WeaklyOwned;
import com.minelittlepony.unicopia.ability.magic.Affine;
import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.Levelled;
import com.minelittlepony.unicopia.ability.magic.SpellContainer;
import com.minelittlepony.unicopia.ability.magic.SpellContainer.Operation;
import com.minelittlepony.unicopia.ability.magic.spell.Situation;
import com.minelittlepony.unicopia.ability.magic.spell.Spell;
import com.minelittlepony.unicopia.block.state.StatePredicate;
import com.minelittlepony.unicopia.entity.EntityPhysics;
import com.minelittlepony.unicopia.entity.EntityReference;
import com.minelittlepony.unicopia.entity.MagicImmune;
import com.minelittlepony.unicopia.entity.Physics;
import com.minelittlepony.unicopia.entity.mob.UEntities;
import com.minelittlepony.unicopia.item.UItems;
import com.minelittlepony.unicopia.network.Channel;
import com.minelittlepony.unicopia.network.MsgSpawnProjectile;
import com.minelittlepony.unicopia.network.datasync.EffectSync;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.LivingEntity;
@ -40,41 +24,28 @@ import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtElement;
import net.minecraft.network.packet.Packet;
import net.minecraft.network.listener.ClientPlayPacketListener;
import net.minecraft.particle.ItemStackParticleEffect;
import net.minecraft.particle.ParticleEffect;
import net.minecraft.particle.ParticleTypes;
import net.minecraft.predicate.entity.EntityPredicates;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.hit.EntityHitResult;
import net.minecraft.util.hit.HitResult;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
/**
* A generalised version of Mojang's projectile entity class with added support for a custom appearance and water phobia.
*
* Can also carry a spell if needed.
*/
public class MagicProjectileEntity extends ThrownItemEntity implements Caster<MagicProjectileEntity>, WeaklyOwned.Mutable<LivingEntity>, MagicImmune {
public class MagicProjectileEntity extends ThrownItemEntity implements WeaklyOwned.Mutable<LivingEntity> {
private static final TrackedData<Float> DAMAGE = DataTracker.registerData(MagicProjectileEntity.class, TrackedDataHandlerRegistry.FLOAT);
private static final TrackedData<Float> GRAVITY = DataTracker.registerData(MagicProjectileEntity.class, TrackedDataHandlerRegistry.FLOAT);
private static final TrackedData<Boolean> HYDROPHOBIC = DataTracker.registerData(MagicProjectileEntity.class, TrackedDataHandlerRegistry.BOOLEAN);
private static final TrackedData<NbtCompound> EFFECT = DataTracker.registerData(MagicProjectileEntity.class, TrackedDataHandlerRegistry.NBT_COMPOUND);
public static final byte PROJECTILE_COLLISSION = 3;
private final EffectSync effectDelegate = new EffectSync(this, EFFECT);
private final EntityPhysics<MagicProjectileEntity> physics = new EntityPhysics<>(this, GRAVITY);
private final EntityReference<Entity> homingTarget = new EntityReference<>();
private EntityReference<LivingEntity> owner;
private int maxAge = 90;
public MagicProjectileEntity(EntityType<MagicProjectileEntity> type, World world) {
public MagicProjectileEntity(EntityType<? extends MagicProjectileEntity> type, World world) {
super(type, world);
}
@ -86,27 +57,24 @@ public class MagicProjectileEntity extends ThrownItemEntity implements Caster<Ma
super(UEntities.THROWN_ITEM, thrower, world);
}
protected MagicProjectileEntity(EntityType<? extends MagicProjectileEntity> type, World world, LivingEntity thrower) {
super(type, thrower, world);
}
@Override
protected void initDataTracker() {
super.initDataTracker();
getDataTracker().startTracking(GRAVITY, 1F);
getDataTracker().startTracking(DAMAGE, 0F);
getDataTracker().startTracking(EFFECT, new NbtCompound());
getDataTracker().startTracking(HYDROPHOBIC, false);
}
@Override
public World asWorld() {
return getWorld();
}
@Override
protected Item getDefaultItem() {
switch (getSpellSlot().get(false).map(Spell::getAffinity).orElse(Affinity.NEUTRAL)) {
case GOOD: return Items.SNOWBALL;
case BAD: return Items.MAGMA_CREAM;
default: return Items.AIR;
}
}
@Override
public MagicProjectileEntity asEntity() {
return this;
return Items.AIR;
}
@Override
@ -140,36 +108,6 @@ public class MagicProjectileEntity extends ThrownItemEntity implements Caster<Ma
homingTarget.set(target);
}
@Override
public LevelStore getLevel() {
return getMasterReference().getTarget().map(target -> target.level()).orElse(Levelled.EMPTY);
}
@Override
public LevelStore getCorruption() {
return getMasterReference().getTarget().map(target -> target.corruption()).orElse(Levelled.EMPTY);
}
@Override
public Physics getPhysics() {
return physics;
}
@Override
public Affinity getAffinity() {
return getSpellSlot().get(true).map(Affine::getAffinity).orElse(Affinity.NEUTRAL);
}
@Override
public SpellContainer getSpellSlot() {
return effectDelegate;
}
@Override
public boolean subtractEnergyCost(double amount) {
return Caster.of(getMaster()).filter(c -> c.subtractEnergyCost(amount)).isPresent();
}
public void addThrowDamage(float damage) {
setThrowDamage(getThrowDamage() + damage);
}
@ -182,14 +120,6 @@ public class MagicProjectileEntity extends ThrownItemEntity implements Caster<Ma
return getDataTracker().get(DAMAGE);
}
public void setHydrophobic() {
getDataTracker().set(HYDROPHOBIC, true);
}
public boolean getHydrophobic() {
return getDataTracker().get(HYDROPHOBIC);
}
public void setMaxAge(int maxAge) {
this.maxAge = maxAge;
}
@ -202,28 +132,6 @@ public class MagicProjectileEntity extends ThrownItemEntity implements Caster<Ma
super.tick();
if (getOwner() == null) {
return;
}
effectDelegate.tick(Situation.PROJECTILE);
if (getHydrophobic()) {
if (StatePredicate.isFluid(getWorld().getBlockState(getBlockPos()))) {
Vec3d vel = getVelocity();
double velY = vel.y;
velY *= -1;
if (!hasNoGravity()) {
velY += 0.16;
}
setVelocity(new Vec3d(vel.x, velY, vel.z));
}
}
homingTarget.ifPresent(getWorld(), e -> {
setNoGravity(true);
noClip = true;
@ -261,12 +169,8 @@ public class MagicProjectileEntity extends ThrownItemEntity implements Caster<Ma
@Override
public void readCustomDataFromNbt(NbtCompound compound) {
super.readCustomDataFromNbt(compound);
physics.fromNBT(compound);
homingTarget.fromNBT(compound.getCompound("homingTarget"));
getMasterReference().fromNBT(compound.getCompound("owner"));
if (compound.contains("effect")) {
getSpellSlot().put(Spell.readNbt(compound.getCompound("effect")));
}
if (compound.contains("maxAge", NbtElement.INT_TYPE)) {
maxAge = compound.getInt("maxAge");
}
@ -275,13 +179,9 @@ public class MagicProjectileEntity extends ThrownItemEntity implements Caster<Ma
@Override
public void writeCustomDataToNbt(NbtCompound compound) {
super.writeCustomDataToNbt(compound);
physics.toNBT(compound);
compound.put("homingTarget", homingTarget.toNBT());
compound.put("owner", getMasterReference().toNBT());
compound.putInt("maxAge", maxAge);
getSpellSlot().get(true).ifPresent(effect -> {
compound.put("effect", Spell.writeNbt(effect));
});
}
@Override
@ -296,12 +196,6 @@ public class MagicProjectileEntity extends ThrownItemEntity implements Caster<Ma
}
}
@Override
public void remove(RemovalReason reason) {
super.remove(reason);
getSpellSlot().clear();
}
@Override
protected void onBlockHit(BlockHitResult hit) {
super.onBlockHit(hit);
@ -313,7 +207,7 @@ public class MagicProjectileEntity extends ThrownItemEntity implements Caster<Ma
protected void onEntityHit(EntityHitResult hit) {
Entity entity = hit.getEntity();
if (EquinePredicates.IS_MAGIC_IMMUNE.test(entity) || !EntityPredicates.EXCEPT_CREATIVE_OR_SPECTATOR.test(entity)) {
if (EquinePredicates.IS_MAGIC_IMMUNE.test(entity)) {
return;
}
@ -329,20 +223,10 @@ public class MagicProjectileEntity extends ThrownItemEntity implements Caster<Ma
}
protected <T extends ProjectileDelegate> void forEachDelegates(Consumer<T> consumer, Function<Object, T> predicate) {
effectDelegate.tick(spell -> {
Optional.ofNullable(predicate.apply(spell)).ifPresent(consumer);
return Operation.SKIP;
});
try {
Optional.ofNullable(predicate.apply(getItem().getItem())).ifPresent(consumer);
} catch (Throwable t) {
Unicopia.LOGGER.error("Error whilst ticking spell on entity {}", getMasterReference(), t);
}
}
@SuppressWarnings("unchecked")
@Override
public Packet<ClientPlayPacketListener> createSpawnPacket() {
return (Packet<ClientPlayPacketListener>)(Object)Channel.SERVER_SPAWN_PROJECTILE.toPacket(new MsgSpawnProjectile(this));
}
}

View file

@ -2,9 +2,25 @@ package com.minelittlepony.unicopia.util;
import com.minelittlepony.common.util.Color;
import net.minecraft.entity.Entity;
import net.minecraft.entity.passive.SheepEntity;
import net.minecraft.util.DyeColor;
import net.minecraft.util.math.MathHelper;
public interface ColorHelper {
static int getRainbowColor(Entity entity, int speed, float tickDelta) {
int n = entity.age / speed + entity.getId();
int o = DyeColor.values().length;
int p = n % o;
int q = (n + 1) % o;
float r = (entity.age % speed + tickDelta) / 25.0f;
float[] fs = SheepEntity.getRgbColor(DyeColor.byId(p));
float[] gs = SheepEntity.getRgbColor(DyeColor.byId(q));
float s = fs[0] * (1.0f - r) + gs[0] * r;
float t = fs[1] * (1.0f - r) + gs[1] * r;
float u = fs[2] * (1.0f - r) + gs[2] * r;
return Color.argbToHex(1, s, t, u);
}
static float[] changeSaturation(float red, float green, float blue, float intensity) {
float avg = (red + green + blue) / 3F;

View file

@ -3,6 +3,7 @@ package com.minelittlepony.unicopia.util;
import com.minelittlepony.unicopia.EntityConvertable;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.sound.SoundCategory;
import net.minecraft.sound.SoundEvent;
import net.minecraft.util.math.random.Random;
@ -26,7 +27,11 @@ public interface SoundEmitter<E extends Entity> extends EntityConvertable<E> {
}
static void playSoundAt(Entity entity, SoundEvent sound, SoundCategory category, float volume, float pitch) {
entity.getWorld().playSound(null, entity.getX(), entity.getY(), entity.getZ(), sound, category, volume, pitch);
if (entity.getWorld().isClient && entity instanceof PlayerEntity p) {
entity.getWorld().playSound(p, entity.getX(), entity.getY(), entity.getZ(), sound, category, volume, pitch);
} else {
entity.getWorld().playSound(null, entity.getX(), entity.getY(), entity.getZ(), sound, category, volume, pitch);
}
}
static float getRandomPitch(Random rng) {

View file

@ -1,12 +0,0 @@
{
"variants": {
"bites=0,stomped=false": { "model": "unicopia:block/apple_pie" },
"bites=1,stomped=false": { "model": "unicopia:block/apple_pie_elbow" },
"bites=2,stomped=false": { "model": "unicopia:block/apple_pie_straight" },
"bites=3,stomped=false": { "model": "unicopia:block/apple_pie_corner" },
"bites=0,stomped=true": { "model": "unicopia:block/stomped_apple_pie" },
"bites=1,stomped=true": { "model": "unicopia:block/stomped_apple_pie_elbow" },
"bites=2,stomped=true": { "model": "unicopia:block/stomped_apple_pie_straight" },
"bites=3,stomped=true": { "model": "unicopia:block/stomped_apple_pie_corner" }
}
}

View file

@ -1,7 +0,0 @@
{
"variants": {
"": {
"model": "unicopia:block/bananas"
}
}
}

View file

@ -1,10 +0,0 @@
{
"variants": {
"facing=up": { "model": "unicopia:block/carved_cloud" },
"facing=down": { "model": "unicopia:block/carved_cloud", "x": 180 },
"facing=north": { "model": "unicopia:block/carved_cloud", "x": 90 },
"facing=south": { "model": "unicopia:block/carved_cloud", "x": -90 },
"facing=east": { "model": "unicopia:block/carved_cloud", "x": 90, "y": 90 },
"facing=west": { "model": "unicopia:block/carved_cloud", "x": 90, "y": -90 }
}
}

View file

@ -1,5 +0,0 @@
{
"variants": {
"": { "model": "unicopia:block/chiselled_chitin" }
}
}

View file

@ -1,10 +0,0 @@
{
"variants": {
"facing=up": { "model": "unicopia:block/chiselled_chitin_hull" },
"facing=down": { "model": "unicopia:block/chiselled_chitin_hull", "x": 180 },
"facing=north": { "model": "unicopia:block/chiselled_chitin_hull", "x": 90 },
"facing=south": { "model": "unicopia:block/chiselled_chitin_hull", "x": -90 },
"facing=east": { "model": "unicopia:block/chiselled_chitin_hull", "x": 90, "y": 90 },
"facing=west": { "model": "unicopia:block/chiselled_chitin_hull", "x": 90, "y": -90 }
}
}

View file

@ -1,7 +0,0 @@
{
"variants": {
"type=double": { "model": "unicopia:block/chiselled_chitin" },
"type=bottom": { "model": "unicopia:block/chiselled_chitin_slab" },
"type=top": { "model": "unicopia:block/chiselled_chitin_slab_top" }
}
}

View file

@ -1,209 +0,0 @@
{
"variants": {
"facing=east,half=bottom,shape=inner_left": {
"model": "unicopia:block/chiselled_chitin_stairs_inner",
"uvlock": true,
"y": 270
},
"facing=east,half=bottom,shape=inner_right": {
"model": "unicopia:block/chiselled_chitin_stairs_inner"
},
"facing=east,half=bottom,shape=outer_left": {
"model": "unicopia:block/chiselled_chitin_stairs_outer",
"uvlock": true,
"y": 270
},
"facing=east,half=bottom,shape=outer_right": {
"model": "unicopia:block/chiselled_chitin_stairs_outer"
},
"facing=east,half=bottom,shape=straight": {
"model": "unicopia:block/chiselled_chitin_stairs"
},
"facing=east,half=top,shape=inner_left": {
"model": "unicopia:block/chiselled_chitin_stairs_inner",
"uvlock": true,
"x": 180
},
"facing=east,half=top,shape=inner_right": {
"model": "unicopia:block/chiselled_chitin_stairs_inner",
"uvlock": true,
"x": 180,
"y": 90
},
"facing=east,half=top,shape=outer_left": {
"model": "unicopia:block/chiselled_chitin_stairs_outer",
"uvlock": true,
"x": 180
},
"facing=east,half=top,shape=outer_right": {
"model": "unicopia:block/chiselled_chitin_stairs_outer",
"uvlock": true,
"x": 180,
"y": 90
},
"facing=east,half=top,shape=straight": {
"model": "unicopia:block/chiselled_chitin_stairs",
"uvlock": true,
"x": 180
},
"facing=north,half=bottom,shape=inner_left": {
"model": "unicopia:block/chiselled_chitin_stairs_inner",
"uvlock": true,
"y": 180
},
"facing=north,half=bottom,shape=inner_right": {
"model": "unicopia:block/chiselled_chitin_stairs_inner",
"uvlock": true,
"y": 270
},
"facing=north,half=bottom,shape=outer_left": {
"model": "unicopia:block/chiselled_chitin_stairs_outer",
"uvlock": true,
"y": 180
},
"facing=north,half=bottom,shape=outer_right": {
"model": "unicopia:block/chiselled_chitin_stairs_outer",
"uvlock": true,
"y": 270
},
"facing=north,half=bottom,shape=straight": {
"model": "unicopia:block/chiselled_chitin_stairs",
"uvlock": true,
"y": 270
},
"facing=north,half=top,shape=inner_left": {
"model": "unicopia:block/chiselled_chitin_stairs_inner",
"uvlock": true,
"x": 180,
"y": 270
},
"facing=north,half=top,shape=inner_right": {
"model": "unicopia:block/chiselled_chitin_stairs_inner",
"uvlock": true,
"x": 180
},
"facing=north,half=top,shape=outer_left": {
"model": "unicopia:block/chiselled_chitin_stairs_outer",
"uvlock": true,
"x": 180,
"y": 270
},
"facing=north,half=top,shape=outer_right": {
"model": "unicopia:block/chiselled_chitin_stairs_outer",
"uvlock": true,
"x": 180
},
"facing=north,half=top,shape=straight": {
"model": "unicopia:block/chiselled_chitin_stairs",
"uvlock": true,
"x": 180,
"y": 270
},
"facing=south,half=bottom,shape=inner_left": {
"model": "unicopia:block/chiselled_chitin_stairs_inner"
},
"facing=south,half=bottom,shape=inner_right": {
"model": "unicopia:block/chiselled_chitin_stairs_inner",
"uvlock": true,
"y": 90
},
"facing=south,half=bottom,shape=outer_left": {
"model": "unicopia:block/chiselled_chitin_stairs_outer"
},
"facing=south,half=bottom,shape=outer_right": {
"model": "unicopia:block/chiselled_chitin_stairs_outer",
"uvlock": true,
"y": 90
},
"facing=south,half=bottom,shape=straight": {
"model": "unicopia:block/chiselled_chitin_stairs",
"uvlock": true,
"y": 90
},
"facing=south,half=top,shape=inner_left": {
"model": "unicopia:block/chiselled_chitin_stairs_inner",
"uvlock": true,
"x": 180,
"y": 90
},
"facing=south,half=top,shape=inner_right": {
"model": "unicopia:block/chiselled_chitin_stairs_inner",
"uvlock": true,
"x": 180,
"y": 180
},
"facing=south,half=top,shape=outer_left": {
"model": "unicopia:block/chiselled_chitin_stairs_outer",
"uvlock": true,
"x": 180,
"y": 90
},
"facing=south,half=top,shape=outer_right": {
"model": "unicopia:block/chiselled_chitin_stairs_outer",
"uvlock": true,
"x": 180,
"y": 180
},
"facing=south,half=top,shape=straight": {
"model": "unicopia:block/chiselled_chitin_stairs",
"uvlock": true,
"x": 180,
"y": 90
},
"facing=west,half=bottom,shape=inner_left": {
"model": "unicopia:block/chiselled_chitin_stairs_inner",
"uvlock": true,
"y": 90
},
"facing=west,half=bottom,shape=inner_right": {
"model": "unicopia:block/chiselled_chitin_stairs_inner",
"uvlock": true,
"y": 180
},
"facing=west,half=bottom,shape=outer_left": {
"model": "unicopia:block/chiselled_chitin_stairs_outer",
"uvlock": true,
"y": 90
},
"facing=west,half=bottom,shape=outer_right": {
"model": "unicopia:block/chiselled_chitin_stairs_outer",
"uvlock": true,
"y": 180
},
"facing=west,half=bottom,shape=straight": {
"model": "unicopia:block/chiselled_chitin_stairs",
"uvlock": true,
"y": 180
},
"facing=west,half=top,shape=inner_left": {
"model": "unicopia:block/chiselled_chitin_stairs_inner",
"uvlock": true,
"x": 180,
"y": 180
},
"facing=west,half=top,shape=inner_right": {
"model": "unicopia:block/chiselled_chitin_stairs_inner",
"uvlock": true,
"x": 180,
"y": 270
},
"facing=west,half=top,shape=outer_left": {
"model": "unicopia:block/chiselled_chitin_stairs_outer",
"uvlock": true,
"x": 180,
"y": 180
},
"facing=west,half=top,shape=outer_right": {
"model": "unicopia:block/chiselled_chitin_stairs_outer",
"uvlock": true,
"x": 180,
"y": 270
},
"facing=west,half=top,shape=straight": {
"model": "unicopia:block/chiselled_chitin_stairs",
"uvlock": true,
"x": 180,
"y": 180
}
}
}

View file

@ -1,5 +0,0 @@
{
"variants": {
"": { "model": "unicopia:block/chitin" }
}
}

View file

@ -1,10 +0,0 @@
{
"variants": {
"facing=up": { "model": "unicopia:block/chitin_spikes" },
"facing=down": { "model": "unicopia:block/chitin_spikes", "x": 180 },
"facing=north": { "model": "unicopia:block/chitin_spikes", "x": 90 },
"facing=south": { "model": "unicopia:block/chitin_spikes", "x": -90 },
"facing=east": { "model": "unicopia:block/chitin_spikes", "x": 90, "y": 90 },
"facing=west": { "model": "unicopia:block/chitin_spikes", "x": 90, "y": -90 }
}
}

View file

@ -1,8 +0,0 @@
{
"variants": {
"count=1": { "model": "unicopia:block/clam_shell_1" },
"count=2": { "model": "unicopia:block/clam_shell_2" },
"count=3": { "model": "unicopia:block/clam_shell_3" },
"count=4": { "model": "unicopia:block/clam_shell_4" }
}
}

View file

@ -1,5 +0,0 @@
{
"variants": {
"": { "model": "unicopia:block/cloth_bed" }
}
}

View file

@ -1,5 +0,0 @@
{
"variants": {
"": { "model": "unicopia:block/cloud" }
}
}

View file

@ -1,5 +0,0 @@
{
"variants": {
"": { "model": "unicopia:block/cloud_bed" }
}
}

View file

@ -1,7 +0,0 @@
{
"variants": {
"type=double": { "model": "unicopia:block/cloud_bricks" },
"type=bottom": { "model": "unicopia:block/cloud_brick_slab" },
"type=top": { "model": "unicopia:block/cloud_brick_slab_top" }
}
}

View file

@ -1,209 +0,0 @@
{
"variants": {
"facing=east,half=bottom,shape=inner_left": {
"model": "unicopia:block/cloud_brick_stairs_inner",
"uvlock": true,
"y": 270
},
"facing=east,half=bottom,shape=inner_right": {
"model": "unicopia:block/cloud_brick_stairs_inner"
},
"facing=east,half=bottom,shape=outer_left": {
"model": "unicopia:block/cloud_brick_stairs_outer",
"uvlock": true,
"y": 270
},
"facing=east,half=bottom,shape=outer_right": {
"model": "unicopia:block/cloud_brick_stairs_outer"
},
"facing=east,half=bottom,shape=straight": {
"model": "unicopia:block/cloud_brick_stairs"
},
"facing=east,half=top,shape=inner_left": {
"model": "unicopia:block/cloud_brick_stairs_inner",
"uvlock": true,
"x": 180
},
"facing=east,half=top,shape=inner_right": {
"model": "unicopia:block/cloud_brick_stairs_inner",
"uvlock": true,
"x": 180,
"y": 90
},
"facing=east,half=top,shape=outer_left": {
"model": "unicopia:block/cloud_brick_stairs_outer",
"uvlock": true,
"x": 180
},
"facing=east,half=top,shape=outer_right": {
"model": "unicopia:block/cloud_brick_stairs_outer",
"uvlock": true,
"x": 180,
"y": 90
},
"facing=east,half=top,shape=straight": {
"model": "unicopia:block/cloud_brick_stairs",
"uvlock": true,
"x": 180
},
"facing=north,half=bottom,shape=inner_left": {
"model": "unicopia:block/cloud_brick_stairs_inner",
"uvlock": true,
"y": 180
},
"facing=north,half=bottom,shape=inner_right": {
"model": "unicopia:block/cloud_brick_stairs_inner",
"uvlock": true,
"y": 270
},
"facing=north,half=bottom,shape=outer_left": {
"model": "unicopia:block/cloud_brick_stairs_outer",
"uvlock": true,
"y": 180
},
"facing=north,half=bottom,shape=outer_right": {
"model": "unicopia:block/cloud_brick_stairs_outer",
"uvlock": true,
"y": 270
},
"facing=north,half=bottom,shape=straight": {
"model": "unicopia:block/cloud_brick_stairs",
"uvlock": true,
"y": 270
},
"facing=north,half=top,shape=inner_left": {
"model": "unicopia:block/cloud_brick_stairs_inner",
"uvlock": true,
"x": 180,
"y": 270
},
"facing=north,half=top,shape=inner_right": {
"model": "unicopia:block/cloud_brick_stairs_inner",
"uvlock": true,
"x": 180
},
"facing=north,half=top,shape=outer_left": {
"model": "unicopia:block/cloud_brick_stairs_outer",
"uvlock": true,
"x": 180,
"y": 270
},
"facing=north,half=top,shape=outer_right": {
"model": "unicopia:block/cloud_brick_stairs_outer",
"uvlock": true,
"x": 180
},
"facing=north,half=top,shape=straight": {
"model": "unicopia:block/cloud_brick_stairs",
"uvlock": true,
"x": 180,
"y": 270
},
"facing=south,half=bottom,shape=inner_left": {
"model": "unicopia:block/cloud_brick_stairs_inner"
},
"facing=south,half=bottom,shape=inner_right": {
"model": "unicopia:block/cloud_brick_stairs_inner",
"uvlock": true,
"y": 90
},
"facing=south,half=bottom,shape=outer_left": {
"model": "unicopia:block/cloud_brick_stairs_outer"
},
"facing=south,half=bottom,shape=outer_right": {
"model": "unicopia:block/cloud_brick_stairs_outer",
"uvlock": true,
"y": 90
},
"facing=south,half=bottom,shape=straight": {
"model": "unicopia:block/cloud_brick_stairs",
"uvlock": true,
"y": 90
},
"facing=south,half=top,shape=inner_left": {
"model": "unicopia:block/cloud_brick_stairs_inner",
"uvlock": true,
"x": 180,
"y": 90
},
"facing=south,half=top,shape=inner_right": {
"model": "unicopia:block/cloud_brick_stairs_inner",
"uvlock": true,
"x": 180,
"y": 180
},
"facing=south,half=top,shape=outer_left": {
"model": "unicopia:block/cloud_brick_stairs_outer",
"uvlock": true,
"x": 180,
"y": 90
},
"facing=south,half=top,shape=outer_right": {
"model": "unicopia:block/cloud_brick_stairs_outer",
"uvlock": true,
"x": 180,
"y": 180
},
"facing=south,half=top,shape=straight": {
"model": "unicopia:block/cloud_brick_stairs",
"uvlock": true,
"x": 180,
"y": 90
},
"facing=west,half=bottom,shape=inner_left": {
"model": "unicopia:block/cloud_brick_stairs_inner",
"uvlock": true,
"y": 90
},
"facing=west,half=bottom,shape=inner_right": {
"model": "unicopia:block/cloud_brick_stairs_inner",
"uvlock": true,
"y": 180
},
"facing=west,half=bottom,shape=outer_left": {
"model": "unicopia:block/cloud_brick_stairs_outer",
"uvlock": true,
"y": 90
},
"facing=west,half=bottom,shape=outer_right": {
"model": "unicopia:block/cloud_brick_stairs_outer",
"uvlock": true,
"y": 180
},
"facing=west,half=bottom,shape=straight": {
"model": "unicopia:block/cloud_brick_stairs",
"uvlock": true,
"y": 180
},
"facing=west,half=top,shape=inner_left": {
"model": "unicopia:block/cloud_brick_stairs_inner",
"uvlock": true,
"x": 180,
"y": 180
},
"facing=west,half=top,shape=inner_right": {
"model": "unicopia:block/cloud_brick_stairs_inner",
"uvlock": true,
"x": 180,
"y": 270
},
"facing=west,half=top,shape=outer_left": {
"model": "unicopia:block/cloud_brick_stairs_outer",
"uvlock": true,
"x": 180,
"y": 180
},
"facing=west,half=top,shape=outer_right": {
"model": "unicopia:block/cloud_brick_stairs_outer",
"uvlock": true,
"x": 180,
"y": 270
},
"facing=west,half=top,shape=straight": {
"model": "unicopia:block/cloud_brick_stairs",
"uvlock": true,
"x": 180,
"y": 180
}
}
}

View file

@ -1,5 +0,0 @@
{
"variants": {
"": { "model": "unicopia:block/cloud_bricks" }
}
}

View file

@ -1,5 +0,0 @@
{
"variants": {
"": { "model": "unicopia:block/cloud_chest" }
}
}

View file

@ -1,68 +0,0 @@
{
"variants": {
"facing=east,half=lower,hinge=left,open=false,powered=false": { "model": "unicopia:block/door/cloud_bottom" },
"facing=south,half=lower,hinge=left,open=false,powered=false": { "model": "unicopia:block/door/cloud_bottom", "y": 90 },
"facing=west,half=lower,hinge=left,open=false,powered=false": { "model": "unicopia:block/door/cloud_bottom", "y": 180 },
"facing=north,half=lower,hinge=left,open=false,powered=false": { "model": "unicopia:block/door/cloud_bottom", "y": 270 },
"facing=east,half=lower,hinge=right,open=false,powered=false": { "model": "unicopia:block/door/cloud_bottom_rh" },
"facing=south,half=lower,hinge=right,open=false,powered=false": { "model": "unicopia:block/door/cloud_bottom_rh", "y": 90 },
"facing=west,half=lower,hinge=right,open=false,powered=false": { "model": "unicopia:block/door/cloud_bottom_rh", "y": 180 },
"facing=north,half=lower,hinge=right,open=false,powered=false": { "model": "unicopia:block/door/cloud_bottom_rh", "y": 270 },
"facing=east,half=lower,hinge=left,open=true,powered=false": { "model": "unicopia:block/door/cloud_bottom_rh", "y": 90 },
"facing=south,half=lower,hinge=left,open=true,powered=false": { "model": "unicopia:block/door/cloud_bottom_rh", "y": 180 },
"facing=west,half=lower,hinge=left,open=true,powered=false": { "model": "unicopia:block/door/cloud_bottom_rh", "y": 270 },
"facing=north,half=lower,hinge=left,open=true,powered=false": { "model": "unicopia:block/door/cloud_bottom_rh" },
"facing=east,half=lower,hinge=right,open=true,powered=false": { "model": "unicopia:block/door/cloud_bottom", "y": 270 },
"facing=south,half=lower,hinge=right,open=true,powered=false": { "model": "unicopia:block/door/cloud_bottom" },
"facing=west,half=lower,hinge=right,open=true,powered=false": { "model": "unicopia:block/door/cloud_bottom", "y": 90 },
"facing=north,half=lower,hinge=right,open=true,powered=false": { "model": "unicopia:block/door/cloud_bottom", "y": 180 },
"facing=east,half=upper,hinge=left,open=false,powered=false": { "model": "unicopia:block/door/cloud_top" },
"facing=south,half=upper,hinge=left,open=false,powered=false": { "model": "unicopia:block/door/cloud_top", "y": 90 },
"facing=west,half=upper,hinge=left,open=false,powered=false": { "model": "unicopia:block/door/cloud_top", "y": 180 },
"facing=north,half=upper,hinge=left,open=false,powered=false": { "model": "unicopia:block/door/cloud_top", "y": 270 },
"facing=east,half=upper,hinge=right,open=false,powered=false": { "model": "unicopia:block/door/cloud_top_rh" },
"facing=south,half=upper,hinge=right,open=false,powered=false": { "model": "unicopia:block/door/cloud_top_rh", "y": 90 },
"facing=west,half=upper,hinge=right,open=false,powered=false": { "model": "unicopia:block/door/cloud_top_rh", "y": 180 },
"facing=north,half=upper,hinge=right,open=false,powered=false": { "model": "unicopia:block/door/cloud_top_rh", "y": 270 },
"facing=east,half=upper,hinge=left,open=true,powered=false": { "model": "unicopia:block/door/cloud_top_rh", "y": 90 },
"facing=south,half=upper,hinge=left,open=true,powered=false": { "model": "unicopia:block/door/cloud_top_rh", "y": 180 },
"facing=west,half=upper,hinge=left,open=true,powered=false": { "model": "unicopia:block/door/cloud_top_rh", "y": 270 },
"facing=north,half=upper,hinge=left,open=true,powered=false": { "model": "unicopia:block/door/cloud_top_rh" },
"facing=east,half=upper,hinge=right,open=true,powered=false": { "model": "unicopia:block/door/cloud_top", "y": 270 },
"facing=south,half=upper,hinge=right,open=true,powered=false": { "model": "unicopia:block/door/cloud_top" },
"facing=west,half=upper,hinge=right,open=true,powered=false": { "model": "unicopia:block/door/cloud_top", "y": 90 },
"facing=north,half=upper,hinge=right,open=true,powered=false": { "model": "unicopia:block/door/cloud_top", "y": 180 },
"facing=east,half=lower,hinge=left,open=false,powered=true": { "model": "unicopia:block/door/cloud_bottom" },
"facing=south,half=lower,hinge=left,open=false,powered=true": { "model": "unicopia:block/door/cloud_bottom", "y": 90 },
"facing=west,half=lower,hinge=left,open=false,powered=true": { "model": "unicopia:block/door/cloud_bottom", "y": 180 },
"facing=north,half=lower,hinge=left,open=false,powered=true": { "model": "unicopia:block/door/cloud_bottom", "y": 270 },
"facing=east,half=lower,hinge=right,open=false,powered=true": { "model": "unicopia:block/door/cloud_bottom_rh" },
"facing=south,half=lower,hinge=right,open=false,powered=true": { "model": "unicopia:block/door/cloud_bottom_rh", "y": 90 },
"facing=west,half=lower,hinge=right,open=false,powered=true": { "model": "unicopia:block/door/cloud_bottom_rh", "y": 180 },
"facing=north,half=lower,hinge=right,open=false,powered=true": { "model": "unicopia:block/door/cloud_bottom_rh", "y": 270 },
"facing=east,half=lower,hinge=left,open=true,powered=true": { "model": "unicopia:block/door/cloud_bottom_rh", "y": 90 },
"facing=south,half=lower,hinge=left,open=true,powered=true": { "model": "unicopia:block/door/cloud_bottom_rh", "y": 180 },
"facing=west,half=lower,hinge=left,open=true,powered=true": { "model": "unicopia:block/door/cloud_bottom_rh", "y": 270 },
"facing=north,half=lower,hinge=left,open=true,powered=true": { "model": "unicopia:block/door/cloud_bottom_rh" },
"facing=east,half=lower,hinge=right,open=true,powered=true": { "model": "unicopia:block/door/cloud_bottom", "y": 270 },
"facing=south,half=lower,hinge=right,open=true,powered=true": { "model": "unicopia:block/door/cloud_bottom" },
"facing=west,half=lower,hinge=right,open=true,powered=true": { "model": "unicopia:block/door/cloud_bottom", "y": 90 },
"facing=north,half=lower,hinge=right,open=true,powered=true": { "model": "unicopia:block/door/cloud_bottom", "y": 180 },
"facing=east,half=upper,hinge=left,open=false,powered=true": { "model": "unicopia:block/door/cloud_top" },
"facing=south,half=upper,hinge=left,open=false,powered=true": { "model": "unicopia:block/door/cloud_top", "y": 90 },
"facing=west,half=upper,hinge=left,open=false,powered=true": { "model": "unicopia:block/door/cloud_top", "y": 180 },
"facing=north,half=upper,hinge=left,open=false,powered=true": { "model": "unicopia:block/door/cloud_top", "y": 270 },
"facing=east,half=upper,hinge=right,open=false,powered=true": { "model": "unicopia:block/door/cloud_top_rh" },
"facing=south,half=upper,hinge=right,open=false,powered=true": { "model": "unicopia:block/door/cloud_top_rh", "y": 90 },
"facing=west,half=upper,hinge=right,open=false,powered=true": { "model": "unicopia:block/door/cloud_top_rh", "y": 180 },
"facing=north,half=upper,hinge=right,open=false,powered=true": { "model": "unicopia:block/door/cloud_top_rh", "y": 270 },
"facing=east,half=upper,hinge=left,open=true,powered=true": { "model": "unicopia:block/door/cloud_top_rh", "y": 90 },
"facing=south,half=upper,hinge=left,open=true,powered=true": { "model": "unicopia:block/door/cloud_top_rh", "y": 180 },
"facing=west,half=upper,hinge=left,open=true,powered=true": { "model": "unicopia:block/door/cloud_top_rh", "y": 270 },
"facing=north,half=upper,hinge=left,open=true,powered=true": { "model": "unicopia:block/door/cloud_top_rh" },
"facing=east,half=upper,hinge=right,open=true,powered=true": { "model": "unicopia:block/door/cloud_top", "y": 270 },
"facing=south,half=upper,hinge=right,open=true,powered=true": { "model": "unicopia:block/door/cloud_top" },
"facing=west,half=upper,hinge=right,open=true,powered=true": { "model": "unicopia:block/door/cloud_top", "y": 90 },
"facing=north,half=upper,hinge=right,open=true,powered=true": { "model": "unicopia:block/door/cloud_top", "y": 180 }
}
}

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