WeightedBlock class
Пакет: com.hypixel.hytale.builtin.randomtick.procedures
Файл: com/hypixel/hytale/builtin/randomtick/procedures/PlaceBlockProcedure.java
Поля (3)
| Модификаторы | Тип | Имя |
|---|---|---|
|
public static final BuilderCodec<PlaceBlockProcedure.WeightedBlock> |
CODEC |
|
private String |
block |
|
private double |
weight |
Методы (3)
| Модификаторы | Возврат | Сигнатура |
|---|---|---|
|
public String |
getBlockpublic String getBlock() |
|
public double |
getWeightpublic double getWeight() |
|
public String |
toStringpublic String toString() |
Исходный код
Показать/скрыть
class="kw">package com.hypixel.hytale.builtin.randomtick.procedures;
class="kw">import com.hypixel.hytale.assetstore.map.BlockTypeAssetMap;
class="kw">import com.hypixel.hytale.codec.Codec;
class="kw">import com.hypixel.hytale.codec.KeyedCodec;
class="kw">import com.hypixel.hytale.codec.builder.BuilderCodec;
class="kw">import com.hypixel.hytale.codec.codecs.array.ArrayCodec;
class="kw">import com.hypixel.hytale.codec.validation.Validators;
class="kw">import com.hypixel.hytale.component.CommandBuffer;
class="kw">import com.hypixel.hytale.component.Ref;
class="kw">import com.hypixel.hytale.component.Store;
class="kw">import com.hypixel.hytale.math.util.ChunkUtil;
class="kw">import com.hypixel.hytale.math.vector.Vector3iUtil;
class="kw">import com.hypixel.hytale.protocol.BlockMaterial;
class="kw">import com.hypixel.hytale.server.core.asset.type.blocktick.config.RandomTickProcedure;
class="kw">import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType;
class="kw">import com.hypixel.hytale.server.core.universe.world.chunk.BlockOperations;
class="kw">import com.hypixel.hytale.server.core.universe.world.chunk.section.BlockSection;
class="kw">import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore;
class="kw">import java.util.Arrays;
class="kw">import java.util.HashSet;
class="kw">import java.util.Random;
class="kw">import java.util.Set;
class="kw">import java.util.concurrent.ThreadLocalRandom;
class="kw">import javax.annotation.Nonnull;
class="kw">import javax.annotation.Nullable;
class="kw">import org.joml.Vector3i;
class="kw">public class PlaceBlockProcedure class="kw">implements RandomTickProcedure {
class="kw">public class="kw">static class="kw">final BuilderCodec<PlaceBlockProcedure> CODEC = BuilderCodec.builder(PlaceBlockProcedure.class, PlaceBlockProcedure::new)
.appendInherited(
new KeyedCodec<>("Placements", new ArrayCodec<>(PlaceBlockProcedure.PlacementRule.CODEC, PlaceBlockProcedure.PlacementRule[]::new)),
(var0, var1) -> var0.placements = var1,
var0 -> var0.placements,
(var0, var1) -> var0.placements = var1.placements
)
.documentation(
"The blocks that can be placed at the configured Offset. Each rule may optionally be scoped to one of this block's visual States; a rule with no State applies to the block's class="kw">default (stateless) form. The first rule matching the block's current State is placed when the target cell is clear."
)
.addValidator(Validators.nonEmptyArray())
.add()
.<Vector3i>appendInherited(
new KeyedCodec<>("Offset", Vector3iUtil.CODEC), (var0, var1) -> var0.offset = var1, var0 -> var0.offset, (var0, var1) -> var0.offset = var1.offset
)
.documentation(
"The block offset (relative to the ticking block) at which to place the block. For example X=0, Y=1, Z=0 places the block one cell directly above."
)
.addValidator(Validators.nonNull())
.add()
.<Boolean>appendInherited(
new KeyedCodec<>("RequireEmptyTarget", Codec.BOOLEAN),
(var0, var1) -> var0.requireEmptyTarget = var1,
var0 -> var0.requireEmptyTarget,
(var0, var1) -> var0.requireEmptyTarget = var1.requireEmptyTarget
)
.documentation(
"Whether the target cell must be empty (air) for the placement to occur. When true (the class="kw">default) an obstruction causes the procedure to silently do nothing and retry on a later tick."
)
.add()
.validator((var0, var1) -> {
if (var0.placements != null) {
Set var2 = new HashSet<>();
for (PlaceBlockProcedure.PlacementRule var6 : var0.placements) {
String var7 = var6.state != null ? var6.state : "class="kw">default";
if (!var2.add(var7)) {
var1.fail("Multiple Placements target the same State '" + var7 + "'; only the first would ever apply.");
}
}
}
})
.build();
class="kw">private PlaceBlockProcedure.PlacementRule[] placements;
class="kw">private Vector3i offset;
class="kw">private boolean requireEmptyTarget = true;
class="kw">public PlaceBlockProcedure() {
}
@Override
class="kw">public void onRandomTick(Store<ChunkStore> var1, CommandBuffer<ChunkStore> var2, BlockSection var3, int var4, int var5, int var6, int var7, BlockType var8) {
if (this.placements != null && this.placements.length != 0 && this.offset != null) {
int var9 = var4 + this.offset.x();
int var10 = var5 + this.offset.y();
int var11 = var6 + this.offset.z();
String var12 = var8.getStateForBlock(var8.getId());
if (var12 == null) {
var12 = "class="kw">default";
}
PlaceBlockProcedure.PlacementRule var13 = this.findRule(var12);
if (var13 != null) {
int var14 = var13.resolveBlockId(ThreadLocalRandom.current());
if (var14 != Integer.MIN_VALUE) {
BlockType var15 = BlockType.getAssetMap().getAsset(var14);
if (var15 != null) {
int var16 = getBlockId(var1, var2, var3, var4, var5, var6, var9, var10, var11);
if (!var13.placesBlockId(var16)) {
if (!this.requireEmptyTarget || isEmpty(var16)) {
var2.run(var6x -> {
ChunkStore var7 = var6x.getExternalData();
Ref var8 = var7.getChunkSectionReferenceAtBlock(var9, var10, var11);
if (var8 != null && var8.isValid()) {
BlockSection var9 = var6x.getComponent(var8, BlockSection.getComponentType());
if (var9 != null) {
int var10 = var9.get(ChunkUtil.indexBlock(var9, var10, var11));
if (var10 != var14) {
if (!this.requireEmptyTarget || isEmpty(var10)) {
BlockOperations.setBlock(var7, var8, var9, var10, var11, var14, var15, 0, 0, 0);
}
}
}
}
});
}
}
}
}
}
}
}
class="kw">private class="kw">static boolean isEmpty(int var0) {
BlockType var1 = BlockType.getAssetMap().getAsset(var0);
class="kw">return var1 != null && var1.getMaterial() == BlockMaterial.Empty;
}
@Nullable
class="kw">private PlaceBlockProcedure.PlacementRule findRule(String var1) {
for (PlaceBlockProcedure.PlacementRule var5 : this.placements) {
String var6 = var5.state != null ? var5.state : "class="kw">default";
if (var6.equals(var1)) {
class="kw">return var5;
}
}
class="kw">return null;
}
class="kw">private class="kw">static int getBlockId(
Store<ChunkStore> var0, CommandBuffer<ChunkStore> var1, BlockSection var2, int var3, int var4, int var5, int var6, int var7, int var8
) {
BlockSection var9 = var2;
if (!ChunkUtil.isSameChunkSection(var3, var4, var5, var6, var7, var8)) {
Ref var10 = var0.getExternalData().getChunkSectionReferenceAtBlock(var6, var7, var8);
if (var10 == null) {
class="kw">return 0;
}
var9 = var1.getComponent(var10, BlockSection.getComponentType());
if (var9 == null) {
class="kw">return 0;
}
}
class="kw">return var9.get(ChunkUtil.indexBlock(var6, var7, var8));
}
@Override
class="kw">public String toString() {
class="kw">return "PlaceBlockProcedure{placements="
+ Arrays.toString(this.placements)
+ ", offset="
+ this.offset
+ ", requireEmptyTarget="
+ this.requireEmptyTarget
+ "}";
}
class="kw">public class="kw">static class PlacementRule {
class="kw">public class="kw">static class="kw">final BuilderCodec<PlaceBlockProcedure.PlacementRule> CODEC = BuilderCodec.builder(
PlaceBlockProcedure.PlacementRule.class, PlaceBlockProcedure.PlacementRule::new
)
.appendInherited(
new KeyedCodec<>("State", Codec.STRING), (var0, var1) -> var0.state = var1, var0 -> var0.state, (var0, var1) -> var0.state = var1.state
)
.documentation(
"Optional. The ticking block's own state (as defined under State.Definitions) that this rule applies to. If omitted, the rule applies to the block's class="kw">default (stateless) form."
)
.add()
.<String>appendInherited(
new KeyedCodec<>("Block", Codec.STRING), (var0, var1) -> var0.block = var1, var0 -> var0.block, (var0, var1) -> var0.block = var1.block
)
.documentation(
"The single block id to place at the configured offset when this rule's State is matched. Use this for a fixed block; for a randomised choice use Blocks instead. Exactly one of Block or Blocks must be set."
)
.addValidatorLate(() -> BlockType.VALIDATOR_CACHE.getValidator().late())
.add()
.<PlaceBlockProcedure.WeightedBlock[]>appendInherited(
new KeyedCodec<>("Blocks", new ArrayCodec<>(PlaceBlockProcedure.WeightedBlock.CODEC, PlaceBlockProcedure.WeightedBlock[]::new)),
(var0, var1) -> var0.blocks = var1,
var0 -> var0.blocks,
(var0, var1) -> var0.blocks = var1.blocks
)
.documentation(
"A weighted list of candidate blocks to choose from when this rule's State is matched. Each placement randomly selects one entry, with higher Weight values chosen proportionally more often. Exactly one of Block or Blocks must be set."
)
.add()
.validator((var0, var1) -> {
boolean var2 = var0.block != null;
boolean var3 = var0.blocks != null && var0.blocks.length > 0;
if (var2 == var3) {
var1.fail("A PlacementRule must specify exactly one of 'Block' (a single block) or 'Blocks' (a weighted list).");
}
})
.build();
class="kw">private String state;
class="kw">private String block;
class="kw">private PlaceBlockProcedure.WeightedBlock[] blocks;
class="kw">private class="kw">transient double totalWeight;
class="kw">public PlacementRule() {
}
class="kw">public String getState() {
class="kw">return this.state;
}
class="kw">public String getBlock() {
class="kw">return this.block;
}
class="kw">public PlaceBlockProcedure.WeightedBlock[] getBlocks() {
class="kw">return this.blocks;
}
int resolveBlockId(@Nonnull Random var1) {
if (this.blocks != null && this.blocks.length > 0) {
PlaceBlockProcedure.WeightedBlock var2 = this.pickWeighted(var1);
class="kw">return var2 != null ? BlockType.getAssetMap().getIndex(var2.block) : Integer.MIN_VALUE;
} else {
class="kw">return this.block != null ? BlockType.getAssetMap().getIndex(this.block) : Integer.MIN_VALUE;
}
}
boolean placesBlockId(int var1) {
if (var1 == Integer.MIN_VALUE) {
class="kw">return false;
}
BlockTypeAssetMap var2 = BlockType.getAssetMap();
if (this.blocks != null && this.blocks.length > 0) {
for (PlaceBlockProcedure.WeightedBlock var6 : this.blocks) {
if (var2.getIndex(var6.block) == var1) {
class="kw">return true;
}
}
class="kw">return false;
} else {
class="kw">return this.block != null && var2.getIndex(this.block) == var1;
}
}
@Nullable
class="kw">private PlaceBlockProcedure.WeightedBlock pickWeighted(@Nonnull Random var1) {
double var2 = this.totalWeight;
if (var2 <= 0.0) {
for (PlaceBlockProcedure.WeightedBlock var7 : this.blocks) {
var2 += var7.weight;
}
this.totalWeight = var2;
}
if (var2 <= 0.0) {
class="kw">return null;
}
double var10 = var1.nextDouble() * var2;
for (PlaceBlockProcedure.WeightedBlock var9 : this.blocks) {
var10 -= var9.weight;
if (var10 <= 0.0) {
class="kw">return var9;
}
}
class="kw">return this.blocks[this.blocks.length - 1];
}
@Override
class="kw">public String toString() {
class="kw">return "PlacementRule{state='" + this.state + "', block='" + this.block + "', blocks=" + Arrays.toString(this.blocks) + "}";
}
}
class="kw">public class="kw">static class WeightedBlock {
class="kw">public class="kw">static class="kw">final BuilderCodec<PlaceBlockProcedure.WeightedBlock> CODEC = BuilderCodec.builder(
PlaceBlockProcedure.WeightedBlock.class, PlaceBlockProcedure.WeightedBlock::new
)
.appendInherited(
new KeyedCodec<>("Block", Codec.STRING), (var0, var1) -> var0.block = var1, var0 -> var0.block, (var0, var1) -> var0.block = var1.block
)
.documentation("The block id that may be placed when this option is selected.")
.addValidatorLate(() -> BlockType.VALIDATOR_CACHE.getValidator().late())
.addValidator(Validators.nonNull())
.add()
.<Double>appendInherited(
new KeyedCodec<>("Weight", Codec.DOUBLE), (var0, var1) -> var0.weight = var1, var0 -> var0.weight, (var0, var1) -> var0.weight = var1.weight
)
.documentation(
"Optional. The relative selection weight for this block (class="kw">default 1.0). A block with weight 2.0 is twice as likely to be chosen as one with weight 1.0."
)
.addValidator(Validators.greaterThan(0.0))
.add()
.build();
class="kw">private String block;
class="kw">private double weight = 1.0;
class="kw">public WeightedBlock() {
}
class="kw">public String getBlock() {
class="kw">return this.block;
}
class="kw">public double getWeight() {
class="kw">return this.weight;
}
@Override
class="kw">public String toString() {
class="kw">return "WeightedBlock{block='" + this.block + "', weight=" + this.weight + "}";
}
}
}