Inspired by 2020's April Fools' 20w14infinite Snapshot, this mod brings endless randomly generated dimensions into Minecraft.
1package net.lerariemann.infinity.entity.custom;
2
3import net.lerariemann.infinity.InfinityMod;
4import net.lerariemann.infinity.util.InfinityMethods;
5import net.lerariemann.infinity.util.VersionMethods;
6import net.lerariemann.infinity.util.core.ConfigType;
7import net.lerariemann.infinity.util.core.NbtUtils;
8import net.minecraft.core.BlockPos;
9import net.minecraft.core.particles.DustParticleOptions;
10import net.minecraft.core.particles.ParticleOptions;
11import net.minecraft.core.registries.BuiltInRegistries;
12import net.minecraft.nbt.CompoundTag;
13import net.minecraft.network.syncher.EntityDataAccessor;
14import net.minecraft.network.syncher.EntityDataSerializers;
15import net.minecraft.network.syncher.SynchedEntityData;
16import net.minecraft.resources.ResourceKey;
17import net.minecraft.resources.ResourceLocation;
18import net.minecraft.server.level.ServerLevel;
19import net.minecraft.sounds.SoundEvent;
20import net.minecraft.world.*;
21import net.minecraft.world.damagesource.DamageSource;
22import net.minecraft.world.entity.EntityType;
23import net.minecraft.world.entity.SpawnGroupData;
24import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
25import net.minecraft.world.entity.ai.attributes.Attributes;
26import net.minecraft.world.entity.monster.Monster;
27import net.minecraft.world.entity.monster.Slime;
28import net.minecraft.world.entity.player.Player;
29import net.minecraft.world.item.ItemStack;
30import net.minecraft.world.level.Level;
31import net.minecraft.world.level.LevelReader;
32import net.minecraft.world.level.ServerLevelAccessor;
33import net.minecraft.world.level.WorldGenLevel;
34import net.minecraft.world.level.block.Block;
35import net.minecraft.world.level.block.Blocks;
36import net.minecraft.world.level.block.state.BlockState;
37//? if >1.21.4 {
38import net.minecraft.world.level.storage.ValueInput;
39import net.minecraft.world.level.storage.ValueOutput;
40import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
41import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets;
42//?}
43import net.minecraft.world.level.storage.loot.LootParams;
44import net.minecraft.world.level.storage.loot.LootTable;
45import org.jspecify.annotations.Nullable;
46
47import java.util.Optional;
48import java.util.Random;
49import java.util.function.BiConsumer;
50import java.util.function.Function;
51
52public class ChaosSlime extends Slime implements TintableEntity {
53 public static final EntityDataAccessor<BlockState> core = SynchedEntityData.defineId(ChaosSlime.class, EntityDataSerializers.BLOCK_STATE);
54 public static final EntityDataAccessor<Integer> color = SynchedEntityData.defineId(ChaosSlime.class, EntityDataSerializers.INT);
55
56 public ChaosSlime(EntityType<? extends ChaosSlime> entityType, Level world) {
57 super(entityType, world);
58 }
59
60 @Override
61 public int getColorNamed() {
62 return hasCustomName() ? TintableEntity.getColorNamed(getName().getString(), tickCount, getId()) : -1;
63 }
64
65 @Override
66 protected void defineSynchedData(
67 //? if >1.21 {
68 SynchedEntityData.Builder builder
69 //?}
70 ) {
71 super.defineSynchedData(
72 //? if >1.21 {
73 builder
74 //?}
75 );
76 //? if <1.21 {
77 /*var builder = this.entityData;
78 *///?}
79 builder.define(core, Blocks.STONE.defaultBlockState());
80 builder.define(color, 0);
81 }
82
83 public static AttributeSupplier.Builder createAttributes() {
84 return Monster.createMonsterAttributes().add(Attributes.MOVEMENT_SPEED, 0.2f);
85 }
86
87 @Override
88 @Nullable
89 public SpawnGroupData finalizeSpawn(ServerLevelAccessor world, DifficultyInstance difficulty,
90 //? if >1.21.2 {
91 net.minecraft.world.entity.EntitySpawnReason
92 //?} else {
93 /*net.minecraft.world.entity.MobSpawnType
94 *///?}
95 spawnReason, @Nullable SpawnGroupData entityData
96 //? if <1.21 {
97 /*,CompoundTag tag
98 *///?}
99 ) {
100 Random r = InfinityMod.random;
101 this.entityData.set(core, VersionMethods.getFromRegistry(BuiltInRegistries.BLOCK, VersionMethods.id(InfinityMod.provider.randomName(r, ConfigType.ALL_BLOCKS))).defaultBlockState());
102 this.entityData.set(color, r.nextInt(16777216));
103 SpawnGroupData res = super.finalizeSpawn(world, difficulty, spawnReason, entityData
104 //? if <1.21
105 /*, tag*/
106 );
107 this.setSize(1 << r.nextInt(3), true);
108 return res;
109 }
110
111 @Override
112 public boolean checkSpawnObstruction(LevelReader world) {
113 return world.isUnobstructed(this);
114 }
115
116 public void setColor(int c) {
117 this.entityData.set(color, c);
118 }
119 @Override
120 public int getColor() {
121 return this.entityData.get(color);
122 }
123
124 public void setCore(BlockState c) {
125 this.entityData.set(core, c);
126 }
127 public BlockState getCore() {
128 return this.entityData.get(core);
129 }
130 public BlockState getCoreForChild() {
131 return Blocks.AIR.defaultBlockState();
132 }
133
134 @Override
135 protected ParticleOptions getParticleType() {
136 return new DustParticleOptions(
137 //? if >1.21.2 {
138 this.getColorForRender()
139 //?} else {
140 /*particleColorFromInt(this.getColorForRender())
141 *///?}
142 , 1.0f);
143 }
144 @Override
145 protected SoundEvent getHurtSound(DamageSource source) {
146 return this.getCore().getSoundType().getHitSound();
147 }
148 @Override
149 protected SoundEvent getDeathSound() {
150 return this.getCore().getSoundType().getBreakSound();
151 }
152 @Override
153 protected SoundEvent getSquishSound() {
154 return this.getCore().getSoundType().getStepSound();
155 }
156 @Override
157 protected SoundEvent getJumpSound() {
158 return this.getCore().getSoundType().getFallSound();
159 }
160
161 public
162 //? if >1.21.4 {
163 Optional<ResourceKey<LootTable>>
164 //?} else if >1.21 {
165 /*ResourceKey<LootTable>
166 *///?} else {
167 /*ResourceLocation
168 *///?}
169 getDefaultLootTable() {
170 return this.getCore().getBlock().getLootTable();
171 }
172
173 //? if >1.21.4 {
174 @Override
175 protected void dropFromLootTable(ServerLevel level, DamageSource damageSource, boolean playerKill) {
176 Optional<ResourceKey<LootTable>> optional = getDefaultLootTable();
177 if (optional.isPresent()) {
178 LootTable loottable = level.getServer().reloadableRegistries().getLootTable(optional.get());
179 LootParams.Builder lootparams$builder = new LootParams.Builder(level)
180 .withParameter(LootContextParams.THIS_ENTITY, this)
181 .withParameter(LootContextParams.ORIGIN, this.position())
182 .withParameter(LootContextParams.DAMAGE_SOURCE, damageSource)
183 .withOptionalParameter(LootContextParams.ATTACKING_ENTITY, damageSource.getEntity())
184 .withOptionalParameter(LootContextParams.DIRECT_ATTACKING_ENTITY, damageSource.getDirectEntity());
185 Player player = this.getLastHurtByPlayer();
186 if (playerKill && player != null) {
187 lootparams$builder = lootparams$builder.withParameter(LootContextParams.LAST_DAMAGE_PLAYER, player).withLuck(player.getLuck());
188 }
189
190 LootParams lootparams = lootparams$builder.create(LootContextParamSets.ENTITY);
191 loottable.getRandomItems(lootparams, this.getLootTableSeed(), stack -> this.spawnAtLocation(level, stack));
192 }
193 }
194 //?}
195
196 @Override
197 public void addAdditionalSaveData(
198 //? if >1.21.2 {
199 ValueOutput
200 //?} else {
201 /*CompoundTag
202 *///?}
203 nbt) {
204 super.addAdditionalSaveData(nbt);
205 nbt.putInt("color", getColor());
206 nbt.putString("core", BuiltInRegistries.BLOCK.getKey(this.getCore().getBlock()).toString());
207 }
208
209 @Override
210 public void readAdditionalSaveData(
211 //? if >1.21.2 {
212 ValueInput
213 //?} else {
214 /*CompoundTag
215 *///?}
216 nbt) {
217 super.readAdditionalSaveData(nbt);
218 this.setColor(NbtUtils.getInt(nbt, "color"));
219 Block b = VersionMethods.getBlock(VersionMethods.id(NbtUtils.getString(nbt,"core")));
220 this.setCore(b.defaultBlockState());
221 }
222
223 public static boolean canSpawn(EntityType<ChaosSlime> type, ServerLevelAccessor world,
224 //? if >1.21.2 {
225 net.minecraft.world.entity.EntitySpawnReason
226 //?} else {
227 /*net.minecraft.world.entity.MobSpawnType
228 *///?}
229 spawnReason, BlockPos pos, net.minecraft.util.RandomSource random) {
230 if (world.getDifficulty() != Difficulty.PEACEFUL && InfinityMethods.chaosMobsEnabled()) {
231 if (!(world instanceof WorldGenLevel)) {
232 return false;
233 }
234 return Slime.checkMobSpawnRules(type, world, spawnReason, pos, random);
235 }
236 return false;
237 }
238}