-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
d01261c
commit 2857f67
Showing
5 changed files
with
322 additions
and
191 deletions.
There are no files selected for viewing
223 changes: 223 additions & 0 deletions
223
src/main/java/net/creeperhost/soulshardsrespawn/block/SoulSpawnerLogic.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,223 @@ | ||
package net.creeperhost.soulshardsrespawn.block; | ||
|
||
import net.creeperhost.soulshardsrespawn.SoulShards; | ||
import net.creeperhost.soulshardsrespawn.api.CageSpawnEvent; | ||
import net.creeperhost.soulshardsrespawn.api.IShardTier; | ||
import net.creeperhost.soulshardsrespawn.core.data.Binding; | ||
import net.minecraft.client.Minecraft; | ||
import net.minecraft.core.BlockPos; | ||
import net.minecraft.core.particles.ParticleTypes; | ||
import net.minecraft.resources.ResourceLocation; | ||
import net.minecraft.server.level.ServerLevel; | ||
import net.minecraft.util.RandomSource; | ||
import net.minecraft.world.entity.*; | ||
import net.minecraft.world.level.BaseSpawner; | ||
import net.minecraft.world.level.Level; | ||
import net.minecraft.world.level.block.Blocks; | ||
import net.minecraft.world.phys.AABB; | ||
import net.minecraftforge.api.distmarker.Dist; | ||
import net.minecraftforge.api.distmarker.OnlyIn; | ||
import net.minecraftforge.common.MinecraftForge; | ||
import net.minecraftforge.event.ForgeEventFactory; | ||
import net.minecraftforge.eventbus.api.Event; | ||
import net.minecraftforge.registries.ForgeRegistries; | ||
import org.jetbrains.annotations.Nullable; | ||
|
||
import java.util.HashMap; | ||
import java.util.Map; | ||
|
||
/** | ||
* Created by brandon3055 on 11/01/2024 | ||
*/ | ||
public class SoulSpawnerLogic extends BaseSpawner { | ||
private static Map<ResourceLocation, Entity> RENDER_ENTITY_CACHE = new HashMap<>(); | ||
|
||
private final TileEntitySoulCage tile; | ||
private double mobRotation; | ||
private double prevMobRotation; | ||
|
||
public SoulSpawnerLogic(TileEntitySoulCage tile) { | ||
this.tile = tile; | ||
} | ||
|
||
@Override | ||
public void setEntityId(EntityType<?> p_45463_) { | ||
} | ||
|
||
@Override | ||
public void clientTick(Level level, BlockPos pos) { | ||
if (!tile.isActive()) { | ||
this.prevMobRotation = this.mobRotation; | ||
} else { | ||
double d3 = (float) pos.getX() + level.random.nextFloat(); | ||
double d4 = (float) pos.getY() + level.random.nextFloat(); | ||
double d5 = (float) pos.getZ() + level.random.nextFloat(); | ||
level.addParticle(ParticleTypes.SMOKE, d3, d4, d5, 0.0D, 0.0D, 0.0D); | ||
level.addParticle(ParticleTypes.FLAME, d3, d4, d5, 0.0D, 0.0D, 0.0D); | ||
|
||
if (tile.spawnDelay > 0) { | ||
tile.spawnDelay--; | ||
} | ||
|
||
this.prevMobRotation = this.mobRotation; | ||
Binding binding = tile.getBinding(); | ||
if (binding != null) { | ||
double progress = 1F - (tile.spawnDelay / (double) binding.getTier().getCooldown()); | ||
this.mobRotation = (this.mobRotation + (progress * 4.5D) + 0.5D) % 360.0D; | ||
} else { | ||
this.mobRotation = (this.mobRotation + (double) (1000.0F / ((float) tile.spawnDelay + 200.0F))) % 360.0D; | ||
} | ||
} | ||
} | ||
|
||
@Override | ||
public void serverTick(ServerLevel level, BlockPos pos) { | ||
if (!tile.isActive()) { | ||
return; | ||
} | ||
|
||
if (tile.spawnDelay == -1) { | ||
resetTimer(); | ||
return; | ||
} | ||
|
||
if (tile.spawnDelay > 0) { | ||
tile.spawnDelay--; | ||
return; | ||
} | ||
|
||
Binding binding = tile.getBinding(); | ||
IShardTier tier = binding.getTier(); | ||
|
||
EntityType<?> type = ForgeRegistries.ENTITY_TYPES.getValue(binding.getBoundEntity()); | ||
if (type == null) { | ||
resetTimer(); | ||
return; | ||
} | ||
|
||
boolean spawnedAny = false; | ||
int successCount = 0; | ||
for (int i = 0; i < tier.getSpawnAmount() + tier.getIndex() + 3; ++i) { | ||
LivingEntity entity = (LivingEntity) type.create(level); | ||
if (entity == null || hasReachedSpawnCap(entity)) { | ||
this.resetTimer(); | ||
return; | ||
} | ||
|
||
do { | ||
double spawnX = pos.getX() + (level.random.nextDouble() - level.random.nextDouble()) * 4.0 + 0.5; | ||
double spawnY = pos.getY() + level.random.nextInt(3) - 1; | ||
double spawnZ = pos.getZ() + (level.random.nextDouble() - level.random.nextDouble()) * 4.0 + 0.5; | ||
entity.absMoveTo(spawnX, spawnY, spawnZ, 0, 0); | ||
} while (entity.blockPosition().getX() == tile.getBlockPos().getX() && entity.blockPosition().getZ() == tile.getBlockPos().getZ()); | ||
entity.moveTo(entity.getX(), entity.getY(), entity.getZ(), level.random.nextFloat() * 360.0F, 0.0F); | ||
|
||
if (attemptEntitySpawn(binding, type, entity, level, (float) entity.getX(), (float) entity.getY(), (float) entity.getZ())) { | ||
entity.getPersistentData().putBoolean("cageBorn", true); | ||
level.levelEvent(2004, pos, 0); | ||
|
||
if (entity instanceof Mob mob) { | ||
mob.spawnAnim(); | ||
} | ||
|
||
spawnedAny = true; | ||
successCount++; | ||
} | ||
if (successCount >= tier.getSpawnAmount()) { | ||
break; | ||
} | ||
} | ||
|
||
if (spawnedAny) { | ||
this.resetTimer(); | ||
} | ||
} | ||
|
||
public boolean attemptEntitySpawn(Binding binding, EntityType<?> type, LivingEntity entity, ServerLevel level, double x, double y, double z) { | ||
if (!level.noCollision(type.getAABB(x, y, z))) { | ||
return false; | ||
} | ||
BlockPos blockpos = new BlockPos(x, y, z); | ||
|
||
if (binding.getTier().checkLight() && !canSpawnInLight(entity)) { | ||
return false; | ||
} | ||
|
||
int tier = binding.getTier().getIndex(); | ||
if (tier < 5 && !SpawnPlacements.checkSpawnRules(type, level, MobSpawnType.SPAWNER, blockpos, level.getRandom())) { | ||
return false; | ||
} | ||
|
||
if (!SoulShards.CONFIG.getBalance().allowBossSpawns() && !entity.canChangeDimensions()) { | ||
return false; | ||
} | ||
|
||
CageSpawnEvent cageEvent = new CageSpawnEvent(binding, tile.getInventory().getStackInSlot(0), entity); | ||
if (MinecraftForge.EVENT_BUS.post(cageEvent)) { | ||
return false; | ||
} | ||
|
||
if (entity instanceof Mob mob) { | ||
if (tier < 5 && (!mob.checkSpawnRules(level, MobSpawnType.SPAWNER) || !mob.checkSpawnObstruction(level))) { | ||
return false; | ||
} | ||
|
||
Event.Result result = ForgeEventFactory.canEntitySpawn(mob, level, x, y, z, this, MobSpawnType.SPAWNER); | ||
if (result == Event.Result.DENY) { | ||
return false; | ||
} | ||
mob.finalizeSpawn(level, level.getCurrentDifficultyAt(blockpos), MobSpawnType.SPAWNER, null, null); | ||
} | ||
|
||
return level.tryAddFreshEntityWithPassengers(entity); | ||
} | ||
|
||
private void resetTimer() { | ||
tile.resetTimer(); | ||
broadcastEvent(tile.getLevel(), tile.getBlockPos(), 1); | ||
} | ||
|
||
private boolean hasReachedSpawnCap(LivingEntity living) { | ||
BlockPos pos = tile.getBlockPos(); | ||
AABB box = new AABB(pos.getX() - 16, pos.getY() - 16, pos.getZ() - 16, pos.getX() + 16, pos.getY() + 16, pos.getZ() + 16); | ||
int mobCount = tile.getLevel().getEntitiesOfClass(living.getClass(), box, e -> e != null && e.getPersistentData().getBoolean("cageBorn")).size(); | ||
return mobCount >= SoulShards.CONFIG.getBalance().getSpawnCap(); | ||
} | ||
|
||
private boolean canSpawnInLight(LivingEntity entityLiving) { | ||
boolean light = tile.getLevel().getLightEngine().getRawBrightness(tile.getBlockPos(), 15) <= 8; | ||
return !(entityLiving instanceof Mob) || light; | ||
} | ||
|
||
@Nullable | ||
@Override | ||
public Entity getOrCreateDisplayEntity(Level level) { | ||
if (tile.getBinding() == null) return null; | ||
ResourceLocation key = tile.getBinding().getBoundEntity(); | ||
if (key == null) return null; | ||
return RENDER_ENTITY_CACHE.computeIfAbsent(key, name -> { | ||
EntityType<?> type = ForgeRegistries.ENTITY_TYPES.getValue(name); | ||
if (type == null) return EntityType.PIG.create(level); | ||
Entity entity = type.create(level); | ||
if (entity == null) return EntityType.PIG.create(level); | ||
return entity; | ||
}); | ||
} | ||
|
||
@Override | ||
@OnlyIn (Dist.CLIENT) | ||
public double getSpin() { | ||
return mobRotation; | ||
} | ||
|
||
@Override | ||
@OnlyIn (Dist.CLIENT) | ||
public double getoSpin() { | ||
return prevMobRotation; | ||
} | ||
|
||
@Override | ||
public void broadcastEvent(Level level, BlockPos blockPos, int event) { | ||
level.blockEvent(blockPos, Blocks.SPAWNER, event, 0); | ||
} | ||
} |
Oops, something went wrong.