[Feature] Particle Effects for the Eternal Portal
This commit is contained in:
parent
2cf510b160
commit
55985d0660
5 changed files with 271 additions and 38 deletions
|
@ -1,5 +1,6 @@
|
|||
package org.betterx.betterend;
|
||||
|
||||
import org.betterx.bclib.api.v2.dataexchange.DataExchangeAPI;
|
||||
import org.betterx.bclib.api.v2.generator.BiomeDecider;
|
||||
import org.betterx.bclib.api.v2.levelgen.biomes.BiomeAPI;
|
||||
import org.betterx.betterend.advancements.BECriteria;
|
||||
|
@ -9,6 +10,7 @@ import org.betterx.betterend.config.Configs;
|
|||
import org.betterx.betterend.effects.EndPotions;
|
||||
import org.betterx.betterend.integration.Integrations;
|
||||
import org.betterx.betterend.integration.trinkets.Elytra;
|
||||
import org.betterx.betterend.network.RitualUpdate;
|
||||
import org.betterx.betterend.recipe.builders.InfusionRecipe;
|
||||
import org.betterx.betterend.registry.*;
|
||||
import org.betterx.betterend.tab.CreativeTabs;
|
||||
|
@ -25,6 +27,8 @@ import net.minecraft.world.level.biome.Biomes;
|
|||
import net.fabricmc.api.ModInitializer;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class BetterEnd implements ModInitializer {
|
||||
public static final String MOD_ID = "betterend";
|
||||
public static final Logger LOGGER = new Logger(MOD_ID);
|
||||
|
@ -81,6 +85,10 @@ public class BetterEnd implements ModInitializer {
|
|||
}
|
||||
});
|
||||
|
||||
DataExchangeAPI.registerDescriptors(List.of(
|
||||
RitualUpdate.DESCRIPTOR
|
||||
));
|
||||
|
||||
if (RUNS_TRINKETS) {
|
||||
Elytra.register();
|
||||
}
|
||||
|
|
|
@ -1,16 +1,24 @@
|
|||
package org.betterx.betterend.blocks;
|
||||
|
||||
import de.ambertation.wunderlib.math.Float3;
|
||||
import org.betterx.bclib.behaviours.interfaces.BehaviourStone;
|
||||
import org.betterx.bclib.interfaces.ClientLevelAccess;
|
||||
import org.betterx.betterend.blocks.basis.PedestalBlock;
|
||||
import org.betterx.betterend.blocks.entities.EternalPedestalEntity;
|
||||
import org.betterx.betterend.client.render.EternalCrystalRenderer;
|
||||
import org.betterx.betterend.client.render.PedestalItemRenderer;
|
||||
import org.betterx.betterend.registry.EndBlocks;
|
||||
import org.betterx.betterend.registry.EndPortals;
|
||||
import org.betterx.betterend.rituals.EternalRitual;
|
||||
|
||||
import net.minecraft.client.particle.Particle;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.particles.ParticleTypes;
|
||||
import net.minecraft.core.particles.SimpleParticleType;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
|
@ -26,6 +34,9 @@ import net.minecraft.world.level.block.state.properties.BooleanProperty;
|
|||
import net.minecraft.world.level.storage.loot.LootParams;
|
||||
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
|
||||
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import java.util.List;
|
||||
|
@ -48,6 +59,7 @@ public class EternalPedestal extends PedestalBlock implements BehaviourStone {
|
|||
if (pedestal.hasRitual()) {
|
||||
EternalRitual ritual = pedestal.getRitual();
|
||||
if (ritual.isActive()) {
|
||||
if (ritual.getWorld() == null) ritual.setWorld(sourceLevel);
|
||||
ResourceLocation targetWorld = ritual.getTargetWorldId();
|
||||
int portalId;
|
||||
if (targetWorld != null) {
|
||||
|
@ -68,9 +80,11 @@ public class EternalPedestal extends PedestalBlock implements BehaviourStone {
|
|||
updatedState.setValue(ACTIVATED, true).setValue(HAS_LIGHT, true)
|
||||
);
|
||||
if (pedestal.hasRitual()) {
|
||||
if (pedestal.getRitual().getWorld() == null) pedestal.getRitual().setWorld(sourceLevel);
|
||||
pedestal.getRitual().checkStructure(player);
|
||||
} else {
|
||||
EternalRitual ritual = new EternalRitual(sourceLevel, pos);
|
||||
pedestal.linkRitual(ritual);
|
||||
ritual.checkStructure(player);
|
||||
}
|
||||
}
|
||||
|
@ -146,4 +160,61 @@ public class EternalPedestal extends PedestalBlock implements BehaviourStone {
|
|||
public boolean hasUniqueEntity() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
private void dispatchParticles(Level level, BlockPos blockPos, RandomSource random) {
|
||||
if (level instanceof ClientLevelAccess clientLevel) {
|
||||
if (level.getBlockEntity(blockPos) instanceof EternalPedestalEntity pedestal
|
||||
&& pedestal.hasRitual()) {
|
||||
BlockState state = level.getBlockState(blockPos);
|
||||
//if (state.getOptionalValue(ACTIVATED).orElse(false))
|
||||
{
|
||||
EternalRitual ritual = pedestal.getRitual();
|
||||
if (ritual != null
|
||||
&& ritual.getCenter() != null
|
||||
&& (ritual.isActive() || ritual.willActivate())
|
||||
) {
|
||||
final var start = Float3.of(blockPos);
|
||||
final var dir = Float3
|
||||
.of(ritual.getCenter())
|
||||
.sub(start)
|
||||
.normalized()
|
||||
.mul(ritual.willActivate() ? 0.2 : 0.05);
|
||||
float[] color = EternalCrystalRenderer.colors(PedestalItemRenderer.getGemAge());
|
||||
|
||||
for (int i = 0; i < random.nextInt(
|
||||
ritual.willActivate() ? 30 : 2,
|
||||
ritual.willActivate() ? 60 : 10
|
||||
); i++) {
|
||||
Float3 rnd = Float3.of(
|
||||
random.nextFloat() * 0.3 - 0.15,
|
||||
random.nextFloat() * -0.1,
|
||||
random.nextFloat() * 0.3 - 0.15
|
||||
).add(dir);
|
||||
SimpleParticleType particleOptions = ParticleTypes.EFFECT;
|
||||
final Particle particle = clientLevel.bcl_addParticle(
|
||||
particleOptions,
|
||||
blockPos.getX() + 0.2 + random.nextFloat() * 0.6,
|
||||
blockPos.getY() + 1 + random.nextFloat() * 0.7,
|
||||
blockPos.getZ() + 0.2 + random.nextFloat() * 0.6,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
);
|
||||
if (particle == null) continue;
|
||||
particle.setColor(color[0], color[1], color[2]);
|
||||
particle.setParticleSpeed(rnd.x, rnd.y, rnd.z);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Environment(EnvType.CLIENT)
|
||||
public void animateTick(BlockState blockState, Level level, BlockPos blockPos, RandomSource randomSource) {
|
||||
super.animateTick(blockState, level, blockPos, randomSource);
|
||||
dispatchParticles(level, blockPos, randomSource);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,7 +60,7 @@ public class PedestalItemRenderer<T extends PedestalBlockEntity> implements Bloc
|
|||
} else {
|
||||
matrices.scale(1.25F, 1.25F, 1.25F);
|
||||
}
|
||||
int age = (int) (minecraft.level.getGameTime() % 314);
|
||||
int age = getGemAge();
|
||||
if (state.is(EndBlocks.ETERNAL_PEDESTAL) && state.getValue(EternalPedestal.ACTIVATED)) {
|
||||
float[] colors = EternalCrystalRenderer.colors(age);
|
||||
int y = blockEntity.getBlockPos().getY();
|
||||
|
@ -101,4 +101,8 @@ public class PedestalItemRenderer<T extends PedestalBlockEntity> implements Bloc
|
|||
}
|
||||
matrices.popPose();
|
||||
}
|
||||
|
||||
public static int getGemAge() {
|
||||
return (int) (Minecraft.getInstance().level.getGameTime() % 314);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
package org.betterx.betterend.network;
|
||||
|
||||
import org.betterx.bclib.api.v2.dataexchange.BaseDataHandler;
|
||||
import org.betterx.bclib.api.v2.dataexchange.DataHandler;
|
||||
import org.betterx.bclib.api.v2.dataexchange.DataHandlerDescriptor;
|
||||
import org.betterx.betterend.BetterEnd;
|
||||
import org.betterx.betterend.rituals.EternalRitual;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
|
||||
import net.fabricmc.fabric.api.networking.v1.PacketSender;
|
||||
|
||||
public class RitualUpdate extends DataHandler.FromServer {
|
||||
public static final DataHandlerDescriptor DESCRIPTOR = new DataHandlerDescriptor(
|
||||
BetterEnd.makeID("ritual_update"),
|
||||
RitualUpdate::new,
|
||||
false,
|
||||
false
|
||||
);
|
||||
|
||||
public RitualUpdate() {
|
||||
super(DESCRIPTOR.IDENTIFIER);
|
||||
}
|
||||
|
||||
private static final byte ACTIVE_FLAG = 1;
|
||||
private static final byte WILL_ACTIVATE_FLAG = 2;
|
||||
|
||||
public RitualUpdate(EternalRitual ritual) {
|
||||
this();
|
||||
this.center = ritual.getCenter();
|
||||
this.axis = ritual.getAxis();
|
||||
|
||||
if (ritual.isActive()) {
|
||||
this.flags |= ACTIVE_FLAG;
|
||||
}
|
||||
if (ritual.willActivate()) {
|
||||
this.flags |= WILL_ACTIVATE_FLAG;
|
||||
}
|
||||
}
|
||||
|
||||
byte flags;
|
||||
BlockPos center;
|
||||
Direction.Axis axis;
|
||||
|
||||
@Override
|
||||
protected void serializeDataOnServer(FriendlyByteBuf buf) {
|
||||
buf.writeBlockPos(center);
|
||||
BaseDataHandler.writeString(buf, axis.getName());
|
||||
buf.writeByte(flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void deserializeIncomingDataOnClient(FriendlyByteBuf buf, PacketSender responseSender) {
|
||||
center = buf.readBlockPos();
|
||||
axis = Direction.Axis.byName(BaseDataHandler.readString(buf));
|
||||
flags = buf.readByte();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void runOnClientGameThread(Minecraft client) {
|
||||
EternalRitual.updateActiveStateOnPedestals(
|
||||
center,
|
||||
axis,
|
||||
(flags & ACTIVE_FLAG) != 0,
|
||||
(flags & WILL_ACTIVATE_FLAG) != 0,
|
||||
client.level,
|
||||
null
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,11 +1,13 @@
|
|||
package org.betterx.betterend.rituals;
|
||||
|
||||
import org.betterx.bclib.api.v2.dataexchange.DataExchangeAPI;
|
||||
import org.betterx.bclib.blocks.BlockProperties;
|
||||
import org.betterx.betterend.BetterEnd;
|
||||
import org.betterx.betterend.advancements.BECriteria;
|
||||
import org.betterx.betterend.blocks.EndPortalBlock;
|
||||
import org.betterx.betterend.blocks.RunedFlavolite;
|
||||
import org.betterx.betterend.blocks.entities.EternalPedestalEntity;
|
||||
import org.betterx.betterend.network.RitualUpdate;
|
||||
import org.betterx.betterend.portal.PortalBuilder;
|
||||
import org.betterx.betterend.registry.EndBlocks;
|
||||
import org.betterx.betterend.registry.EndPortals;
|
||||
|
@ -60,6 +62,7 @@ public class EternalRitual {
|
|||
private BlockPos center;
|
||||
private BlockPos exit;
|
||||
private boolean active = false;
|
||||
private boolean willActivate = false;
|
||||
|
||||
public EternalRitual(Level world) {
|
||||
this.world = world;
|
||||
|
@ -70,10 +73,22 @@ public class EternalRitual {
|
|||
this.configure(initial);
|
||||
}
|
||||
|
||||
public BlockPos getCenter() {
|
||||
return center;
|
||||
}
|
||||
|
||||
public Direction.Axis getAxis() {
|
||||
return axis;
|
||||
}
|
||||
|
||||
public void setWorld(Level world) {
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
public Level getWorld() {
|
||||
return world;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ResourceLocation getTargetWorldId() {
|
||||
return targetWorldId;
|
||||
|
@ -119,6 +134,52 @@ public class EternalRitual {
|
|||
}
|
||||
}
|
||||
|
||||
public void updateActiveStateOnPedestals() {
|
||||
if (world == null) return;
|
||||
updateActiveStateOnPedestals(center, axis, active, willActivate, world, this);
|
||||
DataExchangeAPI.send(new RitualUpdate(this));
|
||||
}
|
||||
|
||||
public static void updateActiveStateOnPedestals(
|
||||
BlockPos center,
|
||||
Direction.Axis axis,
|
||||
boolean active,
|
||||
boolean willActivate,
|
||||
Level world,
|
||||
EternalRitual fallback
|
||||
) {
|
||||
Direction moveX, moveY;
|
||||
if (Direction.Axis.X == axis) {
|
||||
moveX = Direction.EAST;
|
||||
moveY = Direction.NORTH;
|
||||
} else {
|
||||
moveX = Direction.SOUTH;
|
||||
moveY = Direction.EAST;
|
||||
}
|
||||
|
||||
|
||||
for (Point pos : PEDESTAL_POSITIONS) {
|
||||
BlockPos.MutableBlockPos checkPos = center.mutable();
|
||||
checkPos.move(moveX, pos.x).move(moveY, pos.y);
|
||||
if (world.getBlockEntity(checkPos) instanceof EternalPedestalEntity pedestal) {
|
||||
if (pedestal.hasRitual()) {
|
||||
if (fallback == null) fallback = pedestal.getRitual();
|
||||
pedestal.getRitual().active = active;
|
||||
pedestal.getRitual().willActivate = willActivate;
|
||||
} else {
|
||||
if (fallback == null) {
|
||||
fallback = new EternalRitual(world);
|
||||
fallback.center = center;
|
||||
fallback.axis = axis;
|
||||
fallback.willActivate = willActivate;
|
||||
fallback.active = active;
|
||||
}
|
||||
pedestal.linkRitual(fallback);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkFrame(Level world, BlockPos framePos) {
|
||||
Direction moveDir = Direction.Axis.X == axis ? Direction.NORTH : Direction.EAST;
|
||||
boolean valid = true;
|
||||
|
@ -137,8 +198,15 @@ public class EternalRitual {
|
|||
return active;
|
||||
}
|
||||
|
||||
public boolean willActivate() {
|
||||
return willActivate;
|
||||
}
|
||||
|
||||
private void activatePortal(Player player, Item keyItem) {
|
||||
if (active) return;
|
||||
willActivate = true;
|
||||
updateActiveStateOnPedestals();
|
||||
|
||||
ResourceLocation itemId = BuiltInRegistries.ITEM.getKey(keyItem);
|
||||
int portalId = EndPortals.getPortalIdByItem(itemId);
|
||||
Level targetWorld = getTargetWorld(portalId);
|
||||
|
@ -156,13 +224,19 @@ public class EternalRitual {
|
|||
activatePortal(targetWorld, exit, portalId);
|
||||
}
|
||||
activatePortal(world, center, portalId);
|
||||
doEffects((ServerLevel) world, center);
|
||||
if (world instanceof ServerLevel serverLevel) {
|
||||
doEffects(serverLevel, center);
|
||||
}
|
||||
willActivate = false;
|
||||
active = true;
|
||||
updateActiveStateOnPedestals();
|
||||
} catch (Exception ex) {
|
||||
BetterEnd.LOGGER.error("Create End portals error.", ex);
|
||||
removePortal(targetWorld, exit);
|
||||
removePortal(world, center);
|
||||
willActivate = false;
|
||||
active = false;
|
||||
updateActiveStateOnPedestals();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -238,8 +312,7 @@ public class EternalRitual {
|
|||
.setValue(EndPortalBlock.AXIS, portalAxis)
|
||||
.setValue(EndPortalBlock.PORTAL, portalId);
|
||||
ParticleOptions effect = new BlockParticleOption(ParticleTypes.BLOCK, portal);
|
||||
ServerLevel serverWorld = (ServerLevel) world;
|
||||
|
||||
if (world instanceof ServerLevel serverWorld) {
|
||||
PortalBuilder.PORTAL_POSITIONS.forEach(point -> {
|
||||
BlockPos pos = center.mutable().move(moveDir, point.x).move(Direction.UP, point.y);
|
||||
if (!world.getBlockState(pos).is(PortalBuilder.PORTAL)) {
|
||||
|
@ -273,11 +346,14 @@ public class EternalRitual {
|
|||
0.5, 0.5, 0.5, 0.3
|
||||
);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void disablePortal(int state) {
|
||||
if (!active || isInvalid()) return;
|
||||
if (!world.isClientSide())
|
||||
removePortal(getTargetWorld(state), exit);
|
||||
removePortal(world, center);
|
||||
}
|
||||
|
@ -308,6 +384,7 @@ public class EternalRitual {
|
|||
}
|
||||
});
|
||||
this.active = false;
|
||||
updateActiveStateOnPedestals();
|
||||
}
|
||||
|
||||
private Level getTargetWorld(int state) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue