Clean repo for open source release

Remove build artifacts, dev tool configs, unused dependencies,
and third-party source dumps. Add proper README, update .gitignore,
clean up Makefile.
This commit is contained in:
NotEvil
2026-04-12 00:51:22 +02:00
parent 2e7a1d403b
commit f6466360b6
1947 changed files with 238025 additions and 1 deletions

View File

@@ -0,0 +1,474 @@
package com.tiedup.remake.labor;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import org.jetbrains.annotations.Nullable;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraftforge.registries.ForgeRegistries;
/**
* Unified "Bring X Items" labor task.
*
* DESIGN CHANGE (v2.0):
* All tasks are now simplified to "bring X items" instead of:
* - "Mine X blocks" (event-based tracking)
* - "Kill X mobs" (event-based tracking)
* - "Chop X logs" (event-based tracking)
* - "Collect X items" (inventory-based tracking)
*
* Benefits:
* - Single task class (was 4)
* - Periodic inventory checks (no event dependencies)
* - Works with ANY item source (/give, crafting, trading, mining, looting)
* - Maid collects items and deposits in cell chest
* - Tools are provided and automatically retrieved
*/
public class LaborTask {
private final UUID id;
private final Item targetItem; // What to bring
private final int quota; // How many
private final int value; // Emerald reward
private final ItemStack toolGiven; // Tool provided (can be null)
private int progress; // Current count (based on inventory)
private UUID campId;
// ==================== CONSTRUCTORS ====================
public LaborTask(
Item targetItem,
int quota,
int value,
@Nullable ItemStack tool
) {
this.id = UUID.randomUUID();
this.targetItem = targetItem;
this.quota = quota;
this.value = value;
this.toolGiven = tool != null ? tagAsLaborTool(tool.copy()) : null;
this.progress = 0;
}
// ==================== GETTERS ====================
public UUID getId() {
return id;
}
public Item getTargetItem() {
return targetItem;
}
public int getQuota() {
return quota;
}
public int getProgress() {
return progress;
}
public int getValue() {
return value;
}
public UUID getCampId() {
return campId;
}
public void setCampId(UUID campId) {
this.campId = campId;
}
@Nullable
public ItemStack getToolGiven() {
return toolGiven;
}
/**
* Get the tool type (e.g., Items.IRON_AXE).
* Used for retrieving stored tools from cell chest.
*/
@Nullable
public Item getToolType() {
return toolGiven != null ? toolGiven.getItem() : null;
}
/**
* Check if this is a combat task (requires killing mobs).
* Combat tasks use a sword and depend on mob spawns (time-of-day dependent).
*/
public boolean isCombatTask() {
return toolGiven != null && toolGiven.getItem() == Items.IRON_SWORD;
}
// ==================== PROGRESS ====================
/**
* Check if the task is complete.
*/
public boolean isComplete() {
return progress >= quota;
}
/**
* Get completion percentage (0-100).
*/
public int getProgressPercent() {
if (quota <= 0) return 100;
return Math.min(100, (progress * 100) / quota);
}
/**
* Check progress by counting matching items in worker's inventory.
* Called periodically (every ~5 seconds) by MaidManagePrisonersGoal.
*
* @param worker The player doing the task
* @param level The server level (unused but kept for API compatibility)
* @return true if progress was made since last check
*/
public boolean checkProgress(ServerPlayer worker, ServerLevel level) {
int count = 0;
var inventory = worker.getInventory();
for (int i = 0; i < inventory.getContainerSize(); i++) {
ItemStack stack = inventory.getItem(i);
if (!stack.isEmpty() && isAcceptableItem(stack.getItem())) {
count += stack.getCount();
}
}
int oldProgress = progress;
progress = Math.min(count, quota);
return progress > oldProgress;
}
/**
* Check if an item is acceptable for this task.
* For logs, accept any type of log (oak, birch, spruce, etc.)
*/
private boolean isAcceptableItem(Item item) {
// Direct match
if (item == targetItem) {
return true;
}
// If target is any type of log, accept all logs
if (isLogItem(targetItem) && isLogItem(item)) {
return true;
}
// If target is any type of planks, accept all planks
if (isPlankItem(targetItem) && isPlankItem(item)) {
return true;
}
return false;
}
/**
* Check if an item is a log.
*/
private boolean isLogItem(Item item) {
return (
item == Items.OAK_LOG ||
item == Items.BIRCH_LOG ||
item == Items.SPRUCE_LOG ||
item == Items.DARK_OAK_LOG ||
item == Items.JUNGLE_LOG ||
item == Items.ACACIA_LOG ||
item == Items.MANGROVE_LOG ||
item == Items.CHERRY_LOG ||
item == Items.CRIMSON_STEM ||
item == Items.WARPED_STEM
);
}
/**
* Check if an item is a plank.
*/
private boolean isPlankItem(Item item) {
return (
item == Items.OAK_PLANKS ||
item == Items.BIRCH_PLANKS ||
item == Items.SPRUCE_PLANKS ||
item == Items.DARK_OAK_PLANKS ||
item == Items.JUNGLE_PLANKS ||
item == Items.ACACIA_PLANKS ||
item == Items.MANGROVE_PLANKS ||
item == Items.CHERRY_PLANKS ||
item == Items.CRIMSON_PLANKS ||
item == Items.WARPED_PLANKS ||
item == Items.BAMBOO_PLANKS
);
}
// ==================== EQUIPMENT ====================
/**
* Give equipment to the worker for this task.
* Equipment is tagged as LaborTool to prevent dropping.
*
* @param worker The player to give equipment to
*/
public void giveEquipment(ServerPlayer worker) {
// Give tool if one is specified
if (toolGiven != null) {
ItemStack tool = toolGiven.copy();
worker.getInventory().add(tool);
}
// Always give food for sustenance
ItemStack bread = new ItemStack(Items.BREAD, 8);
tagAsLaborTool(bread);
worker.getInventory().add(bread);
// Give torches if tool is a pickaxe (for mining)
if (
toolGiven != null &&
(toolGiven.getItem() == Items.IRON_PICKAXE ||
toolGiven.getItem() == Items.STONE_PICKAXE)
) {
ItemStack torches = new ItemStack(Items.TORCH, 32);
tagAsLaborTool(torches);
worker.getInventory().add(torches);
}
}
/**
* Give equipment using a retrieved tool from cell chest.
* Used to reuse tools instead of creating new ones.
*
* @param worker The player to give equipment to
* @param retrievedTool The tool retrieved from cell chest
*/
public void giveRetrievedEquipment(
ServerPlayer worker,
ItemStack retrievedTool
) {
// Ensure the retrieved tool has LaborTool tag
tagAsLaborTool(retrievedTool);
worker.getInventory().add(retrievedTool);
// Give consumables (food, torches)
ItemStack bread = new ItemStack(Items.BREAD, 8);
tagAsLaborTool(bread);
worker.getInventory().add(bread);
if (
retrievedTool.getItem() == Items.IRON_PICKAXE ||
retrievedTool.getItem() == Items.STONE_PICKAXE
) {
ItemStack torches = new ItemStack(Items.TORCH, 32);
tagAsLaborTool(torches);
worker.getInventory().add(torches);
}
}
/**
* Reclaim equipment from the worker after task completion.
* Removes any items tagged as LaborTool belonging to this camp.
*
* @param worker The player to reclaim equipment from
* @return List of reclaimed tool items (for storage in cell chest)
*/
public List<ItemStack> reclaimEquipment(ServerPlayer worker) {
List<ItemStack> reclaimedTools = new ArrayList<>();
var inventory = worker.getInventory();
for (int i = 0; i < inventory.getContainerSize(); i++) {
ItemStack stack = inventory.getItem(i);
if (!stack.isEmpty() && isLaborTool(stack)) {
// Only store tools (not consumables like bread/torches)
if (isReusableTool(stack)) {
reclaimedTools.add(stack.copy());
}
inventory.setItem(i, ItemStack.EMPTY);
}
}
return reclaimedTools;
}
/**
* Collect task items from worker's inventory.
* Called by maid when task is complete.
*
* @param worker The player to collect items from
* @return List of collected item stacks
*/
public List<ItemStack> collectItems(ServerPlayer worker) {
List<ItemStack> collected = new ArrayList<>();
var inventory = worker.getInventory();
int remaining = quota;
for (
int i = 0;
i < inventory.getContainerSize() && remaining > 0;
i++
) {
ItemStack stack = inventory.getItem(i);
if (!stack.isEmpty() && isAcceptableItem(stack.getItem())) {
int toTake = Math.min(stack.getCount(), remaining);
ItemStack taken = stack.split(toTake);
collected.add(taken);
remaining -= toTake;
}
}
return collected;
}
// ==================== HELPER METHODS ====================
/**
* Check if an item is a labor tool from this camp.
*/
private boolean isLaborTool(ItemStack stack) {
if (!stack.hasTag()) return false;
CompoundTag tag = stack.getTag();
if (tag == null) return false;
if (!tag.getBoolean("LaborTool")) return false;
// Check camp ID if we have one
if (campId != null && tag.hasUUID("CampId")) {
return campId.equals(tag.getUUID("CampId"));
}
return true;
}
/**
* Check if a tool is reusable (should be stored, not discarded).
*/
private boolean isReusableTool(ItemStack stack) {
Item item = stack.getItem();
return (
item == Items.IRON_PICKAXE ||
item == Items.STONE_PICKAXE ||
item == Items.IRON_AXE ||
item == Items.IRON_SWORD ||
item == Items.IRON_SHOVEL ||
item == Items.IRON_HOE
);
}
/**
* Tag an item as a labor tool belonging to this camp.
* BUG FIX: Made tools unbreakable to prevent soft-lock when tools break.
* Problem: Tools breaking left prisoners stuck and punished in loop with no recourse.
*/
private ItemStack tagAsLaborTool(ItemStack stack) {
CompoundTag tag = stack.getOrCreateTag();
tag.putBoolean("LaborTool", true);
tag.putBoolean("Unbreakable", true); // Prevent tool breakage soft-lock
if (campId != null) {
tag.putUUID("CampId", campId);
}
return stack;
}
// ==================== DESCRIPTION ====================
/**
* Get a human-readable description of this task.
*/
public String getDescription() {
return String.format("Bring %d %s", quota, getTargetName());
}
/**
* Get the target item name (formatted).
* For logs, return generic "Logs" instead of specific type.
*/
public String getTargetName() {
if (isLogItem(targetItem)) {
return "Logs";
}
if (isPlankItem(targetItem)) {
return "Planks";
}
return new ItemStack(targetItem).getHoverName().getString();
}
// ==================== SERIALIZATION ====================
/**
* Save task data to NBT.
*/
public CompoundTag save() {
CompoundTag tag = new CompoundTag();
tag.putUUID("id", id);
// Save target item
ResourceLocation itemKey = ForgeRegistries.ITEMS.getKey(targetItem);
if (itemKey != null) {
tag.putString("targetItem", itemKey.toString());
}
tag.putInt("quota", quota);
tag.putInt("progress", progress);
tag.putInt("value", value);
// Save tool if one was given
if (toolGiven != null) {
CompoundTag toolTag = new CompoundTag();
toolGiven.save(toolTag);
tag.put("toolGiven", toolTag);
}
if (campId != null) {
tag.putUUID("campId", campId);
}
return tag;
}
/**
* Load task from NBT. Returns null if invalid.
*/
@Nullable
public static LaborTask load(CompoundTag tag) {
if (
!tag.contains("targetItem") ||
!tag.contains("quota") ||
!tag.contains("value")
) {
return null;
}
// Load target item
String itemKeyStr = tag.getString("targetItem");
ResourceLocation itemKey = ResourceLocation.tryParse(itemKeyStr);
if (itemKey == null) return null;
Item item = ForgeRegistries.ITEMS.getValue(itemKey);
if (item == null || item == Items.AIR) return null;
// Load tool (if present)
ItemStack tool = null;
if (tag.contains("toolGiven")) {
tool = ItemStack.of(tag.getCompound("toolGiven"));
}
// Create task
int quota = tag.getInt("quota");
int value = tag.getInt("value");
LaborTask task = new LaborTask(item, quota, value, tool);
// Load progress and camp ID
if (tag.contains("progress")) {
task.progress = tag.getInt("progress");
}
if (tag.contains("campId")) {
task.campId = tag.getUUID("campId");
}
return task;
}
}

View File

@@ -0,0 +1,255 @@
package com.tiedup.remake.labor;
import java.util.List;
import java.util.Map;
import org.jetbrains.annotations.Nullable;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.RandomSource;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
/**
* Generator for random labor tasks.
*
* DESIGN CHANGE (v2.0):
* All tasks simplified to "Bring X Items" with automatic tool assignment.
*
* Value Guidelines:
* - Standard ransom: 100-200 emeralds
* - Target: ~6 tasks average to pay off
* - Per task value: 18-35 emeralds depending on difficulty
*/
public class LaborTaskGenerator {
private static final RandomSource RANDOM = RandomSource.create();
// ==================== TOOL MAPPING ====================
/**
* Maps items to the tools needed to collect them.
* If an item is not in this map, no tool is given.
*/
private static final Map<Item, ItemStack> TOOL_MAP = Map.ofEntries(
// Logs → Axe
Map.entry(Items.OAK_LOG, new ItemStack(Items.IRON_AXE)),
Map.entry(Items.BIRCH_LOG, new ItemStack(Items.IRON_AXE)),
Map.entry(Items.SPRUCE_LOG, new ItemStack(Items.IRON_AXE)),
Map.entry(Items.DARK_OAK_LOG, new ItemStack(Items.IRON_AXE)),
Map.entry(Items.JUNGLE_LOG, new ItemStack(Items.IRON_AXE)),
Map.entry(Items.ACACIA_LOG, new ItemStack(Items.IRON_AXE)),
Map.entry(Items.MANGROVE_LOG, new ItemStack(Items.IRON_AXE)),
Map.entry(Items.CHERRY_LOG, new ItemStack(Items.IRON_AXE)),
// Gathering → Shovel
Map.entry(Items.SAND, new ItemStack(Items.IRON_SHOVEL)),
Map.entry(Items.GRAVEL, new ItemStack(Items.IRON_SHOVEL)),
Map.entry(Items.DIRT, new ItemStack(Items.IRON_SHOVEL)),
Map.entry(Items.CLAY_BALL, new ItemStack(Items.IRON_SHOVEL)),
// Basic mining → Pickaxe
Map.entry(Items.COBBLESTONE, new ItemStack(Items.STONE_PICKAXE)),
// Ores → Pickaxe
Map.entry(Items.IRON_ORE, new ItemStack(Items.IRON_PICKAXE)),
Map.entry(Items.DEEPSLATE_IRON_ORE, new ItemStack(Items.IRON_PICKAXE)),
Map.entry(Items.RAW_IRON, new ItemStack(Items.IRON_PICKAXE)),
Map.entry(Items.COAL_ORE, new ItemStack(Items.IRON_PICKAXE)),
Map.entry(Items.DEEPSLATE_COAL_ORE, new ItemStack(Items.IRON_PICKAXE)),
Map.entry(Items.COAL, new ItemStack(Items.IRON_PICKAXE)),
Map.entry(Items.DIAMOND_ORE, new ItemStack(Items.IRON_PICKAXE)),
Map.entry(
Items.DEEPSLATE_DIAMOND_ORE,
new ItemStack(Items.IRON_PICKAXE)
),
Map.entry(Items.DIAMOND, new ItemStack(Items.IRON_PICKAXE)),
Map.entry(Items.GOLD_ORE, new ItemStack(Items.IRON_PICKAXE)),
Map.entry(Items.DEEPSLATE_GOLD_ORE, new ItemStack(Items.IRON_PICKAXE)),
Map.entry(Items.RAW_GOLD, new ItemStack(Items.IRON_PICKAXE)),
Map.entry(Items.COPPER_ORE, new ItemStack(Items.IRON_PICKAXE)),
Map.entry(
Items.DEEPSLATE_COPPER_ORE,
new ItemStack(Items.IRON_PICKAXE)
),
Map.entry(Items.RAW_COPPER, new ItemStack(Items.IRON_PICKAXE)),
Map.entry(Items.LAPIS_ORE, new ItemStack(Items.IRON_PICKAXE)),
Map.entry(Items.DEEPSLATE_LAPIS_ORE, new ItemStack(Items.IRON_PICKAXE)),
Map.entry(Items.LAPIS_LAZULI, new ItemStack(Items.IRON_PICKAXE)),
Map.entry(Items.REDSTONE_ORE, new ItemStack(Items.IRON_PICKAXE)),
Map.entry(
Items.DEEPSLATE_REDSTONE_ORE,
new ItemStack(Items.IRON_PICKAXE)
),
Map.entry(Items.REDSTONE, new ItemStack(Items.IRON_PICKAXE)),
Map.entry(Items.EMERALD_ORE, new ItemStack(Items.IRON_PICKAXE)),
Map.entry(
Items.DEEPSLATE_EMERALD_ORE,
new ItemStack(Items.IRON_PICKAXE)
),
Map.entry(Items.EMERALD, new ItemStack(Items.IRON_PICKAXE)),
// Combat drops → Sword
Map.entry(Items.ROTTEN_FLESH, new ItemStack(Items.IRON_SWORD)),
Map.entry(Items.BONE, new ItemStack(Items.IRON_SWORD)),
Map.entry(Items.STRING, new ItemStack(Items.IRON_SWORD)),
Map.entry(Items.GUNPOWDER, new ItemStack(Items.IRON_SWORD)),
Map.entry(Items.SPIDER_EYE, new ItemStack(Items.IRON_SWORD)),
Map.entry(Items.ARROW, new ItemStack(Items.IRON_SWORD))
// Items not in this map (e.g., SWEET_BERRIES, KELP, STICK, TORCH, planks) get no tool
);
// ==================== TASK POOL ====================
/**
* Pool of all available labor tasks.
* Each entry specifies: item to bring, quota, emerald value.
*/
private static final List<TaskSpec> TASK_POOL = List.of(
// Logs (axe provided) — generic "Logs", accepts any type
new TaskSpec(Items.OAK_LOG, 32, 18),
new TaskSpec(Items.OAK_LOG, 48, 25),
new TaskSpec(Items.OAK_LOG, 64, 32),
// Gathering (shovel provided)
new TaskSpec(Items.SAND, 32, 10),
new TaskSpec(Items.GRAVEL, 32, 10),
new TaskSpec(Items.DIRT, 64, 8),
new TaskSpec(Items.CLAY_BALL, 16, 14),
// Basic mining (stone pickaxe provided)
new TaskSpec(Items.COBBLESTONE, 64, 10),
new TaskSpec(Items.COBBLESTONE, 32, 8),
// Easy picks (no tool needed)
new TaskSpec(Items.SWEET_BERRIES, 16, 12),
new TaskSpec(Items.KELP, 32, 10),
// Crafted (no tool needed)
new TaskSpec(Items.OAK_PLANKS, 64, 12),
new TaskSpec(Items.STICK, 64, 10),
new TaskSpec(Items.TORCH, 32, 15),
// Mining - Coal (common, pickaxe provided)
new TaskSpec(Items.COAL, 24, 18),
new TaskSpec(Items.COAL, 32, 22),
// Mining - Iron (pickaxe provided)
new TaskSpec(Items.RAW_IRON, 16, 25),
new TaskSpec(Items.RAW_IRON, 24, 32),
// Mining - Copper (pickaxe provided)
new TaskSpec(Items.RAW_COPPER, 20, 20),
// Mining - Gold (pickaxe provided)
new TaskSpec(Items.RAW_GOLD, 8, 30),
// Mining - Lapis (pickaxe provided)
new TaskSpec(Items.LAPIS_LAZULI, 10, 28),
// Mining - Redstone (pickaxe provided)
new TaskSpec(Items.REDSTONE, 12, 22),
// Mining - Diamond (pickaxe provided, rare, high value)
new TaskSpec(Items.DIAMOND, 5, 35),
// Mining - Emerald (pickaxe provided, very rare)
new TaskSpec(Items.EMERALD, 3, 35),
// Combat drops (sword provided)
new TaskSpec(Items.ROTTEN_FLESH, 24, 18),
new TaskSpec(Items.BONE, 16, 20),
new TaskSpec(Items.STRING, 32, 20),
new TaskSpec(Items.GUNPOWDER, 12, 25),
new TaskSpec(Items.SPIDER_EYE, 8, 20),
new TaskSpec(Items.ARROW, 16, 18)
);
// ==================== GENERATION ====================
/** Combat task items (require mob kills, only assigned at night). */
private static final List<Item> COMBAT_ITEMS = List.of(
Items.ROTTEN_FLESH,
Items.BONE,
Items.STRING,
Items.GUNPOWDER,
Items.SPIDER_EYE,
Items.ARROW
);
/**
* Generate a random labor task, filtering combat tasks to nighttime only.
*
* @param level The server level (used to check time of day), or null to skip filtering
*/
public static LaborTask generateRandom(@Nullable ServerLevel level) {
List<TaskSpec> pool;
if (level != null && isDay(level)) {
// Daytime: exclude combat tasks (mobs don't spawn)
pool = TASK_POOL.stream()
.filter(spec -> !COMBAT_ITEMS.contains(spec.item()))
.toList();
} else {
pool = TASK_POOL;
}
TaskSpec spec = pickRandom(pool);
ItemStack tool = TOOL_MAP.get(spec.item());
return new LaborTask(spec.item(), spec.quota(), spec.value(), tool);
}
/**
* Check if it's daytime in the level.
* Minecraft day cycle: 0-12541 = day, 12542-23999 = night/dusk/dawn.
* We use 13000-23000 as "night enough for mob spawns".
*/
private static boolean isDay(ServerLevel level) {
long timeOfDay = level.getDayTime() % 24000;
return timeOfDay < 13000;
}
/**
* Generate a task requiring a specific item type.
* Used for testing or custom scenarios.
*/
public static LaborTask generateFor(Item item, int quota, int value) {
ItemStack tool = TOOL_MAP.get(item);
return new LaborTask(item, quota, value, tool);
}
// ==================== UTILITY ====================
private static <T> T pickRandom(List<T> list) {
return list.get(RANDOM.nextInt(list.size()));
}
/**
* Task specification record.
*/
private record TaskSpec(Item item, int quota, int value) {}
// ==================== RANSOM CALCULATION ====================
/**
* Calculate ransom amount based on player equipment/level.
*
* @param hasIronArmor Player has iron armor equipped
* @param hasDiamondArmor Player has diamond/netherite armor equipped
* @param hasValuables Player has emeralds/diamonds in inventory
* @return Ransom amount in emeralds
*/
public static int calculateRansomAmount(
boolean hasIronArmor,
boolean hasDiamondArmor,
boolean hasValuables
) {
int base = 100;
if (hasDiamondArmor) {
base = 200;
} else if (hasIronArmor) {
base = 150;
}
if (hasValuables) {
base += 25;
}
// Add some randomness
int variance = RANDOM.nextInt(21) - 10; // -10 to +10
return base + variance;
}
/**
* Estimate number of tasks to pay off a ransom.
*
* @param ransomAmount The ransom amount
* @return Estimated number of tasks
*/
public static int estimateTasksToPayoff(int ransomAmount) {
// Average task value is about 25 emeralds
return (int) Math.ceil(ransomAmount / 25.0);
}
}