Files
2026-07-31 10:34:32 +09:00

1382 lines
41 KiB
JavaScript

/* eslint-disable no-unused-vars */
// Priority: 1000
const artMachineTickRate = 200;
const artMachineProgTime = 20;
const booleanProperty = Java.loadClass(
"net.minecraft.world.level.block.state.properties.BooleanProperty"
);
const integerProperty = Java.loadClass(
"net.minecraft.world.level.block.state.properties.IntegerProperty"
);
const directionProperty = Java.loadClass(
"net.minecraft.world.level.block.state.properties.DirectionProperty"
);
const CropGrowthUtils = Java.loadClass(
"cool.bot.dewdropfarmland.utils.CropHandlerUtils"
);
function rnd(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
function rnd50() {
return Math.random() < 0.5;
}
function rnd75() {
return Math.random() < 0.75;
}
function rnd25() {
return Math.random() < 0.25;
}
function rnd10() {
return Math.random() < 0.1;
}
function rnd5() {
return Math.random() < 0.05;
}
global.surviveCheck = (level, pos) => {
const FARMLAND = Java.loadClass("net.minecraft.world.level.block.FarmBlock");
let blockState = level.getBlockState(pos.below());
let mcBlock = blockState.block;
if (mcBlock instanceof FARMLAND) {
return true;
} else return false;
};
let increaseDataStage = (block, count) => {
let nbt = block.getEntityData();
let currentStage = nbt.data.stage;
currentStage += count || 1;
nbt.merge({ data: { stage: currentStage } });
global.setBlockEntityData(block, nbt)
};
let increaseStage = (input, count) => {
let num = Number(input);
num += count || 1;
return num;
};
let decreaseStage = (input) => {
let num = Number(input);
num -= 1;
return num;
};
const successParticles = (level, block) => {
const { x, y, z } = block;
level.spawnParticles(
"minecraft:happy_villager",
true,
x + 0.5,
y + 0.5,
z + 0.5,
0.1 * rnd(1, 4),
0.1 * rnd(1, 4),
0.1 * rnd(1, 4),
10,
0.1
);
};
const itemHasTag = (item, tag) => {
const tagString = tag.startsWith("#") ? tag.substring(1) : tag;
return item.hasTag(tagString);
};
const setQuality = (nbt, stage, itemQuality) => {
if (
(Number(nbt.data.quality) === 0 && Number(stage) === 0) ||
Number(itemQuality) < Number(nbt.data.quality)
)
nbt.merge({ data: { quality: Number(itemQuality) } });
};
const getCanTakeItems = (
item,
recipe,
properties,
hasTag,
inputCount,
recipes,
nbt
) => {
if (properties.get("working") == "true" || properties.get("mature") == "true") return false;
let itemCheck = recipe !== undefined;
if (hasTag) {
Array.from(recipes.keys()).forEach((key) => {
if (key.startsWith("#")) {
if (itemHasTag(item, key)) {
if (nbt.data.recipe.equals("") || nbt.data.recipe == undefined) {
nbt.merge({ data: { recipe: key, originalInputs: [] } });
itemCheck = true;
}
if (inputCount != -1 && nbt.data.recipe.equals(key)) {
let inputArray = nbt.data.originalInputs.copy();
let usedItem = item.copy();
usedItem.count = inputCount;
inputArray.push(usedItem);
nbt.merge({ data: { originalInputs: inputArray } });
itemCheck = true;
}
}
}
});
}
return itemCheck
};
global.convertFromLegacy = (recipes, level, block) => {
let nbt = block.getEntityData();
let newRecipe;
if (block.id.equals("society:tapper") && !nbt.data.contains("recipe")) {
let newProperties = level.getBlock(block.pos).getProperties();
newProperties.working = false;
newProperties.mature = false;
nbt.merge({ data: { stage: 0, recipe: "" } });
global.setBlockEntityData(block, nbt)
block.set(block.id, newProperties);
return;
}
if (nbt.data.contains("recipe") || !nbt.data.contains("type")) return;
if (nbt.data.type > 0) {
newRecipe = Array.from(recipes.keys())[Number(nbt.data.type) - 1];
}
if (['society:cheese_press', 'society:mayonnaise_machine', 'society:fish_smoker', 'society:seed_maker'].includes(block.id)) {
nbt.merge({ data: { quality: 0 } });
global.setBlockEntityData(block, nbt)
}
if (newRecipe) {
let newProperties = level.getBlock(block.pos).getProperties();
newProperties.working = false;
newProperties.mature = true;
nbt.merge({ data: { recipe: newRecipe } });
global.setBlockEntityData(block, nbt)
block.set(block.id, newProperties);
}
};
global.artisanHarvest = (
block,
recipes,
stageCount,
outputMult,
isCheesePress,
artisanHopper,
server,
player
) => {
let newProperties = block.getProperties();
if (block.properties.get("mature").toLowerCase() === "true") {
let harvestOutput;
let hopperOutputs = [];
if (!artisanHopper) {
global.giveExperience(server, player, "farming", stageCount * 20);
server.runCommandSilent(
`playsound stardew_fishing:dwop block @a ${player.x} ${player.y} ${player.z}`
);
}
let nbt = block.getEntityData();
let hasQuality = nbt.data.quality !== undefined && Number(nbt.data.quality) > 0;
recipes.get(nbt.data.recipe).output.forEach((id) => {
harvestOutput = Item.of(
id,
hasQuality ? `{quality_food:{quality:${Number(nbt.data.quality)}}}` : null
);
// Artisan Cheese Press upgrade: auto age cheese wheels only
if (
isCheesePress &&
(id.includes("wheel") || id.includes("block")) &&
block.properties.get("upgraded").toLowerCase() === "true"
) {
harvestOutput = Item.of(`society:aged_${id.path}`);
}
if (outputMult > 1 && !recipes.get(nbt.data.recipe).multExempt) {
harvestOutput.count = harvestOutput.count * outputMult;
}
if (!artisanHopper) {
block.popItemFromFace(harvestOutput, block.properties.get("facing"));
} else {
hopperOutputs.push(harvestOutput);
}
nbt.merge({ data: { stage: 0, recipe: "", originalInputs: [] } });
if (nbt.data.quality) {
nbt.merge({ data: { stage: 0, recipe: "", quality: 0 } });
}
global.setBlockEntityData(block, nbt)
newProperties.working = false;
newProperties.mature = false;
if (newProperties.duration) newProperties.duration = "0";
block.set(block.id, newProperties);
});
if (artisanHopper) return hopperOutputs;
}
};
// Converted
global.artisanInsert = (
block,
item,
level,
recipes,
stageCount,
stockSound,
multipleInputs,
hasTag,
artisanHopper,
server,
player
) => {
let newProperties = block.getProperties();
let nbt = block.getEntityData();
let stage = nbt.data.stage;
const itemNbt = item.nbt;
let itemQuality;
let hasQuality = nbt.data.quality !== undefined || ['society:cheese_press', 'society:mayonnaise_machine', 'society:fish_smoker', 'society:seed_maker'].includes(block.id);
let useCount =
multipleInputs && item.count >= stageCount - Number(stage)
? stageCount - Number(stage)
: 1;
const recipe = recipes.get(`${item.id}`);
if (
multipleInputs &&
recipe &&
nbt.data.recipe !== "" &&
nbt.data.recipe !== item.id
)
return;
if (
getCanTakeItems(
item,
recipe,
block.properties,
hasTag,
multipleInputs ? useCount : -1,
recipes,
nbt
)
) {
newProperties = block.getProperties();
successParticles(level, block);
server.runCommandSilent(
`playsound ${stockSound} block @a ${block.x} ${block.y} ${block.z}`
);
if (!(hasTag && recipe === undefined))
nbt.merge({ data: { recipe: item.id } });
newProperties.working = false;
newProperties.mature = false;
if (hasQuality && itemNbt && itemNbt.quality_food) {
itemQuality = String(itemNbt.quality_food.quality);
} else if (hasQuality) {
itemQuality = "0";
}
if (multipleInputs) {
if (item.count >= stageCount - Number(stage)) {
nbt.merge({ data: { stage: stageCount } });
} else {
increaseDataStage(block);
}
if (itemQuality) setQuality(nbt, stage, itemQuality);
} else if (itemQuality) {
nbt.merge({ data: { quality: Number(itemQuality) } });
}
if (!multipleInputs || nbt.data.stage === stageCount) {
newProperties.working = true;
nbt.merge({ data: { stage: 0 } });
}
global.setBlockEntityData(block, nbt)
block.set(block.id, newProperties);
if (player && !player.isCreative()) item.count -= useCount;
if (artisanHopper) return useCount;
}
};
global.handleBERightClick = (
stockSound,
clickEvent,
recipes,
stageCount,
multipleInputs,
hasTag,
outputMult,
disableInput,
isCheesePress
) => {
const { item, block, hand, player, level, server } = clickEvent;
// Prevent Deployers from using artisan machines
if (player.isFake()) return;
if (hand == "OFF_HAND") return;
if (hand == "MAIN_HAND") {
global.convertFromLegacy(recipes, level, block);
global.artisanHarvest(
block,
recipes,
stageCount,
outputMult,
isCheesePress,
false,
server,
player
);
if (!disableInput) {
global.artisanInsert(
block,
item,
level,
recipes,
stageCount,
stockSound,
multipleInputs,
hasTag,
false,
server,
player
);
}
}
};
global.setDebt = (server, UUID, amount) => {
for (let index = 0; index < server.persistentData.debts.length; index++) {
if (String(UUID) === String(server.persistentData.debts[index].uuid)) {
server.persistentData.debts[index].amount = amount;
break;
}
}
};
global.getOpposite = (facing, pos) => {
switch (facing) {
case "north":
return pos.offset(0, 0, 1);
case "south":
return pos.offset(0, 0, -1);
case "west":
return pos.offset(1, 0, 0);
case "east":
return pos.offset(-1, 0, 0);
}
};
global.getFacing = (facing, pos) => {
switch (facing) {
case "north":
return pos.offset(0, 0, -1);
case "south":
return pos.offset(0, 0, 1);
case "west":
return pos.offset(-1, 0, 0);
case "east":
return pos.offset(1, 0, 0);
}
};
global.getTapperLog = (level, block) =>
level.getBlock(
global.getOpposite(block.properties.get("facing"), block.getPos())
);
global.getFermentingBarrel = (level, block) =>
level.getBlock(
global.getFacing(block.getProperties().get("facing"), block.getPos())
);
global.handleTapperRandomTick = (tickEvent, returnFluidData) => {
const { block, level, server } = tickEvent;
let newProperties = block.getProperties();
let nbt = block.getEntityData();
const attachedBlock = global.getTapperLog(level, block);
let foundFluidData = undefined;
let hasError = false;
if (attachedBlock.hasTag("society:tappable_blocks")) {
if (
!nbt.data.recipe ||
!nbt.data.recipe.equals(attachedBlock.id) ||
global.hasMultipleTappers(level, block)
) {
hasError = true;
}
if (
returnFluidData ||
(block.properties.get("working").toLowerCase() === "false" &&
block.properties.get("mature").toLowerCase() === "false")
) {
if (global.tapperRecipes) {
const recipe = global.tapperRecipes.get(`${attachedBlock.getId()}`);
let nbt = block.getEntityData();
if (returnFluidData && !foundFluidData && recipe) {
foundFluidData = { fluid: recipe.fluidOutput, time: recipe.time };
nbt.merge({ data: { recipe: `${attachedBlock.getId()}` } });
hasError = false;
}
if (
!returnFluidData &&
getCanTakeItems(
attachedBlock.getId(),
recipe,
block.properties,
false
)
) {
newProperties = block.getProperties();
successParticles(level, block);
server.runCommandSilent(
`playsound vinery:cabinet_close block @a ${block.x} ${block.y} ${block.z}`
);
newProperties.mature = false;
newProperties.working = true;
nbt.merge({ data: { recipe: `${attachedBlock.getId()}`, stage: 0 } });
hasError = false;
}
global.setBlockEntityData(block, nbt)
}
}
if (returnFluidData) {
if (hasError) newProperties.error = true;
else newProperties.error = false;
block.set(block.id, newProperties);
return foundFluidData;
}
if (hasError) newProperties.error = true;
else newProperties.error = false;
block.set(block.id, newProperties);
} else {
newProperties.error = true;
block.set(block.id, newProperties);
if (returnFluidData) return undefined;
}
};
const getMushroomLogData = (level, centerPos, radius) => {
const { x, y, z } = centerPos;
let scanBlock;
let scannedBlocks = 0;
let regularOutputs = [];
let dominantOutputs = [];
let airBlocks = 0;
for (let pos of BlockPos.betweenClosed(
new BlockPos(x - radius, y - radius, z - radius),
[x + radius, y + radius, z + radius]
)) {
if (!level.isLoaded(pos)) continue;
scanBlock = level.getBlock(pos);
if (scanBlock.hasTag("society:mushroom_log_detects")) {
scannedBlocks++;
if (scanBlock.hasTag("society:mushroom_log_dominant")) {
if (!dominantOutputs.includes(scanBlock.id))
dominantOutputs.push(scanBlock.id);
} else {
if (!regularOutputs.includes(scanBlock.id))
regularOutputs.push(scanBlock.id);
}
} else if (scanBlock.id === "minecraft:air") airBlocks++;
}
return {
count: airBlocks < 100 ? 4 : scannedBlocks,
possibleOutputs:
dominantOutputs.length > 0 ? dominantOutputs : regularOutputs,
};
};
global.handleMushroomLogRandomTick = (tickEvent) => {
const { block, level, server } = tickEvent;
let newProperties = block.getProperties();
if (
block.properties.get("working").toLowerCase() === "false" &&
block.properties.get("mature").toLowerCase() === "false"
) {
const leafCount = global.getTaggedBlocksInRadius(
level,
"society:mushroom_log_leaves",
new BlockPos(block.x, block.y + 4, block.z),
8
);
const logData = getMushroomLogData(level, block.pos, 8);
if (!logData || logData.count == 0 || logData.possibleOutputs.length == 0)
return;
let baseCount = Math.max(
1,
Math.floor(Math.min(8, logData.count / 4) + Math.min(8, leafCount / 4))
);
if (global.mushroomLogRecipes) {
let rolledRecipe =
logData.possibleOutputs[
Math.floor(Math.random() * logData.possibleOutputs.length)
];
const recipe = global.mushroomLogRecipes.get(`${rolledRecipe}`);
let nbt = block.getEntityData();
if (getCanTakeItems(rolledRecipe, recipe, block.properties, false)) {
newProperties = block.getProperties();
successParticles(level, block);
server.runCommandSilent(
`playsound species:block.alphacene_foliage.place block @a ${block.x} ${block.y} ${block.z}`
);
newProperties.mature = false;
newProperties.working = true;
let quality = 0;
if (logData.count > 20 && logData.count / 40 > Math.random()) quality = 1;
if (logData.count > 40 && logData.count / 60 > Math.random()) quality = 2;
if (logData.count > 60 && logData.count / 80 > Math.random()) quality = 3;
nbt.merge({
data: { recipe: `${rolledRecipe}`, stage: 0, baseCount: baseCount, quality: quality },
});
}
global.setBlockEntityData(block, nbt)
block.set(block.id, newProperties);
}
}
};
global.hasMultipleTappers = (level, block) => {
const attachedBlock = global.getTapperLog(level, block);
const offsetsToCheck = [
[1, 0],
[0, 1],
[-1, 0],
[0, -1],
];
let tapperCount = 0;
offsetsToCheck.forEach((offset) => {
if (
["society:tapper", "society:auto_tapper"].includes(
level.getBlock(
new BlockPos(
attachedBlock.x + offset[0],
attachedBlock.y,
attachedBlock.z + offset[1]
)
).id
)
)
tapperCount++;
});
return tapperCount > 1;
};
global.handleBERandomTick = (tickEvent, rndFunction, stageCount) => {
const { block } = tickEvent;
const { x, y, z } = block;
const stage = block.getEntityData().data.stage;
const mature = stage >= stageCount - 1;
let newProperties = block.getProperties();
if (block.properties.get("working").toLowerCase() === "true" && rndFunction) {
tickEvent.level.spawnParticles(
"minecraft:campfire_cosy_smoke",
true,
x + 0.5,
y + 1,
z + 0.5,
0.1 * rnd(1, 2),
0.1 * rnd(1, 2),
0.1 * rnd(1, 2),
rnd(1, 4),
0.1
);
newProperties.working = !mature;
newProperties.mature = mature;
increaseDataStage(block);
block.set(block.id, newProperties);
}
};
global.handleBETick = (entity, recipes, stageCount, halveTime, forced) => {
const { level, block } = entity;
let dayTime = level.dayTime();
let morningModulo = dayTime % 24000;
if (
forced ||
(morningModulo >= artMachineProgTime &&
morningModulo < artMachineProgTime + artMachineTickRate)
) {
let blockProperties = level.getBlock(block.pos).getProperties();
if (blockProperties.get("working").toLowerCase() === "false") return;
global.convertFromLegacy(recipes, level, block);
let nbt = block.getEntityData();
let mature;
let recipe = recipes && recipes.get(nbt.data.recipe);
let resolvedStage = (recipe && recipe.time) || stageCount;
const nbtStage = nbt.data.stage;
if (halveTime && blockProperties.get("upgraded").toLowerCase() == "true") {
mature = Number(nbtStage) >= resolvedStage / 2 - 1;
} else {
mature = Number(nbtStage) >= resolvedStage - 1;
}
let newProperties = level.getBlock(block.pos).getProperties();
newProperties.mature = mature;
if (mature) newProperties.working = false;
increaseDataStage(block);
block.set(block.id, newProperties);
}
};
global.isSameQuality = (itemA, itemB) => {
if (!itemA.nbt && !itemB.nbt) return true;
if ((itemA.nbt && !itemB.nbt) || (!itemA.nbt && itemB.nbt)) return false;
if (!itemA.nbt.quality_food && !itemB.nbt.quality_food) return false;
return itemA.nbt.quality_food.quality === itemB.nbt.quality_food.quality;
};
global.inventoryHasRoom = (block, item) => {
let belowItem;
if (block.inventory && item && item !== Item.of("minecraft:air")) {
for (let j = 0; j < block.inventory.slots; j++) {
belowItem = block.inventory.getStackInSlot(j);
if (
belowItem.id === Item.of(item).id &&
global.isSameQuality(belowItem, Item.of(item)) &&
belowItem.count + Item.of(item).count <
block.inventory.getSlotLimit(j) /
(64 / block.inventory.getStackInSlot(j).maxStackSize)
) {
return true;
}
}
for (let j = 0; j < block.inventory.slots; j++) {
belowItem = block.inventory.getStackInSlot(j);
if (belowItem === Item.of("minecraft:air")) {
return true;
}
}
}
return false;
};
global.inventoryBelowHasRoom = (level, block, item) => {
const belowPos = block.getPos().below();
const belowBlock = level.getBlock(belowPos.x, belowPos.y, belowPos.z);
return global.inventoryHasRoom(belowBlock, item);
};
global.inventoryBelowHasRoomForAll = (level, block, items) => {
const belowPos = block.getPos().below();
const belowBlock = level.getBlock(belowPos.x, belowPos.y, belowPos.z);
let hasRoom = true;
items.forEach((item) => {
if (!global.inventoryHasRoom(belowBlock, item)) hasRoom = false;
});
return hasRoom;
};
/**
* @returns result code:
* -1 - Failure - Operation attempted but couldn't be inserted
* 0 - Neutral - Operation not attempted due to no below inventory or item
* 1 - Success - Item successfully inserted
*/
global.insertInto = (block, item) => {
let belowItem;
if (block.inventory && item && item !== Item.of("minecraft:air")) {
for (let j = 0; j < block.inventory.slots; j++) {
belowItem = block.inventory.getStackInSlot(j);
if (
belowItem.id === Item.of(item).id &&
global.isSameQuality(belowItem, Item.of(item)) &&
belowItem.count + Item.of(item).count <
block.inventory.getSlotLimit(j) /
(64 / block.inventory.getStackInSlot(j).maxStackSize)
) {
block.inventory.insertItem(j, item, false);
return 1;
}
}
for (let j = 0; j < block.inventory.slots; j++) {
belowItem = block.inventory.getStackInSlot(j);
if (belowItem === Item.of("minecraft:air")) {
block.inventory.insertItem(j, item, false);
return 1;
}
}
return -1;
}
return 0;
};
global.insertBelow = (level, block, item) => {
const belowPos = block.getPos().below();
const belowBlock = level.getBlock(belowPos.x, belowPos.y, belowPos.z);
return global.insertInto(belowBlock, item);
};
/**
* @returns result code:
* -1 - Failure - Operation attempted but not enough items
* 0 - Neutral - Operation not attempted due to no inventory
* 1 - Success - inventory has items of id, and of at least count
*/
global.inventoryHasItems = (inventory, id, count) => {
if (inventory) {
const slots = inventory.getSlots();
let slotStack;
for (let i = 0; i < slots; i++) {
slotStack = inventory.getStackInSlot(i);
if (slotStack.item.id === id && slotStack.count >= count) {
return 1;
}
}
return -1;
}
return 0;
};
global.hasInventoryItems = (inventory, id, count) => {
if (inventory) {
const slots = inventory.getSlots();
let slotStack;
let foundCount = 0;
for (let i = 0; i < slots; i++) {
slotStack = inventory.getStackInSlot(i);
if (slotStack.item.id === id) {
foundCount += slotStack.count;
}
if (foundCount >= count) return true;
}
}
return false;
};
/**
* @returns result code:
* -1 - Failure - Operation attempted but nothing to use
* 0 - Neutral - Operation not attempted due to no inventory
* 1 - Success - Item successfully consumed
*/
global.useInventoryItems = (inventory, id, count) => {
if (inventory) {
const slots = inventory.getSlots();
let slotStack;
for (let i = 0; i < slots; i++) {
slotStack = inventory.getStackInSlot(i);
if (slotStack.item.id === id && slotStack.count >= count) {
inventory.extractItem(i, count, false);
return 1;
}
}
return -1;
}
return 0;
};
global.inventoryUseItems = (inventory, id, count) => {
if (!inventory) return 0;
const slots = inventory.getSlots();
let remaining = count;
let total = 0;
for (let i = 0; i < slots; i++) {
let stack = inventory.getStackInSlot(i);
if (stack.item.id === id) total += stack.count;
}
if (total < count) return -1;
for (let i = 0; i < slots; i++) {
if (remaining <= 0) break;
let stack = inventory.getStackInSlot(i);
if (stack.item.id === id) {
let toExtract = Math.min(stack.count, remaining);
inventory.extractItem(i, toExtract, false);
remaining -= toExtract;
}
}
return 1;
};
/** All fluid handlers expect the following initialData with a capacity of 10000
*
* blockInfo.initialData({ Fluid: 0, FluidType: "" });
*/
global.getFluid = (blockInfo) => {
if (!blockInfo || !blockInfo.persistentData) {
return Fluid.of("minecraft:water", 0);
}
const foundFluid = blockInfo.persistentData.getString("FluidType");
if (!foundFluid) return Fluid.of("minecraft:water", 0);
if (foundFluid === "minecraft:empty") {
return Fluid.of("minecraft:water", 0);
}
let foundFluidLevel = blockInfo.persistentData.getInt("Fluid");
if (!foundFluidLevel) foundFluidLevel = 0;
return Fluid.of(foundFluid, foundFluidLevel);
};
global.onFill = (blockInfo, fluid, sim) => {
const fluidData = blockInfo.persistentData.getInt("Fluid");
const filled = Math.min(10000 - fluidData, fluid.getAmount());
if (!sim) {
const storedFluidId = blockInfo.persistentData.getString("FluidType");
const incomingFluidId = fluid.getId();
if (storedFluidId === "" || fluidData === 0) {
blockInfo.persistentData.putString("FluidType", incomingFluidId);
blockInfo.persistentData.putInt("Fluid", fluidData + filled);
} else if (storedFluidId === incomingFluidId) {
blockInfo.persistentData.putInt("Fluid", fluidData + filled);
} else {
return (filled = 0);
}
}
return filled;
};
global.onDrain = (blockInfo, fluid, sim) => {
const fluidData = blockInfo.persistentData.getInt("Fluid");
const drained = Math.min(fluidData, fluid.getAmount());
if (!sim) blockInfo.persistentData.putInt("Fluid", fluidData - drained);
return drained;
};
// Text display utils
global.clearOldTextDisplay = (block, level, id) => {
const { x, y, z } = block;
level.getEntitiesWithin(AABB.ofBlock(block).inflate(3))
.filter((entityType) => entityType.type === "minecraft:text_display")
.forEach((entity) => {
entity.getTags().forEach((tag) => {
if (tag === `${id}-${x}-${y}-${z}`) {
entity.kill();
}
});
});
};
global.rotationFromFacing = (facing) => {
switch (facing) {
case "north":
return 180;
case "east":
return 270;
case "south":
return 360;
default:
case "west":
return 90;
}
};
global.spawnTextDisplay = (block, y, id, text) => {
let entity;
const { x, z } = block;
entity = block.createEntity("minecraft:text_display");
let newNbt = entity.getNbt();
newNbt.text = `${text.toJson()}`;
newNbt.background = 0;
newNbt.Rotation = [
NBT.f(global.rotationFromFacing(block.properties.get("facing"))),
NBT.f(0),
];
entity.setNbt(newNbt);
entity.setX(x + 0.5);
entity.setY(y);
entity.setZ(z + 0.5);
entity.addTag(`${id}-${x}-${block.y}-${z}`);
entity.spawn();
};
global.giveExperience = (server, player, category, xp, excludeMastery) => {
if (!player.isFake()) {
server.runCommandSilent(
`puffish_skills experience add ${player.username} society:${category} ${xp}`
);
if (!excludeMastery && player.stages.has("mastery_unlocked")) {
server.runCommandSilent(
`puffish_skills experience add ${player.username} society:mastery ${xp}`
);
}
}
};
/**
* If you can figure out a way to simplify this in a way that doesn't
* make it more difficult to read you get an artifact in-game.
*/
global.getProcessedItem = (item, dropAmount) => {
let processOutput = global.mayonnaiseMachineRecipes.get(item);
if (processOutput)
return { divisor: 1, item: Item.of(processOutput.output[0]), preserveQuality: true };
// Wine Keg
processOutput = global.wineKegRecipes.get(item);
if (processOutput)
return { divisor: 3, item: Item.of(processOutput.output[0]), preserveQuality: false };
// Oil Maker
processOutput = global.oilMakerRecipes.get(item);
if (processOutput)
return { divisor: 1, item: Item.of(processOutput.output[0]), preserveQuality: false };
// Loom
processOutput = global.loomRecipes.get(item);
if (processOutput && dropAmount >= 5)
return { divisor: 5, item: Item.of(processOutput.output[0]), preserveQuality: false };
// Recycling Machine
processOutput = global.recyclingMachineRecipes.get(item);
if (processOutput)
return { divisor: 1, item: Item.of(processOutput.output[0]), preserveQuality: false };
return { divisor: 1, item: item, preserveQuality: true };
};
const stoneRockTable = [
{ block: "society:stone_boulder", weight: 163 },
{ block: "minecraft:coal_ore", weight: 25 },
{ block: "minecraft:copper_ore", weight: 20 },
{ block: "minecraft:iron_ore", weight: 15 },
{ block: "create:zinc_ore", weight: 13 },
{ block: "minecraft:lapis_ore", weight: 2 },
{ block: "society:geode_node", weight: 2, sturdy: true },
{ block: "society:earth_crystal", weight: 2, sturdy: true },
{ block: "society:oak_supply_crate", weight: 2 },
];
const iceRockTable = [
{ block: "society:ice_boulder", weight: 164 },
{ block: "minecraft:iron_ore", weight: 25 },
{ block: "create:zinc_ore", weight: 15 },
{ block: "oreganized:lead_ore", weight: 10 },
{ block: "minecraft:diamond_ore", weight: 4 },
{ block: "society:earth_crystal", weight: 2, sturdy: true },
{ block: "society:omni_geode_node", weight: 1, sturdy: true },
{ block: "society:sparkstone_ore", weight: 2 },
{ block: "society:spruce_supply_crate", weight: 2 },
];
const sandstoneRockTable = [
{ block: "society:sandstone_boulder", weight: 163 },
{ block: "minecraft:gold_ore", weight: 20 },
{ block: "oreganized:lead_ore", weight: 10 },
{ block: "minecraft:redstone_ore", weight: 6 },
{ block: "minecraft:diamond_ore", weight: 4 },
{ block: "society:sparkstone_ore", weight: 4 },
{ block: "society:fire_quartz", weight: 2, sturdy: true },
{ block: "society:magma_geode_node", weight: 2, sturdy: true },
{ block: "society:omni_geode_node", weight: 2, sturdy: true },
{ block: "society:palm_supply_crate", weight: 2 },
{ block: "oreganized:silver_ore", weight: 2 },
{ block: "society:iridium_ore", weight: 1 },
];
const blackstoneRockTable = [
{ block: "society:blackstone_boulder", weight: 148 },
{ block: "minecraft:deepslate_gold_ore", weight: 20 },
{ block: "oreganized:deepslate_lead_ore", weight: 10 },
{ block: "minecraft:deepslate_redstone_ore", weight: 15 },
{ block: "minecraft:deepslate_diamond_ore", weight: 4 },
{ block: "society:deepslate_sparkstone_ore", weight: 10 },
{ block: "society:fire_quartz", weight: 2, sturdy: true },
{ block: "society:magma_geode_node", weight: 2, sturdy: true },
{ block: "society:omni_geode_node", weight: 4, sturdy: true },
{ block: "oreganized:deepslate_silver_ore", weight: 4 },
{ block: "society:grimwood_supply_crate", weight: 2 },
{ block: "society:deepslate_iridium_ore", weight: 2 },
];
const endstoneRockTable = [
{ block: "society:end_stone_boulder", weight: 194 },
{ block: "society:deepslate_sparkstone_ore", weight: 14 },
{ block: "society:omni_geode_node", weight: 4, sturdy: true },
{ block: "society:deepslate_iridium_ore", weight: 3 },
];
const rollReplaceTable = (table, hasRope) => {
let roll = 0;
const totalWeight = table.reduce(
(acc, current) => (hasRope && current.sturdy ? acc : acc + current.weight),
0
);
let currentWeight = 0;
if (totalWeight > 1) {
roll = rnd(0, totalWeight);
for (let index = 0; index < table.length; index++) {
currentWeight += table[index].weight;
if (currentWeight >= roll) {
return table[index].block;
}
}
}
return "minecraft:obsidian";
};
global.handleSkullCavernRegen = (level, block) => {
if (
!level.persistentData ||
!level.persistentData.chunkParityMap ||
!block.id.equals("society:cavern_air")
)
return;
let belowPos;
let belowBlock;
let belowBelowPos;
let hasRope;
let toggleBit =
level.persistentData.chunkParityMap[
level.getChunkAt(block.getPos()).pos.toString()
].toggleBit;
if (block && block.getProperties() && block.getProperties().get("chunkbit")) {
if (String(toggleBit) != block.getProperties().get("chunkbit")) {
belowPos = block.getPos().below();
belowBlock = level.getBlock(belowPos.x, belowPos.y, belowPos.z);
belowBelowPos = belowBlock.getPos().below();
hasRope =
level.getBlock(belowBelowPos.x, belowBelowPos.y, belowBelowPos.z).id ===
"farmersdelight:rope";
let newBlock;
switch (Number(block.properties.get("type"))) {
case 4:
newBlock = rollReplaceTable(endstoneRockTable, hasRope);
break;
case 3:
newBlock = rollReplaceTable(blackstoneRockTable, hasRope);
break;
case 2:
newBlock = rollReplaceTable(sandstoneRockTable, hasRope);
break;
case 1:
newBlock = rollReplaceTable(iceRockTable, hasRope);
break;
default:
case 0:
newBlock = rollReplaceTable(stoneRockTable, hasRope);
break;
}
block.set(newBlock);
}
}
};
const getCardinalMultipartJsonBasic = (name) => {
const path = `society:block/kubejs/${name}`;
return [
{
when: { facing: "north" },
apply: { model: path, y: 0, uvlock: false },
},
{
when: { facing: "east" },
apply: { model: path, y: 90, uvlock: false },
},
{
when: { facing: "south" },
apply: { model: path, y: 180, uvlock: false },
},
{
when: { facing: "west" },
apply: { model: path, y: -90, uvlock: false },
},
];
};
const getCardinalMultipartJsonBasicUpgradable = (name, upgraded) => {
const path = `society:block/kubejs/${name}`;
return [
{
when: { facing: "north", upgraded: upgraded },
apply: { model: path, y: 0, uvlock: false },
},
{
when: { facing: "east", upgraded: upgraded },
apply: { model: path, y: 90, uvlock: false },
},
{
when: { facing: "south", upgraded: upgraded },
apply: { model: path, y: 180, uvlock: false },
},
{
when: { facing: "west", upgraded: upgraded },
apply: { model: path, y: -90, uvlock: false },
},
];
};
global.cropList = [
"minecraft:wheat",
"minecraft:pumpkin_stem",
"minecraft:melon_stem",
"minecraft:beetroots",
"snowyspirit:ginger",
"supplementaries:flax",
"herbalbrews:coffee_plant",
"herbalbrews:rooibos_plant",
"herbalbrews:tea_plant",
"herbalbrews:yerba_mate_plant",
"minecraft:sweet_berry_bush",
"farm_and_charm:tomato_crop",
"farm_and_charm:strawberry",
"farm_and_charm:lettuce_crop",
"farm_and_charm:barley_crop",
"farm_and_charm:onion_crop",
"farm_and_charm:tomato_crop_body",
"farm_and_charm:corn_crop",
"farm_and_charm:oat_crop",
"brewery:hops_crop",
"brewery:hops_crop_body",
"nethervinery:crimson_grape_bush",
"nethervinery:warped_grape_bush",
"vinery:savanna_grape_bush_white",
"vinery:jungle_grape_bush_red",
"vinery:savanna_grape_bush_red",
"vinery:white_grape_bush",
"vinery:red_grape_bush",
"vinery:taiga_grape_bush_red",
"vinery:taiga_grape_bush_white",
"vinery:jungle_grape_bush_white",
"vinery:jungle_grape_bush_red",
"vintagedelight:ghost_pepper_crop",
"vintagedelight:cucumber_crop",
"farmersdelight:cabbages",
"farmersdelight:budding_tomatoes",
"farmersdelight:tomatoes",
"farmersdelight:rice",
"farmersdelight:rice_panicles",
"society:ancient_fruit",
"society:cranberry",
"society:sparkpod",
"windswept:wild_berry_bush",
"society:mana_fruit",
"etcetera:cotton",
"society:tubabacco_leaf",
"brewery:hop_trellis",
"society:blueberry",
"veggiesdelight:cauliflower_crop",
"veggiesdelight:garlic_crop",
"veggiesdelight:bellpepper_crop",
"society:eggplant",
"society:potato",
"society:carrot",
"society:peanut",
"society:sweet_potato",
"society:onion",
"veggiesdelight:turnip_crop",
"veggiesdelight:zucchini_crop",
"veggiesdelight:broccoli_crop",
];
const qualityToInt = (quality) => {
switch (quality) {
case "DIAMOND":
return 3;
case "GOLD":
return 2;
case "IRON":
return 1;
case "NONE":
default:
return 0;
}
};
const getFertilizer = (crop) => {
let block = crop
.getLevel()
.getBlock(crop.getPos().below());
if (block.hasTag("dew_drop_farmland_growth:bountiful_fertilized_farmland"))
return -1;
if (block.hasTag("dew_drop_farmland_growth:low_quality_fertilized_farmland"))
return 1;
if (block.hasTag("dew_drop_farmland_growth:high_quality_fertilized_farmland"))
return 2;
if (
block.hasTag(
"dew_drop_farmland_growth:pristine_quality_fertilized_farmland"
)
)
return 3;
return 0;
};
const LevelData = Java.loadClass(
"de.cadentem.quality_food.capability.LevelData"
);
global.getCropQuality = (crop) => {
let resolvedCrop = crop
if (crop.id === "farmersdelight:rice_panicles") resolvedCrop = crop.getLevel().getBlock(crop.getPos().below());
const fertilizer = getFertilizer(resolvedCrop);
if (fertilizer == -1) return 0;
const qualityName = LevelData.get(
resolvedCrop.getLevel(),
resolvedCrop.getPos(),
false
);
let seedQuality = qualityToInt(qualityName);
if (fertilizer > 1 && seedQuality < 1) seedQuality = 1;
const goldChance =
0.2 * ((seedQuality * 4.6) / 10) +
0.2 * fertilizer * ((seedQuality * 4.6 + 2) / 12) +
0.01;
// // Debug Quality
// console.log(crop)
// console.log("Seed quality " + seedQuality);
// console.log("Fertilizer quality " + fertilizer);
// console.log("Chance for gold: " + goldChance);
if (fertilizer >= 2 && Math.random() < goldChance / 2) return 3;
if (Math.random() < goldChance) return 2;
if (Math.random() < goldChance * 2) return 1;
return 0;
};
const getCardinalMultipartJson = (name, disableExclamation) => {
const path = `society:block/kubejs/${name}/${name}`;
let exclamationJson = [
{
when: { mature: true },
apply: { model: "society:block/kubejs/machine_done" },
},
];
if (disableExclamation) {
exclamationJson = [];
}
let offJson = [
{
when: { working: false, upgraded: false, facing: "north" },
apply: { model: `${path}_off`, y: 0, uvlock: false },
},
{
when: { working: false, upgraded: false, facing: "east" },
apply: { model: `${path}_off`, y: 90, uvlock: false },
},
{
when: { working: false, upgraded: false, facing: "south" },
apply: { model: `${path}_off`, y: 180, uvlock: false },
},
{
when: { working: false, upgraded: false, facing: "west" },
apply: { model: `${path}_off`, y: -90, uvlock: false },
},
{
when: { working: false, upgraded: true, facing: "north" },
apply: { model: `${path}_off_upgraded`, y: 0, uvlock: false },
},
{
when: { working: false, upgraded: true, facing: "east" },
apply: { model: `${path}_off_upgraded`, y: 90, uvlock: false },
},
{
when: { working: false, upgraded: true, facing: "south" },
apply: { model: `${path}_off_upgraded`, y: 180, uvlock: false },
},
{
when: { working: false, upgraded: true, facing: "west" },
apply: { model: `${path}_off_upgraded`, y: -90, uvlock: false },
},
];
let doneJson = [
{
when: { mature: true, upgraded: false, facing: "north" },
apply: { model: `${path}_done`, y: 0, uvlock: false },
},
{
when: { mature: true, upgraded: false, facing: "east" },
apply: { model: `${path}_done`, y: 90, uvlock: false },
},
{
when: { mature: true, upgraded: false, facing: "south" },
apply: { model: `${path}_done`, y: 180, uvlock: false },
},
{
when: { mature: true, upgraded: false, facing: "west" },
apply: { model: `${path}_done`, y: -90, uvlock: false },
},
{
when: { mature: true, upgraded: true, facing: "north" },
apply: { model: `${path}_done_upgraded`, y: 0, uvlock: false },
},
{
when: { mature: true, upgraded: true, facing: "east" },
apply: { model: `${path}_done_upgraded`, y: 90, uvlock: false },
},
{
when: { mature: true, upgraded: true, facing: "south" },
apply: { model: `${path}_done_upgraded`, y: 180, uvlock: false },
},
{
when: { mature: true, upgraded: true, facing: "west" },
apply: { model: `${path}_done_upgraded`, y: -90, uvlock: false },
},
];
return [
{
apply: { model: `society:block/kubejs/${name}/${name}_particle` },
},
{
when: { mature: true },
apply: { model: "society:block/kubejs/machine_done" },
},
{
when: { working: true, upgraded: false, facing: "north" },
apply: { model: path, y: 0, uvlock: false },
},
{
when: { working: true, upgraded: false, facing: "east" },
apply: { model: path, y: 90, uvlock: false },
},
{
when: { working: true, upgraded: false, facing: "south" },
apply: { model: path, y: 180, uvlock: false },
},
{
when: { working: true, upgraded: false, facing: "west" },
apply: { model: path, y: -90, uvlock: false },
},
{
when: { working: true, upgraded: true, facing: "north" },
apply: { model: `${path}_upgraded`, y: 0, uvlock: false },
},
{
when: { working: true, upgraded: true, facing: "east" },
apply: { model: `${path}_upgraded`, y: 90, uvlock: false },
},
{
when: { working: true, upgraded: true, facing: "south" },
apply: { model: `${path}_upgraded`, y: 180, uvlock: false },
},
{
when: { working: true, upgraded: true, facing: "west" },
apply: { model: `${path}_upgraded`, y: -90, uvlock: false },
},
]
.concat(exclamationJson)
.concat(offJson)
.concat(doneJson);
};
global.getTaggedBlocksInRadius = (
level,
scanTag,
centerPos,
radius,
returnTagged
) => {
const { x, y, z } = centerPos;
let scanBlock;
let scannedBlocks = 0;
let taggedBlocks = [];
for (let pos of BlockPos.betweenClosed(
new BlockPos(x - radius, y - radius, z - radius),
[x + radius, y + radius, z + radius]
)) {
if (!level.isLoaded(pos)) continue;
scanBlock = level.getBlock(pos);
if (scanBlock.hasTag(scanTag)) {
scannedBlocks++;
if (returnTagged) taggedBlocks.push(scanBlock.id);
}
}
if (returnTagged) return taggedBlocks;
return scannedBlocks;
};
global.setBlockEntityData = (block, nbt) => {
block.setEntityData(nbt);
block.getEntity().setChanged();
};