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