Skip to main content
2 of 2
added 13753 characters in body

LootJS/Forge GLM injecting items fails due to mod-internal overwrite (Apocalypse Now/Lost Cities)

I am trying to have modded items in the chests of lost cites mod, and there is this problem I am facing, in which a mod called Apocalypse Now automatically injects its mod items into the chests without having a need of datapack, which suggests its being done internally within the mod. What I have found is that it is overwriting loot tables entirely and by that, lootjs/kubejs or the datapacks of the another mod does not inject their itmes.

That another mod is Timeless and Classics Zero, and I made the datapacks and the json file (later) for this mods by taking help of multiple chatbots, since I lack knowledge on making datapacks or json file for the lootjs/kubejs to overwrite or just add your loot to the loot tables without overwriting it. I will have the contents of those files written down below, by which you can see if there are errors or not in those 3 files.

  1. Datapack for the timeless and classics zero mod:

a. add_tacz_apartment.json

  "type": "forge:add_items",
  "conditions": [
    {
      "condition": "forge:loot_table_id",
      "loot_table_id": "minecraft:chests/apartament"
    }
  ],
  "items": [
    {
      "item": "tacz:modern_kinetic_gun",
      "weight": 100,
      "functions": [
        {
          "function": "minecraft:set_nbt",
          "tag": "{GunId:\\\"tacz:glock_17\\\",GunCurrentAmmoCount:7}"
        },
        {
          "function": "minecraft:set_name",
          "name": {
            "text": "Glock 17",
            "italic": false
          }
        }
      ]
    },
    {
      "item": "tacz:modern_kinetic_gun",
      "weight": 6,
      "functions": [
        {
          "function": "minecraft:set_nbt",
          "tag": "{GunId:\\\"tacz:uzi\\\",GunCurrentAmmoCount:25}"
        },
        {
          "function": "minecraft:set_name",
          "name": {
            "text": "Uzi",
            "italic": false
          }
        }
      ]
    },
    {
      "item": "tacz:modern_kinetic_gun",
      "weight": 6,
      "functions": [
        {
          "function": "minecraft:set_nbt",
          "tag": "{GunId:\\\"tacz:db_short\\\",GunCurrentAmmoCount:2}"
        },
        {
          "function": "minecraft:set_name",
          "name": {
            "text": "Sawed-off",
            "italic": false
          }
        }
      ]
    },
    {
      "item": "tacz:sight_uh1",
      "weight": 8
    },
    {
      "item": "tacz:sight_552",
      "weight": 8
    },
    {
      "item": "tacz:muzzle_silencer_phantom_s1",
      "weight": 4
    },
    {
      "item": "tacz:muzzle_compensator_trident",
      "weight": 4
    },
    {
      "item": "tacz:ammo_9mm",
      "weight": 12
    },
    {
      "item": "tacz:ammo_12g",
      "weight": 10
    },
    {
      "item": "tacz:ammo_45acp",
      "weight": 4
    }
  ]
}

b. add_tacz_lostcitychest.json

  "type": "forge:add_items",
  "conditions": [
    {
      "condition": "forge:loot_table_id",
      "loot_table_id": "lostcities:chests/lostcitychest"
    }
  ],
  "items": [
    {
      "item": "tacz:modern_kinetic_gun",
      "weight": 4,
      "functions": [
        {
          "function": "minecraft:set_nbt",
          "tag": "{GunId:\\\"tacz:ak47\\\",GunCurrentAmmoCount:0}"
        },
        {
          "function": "minecraft:set_name",
          "name": {
            "text": "AK-47 (abandoned)",
            "italic": false
          }
        }
      ]
    },
    {
      "item": "tacz:modern_kinetic_gun",
      "weight": 6,
      "functions": [
        {
          "function": "minecraft:set_nbt",
          "tag": "{GunId:\\\"tacz:db_short\\\",GunCurrentAmmoCount:2}"
        },
        {
          "function": "minecraft:set_name",
          "name": {
            "text": "Sawed-off",
            "italic": false
          }
        }
      ]
    },
    {
      "item": "tacz:sight_rmr_dot",
      "weight": 4
    },
    {
      "item": "tacz:light_extended_mag_3",
      "weight": 1
    },
    {
      "item": "tacz:ammo_9mm",
      "weight": 12
    },
    {
      "item": "tacz:ammo_45acp",
      "weight": 4
    },
    {
      "item": "tacz:ammo_12g",
      "weight": 8
    }
  ]
}

c. add_tacz_raildungeon.json

  "type": "forge:add_items",
  "conditions": [
    {
      "condition": "forge:loot_table_id",
      "loot_table_id": "lostcities:chests/raildungeonchest"
    }
  ],
  "items": [
    {
      "item": "tacz:modern_kinetic_gun",
      "weight": 6,
      "functions": [
        {
          "function": "minecraft:set_nbt",
          "tag": "{GunId:\\\"tacz:ak47\\\",GunCurrentAmmoCount:0}"
        },
        {
          "function": "minecraft:set_name",
          "name": {
            "text": "AK-47 (abandoned)",
            "italic": false
          }
        }
      ]
    },
    {
      "item": "tacz:modern_kinetic_gun",
      "weight": 3,
      "functions": [
        {
          "function": "minecraft:set_nbt",
          "tag": "{GunId:\\\"tacz:sks_tactical\\\",GunCurrentAmmoCount:0}"
        },
        {
          "function": "minecraft:set_name",
          "name": {
            "text": "SKS (rifle)",
            "italic": false
          }
        }
      ]
    },
    {
      "item": "tacz:modern_kinetic_gun",
      "weight": 3,
      "functions": [
        {
          "function": "minecraft:set_nbt",
          "tag": "{GunId:\\\"tacz:type_81\\\",GunCurrentAmmoCount:0}"
        },
        {
          "function": "minecraft:set_name",
          "name": {
            "text": "Type 81",
            "italic": false
          }
        }
      ]
    },
    {
      "item": "tacz:modern_kinetic_gun",
      "weight": 1,
      "functions": [
        {
          "function": "minecraft:set_nbt",
          "tag": "{GunId:\\\"tacz:aa12\\\",GunCurrentAmmoCount:0}"
        },
        {
          "function": "minecraft:set_name",
          "name": {
            "text": "AA-12 (very rare)",
            "italic": false
          }
        }
      ]
    },
    {
      "item": "tacz:modern_kinetic_gun",
      "weight": 1,
      "functions": [
        {
          "function": "minecraft:set_nbt",
          "tag": "{GunId:\\\"tacz:m320\\\",GunCurrentAmmoCount:0}"
        },
        {
          "function": "minecraft:set_name",
          "name": {
            "text": "M320 (very rare)",
            "italic": false
          }
        }
      ]
    },
    {
      "item": "tacz:scope_acog_ta31",
      "weight": 4
    },
    {
      "item": "tacz:scope_vudu",
      "weight": 3
    },
    {
      "item": "tacz:scope_mk5hd",
      "weight": 1
    },
    {
      "item": "tacz:muzzle_brake_cyclone_d2",
      "weight": 4
    },
    {
      "item": "tacz:sight_deltapoint_pistol",
      "weight": 4
    },
    {
      "item": "tacz:ammo_556x45",
      "weight": 10
    },
    {
      "item": "tacz:ammo_762x39",
      "weight": 10
    },
    {
      "item": "tacz:ammo_30_06",
      "weight": 4
    },
    {
      "item": "tacz:ammo_45_70",
      "weight": 2
    }
  ]
}
  1. loot_integration.json (file for kubejs/lootjs)
// Defensive LootJS injector — tries multiple API names and catches all errors.
// Replace your existing file with this. It will not throw TypeError on missing methods.

(function() {
  function log() {
    try { console.log("[KubeJS-LOOTFIX]", Array.prototype.join.call(arguments, " ")); } catch (e) {}
  }

  // Items to inject (same lists you used)
  const taczItemsApartment = [
    { item: "tacz:sight_uh1", weight: 8 },
    { item: "tacz:sight_552", weight: 8 },
    { item: "tacz:muzzle_silencer_phantom_s1", weight: 4 },
    { item: "tacz:muzzle_compensator_trident", weight: 4 },
    { item: "tacz:ammo", weight: 12, nbt: '{AmmoId:"tacz:9mm"}' },
    { item: "tacz:ammo", weight: 10, nbt: '{AmmoId:"tacz:12g"}' },
    { item: "tacz:ammo", weight: 4, nbt: '{AmmoId:"tacz:45acp"}' },
    { item: "tacz:modern_kinetic_gun", weight: 8, nbt: '{GunId:"tacz:glock_17",GunCurrentAmmoCount:7}' },
    { item: "tacz:modern_kinetic_gun", weight: 6, nbt: '{GunId:"tacz:uzi",GunCurrentAmmoCount:25}' },
    { item: "tacz:modern_kinetic_gun", weight: 6, nbt: '{GunId:"tacz:db_short",GunCurrentAmmoCount:2}' }
  ];

  const taczItemsRailDungeon = [
    { item: "tacz:scope_acog_ta31", weight: 4 },
    { item: "tacz:scope_vudu", weight: 3 },
    { item: "tacz:scope_mk5hd", weight: 1 },
    { item: "tacz:muzzle_brake_cyclone_d2", weight: 4 },
    { item: "tacz:sight_deltapoint_pistol", weight: 4 },
    { item: "tacz:ammo", weight: 10, nbt: '{AmmoId:"tacz:556x45"}' },
    { item: "tacz:ammo", weight: 10, nbt: '{AmmoId:"tacz:762x39"}' },
    { item: "tacz:ammo", weight: 4, nbt: '{AmmoId:"tacz:30_06"}' },
    { item: "tacz:ammo", weight: 2, nbt: '{AmmoId:"tacz:45_70"}' },
    { item: "tacz:modern_kinetic_gun", weight: 6, nbt: '{GunId:"tacz:ak47",GunCurrentAmmoCount:0}' },
    { item: "tacz:modern_kinetic_gun", weight: 3, nbt: '{GunId:"tacz:sks_tactical",GunCurrentAmmoCount:0}' },
    { item: "tacz:modern_kinetic_gun", weight: 3, nbt: '{GunId:"tacz:type_81",GunCurrentAmmoCount:0}' },
    { item: "tacz:modern_kinetic_gun", weight: 1, nbt: '{GunId:"tacz:aa12",GunCurrentAmmoCount:0}' },
    { item: "tacz:modern_kinetic_gun", weight: 1, nbt: '{GunId:"tacz:m320",GunCurrentAmmoCount:0}' }
  ];

  const taczItemsLostCity = [
    { item: "tacz:sight_rmr_dot", weight: 4 },
    { item: "tacz:light_extended_mag_3", weight: 1 },
    { item: "tacz:ammo", weight: 12, nbt: '{AmmoId:"tacz:9mm"}' },
    { item: "tacz:ammo", weight: 4, nbt: '{AmmoId:"tacz:45acp"}' },
    { item: "tacz:ammo", weight: 8, nbt: '{AmmoId:"tacz:12g"}' },
    { item: "tacz:modern_kinetic_gun", weight: 4, nbt: '{GunId:"tacz:ak47",GunCurrentAmmoCount:0}' },
    { item: "tacz:modern_kinetic_gun", weight: 6, nbt: '{GunId:"tacz:db_short",GunCurrentAmmoCount:2}' }
  ];

  // low-level helper: safely try to call a method on event
  function tryCall(event, methodName, argsArray) {
    try {
      const fn = event[methodName];
      if (typeof fn === "function") {
        return fn.apply(event, argsArray);
      }
      // If fn is not a JS function, still attempt to call (some Java proxies allow direct call)
      if (fn !== undefined) {
        try { return fn(argsArray); } catch (e) { /* ignore */ }
      }
    } catch (e) {
      // swallow errors so script doesn't crash
    }
    return null;
  }

  // helper: add items using a table/context object
  function populateTableLikeObject(tblOrCtx, items) {
    try {
      // preferred API: tblOrCtx.addPool(pool => { pool.addItem(...).withNBT(...) })
      if (typeof tblOrCtx.addPool === "function") {
        tblOrCtx.addPool(function(pool) {
          // if pool.rolls exists, set single roll
          try { if (typeof pool.rolls === "function") pool.rolls([1,1]); } catch(e){}

          items.forEach(function(entry) {
            try {
              if (entry.nbt && typeof pool.addItem === "function") {
                // chain withNBT if available
                const e = pool.addItem(entry.item, entry.weight || 1);
                // some APIs return a wrapper with withNBT, others not - guard it
                try { if (typeof e.withNBT === "function") e.withNBT(entry.nbt); } catch(e){}
              } else if (typeof pool.addItem === "function") {
                pool.addItem(entry.item, entry.weight || 1);
              } else if (typeof pool.add === "function") {
                // older variant: pool.add({ item:..., weight:... })
                pool.add({ item: entry.item, weight: entry.weight || 1, nbt: entry.nbt || null });
              }
            } catch (errEntry) {
              // skip problematic entry
            }
          });
        });
        return true;
      }

      // fallback: if ctx/table has add or addItem methods
      if (typeof tblOrCtx.add === "function") {
        try { tblOrCtx.add(items); return true; } catch(e) {}
      }
      if (typeof tblOrCtx.addItem === "function") {
        items.forEach(function(entry) {
          try {
            const e = tblOrCtx.addItem(entry.item, entry.weight || 1);
            try { if (entry.nbt && typeof e.withNBT === "function") e.withNBT(entry.nbt); } catch(e){}
          } catch(e){}
        });
        return true;
      }
    } catch (e) {
      // swallow
    }
    return false;
  }

  // Tries a bunch of method names in defensive order. Returns true on first success.
  function tryModifyTable(event, tableId, items) {
    // candidate API names to try, in order
    const candidates = [
      "modifyLootTable",
      "modify_table",
      "modifyTable",
      "modify",
      "modify_loot_table"
    ];

    for (let i = 0; i < candidates.length; i++) {
      const name = candidates[i];
      try {
        // Attempt to call event[name](tableId, callback)
        const res = tryCall(event, name, [tableId, function(tblOrCtx) {
          const ok = populateTableLikeObject(tblOrCtx, items);
          if (!ok) {
            // As a fallback, try to call tblOrCtx.add(items)
            try { if (typeof tblOrCtx.add === "function") tblOrCtx.add(items); } catch(e) {}
          }
        }]);
        if (res !== null) {
          log("Used API:", name, "for table:", tableId);
          return true;
        }
      } catch (err) {
        // continue trying next candidate
      }
    }

    // Final fallback: maybe event has an 'add' that accepts an object like { id, items }
    try {
      if (typeof event.add === "function") {
        try { event.add({ id: tableId, items: items }); log("Used event.add fallback for", tableId); return true; } catch(e){}
      }
    } catch (e) {}

    // As last resort, log event keys for debugging
    try {
      const keys = Object.keys(event).join(", ");
      log("No supported modify API found for table", tableId, " — event keys:", keys);
    } catch (e) {
      log("No supported modify API found and couldn't list event keys.");
    }

    return false;
  }

  // Main entry: call inside LootJS.modifiers
  LootJS.modifiers(function(event) {
    try {
      let did1 = tryModifyTable(event, "minecraft:chests/apartament", taczItemsApartment);
      let did2 = tryModifyTable(event, "lostcities:chests/raildungeonchest", taczItemsRailDungeon);
      let did3 = tryModifyTable(event, "lostcities:chests/lostcitychest", taczItemsLostCity);

      log("Injection results — apartament:", !!did1, "raildungeon:", !!did2, "lostcity:", !!did3);
    } catch (e) {
      log("Unexpected error inside LootJS.modifiers block:", String(e));
    }
  });

})();

I don't know if this is the place to ask this, I have asked this same question in reddit but no one replied, maybe due to this issue being too technical. Please help me with this.