跳转至内容
  • 版块
  • 最新
  • 热门
  • 标签
  • 群组
皮肤
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • 默认(Zephyr)
  • 不使用皮肤
折叠
品牌标识

VariedMC 魔改论坛

  1. 主页
  2. 灵感大王
  3. [原创][1.20.1][EidolonJS开发实录]基于链式调用达成在Schema注册中使用回调函数构建配方

[原创][1.20.1][EidolonJS开发实录]基于链式调用达成在Schema注册中使用回调函数构建配方

已定时 已固定 已锁定 已移动 灵感大王
forgekubejs1.20.1java
2 帖子 2 发布者 20 浏览 1 关注中
  • 从旧到新
  • 从新到旧
  • 最多赞同
    回复
    • 在新帖中回复
    登录后回复
    此主题已被删除。只有拥有主题管理权限的用户可以查看。
    • 不是椰浆不 离线
      不是椰浆不 离线
      不是椰浆
      VariedMC Packing KubeJS
      编写于 最后由 编辑
      #1

      项目地址:PickAID/EidolonJS: as the name says


      在为Eidolon中的坩埚注册相应的Schema时,我发现了一个问题:

      坩埚配方的输入并不能够使用简单的RecipeKey添加,相关的代码如下:

      public static class Step {
              public final List<Ingredient> matches = new ArrayList<>();
              public final int stirs;
      
              public Step(int stirs, List<Ingredient> matches) {
                  this.stirs = stirs;
                  this.matches.addAll(matches);
              }
          }
      

      而最初一版的RecipeKey与Schema设计如下:

      public interface CrucibleSchema {
          RecipeKey<OutputItem> OUTPUT = ItemComponents.OUTPUT_ID_WITH_COUNT.key("result");
          RecipeKey<OutputItem[]> OUTPUT = ItemComponents.OUTPUT_ARRAY.key("result");
      
          RecipeComponentBuilder STEP_BUILDER = new RecipeComponentBuilder(2)
                  .add(NumberComponent.INT.key("stirs").optional(1))
                  .add(NumberComponent.INT.key("stirs").defaultOptional())
                  .add(ItemComponents.INPUT_ARRAY.key("items"));
          RecipeKey<RecipeComponentBuilderMap[]> STEPS = STEP_BUILDER.inputRole().asArray().key("steps");
          RecipeSchema SCHEMA = new RecipeSchema(OUTPUT, STEPS);
      

      进行注册后简单对代码进行测试:

      ServerEvents.recipes(event => {
          event.recipes.eidolon.crucible("2x stone", [
              {stirs: 1, items: ["#forge:dusts/redstone", "2x eidolon:soul_shard"]},
              {items: ["#forge:dusts/redstone", "eidolon:soul_shard"]},
              {stirs: 1},
              {stirs: 3}
          ])
      }
      

      配方的确可以正常注册,但是可以看到,Step部分的格式与json几乎一致,不够优雅。
      于是笔者开始尝试在RecipeKey中使用回调函数,然而失败了(也有可能是我菜),
      而我在阅读了SummoningRitual的源代码之后(AlmostReliable/summoningrituals at 1.20.1-forge)有了不一样的想法。
      或许可以使用链式调用形式的配方,并在链式调用的方法中使用回调函数。
      完整的代码实现如下:

      //篇幅原因省去import
      
      //CrucibleSchema.java
      public interface CrucibleSchema {
          @FunctionalInterface
          interface StepBuilderCallback {
              void apply(StepBuilderJS builder);
          }
          class CrucibleRecipeJS extends RecipeJS {
              public CrucibleRecipeJS steps(StepBuilderCallback callback) {
                  var builder = new StepBuilderJS();
                  callback.apply(builder);
                  setValue(STEPS, builder.getStepList().toArray(CrucibleRecipe.Step[]::new));
                  return this;
              }
      
      
          }
      
          RecipeKey<CrucibleRecipe.Step[]> STEPS = new RecipeComponent<CrucibleRecipe.Step[]>() {
              @Override
              public Class<?> componentClass() {
                  return CrucibleRecipe.Step[].class;
              }
      
              @Override
              public JsonElement write(RecipeJS recipe, CrucibleRecipe.Step[] value) {
                  if (value == null) {
                      return null;
                  }
      
                  JsonArray stepsArray = new JsonArray();
                  for (CrucibleRecipe.Step step : value) {
                      JsonObject stepObj = new JsonObject();
      
                      // Add stirs
                      stepObj.addProperty("stirs", step.stirs);
      
                      // Add items
                      if (!step.matches.isEmpty()) {
                          JsonArray itemsArray = new JsonArray();
                          for (Ingredient ingredient : step.matches) {
                              itemsArray.add(ingredient.toJson());
                          }
                          stepObj.add("items", itemsArray);
                      }
      
                      stepsArray.add(stepObj);
                  }
      
                  return stepsArray;
              }
      
              @Override
              public CrucibleRecipe.Step[] read(RecipeJS recipe, Object from) {
                  if (from instanceof JsonElement) {
                      JsonArray stepsArray = ((JsonElement) from).getAsJsonArray();
                      List<CrucibleRecipe.Step> steps = new ArrayList<>();
      
                      for (JsonElement element : stepsArray) {
                          if (!element.isJsonObject()) {
                              throw new JsonSyntaxException("Each step must be a JSON object");
                          }
      
                          JsonObject stepObj = element.getAsJsonObject();
                          int stirs = stepObj.has("stirs") ? stepObj.get("stirs").getAsInt() : 0;
      
                          List<Ingredient> ingredients = new ArrayList<>();
                          if (stepObj.has("items")) {
                              JsonArray itemsArray = stepObj.getAsJsonArray("items");
                              for (JsonElement item : itemsArray) {
                                  ingredients.add(Ingredient.fromJson(item));
                              }
                          }
      
                          steps.add(new CrucibleRecipe.Step(stirs, ingredients));
                      }
      
                      return steps.toArray(CrucibleRecipe.Step[]::new);
                  } else {
                      throw new JsonSyntaxException("Each step must be a JSON object");
                  }
              }
          }.key("steps").noBuilders();
      
          RecipeKey<OutputItem> OUTPUT = ItemComponents.OUTPUT.key("result").noBuilders();
      
          RecipeSchema SCHEMA = new RecipeSchema(CrucibleRecipeJS.class, CrucibleRecipeJS::new, OUTPUT, STEPS).constructor(((recipe, schemaType, keys, from) -> {
              recipe.setValue(OUTPUT, from.getValue(recipe, OUTPUT));
              recipe.setValue(STEPS, new CrucibleRecipe.Step[0]);
          }), OUTPUT);
      
      }
      
      
      //StepBuilderJS.java
      public class StepBuilderJS {
          List<CrucibleRecipe.Step> stepList = new ArrayList<>();
          List<Ingredient> item = new ArrayList<>();
          int stirs = 0;
      
          public StepBuilderJS stirs(int count) {
              stirs = count;
              return this;
          }
      
          public StepBuilderJS stirs() {
              return stirs(1);
          }
      
          public StepBuilderJS items(Ingredient... items) {
              item.addAll(List.of(items));
              return this;
          }
      
          public void step(int count, Ingredient... items) {
              var step = new CrucibleRecipe.Step(count, item);
              stepList.add(step);
          }
      
          public void build(){
              var step = new CrucibleRecipe.Step(stirs, item);
              stepList.add(step);
              stirs(0);
              item.clear();
          }
      
          @HideFromJS
          public List<CrucibleRecipe.Step> getStepList() {
              return stepList;
          }
      }
      

      最终实现的效果如下:

      event.recipes.eidolon.crucible("2x stone").steps((step) => {
              step.stirs(1).items("#forge:dusts/redstone", "eidolon:soul_shard").build()
              step.items("#forge:dusts/redstone","eidolon:soul_shard").build()
              step.stirs(3).build()
          })
      

      或许直接使用链式调用传入每一步的设计更为直接,但是出于个人偏好,笔者仍然选择使用回调函数的形式处理这部分。
      (//TODO 代码详解施工中)

      1 条回复 最后回复
      2
      • 半梦半 离线
        半梦半 离线
        半梦
        Packing
        编写于 最后由 编辑
        #2

        是幻梦吉斯,我们有救了❤

        1 条回复 最后回复
        0
        回复
        • 在新帖中回复
        登录后回复
        • 从旧到新
        • 从新到旧
        • 最多赞同


          • 登录

          • 没有帐号? 注册

          • 登录或注册以进行搜索。
          • 第一个帖子
            最后一个帖子
          0
          • 版块
          • 最新
          • 热门
          • 标签
          • 群组