Skip to content

Commit

Permalink
新增配方输出类型 select_one
Browse files Browse the repository at this point in the history
  • Loading branch information
Gu-ZT committed Apr 19, 2024
1 parent 1bb9318 commit d1198d2
Show file tree
Hide file tree
Showing 9 changed files with 148 additions and 7 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# 铁砧工艺 | [AnvilCraft](./README_en.md)

[![Development Builds](https://github.com/Gu-ZT/AnvilCraftMod/actions/workflows/ci.yml/badge.svg)](https://github.com/Gu-ZT/AnvilCraftMod/actions/workflows/ci.yml)
[![Development Builds](https://github.com/Anvil-Dev/AnvilCraft/actions/workflows/ci.yml/badge.svg)](https://github.com/Anvil-Dev/AnvilCraft/actions/workflows/ci.yml)
[![CurseForge downloads](http://cf.way2muchnoise.eu/full_986251_downloads.svg)](https://www.curseforge.com/minecraft/mc-mods/anvilcraft)
[![Modrinth downloads](https://img.shields.io/modrinth/dt/anvilcraft?color=00AF5C&label=Modrinth%20downloads&logo=modrinth)](https://modrinth.com/mod/anvilcraft)
[![GitHub downloads](https://img.shields.io/github/downloads/Gu-ZT/AnvilCraftMod/total?label=Github%20downloads&logo=github)](https://github.com/Gu-ZT/AnvilCraftMod/releases)
Expand Down
2 changes: 1 addition & 1 deletion README_en.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# [铁砧工艺](./README.md) | AnvilCraft

[![Development Builds](https://github.com/Gu-ZT/AnvilCraftMod/actions/workflows/ci.yml/badge.svg)](https://github.com/Gu-ZT/AnvilCraftMod/actions/workflows/ci.yml)
[![Development Builds](https://github.com/Anvil-Dev/AnvilCraft/actions/workflows/ci.yml/badge.svg)](https://github.com/Anvil-Dev/AnvilCraft/actions/workflows/ci.yml)
[![CurseForge downloads](http://cf.way2muchnoise.eu/full_986251_downloads.svg)](https://www.curseforge.com/minecraft/mc-mods/anvilcraft)
[![Modrinth downloads](https://img.shields.io/modrinth/dt/anvilcraft?color=00AF5C&label=Modrinth%20downloads&logo=modrinth)](https://modrinth.com/mod/anvilcraft)
[![GitHub downloads](https://img.shields.io/github/downloads/Gu-ZT/AnvilCraftMod/total?label=Github%20downloads&logo=github)](https://github.com/Gu-ZT/AnvilCraftMod/releases)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.google.gson.JsonSyntaxException;
import dev.dubhe.anvilcraft.data.recipe.anvil.outcome.DamageAnvil;
import dev.dubhe.anvilcraft.data.recipe.anvil.outcome.RunCommand;
import dev.dubhe.anvilcraft.data.recipe.anvil.outcome.SelectOne;
import dev.dubhe.anvilcraft.data.recipe.anvil.outcome.SetBlock;
import dev.dubhe.anvilcraft.data.recipe.anvil.outcome.SpawnExperience;
import dev.dubhe.anvilcraft.data.recipe.anvil.outcome.SpawnItem;
Expand Down Expand Up @@ -218,7 +219,7 @@ private Builder(RecipeCategory category, ItemStack icon) {
return this;
}

public @NotNull Builder icon(ItemLike icon) {
public @NotNull Builder icon(@NotNull ItemLike icon) {
this.icon = icon.asItem().getDefaultInstance();
return this;
}
Expand Down Expand Up @@ -723,5 +724,6 @@ public enum Type implements RecipeType<AnvilRecipe> {
RecipeOutcome.register("spawn_item", SpawnItem::new, SpawnItem::new);
RecipeOutcome.register("spawn_experience", SpawnExperience::new, SpawnExperience::new);
RecipeOutcome.register("run_command", RunCommand::new, RunCommand::new);
RecipeOutcome.register("select_one", SelectOne::new, SelectOne::new);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,8 @@ static void register(
void toNetwork(FriendlyByteBuf buffer);

JsonElement toJson();

default double getChance() {
return 1.0;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.NotNull;

@Getter
public class RunCommand implements RecipeOutcome {
@Getter
private final String type = "run_command";
private final Vec3 offset;
private final double chance;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package dev.dubhe.anvilcraft.data.recipe.anvil.outcome;

import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import dev.dubhe.anvilcraft.data.recipe.anvil.AnvilCraftingContainer;
import dev.dubhe.anvilcraft.data.recipe.anvil.RecipeOutcome;
import lombok.Getter;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.util.GsonHelper;
import net.minecraft.util.RandomSource;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.List;

@Getter
public class SelectOne implements RecipeOutcome {
private final String type = "select_one";
private final double chance;
private final List<RecipeOutcome> outcomes = new ArrayList<>();

public SelectOne add(RecipeOutcome outcome) {
this.outcomes.add(outcome);
return this;
}

public SelectOne(double chance) {
this.chance = chance;
}

public SelectOne() {
this(1.0);
}

/**
* @param buffer 缓冲区
*/
public SelectOne(@NotNull FriendlyByteBuf buffer) {
this(buffer.readDouble());
for (int i = 0; i < buffer.readVarInt(); i++) {
this.add(RecipeOutcome.fromNetwork(buffer));
}
}

/**
* @param serializedRecipe 序列化配方
*/
public SelectOne(@NotNull JsonObject serializedRecipe) {
if (serializedRecipe.has("chance")) {
this.chance = GsonHelper.getAsDouble(serializedRecipe, "chance");
} else this.chance = 1.0;
if (!serializedRecipe.has("outcomes")) return;
for (JsonElement element : GsonHelper.getAsJsonArray(serializedRecipe, "outcomes")) {
if (element instanceof JsonObject object) this.add(RecipeOutcome.fromJson(object));
}
}

@Override
public boolean process(@NotNull AnvilCraftingContainer container) {
RandomSource random = container.getLevel().random;
List<Double> weights = this.outcomes.stream().map(RecipeOutcome::getChance).toList();
RecipeOutcome outcome = SelectOne.weightedRandomSelect(this.outcomes, weights, random);
if (outcome != null) outcome.process(container);
return true;
}

private static @Nullable <T> T weightedRandomSelect(
@NotNull List<T> elements, @NotNull List<Double> weights, RandomSource random
) {
if (elements.size() != weights.size()) {
throw new IllegalArgumentException("Elements and weights must be of the same size");
}

// 计算权重总和
double totalWeight = weights.stream().mapToDouble(Double::doubleValue).sum();

// 创建累积概率数组
List<Double> cumulativeProbabilities = new ArrayList<>();
double cumulativeSum = 0;
for (double weight : weights) {
cumulativeSum += weight / totalWeight; // 归一化处理
cumulativeProbabilities.add(cumulativeSum);
}

double randomWeight = random.nextDouble(); // 生成0到1之间的随机浮点数

// 使用二分搜索找到对应的元素
int index = binarySearch(cumulativeProbabilities, randomWeight);
if (index < 0 || index >= elements.size()) return null;
return elements.get(index);
}

private static int binarySearch(@NotNull List<Double> cumulativeProbabilities, double value) {
int low = 0;
int high = cumulativeProbabilities.size() - 1;

while (low <= high) {
int mid = (low + high) / 2;
if (cumulativeProbabilities.get(mid) < value) {
low = mid + 1;
} else if (mid > 0 && cumulativeProbabilities.get(mid - 1) >= value) {
high = mid - 1;
} else {
return mid;
}
}
return -1; // 如果权重正确,则永远不应该到达这里
}


@Override
public void toNetwork(@NotNull FriendlyByteBuf buffer) {
buffer.writeUtf(this.getType());
buffer.writeDouble(this.chance);
buffer.writeVarInt(this.outcomes.size());
for (RecipeOutcome outcome : this.outcomes) {
outcome.toNetwork(buffer);
}
}

@Override
public JsonElement toJson() {
JsonObject object = new JsonObject();
object.addProperty("type", this.getType());
object.addProperty("chance", this.chance);
JsonArray outcomes = new JsonArray();
for (RecipeOutcome outcome : this.outcomes) {
outcomes.add(outcome.toJson());
}
object.add("outcomes", outcomes);
return object;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.NotNull;

@Getter
public class SetBlock implements RecipeOutcome {
@Getter
private final String type = "set_block";
private final Vec3 offset;
private final double chance;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.NotNull;

@Getter
public class SpawnExperience implements RecipeOutcome {
@Getter
private final String type = "spawn_experience";
private final Vec3 offset;
private final double chance;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.NotNull;

@Getter
public class SpawnItem implements RecipeOutcome {
@Getter
private final String type = "spawn_item";
private final Vec3 offset;
private final double chance;
Expand Down

0 comments on commit d1198d2

Please sign in to comment.